Commit b7d5e303 by Jamie Madill Committed by Commit Bot

D3D11: Default init all textures.

The resource manager factory methods will use ClearView or zero-filled buffers to set initial data. It assumes there are no 3D depth/stencil textures. This will lead to some wasteful re-creation of RTVs in some cases. This is a temporary measure until we can implement more efficient lazy resource init strategies. BUG=angleproject:1635 Change-Id: I590e76587d3d96a359beedb79e21d24930e5f2e0 Reviewed-on: https://chromium-review.googlesource.com/503254Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent c564c070
......@@ -380,4 +380,9 @@ angle::WorkerThreadPool *RendererD3D::getWorkerThreadPool()
return &mWorkerThreadPool;
}
bool RendererD3D::isRobustResourceInitEnabled() const
{
return mDisplay->isRobustResourceInitEnabled();
}
} // namespace rx
......@@ -282,6 +282,8 @@ class RendererD3D : public BufferFactoryD3D
virtual gl::Error applyComputeUniforms(const ProgramD3D &programD3D,
const std::vector<D3DUniform *> &uniformArray) = 0;
bool isRobustResourceInitEnabled() const;
protected:
virtual bool getLUID(LUID *adapterLuid) const = 0;
virtual void generateCaps(gl::Caps *outCaps,
......
......@@ -168,6 +168,97 @@ HRESULT CreateResource(ID3D11Device *device,
return device->CreateTexture3D(desc, initData, texture);
}
DXGI_FORMAT GetTypedDepthStencilFormat(DXGI_FORMAT dxgiFormat)
{
switch (dxgiFormat)
{
case DXGI_FORMAT_R16_TYPELESS:
return DXGI_FORMAT_D16_UNORM;
case DXGI_FORMAT_R24G8_TYPELESS:
return DXGI_FORMAT_D24_UNORM_S8_UINT;
case DXGI_FORMAT_R32_TYPELESS:
return DXGI_FORMAT_D32_FLOAT;
case DXGI_FORMAT_R32G8X24_TYPELESS:
return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
default:
return dxgiFormat;
}
}
template <typename DescT, typename ResourceT>
gl::Error ClearResource(Renderer11 *renderer, const DescT *desc, ResourceT *texture)
{
// No-op.
return gl::NoError();
}
template <>
gl::Error ClearResource(Renderer11 *renderer,
const D3D11_TEXTURE2D_DESC *desc,
ID3D11Texture2D *texture)
{
ID3D11DeviceContext *context = renderer->getDeviceContext();
if ((desc->BindFlags & D3D11_BIND_DEPTH_STENCIL) != 0)
{
D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
dsvDesc.Flags = 0;
dsvDesc.Format = GetTypedDepthStencilFormat(desc->Format);
const auto &format = d3d11_angle::GetFormat(dsvDesc.Format);
UINT clearFlags = (format.depthBits > 0 ? D3D11_CLEAR_DEPTH : 0) |
(format.stencilBits > 0 ? D3D11_CLEAR_STENCIL : 0);
// Must process each mip level individually.
for (UINT mipLevel = 0; mipLevel < desc->MipLevels; ++mipLevel)
{
if (desc->SampleDesc.Count == 0)
{
dsvDesc.Texture2D.MipSlice = mipLevel;
dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
}
else
{
dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
}
d3d11::DepthStencilView dsv;
ANGLE_TRY(renderer->allocateResource(dsvDesc, texture, &dsv));
context->ClearDepthStencilView(dsv.get(), clearFlags, 1.0f, 0);
}
}
else
{
ASSERT((desc->BindFlags & D3D11_BIND_RENDER_TARGET) != 0);
d3d11::RenderTargetView rtv;
ANGLE_TRY(renderer->allocateResourceNoDesc(texture, &rtv));
const FLOAT zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
context->ClearRenderTargetView(rtv.get(), zero);
}
return gl::NoError();
}
template <>
gl::Error ClearResource(Renderer11 *renderer,
const D3D11_TEXTURE3D_DESC *desc,
ID3D11Texture3D *texture)
{
ID3D11DeviceContext *context = renderer->getDeviceContext();
ASSERT((desc->BindFlags & D3D11_BIND_DEPTH_STENCIL) == 0);
ASSERT((desc->BindFlags & D3D11_BIND_RENDER_TARGET) != 0);
d3d11::RenderTargetView rtv;
ANGLE_TRY(renderer->allocateResourceNoDesc(texture, &rtv));
const FLOAT zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
context->ClearRenderTargetView(rtv.get(), zero);
return gl::NoError();
}
#define ANGLE_RESOURCE_STRINGIFY_OP(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) #RESTYPE
constexpr std::array<const char *, NumResourceTypes> kResourceTypeNames = {
......@@ -202,8 +293,13 @@ gl::Error ResourceManager11::allocate(Renderer11 *renderer,
ID3D11Device *device = renderer->getDevice();
T *resource = nullptr;
HRESULT hr = CreateResource(device, desc, initData, &resource);
GetInitDataFromD3D11<T> *shadowInitData = initData;
if (!shadowInitData && renderer->isRobustResourceInitEnabled())
{
shadowInitData = createInitDataIfNeeded<T>(desc);
}
HRESULT hr = CreateResource(device, desc, shadowInitData, &resource);
if (FAILED(hr))
{
ASSERT(!resource);
......@@ -216,6 +312,11 @@ gl::Error ResourceManager11::allocate(Renderer11 *renderer,
<< gl::FmtHR(hr);
}
if (!shadowInitData && renderer->isRobustResourceInitEnabled())
{
ANGLE_TRY(ClearResource(renderer, desc, resource));
}
ASSERT(resource);
incrResource(GetResourceTypeFromD3D11<T>(), ComputeMemoryUsage(desc));
*resourceOut = std::move(Resource11<T>(resource, this));
......@@ -259,6 +360,102 @@ void ResourceManager11::onRelease(T *resource)
decrResource(GetResourceTypeFromD3D11<T>(), ComputeMemoryUsage(&desc));
}
template <>
const D3D11_SUBRESOURCE_DATA *ResourceManager11::createInitDataIfNeeded<ID3D11Texture2D>(
const D3D11_TEXTURE2D_DESC *desc)
{
ASSERT(desc);
if ((desc->BindFlags & (D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_RENDER_TARGET)) != 0)
{
// This will be done using ClearView methods.
return nullptr;
}
size_t requiredSize = ComputeMemoryUsage(desc);
if (mZeroMemory.size() < requiredSize)
{
mZeroMemory.resize(requiredSize);
mZeroMemory.fill(0);
}
const auto &formatSizeInfo = d3d11::GetDXGIFormatSizeInfo(desc->Format);
UINT subresourceCount = desc->MipLevels * desc->ArraySize;
if (mShadowInitData.size() < subresourceCount)
{
mShadowInitData.resize(subresourceCount);
}
for (UINT mipLevel = 0; mipLevel < desc->MipLevels; ++mipLevel)
{
for (UINT arrayIndex = 0; arrayIndex < desc->ArraySize; ++arrayIndex)
{
UINT subresourceIndex = D3D11CalcSubresource(mipLevel, arrayIndex, desc->MipLevels);
D3D11_SUBRESOURCE_DATA *data = &mShadowInitData[subresourceIndex];
UINT levelWidth = std::max(desc->Width >> mipLevel, 1u);
UINT levelHeight = std::max(desc->Height >> mipLevel, 1u);
data->SysMemPitch = levelWidth * formatSizeInfo.pixelBytes;
data->SysMemSlicePitch = data->SysMemPitch * levelHeight;
data->pSysMem = mZeroMemory.data();
}
}
return mShadowInitData.data();
}
template <>
const D3D11_SUBRESOURCE_DATA *ResourceManager11::createInitDataIfNeeded<ID3D11Texture3D>(
const D3D11_TEXTURE3D_DESC *desc)
{
ASSERT(desc);
if ((desc->BindFlags & D3D11_BIND_RENDER_TARGET) != 0)
{
// This will be done using ClearView methods.
return nullptr;
}
size_t requiredSize = ComputeMemoryUsage(desc);
if (mZeroMemory.size() < requiredSize)
{
mZeroMemory.resize(requiredSize);
mZeroMemory.fill(0);
}
const auto &formatSizeInfo = d3d11::GetDXGIFormatSizeInfo(desc->Format);
UINT subresourceCount = desc->MipLevels;
if (mShadowInitData.size() < subresourceCount)
{
mShadowInitData.resize(subresourceCount);
}
for (UINT mipLevel = 0; mipLevel < desc->MipLevels; ++mipLevel)
{
UINT subresourceIndex = D3D11CalcSubresource(mipLevel, 0, desc->MipLevels);
D3D11_SUBRESOURCE_DATA *data = &mShadowInitData[subresourceIndex];
UINT levelWidth = std::max(desc->Width >> mipLevel, 1u);
UINT levelHeight = std::max(desc->Height >> mipLevel, 1u);
data->SysMemPitch = levelWidth * formatSizeInfo.pixelBytes;
data->SysMemSlicePitch = data->SysMemPitch * levelHeight;
data->pSysMem = mZeroMemory.data();
}
return mShadowInitData.data();
}
template <typename T>
GetInitDataFromD3D11<T> *ResourceManager11::createInitDataIfNeeded(const GetDescFromD3D11<T> *desc)
{
// No-op.
return nullptr;
}
#define ANGLE_INSTANTIATE_OP(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \
\
template gl::Error \
......@@ -276,5 +473,4 @@ template void \
ResourceManager11::onRelease(D3D11TYPE *);
ANGLE_RESOURCE_TYPE_OP(Instantitate, ANGLE_INSTANTIATE_OP)
} // namespace rx
......@@ -12,6 +12,7 @@
#include <array>
#include <memory>
#include "common/MemoryBuffer.h"
#include "common/angleutils.h"
#include "common/debug.h"
#include "libANGLE/Error.h"
......@@ -283,8 +284,14 @@ class ResourceManager11 final : angle::NonCopyable
void incrResource(ResourceType resourceType, size_t memorySize);
void decrResource(ResourceType resourceType, size_t memorySize);
template <typename T>
GetInitDataFromD3D11<T> *createInitDataIfNeeded(const GetDescFromD3D11<T> *desc);
std::array<size_t, NumResourceTypes> mAllocatedResourceCounts;
std::array<size_t, NumResourceTypes> mAllocatedResourceDeviceMemory;
angle::MemoryBuffer mZeroMemory;
std::vector<D3D11_SUBRESOURCE_DATA> mShadowInitData;
};
template <typename ResourceT>
......
......@@ -15,10 +15,13 @@ namespace angle
class RobustResourceInitTest : public ANGLETest
{
protected:
constexpr static int kWidth = 128;
constexpr static int kHeight = 128;
RobustResourceInitTest()
{
setWindowWidth(128);
setWindowHeight(128);
setWindowWidth(kWidth);
setWindowHeight(kHeight);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
......@@ -45,6 +48,28 @@ class RobustResourceInitTest : public ANGLETest
return true;
}
void setupTexture(GLTexture *tex);
void setup3DTexture(GLTexture *tex);
// Checks for uninitialized (non-zero pixels) in a Texture.
void checkNonZeroPixels(GLTexture *texture,
int skipX,
int skipY,
int skipWidth,
int skipHeight,
const GLColor &skip);
void checkNonZeroPixels3D(GLTexture *texture,
int skipX,
int skipY,
int skipWidth,
int skipHeight,
const GLColor &skip);
void checkFramebufferNonZeroPixels(int skipX,
int skipY,
int skipWidth,
int skipHeight,
const GLColor &skip);
};
// Display creation should fail if EGL_ANGLE_display_robust_resource_initialization
......@@ -170,6 +195,167 @@ TEST_P(RobustResourceInitTest, BufferDataZeroSize)
glBufferData(GL_ARRAY_BUFFER, 0, nullptr, GL_STATIC_DRAW);
}
// The following test code translated from WebGL 1 test:
// https://www.khronos.org/registry/webgl/sdk/tests/conformance/misc/uninitialized-test.html
void RobustResourceInitTest::setupTexture(GLTexture *tex)
{
GLuint tempTexture;
glGenTextures(1, &tempTexture);
glBindTexture(GL_TEXTURE_2D, tempTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
// this can be quite undeterministic so to improve odds of seeing uninitialized data write bits
// into tex then delete texture then re-create one with same characteristics (driver will likely
// reuse mem) with this trick on r59046 WebKit/OSX I get FAIL 100% of the time instead of ~15%
// of the time.
std::array<uint8_t, kWidth * kHeight * 4> badData;
for (size_t i = 0; i < badData.size(); ++i)
{
badData[i] = static_cast<uint8_t>(i % 255);
}
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
badData.data());
glDeleteTextures(1, &tempTexture);
// This will create the GLTexture.
glBindTexture(GL_TEXTURE_2D, *tex);
}
void RobustResourceInitTest::setup3DTexture(GLTexture *tex)
{
GLuint tempTexture;
glGenTextures(1, &tempTexture);
glBindTexture(GL_TEXTURE_3D, tempTexture);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, kWidth, kHeight, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
// this can be quite undeterministic so to improve odds of seeing uninitialized data write bits
// into tex then delete texture then re-create one with same characteristics (driver will likely
// reuse mem) with this trick on r59046 WebKit/OSX I get FAIL 100% of the time instead of ~15%
// of the time.
std::array<uint8_t, kWidth * kHeight * 2 * 4> badData;
for (size_t i = 0; i < badData.size(); ++i)
{
badData[i] = static_cast<uint8_t>(i % 255);
}
glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, 2, GL_RGBA, GL_UNSIGNED_BYTE,
badData.data());
glDeleteTextures(1, &tempTexture);
// This will create the GLTexture.
glBindTexture(GL_TEXTURE_3D, *tex);
}
void RobustResourceInitTest::checkNonZeroPixels(GLTexture *texture,
int skipX,
int skipY,
int skipWidth,
int skipHeight,
const GLColor &skip)
{
glBindTexture(GL_TEXTURE_2D, 0);
GLFramebuffer fb;
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->get(), 0);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
checkFramebufferNonZeroPixels(skipX, skipY, skipWidth, skipHeight, skip);
}
void RobustResourceInitTest::checkNonZeroPixels3D(GLTexture *texture,
int skipX,
int skipY,
int skipWidth,
int skipHeight,
const GLColor &skip)
{
glBindTexture(GL_TEXTURE_3D, 0);
GLFramebuffer fb;
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture->get(), 0, 0);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
checkFramebufferNonZeroPixels(skipX, skipY, skipWidth, skipHeight, skip);
}
void RobustResourceInitTest::checkFramebufferNonZeroPixels(int skipX,
int skipY,
int skipWidth,
int skipHeight,
const GLColor &skip)
{
std::array<GLColor, kWidth * kHeight> data;
glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
int k = 0;
for (int y = 0; y < kHeight; ++y)
{
for (int x = 0; x < kWidth; ++x)
{
int index = (y * kWidth + x);
if (x >= skipX && x < skipX + skipWidth && y >= skipY && y < skipY + skipHeight)
{
ASSERT_EQ(skip, data[index]);
}
else
{
k += (data[index] != GLColor::transparentBlack) ? 1 : 0;
}
}
}
EXPECT_EQ(0, k);
}
// Reading an uninitialized texture (texImage2D) should succeed with all bytes set to 0.
TEST_P(RobustResourceInitTest, ReadingUninitializedTexture)
{
if (!setup())
{
return;
}
if (IsOpenGL() || IsD3D9())
{
std::cout << "Robust resource init is not yet fully implemented. (" << GetParam() << ")"
<< std::endl;
return;
}
GLTexture tex;
setupTexture(&tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
checkNonZeroPixels(&tex, 0, 0, 0, 0, GLColor::transparentBlack);
EXPECT_GL_NO_ERROR();
}
// Reading an uninitialized texture (texImage2D) should succeed with all bytes set to 0.
TEST_P(RobustResourceInitTest, ReadingUninitialized3DTexture)
{
if (!setup() || getClientMajorVersion() < 3)
{
return;
}
if (IsOpenGL())
{
std::cout << "Robust resource init is not yet fully implemented. (" << GetParam() << ")"
<< std::endl;
return;
}
GLTexture tex;
setup3DTexture(&tex);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, kWidth, kHeight, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
checkNonZeroPixels3D(&tex, 0, 0, 0, 0, GLColor::transparentBlack);
EXPECT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST(RobustResourceInitTest,
ES2_D3D9(),
ES2_D3D11(),
......
......@@ -151,6 +151,11 @@ bool operator==(const GLColor &a, const GLColor &b)
return a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A;
}
bool operator!=(const GLColor &a, const GLColor &b)
{
return !(a == b);
}
std::ostream &operator<<(std::ostream &ostream, const GLColor &color)
{
ostream << "(" << static_cast<unsigned int>(color.R) << ", "
......
......@@ -110,6 +110,7 @@ GLColor MakeGLColor(TR r, TG g, TB b, TA a)
}
bool operator==(const GLColor &a, const GLColor &b);
bool operator!=(const GLColor &a, const GLColor &b);
std::ostream &operator<<(std::ostream &ostream, const GLColor &color);
GLColor ReadColor(GLint x, GLint y);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment