Commit c4431804 by Jamie Madill Committed by Commit Bot

D3D11: Fix Buffer11::copyFromStorage and UBOs.

The change to initialize a constant buffer immediately after calling BufferData in D3D11 led to a bug where we would map the UBO for writing with the wrong map bits. Fix this by using the same map method as the rest of the code. The D3D11 runtime seems to allow arbitrarily large constant buffers on Windows 10, but not Windows 7. Thus this CL also fixes a bug in our constant buffer size clamping to not copy more than the available buffer size for uniform buffers. BUG=chromium:651493 Change-Id: I876767691d02db90ecb08a8fa78199f03339a35e Reviewed-on: https://chromium-review.googlesource.com/391167Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent f51fdd2e
...@@ -889,45 +889,42 @@ gl::ErrorOrResult<CopyResult> Buffer11::NativeStorage::copyFromStorage(BufferSto ...@@ -889,45 +889,42 @@ gl::ErrorOrResult<CopyResult> Buffer11::NativeStorage::copyFromStorage(BufferSto
bool createBuffer = !mNativeStorage || mBufferSize < requiredSize; bool createBuffer = !mNativeStorage || mBufferSize < requiredSize;
// (Re)initialize D3D buffer if needed // (Re)initialize D3D buffer if needed
bool preserveData = (destOffset > 0);
if (createBuffer) if (createBuffer)
{ {
bool preserveData = (destOffset > 0);
resize(requiredSize, preserveData); resize(requiredSize, preserveData);
} }
size_t clampedSize = size;
if (mUsage == BUFFER_USAGE_UNIFORM)
{
clampedSize = std::min(clampedSize, mBufferSize - destOffset);
}
if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK || if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
source->getUsage() == BUFFER_USAGE_SYSTEM_MEMORY) source->getUsage() == BUFFER_USAGE_SYSTEM_MEMORY)
{ {
ASSERT(source->isMappable(GL_MAP_READ_BIT)); ASSERT(source->isMappable(GL_MAP_READ_BIT) && isMappable(GL_MAP_WRITE_BIT));
uint8_t *sourcePointer = nullptr; // Uniform buffers must be mapped with write/discard.
ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourcePointer)); ASSERT(!(preserveData && mUsage == BUFFER_USAGE_UNIFORM));
D3D11_MAPPED_SUBRESOURCE mappedResource; uint8_t *sourcePointer = nullptr;
HRESULT hr = context->Map(mNativeStorage, 0, D3D11_MAP_WRITE, 0, &mappedResource); ANGLE_TRY(source->map(sourceOffset, clampedSize, GL_MAP_READ_BIT, &sourcePointer));
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
{
source->unmap();
return gl::Error(
GL_OUT_OF_MEMORY,
"Failed to map native storage in Buffer11::NativeStorage::copyFromStorage");
}
uint8_t *destPointer = static_cast<uint8_t *>(mappedResource.pData) + destOffset; uint8_t *destPointer = nullptr;
ANGLE_TRY(map(destOffset, clampedSize, GL_MAP_WRITE_BIT, &destPointer));
// Offset bounds are validated at the API layer memcpy(destPointer, sourcePointer, clampedSize);
ASSERT(sourceOffset + size <= destOffset + mBufferSize);
memcpy(destPointer, sourcePointer, size);
context->Unmap(mNativeStorage, 0); unmap();
source->unmap(); source->unmap();
} }
else else
{ {
D3D11_BOX srcBox; D3D11_BOX srcBox;
srcBox.left = static_cast<unsigned int>(sourceOffset); srcBox.left = static_cast<unsigned int>(sourceOffset);
srcBox.right = static_cast<unsigned int>(sourceOffset + size); srcBox.right = static_cast<unsigned int>(sourceOffset + clampedSize);
srcBox.top = 0; srcBox.top = 0;
srcBox.bottom = 1; srcBox.bottom = 1;
srcBox.front = 0; srcBox.front = 0;
...@@ -1045,6 +1042,9 @@ void Buffer11::NativeStorage::FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, ...@@ -1045,6 +1042,9 @@ void Buffer11::NativeStorage::FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc,
// Constant buffers must be of a limited size, and aligned to 16 byte boundaries // Constant buffers must be of a limited size, and aligned to 16 byte boundaries
// For our purposes we ignore any buffer data past the maximum constant buffer size // For our purposes we ignore any buffer data past the maximum constant buffer size
bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u); bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u);
// Note: it seems that D3D11 allows larger buffers on some platforms, but not all.
// (Windows 10 seems to allow larger constant buffers, but not Windows 7)
bufferDesc->ByteWidth = bufferDesc->ByteWidth =
std::min<UINT>(bufferDesc->ByteWidth, std::min<UINT>(bufferDesc->ByteWidth,
static_cast<UINT>(renderer->getNativeCaps().maxUniformBlockSize)); static_cast<UINT>(renderer->getNativeCaps().maxUniformBlockSize));
......
...@@ -396,6 +396,27 @@ TEST_P(UniformBufferTest, ActiveUniformNames) ...@@ -396,6 +396,27 @@ TEST_P(UniformBufferTest, ActiveUniformNames)
EXPECT_EQ("blockName.f", std::string(&strBuffer[0])); EXPECT_EQ("blockName.f", std::string(&strBuffer[0]));
} }
// Test that using a very large buffer to back a small uniform block works OK.
TEST_P(UniformBufferTest, VeryLarge)
{
glClear(GL_COLOR_BUFFER_BIT);
float floatData[4] = {0.5f, 0.75f, 0.25f, 1.0f};
GLsizei bigSize = 4096 * 64;
glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
glBufferData(GL_UNIFORM_BUFFER, bigSize, nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(float) * 4, floatData);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
drawQuad(mProgram, "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against. // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(UniformBufferTest, ANGLE_INSTANTIATE_TEST(UniformBufferTest,
ES3_D3D11(), ES3_D3D11(),
......
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