Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / compiler / translator / StructureHLSL.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 // StructureHLSL.cpp:
7 //   Definitions of methods for HLSL translation of GLSL structures.
8 //
9
10 #include "compiler/translator/StructureHLSL.h"
11 #include "common/utilities.h"
12 #include "compiler/translator/OutputHLSL.h"
13 #include "compiler/translator/Types.h"
14 #include "compiler/translator/util.h"
15 #include "compiler/translator/UtilsHLSL.h"
16
17 namespace sh
18 {
19
20 Std140PaddingHelper::Std140PaddingHelper(const std::map<TString, int> &structElementIndexes,
21                                          unsigned *uniqueCounter)
22     : mPaddingCounter(uniqueCounter),
23       mElementIndex(0),
24       mStructElementIndexes(structElementIndexes)
25 {}
26
27 TString Std140PaddingHelper::next()
28 {
29     unsigned value = (*mPaddingCounter)++;
30     return str(value);
31 }
32
33 int Std140PaddingHelper::prePadding(const TType &type)
34 {
35     if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
36     {
37         // no padding needed, HLSL will align the field to a new register
38         mElementIndex = 0;
39         return 0;
40     }
41
42     const GLenum glType = GLVariableType(type);
43     const int numComponents = gl::VariableComponentCount(glType);
44
45     if (numComponents >= 4)
46     {
47         // no padding needed, HLSL will align the field to a new register
48         mElementIndex = 0;
49         return 0;
50     }
51
52     if (mElementIndex + numComponents > 4)
53     {
54         // no padding needed, HLSL will align the field to a new register
55         mElementIndex = numComponents;
56         return 0;
57     }
58
59     const int alignment = numComponents == 3 ? 4 : numComponents;
60     const int paddingOffset = (mElementIndex % alignment);
61     const int paddingCount = (paddingOffset != 0 ? (alignment - paddingOffset) : 0);
62
63     mElementIndex += paddingCount;
64     mElementIndex += numComponents;
65     mElementIndex %= 4;
66
67     return paddingCount;
68 }
69
70 TString Std140PaddingHelper::prePaddingString(const TType &type)
71 {
72     int paddingCount = prePadding(type);
73
74     TString padding;
75
76     for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++)
77     {
78         padding += "    float pad_" + next() + ";\n";
79     }
80
81     return padding;
82 }
83
84 TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRowMajorPacking)
85 {
86     if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
87     {
88         return "";
89     }
90
91     int numComponents = 0;
92     TStructure *structure = type.getStruct();
93
94     if (type.isMatrix())
95     {
96         // This method can also be called from structureString, which does not use layout qualifiers.
97         // Thus, use the method parameter for determining the matrix packing.
98         //
99         // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we
100         // wish to always transpose GL matrices to play well with HLSL's matrix array indexing.
101         //
102         const bool isRowMajorMatrix = !useHLSLRowMajorPacking;
103         const GLenum glType = GLVariableType(type);
104         numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix);
105     }
106     else if (structure)
107     {
108         const TString &structName = QualifiedStructNameString(*structure,
109                                                               useHLSLRowMajorPacking, true);
110         numComponents = mStructElementIndexes.find(structName)->second;
111
112         if (numComponents == 0)
113         {
114             return "";
115         }
116     }
117     else
118     {
119         const GLenum glType = GLVariableType(type);
120         numComponents = gl::VariableComponentCount(glType);
121     }
122
123     TString padding;
124     for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++)
125     {
126         padding += "    float pad_" + next() + ";\n";
127     }
128     return padding;
129 }
130
131 StructureHLSL::StructureHLSL()
132     : mUniquePaddingCounter(0)
133 {}
134
135 Std140PaddingHelper StructureHLSL::getPaddingHelper()
136 {
137     return Std140PaddingHelper(mStd140StructElementIndexes, &mUniquePaddingCounter);
138 }
139
140 TString StructureHLSL::defineQualified(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing)
141 {
142     if (useStd140Packing)
143     {
144         Std140PaddingHelper padHelper = getPaddingHelper();
145         return define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper);
146     }
147     else
148     {
149         return define(structure, useHLSLRowMajorPacking, useStd140Packing, NULL);
150     }
151 }
152
153 TString StructureHLSL::defineNameless(const TStructure &structure)
154 {
155     return define(structure, false, false, NULL);
156 }
157
158 TString StructureHLSL::define(const TStructure &structure, bool useHLSLRowMajorPacking,
159                               bool useStd140Packing, Std140PaddingHelper *padHelper)
160 {
161     const TFieldList &fields = structure.fields();
162     const bool isNameless = (structure.name() == "");
163     const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking,
164                                                           useStd140Packing);
165     const TString declareString = (isNameless ? "struct" : "struct " + structName);
166
167     TString string;
168     string += declareString + "\n"
169               "{\n";
170
171     for (unsigned int i = 0; i < fields.size(); i++)
172     {
173         const TField &field = *fields[i];
174         const TType &fieldType = *field.type();
175         const TStructure *fieldStruct = fieldType.getStruct();
176         const TString &fieldTypeString = fieldStruct ?
177                                          QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
178                                                                    useStd140Packing) :
179                                          TypeString(fieldType);
180
181         if (padHelper)
182         {
183             string += padHelper->prePaddingString(fieldType);
184         }
185
186         string += "    " + fieldTypeString + " " + DecorateField(field.name(), structure) + ArrayString(fieldType) + ";\n";
187
188         if (padHelper)
189         {
190             string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
191         }
192     }
193
194     // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable
195     string += (isNameless ? "} " : "};\n");
196
197     return string;
198 }
199
200 void StructureHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
201 {
202     if (name == "")
203     {
204         return;   // Nameless structures don't have constructors
205     }
206
207     if (type.getStruct() && mStructNames.find(name) != mStructNames.end())
208     {
209         return;   // Already added
210     }
211
212     TType ctorType = type;
213     ctorType.clearArrayness();
214     ctorType.setPrecision(EbpHigh);
215     ctorType.setQualifier(EvqTemporary);
216
217     typedef std::vector<TType> ParameterArray;
218     ParameterArray ctorParameters;
219
220     const TStructure* structure = type.getStruct();
221     if (structure)
222     {
223         mStructNames.insert(name);
224
225         // Add element index
226         storeStd140ElementIndex(*structure, false);
227         storeStd140ElementIndex(*structure, true);
228
229         const TString &structString = defineQualified(*structure, false, false);
230
231         if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == mStructDeclarations.end())
232         {
233             // Add row-major packed struct for interface blocks
234             TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
235                 defineQualified(*structure, true, false) +
236                 "#pragma pack_matrix(column_major)\n";
237
238             TString std140String = defineQualified(*structure, false, true);
239             TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
240                 defineQualified(*structure, true, true) +
241                 "#pragma pack_matrix(column_major)\n";
242
243             mStructDeclarations.push_back(structString);
244             mStructDeclarations.push_back(rowMajorString);
245             mStructDeclarations.push_back(std140String);
246             mStructDeclarations.push_back(std140RowMajorString);
247         }
248
249         const TFieldList &fields = structure->fields();
250         for (unsigned int i = 0; i < fields.size(); i++)
251         {
252             ctorParameters.push_back(*fields[i]->type());
253         }
254     }
255     else if (parameters)
256     {
257         for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
258         {
259             ctorParameters.push_back((*parameter)->getAsTyped()->getType());
260         }
261     }
262     else UNREACHABLE();
263
264     TString constructor;
265
266     if (ctorType.getStruct())
267     {
268         constructor += name + " " + name + "_ctor(";
269     }
270     else   // Built-in type
271     {
272         constructor += TypeString(ctorType) + " " + name + "(";
273     }
274
275     for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
276     {
277         const TType &type = ctorParameters[parameter];
278
279         constructor += TypeString(type) + " x" + str(parameter) + ArrayString(type);
280
281         if (parameter < ctorParameters.size() - 1)
282         {
283             constructor += ", ";
284         }
285     }
286
287     constructor += ")\n"
288                    "{\n";
289
290     if (ctorType.getStruct())
291     {
292         constructor += "    " + name + " structure = {";
293     }
294     else
295     {
296         constructor += "    return " + TypeString(ctorType) + "(";
297     }
298
299     if (ctorType.isMatrix() && ctorParameters.size() == 1)
300     {
301         int rows = ctorType.getRows();
302         int cols = ctorType.getCols();
303         const TType &parameter = ctorParameters[0];
304
305         if (parameter.isScalar())
306         {
307             for (int col = 0; col < cols; col++)
308             {
309                 for (int row = 0; row < rows; row++)
310                 {
311                     constructor += TString((row == col) ? "x0" : "0.0");
312
313                     if (row < rows - 1 || col < cols - 1)
314                     {
315                         constructor += ", ";
316                     }
317                 }
318             }
319         }
320         else if (parameter.isMatrix())
321         {
322             for (int col = 0; col < cols; col++)
323             {
324                 for (int row = 0; row < rows; row++)
325                 {
326                     if (row < parameter.getRows() && col < parameter.getCols())
327                     {
328                         constructor += TString("x0") + "[" + str(col) + "][" + str(row) + "]";
329                     }
330                     else
331                     {
332                         constructor += TString((row == col) ? "1.0" : "0.0");
333                     }
334
335                     if (row < rows - 1 || col < cols - 1)
336                     {
337                         constructor += ", ";
338                     }
339                 }
340             }
341         }
342         else
343         {
344             ASSERT(rows == 2 && cols == 2 && parameter.isVector() && parameter.getNominalSize() == 4);
345
346             constructor += "x0";
347         }
348     }
349     else
350     {
351         size_t remainingComponents = ctorType.getObjectSize();
352         size_t parameterIndex = 0;
353
354         while (remainingComponents > 0)
355         {
356             const TType &parameter = ctorParameters[parameterIndex];
357             const size_t parameterSize = parameter.getObjectSize();
358             bool moreParameters = parameterIndex + 1 < ctorParameters.size();
359
360             constructor += "x" + str(parameterIndex);
361
362             if (ctorType.getStruct())
363             {
364                 ASSERT(remainingComponents == parameterSize || moreParameters);
365                 ASSERT(parameterSize <= remainingComponents);
366
367                 remainingComponents -= parameterSize;
368             }
369             else if (parameter.isScalar())
370             {
371                 remainingComponents -= parameter.getObjectSize();
372             }
373             else if (parameter.isVector())
374             {
375                 if (remainingComponents == parameterSize || moreParameters)
376                 {
377                     ASSERT(parameterSize <= remainingComponents);
378                     remainingComponents -= parameterSize;
379                 }
380                 else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
381                 {
382                     switch (remainingComponents)
383                     {
384                       case 1: constructor += ".x";    break;
385                       case 2: constructor += ".xy";   break;
386                       case 3: constructor += ".xyz";  break;
387                       case 4: constructor += ".xyzw"; break;
388                       default: UNREACHABLE();
389                     }
390
391                     remainingComponents = 0;
392                 }
393                 else UNREACHABLE();
394             }
395             else if (parameter.isMatrix())
396             {
397                 int column = 0;
398                 while (remainingComponents > 0 && column < parameter.getCols())
399                 {
400                     constructor += "[" + str(column) + "]";
401
402                     if (remainingComponents < static_cast<size_t>(parameter.getRows()))
403                     {
404                         switch (remainingComponents)
405                         {
406                           case 1:  constructor += ".x";    break;
407                           case 2:  constructor += ".xy";   break;
408                           case 3:  constructor += ".xyz";  break;
409                           default: UNREACHABLE();
410                         }
411
412                         remainingComponents = 0;
413                     }
414                     else
415                     {
416                         remainingComponents -= parameter.getRows();
417
418                         if (remainingComponents > 0)
419                         {
420                             constructor += ", x" + str(parameterIndex);
421                         }
422                     }
423
424                     column++;
425                 }
426             }
427             else UNREACHABLE();
428
429             if (moreParameters)
430             {
431                 parameterIndex++;
432             }
433
434             if (remainingComponents)
435             {
436                 constructor += ", ";
437             }
438         }
439     }
440
441     if (ctorType.getStruct())
442     {
443         constructor += "};\n"
444                         "    return structure;\n"
445                         "}\n";
446     }
447     else
448     {
449         constructor += ");\n"
450                        "}\n";
451     }
452
453     mConstructors.insert(constructor);
454 }
455
456 std::string StructureHLSL::structsHeader() const
457 {
458     TInfoSinkBase out;
459
460     for (size_t structIndex = 0; structIndex < mStructDeclarations.size(); structIndex++)
461     {
462         out << mStructDeclarations[structIndex];
463     }
464
465     for (Constructors::const_iterator constructor = mConstructors.begin();
466          constructor != mConstructors.end();
467          constructor++)
468     {
469         out << *constructor;
470     }
471
472     return out.str();
473 }
474
475 void StructureHLSL::storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking)
476 {
477     Std140PaddingHelper padHelper = getPaddingHelper();
478     const TFieldList &fields = structure.fields();
479
480     for (unsigned int i = 0; i < fields.size(); i++)
481     {
482         padHelper.prePadding(*fields[i]->type());
483     }
484
485     // Add remaining element index to the global map, for use with nested structs in standard layouts
486     const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, true);
487     mStd140StructElementIndexes[structName] = padHelper.elementIndex();
488 }
489
490 }