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)
// tested in GLSLTest and results are consistent with GL.
outputTriplet(out, visit, "firstbithigh(", "", ")");
break;
case EOpArrayLength:
{
TIntermTyped *operand = node->getOperand();
ASSERT(IsInShaderStorageBlock(operand));
mSSBOOutputHLSL->outputLengthFunctionCall(operand);
return false;
}
default:
UNREACHABLE();
}
......
......@@ -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<(
const ShaderStorageBlockFunction &rhs) const
{
......@@ -201,11 +210,30 @@ TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction(
TLayoutBlockStorage storage,
bool rowMajor,
int matrixStride,
int unsizedArrayStride,
TIntermSwizzle *swizzleNode)
{
ShaderStorageBlockFunction ssboFunction;
ssboFunction.typeString = TypeString(type);
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;
if (swizzleNode != nullptr)
{
......@@ -230,20 +258,7 @@ TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction(
}
ssboFunction.rowMajor = rowMajor;
ssboFunction.matrixStride = matrixStride;
ssboFunction.functionName =
TString(getBlockStorageString(storage)) + "_" + ssboFunction.typeString;
switch (method)
{
case SSBOMethod::LOAD:
ssboFunction.functionName += "_Load";
break;
case SSBOMethod::STORE:
ssboFunction.functionName += "_Store";
break;
default:
UNREACHABLE();
}
ssboFunction.functionName += "_" + TString(getBlockStorageString(storage));
if (rowMajor)
{
......@@ -291,7 +306,7 @@ void ShaderStorageBlockFunctionHLSL::shaderStorageBlockFunctionHeader(TInfoSinkB
out << "{\n";
OutputSSBOLoadFunctionBody(out, ssboFunction);
}
else
else if (ssboFunction.method == SSBOMethod::STORE)
{
// Function header
out << "void " << ssboFunction.functionName << "(RWByteAddressBuffer buffer, uint loc, "
......@@ -299,6 +314,14 @@ void ShaderStorageBlockFunctionHLSL::shaderStorageBlockFunctionHeader(TInfoSinkB
out << "{\n";
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"
"\n";
......
......@@ -38,7 +38,8 @@ class TIntermSwizzle;
enum class SSBOMethod
{
LOAD,
STORE
STORE,
LENGTH
};
class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable
......@@ -49,6 +50,7 @@ class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable
TLayoutBlockStorage storage,
bool rowMajor,
int matrixStride,
int unsizedArrayStride,
TIntermSwizzle *node);
void shaderStorageBlockFunctionHeader(TInfoSinkBase &out);
......@@ -63,14 +65,16 @@ class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable
TType type;
bool rowMajor;
int matrixStride;
int unsizedArrayStride;
TVector<int> swizzleOffsets;
bool isDefaultSwizzle;
};
static void OutputSSBOLoadFunctionBody(TInfoSinkBase &out,
const ShaderStorageBlockFunction &imageFunction);
const ShaderStorageBlockFunction &ssboFunction);
static void OutputSSBOStoreFunctionBody(TInfoSinkBase &out,
const ShaderStorageBlockFunction &imageFunction);
const ShaderStorageBlockFunction &ssboFunction);
static void OutputSSBOLengthFunctionBody(TInfoSinkBase &out, int unsizedArrayStride);
using ShaderStorageBlockFunctionSet = std::set<ShaderStorageBlockFunction>;
ShaderStorageBlockFunctionSet mRegisteredShaderStorageBlockFunctions;
};
......
......@@ -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
// the right layout information to GetMatrixStride.
unsigned int GetMatrixStride(const TType &type, TLayoutBlockStorage storage, bool rowMajor)
// the right layout information to GetBlockMemberInfoByType.
const BlockMemberInfo GetBlockMemberInfoByType(const TType &type,
TLayoutBlockStorage storage,
bool rowMajor)
{
sh::Std140BlockEncoder std140Encoder;
sh::Std430BlockEncoder std430Encoder;
......@@ -114,9 +116,7 @@ unsigned int GetMatrixStride(const TType &type, TLayoutBlockStorage storage, boo
{
arraySizes.assign(typeArraySizes->begin(), typeArraySizes->end());
}
const BlockMemberInfo &memberInfo =
encoder->encodeType(GLVariableType(type), arraySizes, rowMajor);
return memberInfo.matrixStride;
return encoder->encodeType(GLVariableType(type), arraySizes, rowMajor);
}
const TField *GetFieldMemberInShaderStorageBlock(const TInterfaceBlock *interfaceBlock,
......@@ -299,7 +299,7 @@ ShaderStorageBlockOutputHLSL::ShaderStorageBlockOutputHLSL(OutputHLSL *outputHLS
: TIntermTraverser(true, true, true, symbolTable),
mMatrixStride(0),
mRowMajor(false),
mIsLoadFunctionCall(false),
mLocationAsTheLastArgument(false),
mOutputHLSL(outputHLSL),
mResourcesHLSL(resourcesHLSL)
{
......@@ -313,16 +313,22 @@ ShaderStorageBlockOutputHLSL::~ShaderStorageBlockOutputHLSL()
void ShaderStorageBlockOutputHLSL::outputStoreFunctionCallPrefix(TIntermTyped *node)
{
mIsLoadFunctionCall = false;
mLocationAsTheLastArgument = false;
traverseSSBOAccess(node, SSBOMethod::STORE);
}
void ShaderStorageBlockOutputHLSL::outputLoadFunctionCall(TIntermTyped *node)
{
mIsLoadFunctionCall = true;
mLocationAsTheLastArgument = true;
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.
// 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.
......@@ -332,7 +338,7 @@ void ShaderStorageBlockOutputHLSL::setMatrixStride(TIntermTyped *node,
{
if (node->getType().isMatrix())
{
mMatrixStride = GetMatrixStride(node->getType(), storage, rowMajor);
mMatrixStride = GetBlockMemberInfoByType(node->getType(), storage, rowMajor).matrixStride;
mRowMajor = rowMajor;
return;
}
......@@ -366,10 +372,17 @@ void ShaderStorageBlockOutputHLSL::traverseSSBOAccess(TIntermTyped *node, SSBOMe
TLayoutBlockStorage storage;
bool rowMajor;
GetBlockLayoutInfo(node, false, &storage, &rowMajor);
int unsizedArrayStride = 0;
if (node->getType().isUnsizedArray())
{
unsizedArrayStride =
GetBlockMemberInfoByType(node->getType(), storage, rowMajor).arrayStride;
}
setMatrixStride(node, storage, rowMajor);
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();
out << functionName;
out << "(";
......@@ -488,7 +501,7 @@ bool ShaderStorageBlockOutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *nod
TInfoSinkBase &out = mOutputHLSL->getInfoSink();
// 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]
if (mIsLoadFunctionCall && isEndOfSSBOAccessChain())
if (mLocationAsTheLastArgument && isEndOfSSBOAccessChain())
{
out << ")";
}
......@@ -657,7 +670,7 @@ void ShaderStorageBlockOutputHLSL::writeEOpIndexDirectOrIndirectOutput(TInfoSink
{
out << ")";
}
if (mIsLoadFunctionCall && isEndOfSSBOAccessChain())
if (mLocationAsTheLastArgument && isEndOfSSBOAccessChain())
{
out << ")";
}
......@@ -683,7 +696,7 @@ void ShaderStorageBlockOutputHLSL::writeDotOperatorOutput(TInfoSinkBase &out, co
out << " * (";
}
}
if (mIsLoadFunctionCall && isEndOfSSBOAccessChain())
if (mLocationAsTheLastArgument && isEndOfSSBOAccessChain())
{
out << ")";
}
......
......@@ -47,8 +47,10 @@ class ShaderStorageBlockOutputHLSL : public TIntermTraverser
// calling this, ", <stored value>)" should be written to the output stream to complete the
// function call.
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);
// This writes the function call to get the lengh of unsized array member of SSBO.
void outputLengthFunctionCall(TIntermTyped *node);
void writeShaderStorageBlocksHeader(TInfoSinkBase &out) const;
......@@ -71,7 +73,7 @@ class ShaderStorageBlockOutputHLSL : public TIntermTraverser
int mMatrixStride;
bool mRowMajor;
bool mIsLoadFunctionCall;
bool mLocationAsTheLastArgument;
OutputHLSL *mOutputHLSL;
ShaderStorageBlockFunctionHLSL *mSSBOFunctionHLSL;
ResourcesHLSL *mResourcesHLSL;
......
......@@ -1539,6 +1539,68 @@ void main()
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_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