| // |
| // Copyright (c) 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. |
| // |
| // UniformHLSL.cpp: |
| // Methods for GLSL to HLSL translation for uniforms and interface blocks. |
| // |
| |
| #include "OutputHLSL.h" |
| #include "common/blocklayout.h" |
| #include "common/utilities.h" |
| #include "compiler/translator/UniformHLSL.h" |
| #include "compiler/translator/StructureHLSL.h" |
| #include "compiler/translator/util.h" |
| #include "compiler/translator/UtilsHLSL.h" |
| #include "compiler/translator/TranslatorHLSL.h" |
| |
| namespace sh |
| { |
| |
| static const char *UniformRegisterPrefix(const TType &type) |
| { |
| if (IsSampler(type.getBasicType())) |
| { |
| return "s"; |
| } |
| else |
| { |
| return "c"; |
| } |
| } |
| |
| static TString InterfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage) |
| { |
| const TType &fieldType = *field.type(); |
| const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking; |
| ASSERT(matrixPacking != EmpUnspecified); |
| 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) |
| { |
| // Use HLSL row-major packing for GLSL column-major matrices |
| return QualifiedStructNameString(*structure, matrixPacking == EmpColumnMajor, |
| blockStorage == EbsStd140); |
| } |
| else |
| { |
| return TypeString(fieldType); |
| } |
| } |
| |
| static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock) |
| { |
| return DecoratePrivate(interfaceBlock.name()) + "_type"; |
| } |
| |
| UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, TranslatorHLSL *translator) |
| : mUniformRegister(0), |
| mInterfaceBlockRegister(0), |
| mSamplerRegister(0), |
| mStructureHLSL(structureHLSL), |
| mOutputType(translator->getOutputType()), |
| mUniforms(translator->getUniforms()) |
| {} |
| |
| void UniformHLSL::reserveUniformRegisters(unsigned int registerCount) |
| { |
| mUniformRegister = registerCount; |
| } |
| |
| void UniformHLSL::reserveInterfaceBlockRegisters(unsigned int registerCount) |
| { |
| mInterfaceBlockRegister = registerCount; |
| } |
| |
| const Uniform *UniformHLSL::findUniformByName(const TString &name) const |
| { |
| for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex) |
| { |
| if (mUniforms[uniformIndex].name == name.c_str()) |
| { |
| return &mUniforms[uniformIndex]; |
| } |
| } |
| |
| UNREACHABLE(); |
| return NULL; |
| } |
| |
| unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, const TString &name) |
| { |
| unsigned int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister); |
| |
| const Uniform *uniform = findUniformByName(name); |
| ASSERT(uniform); |
| |
| mUniformRegisterMap[uniform->name] = registerIndex; |
| |
| unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType); |
| |
| if (gl::IsSampler(uniform->type)) |
| { |
| mSamplerRegister += registerCount; |
| } |
| else |
| { |
| mUniformRegister += registerCount; |
| } |
| |
| return registerIndex; |
| } |
| |
| TString UniformHLSL::uniformsHeader(ShShaderOutput outputType, const ReferencedSymbols &referencedUniforms) |
| { |
| TString uniforms; |
| |
| for (ReferencedSymbols::const_iterator uniformIt = referencedUniforms.begin(); |
| uniformIt != referencedUniforms.end(); uniformIt++) |
| { |
| const TIntermSymbol &uniform = *uniformIt->second; |
| const TType &type = uniform.getType(); |
| const TString &name = uniform.getSymbol(); |
| |
| unsigned int registerIndex = declareUniformAndAssignRegister(type, name); |
| |
| if (outputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) // Also declare the texture |
| { |
| uniforms += "uniform " + SamplerString(type) + " sampler_" + DecorateUniform(name, type) + ArrayString(type) + |
| " : register(s" + str(registerIndex) + ");\n"; |
| |
| uniforms += "uniform " + TextureString(type) + " texture_" + DecorateUniform(name, type) + ArrayString(type) + |
| " : register(t" + str(registerIndex) + ");\n"; |
| } |
| else |
| { |
| 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->name().empty()) ? |
| QualifiedStructNameString(*structure, false, false) : TypeString(type)); |
| |
| const TString ®isterString = TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")"; |
| |
| uniforms += "uniform " + typeName + " " + DecorateUniform(name, type) + ArrayString(type) + " : " + registerString + ";\n"; |
| } |
| } |
| |
| return (uniforms.empty() ? "" : ("// Uniforms\n\n" + uniforms)); |
| } |
| |
| TString UniformHLSL::interfaceBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks) |
| { |
| TString interfaceBlocks; |
| |
| for (ReferencedSymbols::const_iterator interfaceBlockIt = referencedInterfaceBlocks.begin(); |
| interfaceBlockIt != referencedInterfaceBlocks.end(); interfaceBlockIt++) |
| { |
| const TType &nodeType = interfaceBlockIt->second->getType(); |
| const TInterfaceBlock &interfaceBlock = *nodeType.getInterfaceBlock(); |
| |
| unsigned int arraySize = static_cast<unsigned int>(interfaceBlock.arraySize()); |
| unsigned int activeRegister = mInterfaceBlockRegister; |
| |
| mInterfaceBlockRegisterMap[interfaceBlock.name().c_str()] = activeRegister; |
| mInterfaceBlockRegister += std::max(1u, arraySize); |
| |
| // FIXME: interface block field names |
| |
| if (interfaceBlock.hasInstanceName()) |
| { |
| interfaceBlocks += interfaceBlockStructString(interfaceBlock); |
| } |
| |
| if (arraySize > 0) |
| { |
| for (unsigned int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) |
| { |
| interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister + arrayIndex, arrayIndex); |
| } |
| } |
| else |
| { |
| interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister, GL_INVALID_INDEX); |
| } |
| } |
| |
| return (interfaceBlocks.empty() ? "" : ("// Interface Blocks\n\n" + interfaceBlocks)); |
| } |
| |
| TString UniformHLSL::interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex) |
| { |
| const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? Decorate(str(arrayIndex)) : ""); |
| const TString &blockName = interfaceBlock.name() + arrayIndexString; |
| TString hlsl; |
| |
| hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + ")\n" |
| "{\n"; |
| |
| if (interfaceBlock.hasInstanceName()) |
| { |
| hlsl += " " + InterfaceBlockStructName(interfaceBlock) + " " + |
| interfaceBlockInstanceString(interfaceBlock, arrayIndex) + ";\n"; |
| } |
| else |
| { |
| const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); |
| hlsl += interfaceBlockMembersString(interfaceBlock, blockStorage); |
| } |
| |
| hlsl += "};\n\n"; |
| |
| return hlsl; |
| } |
| |
| TString UniformHLSL::interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex) |
| { |
| if (!interfaceBlock.hasInstanceName()) |
| { |
| return ""; |
| } |
| else if (interfaceBlock.isArray()) |
| { |
| return DecoratePrivate(interfaceBlock.instanceName()) + "_" + str(arrayIndex); |
| } |
| else |
| { |
| return Decorate(interfaceBlock.instanceName()); |
| } |
| } |
| |
| TString UniformHLSL::interfaceBlockMembersString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage) |
| { |
| TString hlsl; |
| |
| Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper(); |
| |
| for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); 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); |
| } |
| |
| hlsl += " " + InterfaceBlockFieldTypeString(field, blockStorage) + |
| " " + Decorate(field.name()) + ArrayString(fieldType) + ";\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); |
| } |
| } |
| |
| return hlsl; |
| } |
| |
| TString UniformHLSL::interfaceBlockStructString(const TInterfaceBlock &interfaceBlock) |
| { |
| const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); |
| |
| return "struct " + InterfaceBlockStructName(interfaceBlock) + "\n" |
| "{\n" + |
| interfaceBlockMembersString(interfaceBlock, blockStorage) + |
| "};\n\n"; |
| } |
| |
| } |