Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / compiler / translator / UniformHLSL.cpp
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
18 namespace sh
19 {
20
21 static const char *UniformRegisterPrefix(const TType &type)
22 {
23     if (IsSampler(type.getBasicType()))
24     {
25         return "s";
26     }
27     else
28     {
29         return "c";
30     }
31 }
32
33 static TString InterfaceBlockFieldName(const TInterfaceBlock &interfaceBlock, const TField &field)
34 {
35     if (interfaceBlock.hasInstanceName())
36     {
37         return interfaceBlock.name() + "." + field.name();
38     }
39     else
40     {
41         return field.name();
42     }
43 }
44
45 static TString InterfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage)
46 {
47     const TType &fieldType = *field.type();
48     const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking;
49     ASSERT(matrixPacking != EmpUnspecified);
50     TStructure *structure = fieldType.getStruct();
51
52     if (fieldType.isMatrix())
53     {
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);
57     }
58     else if (structure)
59     {
60         // Use HLSL row-major packing for GLSL column-major matrices
61         return QualifiedStructNameString(*structure, matrixPacking == EmpColumnMajor,
62             blockStorage == EbsStd140);
63     }
64     else
65     {
66         return TypeString(fieldType);
67     }
68 }
69
70 static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock)
71 {
72     return DecoratePrivate(interfaceBlock.name()) + "_type";
73 }
74
75 UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, ShShaderOutput outputType)
76     : mUniformRegister(0),
77       mInterfaceBlockRegister(0),
78       mSamplerRegister(0),
79       mStructureHLSL(structureHLSL),
80       mOutputType(outputType)
81 {}
82
83 void UniformHLSL::reserveUniformRegisters(unsigned int registerCount)
84 {
85     mUniformRegister = registerCount;
86 }
87
88 void UniformHLSL::reserveInterfaceBlockRegisters(unsigned int registerCount)
89 {
90     mInterfaceBlockRegister = registerCount;
91 }
92
93 unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, const TString &name)
94 {
95     unsigned int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister);
96
97     GetVariableTraverser<Uniform> traverser(&mActiveUniforms);
98     traverser.traverse(type, name);
99
100     const sh::Uniform &activeUniform = mActiveUniforms.back();
101     mUniformRegisterMap[activeUniform.name] = registerIndex;
102
103     unsigned int registerCount = HLSLVariableRegisterCount(activeUniform, mOutputType);
104     if (IsSampler(type.getBasicType()))
105     {
106         mSamplerRegister += registerCount;
107     }
108     else
109     {
110         mUniformRegister += registerCount;
111     }
112
113     return registerIndex;
114 }
115
116 TString UniformHLSL::uniformsHeader(ShShaderOutput outputType, const ReferencedSymbols &referencedUniforms)
117 {
118     TString uniforms;
119
120     for (ReferencedSymbols::const_iterator uniformIt = referencedUniforms.begin();
121          uniformIt != referencedUniforms.end(); uniformIt++)
122     {
123         const TIntermSymbol &uniform = *uniformIt->second;
124         const TType &type = uniform.getType();
125         const TString &name = uniform.getSymbol();
126
127         unsigned int registerIndex = declareUniformAndAssignRegister(type, name);
128
129         if (outputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType()))   // Also declare the texture
130         {
131             uniforms += "uniform " + SamplerString(type) + " sampler_" + DecorateUniform(name, type) + ArrayString(type) +
132                         " : register(s" + str(registerIndex) + ");\n";
133
134             uniforms += "uniform " + TextureString(type) + " texture_" + DecorateUniform(name, type) + ArrayString(type) +
135                         " : register(t" + str(registerIndex) + ");\n";
136         }
137         else
138         {
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));
146
147             const TString &registerString = TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")";
148
149             uniforms += "uniform " + typeName + " " + DecorateUniform(name, type) + ArrayString(type) + " : " + registerString + ";\n";
150         }
151     }
152
153     return (uniforms.empty() ? "" : ("// Uniforms\n\n" + uniforms));
154 }
155
156 TString UniformHLSL::interfaceBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks)
157 {
158     TString interfaceBlocks;
159
160     for (ReferencedSymbols::const_iterator interfaceBlockIt = referencedInterfaceBlocks.begin();
161          interfaceBlockIt != referencedInterfaceBlocks.end(); interfaceBlockIt++)
162     {
163         const TType &nodeType = interfaceBlockIt->second->getType();
164         const TInterfaceBlock &interfaceBlock = *nodeType.getInterfaceBlock();
165         const TFieldList &fieldList = interfaceBlock.fields();
166
167         unsigned int arraySize = static_cast<unsigned int>(interfaceBlock.arraySize());
168         unsigned int activeRegister = mInterfaceBlockRegister;
169
170         InterfaceBlock activeBlock;
171         activeBlock.name = interfaceBlock.name().c_str();
172         activeBlock.arraySize = arraySize;
173
174         for (unsigned int typeIndex = 0; typeIndex < fieldList.size(); typeIndex++)
175         {
176             const TField &field = *fieldList[typeIndex];
177             const TString &fullFieldName = InterfaceBlockFieldName(interfaceBlock, field);
178
179             bool isRowMajor = (field.type()->getLayoutQualifier().matrixPacking == EmpRowMajor);
180             GetInterfaceBlockFieldTraverser traverser(&activeBlock.fields, isRowMajor);
181             traverser.traverse(*field.type(), fullFieldName);
182         }
183
184         mInterfaceBlockRegisterMap[activeBlock.name] = activeRegister;
185         mInterfaceBlockRegister += std::max(1u, arraySize);
186
187         activeBlock.layout = GetBlockLayoutType(interfaceBlock.blockStorage());
188
189         if (interfaceBlock.matrixPacking() == EmpRowMajor)
190         {
191             activeBlock.isRowMajorLayout = true;
192         }
193
194         mActiveInterfaceBlocks.push_back(activeBlock);
195
196         if (interfaceBlock.hasInstanceName())
197         {
198             interfaceBlocks += interfaceBlockStructString(interfaceBlock);
199         }
200
201         if (arraySize > 0)
202         {
203             for (unsigned int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
204             {
205                 interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister + arrayIndex, arrayIndex);
206             }
207         }
208         else
209         {
210             interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister, GL_INVALID_INDEX);
211         }
212     }
213
214     return (interfaceBlocks.empty() ? "" : ("// Interface Blocks\n\n" + interfaceBlocks));
215 }
216
217 TString UniformHLSL::interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex)
218 {
219     const TString &arrayIndexString =  (arrayIndex != GL_INVALID_INDEX ? Decorate(str(arrayIndex)) : "");
220     const TString &blockName = interfaceBlock.name() + arrayIndexString;
221     TString hlsl;
222
223     hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + ")\n"
224             "{\n";
225
226     if (interfaceBlock.hasInstanceName())
227     {
228         hlsl += "    " + InterfaceBlockStructName(interfaceBlock) + " " +
229                 interfaceBlockInstanceString(interfaceBlock, arrayIndex) + ";\n";
230     }
231     else
232     {
233         const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
234         hlsl += interfaceBlockMembersString(interfaceBlock, blockStorage);
235     }
236
237     hlsl += "};\n\n";
238
239     return hlsl;
240 }
241
242 TString UniformHLSL::interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex)
243 {
244     if (!interfaceBlock.hasInstanceName())
245     {
246         return "";
247     }
248     else if (interfaceBlock.isArray())
249     {
250         return DecoratePrivate(interfaceBlock.instanceName()) + "_" + str(arrayIndex);
251     }
252     else
253     {
254         return Decorate(interfaceBlock.instanceName());
255     }
256 }
257
258 TString UniformHLSL::interfaceBlockMembersString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage)
259 {
260     TString hlsl;
261
262     Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper();
263
264     for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++)
265     {
266         const TField &field = *interfaceBlock.fields()[typeIndex];
267         const TType &fieldType = *field.type();
268
269         if (blockStorage == EbsStd140)
270         {
271             // 2 and 3 component vector types in some cases need pre-padding
272             hlsl += padHelper.prePadding(fieldType);
273         }
274
275         hlsl += "    " + InterfaceBlockFieldTypeString(field, blockStorage) +
276                 " " + Decorate(field.name()) + ArrayString(fieldType) + ";\n";
277
278         // must pad out after matrices and arrays, where HLSL usually allows itself room to pack stuff
279         if (blockStorage == EbsStd140)
280         {
281             const bool useHLSLRowMajorPacking = (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
282             hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking);
283         }
284     }
285
286     return hlsl;
287 }
288
289 TString UniformHLSL::interfaceBlockStructString(const TInterfaceBlock &interfaceBlock)
290 {
291     const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
292
293     return "struct " + InterfaceBlockStructName(interfaceBlock) + "\n"
294            "{\n" +
295            interfaceBlockMembersString(interfaceBlock, blockStorage) +
296            "};\n\n";
297 }
298
299 }