Commit 81a880aa by Qin Jiajia Committed by Commit Bot

ES31: support ssbo as binary operand

This patch will process ssbo as compound assignment binary operand or readonly binary operand. BUG: angleproject:1951 Change-Id: I4a0da77649d719fa08e6bf4c3d9ace58dbfb7aab Reviewed-on: https://chromium-review.googlesource.com/c/1349449 Commit-Queue: Jiajia Qin <jiajia.qin@intel.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 8e636443
...@@ -156,6 +156,8 @@ angle_translator_sources = [ ...@@ -156,6 +156,8 @@ angle_translator_sources = [
"src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h", "src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h",
"src/compiler/translator/tree_ops/RewriteDoWhile.cpp", "src/compiler/translator/tree_ops/RewriteDoWhile.cpp",
"src/compiler/translator/tree_ops/RewriteDoWhile.h", "src/compiler/translator/tree_ops/RewriteDoWhile.h",
"src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.cpp",
"src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h",
"src/compiler/translator/tree_ops/RewriteStructSamplers.cpp", "src/compiler/translator/tree_ops/RewriteStructSamplers.cpp",
"src/compiler/translator/tree_ops/RewriteStructSamplers.h", "src/compiler/translator/tree_ops/RewriteStructSamplers.h",
"src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.cpp", "src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.cpp",
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "compiler/translator/tree_ops/RemoveDynamicIndexing.h" #include "compiler/translator/tree_ops/RemoveDynamicIndexing.h"
#include "compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h" #include "compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h"
#include "compiler/translator/tree_ops/RewriteElseBlocks.h" #include "compiler/translator/tree_ops/RewriteElseBlocks.h"
#include "compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h"
#include "compiler/translator/tree_ops/RewriteTexelFetchOffset.h" #include "compiler/translator/tree_ops/RewriteTexelFetchOffset.h"
#include "compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.h" #include "compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.h"
#include "compiler/translator/tree_ops/SeparateArrayConstructorStatements.h" #include "compiler/translator/tree_ops/SeparateArrayConstructorStatements.h"
...@@ -129,6 +130,7 @@ void TranslatorHLSL::translate(TIntermBlock *root, ...@@ -129,6 +130,7 @@ void TranslatorHLSL::translate(TIntermBlock *root,
if (getShaderVersion() >= 310) if (getShaderVersion() >= 310)
{ {
sh::RewriteAtomicFunctionExpressions(root, &getSymbolTable(), getShaderVersion()); sh::RewriteAtomicFunctionExpressions(root, &getSymbolTable(), getShaderVersion());
sh::RewriteExpressionsWithShaderStorageBlock(root, &getSymbolTable());
} }
sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(), sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(),
......
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// RewriteExpressionsWithShaderStorageBlock rewrites the expressions that contain shader storage
// block calls into several simple ones that can be easily handled in the HLSL translator. After the
// AST pass, all ssbo related blocks will be like below:
// ssbo_access_chain = ssbo_access_chain;
// ssbo_access_chain = expr_no_ssbo;
// lvalue_no_ssbo = ssbo_access_chain;
//
#include "compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h"
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
#include "compiler/translator/util.h"
namespace sh
{
namespace
{
bool IsCompoundAssignment(TOperator op)
{
switch (op)
{
case EOpAddAssign:
case EOpSubAssign:
case EOpMulAssign:
case EOpVectorTimesMatrixAssign:
case EOpVectorTimesScalarAssign:
case EOpMatrixTimesScalarAssign:
case EOpMatrixTimesMatrixAssign:
case EOpDivAssign:
case EOpIModAssign:
case EOpBitShiftLeftAssign:
case EOpBitShiftRightAssign:
case EOpBitwiseAndAssign:
case EOpBitwiseXorAssign:
case EOpBitwiseOrAssign:
return true;
default:
return false;
}
}
// EOpIndexDirect, EOpIndexIndirect, EOpIndexDirectStruct, EOpIndexDirectInterfaceBlock belong to
// operators in SSBO access chain.
bool IsReadonlyBinaryOperatorNotInSSBOAccessChain(TOperator op)
{
switch (op)
{
case EOpComma:
case EOpAdd:
case EOpSub:
case EOpMul:
case EOpDiv:
case EOpIMod:
case EOpBitShiftLeft:
case EOpBitShiftRight:
case EOpBitwiseAnd:
case EOpBitwiseXor:
case EOpBitwiseOr:
case EOpEqual:
case EOpNotEqual:
case EOpLessThan:
case EOpGreaterThan:
case EOpLessThanEqual:
case EOpGreaterThanEqual:
case EOpVectorTimesScalar:
case EOpMatrixTimesScalar:
case EOpVectorTimesMatrix:
case EOpMatrixTimesVector:
case EOpMatrixTimesMatrix:
case EOpLogicalOr:
case EOpLogicalXor:
case EOpLogicalAnd:
return true;
default:
return false;
}
}
class RewriteExpressionsWithShaderStorageBlockTraverser : public TIntermTraverser
{
public:
RewriteExpressionsWithShaderStorageBlockTraverser(TSymbolTable *symbolTable);
void nextIteration();
bool foundSSBO() const { return mFoundSSBO; }
private:
bool visitBinary(Visit, TIntermBinary *node) override;
TIntermSymbol *insertInitStatementAndReturnTempSymbol(TIntermTyped *node,
TIntermSequence *insertions);
bool mFoundSSBO;
};
RewriteExpressionsWithShaderStorageBlockTraverser::
RewriteExpressionsWithShaderStorageBlockTraverser(TSymbolTable *symbolTable)
: TIntermTraverser(true, false, false, symbolTable), mFoundSSBO(false)
{}
TIntermSymbol *
RewriteExpressionsWithShaderStorageBlockTraverser::insertInitStatementAndReturnTempSymbol(
TIntermTyped *node,
TIntermSequence *insertions)
{
TIntermDeclaration *variableDeclaration;
TVariable *tempVariable =
DeclareTempVariable(mSymbolTable, node, EvqTemporary, &variableDeclaration);
insertions->push_back(variableDeclaration);
return CreateTempSymbolNode(tempVariable);
}
bool RewriteExpressionsWithShaderStorageBlockTraverser::visitBinary(Visit, TIntermBinary *node)
{
if (mFoundSSBO)
{
return false;
}
bool rightSSBO = IsInShaderStorageBlock(node->getRight());
bool leftSSBO = IsInShaderStorageBlock(node->getLeft());
if (!leftSSBO && !rightSSBO)
{
return true;
}
// case 1: Compound assigment operator
// original:
// lssbo += expr_no_ssbo;
// new:
// var temp = lssbo;
// temp += expr_no_ssbo;
// lssbo = temp;
//
// original:
// lssbo += rssbo;
// new:
// var rvalue = rssbo;
// var temp = lssbo;
// temp += rvalue;
// lssbo = temp;
//
// original:
// lvalue_no_ssbo += rssbo;
// new:
// var rvalue = rssbo;
// lvalue_no_ssbo += rvalue;
if (IsCompoundAssignment(node->getOp()))
{
mFoundSSBO = true;
TIntermSequence insertions;
TIntermTyped *rightNode = node->getRight();
if (rightSSBO)
{
rightNode = insertInitStatementAndReturnTempSymbol(node->getRight(), &insertions);
}
if (leftSSBO)
{
TIntermSymbol *tempSymbol =
insertInitStatementAndReturnTempSymbol(node->getLeft(), &insertions);
TIntermBinary *tempCompoundOperate =
new TIntermBinary(node->getOp(), tempSymbol, rightNode);
insertions.push_back(tempCompoundOperate);
insertStatementsInParentBlock(insertions);
TIntermBinary *assignTempValueToSSBO =
new TIntermBinary(EOpAssign, node->getLeft(), tempSymbol);
queueReplacement(assignTempValueToSSBO, OriginalNode::IS_DROPPED);
}
else
{
insertStatementsInParentBlock(insertions);
TIntermBinary *assignTempValueToLValue =
new TIntermBinary(node->getOp(), node->getLeft(), rightNode);
queueReplacement(assignTempValueToLValue, OriginalNode::IS_DROPPED);
}
}
// case 2: Readonly binary operator
// original:
// ssbo0 + ssbo1 + ssbo2;
// new:
// var temp0 = ssbo0;
// var temp1 = ssbo1;
// var temp2 = ssbo2;
// temp0 + temp1 + temp2;
else if (IsReadonlyBinaryOperatorNotInSSBOAccessChain(node->getOp()) && (leftSSBO || rightSSBO))
{
mFoundSSBO = true;
TIntermTyped *rightNode = node->getRight();
TIntermTyped *leftNode = node->getLeft();
TIntermSequence insertions;
if (rightSSBO)
{
rightNode = insertInitStatementAndReturnTempSymbol(node->getRight(), &insertions);
}
if (leftSSBO)
{
leftNode = insertInitStatementAndReturnTempSymbol(node->getLeft(), &insertions);
}
insertStatementsInParentBlock(insertions);
TIntermBinary *newExpr = new TIntermBinary(node->getOp(), leftNode, rightNode);
queueReplacement(newExpr, OriginalNode::IS_DROPPED);
}
return !mFoundSSBO;
}
void RewriteExpressionsWithShaderStorageBlockTraverser::nextIteration()
{
mFoundSSBO = false;
}
} // anonymous namespace
void RewriteExpressionsWithShaderStorageBlock(TIntermNode *root, TSymbolTable *symbolTable)
{
RewriteExpressionsWithShaderStorageBlockTraverser traverser(symbolTable);
do
{
traverser.nextIteration();
root->traverse(&traverser);
if (traverser.foundSSBO())
traverser.updateTree();
} while (traverser.foundSSBO());
}
} // namespace sh
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// RewriteExpressionsWithShaderStorageBlock rewrites the expressions that contain shader storage
// block calls into several simple ones that can be easily handled in the HLSL translator. After the
// AST pass, all ssbo related blocks will be like below:
// ssbo_access_chain = ssbo_access_chain;
// ssbo_access_chain = expr_no_ssbo;
// lvalue_no_ssbo = ssbo_access_chain;
//
// Below situations are needed to be rewritten (Details can be found in .cpp file).
// SSBO as the operand of compound assignment operators.
// SSBO as the operand of ++/--.
// SSBO as the operand of repeated assignment.
// SSBO as the operand of readonly unary/binary/ternary operators.
// SSBO as the argument of aggregate type.
// SSBO as the condition of if/switch/while/do-while/for
#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITE_EXPRESSIONS_WITH_SHADER_STORAGE_BLOCK_H_
#define COMPILER_TRANSLATOR_TREEOPS_REWRITE_EXPRESSIONS_WITH_SHADER_STORAGE_BLOCK_H_
namespace sh
{
class TIntermNode;
class TSymbolTable;
void RewriteExpressionsWithShaderStorageBlock(TIntermNode *root, TSymbolTable *symbolTable);
} // namespace sh
#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITE_EXPRESSIONS_WITH_SHADER_STORAGE_BLOCK_H_
...@@ -1539,6 +1539,127 @@ void main() ...@@ -1539,6 +1539,127 @@ void main()
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// Test that compond assignment operator for buffer variable is correctly handled.
TEST_P(ShaderStorageBufferTest31, CompoundAssignmentOperator)
{
// http://anglebug.com/2990
ANGLE_SKIP_TEST_IF(IsD3D11());
constexpr char kComputeShaderSource[] =
R"(#version 310 es
layout (local_size_x=1) in;
layout(binding=0, std140) buffer Storage0
{
uint b;
} sb_load;
layout(binding=1, std140) buffer Storage1
{
uint b;
} sb_store;
void main()
{
uint temp = 2u;
temp += sb_load.b;
sb_store.b += temp;
sb_store.b += sb_load.b;
}
)";
ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
glUseProgram(program);
constexpr unsigned int kBytesPerComponent = sizeof(unsigned int);
constexpr unsigned int kInputValue = 1u;
constexpr unsigned int kExpectedValue = 5u;
GLBuffer shaderStorageBuffer[2];
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kBytesPerComponent, &kInputValue, GL_STATIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kBytesPerComponent, &kInputValue, 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, kBytesPerComponent, GL_MAP_READ_BIT));
EXPECT_EQ(kExpectedValue, *ptr);
EXPECT_GL_NO_ERROR();
}
// Test that readonly binary operator for buffer variable is correctly handled.
TEST_P(ShaderStorageBufferTest31, ReadonlyBinaryOperator)
{
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 blockIn1 {
uvec2 data1;
};
layout(std430, binding = 1) buffer blockIn2 {
uvec2 data2;
};
layout(std430, binding = 2) buffer blockIn3 {
uvec2 data;
} instanceIn3;
layout(std430, binding = 3) buffer blockOut {
uvec2 data;
} instanceOut;
void main()
{
instanceOut.data = data1 + data2 + instanceIn3.data;
}
)";
ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
glUseProgram(program);
constexpr unsigned int kComponentCount = 2;
constexpr unsigned int kBytesPerComponent = sizeof(unsigned int);
constexpr unsigned int kInputValues1[kComponentCount] = {1u, 2u};
constexpr unsigned int kInputValues2[kComponentCount] = {3u, 4u};
constexpr unsigned int kInputValues3[kComponentCount] = {5u, 6u};
// Create shader storage buffer
GLBuffer shaderStorageBuffer[4];
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kComponentCount * kBytesPerComponent, kInputValues1,
GL_STATIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kComponentCount * kBytesPerComponent, kInputValues2,
GL_STATIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[2]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kComponentCount * kBytesPerComponent, kInputValues3,
GL_STATIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[3]);
glBufferData(GL_SHADER_STORAGE_BUFFER, kComponentCount * kBytesPerComponent, nullptr,
GL_STATIC_DRAW);
// Bind shader storage buffer
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer[0]);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer[1]);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, shaderStorageBuffer[2]);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, shaderStorageBuffer[3]);
glDispatchCompute(1, 1, 1);
glFinish();
// Read back shader storage buffer
constexpr unsigned int kExpectedValues[kComponentCount] = {9u, 12u};
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer[3]);
const GLuint *ptr = reinterpret_cast<const GLuint *>(glMapBufferRange(
GL_SHADER_STORAGE_BUFFER, 0, kComponentCount * kBytesPerComponent, GL_MAP_READ_BIT));
for (unsigned int idx = 0; idx < kComponentCount; idx++)
{
EXPECT_EQ(kExpectedValues[idx], *(ptr + idx));
}
EXPECT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST(ShaderStorageBufferTest31, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11()); ANGLE_INSTANTIATE_TEST(ShaderStorageBufferTest31, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
} // namespace } // namespace
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