blob: fd1a29c1cdf8e3e7d8902d34346343b0b6395155 [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
185 for (unsigned int i = 0; i < fields.size(); i++)
186 {
187 const TField &field = *fields[i];
188 const TType &fieldType = *field.type();
189 const TStructure *fieldStruct = fieldType.getStruct();
190 const TString &fieldTypeString = fieldStruct ?
191 QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
192 useStd140Packing) :
193 TypeString(fieldType);
194
195 if (padHelper)
196 {
197 string += padHelper->prePaddingString(fieldType);
198 }
199
200 string += " " + fieldTypeString + " " + DecorateField(field.name(), structure) + ArrayString(fieldType) + ";\n";
201
202 if (padHelper)
203 {
204 string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
205 }
206 }
207
208 // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable
209 string += (isNameless ? "} " : "};\n");
210
211 return string;
212}
213
214void StructureHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
215{
216 if (name == "")
217 {
218 return; // Nameless structures don't have constructors
219 }
220
221 if (type.getStruct() && mStructNames.find(name) != mStructNames.end())
222 {
223 return; // Already added
224 }
225
226 TType ctorType = type;
227 ctorType.clearArrayness();
228 ctorType.setPrecision(EbpHigh);
229 ctorType.setQualifier(EvqTemporary);
230
231 typedef std::vector<TType> ParameterArray;
232 ParameterArray ctorParameters;
233
234 const TStructure* structure = type.getStruct();
235 if (structure)
236 {
237 mStructNames.insert(name);
238
239 // Add element index
240 storeStd140ElementIndex(*structure, false);
241 storeStd140ElementIndex(*structure, true);
242
243 const TString &structString = defineQualified(*structure, false, false);
244
245 if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == mStructDeclarations.end())
246 {
247 // Add row-major packed struct for interface blocks
248 TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
249 defineQualified(*structure, true, false) +
250 "#pragma pack_matrix(column_major)\n";
251
252 TString std140String = defineQualified(*structure, false, true);
253 TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
254 defineQualified(*structure, true, true) +
255 "#pragma pack_matrix(column_major)\n";
256
257 mStructDeclarations.push_back(structString);
258 mStructDeclarations.push_back(rowMajorString);
259 mStructDeclarations.push_back(std140String);
260 mStructDeclarations.push_back(std140RowMajorString);
261 }
262
263 const TFieldList &fields = structure->fields();
264 for (unsigned int i = 0; i < fields.size(); i++)
265 {
266 ctorParameters.push_back(*fields[i]->type());
267 }
268 }
269 else if (parameters)
270 {
271 for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
272 {
273 ctorParameters.push_back((*parameter)->getAsTyped()->getType());
274 }
275 }
276 else UNREACHABLE();
277
278 TString constructor;
279
280 if (ctorType.getStruct())
281 {
282 constructor += name + " " + name + "_ctor(";
283 }
284 else // Built-in type
285 {
286 constructor += TypeString(ctorType) + " " + name + "(";
287 }
288
289 for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
290 {
Austin Kinross3ae64652015-01-26 15:51:39 -0800291 const TType &paramType = ctorParameters[parameter];
Jamie Madill8daaba12014-06-13 10:04:33 -0400292
Austin Kinross3ae64652015-01-26 15:51:39 -0800293 constructor += TypeString(paramType) + " x" + str(parameter) + ArrayString(paramType);
Jamie Madill8daaba12014-06-13 10:04:33 -0400294
295 if (parameter < ctorParameters.size() - 1)
296 {
297 constructor += ", ";
298 }
299 }
300
301 constructor += ")\n"
302 "{\n";
303
304 if (ctorType.getStruct())
305 {
306 constructor += " " + name + " structure = {";
307 }
308 else
309 {
310 constructor += " return " + TypeString(ctorType) + "(";
311 }
312
313 if (ctorType.isMatrix() && ctorParameters.size() == 1)
314 {
315 int rows = ctorType.getRows();
316 int cols = ctorType.getCols();
317 const TType &parameter = ctorParameters[0];
318
319 if (parameter.isScalar())
320 {
Jamie Madillcf3af0b2014-08-01 17:22:16 -0400321 for (int col = 0; col < cols; col++)
Jamie Madill8daaba12014-06-13 10:04:33 -0400322 {
Jamie Madillcf3af0b2014-08-01 17:22:16 -0400323 for (int row = 0; row < rows; row++)
Jamie Madill8daaba12014-06-13 10:04:33 -0400324 {
325 constructor += TString((row == col) ? "x0" : "0.0");
326
327 if (row < rows - 1 || col < cols - 1)
328 {
329 constructor += ", ";
330 }
331 }
332 }
333 }
334 else if (parameter.isMatrix())
335 {
Jamie Madillf4e39bf2014-08-01 17:22:17 -0400336 for (int col = 0; col < cols; col++)
Jamie Madill8daaba12014-06-13 10:04:33 -0400337 {
Jamie Madillf4e39bf2014-08-01 17:22:17 -0400338 for (int row = 0; row < rows; row++)
Jamie Madill8daaba12014-06-13 10:04:33 -0400339 {
340 if (row < parameter.getRows() && col < parameter.getCols())
341 {
Jamie Madillf4e39bf2014-08-01 17:22:17 -0400342 constructor += TString("x0") + "[" + str(col) + "][" + str(row) + "]";
Jamie Madill8daaba12014-06-13 10:04:33 -0400343 }
344 else
345 {
346 constructor += TString((row == col) ? "1.0" : "0.0");
347 }
348
349 if (row < rows - 1 || col < cols - 1)
350 {
351 constructor += ", ";
352 }
353 }
354 }
355 }
356 else
357 {
358 ASSERT(rows == 2 && cols == 2 && parameter.isVector() && parameter.getNominalSize() == 4);
359
360 constructor += "x0";
361 }
362 }
363 else
364 {
365 size_t remainingComponents = ctorType.getObjectSize();
366 size_t parameterIndex = 0;
367
368 while (remainingComponents > 0)
369 {
370 const TType &parameter = ctorParameters[parameterIndex];
371 const size_t parameterSize = parameter.getObjectSize();
372 bool moreParameters = parameterIndex + 1 < ctorParameters.size();
373
374 constructor += "x" + str(parameterIndex);
375
376 if (ctorType.getStruct())
377 {
378 ASSERT(remainingComponents == parameterSize || moreParameters);
379 ASSERT(parameterSize <= remainingComponents);
380
381 remainingComponents -= parameterSize;
382 }
383 else if (parameter.isScalar())
384 {
385 remainingComponents -= parameter.getObjectSize();
386 }
387 else if (parameter.isVector())
388 {
389 if (remainingComponents == parameterSize || moreParameters)
390 {
391 ASSERT(parameterSize <= remainingComponents);
392 remainingComponents -= parameterSize;
393 }
394 else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
395 {
396 switch (remainingComponents)
397 {
398 case 1: constructor += ".x"; break;
399 case 2: constructor += ".xy"; break;
400 case 3: constructor += ".xyz"; break;
401 case 4: constructor += ".xyzw"; break;
402 default: UNREACHABLE();
403 }
404
405 remainingComponents = 0;
406 }
407 else UNREACHABLE();
408 }
409 else if (parameter.isMatrix())
410 {
411 int column = 0;
412 while (remainingComponents > 0 && column < parameter.getCols())
413 {
414 constructor += "[" + str(column) + "]";
415
416 if (remainingComponents < static_cast<size_t>(parameter.getRows()))
417 {
418 switch (remainingComponents)
419 {
420 case 1: constructor += ".x"; break;
421 case 2: constructor += ".xy"; break;
422 case 3: constructor += ".xyz"; break;
423 default: UNREACHABLE();
424 }
425
426 remainingComponents = 0;
427 }
428 else
429 {
430 remainingComponents -= parameter.getRows();
431
432 if (remainingComponents > 0)
433 {
434 constructor += ", x" + str(parameterIndex);
435 }
436 }
437
438 column++;
439 }
440 }
441 else UNREACHABLE();
442
443 if (moreParameters)
444 {
445 parameterIndex++;
446 }
447
448 if (remainingComponents)
449 {
450 constructor += ", ";
451 }
452 }
453 }
454
455 if (ctorType.getStruct())
456 {
457 constructor += "};\n"
458 " return structure;\n"
459 "}\n";
460 }
461 else
462 {
463 constructor += ");\n"
464 "}\n";
465 }
466
467 mConstructors.insert(constructor);
468}
469
470std::string StructureHLSL::structsHeader() const
471{
472 TInfoSinkBase out;
473
474 for (size_t structIndex = 0; structIndex < mStructDeclarations.size(); structIndex++)
475 {
476 out << mStructDeclarations[structIndex];
477 }
478
Jamie Madill961d5e92014-06-20 15:23:34 -0400479 for (Constructors::const_iterator constructor = mConstructors.begin();
480 constructor != mConstructors.end();
481 constructor++)
Jamie Madill8daaba12014-06-13 10:04:33 -0400482 {
483 out << *constructor;
484 }
485
486 return out.str();
487}
488
489void StructureHLSL::storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking)
490{
Jamie Madill33a74bd2014-08-18 15:47:59 -0400491 Std140PaddingHelper padHelper = getPaddingHelper();
Jamie Madill8daaba12014-06-13 10:04:33 -0400492 const TFieldList &fields = structure.fields();
493
494 for (unsigned int i = 0; i < fields.size(); i++)
495 {
496 padHelper.prePadding(*fields[i]->type());
497 }
498
499 // Add remaining element index to the global map, for use with nested structs in standard layouts
500 const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, true);
501 mStd140StructElementIndexes[structName] = padHelper.elementIndex();
502}
503
Jamie Madill9e5317f2014-06-20 14:56:37 -0400504}