blob: 93e0ba57371074c581be4db9164a99368c1aafbf [file] [log] [blame]
Jamie Madill8daaba12014-06-13 10:04:33 -04001//
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
17namespace sh
18{
19
Jamie Madill33a74bd2014-08-18 15:47:59 -040020Std140PaddingHelper::Std140PaddingHelper(const std::map<TString, int> &structElementIndexes,
21 unsigned *uniqueCounter)
22 : mPaddingCounter(uniqueCounter),
Jamie Madill8daaba12014-06-13 10:04:33 -040023 mElementIndex(0),
Jamie Madill80d934b2015-02-19 10:16:12 -050024 mStructElementIndexes(&structElementIndexes)
Jamie Madill8daaba12014-06-13 10:04:33 -040025{}
26
Jamie Madill80d934b2015-02-19 10:16:12 -050027Std140PaddingHelper::Std140PaddingHelper(const Std140PaddingHelper &other)
28 : mPaddingCounter(other.mPaddingCounter),
29 mElementIndex(other.mElementIndex),
30 mStructElementIndexes(other.mStructElementIndexes)
31{}
32
33Std140PaddingHelper &Std140PaddingHelper::operator=(const Std140PaddingHelper &other)
34{
35 mPaddingCounter = other.mPaddingCounter;
36 mElementIndex = other.mElementIndex;
37 mStructElementIndexes = other.mStructElementIndexes;
38 return *this;
39}
40
Jamie Madill33a74bd2014-08-18 15:47:59 -040041TString Std140PaddingHelper::next()
42{
43 unsigned value = (*mPaddingCounter)++;
44 return str(value);
45}
46
Jamie Madill8daaba12014-06-13 10:04:33 -040047int Std140PaddingHelper::prePadding(const TType &type)
48{
49 if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
50 {
51 // no padding needed, HLSL will align the field to a new register
52 mElementIndex = 0;
53 return 0;
54 }
55
56 const GLenum glType = GLVariableType(type);
Jamie Madillf2575982014-06-25 16:04:54 -040057 const int numComponents = gl::VariableComponentCount(glType);
Jamie Madill8daaba12014-06-13 10:04:33 -040058
59 if (numComponents >= 4)
60 {
61 // no padding needed, HLSL will align the field to a new register
62 mElementIndex = 0;
63 return 0;
64 }
65
66 if (mElementIndex + numComponents > 4)
67 {
68 // no padding needed, HLSL will align the field to a new register
69 mElementIndex = numComponents;
70 return 0;
71 }
72
73 const int alignment = numComponents == 3 ? 4 : numComponents;
74 const int paddingOffset = (mElementIndex % alignment);
75 const int paddingCount = (paddingOffset != 0 ? (alignment - paddingOffset) : 0);
76
77 mElementIndex += paddingCount;
78 mElementIndex += numComponents;
79 mElementIndex %= 4;
80
81 return paddingCount;
82}
83
84TString Std140PaddingHelper::prePaddingString(const TType &type)
85{
86 int paddingCount = prePadding(type);
87
88 TString padding;
89
90 for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++)
91 {
Jamie Madill33a74bd2014-08-18 15:47:59 -040092 padding += " float pad_" + next() + ";\n";
Jamie Madill8daaba12014-06-13 10:04:33 -040093 }
94
95 return padding;
96}
97
98TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRowMajorPacking)
99{
100 if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
101 {
102 return "";
103 }
104
105 int numComponents = 0;
106 TStructure *structure = type.getStruct();
107
108 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 const bool isRowMajorMatrix = !useHLSLRowMajorPacking;
117 const GLenum glType = GLVariableType(type);
118 numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix);
119 }
120 else if (structure)
121 {
122 const TString &structName = QualifiedStructNameString(*structure,
123 useHLSLRowMajorPacking, true);
Jamie Madill80d934b2015-02-19 10:16:12 -0500124 numComponents = mStructElementIndexes->find(structName)->second;
Jamie Madill8daaba12014-06-13 10:04:33 -0400125
126 if (numComponents == 0)
127 {
128 return "";
129 }
130 }
131 else
132 {
133 const GLenum glType = GLVariableType(type);
Jamie Madillf2575982014-06-25 16:04:54 -0400134 numComponents = gl::VariableComponentCount(glType);
Jamie Madill8daaba12014-06-13 10:04:33 -0400135 }
136
137 TString padding;
138 for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++)
139 {
Jamie Madill33a74bd2014-08-18 15:47:59 -0400140 padding += " float pad_" + next() + ";\n";
Jamie Madill8daaba12014-06-13 10:04:33 -0400141 }
142 return padding;
143}
144
145StructureHLSL::StructureHLSL()
Jamie Madill33a74bd2014-08-18 15:47:59 -0400146 : mUniquePaddingCounter(0)
Jamie Madill8daaba12014-06-13 10:04:33 -0400147{}
148
Jamie Madill33a74bd2014-08-18 15:47:59 -0400149Std140PaddingHelper StructureHLSL::getPaddingHelper()
150{
151 return Std140PaddingHelper(mStd140StructElementIndexes, &mUniquePaddingCounter);
152}
153
Jamie Madill8daaba12014-06-13 10:04:33 -0400154TString StructureHLSL::defineQualified(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing)
155{
156 if (useStd140Packing)
157 {
Jamie Madill33a74bd2014-08-18 15:47:59 -0400158 Std140PaddingHelper padHelper = getPaddingHelper();
Jamie Madill8daaba12014-06-13 10:04:33 -0400159 return define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper);
160 }
161 else
162 {
163 return define(structure, useHLSLRowMajorPacking, useStd140Packing, NULL);
164 }
165}
166
167TString StructureHLSL::defineNameless(const TStructure &structure)
168{
169 return define(structure, false, false, NULL);
170}
171
172TString StructureHLSL::define(const TStructure &structure, bool useHLSLRowMajorPacking,
173 bool useStd140Packing, Std140PaddingHelper *padHelper)
174{
175 const TFieldList &fields = structure.fields();
176 const bool isNameless = (structure.name() == "");
177 const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking,
178 useStd140Packing);
179 const TString declareString = (isNameless ? "struct" : "struct " + structName);
180
181 TString string;
182 string += declareString + "\n"
183 "{\n";
184
Olli Etuaho96963162016-03-21 11:54:33 +0200185 for (const TField *field : fields)
Jamie Madill8daaba12014-06-13 10:04:33 -0400186 {
Olli Etuaho96963162016-03-21 11:54:33 +0200187 const TType &fieldType = *field->type();
188 if (!IsSampler(fieldType.getBasicType()))
Jamie Madill8daaba12014-06-13 10:04:33 -0400189 {
Olli Etuaho96963162016-03-21 11:54:33 +0200190 const TStructure *fieldStruct = fieldType.getStruct();
191 const TString &fieldTypeString =
192 fieldStruct ? QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
193 useStd140Packing)
194 : TypeString(fieldType);
Jamie Madill8daaba12014-06-13 10:04:33 -0400195
Olli Etuaho96963162016-03-21 11:54:33 +0200196 if (padHelper)
197 {
198 string += padHelper->prePaddingString(fieldType);
199 }
Jamie Madill8daaba12014-06-13 10:04:33 -0400200
Olli Etuaho96963162016-03-21 11:54:33 +0200201 string += " " + fieldTypeString + " " + DecorateField(field->name(), structure) +
202 ArrayString(fieldType) + ";\n";
203
204 if (padHelper)
205 {
206 string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
207 }
Jamie Madill8daaba12014-06-13 10:04:33 -0400208 }
209 }
210
211 // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable
212 string += (isNameless ? "} " : "};\n");
213
214 return string;
215}
216
Olli Etuahobe59c2f2016-03-07 11:32:34 +0200217TString StructureHLSL::addConstructor(const TType &type,
218 const TString &name,
219 const TIntermSequence *parameters)
Jamie Madill8daaba12014-06-13 10:04:33 -0400220{
221 if (name == "")
222 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +0200223 return TString(); // Nameless structures don't have constructors
Jamie Madill8daaba12014-06-13 10:04:33 -0400224 }
225
226 if (type.getStruct() && mStructNames.find(name) != mStructNames.end())
227 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +0200228 return TString(name); // Already added
Jamie Madill8daaba12014-06-13 10:04:33 -0400229 }
230
231 TType ctorType = type;
232 ctorType.clearArrayness();
233 ctorType.setPrecision(EbpHigh);
234 ctorType.setQualifier(EvqTemporary);
235
236 typedef std::vector<TType> ParameterArray;
237 ParameterArray ctorParameters;
238
Olli Etuahobe59c2f2016-03-07 11:32:34 +0200239 TString constructorFunctionName;
240
Jamie Madill8daaba12014-06-13 10:04:33 -0400241 const TStructure* structure = type.getStruct();
242 if (structure)
243 {
244 mStructNames.insert(name);
245
246 // Add element index
247 storeStd140ElementIndex(*structure, false);
248 storeStd140ElementIndex(*structure, true);
249
250 const TString &structString = defineQualified(*structure, false, false);
251
252 if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == mStructDeclarations.end())
253 {
254 // Add row-major packed struct for interface blocks
255 TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
256 defineQualified(*structure, true, false) +
257 "#pragma pack_matrix(column_major)\n";
258
259 TString std140String = defineQualified(*structure, false, true);
260 TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
261 defineQualified(*structure, true, true) +
262 "#pragma pack_matrix(column_major)\n";
263
264 mStructDeclarations.push_back(structString);
265 mStructDeclarations.push_back(rowMajorString);
266 mStructDeclarations.push_back(std140String);
267 mStructDeclarations.push_back(std140RowMajorString);
268 }
269
270 const TFieldList &fields = structure->fields();
Olli Etuaho96963162016-03-21 11:54:33 +0200271 for (const TField *field : fields)
Jamie Madill8daaba12014-06-13 10:04:33 -0400272 {
Olli Etuaho96963162016-03-21 11:54:33 +0200273 const TType *fieldType = field->type();
274 if (!IsSampler(fieldType->getBasicType()))
275 {
276 ctorParameters.push_back(*fieldType);
277 }
Jamie Madill8daaba12014-06-13 10:04:33 -0400278 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +0200279 constructorFunctionName = TString(name);
Jamie Madill8daaba12014-06-13 10:04:33 -0400280 }
281 else if (parameters)
282 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +0200283 for (auto parameter : *parameters)
Jamie Madill8daaba12014-06-13 10:04:33 -0400284 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +0200285 const TType &paramType = parameter->getAsTyped()->getType();
286 ctorParameters.push_back(paramType);
Jamie Madill8daaba12014-06-13 10:04:33 -0400287 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +0200288 constructorFunctionName = TString(name) + DisambiguateFunctionName(parameters);
Jamie Madill8daaba12014-06-13 10:04:33 -0400289 }
290 else UNREACHABLE();
291
292 TString constructor;
293
294 if (ctorType.getStruct())
295 {
296 constructor += name + " " + name + "_ctor(";
297 }
298 else // Built-in type
299 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +0200300 constructor += TypeString(ctorType) + " " + constructorFunctionName + "(";
Jamie Madill8daaba12014-06-13 10:04:33 -0400301 }
302
303 for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
304 {
Austin Kinross3ae64652015-01-26 15:51:39 -0800305 const TType &paramType = ctorParameters[parameter];
Jamie Madill8daaba12014-06-13 10:04:33 -0400306
Austin Kinross3ae64652015-01-26 15:51:39 -0800307 constructor += TypeString(paramType) + " x" + str(parameter) + ArrayString(paramType);
Jamie Madill8daaba12014-06-13 10:04:33 -0400308
309 if (parameter < ctorParameters.size() - 1)
310 {
311 constructor += ", ";
312 }
313 }
314
315 constructor += ")\n"
316 "{\n";
317
318 if (ctorType.getStruct())
319 {
Olli Etuaho96963162016-03-21 11:54:33 +0200320 constructor += " " + name + " structure";
321 if (ctorParameters.empty())
322 {
323 constructor += ";\n";
324 }
325 else
326 {
327 constructor += " = { ";
328 }
Jamie Madill8daaba12014-06-13 10:04:33 -0400329 }
330 else
331 {
332 constructor += " return " + TypeString(ctorType) + "(";
333 }
334
335 if (ctorType.isMatrix() && ctorParameters.size() == 1)
336 {
337 int rows = ctorType.getRows();
338 int cols = ctorType.getCols();
339 const TType &parameter = ctorParameters[0];
340
341 if (parameter.isScalar())
342 {
Jamie Madillcf3af0b2014-08-01 17:22:16 -0400343 for (int col = 0; col < cols; col++)
Jamie Madill8daaba12014-06-13 10:04:33 -0400344 {
Jamie Madillcf3af0b2014-08-01 17:22:16 -0400345 for (int row = 0; row < rows; row++)
Jamie Madill8daaba12014-06-13 10:04:33 -0400346 {
347 constructor += TString((row == col) ? "x0" : "0.0");
348
349 if (row < rows - 1 || col < cols - 1)
350 {
351 constructor += ", ";
352 }
353 }
354 }
355 }
356 else if (parameter.isMatrix())
357 {
Jamie Madillf4e39bf2014-08-01 17:22:17 -0400358 for (int col = 0; col < cols; col++)
Jamie Madill8daaba12014-06-13 10:04:33 -0400359 {
Jamie Madillf4e39bf2014-08-01 17:22:17 -0400360 for (int row = 0; row < rows; row++)
Jamie Madill8daaba12014-06-13 10:04:33 -0400361 {
362 if (row < parameter.getRows() && col < parameter.getCols())
363 {
Jamie Madillf4e39bf2014-08-01 17:22:17 -0400364 constructor += TString("x0") + "[" + str(col) + "][" + str(row) + "]";
Jamie Madill8daaba12014-06-13 10:04:33 -0400365 }
366 else
367 {
368 constructor += TString((row == col) ? "1.0" : "0.0");
369 }
370
371 if (row < rows - 1 || col < cols - 1)
372 {
373 constructor += ", ";
374 }
375 }
376 }
377 }
378 else
379 {
380 ASSERT(rows == 2 && cols == 2 && parameter.isVector() && parameter.getNominalSize() == 4);
381
382 constructor += "x0";
383 }
384 }
385 else
386 {
Olli Etuaho96963162016-03-21 11:54:33 +0200387 size_t remainingComponents = 0;
388 if (ctorType.getStruct())
389 {
390 remainingComponents = ctorParameters.size();
391 }
392 else
393 {
394 remainingComponents = ctorType.getObjectSize();
395 }
Jamie Madill8daaba12014-06-13 10:04:33 -0400396 size_t parameterIndex = 0;
397
398 while (remainingComponents > 0)
399 {
400 const TType &parameter = ctorParameters[parameterIndex];
401 const size_t parameterSize = parameter.getObjectSize();
402 bool moreParameters = parameterIndex + 1 < ctorParameters.size();
403
404 constructor += "x" + str(parameterIndex);
405
406 if (ctorType.getStruct())
407 {
Olli Etuaho96963162016-03-21 11:54:33 +0200408 ASSERT(remainingComponents == 1 || moreParameters);
Jamie Madill8daaba12014-06-13 10:04:33 -0400409
Olli Etuaho96963162016-03-21 11:54:33 +0200410 --remainingComponents;
Jamie Madill8daaba12014-06-13 10:04:33 -0400411 }
412 else if (parameter.isScalar())
413 {
414 remainingComponents -= parameter.getObjectSize();
415 }
416 else if (parameter.isVector())
417 {
418 if (remainingComponents == parameterSize || moreParameters)
419 {
420 ASSERT(parameterSize <= remainingComponents);
421 remainingComponents -= parameterSize;
422 }
423 else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
424 {
425 switch (remainingComponents)
426 {
427 case 1: constructor += ".x"; break;
428 case 2: constructor += ".xy"; break;
429 case 3: constructor += ".xyz"; break;
430 case 4: constructor += ".xyzw"; break;
431 default: UNREACHABLE();
432 }
433
434 remainingComponents = 0;
435 }
436 else UNREACHABLE();
437 }
438 else if (parameter.isMatrix())
439 {
440 int column = 0;
441 while (remainingComponents > 0 && column < parameter.getCols())
442 {
443 constructor += "[" + str(column) + "]";
444
445 if (remainingComponents < static_cast<size_t>(parameter.getRows()))
446 {
447 switch (remainingComponents)
448 {
449 case 1: constructor += ".x"; break;
450 case 2: constructor += ".xy"; break;
451 case 3: constructor += ".xyz"; break;
452 default: UNREACHABLE();
453 }
454
455 remainingComponents = 0;
456 }
457 else
458 {
459 remainingComponents -= parameter.getRows();
460
461 if (remainingComponents > 0)
462 {
463 constructor += ", x" + str(parameterIndex);
464 }
465 }
466
467 column++;
468 }
469 }
470 else UNREACHABLE();
471
472 if (moreParameters)
473 {
474 parameterIndex++;
475 }
476
477 if (remainingComponents)
478 {
479 constructor += ", ";
480 }
481 }
482 }
483
484 if (ctorType.getStruct())
485 {
Olli Etuaho96963162016-03-21 11:54:33 +0200486 if (!ctorParameters.empty())
487 {
488 constructor += "};\n";
489 }
490 constructor +=
491 " return structure;\n"
492 "}\n";
Jamie Madill8daaba12014-06-13 10:04:33 -0400493 }
494 else
495 {
496 constructor += ");\n"
497 "}\n";
498 }
499
500 mConstructors.insert(constructor);
Olli Etuahobe59c2f2016-03-07 11:32:34 +0200501
502 return constructorFunctionName;
Jamie Madill8daaba12014-06-13 10:04:33 -0400503}
504
505std::string StructureHLSL::structsHeader() const
506{
507 TInfoSinkBase out;
508
509 for (size_t structIndex = 0; structIndex < mStructDeclarations.size(); structIndex++)
510 {
511 out << mStructDeclarations[structIndex];
512 }
513
Jamie Madill961d5e92014-06-20 15:23:34 -0400514 for (Constructors::const_iterator constructor = mConstructors.begin();
515 constructor != mConstructors.end();
516 constructor++)
Jamie Madill8daaba12014-06-13 10:04:33 -0400517 {
518 out << *constructor;
519 }
520
521 return out.str();
522}
523
524void StructureHLSL::storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking)
525{
Jamie Madill33a74bd2014-08-18 15:47:59 -0400526 Std140PaddingHelper padHelper = getPaddingHelper();
Jamie Madill8daaba12014-06-13 10:04:33 -0400527 const TFieldList &fields = structure.fields();
528
529 for (unsigned int i = 0; i < fields.size(); i++)
530 {
531 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 const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, true);
536 mStd140StructElementIndexes[structName] = padHelper.elementIndex();
537}
538
Jamie Madill9e5317f2014-06-20 14:56:37 -0400539}