summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp')
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp989
1 files changed, 989 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp
new file mode 100644
index 0000000000..e43bd44d4a
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp
@@ -0,0 +1,989 @@
+//
+// Copyright 2014 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.
+//
+// ResourcesHLSL.cpp:
+// Methods for GLSL to HLSL translation for uniforms and interface blocks.
+//
+
+#include "compiler/translator/ResourcesHLSL.h"
+
+#include "common/utilities.h"
+#include "compiler/translator/AtomicCounterFunctionHLSL.h"
+#include "compiler/translator/ImmutableStringBuilder.h"
+#include "compiler/translator/StructureHLSL.h"
+#include "compiler/translator/UtilsHLSL.h"
+#include "compiler/translator/blocklayoutHLSL.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kAngleDecorString("angle_");
+
+static const char *UniformRegisterPrefix(const TType &type)
+{
+ if (IsSampler(type.getBasicType()))
+ {
+ return "s";
+ }
+ else
+ {
+ return "c";
+ }
+}
+
+static TString InterfaceBlockFieldTypeString(const TField &field,
+ TLayoutBlockStorage blockStorage,
+ bool usedStructuredbuffer)
+{
+ const TType &fieldType = *field.type();
+ const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking;
+ ASSERT(matrixPacking != EmpUnspecified);
+ const TStructure *structure = fieldType.getStruct();
+
+ if (fieldType.isMatrix())
+ {
+ // Use HLSL row-major packing for GLSL column-major matrices
+ const TString &matrixPackString =
+ (matrixPacking == EmpRowMajor ? "column_major" : "row_major");
+ return matrixPackString + " " + TypeString(fieldType);
+ }
+ else if (structure)
+ {
+ // If uniform block's layout is std140 and translating it to StructuredBuffer,
+ // should pack structure in the end, in order to fit API buffer.
+ bool forcePackingEnd = usedStructuredbuffer && (blockStorage == EbsStd140);
+ // Use HLSL row-major packing for GLSL column-major matrices
+ return QualifiedStructNameString(*structure, matrixPacking == EmpColumnMajor,
+ blockStorage == EbsStd140, forcePackingEnd);
+ }
+ else
+ {
+ return TypeString(fieldType);
+ }
+}
+
+static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock)
+{
+ return DecoratePrivate(interfaceBlock.name()) + "_type";
+}
+
+void OutputUniformIndexArrayInitializer(TInfoSinkBase &out,
+ const TType &type,
+ unsigned int startIndex)
+{
+ out << "{";
+ TType elementType(type);
+ elementType.toArrayElementType();
+ for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
+ {
+ if (i > 0u)
+ {
+ out << ", ";
+ }
+ if (elementType.isArray())
+ {
+ OutputUniformIndexArrayInitializer(out, elementType,
+ startIndex + i * elementType.getArraySizeProduct());
+ }
+ else
+ {
+ out << (startIndex + i);
+ }
+ }
+ out << "}";
+}
+
+static TString InterfaceBlockScalarVectorFieldPaddingString(const TType &type)
+{
+ switch (type.getBasicType())
+ {
+ case EbtFloat:
+ switch (type.getNominalSize())
+ {
+ case 1:
+ return "float3 padding;";
+ case 2:
+ return "float2 padding;";
+ case 3:
+ return "float padding;";
+ default:
+ break;
+ }
+ break;
+ case EbtInt:
+ switch (type.getNominalSize())
+ {
+ case 1:
+ return "int3 padding;";
+ case 2:
+ return "int2 padding;";
+ case 3:
+ return "int padding";
+ default:
+ break;
+ }
+ break;
+ case EbtUInt:
+ switch (type.getNominalSize())
+ {
+ case 1:
+ return "uint3 padding;";
+ case 2:
+ return "uint2 padding;";
+ case 3:
+ return "uint padding;";
+ default:
+ break;
+ }
+ break;
+ case EbtBool:
+ switch (type.getNominalSize())
+ {
+ case 1:
+ return "bool3 padding;";
+ case 2:
+ return "bool2 padding;";
+ case 3:
+ return "bool padding;";
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return "";
+}
+
+static bool IsAnyRasterOrdered(const TVector<const TVariable *> &imageVars)
+{
+ for (const TVariable *imageVar : imageVars)
+ {
+ if (imageVar->getType().getLayoutQualifier().rasterOrdered)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // anonymous namespace
+
+ResourcesHLSL::ResourcesHLSL(StructureHLSL *structureHLSL,
+ ShShaderOutput outputType,
+ const std::vector<ShaderVariable> &uniforms,
+ unsigned int firstUniformRegister)
+ : mUniformRegister(firstUniformRegister),
+ mUniformBlockRegister(0),
+ mSRVRegister(0),
+ mUAVRegister(0),
+ mSamplerCount(0),
+ mStructureHLSL(structureHLSL),
+ mOutputType(outputType),
+ mUniforms(uniforms)
+{}
+
+void ResourcesHLSL::reserveUniformRegisters(unsigned int registerCount)
+{
+ mUniformRegister = registerCount;
+}
+
+void ResourcesHLSL::reserveUniformBlockRegisters(unsigned int registerCount)
+{
+ mUniformBlockRegister = registerCount;
+}
+
+const ShaderVariable *ResourcesHLSL::findUniformByName(const ImmutableString &name) const
+{
+ for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
+ {
+ if (name == mUniforms[uniformIndex].name)
+ {
+ return &mUniforms[uniformIndex];
+ }
+ }
+
+ return nullptr;
+}
+
+unsigned int ResourcesHLSL::assignUniformRegister(const TType &type,
+ const ImmutableString &name,
+ unsigned int *outRegisterCount)
+{
+ unsigned int registerIndex;
+ const ShaderVariable *uniform = findUniformByName(name);
+ ASSERT(uniform);
+
+ if (IsSampler(type.getBasicType()) ||
+ (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly))
+ {
+ registerIndex = mSRVRegister;
+ }
+ else if (IsImage(type.getBasicType()))
+ {
+ registerIndex = mUAVRegister;
+ }
+ else
+ {
+ registerIndex = mUniformRegister;
+ }
+
+ if (uniform->name == "angle_DrawID" && uniform->mappedName == "angle_DrawID")
+ {
+ mUniformRegisterMap["gl_DrawID"] = registerIndex;
+ }
+ else
+ {
+ mUniformRegisterMap[uniform->name] = registerIndex;
+ }
+
+ if (uniform->name == "angle_BaseVertex" && uniform->mappedName == "angle_BaseVertex")
+ {
+ mUniformRegisterMap["gl_BaseVertex"] = registerIndex;
+ }
+ else
+ {
+ mUniformRegisterMap[uniform->name] = registerIndex;
+ }
+
+ if (uniform->name == "angle_BaseInstance" && uniform->mappedName == "angle_BaseInstance")
+ {
+ mUniformRegisterMap["gl_BaseInstance"] = registerIndex;
+ }
+ else
+ {
+ mUniformRegisterMap[uniform->name] = registerIndex;
+ }
+
+ unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType);
+
+ if (IsSampler(type.getBasicType()) ||
+ (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly))
+ {
+ mSRVRegister += registerCount;
+ }
+ else if (IsImage(type.getBasicType()))
+ {
+ mUAVRegister += registerCount;
+ }
+ else
+ {
+ mUniformRegister += registerCount;
+ }
+ if (outRegisterCount)
+ {
+ *outRegisterCount = registerCount;
+ }
+ return registerIndex;
+}
+
+unsigned int ResourcesHLSL::assignSamplerInStructUniformRegister(const TType &type,
+ const TString &name,
+ unsigned int *outRegisterCount)
+{
+ // Sampler that is a field of a uniform structure.
+ ASSERT(IsSampler(type.getBasicType()));
+ unsigned int registerIndex = mSRVRegister;
+ mUniformRegisterMap[std::string(name.c_str())] = registerIndex;
+ unsigned int registerCount = type.isArray() ? type.getArraySizeProduct() : 1u;
+ mSRVRegister += registerCount;
+ if (outRegisterCount)
+ {
+ *outRegisterCount = registerCount;
+ }
+ return registerIndex;
+}
+
+void ResourcesHLSL::outputHLSLSamplerUniformGroup(
+ TInfoSinkBase &out,
+ const HLSLTextureGroup textureGroup,
+ const TVector<const TVariable *> &group,
+ const TMap<const TVariable *, TString> &samplerInStructSymbolsToAPINames,
+ unsigned int *groupTextureRegisterIndex)
+{
+ if (group.empty())
+ {
+ return;
+ }
+ unsigned int groupRegisterCount = 0;
+ for (const TVariable *uniform : group)
+ {
+ const TType &type = uniform->getType();
+ const ImmutableString &name = uniform->name();
+ unsigned int registerCount;
+
+ // The uniform might be just a regular sampler or one extracted from a struct.
+ unsigned int samplerArrayIndex = 0u;
+ const ShaderVariable *uniformByName = findUniformByName(name);
+ if (uniformByName)
+ {
+ samplerArrayIndex = assignUniformRegister(type, name, &registerCount);
+ }
+ else
+ {
+ ASSERT(samplerInStructSymbolsToAPINames.find(uniform) !=
+ samplerInStructSymbolsToAPINames.end());
+ samplerArrayIndex = assignSamplerInStructUniformRegister(
+ type, samplerInStructSymbolsToAPINames.at(uniform), &registerCount);
+ }
+ groupRegisterCount += registerCount;
+
+ if (type.isArray())
+ {
+ out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type)
+ << " = ";
+ OutputUniformIndexArrayInitializer(out, type, samplerArrayIndex);
+ out << ";\n";
+ }
+ else
+ {
+ out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = "
+ << samplerArrayIndex << ";\n";
+ }
+ }
+ TString suffix = TextureGroupSuffix(textureGroup);
+ // Since HLSL_TEXTURE_2D is the first group, it has a fixed offset of zero.
+ if (textureGroup != HLSL_TEXTURE_2D)
+ {
+ out << "static const uint textureIndexOffset" << suffix << " = "
+ << (*groupTextureRegisterIndex) << ";\n";
+ out << "static const uint samplerIndexOffset" << suffix << " = "
+ << (*groupTextureRegisterIndex) << ";\n";
+ }
+ out << "uniform " << TextureString(textureGroup) << " textures" << suffix << "["
+ << groupRegisterCount << "]"
+ << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
+ out << "uniform " << SamplerString(textureGroup) << " samplers" << suffix << "["
+ << groupRegisterCount << "]"
+ << " : register(s" << (*groupTextureRegisterIndex) << ");\n";
+ *groupTextureRegisterIndex += groupRegisterCount;
+}
+
+void ResourcesHLSL::outputHLSLImageUniformIndices(TInfoSinkBase &out,
+ const TVector<const TVariable *> &group,
+ unsigned int imageArrayIndex,
+ unsigned int *groupRegisterCount)
+{
+ for (const TVariable *uniform : group)
+ {
+ const TType &type = uniform->getType();
+ const ImmutableString &name = uniform->name();
+ unsigned int registerCount = 0;
+
+ assignUniformRegister(type, name, &registerCount);
+ *groupRegisterCount += registerCount;
+
+ if (type.isArray())
+ {
+ out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type)
+ << " = ";
+ OutputUniformIndexArrayInitializer(out, type, imageArrayIndex);
+ out << ";\n";
+ }
+ else
+ {
+ out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = "
+ << imageArrayIndex << ";\n";
+ }
+
+ imageArrayIndex += registerCount;
+ }
+}
+
+void ResourcesHLSL::outputHLSLReadonlyImageUniformGroup(TInfoSinkBase &out,
+ const HLSLTextureGroup textureGroup,
+ const TVector<const TVariable *> &group,
+ unsigned int *groupTextureRegisterIndex)
+{
+ if (group.empty())
+ {
+ return;
+ }
+
+ unsigned int groupRegisterCount = 0;
+ outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount);
+
+ TString suffix = TextureGroupSuffix(textureGroup);
+ out << "static const uint readonlyImageIndexOffset" << suffix << " = "
+ << (*groupTextureRegisterIndex) << ";\n";
+ out << "uniform " << TextureString(textureGroup) << " readonlyImages" << suffix << "["
+ << groupRegisterCount << "]"
+ << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
+ *groupTextureRegisterIndex += groupRegisterCount;
+}
+
+void ResourcesHLSL::outputHLSLImageUniformGroup(TInfoSinkBase &out,
+ const HLSLRWTextureGroup textureGroup,
+ const TVector<const TVariable *> &group,
+ unsigned int *groupTextureRegisterIndex)
+{
+ if (group.empty())
+ {
+ return;
+ }
+
+ // ROVs should all be written out in DynamicImage2DHLSL.cpp.
+ ASSERT(!IsAnyRasterOrdered(group));
+
+ unsigned int groupRegisterCount = 0;
+ outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount);
+
+ TString suffix = RWTextureGroupSuffix(textureGroup);
+ out << "static const uint imageIndexOffset" << suffix << " = " << (*groupTextureRegisterIndex)
+ << ";\n";
+ out << "uniform " << RWTextureString(textureGroup) << " images" << suffix << "["
+ << groupRegisterCount << "]"
+ << " : register(u" << (*groupTextureRegisterIndex) << ");\n";
+ *groupTextureRegisterIndex += groupRegisterCount;
+}
+
+void ResourcesHLSL::outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out,
+ const TType &type,
+ const TVariable &variable,
+ const unsigned int registerIndex)
+{
+ out << "uniform " << SamplerString(type.getBasicType()) << " sampler_"
+ << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(s"
+ << str(registerIndex) << ");\n";
+ out << "uniform " << TextureString(type.getBasicType()) << " texture_"
+ << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(t"
+ << str(registerIndex) << ");\n";
+}
+
+void ResourcesHLSL::outputUniform(TInfoSinkBase &out,
+ const TType &type,
+ const TVariable &variable,
+ const unsigned int registerIndex)
+{
+ const TStructure *structure = type.getStruct();
+ // If this is a nameless struct, we need to use its full definition, rather than its (empty)
+ // name.
+ // TypeString() will invoke defineNameless in this case; qualifier prefixes are unnecessary for
+ // nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers
+ // are permitted.
+ const TString &typeName = ((structure && structure->symbolType() != SymbolType::Empty)
+ ? QualifiedStructNameString(*structure, false, false, false)
+ : TypeString(type));
+
+ const TString &registerString =
+ TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")";
+
+ out << "uniform " << typeName << " ";
+
+ out << DecorateVariableIfNeeded(variable);
+
+ out << ArrayString(type) << " : " << registerString << ";\n";
+}
+
+void ResourcesHLSL::outputAtomicCounterBuffer(TInfoSinkBase &out,
+ const int binding,
+ const unsigned int registerIndex)
+{
+ // Atomic counter memory access is not incoherent
+ out << "uniform globallycoherent RWByteAddressBuffer "
+ << getAtomicCounterNameForBinding(binding) << " : register(u" << registerIndex << ");\n";
+}
+
+void ResourcesHLSL::uniformsHeader(TInfoSinkBase &out,
+ ShShaderOutput outputType,
+ const ReferencedVariables &referencedUniforms,
+ TSymbolTable *symbolTable)
+{
+ if (!referencedUniforms.empty())
+ {
+ out << "// Uniforms\n\n";
+ }
+ // In the case of HLSL 4, sampler uniforms need to be grouped by type before the code is
+ // written. They are grouped based on the combination of the HLSL texture type and
+ // HLSL sampler type, enumerated in HLSLTextureSamplerGroup.
+ TVector<TVector<const TVariable *>> groupedSamplerUniforms(HLSL_TEXTURE_MAX + 1);
+ TMap<const TVariable *, TString> samplerInStructSymbolsToAPINames;
+ TVector<TVector<const TVariable *>> groupedReadonlyImageUniforms(HLSL_TEXTURE_MAX + 1);
+ TVector<TVector<const TVariable *>> groupedImageUniforms(HLSL_RWTEXTURE_MAX + 1);
+
+ TUnorderedMap<int, unsigned int> assignedAtomicCounterBindings;
+ unsigned int reservedReadonlyImageRegisterCount = 0, reservedImageRegisterCount = 0;
+ for (auto &uniformIt : referencedUniforms)
+ {
+ // Output regular uniforms. Group sampler uniforms by type.
+ const TVariable &variable = *uniformIt.second;
+ const TType &type = variable.getType();
+
+ if (outputType == SH_HLSL_4_1_OUTPUT && IsSampler(type.getBasicType()))
+ {
+ HLSLTextureGroup group = TextureGroup(type.getBasicType());
+ groupedSamplerUniforms[group].push_back(&variable);
+ }
+ else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(type.getBasicType()))
+ {
+ unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr);
+ outputHLSL4_0_FL9_3Sampler(out, type, variable, registerIndex);
+ }
+ else if (outputType == SH_HLSL_4_1_OUTPUT && IsImage(type.getBasicType()))
+ {
+ if (IsImage2D(type.getBasicType()))
+ {
+ const ShaderVariable *uniform = findUniformByName(variable.name());
+ if (type.getMemoryQualifier().readonly)
+ {
+ reservedReadonlyImageRegisterCount +=
+ HLSLVariableRegisterCount(*uniform, mOutputType);
+ }
+ else
+ {
+ reservedImageRegisterCount += HLSLVariableRegisterCount(*uniform, mOutputType);
+ }
+ continue;
+ }
+ if (type.getMemoryQualifier().readonly)
+ {
+ HLSLTextureGroup group = TextureGroup(
+ type.getBasicType(), type.getLayoutQualifier().imageInternalFormat);
+ groupedReadonlyImageUniforms[group].push_back(&variable);
+ }
+ else
+ {
+ HLSLRWTextureGroup group = RWTextureGroup(
+ type.getBasicType(), type.getLayoutQualifier().imageInternalFormat);
+ groupedImageUniforms[group].push_back(&variable);
+ }
+ }
+ else if (outputType == SH_HLSL_4_1_OUTPUT && IsAtomicCounter(type.getBasicType()))
+ {
+ TLayoutQualifier layout = type.getLayoutQualifier();
+ int binding = layout.binding;
+ unsigned int registerIndex;
+ if (assignedAtomicCounterBindings.find(binding) == assignedAtomicCounterBindings.end())
+ {
+ registerIndex = mUAVRegister++;
+ assignedAtomicCounterBindings[binding] = registerIndex;
+ outputAtomicCounterBuffer(out, binding, registerIndex);
+ }
+ else
+ {
+ registerIndex = assignedAtomicCounterBindings[binding];
+ }
+ const ShaderVariable *uniform = findUniformByName(variable.name());
+ mUniformRegisterMap[uniform->name] = registerIndex;
+ }
+ else
+ {
+ if (type.isStructureContainingSamplers())
+ {
+ TVector<const TVariable *> samplerSymbols;
+ TMap<const TVariable *, TString> symbolsToAPINames;
+ ImmutableStringBuilder namePrefix(kAngleDecorString.length() +
+ variable.name().length());
+ namePrefix << kAngleDecorString;
+ namePrefix << variable.name();
+ type.createSamplerSymbols(namePrefix, TString(variable.name().data()),
+ &samplerSymbols, &symbolsToAPINames, symbolTable);
+ for (const TVariable *sampler : samplerSymbols)
+ {
+ const TType &samplerType = sampler->getType();
+
+ if (outputType == SH_HLSL_4_1_OUTPUT)
+ {
+ HLSLTextureGroup group = TextureGroup(samplerType.getBasicType());
+ groupedSamplerUniforms[group].push_back(sampler);
+ samplerInStructSymbolsToAPINames[sampler] = symbolsToAPINames[sampler];
+ }
+ else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
+ {
+ unsigned int registerIndex = assignSamplerInStructUniformRegister(
+ samplerType, symbolsToAPINames[sampler], nullptr);
+ outputHLSL4_0_FL9_3Sampler(out, samplerType, *sampler, registerIndex);
+ }
+ else
+ {
+ ASSERT(outputType == SH_HLSL_3_0_OUTPUT);
+ unsigned int registerIndex = assignSamplerInStructUniformRegister(
+ samplerType, symbolsToAPINames[sampler], nullptr);
+ outputUniform(out, samplerType, *sampler, registerIndex);
+ }
+ }
+ }
+ unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr);
+ outputUniform(out, type, variable, registerIndex);
+ }
+ }
+
+ if (outputType == SH_HLSL_4_1_OUTPUT)
+ {
+ unsigned int groupTextureRegisterIndex = 0;
+ // Atomic counters and RW texture share the same resources. Therefore, RW texture need to
+ // start counting after the last atomic counter.
+ unsigned int groupRWTextureRegisterIndex = mUAVRegister;
+ // TEXTURE_2D is special, index offset is assumed to be 0 and omitted in that case.
+ ASSERT(HLSL_TEXTURE_MIN == HLSL_TEXTURE_2D);
+ for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
+ {
+ outputHLSLSamplerUniformGroup(
+ out, HLSLTextureGroup(groupId), groupedSamplerUniforms[groupId],
+ samplerInStructSymbolsToAPINames, &groupTextureRegisterIndex);
+ }
+ mSamplerCount = groupTextureRegisterIndex;
+
+ // Reserve t type register for readonly image2D variables.
+ mReadonlyImage2DRegisterIndex = mSRVRegister;
+ groupTextureRegisterIndex += reservedReadonlyImageRegisterCount;
+ mSRVRegister += reservedReadonlyImageRegisterCount;
+
+ for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
+ {
+ outputHLSLReadonlyImageUniformGroup(out, HLSLTextureGroup(groupId),
+ groupedReadonlyImageUniforms[groupId],
+ &groupTextureRegisterIndex);
+ }
+ mReadonlyImageCount = groupTextureRegisterIndex - mReadonlyImage2DRegisterIndex;
+ if (mReadonlyImageCount)
+ {
+ out << "static const uint readonlyImageIndexStart = " << mReadonlyImage2DRegisterIndex
+ << ";\n";
+ }
+
+ // Reserve u type register for writable image2D variables.
+ mImage2DRegisterIndex = mUAVRegister;
+ groupRWTextureRegisterIndex += reservedImageRegisterCount;
+ mUAVRegister += reservedImageRegisterCount;
+
+ for (int groupId = HLSL_RWTEXTURE_MIN; groupId < HLSL_RWTEXTURE_MAX; ++groupId)
+ {
+ outputHLSLImageUniformGroup(out, HLSLRWTextureGroup(groupId),
+ groupedImageUniforms[groupId],
+ &groupRWTextureRegisterIndex);
+ }
+ mImageCount = groupRWTextureRegisterIndex - mImage2DRegisterIndex;
+ if (mImageCount)
+ {
+ out << "static const uint imageIndexStart = " << mImage2DRegisterIndex << ";\n";
+ }
+ }
+}
+
+void ResourcesHLSL::samplerMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex)
+{
+ // If mSamplerCount is 0 the shader doesn't use any textures for samplers.
+ if (mSamplerCount > 0)
+ {
+ out << " struct SamplerMetadata\n"
+ " {\n"
+ " int baseLevel;\n"
+ " int internalFormatBits;\n"
+ " int wrapModes;\n"
+ " int padding;\n"
+ " int4 intBorderColor;\n"
+ " };\n"
+ " SamplerMetadata samplerMetadata["
+ << mSamplerCount << "] : packoffset(c" << regIndex << ");\n";
+ }
+}
+
+void ResourcesHLSL::imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex)
+{
+ if (mReadonlyImageCount > 0 || mImageCount > 0)
+ {
+ out << " struct ImageMetadata\n"
+ " {\n"
+ " int layer;\n"
+ " uint level;\n"
+ " int2 padding;\n"
+ " };\n";
+
+ if (mReadonlyImageCount > 0)
+ {
+ out << " ImageMetadata readonlyImageMetadata[" << mReadonlyImageCount
+ << "] : packoffset(c" << regIndex << ");\n";
+ }
+
+ if (mImageCount > 0)
+ {
+ out << " ImageMetadata imageMetadata[" << mImageCount << "] : packoffset(c"
+ << regIndex + mReadonlyImageCount << ");\n";
+ }
+ }
+}
+
+TString ResourcesHLSL::uniformBlocksHeader(
+ const ReferencedInterfaceBlocks &referencedInterfaceBlocks,
+ const std::map<int, const TInterfaceBlock *> &uniformBlockOptimizedMap)
+{
+ TString interfaceBlocks;
+
+ for (const auto &blockReference : referencedInterfaceBlocks)
+ {
+ const TInterfaceBlock &interfaceBlock = *blockReference.second->block;
+ const TVariable *instanceVariable = blockReference.second->instanceVariable;
+ if (instanceVariable != nullptr)
+ {
+ interfaceBlocks += uniformBlockStructString(interfaceBlock);
+ }
+
+ // In order to avoid compile performance issue, translate uniform block to structured
+ // buffer. anglebug.com/3682.
+ if (uniformBlockOptimizedMap.count(interfaceBlock.uniqueId().get()) != 0)
+ {
+ unsigned int structuredBufferRegister = mSRVRegister;
+ if (instanceVariable != nullptr && instanceVariable->getType().isArray())
+ {
+ unsigned int instanceArraySize =
+ instanceVariable->getType().getOutermostArraySize();
+ for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
+ {
+ interfaceBlocks += uniformBlockWithOneLargeArrayMemberString(
+ interfaceBlock, instanceVariable, structuredBufferRegister + arrayIndex,
+ arrayIndex);
+ }
+ mSRVRegister += instanceArraySize;
+ }
+ else
+ {
+ interfaceBlocks += uniformBlockWithOneLargeArrayMemberString(
+ interfaceBlock, instanceVariable, structuredBufferRegister, GL_INVALID_INDEX);
+ mSRVRegister += 1u;
+ }
+ mUniformBlockRegisterMap[interfaceBlock.name().data()] = structuredBufferRegister;
+ mUniformBlockUseStructuredBufferMap[interfaceBlock.name().data()] = true;
+ continue;
+ }
+
+ unsigned int activeRegister = mUniformBlockRegister;
+ mUniformBlockRegisterMap[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 += uniformBlockString(interfaceBlock, instanceVariable,
+ activeRegister + arrayIndex, arrayIndex);
+ }
+ mUniformBlockRegister += instanceArraySize;
+ }
+ else
+ {
+ interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable, activeRegister,
+ GL_INVALID_INDEX);
+ mUniformBlockRegister += 1u;
+ }
+ }
+
+ return (interfaceBlocks.empty() ? "" : ("// Uniform Blocks\n\n" + interfaceBlocks));
+}
+
+void ResourcesHLSL::allocateShaderStorageBlockRegisters(
+ const ReferencedInterfaceBlocks &referencedInterfaceBlocks)
+{
+ for (const auto &interfaceBlockReference : referencedInterfaceBlocks)
+ {
+ const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block;
+ const TVariable *instanceVariable = interfaceBlockReference.second->instanceVariable;
+
+ mShaderStorageBlockRegisterMap[interfaceBlock.name().data()] = mUAVRegister;
+
+ if (instanceVariable != nullptr && instanceVariable->getType().isArray())
+ {
+ mUAVRegister += instanceVariable->getType().getOutermostArraySize();
+ }
+ else
+ {
+ mUAVRegister += 1u;
+ }
+ }
+}
+
+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 = mShaderStorageBlockRegisterMap[interfaceBlock.name().data()];
+
+ 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);
+ }
+ }
+ else
+ {
+ interfaceBlocks += shaderStorageBlockString(interfaceBlock, instanceVariable,
+ activeRegister, GL_INVALID_INDEX);
+ }
+ }
+
+ return interfaceBlocks;
+}
+
+TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock,
+ const TVariable *instanceVariable,
+ unsigned int registerIndex,
+ unsigned int arrayIndex)
+{
+ const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? str(arrayIndex) : "");
+ const TString &blockName = TString(interfaceBlock.name().data()) + arrayIndexString;
+ TString hlsl;
+
+ hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) +
+ ")\n"
+ "{\n";
+
+ if (instanceVariable != nullptr)
+ {
+ hlsl += " " + InterfaceBlockStructName(interfaceBlock) + " " +
+ InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + ";\n";
+ }
+ else
+ {
+ const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
+ hlsl += uniformBlockMembersString(interfaceBlock, blockStorage);
+ }
+
+ hlsl += "};\n\n";
+
+ return hlsl;
+}
+
+TString ResourcesHLSL::uniformBlockWithOneLargeArrayMemberString(
+ const TInterfaceBlock &interfaceBlock,
+ const TVariable *instanceVariable,
+ unsigned int registerIndex,
+ unsigned int arrayIndex)
+{
+ TString hlsl, typeString;
+
+ const TField &field = *interfaceBlock.fields()[0];
+ const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
+ typeString = InterfaceBlockFieldTypeString(field, blockStorage, true);
+ const TType &fieldType = *field.type();
+ if (fieldType.isMatrix())
+ {
+ if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0)
+ {
+ hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " +
+ Decorate(field.name()) + "; };\n";
+ }
+ typeString = "pack" + Decorate(interfaceBlock.name());
+ }
+ else if (fieldType.isVectorArray() || fieldType.isScalarArray())
+ {
+ // If the member is an array of scalars or vectors, std140 rules require the base array
+ // stride are rounded up to the base alignment of a vec4.
+ if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0)
+ {
+ hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " +
+ Decorate(field.name()) + ";\n";
+ hlsl += InterfaceBlockScalarVectorFieldPaddingString(fieldType) + " };\n";
+ }
+ typeString = "pack" + Decorate(interfaceBlock.name());
+ }
+
+ if (instanceVariable != nullptr)
+ {
+
+ hlsl += "StructuredBuffer <" + typeString + "> " +
+ InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + "_" +
+ Decorate(field.name()) + +" : register(t" + str(registerIndex) + ");\n";
+ }
+ else
+ {
+ hlsl += "StructuredBuffer <" + typeString + "> " + Decorate(field.name()) +
+ " : register(t" + str(registerIndex) + ");\n";
+ }
+
+ return hlsl;
+}
+
+TString ResourcesHLSL::shaderStorageBlockString(const TInterfaceBlock &interfaceBlock,
+ 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)
+ {
+ return DecoratePrivate(instanceName) + "_" + str(arrayIndex);
+ }
+ else
+ {
+ return Decorate(instanceName);
+ }
+}
+
+TString ResourcesHLSL::uniformBlockMembersString(const TInterfaceBlock &interfaceBlock,
+ TLayoutBlockStorage blockStorage)
+{
+ TString hlsl;
+
+ Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper();
+
+ const unsigned int fieldCount = static_cast<unsigned int>(interfaceBlock.fields().size());
+ for (unsigned int typeIndex = 0; typeIndex < fieldCount; typeIndex++)
+ {
+ const TField &field = *interfaceBlock.fields()[typeIndex];
+ const TType &fieldType = *field.type();
+
+ if (blockStorage == EbsStd140)
+ {
+ // 2 and 3 component vector types in some cases need pre-padding
+ hlsl += padHelper.prePaddingString(fieldType, false);
+ }
+
+ hlsl += " " + InterfaceBlockFieldTypeString(field, blockStorage, false) + " " +
+ Decorate(field.name()) + ArrayString(fieldType).data() + ";\n";
+
+ // must pad out after matrices and arrays, where HLSL usually allows itself room to pack
+ // stuff
+ if (blockStorage == EbsStd140)
+ {
+ const bool useHLSLRowMajorPacking =
+ (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
+ hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking,
+ typeIndex == fieldCount - 1, false);
+ }
+ }
+
+ return hlsl;
+}
+
+TString ResourcesHLSL::uniformBlockStructString(const TInterfaceBlock &interfaceBlock)
+{
+ const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
+
+ return "struct " + InterfaceBlockStructName(interfaceBlock) +
+ "\n"
+ "{\n" +
+ uniformBlockMembersString(interfaceBlock, blockStorage) + "};\n\n";
+}
+} // namespace sh