Commit 3de2703d by Olli Etuaho Committed by Commit Bot

Fix handling matrix qualifiers on block members

Individual block member row_major/column_major layout qualifiers may override the qualifiers set on the block. During parsing, this was already being handled correctly, so that the qualifier is resolved for each block member and recorded for each TField / InterfaceBlockField. Now we always write the qualifiers on a per-member granularity to the output GLSL shaders, so that the native driver gets the correct per-member qualifiers. This replaces earlier behavior where the matrix qualifiers were only written per-block. Also only use qualifiers from individual members in block layout. Since the block-level qualifier information is no longer used after parsing, it is no longer kept in the AST. A dummy value is still set to the InterfaceBlock structs exposed through the ShaderVars interface, since that has existing usage in Chromium that needs to be removed before the field can be removed. Some AMD OpenGL drivers don't seem to handle matrix layout qualifiers correctly, so most of the added tests need to be skipped for AMD GL. On NVIDIA and Intel the tests pass. BUG=angleproject:2271 TEST=angle_unittests, angle_end2end_tests, dEQP-GLES31.functional.program_interface_query.uniform.matrix* Change-Id: I1baa7a633bc2da548743c2190cb72db491b5227a Reviewed-on: https://chromium-review.googlesource.com/800174Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent bf0a40bb
......@@ -25,7 +25,7 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 190
#define ANGLE_SH_VERSION 191
enum ShShaderSpec
{
......
......@@ -270,7 +270,11 @@ struct InterfaceBlock
std::string instanceName;
unsigned int arraySize;
BlockLayoutType layout;
// Deprecated. Matrix packing should only be queried from individual fields of the block.
// TODO(oetuaho): Remove this once it is no longer used in Chromium.
bool isRowMajorLayout;
int binding;
bool staticUse;
BlockType blockType;
......
......@@ -666,7 +666,8 @@ void CollectVariablesTraverser::recordInterfaceBlock(const TType &interfaceBlock
if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM ||
interfaceBlock->blockType == BlockType::BLOCK_BUFFER)
{
interfaceBlock->isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
// TODO(oetuaho): Remove setting isRowMajorLayout.
interfaceBlock->isRowMajorLayout = false;
interfaceBlock->binding = blockType->blockBinding();
interfaceBlock->layout = GetBlockLayoutType(blockType->blockStorage());
}
......
......@@ -1221,29 +1221,10 @@ void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfa
break;
}
out << ", ";
if (interfaceBlock->blockBinding() > 0)
{
out << "binding = " << interfaceBlock->blockBinding();
out << ", ";
}
switch (interfaceBlock->matrixPacking())
{
case EmpUnspecified:
case EmpColumnMajor:
// Default matrix packing is column major.
out << "column_major";
break;
case EmpRowMajor:
out << "row_major";
break;
default:
UNREACHABLE();
break;
out << "binding = " << interfaceBlock->blockBinding();
}
out << ") ";
......@@ -1255,9 +1236,30 @@ void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBloc
out << hashName(TName(interfaceBlock->name())) << "{\n";
const TFieldList &fields = interfaceBlock->fields();
for (size_t i = 0; i < fields.size(); ++i)
for (const TField *field : fields)
{
const TField *field = fields[i];
if (field->type()->isMatrix() || field->type()->isStructureContainingMatrices())
{
out << "layout(";
switch (field->type()->getLayoutQualifier().matrixPacking)
{
case EmpUnspecified:
case EmpColumnMajor:
// Default matrix packing is column major.
out << "column_major";
break;
case EmpRowMajor:
out << "row_major";
break;
default:
UNREACHABLE();
break;
}
out << ") ";
}
if (writeVariablePrecision(field->type()->getPrecision()))
out << " ";
out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
......
......@@ -437,6 +437,11 @@ bool TType::isStructureContainingArrays() const
return mStructure ? mStructure->containsArrays() : false;
}
bool TType::isStructureContainingMatrices() const
{
return mStructure ? mStructure->containsMatrices() : false;
}
bool TType::isStructureContainingType(TBasicType t) const
{
return mStructure ? mStructure->containsType(t) : false;
......@@ -930,6 +935,17 @@ bool TFieldListCollection::containsArrays() const
return false;
}
bool TFieldListCollection::containsMatrices() const
{
for (const auto *field : *mFields)
{
const TType *fieldType = field->type();
if (fieldType->isMatrix() || fieldType->isStructureContainingMatrices())
return true;
}
return false;
}
bool TFieldListCollection::containsType(TBasicType type) const
{
for (const auto *field : *mFields)
......@@ -1032,7 +1048,6 @@ TInterfaceBlock::TInterfaceBlock(const TString *name,
mName(name),
mInstanceName(instanceName),
mBlockStorage(layoutQualifier.blockStorage),
mMatrixPacking(layoutQualifier.matrixPacking),
mBinding(layoutQualifier.binding)
{
}
......
......@@ -55,6 +55,7 @@ class TFieldListCollection : angle::NonCopyable
const TFieldList &fields() const { return *mFields; }
bool containsArrays() const;
bool containsMatrices() const;
bool containsType(TBasicType t) const;
bool containsSamplers() const;
......@@ -92,15 +93,15 @@ class TInterfaceBlock : public TFieldListCollection
const TString &instanceName() const { return *mInstanceName; }
bool hasInstanceName() const { return mInstanceName != nullptr; }
TLayoutBlockStorage blockStorage() const { return mBlockStorage; }
TLayoutMatrixPacking matrixPacking() const { return mMatrixPacking; }
int blockBinding() const { return mBinding; }
private:
const TString *mName;
const TString *mInstanceName; // for interface block instance names
TLayoutBlockStorage mBlockStorage;
TLayoutMatrixPacking mMatrixPacking;
int mBinding;
// Note that we only record matrix packing on a per-field granularity.
};
//
......@@ -281,6 +282,7 @@ class TType
bool isNamelessStruct() const;
bool isStructureContainingArrays() const;
bool isStructureContainingMatrices() const;
bool isStructureContainingType(TBasicType t) const;
bool isStructureContainingSamplers() const;
......
......@@ -28,6 +28,13 @@ bool IsRowMajorLayout(const ShaderVariable &var)
}
template <typename VarT>
void GetUniformBlockInfo(const std::vector<VarT> &fields,
const std::string &prefix,
sh::BlockLayoutEncoder *encoder,
bool inRowMajorLayout,
BlockLayoutMap *blockInfoOut);
template <typename VarT>
void GetUniformBlockStructMemberInfo(const std::vector<VarT> &fields,
const std::string &fieldName,
sh::BlockLayoutEncoder *encoder,
......@@ -71,7 +78,7 @@ void GetUniformBlockArrayOfArraysMemberInfo(const VarT &field,
unsigned int arrayNestingIndex,
const std::string &arrayName,
sh::BlockLayoutEncoder *encoder,
bool inRowMajorLayout,
bool isRowMajorMatrix,
BlockLayoutMap *blockInfoOut)
{
const unsigned int currentArraySize = field.getNestedArraySize(arrayNestingIndex);
......@@ -81,14 +88,61 @@ void GetUniformBlockArrayOfArraysMemberInfo(const VarT &field,
if (arrayNestingIndex + 2u < field.arraySizes.size())
{
GetUniformBlockArrayOfArraysMemberInfo(field, arrayNestingIndex + 1u, elementName,
encoder, inRowMajorLayout, blockInfoOut);
encoder, isRowMajorMatrix, blockInfoOut);
}
else
{
std::vector<unsigned int> innermostArraySize(
1u, field.getNestedArraySize(arrayNestingIndex + 1u));
(*blockInfoOut)[elementName] =
encoder->encodeType(field.type, innermostArraySize, inRowMajorLayout);
encoder->encodeType(field.type, innermostArraySize, isRowMajorMatrix);
}
}
}
template <typename VarT>
void GetUniformBlockInfo(const std::vector<VarT> &fields,
const std::string &prefix,
sh::BlockLayoutEncoder *encoder,
bool inRowMajorLayout,
BlockLayoutMap *blockInfoOut)
{
for (const VarT &field : fields)
{
// Skip samplers. On Vulkan we use this for the default uniform block, so samplers may be
// included.
if (gl::IsSamplerType(field.type))
{
continue;
}
const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field));
if (field.isStruct())
{
if (field.isArray())
{
GetUniformBlockStructArrayMemberInfo(field, 0u, fieldName, encoder, rowMajorLayout,
blockInfoOut);
}
else
{
GetUniformBlockStructMemberInfo(field.fields, fieldName, encoder, rowMajorLayout,
blockInfoOut);
}
}
else if (field.isArrayOfArrays())
{
GetUniformBlockArrayOfArraysMemberInfo(field, 0u, fieldName, encoder,
rowMajorLayout && gl::IsMatrixType(field.type),
blockInfoOut);
}
else
{
(*blockInfoOut)[fieldName] = encoder->encodeType(
field.type, field.arraySizes, rowMajorLayout && gl::IsMatrixType(field.type));
}
}
}
......@@ -212,70 +266,25 @@ void Std140BlockEncoder::advanceOffset(GLenum type,
}
}
template <typename VarT>
void GetUniformBlockInfo(const std::vector<VarT> &fields,
void GetUniformBlockInfo(const std::vector<InterfaceBlockField> &fields,
const std::string &prefix,
sh::BlockLayoutEncoder *encoder,
bool inRowMajorLayout,
BlockLayoutMap *blockInfoOut)
{
for (const VarT &field : fields)
{
// Skip samplers. On Vulkan we use this for the default uniform block, so samplers may be
// included.
if (gl::IsSamplerType(field.type))
{
continue;
}
const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
if (field.isStruct())
{
bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field));
// Matrix packing is always recorded in individual fields, so they'll set the row major layout
// flag to true if needed.
GetUniformBlockInfo(fields, prefix, encoder, false, blockInfoOut);
}
if (field.isArray())
{
GetUniformBlockStructArrayMemberInfo(field, 0u, fieldName, encoder, rowMajorLayout,
blockInfoOut);
}
else
{
GetUniformBlockStructMemberInfo(field.fields, fieldName, encoder, rowMajorLayout,
blockInfoOut);
}
}
else if (field.isArrayOfArrays())
{
bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout);
GetUniformBlockArrayOfArraysMemberInfo(field, 0u, fieldName, encoder, isRowMajorMatrix,
blockInfoOut);
}
else
{
bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout);
(*blockInfoOut)[fieldName] =
encoder->encodeType(field.type, field.arraySizes, isRowMajorMatrix);
}
}
void GetUniformBlockInfo(const std::vector<Uniform> &uniforms,
const std::string &prefix,
sh::BlockLayoutEncoder *encoder,
BlockLayoutMap *blockInfoOut)
{
// Matrix packing is always recorded in individual fields, so they'll set the row major layout
// flag to true if needed.
GetUniformBlockInfo(uniforms, prefix, encoder, false, blockInfoOut);
}
template void GetUniformBlockInfo(const std::vector<InterfaceBlockField> &,
const std::string &,
sh::BlockLayoutEncoder *,
bool,
BlockLayoutMap *);
template void GetUniformBlockInfo(const std::vector<Uniform> &,
const std::string &,
sh::BlockLayoutEncoder *,
bool,
BlockLayoutMap *);
template void GetUniformBlockInfo(const std::vector<ShaderVariable> &,
const std::string &,
sh::BlockLayoutEncoder *,
bool,
BlockLayoutMap *);
} // namespace sh
......@@ -131,13 +131,16 @@ class Std140BlockEncoder : public BlockLayoutEncoder
using BlockLayoutMap = std::map<std::string, BlockMemberInfo>;
// Only valid to call with ShaderVariable, InterfaceBlockField and Uniform.
template <typename VarT>
void GetUniformBlockInfo(const std::vector<VarT> &fields,
void GetUniformBlockInfo(const std::vector<InterfaceBlockField> &fields,
const std::string &prefix,
sh::BlockLayoutEncoder *encoder,
bool inRowMajorLayout,
BlockLayoutMap *blockLayoutMap);
BlockLayoutMap *blockInfoOut);
// Used for laying out the default uniform block on the Vulkan backend.
void GetUniformBlockInfo(const std::vector<Uniform> &uniforms,
const std::string &prefix,
sh::BlockLayoutEncoder *encoder,
BlockLayoutMap *blockInfoOut);
} // namespace sh
......
......@@ -2451,7 +2451,6 @@ bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog,
return false;
}
if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout ||
vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout ||
vertexInterfaceBlock.binding != fragmentInterfaceBlock.binding)
{
infoLog << "Layout qualifiers differ for interface block '" << blockName
......
......@@ -252,7 +252,7 @@ size_t UniformBlockInfo::getBlockInfo(const sh::InterfaceBlock &interfaceBlock)
}
sh::GetUniformBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder,
interfaceBlock.isRowMajorLayout, &mBlockLayout);
&mBlockLayout);
return encoder->getBlockSize();
}
......
......@@ -39,7 +39,7 @@ gl::Error InitDefaultUniformBlock(const gl::Context *context,
}
sh::Std140BlockEncoder blockEncoder;
sh::GetUniformBlockInfo(uniforms, "", &blockEncoder, false, blockLayoutMapOut);
sh::GetUniformBlockInfo(uniforms, "", &blockEncoder, blockLayoutMapOut);
size_t blockSize = blockEncoder.getBlockSize();
......
......@@ -319,7 +319,6 @@ TEST_F(CollectVertexVariablesTest, SimpleInterfaceBlock)
const InterfaceBlock &interfaceBlock = interfaceBlocks[0];
EXPECT_EQ(0u, interfaceBlock.arraySize);
EXPECT_FALSE(interfaceBlock.isRowMajorLayout);
EXPECT_EQ(BLOCKLAYOUT_SHARED, interfaceBlock.layout);
EXPECT_EQ("b", interfaceBlock.name);
EXPECT_TRUE(interfaceBlock.staticUse);
......@@ -355,7 +354,6 @@ TEST_F(CollectVertexVariablesTest, SimpleInstancedInterfaceBlock)
const InterfaceBlock &interfaceBlock = interfaceBlocks[0];
EXPECT_EQ(0u, interfaceBlock.arraySize);
EXPECT_FALSE(interfaceBlock.isRowMajorLayout);
EXPECT_EQ(BLOCKLAYOUT_SHARED, interfaceBlock.layout);
EXPECT_EQ("b", interfaceBlock.name);
EXPECT_EQ("blockInstance", interfaceBlock.instanceName);
......@@ -393,7 +391,6 @@ TEST_F(CollectVertexVariablesTest, StructInterfaceBlock)
const InterfaceBlock &interfaceBlock = interfaceBlocks[0];
EXPECT_EQ(0u, interfaceBlock.arraySize);
EXPECT_FALSE(interfaceBlock.isRowMajorLayout);
EXPECT_EQ(BLOCKLAYOUT_SHARED, interfaceBlock.layout);
EXPECT_EQ("b", interfaceBlock.name);
EXPECT_EQ(DecorateName("b"), interfaceBlock.mappedName);
......@@ -439,7 +436,6 @@ TEST_F(CollectVertexVariablesTest, StructInstancedInterfaceBlock)
const InterfaceBlock &interfaceBlock = interfaceBlocks[0];
EXPECT_EQ(0u, interfaceBlock.arraySize);
EXPECT_FALSE(interfaceBlock.isRowMajorLayout);
EXPECT_EQ(BLOCKLAYOUT_SHARED, interfaceBlock.layout);
EXPECT_EQ("b", interfaceBlock.name);
EXPECT_EQ(DecorateName("b"), interfaceBlock.mappedName);
......@@ -486,7 +482,6 @@ TEST_F(CollectVertexVariablesTest, NestedStructRowMajorInterfaceBlock)
const InterfaceBlock &interfaceBlock = interfaceBlocks[0];
EXPECT_EQ(0u, interfaceBlock.arraySize);
EXPECT_TRUE(interfaceBlock.isRowMajorLayout);
EXPECT_EQ(BLOCKLAYOUT_SHARED, interfaceBlock.layout);
EXPECT_EQ("b", interfaceBlock.name);
EXPECT_EQ(DecorateName("b"), interfaceBlock.mappedName);
......@@ -795,7 +790,6 @@ TEST_F(CollectHashedVertexVariablesTest, InstancedInterfaceBlock)
const InterfaceBlock &interfaceBlock = interfaceBlocks[0];
EXPECT_EQ(0u, interfaceBlock.arraySize);
EXPECT_FALSE(interfaceBlock.isRowMajorLayout);
EXPECT_EQ(BLOCKLAYOUT_SHARED, interfaceBlock.layout);
EXPECT_EQ("blockName", interfaceBlock.name);
EXPECT_EQ("blockInstance", interfaceBlock.instanceName);
......
......@@ -538,8 +538,6 @@
1442 OPENGL : dEQP-GLES31.functional.program_interface_query.program_output.* = FAIL
1442 OPENGL : dEQP-GLES31.functional.program_interface_query.shader_storage_block.* = FAIL
1442 OPENGL : dEQP-GLES31.functional.program_interface_query.transform_feedback_varying.* = FAIL
1442 OPENGL : dEQP-GLES31.functional.program_interface_query.uniform.matrix_row_major.* = FAIL
1442 OPENGL : dEQP-GLES31.functional.program_interface_query.uniform.matrix_stride.* = FAIL
1442 OPENGL : dEQP-GLES31.functional.program_interface_query.uniform.referenced_by_shader.* = FAIL
1442 OPENGL : dEQP-GLES31.functional.program_interface_query.uniform.random.* = FAIL
1442 OPENGL : dEQP-GLES31.functional.program_interface_query.uniform_block.resource_list.block_array = FAIL
......
......@@ -1196,6 +1196,200 @@ TEST_P(UniformBufferTest, DetachShaders)
glDeleteProgram(program);
}
// Test a uniform block where the whole block is set as row-major.
TEST_P(UniformBufferTest, Std140UniformBlockWithRowMajorQualifier)
{
// AMD OpenGL driver doesn't seem to apply the row-major qualifier right.
// http://anglebug.com/2273
ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
const std::string &fragmentShader =
R"(#version 300 es
precision highp float;
out vec4 my_FragColor;
layout(std140, row_major) uniform matrixBuffer
{
mat2 m;
} buffer;
void main()
{
// Vector constructor accesses elements in column-major order.
my_FragColor = vec4(buffer.m);
})";
ANGLE_GL_PROGRAM(program, mVertexShaderSource, fragmentShader);
GLint uniformBufferIndex = glGetUniformBlockIndex(program, "matrixBuffer");
glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
const GLsizei kElementsPerMatrix = 8; // Each mat2 row gets padded into a vec4.
const GLsizei kBytesPerElement = 4;
const GLsizei kDataSize = kElementsPerMatrix * kBytesPerElement;
std::vector<GLubyte> v(kDataSize, 0);
float *vAsFloat = reinterpret_cast<float *>(v.data());
vAsFloat[0u] = 1.0f;
vAsFloat[1u] = 128.0f / 255.0f;
vAsFloat[4u] = 64.0f / 255.0f;
vAsFloat[5u] = 32.0f / 255.0f;
glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
glUniformBlockBinding(program, uniformBufferIndex, 0);
drawQuad(program.get(), "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(255, 64, 128, 32), 5);
}
// Test a uniform block where an individual matrix field is set as row-major whereas the whole block
// is set as column-major.
TEST_P(UniformBufferTest, Std140UniformBlockWithPerMemberRowMajorQualifier)
{
// AMD OpenGL driver doesn't seem to apply the row-major qualifier right.
// http://anglebug.com/2273
ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
const std::string &fragmentShader =
R"(#version 300 es
precision highp float;
out vec4 my_FragColor;
layout(std140, column_major) uniform matrixBuffer
{
layout(row_major) mat2 m;
} buffer;
void main()
{
// Vector constructor accesses elements in column-major order.
my_FragColor = vec4(buffer.m);
})";
ANGLE_GL_PROGRAM(program, mVertexShaderSource, fragmentShader);
GLint uniformBufferIndex = glGetUniformBlockIndex(program, "matrixBuffer");
glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
const GLsizei kElementsPerMatrix = 8; // Each mat2 row gets padded into a vec4.
const GLsizei kBytesPerElement = 4;
const GLsizei kDataSize = kElementsPerMatrix * kBytesPerElement;
std::vector<GLubyte> v(kDataSize, 0);
float *vAsFloat = reinterpret_cast<float *>(v.data());
vAsFloat[0u] = 1.0f;
vAsFloat[1u] = 128.0f / 255.0f;
vAsFloat[4u] = 64.0f / 255.0f;
vAsFloat[5u] = 32.0f / 255.0f;
glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
glUniformBlockBinding(program, uniformBufferIndex, 0);
drawQuad(program.get(), "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(255, 64, 128, 32), 5);
}
// Test a uniform block where an individual matrix field is set as column-major whereas the whole
// block is set as row-major.
TEST_P(UniformBufferTest, Std140UniformBlockWithPerMemberColumnMajorQualifier)
{
const std::string &fragmentShader =
R"(#version 300 es
precision highp float;
out vec4 my_FragColor;
layout(std140, row_major) uniform matrixBuffer
{
// 2 columns, 3 rows.
layout(column_major) mat2x3 m;
} buffer;
void main()
{
// Vector constructor accesses elements in column-major order.
my_FragColor = vec4(buffer.m);
})";
ANGLE_GL_PROGRAM(program, mVertexShaderSource, fragmentShader);
GLint uniformBufferIndex = glGetUniformBlockIndex(program, "matrixBuffer");
glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
const GLsizei kElementsPerMatrix = 8; // Each mat2x3 column gets padded into a vec4.
const GLsizei kBytesPerElement = 4;
const GLsizei kDataSize = kElementsPerMatrix * kBytesPerElement;
std::vector<GLubyte> v(kDataSize, 0);
float *vAsFloat = reinterpret_cast<float *>(v.data());
vAsFloat[0u] = 1.0f;
vAsFloat[1u] = 192.0f / 255.0f;
vAsFloat[2u] = 128.0f / 255.0f;
vAsFloat[4u] = 96.0f / 255.0f;
vAsFloat[5u] = 64.0f / 255.0f;
vAsFloat[6u] = 32.0f / 255.0f;
glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
glUniformBlockBinding(program, uniformBufferIndex, 0);
drawQuad(program.get(), "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(255, 192, 128, 96), 5);
}
// Test a uniform block where a struct field is set as row-major.
TEST_P(UniformBufferTest, Std140UniformBlockWithRowMajorQualifierOnStruct)
{
// AMD OpenGL driver doesn't seem to apply the row-major qualifier right.
// http://anglebug.com/2273
ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
const std::string &fragmentShader =
R"(#version 300 es
precision highp float;
out vec4 my_FragColor;
struct S
{
mat2 m;
};
layout(std140) uniform matrixBuffer
{
layout(row_major) S s;
} buffer;
void main()
{
// Vector constructor accesses elements in column-major order.
my_FragColor = vec4(buffer.s.m);
})";
ANGLE_GL_PROGRAM(program, mVertexShaderSource, fragmentShader);
GLint uniformBufferIndex = glGetUniformBlockIndex(program, "matrixBuffer");
glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
const GLsizei kElementsPerMatrix = 8; // Each mat2 row gets padded into a vec4.
const GLsizei kBytesPerElement = 4;
const GLsizei kDataSize = kElementsPerMatrix * kBytesPerElement;
std::vector<GLubyte> v(kDataSize, 0);
float *vAsFloat = reinterpret_cast<float *>(v.data());
vAsFloat[0u] = 1.0f;
vAsFloat[1u] = 128.0f / 255.0f;
vAsFloat[4u] = 64.0f / 255.0f;
vAsFloat[5u] = 32.0f / 255.0f;
glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
glUniformBlockBinding(program, uniformBufferIndex, 0);
drawQuad(program.get(), "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(255, 64, 128, 32), 5);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(UniformBufferTest,
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