1 // 2 // Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 // UniformHLSL.cpp: 7 // Methods for GLSL to HLSL translation for uniforms and interface blocks. 8 // 9 10 #include "OutputHLSL.h" 11 #include "common/blocklayout.h" 12 #include "common/utilities.h" 13 #include "compiler/translator/UniformHLSL.h" 14 #include "compiler/translator/StructureHLSL.h" 15 #include "compiler/translator/util.h" 16 #include "compiler/translator/UtilsHLSL.h" 17 #include "compiler/translator/TranslatorHLSL.h" 18 19 namespace sh 20 { 21 22 static const char *UniformRegisterPrefix(const TType &type) 23 { 24 if (IsSampler(type.getBasicType())) 25 { 26 return "s"; 27 } 28 else 29 { 30 return "c"; 31 } 32 } 33 34 static TString InterfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage) 35 { 36 const TType &fieldType = *field.type(); 37 const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking; 38 ASSERT(matrixPacking != EmpUnspecified); 39 TStructure *structure = fieldType.getStruct(); 40 41 if (fieldType.isMatrix()) 42 { 43 // Use HLSL row-major packing for GLSL column-major matrices 44 const TString &matrixPackString = (matrixPacking == EmpRowMajor ? "column_major" : "row_major"); 45 return matrixPackString + " " + TypeString(fieldType); 46 } 47 else if (structure) 48 { 49 // Use HLSL row-major packing for GLSL column-major matrices 50 return QualifiedStructNameString(*structure, matrixPacking == EmpColumnMajor, 51 blockStorage == EbsStd140); 52 } 53 else 54 { 55 return TypeString(fieldType); 56 } 57 } 58 59 static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock) 60 { 61 return DecoratePrivate(interfaceBlock.name()) + "_type"; 62 } 63 64 UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, TranslatorHLSL *translator) 65 : mUniformRegister(0), 66 mInterfaceBlockRegister(0), 67 mSamplerRegister(0), 68 mStructureHLSL(structureHLSL), 69 mOutputType(translator->getOutputType()), 70 mUniforms(translator->getUniforms()) 71 {} 72 73 void UniformHLSL::reserveUniformRegisters(unsigned int registerCount) 74 { 75 mUniformRegister = registerCount; 76 } 77 78 void UniformHLSL::reserveInterfaceBlockRegisters(unsigned int registerCount) 79 { 80 mInterfaceBlockRegister = registerCount; 81 } 82 83 const Uniform *UniformHLSL::findUniformByName(const TString &name) const 84 { 85 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex) 86 { 87 if (mUniforms[uniformIndex].name == name.c_str()) 88 { 89 return &mUniforms[uniformIndex]; 90 } 91 } 92 93 UNREACHABLE(); 94 return NULL; 95 } 96 97 unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, const TString &name) 98 { 99 unsigned int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister); 100 101 const Uniform *uniform = findUniformByName(name); 102 ASSERT(uniform); 103 104 mUniformRegisterMap[uniform->name] = registerIndex; 105 106 unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType); 107 108 if (gl::IsSampler(uniform->type)) 109 { 110 mSamplerRegister += registerCount; 111 } 112 else 113 { 114 mUniformRegister += registerCount; 115 } 116 117 return registerIndex; 118 } 119 120 TString UniformHLSL::uniformsHeader(ShShaderOutput outputType, const ReferencedSymbols &referencedUniforms) 121 { 122 TString uniforms; 123 124 for (ReferencedSymbols::const_iterator uniformIt = referencedUniforms.begin(); 125 uniformIt != referencedUniforms.end(); uniformIt++) 126 { 127 const TIntermSymbol &uniform = *uniformIt->second; 128 const TType &type = uniform.getType(); 129 const TString &name = uniform.getSymbol(); 130 131 unsigned int registerIndex = declareUniformAndAssignRegister(type, name); 132 133 if (outputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) // Also declare the texture 134 { 135 uniforms += "uniform " + SamplerString(type) + " sampler_" + DecorateUniform(name, type) + ArrayString(type) + 136 " : register(s" + str(registerIndex) + ");\n"; 137 138 uniforms += "uniform " + TextureString(type) + " texture_" + DecorateUniform(name, type) + ArrayString(type) + 139 " : register(t" + str(registerIndex) + ");\n"; 140 } 141 else 142 { 143 const TStructure *structure = type.getStruct(); 144 // If this is a nameless struct, we need to use its full definition, rather than its (empty) name. 145 // TypeString() will invoke defineNameless in this case; qualifier prefixes are unnecessary for 146 // nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers are 147 // permitted. 148 const TString &typeName = ((structure && !structure->name().empty()) ? 149 QualifiedStructNameString(*structure, false, false) : TypeString(type)); 150 151 const TString ®isterString = TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")"; 152 153 uniforms += "uniform " + typeName + " " + DecorateUniform(name, type) + ArrayString(type) + " : " + registerString + ";\n"; 154 } 155 } 156 157 return (uniforms.empty() ? "" : ("// Uniforms\n\n" + uniforms)); 158 } 159 160 TString UniformHLSL::interfaceBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks) 161 { 162 TString interfaceBlocks; 163 164 for (ReferencedSymbols::const_iterator interfaceBlockIt = referencedInterfaceBlocks.begin(); 165 interfaceBlockIt != referencedInterfaceBlocks.end(); interfaceBlockIt++) 166 { 167 const TType &nodeType = interfaceBlockIt->second->getType(); 168 const TInterfaceBlock &interfaceBlock = *nodeType.getInterfaceBlock(); 169 170 unsigned int arraySize = static_cast<unsigned int>(interfaceBlock.arraySize()); 171 unsigned int activeRegister = mInterfaceBlockRegister; 172 173 mInterfaceBlockRegisterMap[interfaceBlock.name().c_str()] = activeRegister; 174 mInterfaceBlockRegister += std::max(1u, arraySize); 175 176 // FIXME: interface block field names 177 178 if (interfaceBlock.hasInstanceName()) 179 { 180 interfaceBlocks += interfaceBlockStructString(interfaceBlock); 181 } 182 183 if (arraySize > 0) 184 { 185 for (unsigned int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) 186 { 187 interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister + arrayIndex, arrayIndex); 188 } 189 } 190 else 191 { 192 interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister, GL_INVALID_INDEX); 193 } 194 } 195 196 return (interfaceBlocks.empty() ? "" : ("// Interface Blocks\n\n" + interfaceBlocks)); 197 } 198 199 TString UniformHLSL::interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex) 200 { 201 const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? Decorate(str(arrayIndex)) : ""); 202 const TString &blockName = interfaceBlock.name() + arrayIndexString; 203 TString hlsl; 204 205 hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + ")\n" 206 "{\n"; 207 208 if (interfaceBlock.hasInstanceName()) 209 { 210 hlsl += " " + InterfaceBlockStructName(interfaceBlock) + " " + 211 interfaceBlockInstanceString(interfaceBlock, arrayIndex) + ";\n"; 212 } 213 else 214 { 215 const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); 216 hlsl += interfaceBlockMembersString(interfaceBlock, blockStorage); 217 } 218 219 hlsl += "};\n\n"; 220 221 return hlsl; 222 } 223 224 TString UniformHLSL::interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex) 225 { 226 if (!interfaceBlock.hasInstanceName()) 227 { 228 return ""; 229 } 230 else if (interfaceBlock.isArray()) 231 { 232 return DecoratePrivate(interfaceBlock.instanceName()) + "_" + str(arrayIndex); 233 } 234 else 235 { 236 return Decorate(interfaceBlock.instanceName()); 237 } 238 } 239 240 TString UniformHLSL::interfaceBlockMembersString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage) 241 { 242 TString hlsl; 243 244 Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper(); 245 246 for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++) 247 { 248 const TField &field = *interfaceBlock.fields()[typeIndex]; 249 const TType &fieldType = *field.type(); 250 251 if (blockStorage == EbsStd140) 252 { 253 // 2 and 3 component vector types in some cases need pre-padding 254 hlsl += padHelper.prePaddingString(fieldType); 255 } 256 257 hlsl += " " + InterfaceBlockFieldTypeString(field, blockStorage) + 258 " " + Decorate(field.name()) + ArrayString(fieldType) + ";\n"; 259 260 // must pad out after matrices and arrays, where HLSL usually allows itself room to pack stuff 261 if (blockStorage == EbsStd140) 262 { 263 const bool useHLSLRowMajorPacking = (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor); 264 hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking); 265 } 266 } 267 268 return hlsl; 269 } 270 271 TString UniformHLSL::interfaceBlockStructString(const TInterfaceBlock &interfaceBlock) 272 { 273 const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); 274 275 return "struct " + InterfaceBlockStructName(interfaceBlock) + "\n" 276 "{\n" + 277 interfaceBlockMembersString(interfaceBlock, blockStorage) + 278 "};\n\n"; 279 } 280 281 } 282