Commit a735ee2f by Qin Jiajia Committed by Commit Bot

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/848215Reviewed-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jiajia Qin <jiajia.qin@intel.com>
parent 1cee0421
...@@ -229,6 +229,10 @@ angle_translator_hlsl_sources = [ ...@@ -229,6 +229,10 @@ angle_translator_hlsl_sources = [
"src/compiler/translator/OutputHLSL.h", "src/compiler/translator/OutputHLSL.h",
"src/compiler/translator/ResourcesHLSL.cpp", "src/compiler/translator/ResourcesHLSL.cpp",
"src/compiler/translator/ResourcesHLSL.h", "src/compiler/translator/ResourcesHLSL.h",
"src/compiler/translator/ShaderStorageBlockFunctionHLSL.cpp",
"src/compiler/translator/ShaderStorageBlockFunctionHLSL.h",
"src/compiler/translator/ShaderStorageBlockOutputHLSL.cpp",
"src/compiler/translator/ShaderStorageBlockOutputHLSL.h",
"src/compiler/translator/StructureHLSL.cpp", "src/compiler/translator/StructureHLSL.cpp",
"src/compiler/translator/StructureHLSL.h", "src/compiler/translator/StructureHLSL.h",
"src/compiler/translator/TextureFunctionHLSL.cpp", "src/compiler/translator/TextureFunctionHLSL.cpp",
......
...@@ -59,22 +59,25 @@ bool IsDeclarationWrittenOut(TIntermDeclaration *node) ...@@ -59,22 +59,25 @@ bool IsDeclarationWrittenOut(TIntermDeclaration *node)
variable->getQualifier() == EvqConst || variable->getQualifier() == EvqShared); variable->getQualifier() == EvqConst || variable->getQualifier() == EvqShared);
} }
bool IsInStd140InterfaceBlock(TIntermTyped *node) bool IsInStd140UniformBlock(TIntermTyped *node)
{ {
TIntermBinary *binaryNode = node->getAsBinaryNode(); TIntermBinary *binaryNode = node->getAsBinaryNode();
if (binaryNode) if (binaryNode)
{ {
return IsInStd140InterfaceBlock(binaryNode->getLeft()); return IsInStd140UniformBlock(binaryNode->getLeft());
} }
const TType &type = node->getType(); const TType &type = node->getType();
// determine if we are in the standard layout if (type.getQualifier() == EvqUniform)
const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
if (interfaceBlock)
{ {
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; return false;
...@@ -249,10 +252,13 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType, ...@@ -249,10 +252,13 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType,
// Reserve registers for the default uniform block and driver constants // Reserve registers for the default uniform block and driver constants
mResourcesHLSL->reserveUniformBlockRegisters(2); mResourcesHLSL->reserveUniformBlockRegisters(2);
mSSBOOutputHLSL = new ShaderStorageBlockOutputHLSL(this, symbolTable, mResourcesHLSL);
} }
OutputHLSL::~OutputHLSL() OutputHLSL::~OutputHLSL()
{ {
SafeDelete(mSSBOOutputHLSL);
SafeDelete(mStructureHLSL); SafeDelete(mStructureHLSL);
SafeDelete(mResourcesHLSL); SafeDelete(mResourcesHLSL);
SafeDelete(mTextureFunctionHLSL); SafeDelete(mTextureFunctionHLSL);
...@@ -384,9 +390,20 @@ TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std14 ...@@ -384,9 +390,20 @@ TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std14
{ {
const TInterfaceBlock *interfaceBlock = const TInterfaceBlock *interfaceBlock =
mappedStruct.blockDeclarator->getType().getInterfaceBlock(); 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; unsigned int instanceCount = 1u;
...@@ -409,7 +426,7 @@ TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std14 ...@@ -409,7 +426,7 @@ TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std14
unsigned int instanceStringArrayIndex = GL_INVALID_INDEX; unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
if (isInstanceArray) if (isInstanceArray)
instanceStringArrayIndex = instanceArrayIndex; instanceStringArrayIndex = instanceArrayIndex;
TString instanceString = mResourcesHLSL->UniformBlockInstanceString( TString instanceString = mResourcesHLSL->InterfaceBlockInstanceString(
instanceName, instanceStringArrayIndex); instanceName, instanceStringArrayIndex);
originalName += instanceString; originalName += instanceString;
mappedName += instanceString; mappedName += instanceString;
...@@ -473,6 +490,7 @@ void OutputHLSL::header(TInfoSinkBase &out, ...@@ -473,6 +490,7 @@ void OutputHLSL::header(TInfoSinkBase &out,
mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable); mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks); out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out);
if (!mEqualityFunctions.empty()) if (!mEqualityFunctions.empty())
{ {
...@@ -905,7 +923,7 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) ...@@ -905,7 +923,7 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
TInfoSinkBase &out = getInfoSink(); TInfoSinkBase &out = getInfoSink();
// Handle accessing std140 structs by value // Handle accessing std140 structs by value
if (IsInStd140InterfaceBlock(node) && node->getBasicType() == EbtStruct) if (IsInStd140UniformBlock(node) && node->getBasicType() == EbtStruct)
{ {
out << "map"; out << "map";
} }
...@@ -949,6 +967,10 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) ...@@ -949,6 +967,10 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
out << DecorateVariableIfNeeded(variable); out << DecorateVariableIfNeeded(variable);
} }
else if (qualifier == EvqBuffer)
{
UNREACHABLE();
}
else if (qualifier == EvqAttribute || qualifier == EvqVertexIn) else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
{ {
mReferencedAttributes[uniqueId.get()] = &variable; mReferencedAttributes[uniqueId.get()] = &variable;
...@@ -1193,6 +1215,29 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1193,6 +1215,29 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
out << ")"; out << ")";
return false; 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); outputAssign(visit, node->getType(), out);
break; break;
...@@ -1224,6 +1269,11 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1224,6 +1269,11 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
else if (visit == InVisit) else if (visit == InVisit)
{ {
out << " = "; out << " = ";
if (IsInShaderStorageBlock(node->getRight()))
{
mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
return false;
}
} }
break; break;
case EOpAddAssign: case EOpAddAssign:
...@@ -1303,13 +1353,15 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1303,13 +1353,15 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
{ {
TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode(); TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock(); const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
ASSERT(leftType.getQualifier() == EvqUniform);
if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0) if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
{ {
mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] = mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable()); new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
} }
const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0); const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
out << mResourcesHLSL->UniformBlockInstanceString( out << mResourcesHLSL->InterfaceBlockInstanceString(
instanceArraySymbol->getName(), arrayIndex); instanceArraySymbol->getName(), arrayIndex);
return false; return false;
} }
...@@ -1370,9 +1422,10 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1370,9 +1422,10 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
break; break;
case EOpIndexDirectInterfaceBlock: case EOpIndexDirectInterfaceBlock:
{ {
bool structInStd140Block = ASSERT(!IsInShaderStorageBlock(node->getLeft()));
node->getBasicType() == EbtStruct && IsInStd140InterfaceBlock(node->getLeft()); bool structInStd140UniformBlock =
if (visit == PreVisit && structInStd140Block) node->getBasicType() == EbtStruct && IsInStd140UniformBlock(node->getLeft());
if (visit == PreVisit && structInStd140UniformBlock)
{ {
out << "map"; out << "map";
} }
...@@ -1382,7 +1435,7 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1382,7 +1435,7 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
node->getLeft()->getType().getInterfaceBlock(); node->getLeft()->getType().getInterfaceBlock();
const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
const TField *field = interfaceBlock->fields()[index->getIConst(0)]; const TField *field = interfaceBlock->fields()[index->getIConst(0)];
if (structInStd140Block) if (structInStd140UniformBlock)
{ {
out << "_"; out << "_";
} }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "compiler/translator/Compiler.h" #include "compiler/translator/Compiler.h"
#include "compiler/translator/FlagStd140Structs.h" #include "compiler/translator/FlagStd140Structs.h"
#include "compiler/translator/ImmutableString.h" #include "compiler/translator/ImmutableString.h"
#include "compiler/translator/ShaderStorageBlockOutputHLSL.h"
#include "compiler/translator/tree_util/IntermTraverse.h" #include "compiler/translator/tree_util/IntermTraverse.h"
class BuiltInFunctionEmulator; class BuiltInFunctionEmulator;
...@@ -30,16 +31,6 @@ class TSymbolTable; ...@@ -30,16 +31,6 @@ class TSymbolTable;
class TVariable; class TVariable;
class UnfoldShortCircuit; class UnfoldShortCircuit;
struct TReferencedBlock : angle::NonCopyable
{
POOL_ALLOCATOR_NEW_DELETE();
TReferencedBlock(const TInterfaceBlock *block, const TVariable *instanceVariable);
const TInterfaceBlock *block;
const TVariable *instanceVariable; // May be nullptr if the block is not instanced.
};
// Maps from uniqueId to a variable.
using ReferencedInterfaceBlocks = std::map<int, const TReferencedBlock *>;
using ReferencedVariables = std::map<int, const TVariable *>; using ReferencedVariables = std::map<int, const TVariable *>;
class OutputHLSL : public TIntermTraverser class OutputHLSL : public TIntermTraverser
...@@ -73,6 +64,8 @@ class OutputHLSL : public TIntermTraverser ...@@ -73,6 +64,8 @@ class OutputHLSL : public TIntermTraverser
} }
protected: protected:
friend class ShaderStorageBlockOutputHLSL;
void writeReferencedAttributes(TInfoSinkBase &out) const; void writeReferencedAttributes(TInfoSinkBase &out) const;
void writeReferencedVaryings(TInfoSinkBase &out) const; void writeReferencedVaryings(TInfoSinkBase &out) const;
void header(TInfoSinkBase &out, void header(TInfoSinkBase &out,
...@@ -263,6 +256,7 @@ class OutputHLSL : public TIntermTraverser ...@@ -263,6 +256,7 @@ class OutputHLSL : public TIntermTraverser
TString generateStructMapping(const std::vector<MappedStruct> &std140Structs) const; TString generateStructMapping(const std::vector<MappedStruct> &std140Structs) const;
ImmutableString samplerNamePrefixFromStruct(TIntermTyped *node); ImmutableString samplerNamePrefixFromStruct(TIntermTyped *node);
bool ancestorEvaluatesToSamplerInStruct(); bool ancestorEvaluatesToSamplerInStruct();
ShaderStorageBlockOutputHLSL *mSSBOOutputHLSL;
}; };
} }
......
...@@ -102,7 +102,7 @@ ResourcesHLSL::ResourcesHLSL(StructureHLSL *structureHLSL, ...@@ -102,7 +102,7 @@ ResourcesHLSL::ResourcesHLSL(StructureHLSL *structureHLSL,
: mUniformRegister(firstUniformRegister), : mUniformRegister(firstUniformRegister),
mUniformBlockRegister(0), mUniformBlockRegister(0),
mTextureRegister(0), mTextureRegister(0),
mRWTextureRegister(0), mUAVRegister(0),
mSamplerCount(0), mSamplerCount(0),
mStructureHLSL(structureHLSL), mStructureHLSL(structureHLSL),
mOutputType(outputType), mOutputType(outputType),
...@@ -148,7 +148,7 @@ unsigned int ResourcesHLSL::assignUniformRegister(const TType &type, ...@@ -148,7 +148,7 @@ unsigned int ResourcesHLSL::assignUniformRegister(const TType &type,
} }
else if (IsImage(type.getBasicType())) else if (IsImage(type.getBasicType()))
{ {
registerIndex = mRWTextureRegister; registerIndex = mUAVRegister;
} }
else else
{ {
...@@ -166,7 +166,7 @@ unsigned int ResourcesHLSL::assignUniformRegister(const TType &type, ...@@ -166,7 +166,7 @@ unsigned int ResourcesHLSL::assignUniformRegister(const TType &type,
} }
else if (IsImage(type.getBasicType())) else if (IsImage(type.getBasicType()))
{ {
mRWTextureRegister += registerCount; mUAVRegister += registerCount;
} }
else else
{ {
...@@ -553,6 +553,40 @@ TString ResourcesHLSL::uniformBlocksHeader( ...@@ -553,6 +553,40 @@ TString ResourcesHLSL::uniformBlocksHeader(
return (interfaceBlocks.empty() ? "" : ("// Uniform Blocks\n\n" + interfaceBlocks)); return (interfaceBlocks.empty() ? "" : ("// Uniform Blocks\n\n" + interfaceBlocks));
} }
TString ResourcesHLSL::shaderStorageBlocksHeader(
const ReferencedInterfaceBlocks &referencedInterfaceBlocks)
{
TString interfaceBlocks;
for (const auto &interfaceBlockReference : referencedInterfaceBlocks)
{
const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block;
const TVariable *instanceVariable = interfaceBlockReference.second->instanceVariable;
unsigned int activeRegister = mUAVRegister;
mShaderStorageBlockRegisterMap[interfaceBlock.name().data()] = activeRegister;
if (instanceVariable != nullptr && instanceVariable->getType().isArray())
{
unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize();
for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
{
interfaceBlocks += shaderStorageBlockString(
interfaceBlock, instanceVariable, activeRegister + arrayIndex, arrayIndex);
}
mUAVRegister += instanceArraySize;
}
else
{
interfaceBlocks += shaderStorageBlockString(interfaceBlock, instanceVariable,
activeRegister, GL_INVALID_INDEX);
mUAVRegister += 1u;
}
}
return (interfaceBlocks.empty() ? "" : ("// Shader Storage Blocks\n\n" + interfaceBlocks));
}
TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock, TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock,
const TVariable *instanceVariable, const TVariable *instanceVariable,
unsigned int registerIndex, unsigned int registerIndex,
...@@ -569,7 +603,7 @@ TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock, ...@@ -569,7 +603,7 @@ TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock,
if (instanceVariable != nullptr) if (instanceVariable != nullptr)
{ {
hlsl += " " + InterfaceBlockStructName(interfaceBlock) + " " + hlsl += " " + InterfaceBlockStructName(interfaceBlock) + " " +
UniformBlockInstanceString(instanceVariable->name(), arrayIndex) + ";\n"; InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + ";\n";
} }
else else
{ {
...@@ -582,8 +616,28 @@ TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock, ...@@ -582,8 +616,28 @@ TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock,
return hlsl; return hlsl;
} }
TString ResourcesHLSL::UniformBlockInstanceString(const ImmutableString &instanceName, TString ResourcesHLSL::shaderStorageBlockString(const TInterfaceBlock &interfaceBlock,
unsigned int arrayIndex) const TVariable *instanceVariable,
unsigned int registerIndex,
unsigned int arrayIndex)
{
TString hlsl;
if (instanceVariable != nullptr)
{
hlsl += "RWByteAddressBuffer " +
InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) +
": register(u" + str(registerIndex) + ");\n";
}
else
{
hlsl += "RWByteAddressBuffer " + Decorate(interfaceBlock.name()) + ": register(u" +
str(registerIndex) + ");\n";
}
return hlsl;
}
TString ResourcesHLSL::InterfaceBlockInstanceString(const ImmutableString &instanceName,
unsigned int arrayIndex)
{ {
if (arrayIndex != GL_INVALID_INDEX) if (arrayIndex != GL_INVALID_INDEX)
{ {
......
...@@ -38,10 +38,11 @@ class ResourcesHLSL : angle::NonCopyable ...@@ -38,10 +38,11 @@ class ResourcesHLSL : angle::NonCopyable
void samplerMetadataUniforms(TInfoSinkBase &out, const char *reg); void samplerMetadataUniforms(TInfoSinkBase &out, const char *reg);
TString uniformBlocksHeader(const ReferencedInterfaceBlocks &referencedInterfaceBlocks); TString uniformBlocksHeader(const ReferencedInterfaceBlocks &referencedInterfaceBlocks);
TString shaderStorageBlocksHeader(const ReferencedInterfaceBlocks &referencedInterfaceBlocks);
// Used for direct index references // Used for direct index references
static TString UniformBlockInstanceString(const ImmutableString &instanceName, static TString InterfaceBlockInstanceString(const ImmutableString &instanceName,
unsigned int arrayIndex); unsigned int arrayIndex);
const std::map<std::string, unsigned int> &getUniformBlockRegisterMap() const const std::map<std::string, unsigned int> &getUniformBlockRegisterMap() const
{ {
...@@ -57,6 +58,11 @@ class ResourcesHLSL : angle::NonCopyable ...@@ -57,6 +58,11 @@ class ResourcesHLSL : angle::NonCopyable
const TVariable *instanceVariable, const TVariable *instanceVariable,
unsigned int registerIndex, unsigned int registerIndex,
unsigned int arrayIndex); unsigned int arrayIndex);
TString shaderStorageBlockString(const TInterfaceBlock &interfaceBlock,
const TVariable *instanceVariable,
unsigned int registerIndex,
unsigned int arrayIndex);
TString uniformBlockMembersString(const TInterfaceBlock &interfaceBlock, TString uniformBlockMembersString(const TInterfaceBlock &interfaceBlock,
TLayoutBlockStorage blockStorage); TLayoutBlockStorage blockStorage);
TString uniformBlockStructString(const TInterfaceBlock &interfaceBlock); TString uniformBlockStructString(const TInterfaceBlock &interfaceBlock);
...@@ -104,13 +110,14 @@ class ResourcesHLSL : angle::NonCopyable ...@@ -104,13 +110,14 @@ class ResourcesHLSL : angle::NonCopyable
unsigned int mUniformRegister; unsigned int mUniformRegister;
unsigned int mUniformBlockRegister; unsigned int mUniformBlockRegister;
unsigned int mTextureRegister; unsigned int mTextureRegister;
unsigned int mRWTextureRegister; unsigned int mUAVRegister;
unsigned int mSamplerCount; unsigned int mSamplerCount;
StructureHLSL *mStructureHLSL; StructureHLSL *mStructureHLSL;
ShShaderOutput mOutputType; ShShaderOutput mOutputType;
const std::vector<Uniform> &mUniforms; const std::vector<Uniform> &mUniforms;
std::map<std::string, unsigned int> mUniformBlockRegisterMap; std::map<std::string, unsigned int> mUniformBlockRegisterMap;
std::map<std::string, unsigned int> mShaderStorageBlockRegisterMap;
std::map<std::string, unsigned int> mUniformRegisterMap; std::map<std::string, unsigned int> mUniformRegisterMap;
}; };
} }
......
//
// 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.
//
// ShaderStorageBlockFunctionHLSL: Wrapper functions for RWByteAddressBuffer Load/Store functions.
//
#include "compiler/translator/ShaderStorageBlockFunctionHLSL.h"
#include "compiler/translator/UtilsHLSL.h"
namespace sh
{
// static
void ShaderStorageBlockFunctionHLSL::OutputSSBOLoadFunctionBody(
TInfoSinkBase &out,
const ShaderStorageBlockFunction &ssboFunction)
{
if (ssboFunction.type.isScalar())
{
TString convertString;
switch (ssboFunction.type.getBasicType())
{
case EbtFloat:
convertString = "asfloat(";
break;
case EbtInt:
convertString = "asint(";
break;
case EbtUInt:
convertString = "asuint(";
break;
case EbtBool:
convertString = "asint(";
break;
default:
UNREACHABLE();
break;
}
out << " " << ssboFunction.typeString << " result = " << convertString
<< "buffer.Load(loc));\n";
out << " return result;\n";
return;
}
// TODO(jiajia.qin@intel.com): Process all possible return types.
out << " return 1.0;\n";
}
// static
void ShaderStorageBlockFunctionHLSL::OutputSSBOStoreFunctionBody(
TInfoSinkBase &out,
const ShaderStorageBlockFunction &ssboFunction)
{
if (ssboFunction.type.isScalar())
{
out << " buffer.Store(loc, asuint(value));\n";
}
// TODO(jiajia.qin@intel.com): Process all possible return types.
}
bool ShaderStorageBlockFunctionHLSL::ShaderStorageBlockFunction::operator<(
const ShaderStorageBlockFunction &rhs) const
{
return std::tie(functionName, typeString, method) <
std::tie(rhs.functionName, rhs.typeString, rhs.method);
}
TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction(const TType &type,
SSBOMethod method)
{
ShaderStorageBlockFunction ssboFunction;
ssboFunction.typeString = TypeString(type);
ssboFunction.method = method;
ssboFunction.type = type;
switch (method)
{
case SSBOMethod::LOAD:
ssboFunction.functionName = ssboFunction.typeString + "_Load";
break;
case SSBOMethod::STORE:
ssboFunction.functionName = ssboFunction.typeString + "_Store";
break;
default:
UNREACHABLE();
}
mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
return ssboFunction.functionName;
}
void ShaderStorageBlockFunctionHLSL::shaderStorageBlockFunctionHeader(TInfoSinkBase &out)
{
for (const ShaderStorageBlockFunction &ssboFunction : mRegisteredShaderStorageBlockFunctions)
{
if (ssboFunction.method == SSBOMethod::LOAD)
{
// Function header
out << ssboFunction.typeString << " " << ssboFunction.functionName
<< "(RWByteAddressBuffer buffer, uint loc)\n";
out << "{\n";
OutputSSBOLoadFunctionBody(out, ssboFunction);
}
else
{
// Function header
out << "void " << ssboFunction.functionName << "(RWByteAddressBuffer buffer, uint loc, "
<< ssboFunction.typeString << " value)\n";
out << "{\n";
OutputSSBOStoreFunctionBody(out, ssboFunction);
}
out << "}\n"
"\n";
}
}
} // 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.
//
// ShaderStorageBlockOutputHLSL: A traverser to translate a ssbo_access_chain to an offset of
// RWByteAddressBuffer.
// //EOpIndexDirectInterfaceBlock
// ssbo_variable :=
// | the name of the SSBO
// | the name of a variable in an SSBO backed interface block
// // EOpIndexInDirect
// // EOpIndexDirect
// ssbo_array_indexing := ssbo_access_chain[expr_no_ssbo]
// // EOpIndexDirectStruct
// ssbo_structure_access := ssbo_access_chain.identifier
// ssbo_access_chain :=
// | ssbo_variable
// | ssbo_array_indexing
// | ssbo_structure_access
//
#ifndef COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKFUNCTIONHLSL_H_
#define COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKFUNCTIONHLSL_H_
#include <set>
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/Types.h"
namespace sh
{
enum class SSBOMethod
{
LOAD,
STORE
};
class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable
{
public:
TString registerShaderStorageBlockFunction(const TType &type, SSBOMethod method);
void shaderStorageBlockFunctionHeader(TInfoSinkBase &out);
private:
struct ShaderStorageBlockFunction
{
bool operator<(const ShaderStorageBlockFunction &rhs) const;
TString functionName;
TString typeString;
SSBOMethod method;
TType type;
};
static void OutputSSBOLoadFunctionBody(TInfoSinkBase &out,
const ShaderStorageBlockFunction &imageFunction);
static void OutputSSBOStoreFunctionBody(TInfoSinkBase &out,
const ShaderStorageBlockFunction &imageFunction);
using ShaderStorageBlockFunctionSet = std::set<ShaderStorageBlockFunction>;
ShaderStorageBlockFunctionSet mRegisteredShaderStorageBlockFunctions;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKFUNCTIONHLSL_H_
//
// 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.
//
// ShaderStorageBlockOutputHLSL: A traverser to translate a buffer variable of shader storage block
// to an offset of RWByteAddressBuffer.
//
#ifndef COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKOUTPUTHLSL_H_
#define COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKOUTPUTHLSL_H_
#include "compiler/translator/ShaderStorageBlockFunctionHLSL.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
namespace sh
{
class ResourcesHLSL;
class OutputHLSL;
class TSymbolTable;
struct TReferencedBlock : angle::NonCopyable
{
POOL_ALLOCATOR_NEW_DELETE();
TReferencedBlock(const TInterfaceBlock *block, const TVariable *instanceVariable);
const TInterfaceBlock *block;
const TVariable *instanceVariable; // May be nullptr if the block is not instanced.
};
// Maps from uniqueId to a variable.
using ReferencedInterfaceBlocks = std::map<int, const TReferencedBlock *>;
class ShaderStorageBlockOutputHLSL : public TIntermTraverser
{
public:
ShaderStorageBlockOutputHLSL(OutputHLSL *outputHLSL,
TSymbolTable *symbolTable,
ResourcesHLSL *resourcesHLSL);
~ShaderStorageBlockOutputHLSL();
// This writes part of the function call to store a value to a SSBO to the output stream. After
// 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.
void outputLoadFunctionCall(TIntermTyped *node);
void writeShaderStorageBlocksHeader(TInfoSinkBase &out) const;
protected:
void visitSymbol(TIntermSymbol *) override;
void visitConstantUnion(TIntermConstantUnion *) override;
bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
bool visitBinary(Visit visit, TIntermBinary *) override;
private:
void traverseSSBOAccess(TIntermTyped *node, SSBOMethod method);
bool isEndOfSSBOAccessChain();
void writeEOpIndexDirectOrIndirectOutput(TInfoSinkBase &out, Visit visit, TIntermBinary *node);
// Common part in dot operations.
void writeDotOperatorOutput(TInfoSinkBase &out, const TField *field);
bool mIsLoadFunctionCall;
OutputHLSL *mOutputHLSL;
ShaderStorageBlockFunctionHLSL *mSSBOFunctionHLSL;
ResourcesHLSL *mResourcesHLSL;
ReferencedInterfaceBlocks mReferencedShaderStorageBlocks;
};
}
#endif // COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKOUTPUTHLSL_H_
...@@ -174,7 +174,7 @@ TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRo ...@@ -174,7 +174,7 @@ TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRo
return ""; return "";
} }
int numComponents = 0; int numComponents = 0;
const TStructure *structure = type.getStruct(); const TStructure *structure = type.getStruct();
if (type.isMatrix()) if (type.isMatrix())
......
...@@ -32,7 +32,12 @@ class TField : angle::NonCopyable ...@@ -32,7 +32,12 @@ class TField : angle::NonCopyable
public: public:
POOL_ALLOCATOR_NEW_DELETE(); POOL_ALLOCATOR_NEW_DELETE();
TField(TType *type, const ImmutableString &name, const TSourceLoc &line, SymbolType symbolType) TField(TType *type, const ImmutableString &name, const TSourceLoc &line, SymbolType symbolType)
: mType(type), mName(name), mLine(line), mSymbolType(symbolType) : mType(type),
mName(name),
mLine(line),
mSymbolType(symbolType),
mOffset(0),
mArrayStride(0)
{ {
ASSERT(mSymbolType != SymbolType::Empty); ASSERT(mSymbolType != SymbolType::Empty);
} }
...@@ -44,12 +49,18 @@ class TField : angle::NonCopyable ...@@ -44,12 +49,18 @@ class TField : angle::NonCopyable
const ImmutableString &name() const { return mName; } const ImmutableString &name() const { return mName; }
const TSourceLoc &line() const { return mLine; } const TSourceLoc &line() const { return mLine; }
SymbolType symbolType() const { return mSymbolType; } SymbolType symbolType() const { return mSymbolType; }
unsigned int getOffset() const { return mOffset; }
unsigned int getArrayStride() const { return mArrayStride; }
void setOffset(unsigned int offset) { mOffset = offset; }
void setArrayStride(int arrayStride) { mArrayStride = arrayStride; }
private: private:
TType *mType; TType *mType;
const ImmutableString mName; const ImmutableString mName;
const TSourceLoc mLine; const TSourceLoc mLine;
const SymbolType mSymbolType; const SymbolType mSymbolType;
unsigned int mOffset;
unsigned int mArrayStride;
}; };
typedef TVector<TField *> TFieldList; typedef TVector<TField *> TFieldList;
......
...@@ -3,8 +3,10 @@ ...@@ -3,8 +3,10 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// //
// RemoveDynamicIndexing is an AST traverser to remove dynamic indexing of vectors and matrices, // RemoveDynamicIndexing is an AST traverser to remove dynamic indexing of non-SSBO vectors and
// replacing them with calls to functions that choose which component to return or write. // matrices, replacing them with calls to functions that choose which component to return or write.
// We don't need to consider dynamic indexing in SSBO since it can be directly as part of the offset
// of RWByteAddressBuffer.
// //
#include "compiler/translator/tree_ops/RemoveDynamicIndexing.h" #include "compiler/translator/tree_ops/RemoveDynamicIndexing.h"
...@@ -374,7 +376,7 @@ bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *nod ...@@ -374,7 +376,7 @@ bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *nod
TIntermSymbol *tempIndex = CreateTempSymbolNode(indexVariable); TIntermSymbol *tempIndex = CreateTempSymbolNode(indexVariable);
queueReplacementWithParent(node, node->getRight(), tempIndex, OriginalNode::IS_DROPPED); queueReplacementWithParent(node, node->getRight(), tempIndex, OriginalNode::IS_DROPPED);
} }
else if (IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(node)) else if (IntermNodePatternMatcher::IsDynamicIndexingOfNonSSBOVectorOrMatrix(node))
{ {
mPerfDiagnostics->warning(node->getLine(), mPerfDiagnostics->warning(node->getLine(),
"Performance: dynamic indexing of vectors and " "Performance: dynamic indexing of vectors and "
...@@ -429,7 +431,7 @@ bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *nod ...@@ -429,7 +431,7 @@ bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *nod
TIntermBinary *leftBinary = node->getLeft()->getAsBinaryNode(); TIntermBinary *leftBinary = node->getLeft()->getAsBinaryNode();
if (leftBinary != nullptr && if (leftBinary != nullptr &&
IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(leftBinary)) IntermNodePatternMatcher::IsDynamicIndexingOfNonSSBOVectorOrMatrix(leftBinary))
{ {
// This is a case like: // This is a case like:
// mat2 m; // mat2 m;
......
...@@ -3,8 +3,10 @@ ...@@ -3,8 +3,10 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// //
// RemoveDynamicIndexing is an AST traverser to remove dynamic indexing of vectors and matrices, // RemoveDynamicIndexing is an AST traverser to remove dynamic indexing of non-SSBO vectors and
// replacing them with calls to functions that choose which component to return or write. // matrices, replacing them with calls to functions that choose which component to return or write.
// We don't need to consider dynamic indexing in SSBO since it can be directly as part of the offset
// of RWByteAddressBuffer.
// //
#ifndef COMPILER_TRANSLATOR_TREEOPS_REMOVEDYNAMICINDEXING_H_ #ifndef COMPILER_TRANSLATOR_TREEOPS_REMOVEDYNAMICINDEXING_H_
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "compiler/translator/IntermNode.h" #include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h" #include "compiler/translator/SymbolTable.h"
#include "compiler/translator/util.h"
namespace sh namespace sh
{ {
...@@ -48,6 +49,12 @@ IntermNodePatternMatcher::IntermNodePatternMatcher(const unsigned int mask) : mM ...@@ -48,6 +49,12 @@ IntermNodePatternMatcher::IntermNodePatternMatcher(const unsigned int mask) : mM
} }
// static // static
bool IntermNodePatternMatcher::IsDynamicIndexingOfNonSSBOVectorOrMatrix(TIntermBinary *node)
{
return IsDynamicIndexingOfVectorOrMatrix(node) && !IsInShaderStorageBlock(node->getLeft());
}
// static
bool IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node) bool IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node)
{ {
return node->getOp() == EOpIndexIndirect && !node->getLeft()->isArray() && return node->getOp() == EOpIndexIndirect && !node->getLeft()->isArray() &&
......
...@@ -24,6 +24,7 @@ class TIntermUnary; ...@@ -24,6 +24,7 @@ class TIntermUnary;
class IntermNodePatternMatcher class IntermNodePatternMatcher
{ {
public: public:
static bool IsDynamicIndexingOfNonSSBOVectorOrMatrix(TIntermBinary *node);
static bool IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node); static bool IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node);
enum PatternType enum PatternType
......
...@@ -751,4 +751,28 @@ bool IsOutputVulkan(ShShaderOutput output) ...@@ -751,4 +751,28 @@ bool IsOutputVulkan(ShShaderOutput output)
return output == SH_GLSL_VULKAN_OUTPUT; return output == SH_GLSL_VULKAN_OUTPUT;
} }
bool IsInShaderStorageBlock(TIntermTyped *node)
{
TIntermBinary *binaryNode = nullptr;
TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
if (swizzleNode)
{
binaryNode = swizzleNode->getOperand()->getAsBinaryNode();
if (binaryNode)
{
return IsInShaderStorageBlock(binaryNode->getLeft());
}
}
binaryNode = node->getAsBinaryNode();
if (binaryNode)
{
return IsInShaderStorageBlock(binaryNode->getLeft());
}
const TType &type = node->getType();
return type.getQualifier() == EvqBuffer;
}
} // namespace sh } // namespace sh
...@@ -25,6 +25,7 @@ namespace sh ...@@ -25,6 +25,7 @@ namespace sh
{ {
class TIntermBlock; class TIntermBlock;
class TSymbolTable; class TSymbolTable;
class TIntermTyped;
float NumericLexFloat32OutOfRangeToInfinity(const std::string &str); float NumericLexFloat32OutOfRangeToInfinity(const std::string &str);
...@@ -62,6 +63,8 @@ bool IsOutputESSL(ShShaderOutput output); ...@@ -62,6 +63,8 @@ bool IsOutputESSL(ShShaderOutput output);
bool IsOutputGLSL(ShShaderOutput output); bool IsOutputGLSL(ShShaderOutput output);
bool IsOutputHLSL(ShShaderOutput output); bool IsOutputHLSL(ShShaderOutput output);
bool IsOutputVulkan(ShShaderOutput output); bool IsOutputVulkan(ShShaderOutput output);
bool IsInShaderStorageBlock(TIntermTyped *node);
} // namespace sh } // namespace sh
#endif // COMPILER_TRANSLATOR_UTIL_H_ #endif // COMPILER_TRANSLATOR_UTIL_H_
...@@ -58,6 +58,16 @@ ...@@ -58,6 +58,16 @@
1951 D3D11 : dEQP-GLES31.functional.ssbo.* = SKIP 1951 D3D11 : dEQP-GLES31.functional.ssbo.* = SKIP
1442 D3D11 : dEQP-GLES31.functional.layout_binding.image.* = SKIP 1442 D3D11 : dEQP-GLES31.functional.layout_binding.image.* = SKIP
1951 D3D11 : dEQP-GLES31.functional.shaders.linkage.es31.shader_storage_block.* = SKIP 1951 D3D11 : dEQP-GLES31.functional.shaders.linkage.es31.shader_storage_block.* = SKIP
// This case is skipped since it uses atomic counter builtin functions which haven't been implemented.
1729 D3D11 : dEQP-GLES31.functional.state_query.program.active_atomic_counter_buffers_get_programiv = SKIP
// Below cases are skipped since it uses variable * ssbo.matrix as the expression which haven't been implemented,
// that will result the code entering unreachable.
1951 D3D11 : dEQP-GLES31.functional.debug.negative_coverage.callbacks.ssbo_block.ssbo_block_interface_matching_tests = SKIP
1951 D3D11 : dEQP-GLES31.functional.debug.negative_coverage.callbacks.ssbo_block.ssbo_using_shared_qualifier_tests = SKIP
1951 D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.ssbo_block.ssbo_block_interface_matching_tests = SKIP
1951 D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.ssbo_block.ssbo_using_shared_qualifier_tests = SKIP
1951 D3D11 : dEQP-GLES31.functional.debug.negative_coverage.log.ssbo_block.ssbo_block_interface_matching_tests = SKIP
1951 D3D11 : dEQP-GLES31.functional.debug.negative_coverage.log.ssbo_block.ssbo_using_shared_qualifier_tests = SKIP
// D3D11 Failing Tests // D3D11 Failing Tests
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_compute_shared_memory_size_* = FAIL 1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_compute_shared_memory_size_* = FAIL
...@@ -80,7 +90,6 @@ ...@@ -80,7 +90,6 @@
1442 D3D11 : dEQP-GLES31.functional.debug.error_groups.case_3 = FAIL 1442 D3D11 : dEQP-GLES31.functional.debug.error_groups.case_3 = FAIL
1442 D3D11 : dEQP-GLES31.functional.debug.error_groups.case_9 = FAIL 1442 D3D11 : dEQP-GLES31.functional.debug.error_groups.case_9 = FAIL
1442 D3D11 : dEQP-GLES31.functional.debug.error_groups.case_10 = FAIL 1442 D3D11 : dEQP-GLES31.functional.debug.error_groups.case_10 = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.program.active_atomic_counter_buffers_get_programiv = FAIL
1442 D3D11 : dEQP-GLES31.functional.layout_binding.ubo.* = FAIL 1442 D3D11 : dEQP-GLES31.functional.layout_binding.ubo.* = FAIL
1663 D3D11 : dEQP-GLES31.functional.draw_indirect.compute_interop.* = FAIL 1663 D3D11 : dEQP-GLES31.functional.draw_indirect.compute_interop.* = FAIL
1442 D3D11 : dEQP-GLES31.functional.shaders.builtin_constants.core.max_vertex_attribs = FAIL 1442 D3D11 : dEQP-GLES31.functional.shaders.builtin_constants.core.max_vertex_attribs = FAIL
......
...@@ -1803,6 +1803,185 @@ TEST_P(ComputeShaderTest, LoadImageThenStore) ...@@ -1803,6 +1803,185 @@ TEST_P(ComputeShaderTest, LoadImageThenStore)
EXPECT_EQ(100u, outputValue); EXPECT_EQ(100u, outputValue);
} }
// Test that scalar buffer variables are supported.
TEST_P(ComputeShaderTest, ShaderStorageBlocksScalar)
{
const char kCSSource[] =
R"(#version 310 es
layout(local_size_x=1) in;
layout(std140, binding = 0) buffer blockA {
uvec3 uv;
float f;
} instanceA;
layout(std140, binding = 1) buffer blockB {
vec2 v;
uint u[3];
float f;
};
void main()
{
f = instanceA.f;
})";
ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
EXPECT_GL_NO_ERROR();
}
// Test that vector buffer variables are supported.
TEST_P(ComputeShaderTest, ShaderStorageBlocksVector)
{
const char kCSSource[] =
R"(#version 310 es
layout(local_size_x=1) in;
layout(std140, binding = 0) buffer blockA {
vec2 f;
} instanceA;
layout(std140, binding = 1) buffer blockB {
vec3 f;
};
void main()
{
f[1] = instanceA.f[0];
})";
ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
EXPECT_GL_NO_ERROR();
}
// Test that matrix buffer variables are supported.
TEST_P(ComputeShaderTest, ShaderStorageBlocksMatrix)
{
const char kCSSource[] =
R"(#version 310 es
layout(local_size_x=1) in;
layout(std140, binding = 0) buffer blockA {
mat3x4 m;
} instanceA;
layout(std140, binding = 1) buffer blockB {
mat3x4 m;
};
void main()
{
m[0][1] = instanceA.m[0][1];
})";
ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
EXPECT_GL_NO_ERROR();
}
// Test that scalar array buffer variables are supported.
TEST_P(ComputeShaderTest, ShaderStorageBlocksScalarArray)
{
const char kCSSource[] =
R"(#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()
{
f[gl_LocalInvocationIndex] = instanceA.f[gl_LocalInvocationIndex];
})";
ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
EXPECT_GL_NO_ERROR();
}
// Test that vector array buffer variables are supported.
TEST_P(ComputeShaderTest, ShaderStorageBlocksVectorArray)
{
const char kCSSource[] =
R"(#version 310 es
layout(local_size_x=4) in;
layout(std140, binding = 0) buffer blockA {
vec2 v[4];
} instanceA;
layout(std140, binding = 1) buffer blockB {
vec4 v[4];
};
void main()
{
v[0][gl_LocalInvocationIndex] = instanceA.v[gl_LocalInvocationIndex][1];
})";
ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
EXPECT_GL_NO_ERROR();
}
// Test that matrix array buffer variables are supported.
TEST_P(ComputeShaderTest, ShaderStorageBlocksMatrixArray)
{
const char kCSSource[] =
R"(#version 310 es
layout(local_size_x=8) in;
layout(std140, binding = 0) buffer blockA {
float v1[5];
mat4 m[8];
} instanceA;
layout(std140, binding = 1) buffer blockB {
vec2 v1[3];
mat4 m[8];
};
void main()
{
float data = instanceA.m[gl_LocalInvocationIndex][0][0];
m[gl_LocalInvocationIndex][gl_LocalInvocationIndex][gl_LocalInvocationIndex] = data;
})";
ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
EXPECT_GL_NO_ERROR();
}
// Test that shader storage blocks only in assignment right is supported.
TEST_P(ComputeShaderTest, ShaderStorageBlocksInAssignmentRight)
{
const char kCSSource[] =
R"(#version 310 es
layout(local_size_x=8) in;
layout(std140, binding = 0) buffer blockA {
float data[8];
} instanceA;
layout(r32f, binding = 0) writeonly uniform highp image2D imageOut;
void main()
{
float data = 1.0;
data = instanceA.data[gl_LocalInvocationIndex];
imageStore(imageOut, ivec2(gl_LocalInvocationID.xy), vec4(data));
}
)";
ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
EXPECT_GL_NO_ERROR();
}
// Test that shader storage blocks with unsized array are supported.
TEST_P(ComputeShaderTest, ShaderStorageBlocksWithUnsizedArray)
{
const char kCSSource[] =
R"(#version 310 es
layout(local_size_x=8) in;
layout(std140, binding = 0) buffer blockA {
float v[];
} instanceA;
layout(std140, binding = 0) buffer blockB {
float v[];
} instanceB[1];
void main()
{
float data = instanceA.v[gl_LocalInvocationIndex];
instanceB[0].v[gl_LocalInvocationIndex * 2u + 1u] = data;
}
)";
ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
EXPECT_GL_NO_ERROR();
}
// Check that it is not possible to create a compute shader when the context does not support ES // Check that it is not possible to create a compute shader when the context does not support ES
// 3.10 // 3.10
TEST_P(ComputeShaderTestES3, NotSupported) TEST_P(ComputeShaderTestES3, NotSupported)
......
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