Skip to content
This repository has been archived by the owner on Feb 25, 2025. It is now read-only.

Commit

Permalink
Avoid GPU-GPU copy for StructuredBuffer
Browse files Browse the repository at this point in the history
If uniform block is translated to StructureBuffer on D3D backend,
must do a GPU-GPU copy when updating uniform buffer. If buffer's
latest usage is StructuredBuffer, directly upload to structured
buffer.

Bug: angleproject:3682
Change-Id: I7303866d08705a43238732e5f5ae4858f0a33d63
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2131871
Commit-Queue: Xinghua Cao <xinghua.cao@intel.com>
Reviewed-by: Jiajia Qin <jiajia.qin@intel.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Kenneth Russell <kbr@chromium.org>
  • Loading branch information
xhcao authored and Commit Bot committed Apr 10, 2020
1 parent df3cc20 commit c68dfaf
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 1 deletion.
11 changes: 10 additions & 1 deletion src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,16 @@ angle::Result Buffer11::setSubData(const gl::Context *context,
size <= static_cast<UINT>(mRenderer->getNativeCaps().maxUniformBlockSize) &&
!mRenderer->getFeatures().useSystemMemoryForConstantBuffers.enabled)
{
ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_UNIFORM, &writeBuffer));
BufferStorage *latestStorage = nullptr;
ANGLE_TRY(getLatestBufferStorage(context, &latestStorage));
if (latestStorage && (latestStorage->getUsage() == BUFFER_USAGE_STRUCTURED))
{
ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_STRUCTURED, &writeBuffer));
}
else
{
ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_UNIFORM, &writeBuffer));
}
}
else
{
Expand Down
120 changes: 120 additions & 0 deletions src/tests/gl_tests/UniformBufferTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2397,6 +2397,126 @@ TEST_P(UniformBufferTest, UniformBlocksInDiffProgramShareUniformBuffer)
}
}

// Test two uniform blocks share the same uniform buffer. On D3D backend, one uniform
// block with a large array member will be translated to StructuredBuffer, and the
// other uniform block will be translated to cbuffer, this case verifies that update
// buffer data correctly.
TEST_P(UniformBufferTest, UniformBlocksSharedSameUniformBuffer)
{
ANGLE_SKIP_TEST_IF(IsIntel() && IsOSX());

GLint64 maxUniformBlockSize;
glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
std::ostringstream stream;
GLuint arraySize;
// Ensure that shader uniform block do not exceed MAX_UNIFORM_BLOCK_SIZE limit.
if (maxUniformBlockSize >= 16384 && maxUniformBlockSize < 32768)
{
arraySize = 128;
stream << "const uint arraySize = 128u;\n"
"const uint divisor1 = 128u;\n"
"const uint divisor2 = 32u;\n";
}
else if (maxUniformBlockSize >= 32768 && maxUniformBlockSize < 65536)
{
arraySize = 256;
stream << "const uint arraySize = 256u;\n"
"const uint divisor1 = 64u;\n"
"const uint divisor2 = 16u;\n";
}
else
{
arraySize = 512;
stream << "const uint arraySize = 512u;\n"
"const uint divisor1 = 32u;\n"
"const uint divisor2 = 8u;\n";
}

const std::string &kFS =
"#version 300 es\n"
"precision highp float;\n" +
stream.str() +
"out vec4 my_FragColor;\n"
"struct S { mat4 color;};\n"
"layout(std140) uniform buffer { S s[arraySize]; };\n"
"layout(std140) uniform buffer1 { vec4 factor; };\n"
"void main()\n"
"{\n"
" uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
" uint index = coord.x + coord.y * 128u;\n"
" uint index_x = index / divisor1;\n"
" uint index_y = (index % divisor1) / divisor2;\n"
" my_FragColor = s[index_x].color[index_y] + factor;\n"
"}\n";

GLint blockSize;
ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
GLint uniformBufferIndex1 = glGetUniformBlockIndex(program, "buffer1");
GLint alignment;
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment);
while (alignment >= 0 && alignment < 16)
{
alignment += alignment;
}

glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
glBufferData(GL_UNIFORM_BUFFER, alignment + blockSize, nullptr, GL_STATIC_DRAW);

const GLuint kVectorPerMat = 4;
const GLuint kFloatPerVector = 4;
GLuint kVectorCount = arraySize * kVectorPerMat;
GLuint kFloatCount = kVectorCount * kFloatPerVector;
std::vector<GLfloat> floatData(kFloatCount, 0.0f);
std::vector<GLfloat> floatData1(4, 0.0f);
const GLuint kPositionCount = 12;
unsigned int positionToTest[kPositionCount][2] = {{0, 0}, {75, 0}, {98, 13}, {31, 31},
{0, 32}, {65, 33}, {23, 54}, {63, 63},
{0, 64}, {43, 86}, {53, 100}, {127, 127}};

for (GLuint i = 0; i < kVectorCount; i++)
{
floatData[4 * i + 2] = 0.5f;
floatData[4 * i + 3] = 0.5f;
}
floatData1[0] = 1.0f;
floatData1[1] = 0.0f;
floatData1[2] = 0.5f;
floatData1[3] = 0.5f;

glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, 0, 4 * sizeof(float));
glUniformBlockBinding(program, uniformBufferIndex1, 0);
glBindBufferRange(GL_UNIFORM_BUFFER, 1, mUniformBuffer, alignment,
kVectorCount * kFloatPerVector * sizeof(float));
glUniformBlockBinding(program, uniformBufferIndex, 1);

glBufferSubData(GL_UNIFORM_BUFFER, alignment, kFloatCount * sizeof(GLfloat), floatData.data());
glBufferSubData(GL_UNIFORM_BUFFER, 0, 4 * sizeof(GLfloat), floatData1.data());
drawQuad(program.get(), essl3_shaders::PositionAttrib(), 0.5f);
for (GLuint i = 0; i < kPositionCount; i++)
{
EXPECT_PIXEL_COLOR_EQ(positionToTest[i][0], positionToTest[i][1], GLColor::magenta);
}

for (GLuint i = 0; i < kVectorCount; i++)
{
floatData[4 * i + 1] = 0.5f;
floatData[4 * i + 2] = 0.0f;
}
floatData1[0] = 0.0f;
floatData1[1] = 0.5f;
floatData1[2] = 0.0f;
floatData1[3] = 0.5f;
glBufferSubData(GL_UNIFORM_BUFFER, alignment, kFloatCount * sizeof(GLfloat), floatData.data());
glBufferSubData(GL_UNIFORM_BUFFER, 0, 4 * sizeof(GLfloat), floatData1.data());
drawQuad(program.get(), essl3_shaders::PositionAttrib(), 0.5f);
for (GLuint i = 0; i < kPositionCount; i++)
{
EXPECT_PIXEL_COLOR_EQ(positionToTest[i][0], positionToTest[i][1], GLColor::green);
}
}

// Test a uniform block where an array of row-major matrices is dynamically indexed.
TEST_P(UniformBufferTest, Std140UniformBlockWithDynamicallyIndexedRowMajorArray)
{
Expand Down

0 comments on commit c68dfaf

Please sign in to comment.