Commit 88faa696 by Qin Jiajia Committed by Commit Bot

ES31: Add unsized array length support in SSBO

Bug: angleproject:1951 Change-Id: I10c798c62a741b156f5b614e0df0795c0e845108 Reviewed-on: https://chromium-review.googlesource.com/c/1365154Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Jiajia Qin <jiajia.qin@intel.com>
parent a48f26fb
...@@ -1837,6 +1837,13 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) ...@@ -1837,6 +1837,13 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
// tested in GLSLTest and results are consistent with GL. // tested in GLSLTest and results are consistent with GL.
outputTriplet(out, visit, "firstbithigh(", "", ")"); outputTriplet(out, visit, "firstbithigh(", "", ")");
break; break;
case EOpArrayLength:
{
TIntermTyped *operand = node->getOperand();
ASSERT(IsInShaderStorageBlock(operand));
mSSBOOutputHLSL->outputLengthFunctionCall(operand);
return false;
}
default: default:
UNREACHABLE(); UNREACHABLE();
} }
......
...@@ -189,6 +189,15 @@ void ShaderStorageBlockFunctionHLSL::OutputSSBOStoreFunctionBody( ...@@ -189,6 +189,15 @@ void ShaderStorageBlockFunctionHLSL::OutputSSBOStoreFunctionBody(
} }
} }
// static
void ShaderStorageBlockFunctionHLSL::OutputSSBOLengthFunctionBody(TInfoSinkBase &out,
int unsizedArrayStride)
{
out << " uint dim = 0;\n";
out << " buffer.GetDimensions(dim);\n";
out << " return int((dim - loc)/uint(" << unsizedArrayStride << "));\n";
}
bool ShaderStorageBlockFunctionHLSL::ShaderStorageBlockFunction::operator<( bool ShaderStorageBlockFunctionHLSL::ShaderStorageBlockFunction::operator<(
const ShaderStorageBlockFunction &rhs) const const ShaderStorageBlockFunction &rhs) const
{ {
...@@ -201,11 +210,30 @@ TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction( ...@@ -201,11 +210,30 @@ TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction(
TLayoutBlockStorage storage, TLayoutBlockStorage storage,
bool rowMajor, bool rowMajor,
int matrixStride, int matrixStride,
int unsizedArrayStride,
TIntermSwizzle *swizzleNode) TIntermSwizzle *swizzleNode)
{ {
ShaderStorageBlockFunction ssboFunction; ShaderStorageBlockFunction ssboFunction;
ssboFunction.typeString = TypeString(type);
ssboFunction.method = method; ssboFunction.method = method;
switch (method)
{
case SSBOMethod::LOAD:
ssboFunction.functionName = "_Load_";
break;
case SSBOMethod::STORE:
ssboFunction.functionName = "_Store_";
break;
case SSBOMethod::LENGTH:
ssboFunction.unsizedArrayStride = unsizedArrayStride;
ssboFunction.functionName = "_Length_" + str(unsizedArrayStride);
mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
return ssboFunction.functionName;
default:
UNREACHABLE();
}
ssboFunction.typeString = TypeString(type);
ssboFunction.functionName += ssboFunction.typeString;
ssboFunction.type = type; ssboFunction.type = type;
if (swizzleNode != nullptr) if (swizzleNode != nullptr)
{ {
...@@ -230,20 +258,7 @@ TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction( ...@@ -230,20 +258,7 @@ TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction(
} }
ssboFunction.rowMajor = rowMajor; ssboFunction.rowMajor = rowMajor;
ssboFunction.matrixStride = matrixStride; ssboFunction.matrixStride = matrixStride;
ssboFunction.functionName = ssboFunction.functionName += "_" + TString(getBlockStorageString(storage));
TString(getBlockStorageString(storage)) + "_" + ssboFunction.typeString;
switch (method)
{
case SSBOMethod::LOAD:
ssboFunction.functionName += "_Load";
break;
case SSBOMethod::STORE:
ssboFunction.functionName += "_Store";
break;
default:
UNREACHABLE();
}
if (rowMajor) if (rowMajor)
{ {
...@@ -291,7 +306,7 @@ void ShaderStorageBlockFunctionHLSL::shaderStorageBlockFunctionHeader(TInfoSinkB ...@@ -291,7 +306,7 @@ void ShaderStorageBlockFunctionHLSL::shaderStorageBlockFunctionHeader(TInfoSinkB
out << "{\n"; out << "{\n";
OutputSSBOLoadFunctionBody(out, ssboFunction); OutputSSBOLoadFunctionBody(out, ssboFunction);
} }
else else if (ssboFunction.method == SSBOMethod::STORE)
{ {
// Function header // Function header
out << "void " << ssboFunction.functionName << "(RWByteAddressBuffer buffer, uint loc, " out << "void " << ssboFunction.functionName << "(RWByteAddressBuffer buffer, uint loc, "
...@@ -299,6 +314,14 @@ void ShaderStorageBlockFunctionHLSL::shaderStorageBlockFunctionHeader(TInfoSinkB ...@@ -299,6 +314,14 @@ void ShaderStorageBlockFunctionHLSL::shaderStorageBlockFunctionHeader(TInfoSinkB
out << "{\n"; out << "{\n";
OutputSSBOStoreFunctionBody(out, ssboFunction); OutputSSBOStoreFunctionBody(out, ssboFunction);
} }
else
{
ASSERT(ssboFunction.method == SSBOMethod::LENGTH);
out << "int " << ssboFunction.functionName
<< "(RWByteAddressBuffer buffer, uint loc)\n";
out << "{\n";
OutputSSBOLengthFunctionBody(out, ssboFunction.unsizedArrayStride);
}
out << "}\n" out << "}\n"
"\n"; "\n";
......
...@@ -38,7 +38,8 @@ class TIntermSwizzle; ...@@ -38,7 +38,8 @@ class TIntermSwizzle;
enum class SSBOMethod enum class SSBOMethod
{ {
LOAD, LOAD,
STORE STORE,
LENGTH
}; };
class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable
...@@ -49,6 +50,7 @@ class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable ...@@ -49,6 +50,7 @@ class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable
TLayoutBlockStorage storage, TLayoutBlockStorage storage,
bool rowMajor, bool rowMajor,
int matrixStride, int matrixStride,
int unsizedArrayStride,
TIntermSwizzle *node); TIntermSwizzle *node);
void shaderStorageBlockFunctionHeader(TInfoSinkBase &out); void shaderStorageBlockFunctionHeader(TInfoSinkBase &out);
...@@ -63,14 +65,16 @@ class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable ...@@ -63,14 +65,16 @@ class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable
TType type; TType type;
bool rowMajor; bool rowMajor;
int matrixStride; int matrixStride;
int unsizedArrayStride;
TVector<int> swizzleOffsets; TVector<int> swizzleOffsets;
bool isDefaultSwizzle; bool isDefaultSwizzle;
}; };
static void OutputSSBOLoadFunctionBody(TInfoSinkBase &out, static void OutputSSBOLoadFunctionBody(TInfoSinkBase &out,
const ShaderStorageBlockFunction &imageFunction); const ShaderStorageBlockFunction &ssboFunction);
static void OutputSSBOStoreFunctionBody(TInfoSinkBase &out, static void OutputSSBOStoreFunctionBody(TInfoSinkBase &out,
const ShaderStorageBlockFunction &imageFunction); const ShaderStorageBlockFunction &ssboFunction);
static void OutputSSBOLengthFunctionBody(TInfoSinkBase &out, int unsizedArrayStride);
using ShaderStorageBlockFunctionSet = std::set<ShaderStorageBlockFunction>; using ShaderStorageBlockFunctionSet = std::set<ShaderStorageBlockFunction>;
ShaderStorageBlockFunctionSet mRegisteredShaderStorageBlockFunctions; ShaderStorageBlockFunctionSet mRegisteredShaderStorageBlockFunctions;
}; };
......
...@@ -87,8 +87,10 @@ void GetBlockLayoutInfo(TIntermTyped *node, ...@@ -87,8 +87,10 @@ void GetBlockLayoutInfo(TIntermTyped *node,
} }
// It's possible that the current type has lost the original layout information. So we should pass // It's possible that the current type has lost the original layout information. So we should pass
// the right layout information to GetMatrixStride. // the right layout information to GetBlockMemberInfoByType.
unsigned int GetMatrixStride(const TType &type, TLayoutBlockStorage storage, bool rowMajor) const BlockMemberInfo GetBlockMemberInfoByType(const TType &type,
TLayoutBlockStorage storage,
bool rowMajor)
{ {
sh::Std140BlockEncoder std140Encoder; sh::Std140BlockEncoder std140Encoder;
sh::Std430BlockEncoder std430Encoder; sh::Std430BlockEncoder std430Encoder;
...@@ -114,9 +116,7 @@ unsigned int GetMatrixStride(const TType &type, TLayoutBlockStorage storage, boo ...@@ -114,9 +116,7 @@ unsigned int GetMatrixStride(const TType &type, TLayoutBlockStorage storage, boo
{ {
arraySizes.assign(typeArraySizes->begin(), typeArraySizes->end()); arraySizes.assign(typeArraySizes->begin(), typeArraySizes->end());
} }
const BlockMemberInfo &memberInfo = return encoder->encodeType(GLVariableType(type), arraySizes, rowMajor);
encoder->encodeType(GLVariableType(type), arraySizes, rowMajor);
return memberInfo.matrixStride;
} }
const TField *GetFieldMemberInShaderStorageBlock(const TInterfaceBlock *interfaceBlock, const TField *GetFieldMemberInShaderStorageBlock(const TInterfaceBlock *interfaceBlock,
...@@ -299,7 +299,7 @@ ShaderStorageBlockOutputHLSL::ShaderStorageBlockOutputHLSL(OutputHLSL *outputHLS ...@@ -299,7 +299,7 @@ ShaderStorageBlockOutputHLSL::ShaderStorageBlockOutputHLSL(OutputHLSL *outputHLS
: TIntermTraverser(true, true, true, symbolTable), : TIntermTraverser(true, true, true, symbolTable),
mMatrixStride(0), mMatrixStride(0),
mRowMajor(false), mRowMajor(false),
mIsLoadFunctionCall(false), mLocationAsTheLastArgument(false),
mOutputHLSL(outputHLSL), mOutputHLSL(outputHLSL),
mResourcesHLSL(resourcesHLSL) mResourcesHLSL(resourcesHLSL)
{ {
...@@ -313,16 +313,22 @@ ShaderStorageBlockOutputHLSL::~ShaderStorageBlockOutputHLSL() ...@@ -313,16 +313,22 @@ ShaderStorageBlockOutputHLSL::~ShaderStorageBlockOutputHLSL()
void ShaderStorageBlockOutputHLSL::outputStoreFunctionCallPrefix(TIntermTyped *node) void ShaderStorageBlockOutputHLSL::outputStoreFunctionCallPrefix(TIntermTyped *node)
{ {
mIsLoadFunctionCall = false; mLocationAsTheLastArgument = false;
traverseSSBOAccess(node, SSBOMethod::STORE); traverseSSBOAccess(node, SSBOMethod::STORE);
} }
void ShaderStorageBlockOutputHLSL::outputLoadFunctionCall(TIntermTyped *node) void ShaderStorageBlockOutputHLSL::outputLoadFunctionCall(TIntermTyped *node)
{ {
mIsLoadFunctionCall = true; mLocationAsTheLastArgument = true;
traverseSSBOAccess(node, SSBOMethod::LOAD); traverseSSBOAccess(node, SSBOMethod::LOAD);
} }
void ShaderStorageBlockOutputHLSL::outputLengthFunctionCall(TIntermTyped *node)
{
mLocationAsTheLastArgument = true;
traverseSSBOAccess(node, SSBOMethod::LENGTH);
}
// Note that we must calculate the matrix stride here instead of ShaderStorageBlockFunctionHLSL. // 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 // It's because that if the current node's type is a vector which comes from a matrix, we will
// lose the matrix type info once we enter ShaderStorageBlockFunctionHLSL. // lose the matrix type info once we enter ShaderStorageBlockFunctionHLSL.
...@@ -332,7 +338,7 @@ void ShaderStorageBlockOutputHLSL::setMatrixStride(TIntermTyped *node, ...@@ -332,7 +338,7 @@ void ShaderStorageBlockOutputHLSL::setMatrixStride(TIntermTyped *node,
{ {
if (node->getType().isMatrix()) if (node->getType().isMatrix())
{ {
mMatrixStride = GetMatrixStride(node->getType(), storage, rowMajor); mMatrixStride = GetBlockMemberInfoByType(node->getType(), storage, rowMajor).matrixStride;
mRowMajor = rowMajor; mRowMajor = rowMajor;
return; return;
} }
...@@ -366,10 +372,17 @@ void ShaderStorageBlockOutputHLSL::traverseSSBOAccess(TIntermTyped *node, SSBOMe ...@@ -366,10 +372,17 @@ void ShaderStorageBlockOutputHLSL::traverseSSBOAccess(TIntermTyped *node, SSBOMe
TLayoutBlockStorage storage; TLayoutBlockStorage storage;
bool rowMajor; bool rowMajor;
GetBlockLayoutInfo(node, false, &storage, &rowMajor); GetBlockLayoutInfo(node, false, &storage, &rowMajor);
int unsizedArrayStride = 0;
if (node->getType().isUnsizedArray())
{
unsizedArrayStride =
GetBlockMemberInfoByType(node->getType(), storage, rowMajor).arrayStride;
}
setMatrixStride(node, storage, rowMajor); setMatrixStride(node, storage, rowMajor);
const TString &functionName = mSSBOFunctionHLSL->registerShaderStorageBlockFunction( const TString &functionName = mSSBOFunctionHLSL->registerShaderStorageBlockFunction(
node->getType(), method, storage, mRowMajor, mMatrixStride, node->getAsSwizzleNode()); node->getType(), method, storage, mRowMajor, mMatrixStride, unsizedArrayStride,
node->getAsSwizzleNode());
TInfoSinkBase &out = mOutputHLSL->getInfoSink(); TInfoSinkBase &out = mOutputHLSL->getInfoSink();
out << functionName; out << functionName;
out << "("; out << "(";
...@@ -488,7 +501,7 @@ bool ShaderStorageBlockOutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *nod ...@@ -488,7 +501,7 @@ bool ShaderStorageBlockOutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *nod
TInfoSinkBase &out = mOutputHLSL->getInfoSink(); TInfoSinkBase &out = mOutputHLSL->getInfoSink();
// TODO(jiajia.qin@intel.com): add swizzle process if the swizzle node is not the last node // TODO(jiajia.qin@intel.com): add swizzle process if the swizzle node is not the last node
// of ssbo access chain. Such as, data.xy[0] // of ssbo access chain. Such as, data.xy[0]
if (mIsLoadFunctionCall && isEndOfSSBOAccessChain()) if (mLocationAsTheLastArgument && isEndOfSSBOAccessChain())
{ {
out << ")"; out << ")";
} }
...@@ -657,7 +670,7 @@ void ShaderStorageBlockOutputHLSL::writeEOpIndexDirectOrIndirectOutput(TInfoSink ...@@ -657,7 +670,7 @@ void ShaderStorageBlockOutputHLSL::writeEOpIndexDirectOrIndirectOutput(TInfoSink
{ {
out << ")"; out << ")";
} }
if (mIsLoadFunctionCall && isEndOfSSBOAccessChain()) if (mLocationAsTheLastArgument && isEndOfSSBOAccessChain())
{ {
out << ")"; out << ")";
} }
...@@ -683,7 +696,7 @@ void ShaderStorageBlockOutputHLSL::writeDotOperatorOutput(TInfoSinkBase &out, co ...@@ -683,7 +696,7 @@ void ShaderStorageBlockOutputHLSL::writeDotOperatorOutput(TInfoSinkBase &out, co
out << " * ("; out << " * (";
} }
} }
if (mIsLoadFunctionCall && isEndOfSSBOAccessChain()) if (mLocationAsTheLastArgument && isEndOfSSBOAccessChain())
{ {
out << ")"; out << ")";
} }
......
...@@ -47,8 +47,10 @@ class ShaderStorageBlockOutputHLSL : public TIntermTraverser ...@@ -47,8 +47,10 @@ class ShaderStorageBlockOutputHLSL : public TIntermTraverser
// calling this, ", <stored value>)" should be written to the output stream to complete the // calling this, ", <stored value>)" should be written to the output stream to complete the
// function call. // function call.
void outputStoreFunctionCallPrefix(TIntermTyped *node); void outputStoreFunctionCallPrefix(TIntermTyped *node);
// This writes the funciton call to load a SSBO value to the output stream. // This writes the function call to load a SSBO value to the output stream.
void outputLoadFunctionCall(TIntermTyped *node); void outputLoadFunctionCall(TIntermTyped *node);
// This writes the function call to get the lengh of unsized array member of SSBO.
void outputLengthFunctionCall(TIntermTyped *node);
void writeShaderStorageBlocksHeader(TInfoSinkBase &out) const; void writeShaderStorageBlocksHeader(TInfoSinkBase &out) const;
...@@ -71,7 +73,7 @@ class ShaderStorageBlockOutputHLSL : public TIntermTraverser ...@@ -71,7 +73,7 @@ class ShaderStorageBlockOutputHLSL : public TIntermTraverser
int mMatrixStride; int mMatrixStride;
bool mRowMajor; bool mRowMajor;
bool mIsLoadFunctionCall; bool mLocationAsTheLastArgument;
OutputHLSL *mOutputHLSL; OutputHLSL *mOutputHLSL;
ShaderStorageBlockFunctionHLSL *mSSBOFunctionHLSL; ShaderStorageBlockFunctionHLSL *mSSBOFunctionHLSL;
ResourcesHLSL *mResourcesHLSL; ResourcesHLSL *mResourcesHLSL;
......
...@@ -1539,6 +1539,68 @@ void main() ...@@ -1539,6 +1539,68 @@ void main()
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// Test that the length of unsized array is supported.
TEST_P(ShaderStorageBufferTest31, UnsizedArrayLength)
{
constexpr char kComputeShaderSource[] =
R"(#version 310 es
layout (local_size_x=1) in;
layout(std430, binding = 0) buffer Storage0 {
uint buf1[2];
uint buf2[];
} sb_load;
layout(std430, binding = 1) buffer Storage1 {
int unsizedArrayLength;
uint buf1[2];
uint buf2[];
} sb_store;
void main()
{
sb_store.unsizedArrayLength = sb_store.buf2.length();
for (int i = 0; i < sb_load.buf1.length(); i++) {
sb_store.buf1[i] = sb_load.buf1[i];
}
for (int i = 0; i < sb_load.buf2.length(); i++) {
sb_store.buf2[i] = sb_load.buf2[i];
}
}
)";
ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
glUseProgram(program);
constexpr unsigned int kBytesPerComponent = sizeof(unsigned int);
constexpr unsigned int kLoadBlockElementCount = 5;
constexpr unsigned int kStoreBlockElementCount = 6;
constexpr unsigned int kInputValues[kLoadBlockElementCount] = {1u, 2u, 3u, 4u, 5u};
constexpr unsigned int kExpectedValues[kStoreBlockElementCount] = {3u, 1u, 2u, 3u, 4u, 5u};
GLBuffer shaderStorageBuffer[2];
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kLoadBlockElementCount * kBytesPerComponent,
&kInputValues, GL_STATIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kStoreBlockElementCount * kBytesPerComponent, nullptr,
GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
glDispatchCompute(1, 1, 1);
glFinish();
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
const GLuint *ptr = reinterpret_cast<const GLuint *>(
glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kStoreBlockElementCount * kBytesPerComponent,
GL_MAP_READ_BIT));
for (unsigned int i = 0; i < kStoreBlockElementCount; i++)
{
EXPECT_EQ(kExpectedValues[i], *(ptr + i));
}
EXPECT_GL_NO_ERROR();
}
// Test that compond assignment operator for buffer variable is correctly handled. // Test that compond assignment operator for buffer variable is correctly handled.
TEST_P(ShaderStorageBufferTest31, CompoundAssignmentOperator) TEST_P(ShaderStorageBufferTest31, CompoundAssignmentOperator)
{ {
......
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