diff options
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp')
-rw-r--r-- | gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp | 956 |
1 files changed, 956 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..a6bebfee67 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp @@ -0,0 +1,956 @@ +// +// 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 ""; +} + +} // 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, ®isterCount); + } + else + { + ASSERT(samplerInStructSymbolsToAPINames.find(uniform) != + samplerInStructSymbolsToAPINames.end()); + samplerArrayIndex = assignSamplerInStructUniformRegister( + type, samplerInStructSymbolsToAPINames.at(uniform), ®isterCount); + } + 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, ®isterCount); + *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; + } + + 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 ®isterString = + 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)); +} + +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, + 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 |