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.
7 // Methods for GLSL to HLSL translation for uniforms and interface blocks.
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"
21 static const char *UniformRegisterPrefix(const TType &type)
23 if (IsSampler(type.getBasicType()))
33 static TString InterfaceBlockFieldName(const TInterfaceBlock &interfaceBlock, const TField &field)
35 if (interfaceBlock.hasInstanceName())
37 return interfaceBlock.name() + "." + field.name();
45 static TString InterfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage)
47 const TType &fieldType = *field.type();
48 const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking;
49 ASSERT(matrixPacking != EmpUnspecified);
50 TStructure *structure = fieldType.getStruct();
52 if (fieldType.isMatrix())
54 // Use HLSL row-major packing for GLSL column-major matrices
55 const TString &matrixPackString = (matrixPacking == EmpRowMajor ? "column_major" : "row_major");
56 return matrixPackString + " " + TypeString(fieldType);
60 // Use HLSL row-major packing for GLSL column-major matrices
61 return QualifiedStructNameString(*structure, matrixPacking == EmpColumnMajor,
62 blockStorage == EbsStd140);
66 return TypeString(fieldType);
70 static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock)
72 return DecoratePrivate(interfaceBlock.name()) + "_type";
75 UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, ShShaderOutput outputType)
76 : mUniformRegister(0),
77 mInterfaceBlockRegister(0),
79 mStructureHLSL(structureHLSL),
80 mOutputType(outputType)
83 void UniformHLSL::reserveUniformRegisters(unsigned int registerCount)
85 mUniformRegister = registerCount;
88 void UniformHLSL::reserveInterfaceBlockRegisters(unsigned int registerCount)
90 mInterfaceBlockRegister = registerCount;
93 unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, const TString &name)
95 unsigned int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister);
97 GetVariableTraverser<Uniform> traverser(&mActiveUniforms);
98 traverser.traverse(type, name);
100 const sh::Uniform &activeUniform = mActiveUniforms.back();
101 mUniformRegisterMap[activeUniform.name] = registerIndex;
103 unsigned int registerCount = HLSLVariableRegisterCount(activeUniform, mOutputType);
104 if (IsSampler(type.getBasicType()))
106 mSamplerRegister += registerCount;
110 mUniformRegister += registerCount;
113 return registerIndex;
116 TString UniformHLSL::uniformsHeader(ShShaderOutput outputType, const ReferencedSymbols &referencedUniforms)
120 for (ReferencedSymbols::const_iterator uniformIt = referencedUniforms.begin();
121 uniformIt != referencedUniforms.end(); uniformIt++)
123 const TIntermSymbol &uniform = *uniformIt->second;
124 const TType &type = uniform.getType();
125 const TString &name = uniform.getSymbol();
127 unsigned int registerIndex = declareUniformAndAssignRegister(type, name);
129 if (outputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) // Also declare the texture
131 uniforms += "uniform " + SamplerString(type) + " sampler_" + DecorateUniform(name, type) + ArrayString(type) +
132 " : register(s" + str(registerIndex) + ");\n";
134 uniforms += "uniform " + TextureString(type) + " texture_" + DecorateUniform(name, type) + ArrayString(type) +
135 " : register(t" + str(registerIndex) + ");\n";
139 const TStructure *structure = type.getStruct();
140 // If this is a nameless struct, we need to use its full definition, rather than its (empty) name.
141 // TypeString() will invoke defineNameless in this case, but layout qualifiers will not be taken into
142 // account in this case.
143 // TODO: handle nameless structs with layout qualifiers.
144 const TString &typeName = ((structure && !structure->name().empty()) ?
145 QualifiedStructNameString(*structure, false, false) : TypeString(type));
147 const TString ®isterString = TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")";
149 uniforms += "uniform " + typeName + " " + DecorateUniform(name, type) + ArrayString(type) + " : " + registerString + ";\n";
153 return (uniforms.empty() ? "" : ("// Uniforms\n\n" + uniforms));
156 TString UniformHLSL::interfaceBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks)
158 TString interfaceBlocks;
160 for (ReferencedSymbols::const_iterator interfaceBlockIt = referencedInterfaceBlocks.begin();
161 interfaceBlockIt != referencedInterfaceBlocks.end(); interfaceBlockIt++)
163 const TType &nodeType = interfaceBlockIt->second->getType();
164 const TInterfaceBlock &interfaceBlock = *nodeType.getInterfaceBlock();
165 const TFieldList &fieldList = interfaceBlock.fields();
167 unsigned int arraySize = static_cast<unsigned int>(interfaceBlock.arraySize());
168 unsigned int activeRegister = mInterfaceBlockRegister;
170 InterfaceBlock activeBlock;
171 activeBlock.name = interfaceBlock.name().c_str();
172 activeBlock.arraySize = arraySize;
174 for (unsigned int typeIndex = 0; typeIndex < fieldList.size(); typeIndex++)
176 const TField &field = *fieldList[typeIndex];
177 const TString &fullFieldName = InterfaceBlockFieldName(interfaceBlock, field);
179 bool isRowMajor = (field.type()->getLayoutQualifier().matrixPacking == EmpRowMajor);
180 GetInterfaceBlockFieldTraverser traverser(&activeBlock.fields, isRowMajor);
181 traverser.traverse(*field.type(), fullFieldName);
184 mInterfaceBlockRegisterMap[activeBlock.name] = activeRegister;
185 mInterfaceBlockRegister += std::max(1u, arraySize);
187 activeBlock.layout = GetBlockLayoutType(interfaceBlock.blockStorage());
189 if (interfaceBlock.matrixPacking() == EmpRowMajor)
191 activeBlock.isRowMajorLayout = true;
194 mActiveInterfaceBlocks.push_back(activeBlock);
196 if (interfaceBlock.hasInstanceName())
198 interfaceBlocks += interfaceBlockStructString(interfaceBlock);
203 for (unsigned int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
205 interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister + arrayIndex, arrayIndex);
210 interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister, GL_INVALID_INDEX);
214 return (interfaceBlocks.empty() ? "" : ("// Interface Blocks\n\n" + interfaceBlocks));
217 TString UniformHLSL::interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex)
219 const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? Decorate(str(arrayIndex)) : "");
220 const TString &blockName = interfaceBlock.name() + arrayIndexString;
223 hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + ")\n"
226 if (interfaceBlock.hasInstanceName())
228 hlsl += " " + InterfaceBlockStructName(interfaceBlock) + " " +
229 interfaceBlockInstanceString(interfaceBlock, arrayIndex) + ";\n";
233 const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
234 hlsl += interfaceBlockMembersString(interfaceBlock, blockStorage);
242 TString UniformHLSL::interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex)
244 if (!interfaceBlock.hasInstanceName())
248 else if (interfaceBlock.isArray())
250 return DecoratePrivate(interfaceBlock.instanceName()) + "_" + str(arrayIndex);
254 return Decorate(interfaceBlock.instanceName());
258 TString UniformHLSL::interfaceBlockMembersString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage)
262 Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper();
264 for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++)
266 const TField &field = *interfaceBlock.fields()[typeIndex];
267 const TType &fieldType = *field.type();
269 if (blockStorage == EbsStd140)
271 // 2 and 3 component vector types in some cases need pre-padding
272 hlsl += padHelper.prePadding(fieldType);
275 hlsl += " " + InterfaceBlockFieldTypeString(field, blockStorage) +
276 " " + Decorate(field.name()) + ArrayString(fieldType) + ";\n";
278 // must pad out after matrices and arrays, where HLSL usually allows itself room to pack stuff
279 if (blockStorage == EbsStd140)
281 const bool useHLSLRowMajorPacking = (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
282 hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking);
289 TString UniformHLSL::interfaceBlockStructString(const TInterfaceBlock &interfaceBlock)
291 const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
293 return "struct " + InterfaceBlockStructName(interfaceBlock) + "\n"
295 interfaceBlockMembersString(interfaceBlock, blockStorage) +