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