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 // Definitions of methods for HLSL translation of GLSL structures.
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"
20 Std140PaddingHelper::Std140PaddingHelper(const std::map<TString, int> &structElementIndexes,
21 unsigned *uniqueCounter)
22 : mPaddingCounter(uniqueCounter),
24 mStructElementIndexes(structElementIndexes)
27 TString Std140PaddingHelper::next()
29 unsigned value = (*mPaddingCounter)++;
33 int Std140PaddingHelper::prePadding(const TType &type)
35 if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
37 // no padding needed, HLSL will align the field to a new register
42 const GLenum glType = GLVariableType(type);
43 const int numComponents = gl::VariableComponentCount(glType);
45 if (numComponents >= 4)
47 // no padding needed, HLSL will align the field to a new register
52 if (mElementIndex + numComponents > 4)
54 // no padding needed, HLSL will align the field to a new register
55 mElementIndex = numComponents;
59 const int alignment = numComponents == 3 ? 4 : numComponents;
60 const int paddingOffset = (mElementIndex % alignment);
61 const int paddingCount = (paddingOffset != 0 ? (alignment - paddingOffset) : 0);
63 mElementIndex += paddingCount;
64 mElementIndex += numComponents;
70 TString Std140PaddingHelper::prePaddingString(const TType &type)
72 int paddingCount = prePadding(type);
76 for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++)
78 padding += " float pad_" + next() + ";\n";
84 TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRowMajorPacking)
86 if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
91 int numComponents = 0;
92 TStructure *structure = type.getStruct();
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.
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.
102 const bool isRowMajorMatrix = !useHLSLRowMajorPacking;
103 const GLenum glType = GLVariableType(type);
104 numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix);
108 const TString &structName = QualifiedStructNameString(*structure,
109 useHLSLRowMajorPacking, true);
110 numComponents = mStructElementIndexes.find(structName)->second;
112 if (numComponents == 0)
119 const GLenum glType = GLVariableType(type);
120 numComponents = gl::VariableComponentCount(glType);
124 for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++)
126 padding += " float pad_" + next() + ";\n";
131 StructureHLSL::StructureHLSL()
132 : mUniquePaddingCounter(0)
135 Std140PaddingHelper StructureHLSL::getPaddingHelper()
137 return Std140PaddingHelper(mStd140StructElementIndexes, &mUniquePaddingCounter);
140 TString StructureHLSL::defineQualified(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing)
142 if (useStd140Packing)
144 Std140PaddingHelper padHelper = getPaddingHelper();
145 return define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper);
149 return define(structure, useHLSLRowMajorPacking, useStd140Packing, NULL);
153 TString StructureHLSL::defineNameless(const TStructure &structure)
155 return define(structure, false, false, NULL);
158 TString StructureHLSL::define(const TStructure &structure, bool useHLSLRowMajorPacking,
159 bool useStd140Packing, Std140PaddingHelper *padHelper)
161 const TFieldList &fields = structure.fields();
162 const bool isNameless = (structure.name() == "");
163 const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking,
165 const TString declareString = (isNameless ? "struct" : "struct " + structName);
168 string += declareString + "\n"
171 for (unsigned int i = 0; i < fields.size(); i++)
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,
179 TypeString(fieldType);
183 string += padHelper->prePaddingString(fieldType);
186 string += " " + fieldTypeString + " " + DecorateField(field.name(), structure) + ArrayString(fieldType) + ";\n";
190 string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
194 // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable
195 string += (isNameless ? "} " : "};\n");
200 void StructureHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
204 return; // Nameless structures don't have constructors
207 if (type.getStruct() && mStructNames.find(name) != mStructNames.end())
209 return; // Already added
212 TType ctorType = type;
213 ctorType.clearArrayness();
214 ctorType.setPrecision(EbpHigh);
215 ctorType.setQualifier(EvqTemporary);
217 typedef std::vector<TType> ParameterArray;
218 ParameterArray ctorParameters;
220 const TStructure* structure = type.getStruct();
223 mStructNames.insert(name);
226 storeStd140ElementIndex(*structure, false);
227 storeStd140ElementIndex(*structure, true);
229 const TString &structString = defineQualified(*structure, false, false);
231 if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == mStructDeclarations.end())
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";
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";
243 mStructDeclarations.push_back(structString);
244 mStructDeclarations.push_back(rowMajorString);
245 mStructDeclarations.push_back(std140String);
246 mStructDeclarations.push_back(std140RowMajorString);
249 const TFieldList &fields = structure->fields();
250 for (unsigned int i = 0; i < fields.size(); i++)
252 ctorParameters.push_back(*fields[i]->type());
257 for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
259 ctorParameters.push_back((*parameter)->getAsTyped()->getType());
266 if (ctorType.getStruct())
268 constructor += name + " " + name + "_ctor(";
270 else // Built-in type
272 constructor += TypeString(ctorType) + " " + name + "(";
275 for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
277 const TType &type = ctorParameters[parameter];
279 constructor += TypeString(type) + " x" + str(parameter) + ArrayString(type);
281 if (parameter < ctorParameters.size() - 1)
290 if (ctorType.getStruct())
292 constructor += " " + name + " structure = {";
296 constructor += " return " + TypeString(ctorType) + "(";
299 if (ctorType.isMatrix() && ctorParameters.size() == 1)
301 int rows = ctorType.getRows();
302 int cols = ctorType.getCols();
303 const TType ¶meter = ctorParameters[0];
305 if (parameter.isScalar())
307 for (int col = 0; col < cols; col++)
309 for (int row = 0; row < rows; row++)
311 constructor += TString((row == col) ? "x0" : "0.0");
313 if (row < rows - 1 || col < cols - 1)
320 else if (parameter.isMatrix())
322 for (int col = 0; col < cols; col++)
324 for (int row = 0; row < rows; row++)
326 if (row < parameter.getRows() && col < parameter.getCols())
328 constructor += TString("x0") + "[" + str(col) + "][" + str(row) + "]";
332 constructor += TString((row == col) ? "1.0" : "0.0");
335 if (row < rows - 1 || col < cols - 1)
344 ASSERT(rows == 2 && cols == 2 && parameter.isVector() && parameter.getNominalSize() == 4);
351 size_t remainingComponents = ctorType.getObjectSize();
352 size_t parameterIndex = 0;
354 while (remainingComponents > 0)
356 const TType ¶meter = ctorParameters[parameterIndex];
357 const size_t parameterSize = parameter.getObjectSize();
358 bool moreParameters = parameterIndex + 1 < ctorParameters.size();
360 constructor += "x" + str(parameterIndex);
362 if (ctorType.getStruct())
364 ASSERT(remainingComponents == parameterSize || moreParameters);
365 ASSERT(parameterSize <= remainingComponents);
367 remainingComponents -= parameterSize;
369 else if (parameter.isScalar())
371 remainingComponents -= parameter.getObjectSize();
373 else if (parameter.isVector())
375 if (remainingComponents == parameterSize || moreParameters)
377 ASSERT(parameterSize <= remainingComponents);
378 remainingComponents -= parameterSize;
380 else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
382 switch (remainingComponents)
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();
391 remainingComponents = 0;
395 else if (parameter.isMatrix())
398 while (remainingComponents > 0 && column < parameter.getCols())
400 constructor += "[" + str(column) + "]";
402 if (remainingComponents < static_cast<size_t>(parameter.getRows()))
404 switch (remainingComponents)
406 case 1: constructor += ".x"; break;
407 case 2: constructor += ".xy"; break;
408 case 3: constructor += ".xyz"; break;
409 default: UNREACHABLE();
412 remainingComponents = 0;
416 remainingComponents -= parameter.getRows();
418 if (remainingComponents > 0)
420 constructor += ", x" + str(parameterIndex);
434 if (remainingComponents)
441 if (ctorType.getStruct())
443 constructor += "};\n"
444 " return structure;\n"
449 constructor += ");\n"
453 mConstructors.insert(constructor);
456 std::string StructureHLSL::structsHeader() const
460 for (size_t structIndex = 0; structIndex < mStructDeclarations.size(); structIndex++)
462 out << mStructDeclarations[structIndex];
465 for (Constructors::const_iterator constructor = mConstructors.begin();
466 constructor != mConstructors.end();
475 void StructureHLSL::storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking)
477 Std140PaddingHelper padHelper = getPaddingHelper();
478 const TFieldList &fields = structure.fields();
480 for (unsigned int i = 0; i < fields.size(); i++)
482 padHelper.prePadding(*fields[i]->type());
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();