• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 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 //   HLSL translation of GLSL constructors and 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/UtilsHLSL.h"
15 #include "compiler/translator/util.h"
16 
17 namespace sh
18 {
19 
20 namespace
21 {
22 
Define(const TStructure & structure,bool useHLSLRowMajorPacking,bool useStd140Packing,Std140PaddingHelper * padHelper)23 TString Define(const TStructure &structure,
24                bool useHLSLRowMajorPacking,
25                bool useStd140Packing,
26                Std140PaddingHelper *padHelper)
27 {
28     const TFieldList &fields = structure.fields();
29     const bool isNameless    = (structure.symbolType() == SymbolType::Empty);
30     const TString &structName =
31         QualifiedStructNameString(structure, useHLSLRowMajorPacking, useStd140Packing);
32     const TString declareString = (isNameless ? "struct" : "struct " + structName);
33 
34     TString string;
35     string += declareString +
36               "\n"
37               "{\n";
38 
39     for (const TField *field : fields)
40     {
41         const TType &fieldType = *field->type();
42         if (!IsSampler(fieldType.getBasicType()))
43         {
44             const TStructure *fieldStruct = fieldType.getStruct();
45             const TString &fieldTypeString =
46                 fieldStruct ? QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
47                                                         useStd140Packing)
48                             : TypeString(fieldType);
49 
50             if (padHelper)
51             {
52                 string += padHelper->prePaddingString(fieldType);
53             }
54 
55             string += "    " + fieldTypeString + " " + DecorateField(field->name(), structure) +
56                       ArrayString(fieldType).data() + ";\n";
57 
58             if (padHelper)
59             {
60                 string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
61             }
62         }
63     }
64 
65     // Nameless structs do not finish with a semicolon and newline, to leave room for an instance
66     // variable
67     string += (isNameless ? "} " : "};\n");
68 
69     return string;
70 }
71 
WriteParameterList(const std::vector<TType> & parameters)72 TString WriteParameterList(const std::vector<TType> &parameters)
73 {
74     TString parameterList;
75     for (size_t parameter = 0u; parameter < parameters.size(); parameter++)
76     {
77         const TType &paramType = parameters[parameter];
78 
79         parameterList +=
80             TypeString(paramType) + " x" + str(parameter) + ArrayString(paramType).data();
81 
82         if (parameter < parameters.size() - 1u)
83         {
84             parameterList += ", ";
85         }
86     }
87     return parameterList;
88 }
89 
90 }  // anonymous namespace
91 
Std140PaddingHelper(const std::map<TString,int> & structElementIndexes,unsigned * uniqueCounter)92 Std140PaddingHelper::Std140PaddingHelper(const std::map<TString, int> &structElementIndexes,
93                                          unsigned *uniqueCounter)
94     : mPaddingCounter(uniqueCounter), mElementIndex(0), mStructElementIndexes(&structElementIndexes)
95 {}
96 
Std140PaddingHelper(const Std140PaddingHelper & other)97 Std140PaddingHelper::Std140PaddingHelper(const Std140PaddingHelper &other)
98     : mPaddingCounter(other.mPaddingCounter),
99       mElementIndex(other.mElementIndex),
100       mStructElementIndexes(other.mStructElementIndexes)
101 {}
102 
operator =(const Std140PaddingHelper & other)103 Std140PaddingHelper &Std140PaddingHelper::operator=(const Std140PaddingHelper &other)
104 {
105     mPaddingCounter       = other.mPaddingCounter;
106     mElementIndex         = other.mElementIndex;
107     mStructElementIndexes = other.mStructElementIndexes;
108     return *this;
109 }
110 
next()111 TString Std140PaddingHelper::next()
112 {
113     unsigned value = (*mPaddingCounter)++;
114     return str(value);
115 }
116 
prePadding(const TType & type)117 int Std140PaddingHelper::prePadding(const TType &type)
118 {
119     if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
120     {
121         // no padding needed, HLSL will align the field to a new register
122         mElementIndex = 0;
123         return 0;
124     }
125 
126     const GLenum glType     = GLVariableType(type);
127     const int numComponents = gl::VariableComponentCount(glType);
128 
129     if (numComponents >= 4)
130     {
131         // no padding needed, HLSL will align the field to a new register
132         mElementIndex = 0;
133         return 0;
134     }
135 
136     if (mElementIndex + numComponents > 4)
137     {
138         // no padding needed, HLSL will align the field to a new register
139         mElementIndex = numComponents;
140         return 0;
141     }
142 
143     const int alignment     = numComponents == 3 ? 4 : numComponents;
144     const int paddingOffset = (mElementIndex % alignment);
145     const int paddingCount  = (paddingOffset != 0 ? (alignment - paddingOffset) : 0);
146 
147     mElementIndex += paddingCount;
148     mElementIndex += numComponents;
149     mElementIndex %= 4;
150 
151     return paddingCount;
152 }
153 
prePaddingString(const TType & type)154 TString Std140PaddingHelper::prePaddingString(const TType &type)
155 {
156     int paddingCount = prePadding(type);
157 
158     TString padding;
159 
160     for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++)
161     {
162         padding += "    float pad_" + next() + ";\n";
163     }
164 
165     return padding;
166 }
167 
postPaddingString(const TType & type,bool useHLSLRowMajorPacking)168 TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRowMajorPacking)
169 {
170     if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
171     {
172         return "";
173     }
174 
175     int numComponents           = 0;
176     const TStructure *structure = type.getStruct();
177 
178     if (type.isMatrix())
179     {
180         // This method can also be called from structureString, which does not use layout
181         // qualifiers.
182         // Thus, use the method parameter for determining the matrix packing.
183         //
184         // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we
185         // wish to always transpose GL matrices to play well with HLSL's matrix array indexing.
186         //
187         const bool isRowMajorMatrix = !useHLSLRowMajorPacking;
188         const GLenum glType         = GLVariableType(type);
189         numComponents               = gl::MatrixComponentCount(glType, isRowMajorMatrix);
190     }
191     else if (structure)
192     {
193         const TString &structName =
194             QualifiedStructNameString(*structure, useHLSLRowMajorPacking, true);
195         numComponents = mStructElementIndexes->find(structName)->second;
196 
197         if (numComponents == 0)
198         {
199             return "";
200         }
201     }
202     else
203     {
204         const GLenum glType = GLVariableType(type);
205         numComponents       = gl::VariableComponentCount(glType);
206     }
207 
208     TString padding;
209     for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++)
210     {
211         padding += "    float pad_" + next() + ";\n";
212     }
213     return padding;
214 }
215 
StructureHLSL()216 StructureHLSL::StructureHLSL() : mUniquePaddingCounter(0) {}
217 
getPaddingHelper()218 Std140PaddingHelper StructureHLSL::getPaddingHelper()
219 {
220     return Std140PaddingHelper(mStd140StructElementIndexes, &mUniquePaddingCounter);
221 }
222 
defineQualified(const TStructure & structure,bool useHLSLRowMajorPacking,bool useStd140Packing)223 TString StructureHLSL::defineQualified(const TStructure &structure,
224                                        bool useHLSLRowMajorPacking,
225                                        bool useStd140Packing)
226 {
227     if (useStd140Packing)
228     {
229         Std140PaddingHelper padHelper = getPaddingHelper();
230         return Define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper);
231     }
232     else
233     {
234         return Define(structure, useHLSLRowMajorPacking, useStd140Packing, nullptr);
235     }
236 }
237 
defineNameless(const TStructure & structure)238 TString StructureHLSL::defineNameless(const TStructure &structure)
239 {
240     return Define(structure, false, false, nullptr);
241 }
242 
defineVariants(const TStructure & structure,const TString & name)243 StructureHLSL::DefinedStructs::iterator StructureHLSL::defineVariants(const TStructure &structure,
244                                                                       const TString &name)
245 {
246     ASSERT(mDefinedStructs.find(name) == mDefinedStructs.end());
247 
248     for (const TField *field : structure.fields())
249     {
250         const TType *fieldType = field->type();
251         if (fieldType->getBasicType() == EbtStruct)
252         {
253             ensureStructDefined(*fieldType->getStruct());
254         }
255     }
256 
257     DefinedStructs::iterator addedStruct =
258         mDefinedStructs.insert(std::make_pair(name, new TStructProperties())).first;
259     // Add element index
260     storeStd140ElementIndex(structure, false);
261     storeStd140ElementIndex(structure, true);
262 
263     const TString &structString = defineQualified(structure, false, false);
264 
265     ASSERT(std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) ==
266            mStructDeclarations.end());
267     // Add row-major packed struct for interface blocks
268     TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
269                              defineQualified(structure, true, false) +
270                              "#pragma pack_matrix(column_major)\n";
271 
272     TString std140String         = defineQualified(structure, false, true);
273     TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
274                                    defineQualified(structure, true, true) +
275                                    "#pragma pack_matrix(column_major)\n";
276 
277     mStructDeclarations.push_back(structString);
278     mStructDeclarations.push_back(rowMajorString);
279     mStructDeclarations.push_back(std140String);
280     mStructDeclarations.push_back(std140RowMajorString);
281     return addedStruct;
282 }
283 
ensureStructDefined(const TStructure & structure)284 void StructureHLSL::ensureStructDefined(const TStructure &structure)
285 {
286     const TString name = StructNameString(structure);
287     if (name == "")
288     {
289         return;  // Nameless structures are not defined
290     }
291     if (mDefinedStructs.find(name) == mDefinedStructs.end())
292     {
293         defineVariants(structure, name);
294     }
295 }
296 
addStructConstructor(const TStructure & structure)297 TString StructureHLSL::addStructConstructor(const TStructure &structure)
298 {
299     const TString name = StructNameString(structure);
300 
301     if (name == "")
302     {
303         return TString();  // Nameless structures don't have constructors
304     }
305 
306     auto definedStruct = mDefinedStructs.find(name);
307     if (definedStruct == mDefinedStructs.end())
308     {
309         definedStruct = defineVariants(structure, name);
310     }
311     const TString constructorFunctionName = TString(name) + "_ctor";
312     TString *constructor                  = &definedStruct->second->constructor;
313     if (!constructor->empty())
314     {
315         return constructorFunctionName;  // Already added
316     }
317     *constructor += name + " " + constructorFunctionName + "(";
318 
319     std::vector<TType> ctorParameters;
320     const TFieldList &fields = structure.fields();
321     for (const TField *field : fields)
322     {
323         const TType *fieldType = field->type();
324         if (!IsSampler(fieldType->getBasicType()))
325         {
326             ctorParameters.push_back(*fieldType);
327         }
328     }
329     // Structs that have sampler members should not have constructor calls, and otherwise structs
330     // are guaranteed to be non-empty by the grammar. Structs can't contain empty declarations
331     // either.
332     ASSERT(!ctorParameters.empty());
333 
334     *constructor += WriteParameterList(ctorParameters);
335 
336     *constructor +=
337         ")\n"
338         "{\n"
339         "    " +
340         name + " structure = { ";
341 
342     for (size_t parameterIndex = 0u; parameterIndex < ctorParameters.size(); ++parameterIndex)
343     {
344         *constructor += "x" + str(parameterIndex);
345         if (parameterIndex < ctorParameters.size() - 1u)
346         {
347             *constructor += ", ";
348         }
349     }
350     *constructor +=
351         "};\n"
352         "    return structure;\n"
353         "}\n";
354 
355     return constructorFunctionName;
356 }
357 
addBuiltInConstructor(const TType & type,const TIntermSequence * parameters)358 TString StructureHLSL::addBuiltInConstructor(const TType &type, const TIntermSequence *parameters)
359 {
360     ASSERT(!type.isArray());
361     ASSERT(type.getStruct() == nullptr);
362     ASSERT(parameters);
363 
364     TType ctorType = type;
365     ctorType.setPrecision(EbpHigh);
366     ctorType.setQualifier(EvqTemporary);
367 
368     const TString constructorFunctionName =
369         TString(type.getBuiltInTypeNameString()) + "_ctor" + DisambiguateFunctionName(parameters);
370     TString constructor = TypeString(ctorType) + " " + constructorFunctionName + "(";
371 
372     std::vector<TType> ctorParameters;
373     for (auto parameter : *parameters)
374     {
375         const TType &paramType = parameter->getAsTyped()->getType();
376         ASSERT(!paramType.isArray());
377         ctorParameters.push_back(paramType);
378     }
379     constructor += WriteParameterList(ctorParameters);
380 
381     constructor +=
382         ")\n"
383         "{\n"
384         "    return " +
385         TypeString(ctorType) + "(";
386 
387     if (ctorType.isMatrix() && ctorParameters.size() == 1)
388     {
389         int rows               = ctorType.getRows();
390         int cols               = ctorType.getCols();
391         const TType &parameter = ctorParameters[0];
392 
393         if (parameter.isScalar())
394         {
395             for (int col = 0; col < cols; col++)
396             {
397                 for (int row = 0; row < rows; row++)
398                 {
399                     constructor += TString((row == col) ? "x0" : "0.0");
400 
401                     if (row < rows - 1 || col < cols - 1)
402                     {
403                         constructor += ", ";
404                     }
405                 }
406             }
407         }
408         else if (parameter.isMatrix())
409         {
410             for (int col = 0; col < cols; col++)
411             {
412                 for (int row = 0; row < rows; row++)
413                 {
414                     if (row < parameter.getRows() && col < parameter.getCols())
415                     {
416                         constructor += TString("x0") + "[" + str(col) + "][" + str(row) + "]";
417                     }
418                     else
419                     {
420                         constructor += TString((row == col) ? "1.0" : "0.0");
421                     }
422 
423                     if (row < rows - 1 || col < cols - 1)
424                     {
425                         constructor += ", ";
426                     }
427                 }
428             }
429         }
430         else
431         {
432             ASSERT(rows == 2 && cols == 2 && parameter.isVector() &&
433                    parameter.getNominalSize() == 4);
434 
435             constructor += "x0";
436         }
437     }
438     else
439     {
440         size_t remainingComponents = ctorType.getObjectSize();
441         size_t parameterIndex      = 0;
442 
443         while (remainingComponents > 0)
444         {
445             const TType &parameter     = ctorParameters[parameterIndex];
446             const size_t parameterSize = parameter.getObjectSize();
447             bool moreParameters        = parameterIndex + 1 < ctorParameters.size();
448 
449             constructor += "x" + str(parameterIndex);
450 
451             if (parameter.isScalar())
452             {
453                 remainingComponents -= parameter.getObjectSize();
454             }
455             else if (parameter.isVector())
456             {
457                 if (remainingComponents == parameterSize || moreParameters)
458                 {
459                     ASSERT(parameterSize <= remainingComponents);
460                     remainingComponents -= parameterSize;
461                 }
462                 else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
463                 {
464                     switch (remainingComponents)
465                     {
466                         case 1:
467                             constructor += ".x";
468                             break;
469                         case 2:
470                             constructor += ".xy";
471                             break;
472                         case 3:
473                             constructor += ".xyz";
474                             break;
475                         case 4:
476                             constructor += ".xyzw";
477                             break;
478                         default:
479                             UNREACHABLE();
480                     }
481 
482                     remainingComponents = 0;
483                 }
484                 else
485                     UNREACHABLE();
486             }
487             else if (parameter.isMatrix())
488             {
489                 int column = 0;
490                 while (remainingComponents > 0 && column < parameter.getCols())
491                 {
492                     constructor += "[" + str(column) + "]";
493 
494                     if (remainingComponents < static_cast<size_t>(parameter.getRows()))
495                     {
496                         switch (remainingComponents)
497                         {
498                             case 1:
499                                 constructor += ".x";
500                                 break;
501                             case 2:
502                                 constructor += ".xy";
503                                 break;
504                             case 3:
505                                 constructor += ".xyz";
506                                 break;
507                             default:
508                                 UNREACHABLE();
509                         }
510 
511                         remainingComponents = 0;
512                     }
513                     else
514                     {
515                         remainingComponents -= parameter.getRows();
516 
517                         if (remainingComponents > 0)
518                         {
519                             constructor += ", x" + str(parameterIndex);
520                         }
521                     }
522 
523                     column++;
524                 }
525             }
526             else
527             {
528                 UNREACHABLE();
529             }
530 
531             if (moreParameters)
532             {
533                 parameterIndex++;
534             }
535 
536             if (remainingComponents)
537             {
538                 constructor += ", ";
539             }
540         }
541     }
542 
543     constructor +=
544         ");\n"
545         "}\n";
546 
547     mBuiltInConstructors.insert(constructor);
548 
549     return constructorFunctionName;
550 }
551 
structsHeader() const552 std::string StructureHLSL::structsHeader() const
553 {
554     TInfoSinkBase out;
555 
556     for (auto &declaration : mStructDeclarations)
557     {
558         out << declaration;
559     }
560 
561     for (auto &structure : mDefinedStructs)
562     {
563         out << structure.second->constructor;
564     }
565 
566     for (auto &constructor : mBuiltInConstructors)
567     {
568         out << constructor;
569     }
570 
571     return out.str();
572 }
573 
storeStd140ElementIndex(const TStructure & structure,bool useHLSLRowMajorPacking)574 void StructureHLSL::storeStd140ElementIndex(const TStructure &structure,
575                                             bool useHLSLRowMajorPacking)
576 {
577     Std140PaddingHelper padHelper = getPaddingHelper();
578     const TFieldList &fields      = structure.fields();
579 
580     for (const TField *field : fields)
581     {
582         padHelper.prePadding(*field->type());
583     }
584 
585     // Add remaining element index to the global map, for use with nested structs in standard
586     // layouts
587     const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, true);
588     mStd140StructElementIndexes[structName] = padHelper.elementIndex();
589 }
590 
591 }  // namespace sh
592