Commit 15214423 by Qin Jiajia Committed by Commit Bot

ES31: Add top_level_array_stride support

Bug: angleproject:1920 Change-Id: Id18c6cc1bb840c05f73a019156c462886f01d9eb Reviewed-on: https://chromium-review.googlesource.com/c/1396745 Commit-Queue: Jiajia Qin <jiajia.qin@intel.com> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 85ca1895
......@@ -26,7 +26,7 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 204
#define ANGLE_SH_VERSION 205
enum ShShaderSpec
{
......
......@@ -71,6 +71,12 @@ struct ShaderVariable
bool isArrayOfArrays() const { return arraySizes.size() >= 2u; }
bool isArray() const { return !arraySizes.empty(); }
unsigned int getArraySizeProduct() const;
// Return the inner array size product.
// For example, if there's a variable declared as size 3 array of size 4 array of size 5 array
// of int:
// int a[3][4][5];
// then getInnerArraySizeProduct of a would be 4*5.
unsigned int getInnerArraySizeProduct() const;
// Array size 0 means not an array when passed to or returned from these functions.
// Note that setArraySize() is deprecated and should not be used inside ANGLE.
......
......@@ -107,6 +107,16 @@ void ShaderVariable::setArraySize(unsigned int size)
}
}
unsigned int ShaderVariable::getInnerArraySizeProduct() const
{
unsigned int arraySizeProduct = 1u;
for (size_t index = 1; index < arraySizes.size(); ++index)
{
arraySizeProduct *= getNestedArraySize(index);
}
return arraySizeProduct;
}
unsigned int ShaderVariable::getArraySizeProduct() const
{
return gl::ArraySizeProduct(arraySizes);
......
......@@ -42,7 +42,7 @@ class BlockLayoutMapVisitor : public BlockEncoderVisitor
template <typename VarT>
void GetInterfaceBlockInfo(const std::vector<VarT> &fields,
const std::string &prefix,
sh::BlockLayoutEncoder *encoder,
BlockLayoutEncoder *encoder,
bool inRowMajorLayout,
BlockLayoutMap *blockInfoOut)
{
......@@ -74,7 +74,6 @@ void TraverseStructArrayVariable(const ShaderVariable &variable,
for (unsigned int arrayElement = 0u; arrayElement < count; ++arrayElement)
{
visitor->enterArrayElement(variable, arrayElement);
ShaderVariable elementVar = variable;
elementVar.indexIntoArray(arrayElement);
......@@ -188,6 +187,19 @@ BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type,
return memberInfo;
}
size_t BlockLayoutEncoder::getShaderVariableSize(const ShaderVariable &structVar, bool isRowMajor)
{
size_t currentOffset = mCurrentOffset;
mCurrentOffset = 0;
BlockEncoderVisitor visitor("", "", this);
enterAggregateType(structVar);
TraverseShaderVariables(structVar.fields, isRowMajor, &visitor);
exitAggregateType(structVar);
size_t structVarSize = getCurrentOffset();
mCurrentOffset = currentOffset;
return structVarSize;
}
// static
size_t BlockLayoutEncoder::GetBlockRegister(const BlockMemberInfo &info)
{
......@@ -323,7 +335,7 @@ size_t Std430BlockEncoder::getTypeBaseAlignment(GLenum type, bool isRowMajorMatr
void GetInterfaceBlockInfo(const std::vector<InterfaceBlockField> &fields,
const std::string &prefix,
sh::BlockLayoutEncoder *encoder,
BlockLayoutEncoder *encoder,
BlockLayoutMap *blockInfoOut)
{
// Matrix packing is always recorded in individual fields, so they'll set the row major layout
......@@ -333,7 +345,7 @@ void GetInterfaceBlockInfo(const std::vector<InterfaceBlockField> &fields,
void GetUniformBlockInfo(const std::vector<Uniform> &uniforms,
const std::string &prefix,
sh::BlockLayoutEncoder *encoder,
BlockLayoutEncoder *encoder,
BlockLayoutMap *blockInfoOut)
{
// Matrix packing is always recorded in individual fields, so they'll set the row major layout
......@@ -478,16 +490,62 @@ BlockEncoderVisitor::~BlockEncoderVisitor() = default;
void BlockEncoderVisitor::enterStructAccess(const ShaderVariable &structVar, bool isRowMajor)
{
mStructStackSize++;
if (!mIsTopLevelArrayStrideReady)
{
size_t structSize = mEncoder->getShaderVariableSize(structVar, isRowMajor);
mTopLevelArrayStride *= structSize;
mIsTopLevelArrayStrideReady = true;
}
VariableNameVisitor::enterStructAccess(structVar, isRowMajor);
mEncoder->enterAggregateType(structVar);
}
void BlockEncoderVisitor::exitStructAccess(const ShaderVariable &structVar, bool isRowMajor)
{
mStructStackSize--;
mEncoder->exitAggregateType(structVar);
VariableNameVisitor::exitStructAccess(structVar, isRowMajor);
}
void BlockEncoderVisitor::enterArrayElement(const sh::ShaderVariable &arrayVar,
unsigned int arrayElement)
{
if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
{
// From the ES 3.1 spec "7.3.1.1 Naming Active Resources":
// For an active shader storage block member declared as an array of an aggregate type,
// an entry will be generated only for the first array element, regardless of its type.
// Such block members are referred to as top-level arrays. If the block member is an
// aggregate type, the enumeration rules are then applied recursively.
if (arrayElement == 0)
{
mTopLevelArraySize = arrayVar.getOutermostArraySize();
mTopLevelArrayStride = arrayVar.getInnerArraySizeProduct();
mIsTopLevelArrayStrideReady = false;
}
else
{
mSkipEnabled = true;
}
}
VariableNameVisitor::enterArrayElement(arrayVar, arrayElement);
}
void BlockEncoderVisitor::exitArrayElement(const sh::ShaderVariable &arrayVar,
unsigned int arrayElement)
{
if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
{
mTopLevelArraySize = 1;
mTopLevelArrayStride = 0;
mIsTopLevelArrayStrideReady = true;
mSkipEnabled = false;
}
VariableNameVisitor::exitArrayElement(arrayVar, arrayElement);
}
void BlockEncoderVisitor::visitNamedVariable(const ShaderVariable &variable,
bool isRowMajor,
const std::string &name,
......@@ -501,6 +559,13 @@ void BlockEncoderVisitor::visitNamedVariable(const ShaderVariable &variable,
}
BlockMemberInfo variableInfo =
mEncoder->encodeType(variable.type, innermostArraySize, isRowMajor);
if (!mIsTopLevelArrayStrideReady)
{
ASSERT(mTopLevelArrayStride);
mTopLevelArrayStride *= variableInfo.arrayStride;
mIsTopLevelArrayStrideReady = true;
}
variableInfo.topLevelArrayStride = mTopLevelArrayStride;
encodeVariable(variable, variableInfo, name, mappedName);
}
......
......@@ -84,6 +84,7 @@ class BlockLayoutEncoder
bool isRowMajorMatrix);
size_t getCurrentOffset() const { return mCurrentOffset * kBytesPerComponent; }
size_t getShaderVariableSize(const ShaderVariable &structVar, bool isRowMajor);
// Called when entering/exiting a structure variable.
virtual void enterAggregateType(const ShaderVariable &structVar) = 0;
......@@ -257,6 +258,8 @@ class BlockEncoderVisitor : public VariableNameVisitor
void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) override;
void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) override;
void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override;
void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override;
void visitNamedVariable(const ShaderVariable &variable,
bool isRowMajor,
......@@ -266,10 +269,18 @@ class BlockEncoderVisitor : public VariableNameVisitor
virtual void encodeVariable(const ShaderVariable &variable,
const BlockMemberInfo &variableInfo,
const std::string &name,
const std::string &mappedName) = 0;
const std::string &mappedName)
{}
protected:
int mTopLevelArraySize = 1;
int mTopLevelArrayStride = 0;
bool mIsTopLevelArrayStrideReady = true;
bool mSkipEnabled = false;
private:
BlockLayoutEncoder *mEncoder;
unsigned int mStructStackSize = 0;
};
void TraverseShaderVariable(const ShaderVariable &variable,
......
......@@ -303,7 +303,7 @@ class UniformBlockEncodingVisitor : public sh::VariableNameVisitor
// The purpose of this visitor is to capture the buffer variables in a shader storage block. Each
// new buffer variable is stored in "bufferVariablesOut".
class ShaderStorageBlockVisitor : public sh::VariableNameVisitor
class ShaderStorageBlockVisitor : public sh::BlockEncoderVisitor
{
public:
ShaderStorageBlockVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
......@@ -312,56 +312,13 @@ class ShaderStorageBlockVisitor : public sh::VariableNameVisitor
std::vector<BufferVariable> *bufferVariablesOut,
ShaderType shaderType,
int blockIndex)
: sh::VariableNameVisitor(namePrefix, mappedNamePrefix),
: sh::BlockEncoderVisitor(namePrefix, mappedNamePrefix, &mDummyEncoder),
mGetMemberInfo(getMemberInfo),
mBufferVariablesOut(bufferVariablesOut),
mShaderType(shaderType),
mBlockIndex(blockIndex)
{}
void enterArrayElement(const sh::ShaderVariable &arrayVar, unsigned int arrayElement) override
{
if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
{
// From the ES 3.1 spec "7.3.1.1 Naming Active Resources":
// For an active shader storage block member declared as an array of an aggregate type,
// an entry will be generated only for the first array element, regardless of its type.
// Such block members are referred to as top-level arrays. If the block member is an
// aggregate type, the enumeration rules are then applied recursively.
if (arrayElement == 0)
{
mTopLevelArraySize = arrayVar.getOutermostArraySize();
}
else
{
mSkipEnabled = true;
}
}
sh::VariableNameVisitor::enterArrayElement(arrayVar, arrayElement);
}
void exitArrayElement(const sh::ShaderVariable &arrayVar, unsigned int arrayElement) override
{
if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
{
mTopLevelArraySize = 1;
mSkipEnabled = false;
}
sh::VariableNameVisitor::exitArrayElement(arrayVar, arrayElement);
}
void enterStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
{
mStructStackSize++;
sh::VariableNameVisitor::enterStructAccess(structVar, isRowMajor);
}
void exitStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
{
mStructStackSize--;
sh::VariableNameVisitor::exitStructAccess(structVar, isRowMajor);
}
void visitNamedVariable(const sh::ShaderVariable &variable,
bool isRowMajor,
const std::string &name,
......@@ -405,9 +362,7 @@ class ShaderStorageBlockVisitor : public sh::VariableNameVisitor
std::vector<BufferVariable> *mBufferVariablesOut;
const ShaderType mShaderType;
const int mBlockIndex;
unsigned int mStructStackSize = 0;
int mTopLevelArraySize = 1;
bool mSkipEnabled = false;
sh::DummyBlockEncoder mDummyEncoder;
};
struct ShaderUniformCount
......
......@@ -23,6 +23,7 @@ namespace sh
struct BlockMemberInfo;
struct InterfaceBlock;
struct ShaderVariable;
class BlockEncoderVisitor;
class ShaderVariableVisitor;
struct Uniform;
} // namespace sh
......
......@@ -715,6 +715,8 @@ TEST_P(ProgramInterfaceTestES31, GetBufferVariableProperties)
// Tests the resource property querying for buffer variable in std430 SSBO works correctly.
TEST_P(ProgramInterfaceTestES31, GetStd430BufferVariableProperties)
{
ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsOpenGL());
constexpr char kComputeShaderSource[] =
R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
......@@ -788,11 +790,9 @@ void main()
EXPECT_EQ(0, params[7]); // referenced_by_vertex_shader
EXPECT_EQ(0, params[8]); // referenced_by_fragment_shader
EXPECT_EQ(1, params[9]); // referenced_by_compute_shader
// TODO(jiajia.qin@intel.com): top_level_array_stride is not correctly handled in D3D side.
// http://anglebug.com/1920.
// EXPECT_EQ(0, params[11]); // top_level_array_stride
EXPECT_EQ(1, params[10]); // top_level_array_size
EXPECT_EQ(0, params[11]); // top_level_array_stride
EXPECT_EQ(GL_UNSIGNED_INT, params[12]); // type
index = glGetProgramResourceIndex(program, GL_BUFFER_VARIABLE, "blockIn.s.m");
......@@ -818,15 +818,125 @@ void main()
EXPECT_EQ(0, params[7]); // referenced_by_vertex_shader
EXPECT_EQ(0, params[8]); // referenced_by_fragment_shader
// TODO(jiajia.qin@intel.com): referenced_by_compute_shader and top_level_array_stride are not
// TODO(jiajia.qin@intel.com): referenced_by_compute_shader is not
// correctly handled. http://anglebug.com/1920.
// EXPECT_EQ(1, params[9]); // referenced_by_compute_shader
// EXPECT_EQ(0, params[11]); // top_level_array_stride
EXPECT_EQ(1, params[10]); // top_level_array_size
EXPECT_EQ(0, params[11]); // top_level_array_stride
EXPECT_EQ(GL_FLOAT_MAT2, params[12]); // type
}
// Test that TOP_LEVEL_ARRAY_STRIDE for buffer variable with aggregate type works correctly.
TEST_P(ProgramInterfaceTestES31, TopLevelArrayStrideWithAggregateType)
{
constexpr char kComputeShaderSource[] =
R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
struct S
{
uvec2 v;
mat2 m;
};
layout(std430, binding = 0) buffer blockIn {
uint u;
uint a[2];
S s;
} instanceIn;
layout(std430, binding = 1) buffer blockOut {
uint u;
uint a[4][3];
S s[3][2];
} instanceOut;
void main()
{
instanceOut.u = instanceIn.u;
instanceOut.a[0][0] = instanceIn.a[0];
instanceOut.a[0][1] = instanceIn.a[1];
instanceOut.s[0][0].v = instanceIn.s.v;
instanceOut.s[0][0].m = instanceIn.s.m;
}
)";
ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
GLuint index = glGetProgramResourceIndex(program, GL_BUFFER_VARIABLE, "blockOut.s[0][0].m");
EXPECT_GL_NO_ERROR();
EXPECT_NE(GL_INVALID_INDEX, index);
GLchar name[64];
GLsizei length;
glGetProgramResourceName(program, GL_BUFFER_VARIABLE, index, sizeof(name), &length, name);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(18, length);
EXPECT_EQ("blockOut.s[0][0].m", std::string(name));
GLenum props[] = {GL_ARRAY_SIZE,
GL_ARRAY_STRIDE,
GL_BLOCK_INDEX,
GL_IS_ROW_MAJOR,
GL_MATRIX_STRIDE,
GL_NAME_LENGTH,
GL_OFFSET,
GL_REFERENCED_BY_VERTEX_SHADER,
GL_REFERENCED_BY_FRAGMENT_SHADER,
GL_REFERENCED_BY_COMPUTE_SHADER,
GL_TOP_LEVEL_ARRAY_SIZE,
GL_TOP_LEVEL_ARRAY_STRIDE,
GL_TYPE};
GLsizei propCount = static_cast<GLsizei>(ArraySize(props));
constexpr int kBufSize = 256;
GLint params[kBufSize];
glGetProgramResourceiv(program, GL_BUFFER_VARIABLE, index, propCount, props, kBufSize, &length,
params);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(propCount, length);
EXPECT_EQ(1, params[0]); // array_size
EXPECT_LE(0, params[1]); // array_stride
EXPECT_LE(0, params[2]); // block_index
EXPECT_EQ(0, params[3]); // is_row_major
EXPECT_EQ(8, params[4]); // matrix_stride
EXPECT_EQ(19, params[5]); // name_length
EXPECT_EQ(64, params[6]); // offset
EXPECT_EQ(0, params[7]); // referenced_by_vertex_shader
EXPECT_EQ(0, params[8]); // referenced_by_fragment_shader
// TODO(jiajia.qin@intel.com): referenced_by_compute_shader is not
// correctly handled. http://anglebug.com/1920.
// EXPECT_EQ(1, params[9]); // referenced_by_compute_shader
EXPECT_EQ(3, params[10]); // top_level_array_size
EXPECT_EQ(48, params[11]); // top_level_array_stride
EXPECT_EQ(GL_FLOAT_MAT2, params[12]); // type
index = glGetProgramResourceIndex(program, GL_BUFFER_VARIABLE, "blockOut.a[0][0]");
EXPECT_GL_NO_ERROR();
EXPECT_NE(GL_INVALID_INDEX, index);
glGetProgramResourceName(program, GL_BUFFER_VARIABLE, index, sizeof(name), &length, name);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(16, length);
EXPECT_EQ("blockOut.a[0][0]", std::string(name));
glGetProgramResourceiv(program, GL_BUFFER_VARIABLE, index, propCount, props, kBufSize, &length,
params);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(propCount, length);
EXPECT_EQ(3, params[0]); // array_size
EXPECT_LE(0, params[1]); // array_stride
EXPECT_LE(0, params[2]); // block_index
EXPECT_EQ(0, params[3]); // is_row_major
EXPECT_EQ(0, params[4]); // matrix_stride
EXPECT_EQ(17, params[5]); // name_length
EXPECT_EQ(4, params[6]); // offset
EXPECT_EQ(0, params[7]); // referenced_by_vertex_shader
EXPECT_EQ(0, params[8]); // referenced_by_fragment_shader
EXPECT_EQ(1, params[9]); // referenced_by_compute_shader
EXPECT_EQ(4, params[10]); // top_level_array_size
EXPECT_EQ(12, params[11]); // top_level_array_stride
EXPECT_EQ(GL_UNSIGNED_INT, params[12]); // type
}
// Tests the resource property query for shader storage block can be done correctly.
TEST_P(ProgramInterfaceTestES31, GetShaderStorageBlockProperties)
{
......
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