ES31: Support shader storage block in D3D11 compiler - Part1
This patch is the first step to implement a basic skeleton to translate
shader storage block to HLSL RWByteAddressBuffer.
In GLSL each shader storage block is just one structured block and in API side
it corresponds to a buffer range where stores the whole structure.
RWStructuredBuffer is an array-like object and can have many structured
elements. The structured element doesn't support unsized array and also have
a small limitation on the element size. So we choose RWByteAddressBuffer as
the counterpart of shader storage block in HLSL.
Due to RWByteAddressBuffer does not support using an index to reference a
specific location, we must use Load and Store to process the read/write
operation of a buffer variable. Moreover, in the compiler tree, since we
can't use variable name to get the resource value in RWByteAddressBuffer,
we have to calculate the offset of buffer variable in a shader storage block,
then call the corresponding wrapper function to get the right value.
In this patch, we only process below situations:
assign_to_ssbo := ssbo_access_chain = expr_no_ssbo;
assign_from_ssbo := lvalue_no_ssbo = ssbo_access_chain;
The translation is like below:
// GLSL
#version 310 es
layout(local_size_x=8) in;
layout(std140, binding = 0) buffer blockA {
float f[8];
} instanceA;
layout(std140, binding = 1) buffer blockB {
float f[8];
};
void main()
{
float data = instanceA.f[gl_LocalInvocationIndex];
f[gl_LocalInvocationIndex] = data;
}
// HLSL
RWByteAddressBuffer _instanceA: register(u0);
RWByteAddressBuffer _blockB: register(u1);
float float_Load(RWByteAddressBuffer buffer, uint loc)
{
float result = asfloat(buffer.Load(loc));
return result;
}
void float_Store(RWByteAddressBuffer buffer, uint loc, float value)
{
buffer.Store(loc, asuint(value));
}
void gl_main()
{
float _data = float_Load(_instanceA, 0 + 16 * gl_LocalInvocationIndex);
float_Store(_blockB, 0 + 16 * gl_LocalInvocationIndex, _data);
}
We will do below things in the following patches:
1. Modify the intermediate tree to flatten all ssbo usages to:
assign_to_ssbo := ssbo_access_chain = expr_no_ssbo;
assign_from_ssbo := lvalue_no_ssbo = ssbo_access_chain;
e.g.
intanceA.a +=1;
->tmp = intanceA.a;
intanceA.a = tmp + 1;
while(++instanceA.a < 16) {
}
->
int PreIncrement(out int a)
{
a += 1;
return a;
}
tmp = instanceA.a;
while(PreIncrement(tmp) < 16) {
instanceA.a = tmp
}
2. Add offset calculation for structure and array of arrays.
TODOs have been marked in the corresponding places in this patch.
3. Improve helper functions so that they can process all possible types.
TODOs have been marked in the corresponding places in this patch.
4. Process the swizzle situation.
TODOs have been marked in the corresponding places in this patch.
A possible method is to extend current helper functions like below:
*_Load(RWByteAddressBuffer buffer, uint loc, bool isSwizzle, uint4 swizzleOffset)
Bug: angleproject:1951
Test: angle_end2end_tests
Change-Id: I68ae68d5bb77d0d5627c8272627a7f689b8dc38b
Reviewed-on: https://chromium-review.googlesource.com/848215
Reviewed-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jiajia Qin <jiajia.qin@intel.com>
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 0f360b9..65925f7 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -59,22 +59,25 @@
variable->getQualifier() == EvqConst || variable->getQualifier() == EvqShared);
}
-bool IsInStd140InterfaceBlock(TIntermTyped *node)
+bool IsInStd140UniformBlock(TIntermTyped *node)
{
TIntermBinary *binaryNode = node->getAsBinaryNode();
if (binaryNode)
{
- return IsInStd140InterfaceBlock(binaryNode->getLeft());
+ return IsInStd140UniformBlock(binaryNode->getLeft());
}
const TType &type = node->getType();
- // determine if we are in the standard layout
- const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
- if (interfaceBlock)
+ if (type.getQualifier() == EvqUniform)
{
- return (interfaceBlock->blockStorage() == EbsStd140);
+ // determine if we are in the standard layout
+ const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+ if (interfaceBlock)
+ {
+ return (interfaceBlock->blockStorage() == EbsStd140);
+ }
}
return false;
@@ -249,10 +252,13 @@
// Reserve registers for the default uniform block and driver constants
mResourcesHLSL->reserveUniformBlockRegisters(2);
+
+ mSSBOOutputHLSL = new ShaderStorageBlockOutputHLSL(this, symbolTable, mResourcesHLSL);
}
OutputHLSL::~OutputHLSL()
{
+ SafeDelete(mSSBOOutputHLSL);
SafeDelete(mStructureHLSL);
SafeDelete(mResourcesHLSL);
SafeDelete(mTextureFunctionHLSL);
@@ -384,9 +390,20 @@
{
const TInterfaceBlock *interfaceBlock =
mappedStruct.blockDeclarator->getType().getInterfaceBlock();
- if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
+ TQualifier qualifier = mappedStruct.blockDeclarator->getType().getQualifier();
+ switch (qualifier)
{
- continue;
+ case EvqUniform:
+ if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
+ {
+ continue;
+ }
+ break;
+ case EvqBuffer:
+ continue;
+ default:
+ UNREACHABLE();
+ return mappedStructs;
}
unsigned int instanceCount = 1u;
@@ -409,7 +426,7 @@
unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
if (isInstanceArray)
instanceStringArrayIndex = instanceArrayIndex;
- TString instanceString = mResourcesHLSL->UniformBlockInstanceString(
+ TString instanceString = mResourcesHLSL->InterfaceBlockInstanceString(
instanceName, instanceStringArrayIndex);
originalName += instanceString;
mappedName += instanceString;
@@ -473,6 +490,7 @@
mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
+ mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out);
if (!mEqualityFunctions.empty())
{
@@ -905,7 +923,7 @@
TInfoSinkBase &out = getInfoSink();
// Handle accessing std140 structs by value
- if (IsInStd140InterfaceBlock(node) && node->getBasicType() == EbtStruct)
+ if (IsInStd140UniformBlock(node) && node->getBasicType() == EbtStruct)
{
out << "map";
}
@@ -949,6 +967,10 @@
out << DecorateVariableIfNeeded(variable);
}
+ else if (qualifier == EvqBuffer)
+ {
+ UNREACHABLE();
+ }
else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
{
mReferencedAttributes[uniqueId.get()] = &variable;
@@ -1193,6 +1215,29 @@
out << ")";
return false;
}
+ else if (IsInShaderStorageBlock(node->getLeft()))
+ {
+ mSSBOOutputHLSL->outputStoreFunctionCallPrefix(node->getLeft());
+ out << ", ";
+ if (IsInShaderStorageBlock(node->getRight()))
+ {
+ mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
+ }
+ else
+ {
+ node->getRight()->traverse(this);
+ }
+
+ out << ")";
+ return false;
+ }
+ else if (IsInShaderStorageBlock(node->getRight()))
+ {
+ node->getLeft()->traverse(this);
+ out << " = ";
+ mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
+ return false;
+ }
outputAssign(visit, node->getType(), out);
break;
@@ -1224,6 +1269,11 @@
else if (visit == InVisit)
{
out << " = ";
+ if (IsInShaderStorageBlock(node->getRight()))
+ {
+ mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
+ return false;
+ }
}
break;
case EOpAddAssign:
@@ -1303,13 +1353,15 @@
{
TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
+
+ ASSERT(leftType.getQualifier() == EvqUniform);
if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
{
mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
}
const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
- out << mResourcesHLSL->UniformBlockInstanceString(
+ out << mResourcesHLSL->InterfaceBlockInstanceString(
instanceArraySymbol->getName(), arrayIndex);
return false;
}
@@ -1370,9 +1422,10 @@
break;
case EOpIndexDirectInterfaceBlock:
{
- bool structInStd140Block =
- node->getBasicType() == EbtStruct && IsInStd140InterfaceBlock(node->getLeft());
- if (visit == PreVisit && structInStd140Block)
+ ASSERT(!IsInShaderStorageBlock(node->getLeft()));
+ bool structInStd140UniformBlock =
+ node->getBasicType() == EbtStruct && IsInStd140UniformBlock(node->getLeft());
+ if (visit == PreVisit && structInStd140UniformBlock)
{
out << "map";
}
@@ -1382,7 +1435,7 @@
node->getLeft()->getType().getInterfaceBlock();
const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
const TField *field = interfaceBlock->fields()[index->getIConst(0)];
- if (structInStd140Block)
+ if (structInStd140UniformBlock)
{
out << "_";
}