Commit 2caf7ffd by Xinghua Cao Committed by Commit Bot

Address a TODO for instance uniform block

This patch resolves one TODO that Support to translate instance uniform block containing only a large array member to Structured buffer on D3D backend when necessary. Bug: angleproject:4205 Change-Id: If2cd6cf633080820ea33e52269d7d86cd587c9ee Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2114912 Commit-Queue: Xinghua Cao <xinghua.cao@intel.com> Reviewed-by: 's avatarJiajia Qin <jiajia.qin@intel.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 23196076
...@@ -86,6 +86,30 @@ bool IsInStd140UniformBlock(TIntermTyped *node) ...@@ -86,6 +86,30 @@ bool IsInStd140UniformBlock(TIntermTyped *node)
return false; return false;
} }
bool IsInstanceUniformBlock(TIntermTyped *node)
{
TIntermBinary *binaryNode = node->getAsBinaryNode();
if (binaryNode)
{
return IsInstanceUniformBlock(binaryNode->getLeft());
}
const TVariable &variable = node->getAsSymbolNode()->variable();
const TType &variableType = variable.getType();
const TType &type = node->getType();
if (type.getQualifier() == EvqUniform)
{
// determine if it is instance uniform block.
const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
return interfaceBlock && variableType.isInterfaceBlock();
}
return false;
}
const char *GetHLSLAtomicFunctionStringAndLeftParenthesis(TOperator op) const char *GetHLSLAtomicFunctionStringAndLeftParenthesis(TOperator op)
{ {
switch (op) switch (op)
...@@ -1683,7 +1707,11 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1683,7 +1707,11 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
node->getLeft()->getType().getInterfaceBlock(); node->getLeft()->getType().getInterfaceBlock();
const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
const TField *field = interfaceBlock->fields()[index->getIConst(0)]; const TField *field = interfaceBlock->fields()[index->getIConst(0)];
if (structInStd140UniformBlock) bool instanceUniformBlock = IsInstanceUniformBlock(node->getLeft());
if (structInStd140UniformBlock ||
(instanceUniformBlock &&
mResourcesHLSL->shouldTranslateUniformBlockToStructuredBuffer(
*interfaceBlock)))
{ {
out << "_"; out << "_";
} }
......
...@@ -656,16 +656,29 @@ TString ResourcesHLSL::uniformBlocksHeader( ...@@ -656,16 +656,29 @@ TString ResourcesHLSL::uniformBlocksHeader(
// In order to avoid compile performance issue, translate uniform block to structured // In order to avoid compile performance issue, translate uniform block to structured
// buffer. anglebug.com/3682. // buffer. anglebug.com/3682.
// TODO(anglebug.com/4205): Support uniform block with an instance name. if (shouldTranslateUniformBlockToStructuredBuffer(interfaceBlock))
if (instanceVariable == nullptr &&
shouldTranslateUniformBlockToStructuredBuffer(interfaceBlock))
{ {
unsigned int structuredBufferRegister = mSRVRegister; unsigned int structuredBufferRegister = mSRVRegister;
interfaceBlocks += if (instanceVariable != nullptr && instanceVariable->getType().isArray())
uniformBlockWithOneLargeArrayMemberString(interfaceBlock, structuredBufferRegister); {
unsigned int instanceArraySize =
instanceVariable->getType().getOutermostArraySize();
for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
{
interfaceBlocks += uniformBlockWithOneLargeArrayMemberString(
interfaceBlock, instanceVariable, structuredBufferRegister + arrayIndex,
arrayIndex);
}
mSRVRegister += instanceArraySize;
}
else
{
interfaceBlocks += uniformBlockWithOneLargeArrayMemberString(
interfaceBlock, instanceVariable, structuredBufferRegister, GL_INVALID_INDEX);
mSRVRegister += 1u;
}
mUniformBlockRegisterMap[interfaceBlock.name().data()] = structuredBufferRegister; mUniformBlockRegisterMap[interfaceBlock.name().data()] = structuredBufferRegister;
mUniformBlockUseStructuredBufferMap[interfaceBlock.name().data()] = true; mUniformBlockUseStructuredBufferMap[interfaceBlock.name().data()] = true;
mSRVRegister += 1u;
continue; continue;
} }
...@@ -758,7 +771,9 @@ TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock, ...@@ -758,7 +771,9 @@ TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock,
TString ResourcesHLSL::uniformBlockWithOneLargeArrayMemberString( TString ResourcesHLSL::uniformBlockWithOneLargeArrayMemberString(
const TInterfaceBlock &interfaceBlock, const TInterfaceBlock &interfaceBlock,
unsigned int registerIndex) const TVariable *instanceVariable,
unsigned int registerIndex,
unsigned int arrayIndex)
{ {
TString hlsl, typeString; TString hlsl, typeString;
...@@ -766,8 +781,18 @@ TString ResourcesHLSL::uniformBlockWithOneLargeArrayMemberString( ...@@ -766,8 +781,18 @@ TString ResourcesHLSL::uniformBlockWithOneLargeArrayMemberString(
const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
typeString = InterfaceBlockFieldTypeString(field, blockStorage, true); typeString = InterfaceBlockFieldTypeString(field, blockStorage, true);
hlsl += "StructuredBuffer <" + typeString + "> " + Decorate(field.name()) + " : register(t" + if (instanceVariable != nullptr)
str(registerIndex) + ");\n"; {
hlsl += "StructuredBuffer <" + typeString + "> " +
InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + "_" +
Decorate(field.name()) + +" : register(t" + str(registerIndex) + ");\n";
}
else
{
hlsl += "StructuredBuffer <" + typeString + "> " + Decorate(field.name()) +
" : register(t" + str(registerIndex) + ");\n";
}
return hlsl; return hlsl;
} }
......
...@@ -68,6 +68,7 @@ class ResourcesHLSL : angle::NonCopyable ...@@ -68,6 +68,7 @@ class ResourcesHLSL : angle::NonCopyable
unsigned int getReadonlyImage2DRegisterIndex() const { return mReadonlyImage2DRegisterIndex; } unsigned int getReadonlyImage2DRegisterIndex() const { return mReadonlyImage2DRegisterIndex; }
unsigned int getImage2DRegisterIndex() const { return mImage2DRegisterIndex; } unsigned int getImage2DRegisterIndex() const { return mImage2DRegisterIndex; }
bool shouldTranslateUniformBlockToStructuredBuffer(const TInterfaceBlock &interfaceBlock);
private: private:
TString uniformBlockString(const TInterfaceBlock &interfaceBlock, TString uniformBlockString(const TInterfaceBlock &interfaceBlock,
...@@ -75,7 +76,9 @@ class ResourcesHLSL : angle::NonCopyable ...@@ -75,7 +76,9 @@ class ResourcesHLSL : angle::NonCopyable
unsigned int registerIndex, unsigned int registerIndex,
unsigned int arrayIndex); unsigned int arrayIndex);
TString uniformBlockWithOneLargeArrayMemberString(const TInterfaceBlock &interfaceBlock, TString uniformBlockWithOneLargeArrayMemberString(const TInterfaceBlock &interfaceBlock,
unsigned int registerIndex); const TVariable *instanceVariable,
unsigned int registerIndex,
unsigned int arrayIndex);
TString shaderStorageBlockString(const TInterfaceBlock &interfaceBlock, TString shaderStorageBlockString(const TInterfaceBlock &interfaceBlock,
const TVariable *instanceVariable, const TVariable *instanceVariable,
...@@ -125,7 +128,6 @@ class ResourcesHLSL : angle::NonCopyable ...@@ -125,7 +128,6 @@ class ResourcesHLSL : angle::NonCopyable
const HLSLRWTextureGroup textureGroup, const HLSLRWTextureGroup textureGroup,
const TVector<const TVariable *> &group, const TVector<const TVariable *> &group,
unsigned int *groupTextureRegisterIndex); unsigned int *groupTextureRegisterIndex);
bool shouldTranslateUniformBlockToStructuredBuffer(const TInterfaceBlock &interfaceBlock);
unsigned int mUniformRegister; unsigned int mUniformRegister;
unsigned int mUniformBlockRegister; unsigned int mUniformBlockRegister;
......
...@@ -1744,6 +1744,252 @@ TEST_P(UniformBufferTest, UniformBlockWithOneLargeStructArray) ...@@ -1744,6 +1744,252 @@ TEST_P(UniformBufferTest, UniformBlockWithOneLargeStructArray)
} }
} }
// Test instance uniform buffer with large struct array member, where the struct
// itself contains a mat4 member.
TEST_P(UniformBufferTest, InstanceUniformBlockWithOneLargeStructArray)
{
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]; } instance;\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 = instance.s[index_x].color[index_y];\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);
glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
glBufferData(GL_UNIFORM_BUFFER, blockSize, nullptr, GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
glUniformBlockBinding(program, uniformBufferIndex, 0);
const GLuint kVectorPerMat = 4;
const GLuint kFloatPerVector = 4;
GLuint kVectorCount = arraySize * kVectorPerMat;
GLuint kFloatCount = kVectorCount * kFloatPerVector;
std::vector<GLfloat> floatData(kFloatCount, 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] = 1.0f;
floatData[4 * i + 3] = 1.0f;
}
glBufferSubData(GL_UNIFORM_BUFFER, 0, kFloatCount * sizeof(GLfloat), floatData.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::blue);
}
for (GLuint i = 0; i < kVectorCount; i++)
{
floatData[4 * i + 1] = 1.0f;
floatData[4 * i + 2] = 0.0f;
}
glBufferSubData(GL_UNIFORM_BUFFER, 0, kFloatCount * sizeof(GLfloat), floatData.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);
}
for (GLuint i = kVectorCount / 4; i < kVectorCount / 2; i++)
{
floatData[4 * i] = 1.0f;
floatData[4 * i + 1] = 0.0f;
}
glBufferSubData(GL_UNIFORM_BUFFER, 0, kFloatCount * sizeof(GLfloat), floatData.data());
drawQuad(program.get(), essl3_shaders::PositionAttrib(), 0.5f);
for (GLuint i = 0; i < kPositionCount; i++)
{
if (positionToTest[i][1] > 31 && positionToTest[i][1] < 64)
{
EXPECT_PIXEL_COLOR_EQ(positionToTest[i][0], positionToTest[i][1], GLColor::red);
}
else
{
EXPECT_PIXEL_COLOR_EQ(positionToTest[i][0], positionToTest[i][1], GLColor::green);
}
}
}
// Test instance array uniform buffer with large struct array member, where the
// struct itself contains a mat4 member.
TEST_P(UniformBufferTest, InstanceArrayUniformBlockWithOneLargeStructArray)
{
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]; } instance[2];\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 = instance[0].s[index_x].color[index_y] + "
"instance[1].s[index_x].color[index_y];\n"
"}\n";
GLint blockSize0, blockSize1;
ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
GLint uniformBufferIndex0 = glGetUniformBlockIndex(program, "buffer[0]");
GLint uniformBufferIndex1 = glGetUniformBlockIndex(program, "buffer[1]");
glGetActiveUniformBlockiv(program, uniformBufferIndex0, GL_UNIFORM_BLOCK_DATA_SIZE,
&blockSize0);
glGetActiveUniformBlockiv(program, uniformBufferIndex1, GL_UNIFORM_BLOCK_DATA_SIZE,
&blockSize1);
glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
glBufferData(GL_UNIFORM_BUFFER, blockSize0, nullptr, GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
glUniformBlockBinding(program, uniformBufferIndex0, 0);
const GLuint kVectorPerMat = 4;
const GLuint kFloatPerVector = 4;
GLuint kVectorCount = arraySize * kVectorPerMat;
GLuint kFloatCount = kVectorCount * kFloatPerVector;
std::vector<GLfloat> floatData0(kFloatCount, 0.0f);
std::vector<GLfloat> floatData1(kFloatCount, 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++)
{
floatData0[4 * i + 2] = 1.0f;
floatData0[4 * i + 3] = 1.0f;
}
glBufferSubData(GL_UNIFORM_BUFFER, 0, kFloatCount * sizeof(GLfloat), floatData0.data());
GLBuffer uniformBuffer1;
glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffer1);
glBufferData(GL_UNIFORM_BUFFER, blockSize1, nullptr, GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 1, uniformBuffer1);
glUniformBlockBinding(program, uniformBufferIndex0, 1);
for (GLuint i = 0; i < kVectorCount; i++)
{
floatData1[4 * i + 1] = 1.0f;
}
glBufferSubData(GL_UNIFORM_BUFFER, 0, kFloatCount * 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::cyan);
}
glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
for (GLuint i = 0; i < kVectorCount; i++)
{
floatData0[4 * i] = 1.0f;
floatData0[4 * i + 2] = 0.0f;
}
glBufferSubData(GL_UNIFORM_BUFFER, 0, kFloatCount * sizeof(GLfloat), floatData0.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::yellow);
}
glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffer1);
for (GLuint i = kVectorCount / 4; i < kVectorCount / 2; i++)
{
floatData1[4 * i + 2] = 1.0f;
floatData1[4 * i + 1] = 0.0f;
}
glBufferSubData(GL_UNIFORM_BUFFER, 0, kFloatCount * sizeof(GLfloat), floatData1.data());
drawQuad(program.get(), essl3_shaders::PositionAttrib(), 0.5f);
for (GLuint i = 0; i < kPositionCount; i++)
{
if (positionToTest[i][1] > 31 && positionToTest[i][1] < 64)
{
EXPECT_PIXEL_COLOR_EQ(positionToTest[i][0], positionToTest[i][1], GLColor::magenta);
}
else
{
EXPECT_PIXEL_COLOR_EQ(positionToTest[i][0], positionToTest[i][1], GLColor::yellow);
}
}
}
// Test uniform buffer with large struct array member, where the struct itself contains // Test uniform buffer with large struct array member, where the struct itself contains
// a mat4 member and a float member. // a mat4 member and a float member.
TEST_P(UniformBufferTest, UniformBlockWithOneLargeMixStructArray) TEST_P(UniformBufferTest, UniformBlockWithOneLargeMixStructArray)
......
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