Commit b81ff9e6 by Qin Jiajia Committed by Commit Bot

ES31: Add std430 encoder.

Bug: angleproject:1951 Change-Id: I5e469ee5f13604102b0ee268d5bf9f5ac4809ecd Reviewed-on: https://chromium-review.googlesource.com/c/1278098 Commit-Queue: Jiajia Qin <jiajia.qin@intel.com> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent ffdbfa39
......@@ -91,6 +91,7 @@ void GetBlockLayoutInfo(TIntermTyped *node,
unsigned int GetMatrixStride(const TType &type, TLayoutBlockStorage storage, bool rowMajor)
{
sh::Std140BlockEncoder std140Encoder;
sh::Std430BlockEncoder std430Encoder;
sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false);
sh::BlockLayoutEncoder *encoder = nullptr;
......@@ -98,6 +99,10 @@ unsigned int GetMatrixStride(const TType &type, TLayoutBlockStorage storage, boo
{
encoder = &std140Encoder;
}
else if (storage == EbsStd430)
{
encoder = &std430Encoder;
}
else
{
encoder = &hlslEncoder;
......@@ -137,9 +142,11 @@ void GetShaderStorageBlockFieldMemberInfo(const TFieldList &fields,
size_t GetBlockFieldMemberInfoAndReturnBlockSize(const TFieldList &fields,
TLayoutBlockStorage storage,
bool rowMajor,
BlockMemberInfoMap *blockInfoOut)
BlockMemberInfoMap *blockInfoOut,
int *structureBaseAlignment)
{
sh::Std140BlockEncoder std140Encoder;
sh::Std430BlockEncoder std430Encoder;
sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false);
sh::BlockLayoutEncoder *structureEncoder = nullptr;
......@@ -147,15 +154,19 @@ size_t GetBlockFieldMemberInfoAndReturnBlockSize(const TFieldList &fields,
{
structureEncoder = &std140Encoder;
}
else if (storage == EbsStd430)
{
structureEncoder = &std430Encoder;
}
else
{
// TODO(jiajia.qin@intel.com): add std430 support.
structureEncoder = &hlslEncoder;
}
GetShaderStorageBlockFieldMemberInfo(fields, structureEncoder, storage, rowMajor, false,
blockInfoOut);
structureEncoder->exitAggregateType();
*structureBaseAlignment = static_cast<int>(structureEncoder->getStructureBaseAlignment());
return structureEncoder->getBlockSize();
}
......@@ -176,11 +187,20 @@ void GetShaderStorageBlockFieldMemberInfo(const TFieldList &fields,
}
if (fieldType.getStruct())
{
encoder->enterAggregateType();
int structureBaseAlignment = 0;
// This is to set structure member offset and array stride using a new encoder to ensure
// that the first field member offset in structure is always zero.
size_t structureStride = GetBlockFieldMemberInfoAndReturnBlockSize(
fieldType.getStruct()->fields(), storage, isRowMajorLayout, blockInfoOut);
fieldType.getStruct()->fields(), storage, isRowMajorLayout, blockInfoOut,
&structureBaseAlignment);
// According to OpenGL ES 3.1 spec, session 7.6.2.2 Standard Uniform Block Layout. In
// rule 9, if the member is a structure, the base alignment of the structure is N, where
// N is the largest base alignment value of any of its members. When using the std430
// storage layout, the base alignment and stride of structures in rule 9 are not rounded
// up a multiple of the base alignment of a vec4. So we must set structure base
// alignment before enterAggregateType.
encoder->setStructureBaseAlignment(structureBaseAlignment);
encoder->enterAggregateType();
const BlockMemberInfo memberInfo(static_cast<int>(encoder->getBlockSize()),
static_cast<int>(structureStride), 0, false);
(*blockInfoOut)[field] = memberInfo;
......@@ -236,6 +256,7 @@ void GetShaderStorageBlockMembersInfo(const TInterfaceBlock *interfaceBlock,
BlockMemberInfoMap *blockInfoOut)
{
sh::Std140BlockEncoder std140Encoder;
sh::Std430BlockEncoder std430Encoder;
sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false);
sh::BlockLayoutEncoder *encoder = nullptr;
......@@ -243,9 +264,12 @@ void GetShaderStorageBlockMembersInfo(const TInterfaceBlock *interfaceBlock,
{
encoder = &std140Encoder;
}
else if (interfaceBlock->blockStorage() == EbsStd430)
{
encoder = &std430Encoder;
}
else
{
// TODO(jiajia.qin@intel.com): add std430 support.
encoder = &hlslEncoder;
}
......
......@@ -41,6 +41,9 @@ void GetInterfaceBlockStructMemberInfo(const std::vector<VarT> &fields,
bool inRowMajorLayout,
BlockLayoutMap *blockInfoOut)
{
// TODO(jiajia.qin@intel.com):we need to set the right structure base alignment before
// enterAggregateType for std430 layout just like GetShaderStorageBlockFieldMemberInfo did in
// ShaderStorageBlockOutputHLSL.cpp. http://anglebug.com/1920
encoder->enterAggregateType();
GetInterfaceBlockInfo(fields, fieldName, encoder, inRowMajorLayout, blockInfoOut);
encoder->exitAggregateType();
......@@ -149,9 +152,7 @@ void GetInterfaceBlockInfo(const std::vector<VarT> &fields,
} // anonymous namespace
BlockLayoutEncoder::BlockLayoutEncoder() : mCurrentOffset(0)
{
}
BlockLayoutEncoder::BlockLayoutEncoder() : mCurrentOffset(0), mStructureBaseAlignment(0) {}
BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type,
const std::vector<unsigned int> &arraySizes,
......@@ -177,6 +178,11 @@ void BlockLayoutEncoder::increaseCurrentOffset(size_t offsetInBytes)
mCurrentOffset += (offsetInBytes / BytesPerComponent);
}
void BlockLayoutEncoder::setStructureBaseAlignment(size_t baseAlignment)
{
mStructureBaseAlignment = baseAlignment;
}
// static
size_t BlockLayoutEncoder::getBlockRegister(const BlockMemberInfo &info)
{
......@@ -261,9 +267,8 @@ void Std140BlockEncoder::advanceOffset(GLenum type,
}
else if (gl::IsMatrixType(type))
{
ASSERT(matrixStride == ComponentsPerRegister);
const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
mCurrentOffset += ComponentsPerRegister * numRegisters;
mCurrentOffset += matrixStride * numRegisters;
}
else
{
......@@ -271,6 +276,54 @@ void Std140BlockEncoder::advanceOffset(GLenum type,
}
}
Std430BlockEncoder::Std430BlockEncoder() {}
void Std430BlockEncoder::nextRegister()
{
mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, mStructureBaseAlignment);
}
void Std430BlockEncoder::getBlockLayoutInfo(GLenum type,
const std::vector<unsigned int> &arraySizes,
bool isRowMajorMatrix,
int *arrayStrideOut,
int *matrixStrideOut)
{
// We assume we are only dealing with 4 byte components (no doubles or half-words currently)
ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent);
size_t baseAlignment = 0;
int matrixStride = 0;
int arrayStride = 0;
if (gl::IsMatrixType(type))
{
const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix);
baseAlignment = (numComponents == 3 ? 4u : static_cast<size_t>(numComponents));
matrixStride = baseAlignment;
if (!arraySizes.empty())
{
const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
arrayStride = matrixStride * numRegisters;
}
}
else
{
const int numComponents = gl::VariableComponentCount(type);
baseAlignment = (numComponents == 3 ? 4u : static_cast<size_t>(numComponents));
if (!arraySizes.empty())
{
arrayStride = baseAlignment;
}
}
mStructureBaseAlignment = std::max(baseAlignment, mStructureBaseAlignment);
mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment);
*matrixStrideOut = matrixStride;
*arrayStrideOut = arrayStride;
}
void GetInterfaceBlockInfo(const std::vector<InterfaceBlockField> &fields,
const std::string &prefix,
sh::BlockLayoutEncoder *encoder,
......
......@@ -78,7 +78,9 @@ class BlockLayoutEncoder
bool isRowMajorMatrix);
size_t getBlockSize() const { return mCurrentOffset * BytesPerComponent; }
size_t getStructureBaseAlignment() const { return mStructureBaseAlignment; }
void increaseCurrentOffset(size_t offsetInBytes);
void setStructureBaseAlignment(size_t baseAlignment);
virtual void enterAggregateType() = 0;
virtual void exitAggregateType() = 0;
......@@ -91,8 +93,9 @@ class BlockLayoutEncoder
protected:
size_t mCurrentOffset;
size_t mStructureBaseAlignment;
void nextRegister();
virtual void nextRegister();
virtual void getBlockLayoutInfo(GLenum type,
const std::vector<unsigned int> &arraySizes,
......@@ -130,6 +133,20 @@ class Std140BlockEncoder : public BlockLayoutEncoder
int matrixStride) override;
};
class Std430BlockEncoder : public Std140BlockEncoder
{
public:
Std430BlockEncoder();
protected:
void nextRegister() override;
void getBlockLayoutInfo(GLenum type,
const std::vector<unsigned int> &arraySizes,
bool isRowMajorMatrix,
int *arrayStrideOut,
int *matrixStrideOut) override;
};
using BlockLayoutMap = std::map<std::string, BlockMemberInfo>;
void GetInterfaceBlockInfo(const std::vector<InterfaceBlockField> &fields,
......
......@@ -752,6 +752,270 @@ void main()
EXPECT_GL_NO_ERROR();
}
// Test that access/write to vector data in std430 shader storage block.
TEST_P(ShaderStorageBufferTest31, VectorArrayInSSBOWithStd430Qualifier)
{
constexpr char kComputeShaderSource[] =
R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(std430, binding = 0) buffer blockIn {
uvec2 data[2];
} instanceIn;
layout(std430, binding = 1) buffer blockOut {
uvec2 data[2];
} instanceOut;
void main()
{
instanceOut.data[0] = instanceIn.data[0];
instanceOut.data[1] = instanceIn.data[1];
}
)";
ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
glUseProgram(program);
constexpr unsigned int kElementCount = 2;
constexpr unsigned int kBytesPerComponent = sizeof(unsigned int);
constexpr unsigned int kArrayStride = 8;
constexpr unsigned int kComponentCount = kArrayStride / kBytesPerComponent;
constexpr unsigned int kExpectedValues[kElementCount][kComponentCount] = {{1u, 2u}, {3u, 4u}};
// Create shader storage buffer
GLBuffer shaderStorageBuffer[2];
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kElementCount * kArrayStride, kExpectedValues,
GL_STATIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kElementCount * kArrayStride, nullptr, GL_STATIC_DRAW);
// Bind shader storage buffer
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
glDispatchCompute(1, 1, 1);
glFinish();
// Read back shader storage buffer
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
const GLuint *ptr = reinterpret_cast<const GLuint *>(glMapBufferRange(
GL_SHADER_STORAGE_BUFFER, 0, kElementCount * kArrayStride, GL_MAP_READ_BIT));
for (unsigned int idx = 0; idx < kElementCount; idx++)
{
for (unsigned int idy = 0; idy < kComponentCount; idy++)
{
EXPECT_EQ(kExpectedValues[idx][idy], *(ptr + idx * kComponentCount + idy));
}
}
EXPECT_GL_NO_ERROR();
}
// Test that access/write to matrix data in std430 shader storage block.
TEST_P(ShaderStorageBufferTest31, MatrixInSSBOWithStd430Qualifier)
{
constexpr char kComputeShaderSource[] =
R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(std430, binding = 0) buffer blockIn {
mat2 data;
} instanceIn;
layout(std430, binding = 1) buffer blockOut {
mat2 data;
} instanceOut;
void main()
{
instanceOut.data = instanceIn.data;
}
)";
ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
glUseProgram(program);
constexpr unsigned int kColumns = 2;
constexpr unsigned int kRows = 2;
constexpr unsigned int kBytesPerComponent = sizeof(float);
constexpr unsigned int kMatrixStride = kRows * kBytesPerComponent;
constexpr float kInputDada[kColumns * kRows] = {0.1, 0.2, 0.4, 0.5};
MatrixCase matrixCase(kRows, kColumns, kMatrixStride, kComputeShaderSource, kInputDada);
runMatrixTest(matrixCase);
}
// Test that access/write to structure data in std430 shader storage block.
TEST_P(ShaderStorageBufferTest31, StructureInSSBOWithStd430Qualifier)
{
constexpr char kComputeShaderSource[] =
R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
struct S
{
uvec2 u;
};
layout(std430, binding = 0) buffer blockIn {
uint i1;
S s;
uint i2;
} instanceIn;
layout(std430, binding = 1) buffer blockOut {
uint i1;
S s;
uint i2;
} instanceOut;
void main()
{
instanceOut.i1 = instanceIn.i1;
instanceOut.s.u = instanceIn.s.u;
instanceOut.i2 = instanceIn.i2;
}
)";
ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
glUseProgram(program);
GLuint kI1Data = 1u;
std::array<GLuint, 2> kUData = {{
2u,
3u,
}};
GLuint kI2Data = 4u;
constexpr unsigned int kBytesPerComponent = sizeof(GLuint);
constexpr unsigned int kStructureStartOffset = 8;
constexpr unsigned int kStructureSize = 8;
constexpr unsigned int kTotalSize = kStructureStartOffset + kStructureSize + kBytesPerComponent;
// Create shader storage buffer
GLBuffer shaderStorageBuffer[2];
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kTotalSize, nullptr, GL_STATIC_DRAW);
// upload data to instanceIn.i1
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, kBytesPerComponent, &kI1Data);
// upload data to instanceIn.s.u
glBufferSubData(GL_SHADER_STORAGE_BUFFER, kStructureStartOffset, kStructureSize, kUData.data());
// upload data to instanceIn.i2
glBufferSubData(GL_SHADER_STORAGE_BUFFER, kStructureStartOffset + kStructureSize,
kBytesPerComponent, &kI2Data);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kTotalSize, nullptr, GL_STATIC_DRAW);
// Bind shader storage buffer
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
glDispatchCompute(1, 1, 1);
glFinish();
// Read back shader storage buffer
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
GLuint kExpectedValues[4] = {1u, 2u, 3u, 4u};
const GLuint *ptr = reinterpret_cast<const GLuint *>(
glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kTotalSize, GL_MAP_READ_BIT));
EXPECT_EQ(kExpectedValues[0], *ptr);
ptr += (kStructureStartOffset / kBytesPerComponent);
EXPECT_EQ(kExpectedValues[1], *ptr);
EXPECT_EQ(kExpectedValues[2], *(ptr + 1));
ptr += (kStructureSize / kBytesPerComponent);
EXPECT_EQ(kExpectedValues[3], *ptr);
EXPECT_GL_NO_ERROR();
}
// Test that access/write to structure of structure data in std430 shader storage block.
TEST_P(ShaderStorageBufferTest31, StructureOfStructureInSSBOWithStd430Qualifier)
{
constexpr char kComputeShaderSource[] =
R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
struct S2
{
uvec3 u2;
};
struct S1
{
uvec2 u1;
S2 s2;
};
layout(std430, binding = 0) buffer blockIn {
uint i1;
S1 s1;
uint i2;
} instanceIn;
layout(std430, binding = 1) buffer blockOut {
uint i1;
S1 s1;
uint i2;
} instanceOut;
void main()
{
instanceOut.i1 = instanceIn.i1;
instanceOut.s1.u1 = instanceIn.s1.u1;
instanceOut.s1.s2.u2 = instanceIn.s1.s2.u2;
instanceOut.i2 = instanceIn.i2;
}
)";
ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
glUseProgram(program);
constexpr unsigned int kBytesPerComponent = sizeof(GLuint);
constexpr unsigned int kStructureS1StartOffset = 16;
constexpr unsigned int kStructureS2StartOffset = 32;
constexpr unsigned int kStructureS1Size = 32;
constexpr unsigned int kTotalSize =
kStructureS1StartOffset + kStructureS1Size + kBytesPerComponent;
GLuint kI1Data = 1u;
std::array<GLuint, 2> kU1Data = {{2u, 3u}};
std::array<GLuint, 3> kU2Data = {{4u, 5u, 6u}};
GLuint kI2Data = 7u;
// Create shader storage buffer
GLBuffer shaderStorageBuffer[2];
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kTotalSize, nullptr, GL_STATIC_DRAW);
// upload data to instanceIn.i1
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, kBytesPerComponent, &kI1Data);
// upload data to instanceIn.s1.u1
glBufferSubData(GL_SHADER_STORAGE_BUFFER, kStructureS1StartOffset,
kU1Data.size() * kBytesPerComponent, kU1Data.data());
// upload data to instanceIn.s1.s2.u2
glBufferSubData(GL_SHADER_STORAGE_BUFFER, kStructureS2StartOffset,
kU2Data.size() * kBytesPerComponent, kU2Data.data());
// upload data to instanceIn.i2
glBufferSubData(GL_SHADER_STORAGE_BUFFER, kStructureS1StartOffset + kStructureS1Size,
kBytesPerComponent, &kI2Data);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kTotalSize, nullptr, GL_STATIC_DRAW);
// Bind shader storage buffer
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
glDispatchCompute(1, 1, 1);
glFinish();
// Read back shader storage buffer
GLuint kExpectedValues[7] = {1u, 2u, 3u, 4u, 5u, 6u, 7u};
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
const GLuint *ptr = reinterpret_cast<const GLuint *>(
glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kTotalSize, GL_MAP_READ_BIT));
EXPECT_EQ(kExpectedValues[0], *ptr);
ptr += (kStructureS1StartOffset / kBytesPerComponent);
EXPECT_EQ(kExpectedValues[1], *ptr);
EXPECT_EQ(kExpectedValues[2], *(ptr + 1));
ptr += ((kStructureS2StartOffset - kStructureS1StartOffset) / kBytesPerComponent);
EXPECT_EQ(kExpectedValues[3], *ptr);
EXPECT_EQ(kExpectedValues[4], *(ptr + 1));
EXPECT_EQ(kExpectedValues[5], *(ptr + 2));
ptr += ((kStructureS1Size - kStructureS2StartOffset) / kBytesPerComponent);
EXPECT_EQ(kExpectedValues[6], *(ptr + 4));
EXPECT_GL_NO_ERROR();
}
// Test atomic memory functions.
TEST_P(ShaderStorageBufferTest31, AtomicMemoryFunctions)
{
......
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