Commit 48f63f90 by Qin Jiajia Committed by Commit Bot

ES31: add row major matrix support (part 2)

This patch implements read/write vector data in matrix or matrix data directly in a shader storage block with row_major qualifier. Bug: angleproject:1951 Change-Id: Id7847e2245b09414709361412a95c4dd84b9ee97 Reviewed-on: https://chromium-review.googlesource.com/c/1304019Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jiajia Qin <jiajia.qin@intel.com>
parent 50bf0429
......@@ -16,38 +16,6 @@
namespace sh
{
namespace
{
unsigned int GetMatrixStride(const TType &type)
{
sh::Std140BlockEncoder std140Encoder;
sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false);
sh::BlockLayoutEncoder *encoder = nullptr;
if (type.getLayoutQualifier().blockStorage == EbsStd140)
{
encoder = &std140Encoder;
}
else
{
// TODO(jiajia.qin@intel.com): add std430 support. http://anglebug.com/1951
encoder = &hlslEncoder;
}
const bool isRowMajorLayout = (type.getLayoutQualifier().matrixPacking == EmpRowMajor);
std::vector<unsigned int> arraySizes;
auto *typeArraySizes = type.getArraySizes();
if (typeArraySizes != nullptr)
{
arraySizes.assign(typeArraySizes->begin(), typeArraySizes->end());
}
const BlockMemberInfo &memberInfo =
encoder->encodeType(GLVariableType(type), arraySizes, isRowMajorLayout);
return memberInfo.matrixStride;
}
} // anonymous namespace
// static
void ShaderStorageBlockFunctionHLSL::OutputSSBOLoadFunctionBody(
TInfoSinkBase &out,
......@@ -80,20 +48,47 @@ void ShaderStorageBlockFunctionHLSL::OutputSSBOLoadFunctionBody(
}
else if (ssboFunction.type.isVector())
{
out << " = " << convertString << "buffer.Load" << ssboFunction.type.getNominalSize()
<< "(loc));\n";
if (ssboFunction.rowMajor)
{
out << " = {";
for (int index = 0; index < ssboFunction.type.getNominalSize(); index++)
{
out << convertString << "buffer.Load(loc + " << index * ssboFunction.matrixStride
<< ")),";
}
out << "};\n";
}
else
{
out << " = " << convertString << "buffer.Load" << ssboFunction.type.getNominalSize()
<< "(loc));\n";
}
}
else if (ssboFunction.type.isMatrix())
{
unsigned int matrixStride = GetMatrixStride(ssboFunction.type);
out << " = {";
for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
if (ssboFunction.rowMajor)
{
out << "asfloat(buffer.Load" << ssboFunction.type.getCols() << "(loc +"
<< rowIndex * matrixStride << ")), ";
out << ";";
out << " float" << ssboFunction.type.getRows() << "x" << ssboFunction.type.getCols()
<< " tmp_ = {";
for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
{
out << "asfloat(buffer.Load" << ssboFunction.type.getCols() << "(loc + "
<< rowIndex * ssboFunction.matrixStride << ")), ";
}
out << "};\n";
out << " result = transpose(tmp_);\n";
}
else
{
out << " = {";
for (int columnIndex = 0; columnIndex < ssboFunction.type.getCols(); columnIndex++)
{
out << "asfloat(buffer.Load" << ssboFunction.type.getRows() << "(loc + "
<< columnIndex * ssboFunction.matrixStride << ")), ";
}
out << "};\n";
}
out << "};\n";
}
else
{
......@@ -124,25 +119,51 @@ void ShaderStorageBlockFunctionHLSL::OutputSSBOStoreFunctionBody(
}
else if (ssboFunction.type.isVector())
{
if (ssboFunction.type.getBasicType() == EbtBool)
if (ssboFunction.rowMajor)
{
out << " uint" << ssboFunction.type.getNominalSize() << " _tmp = uint"
<< ssboFunction.type.getNominalSize() << "(value);\n";
out << " buffer.Store" << ssboFunction.type.getNominalSize() << "(loc, _tmp);\n";
for (int index = 0; index < ssboFunction.type.getNominalSize(); index++)
{
// Don't need to worry about bool value since there is no bool matrix.
out << "buffer.Store(loc + " << index * ssboFunction.matrixStride
<< ", asuint(value[" << index << "]));\n";
}
}
else
{
out << " buffer.Store" << ssboFunction.type.getNominalSize()
<< "(loc, asuint(value));\n";
if (ssboFunction.type.getBasicType() == EbtBool)
{
out << " uint" << ssboFunction.type.getNominalSize() << " _tmp = uint"
<< ssboFunction.type.getNominalSize() << "(value);\n";
out << " buffer.Store" << ssboFunction.type.getNominalSize() << "(loc, _tmp);\n";
}
else
{
out << " buffer.Store" << ssboFunction.type.getNominalSize()
<< "(loc, asuint(value));\n";
}
}
}
else if (ssboFunction.type.isMatrix())
{
unsigned int matrixStride = GetMatrixStride(ssboFunction.type);
for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
if (ssboFunction.rowMajor)
{
out << " buffer.Store" << ssboFunction.type.getCols() << "(loc +"
<< rowIndex * matrixStride << ", asuint(value[" << rowIndex << "]));\n";
out << " float" << ssboFunction.type.getRows() << "x" << ssboFunction.type.getCols()
<< " tmp_ = transpose(value);\n";
for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
{
out << " buffer.Store" << ssboFunction.type.getCols() << "(loc + "
<< rowIndex * ssboFunction.matrixStride << ", asuint(tmp_[" << rowIndex
<< "]));\n";
}
}
else
{
for (int columnIndex = 0; columnIndex < ssboFunction.type.getCols(); columnIndex++)
{
out << " buffer.Store" << ssboFunction.type.getRows() << "(loc + "
<< columnIndex * ssboFunction.matrixStride << ", asuint(value[" << columnIndex
<< "]));\n";
}
}
}
else
......@@ -158,26 +179,42 @@ bool ShaderStorageBlockFunctionHLSL::ShaderStorageBlockFunction::operator<(
std::tie(rhs.functionName, rhs.typeString, rhs.method);
}
TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction(const TType &type,
SSBOMethod method)
TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction(
const TType &type,
SSBOMethod method,
TLayoutBlockStorage storage,
bool rowMajor,
int matrixStride)
{
ShaderStorageBlockFunction ssboFunction;
ssboFunction.typeString = TypeString(type);
ssboFunction.method = method;
ssboFunction.type = type;
ssboFunction.rowMajor = rowMajor;
ssboFunction.matrixStride = matrixStride;
ssboFunction.functionName =
TString(getBlockStorageString(storage)) + "_" + ssboFunction.typeString;
switch (method)
{
case SSBOMethod::LOAD:
ssboFunction.functionName = ssboFunction.typeString + "_Load";
ssboFunction.functionName += "_Load";
break;
case SSBOMethod::STORE:
ssboFunction.functionName = ssboFunction.typeString + "_Store";
ssboFunction.functionName += "_Store";
break;
default:
UNREACHABLE();
}
if (rowMajor)
{
ssboFunction.functionName += "_rm_";
}
else
{
ssboFunction.functionName += "_cm_";
}
mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
return ssboFunction.functionName;
}
......
......@@ -43,7 +43,11 @@ enum class SSBOMethod
class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable
{
public:
TString registerShaderStorageBlockFunction(const TType &type, SSBOMethod method);
TString registerShaderStorageBlockFunction(const TType &type,
SSBOMethod method,
TLayoutBlockStorage storage,
bool rowMajor,
int matrixStride);
void shaderStorageBlockFunctionHeader(TInfoSinkBase &out);
......@@ -55,6 +59,9 @@ class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable
TString typeString;
SSBOMethod method;
TType type;
TLayoutBlockStorage storage;
bool rowMajor;
int matrixStride;
};
static void OutputSSBOLoadFunctionBody(TInfoSinkBase &out,
......
......@@ -35,6 +35,85 @@ namespace sh
namespace
{
void GetBlockLayoutInfo(TIntermTyped *node,
bool rowMajorAlreadyAssigned,
TLayoutBlockStorage *storage,
bool *rowMajor)
{
TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
if (swizzleNode)
{
return GetBlockLayoutInfo(swizzleNode->getOperand(), rowMajorAlreadyAssigned, storage,
rowMajor);
}
TIntermBinary *binaryNode = node->getAsBinaryNode();
if (binaryNode)
{
switch (binaryNode->getOp())
{
case EOpIndexDirectInterfaceBlock:
{
// The column_major/row_major qualifier of a field member overrides the interface
// block's row_major/column_major. So we can assign rowMajor here and don't need to
// assign it again. But we still need to call recursively to get the storage's
// value.
const TType &type = node->getType();
*rowMajor = type.getLayoutQualifier().matrixPacking == EmpRowMajor;
return GetBlockLayoutInfo(binaryNode->getLeft(), true, storage, rowMajor);
}
case EOpIndexIndirect:
case EOpIndexDirect:
case EOpIndexDirectStruct:
return GetBlockLayoutInfo(binaryNode->getLeft(), rowMajorAlreadyAssigned, storage,
rowMajor);
default:
UNREACHABLE();
return;
}
}
const TType &type = node->getType();
ASSERT(type.getQualifier() == EvqBuffer);
const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
ASSERT(interfaceBlock);
*storage = interfaceBlock->blockStorage();
// If the block doesn't have an instance name, rowMajorAlreadyAssigned will be false. In
// this situation, we still need to set rowMajor's value.
if (!rowMajorAlreadyAssigned)
{
*rowMajor = type.getLayoutQualifier().matrixPacking == EmpRowMajor;
}
}
// It's possible that the current type has lost the original layout information. So we should pass
// the right layout information to GetMatrixStride.
unsigned int GetMatrixStride(const TType &type, TLayoutBlockStorage storage, bool rowMajor)
{
sh::Std140BlockEncoder std140Encoder;
sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false);
sh::BlockLayoutEncoder *encoder = nullptr;
if (storage == EbsStd140)
{
encoder = &std140Encoder;
}
else
{
encoder = &hlslEncoder;
}
std::vector<unsigned int> arraySizes;
auto *typeArraySizes = type.getArraySizes();
if (typeArraySizes != nullptr)
{
arraySizes.assign(typeArraySizes->begin(), typeArraySizes->end());
}
const BlockMemberInfo &memberInfo =
encoder->encodeType(GLVariableType(type), arraySizes, rowMajor);
return memberInfo.matrixStride;
}
const TField *GetFieldMemberInShaderStorageBlock(const TInterfaceBlock *interfaceBlock,
const ImmutableString &variableName)
{
......@@ -222,8 +301,40 @@ void ShaderStorageBlockOutputHLSL::outputLoadFunctionCall(TIntermTyped *node)
void ShaderStorageBlockOutputHLSL::traverseSSBOAccess(TIntermTyped *node, SSBOMethod method)
{
const TString &functionName =
mSSBOFunctionHLSL->registerShaderStorageBlockFunction(node->getType(), method);
mMatrixStride = 0;
mRowMajor = false;
// Note that we don't have correct BlockMemberInfo from mBlockMemberInfoMap at the current
// point. But we must use those information to generate the right function name. So here we have
// to calculate them again.
TLayoutBlockStorage storage;
bool rowMajor;
GetBlockLayoutInfo(node, false, &storage, &rowMajor);
// Note that we must calculate the matrix stride here instead of ShaderStorageBlockFunctionHLSL.
// It's because that if the current node's type is a vector which comes from a matrix, we will
// lost the matrix type info once we enter ShaderStorageBlockFunctionHLSL.
if (node->getType().isVector())
{
TIntermBinary *binaryNode = node->getAsBinaryNode();
if (binaryNode)
{
const TType &leftType = binaryNode->getLeft()->getType();
if (leftType.isMatrix())
{
mMatrixStride = GetMatrixStride(leftType, storage, rowMajor);
mRowMajor = rowMajor;
}
}
}
else if (node->getType().isMatrix())
{
mMatrixStride = GetMatrixStride(node->getType(), storage, rowMajor);
mRowMajor = rowMajor;
}
const TString &functionName = mSSBOFunctionHLSL->registerShaderStorageBlockFunction(
node->getType(), method, storage, mRowMajor, mMatrixStride);
TInfoSinkBase &out = mOutputHLSL->getInfoSink();
out << functionName;
out << "(";
......
......@@ -15,6 +15,28 @@ using namespace angle;
namespace
{
struct MatrixCase
{
MatrixCase(unsigned cols,
unsigned rows,
unsigned matrixStride,
const char *computeShaderSource,
const float *inputData)
: mColumns(cols),
mRows(rows),
mMatrixStride(matrixStride),
mComputeShaderSource(computeShaderSource),
mInputdata(inputData)
{
}
unsigned int mColumns;
unsigned int mRows;
unsigned int mMatrixStride;
const char *mComputeShaderSource;
const float *mInputdata;
const unsigned int kBytesPerComponent = sizeof(float);
};
class ShaderStorageBufferTest31 : public ANGLETest
{
protected:
......@@ -28,27 +50,19 @@ class ShaderStorageBufferTest31 : public ANGLETest
setConfigAlphaBits(8);
}
void runStd140RowMajorMatrixTest(const char *computeShaderSource)
void runMatrixTest(const MatrixCase &matrixCase)
{
ANGLE_GL_COMPUTE_PROGRAM(program, computeShaderSource);
ANGLE_GL_COMPUTE_PROGRAM(program, matrixCase.mComputeShaderSource);
glUseProgram(program);
constexpr unsigned int kColumns = 2;
constexpr unsigned int kRows = 3;
constexpr unsigned int kBytesPerComponent = sizeof(float);
constexpr unsigned int kMatrixStride = 16;
// kMatrixStride / kBytesPerComponent is used instead of kColumns is because std140 layout
// requires that base alignment and stride of arrays of scalars and vectors are rounded up a
// multiple of the base alignment of a vec4.
constexpr float kInputDada[kRows][kMatrixStride / kBytesPerComponent] = {
{0.1, 0.2, 0.0, 0.0}, {0.3, 0.4, 0.0, 0.0}, {0.5, 0.6, 0.0, 0.0}};
// Create shader storage buffer
GLBuffer shaderStorageBuffer[2];
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kRows * kMatrixStride, kInputDada, GL_STATIC_DRAW);
glBufferData(GL_SHADER_STORAGE_BUFFER, matrixCase.mRows * matrixCase.mMatrixStride,
matrixCase.mInputdata, GL_STATIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kRows * kMatrixStride, nullptr, GL_STATIC_DRAW);
glBufferData(GL_SHADER_STORAGE_BUFFER, matrixCase.mRows * matrixCase.mMatrixStride, nullptr,
GL_STATIC_DRAW);
// Bind shader storage buffer
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
......@@ -58,16 +72,19 @@ class ShaderStorageBufferTest31 : public ANGLETest
glFinish();
// Read back shader storage buffer
constexpr float kExpectedValues[kRows][kColumns] = {{0.1, 0.2}, {0.3, 0.4}, {0.5, 0.6}};
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
const GLfloat *ptr = reinterpret_cast<const GLfloat *>(
glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kRows * kMatrixStride, GL_MAP_READ_BIT));
for (unsigned int idx = 0; idx < kRows; idx++)
glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0,
matrixCase.mRows * matrixCase.mMatrixStride, GL_MAP_READ_BIT));
for (unsigned int idx = 0; idx < matrixCase.mRows; idx++)
{
for (unsigned int idy = 0; idy < kColumns; idy++)
for (unsigned int idy = 0; idy < matrixCase.mColumns; idy++)
{
EXPECT_EQ(kExpectedValues[idx][idy],
*(ptr + idx * (kMatrixStride / kBytesPerComponent) + idy));
EXPECT_EQ(matrixCase.mInputdata[idx * (matrixCase.mMatrixStride /
matrixCase.kBytesPerComponent) +
idy],
*(ptr + idx * (matrixCase.mMatrixStride / matrixCase.kBytesPerComponent) +
idy));
}
}
......@@ -319,7 +336,79 @@ void main()
}
)";
runStd140RowMajorMatrixTest(kComputeShaderSource);
constexpr unsigned int kColumns = 2;
constexpr unsigned int kRows = 3;
constexpr unsigned int kBytesPerComponent = sizeof(float);
// std140 layout requires that base alignment and stride of arrays of scalars and vectors are
// rounded up a multiple of the base alignment of a vec4.
constexpr unsigned int kMatrixStride = 16;
constexpr float kInputDada[kRows * (kMatrixStride / kBytesPerComponent)] = {
0.1, 0.2, 0.0, 0.0, 0.3, 0.4, 0.0, 0.0, 0.5, 0.6, 0.0, 0.0};
MatrixCase matrixCase(kColumns, kRows, kMatrixStride, kComputeShaderSource, kInputDada);
runMatrixTest(matrixCase);
}
TEST_P(ShaderStorageBufferTest31, VectorDataInMatrixInSSBOWithRowMajorQualifier)
{
ANGLE_SKIP_TEST_IF(IsAndroid());
constexpr char kComputeShaderSource[] =
R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(std140, binding = 0) buffer blockIn {
layout(row_major) mat2x3 data;
} instanceIn;
layout(std140, binding = 1) buffer blockOut {
layout(row_major) mat2x3 data;
} instanceOut;
void main()
{
instanceOut.data[0] = instanceIn.data[0];
instanceOut.data[1] = instanceIn.data[1];
}
)";
constexpr unsigned int kColumns = 2;
constexpr unsigned int kRows = 3;
constexpr unsigned int kBytesPerComponent = sizeof(float);
// std140 layout requires that base alignment and stride of arrays of scalars and vectors are
// rounded up a multiple of the base alignment of a vec4.
constexpr unsigned int kMatrixStride = 16;
constexpr float kInputDada[kRows * (kMatrixStride / kBytesPerComponent)] = {
0.1, 0.2, 0.0, 0.0, 0.3, 0.4, 0.0, 0.0, 0.5, 0.6, 0.0, 0.0};
MatrixCase matrixCase(kColumns, kRows, kMatrixStride, kComputeShaderSource, kInputDada);
runMatrixTest(matrixCase);
}
TEST_P(ShaderStorageBufferTest31, MatrixDataInSSBOWithRowMajorQualifier)
{
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;
layout(std140, binding = 0) buffer blockIn {
layout(row_major) mat2x3 data;
} instanceIn;
layout(std140, binding = 1) buffer blockOut {
layout(row_major) mat2x3 data;
} instanceOut;
void main()
{
instanceOut.data = instanceIn.data;
}
)";
constexpr unsigned int kColumns = 2;
constexpr unsigned int kRows = 3;
constexpr unsigned int kBytesPerComponent = sizeof(float);
// std140 layout requires that base alignment and stride of arrays of scalars and vectors are
// rounded up a multiple of the base alignment of a vec4.
constexpr unsigned int kMatrixStride = 16;
constexpr float kInputDada[kRows * (kMatrixStride / kBytesPerComponent)] = {
0.1, 0.2, 0.0, 0.0, 0.3, 0.4, 0.0, 0.0, 0.5, 0.6, 0.0, 0.0};
MatrixCase matrixCase(kColumns, kRows, kMatrixStride, kComputeShaderSource, kInputDada);
runMatrixTest(matrixCase);
}
// Test that access/write to scalar data in structure matrix in shader storage block with row major.
......@@ -354,11 +443,20 @@ void main()
}
)";
runStd140RowMajorMatrixTest(kComputeShaderSource);
constexpr unsigned int kColumns = 2;
constexpr unsigned int kRows = 3;
constexpr unsigned int kBytesPerComponent = sizeof(float);
// std140 layout requires that base alignment and stride of arrays of scalars and vectors are
// rounded up a multiple of the base alignment of a vec4.
constexpr unsigned int kMatrixStride = 16;
constexpr float kInputDada[kRows * (kMatrixStride / kBytesPerComponent)] = {
0.1, 0.2, 0.0, 0.0, 0.3, 0.4, 0.0, 0.0, 0.5, 0.6, 0.0, 0.0};
MatrixCase matrixCase(kColumns, kRows, kMatrixStride, kComputeShaderSource, kInputDada);
runMatrixTest(matrixCase);
}
// Test that access/write to column major matrix data in shader storage buffer.
TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferMatrix)
TEST_P(ShaderStorageBufferTest31, ScalarDataInMatrixInSSBO)
{
constexpr char kComputeShaderSource[] =
R"(#version 310 es
......@@ -380,49 +478,69 @@ void main()
}
)";
ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
glUseProgram(program.get());
constexpr unsigned int kColumns = 2;
constexpr unsigned int kRows = 3;
constexpr unsigned int kBytesPerComponent = sizeof(float);
constexpr unsigned int kVectorStride = 16;
// kVectorStride / kBytesPerComponent is used instead of kRows is because std140 layout requires
// that base alignment and stride of arrays of scalars and vectors are rounded up a multiple of
// the base alignment of a vec4.
constexpr float kInputDada[kColumns][kVectorStride / kBytesPerComponent] = {
{0.1, 0.2, 0.3, 0.0}, {0.4, 0.5, 0.6, 0.0}};
// Create shader storage buffer
GLBuffer shaderStorageBuffer[2];
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kColumns * kVectorStride, kInputDada, GL_STATIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kColumns * kVectorStride, nullptr, GL_STATIC_DRAW);
// Bind shader storage buffer
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
constexpr unsigned int kColumns = 2;
constexpr unsigned int kRows = 3;
constexpr unsigned int kBytesPerComponent = sizeof(float);
constexpr unsigned int kMatrixStride = 16;
constexpr float kInputDada[kColumns * (kMatrixStride / kBytesPerComponent)] = {
0.1, 0.2, 0.3, 0.0, 0.4, 0.5, 0.6, 0.0};
MatrixCase matrixCase(kRows, kColumns, kMatrixStride, kComputeShaderSource, kInputDada);
runMatrixTest(matrixCase);
}
glDispatchCompute(1, 1, 1);
TEST_P(ShaderStorageBufferTest31, VectorDataInMatrixInSSBOWithColumnMajorQualifier)
{
constexpr char kComputeShaderSource[] =
R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(std140, binding = 0) buffer blockIn {
layout(column_major) mat2x3 data;
} instanceIn;
layout(std140, binding = 1) buffer blockOut {
layout(column_major) mat2x3 data;
} instanceOut;
void main()
{
instanceOut.data[0] = instanceIn.data[0];
instanceOut.data[1] = instanceIn.data[1];
}
)";
glFinish();
constexpr unsigned int kColumns = 2;
constexpr unsigned int kRows = 3;
constexpr unsigned int kBytesPerComponent = sizeof(float);
constexpr unsigned int kMatrixStride = 16;
constexpr float kInputDada[kColumns * (kMatrixStride / kBytesPerComponent)] = {
0.1, 0.2, 0.3, 0.0, 0.4, 0.5, 0.6, 0.0};
MatrixCase matrixCase(kRows, kColumns, kMatrixStride, kComputeShaderSource, kInputDada);
runMatrixTest(matrixCase);
}
// Read back shader storage buffer
constexpr float kExpectedValues[kColumns][kRows] = {{0.1, 0.2, 0.3}, {0.4, 0.5, 0.6}};
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
const GLfloat *ptr = reinterpret_cast<const GLfloat *>(
glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kColumns * kVectorStride, GL_MAP_READ_BIT));
for (unsigned int idx = 0; idx < kColumns; idx++)
{
for (unsigned int idy = 0; idy < kRows; idy++)
{
EXPECT_EQ(kExpectedValues[idx][idy],
*(ptr + idx * (kVectorStride / kBytesPerComponent) + idy));
}
}
TEST_P(ShaderStorageBufferTest31, MatrixDataInSSBOWithColumnMajorQualifier)
{
constexpr char kComputeShaderSource[] =
R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(std140, binding = 0) buffer blockIn {
layout(column_major) mat2x3 data;
} instanceIn;
layout(std140, binding = 1) buffer blockOut {
layout(column_major) mat2x3 data;
} instanceOut;
void main()
{
instanceOut.data = instanceIn.data;
}
)";
EXPECT_GL_NO_ERROR();
constexpr unsigned int kColumns = 2;
constexpr unsigned int kRows = 3;
constexpr unsigned int kBytesPerComponent = sizeof(float);
constexpr unsigned int kMatrixStride = 16;
constexpr float kInputDada[kColumns * (kMatrixStride / kBytesPerComponent)] = {
0.1, 0.2, 0.3, 0.0, 0.4, 0.5, 0.6, 0.0};
MatrixCase matrixCase(kRows, kColumns, kMatrixStride, kComputeShaderSource, kInputDada);
runMatrixTest(matrixCase);
}
// Test that access/write to structure data in shader storage buffer.
......
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