blob: 48929affe636882970fff63fdf2a5a1c97e098dd [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),
24 mStructElementIndexes(structElementIndexes)
25{}
26
Jamie Madill33a74bd2014-08-18 15:47:59 -040027TString Std140PaddingHelper::next()
28{
29 unsigned value = (*mPaddingCounter)++;
30 return str(value);
31}
32
Jamie Madill8daaba12014-06-13 10:04:33 -040033int Std140PaddingHelper::prePadding(const TType &type)
34{
35 if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
36 {
37 // no padding needed, HLSL will align the field to a new register
38 mElementIndex = 0;
39 return 0;
40 }
41
42 const GLenum glType = GLVariableType(type);
Jamie Madillf2575982014-06-25 16:04:54 -040043 const int numComponents = gl::VariableComponentCount(glType);
Jamie Madill8daaba12014-06-13 10:04:33 -040044
45 if (numComponents >= 4)
46 {
47 // no padding needed, HLSL will align the field to a new register
48 mElementIndex = 0;
49 return 0;
50 }
51
52 if (mElementIndex + numComponents > 4)
53 {
54 // no padding needed, HLSL will align the field to a new register
55 mElementIndex = numComponents;
56 return 0;
57 }
58
59 const int alignment = numComponents == 3 ? 4 : numComponents;
60 const int paddingOffset = (mElementIndex % alignment);
61 const int paddingCount = (paddingOffset != 0 ? (alignment - paddingOffset) : 0);
62
63 mElementIndex += paddingCount;
64 mElementIndex += numComponents;
65 mElementIndex %= 4;
66
67 return paddingCount;
68}
69
70TString Std140PaddingHelper::prePaddingString(const TType &type)
71{
72 int paddingCount = prePadding(type);
73
74 TString padding;
75
76 for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++)
77 {
Jamie Madill33a74bd2014-08-18 15:47:59 -040078 padding += " float pad_" + next() + ";\n";
Jamie Madill8daaba12014-06-13 10:04:33 -040079 }
80
81 return padding;
82}
83
84TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRowMajorPacking)
85{
86 if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
87 {
88 return "";
89 }
90
91 int numComponents = 0;
92 TStructure *structure = type.getStruct();
93
94 if (type.isMatrix())
95 {
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.
98 //
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.
101 //
102 const bool isRowMajorMatrix = !useHLSLRowMajorPacking;
103 const GLenum glType = GLVariableType(type);
104 numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix);
105 }
106 else if (structure)
107 {
108 const TString &structName = QualifiedStructNameString(*structure,
109 useHLSLRowMajorPacking, true);
110 numComponents = mStructElementIndexes.find(structName)->second;
111
112 if (numComponents == 0)
113 {
114 return "";
115 }
116 }
117 else
118 {
119 const GLenum glType = GLVariableType(type);
Jamie Madillf2575982014-06-25 16:04:54 -0400120 numComponents = gl::VariableComponentCount(glType);
Jamie Madill8daaba12014-06-13 10:04:33 -0400121 }
122
123 TString padding;
124 for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++)
125 {
Jamie Madill33a74bd2014-08-18 15:47:59 -0400126 padding += " float pad_" + next() + ";\n";
Jamie Madill8daaba12014-06-13 10:04:33 -0400127 }
128 return padding;
129}
130
131StructureHLSL::StructureHLSL()
Jamie Madill33a74bd2014-08-18 15:47:59 -0400132 : mUniquePaddingCounter(0)
Jamie Madill8daaba12014-06-13 10:04:33 -0400133{}
134
Jamie Madill33a74bd2014-08-18 15:47:59 -0400135Std140PaddingHelper StructureHLSL::getPaddingHelper()
136{
137 return Std140PaddingHelper(mStd140StructElementIndexes, &mUniquePaddingCounter);
138}
139
Jamie Madill8daaba12014-06-13 10:04:33 -0400140TString StructureHLSL::defineQualified(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing)
141{
142 if (useStd140Packing)
143 {
Jamie Madill33a74bd2014-08-18 15:47:59 -0400144 Std140PaddingHelper padHelper = getPaddingHelper();
Jamie Madill8daaba12014-06-13 10:04:33 -0400145 return define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper);
146 }
147 else
148 {
149 return define(structure, useHLSLRowMajorPacking, useStd140Packing, NULL);
150 }
151}
152
153TString StructureHLSL::defineNameless(const TStructure &structure)
154{
155 return define(structure, false, false, NULL);
156}
157
158TString StructureHLSL::define(const TStructure &structure, bool useHLSLRowMajorPacking,
159 bool useStd140Packing, Std140PaddingHelper *padHelper)
160{
161 const TFieldList &fields = structure.fields();
162 const bool isNameless = (structure.name() == "");
163 const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking,
164 useStd140Packing);
165 const TString declareString = (isNameless ? "struct" : "struct " + structName);
166
167 TString string;
168 string += declareString + "\n"
169 "{\n";
170
171 for (unsigned int i = 0; i < fields.size(); i++)
172 {
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,
178 useStd140Packing) :
179 TypeString(fieldType);
180
181 if (padHelper)
182 {
183 string += padHelper->prePaddingString(fieldType);
184 }
185
186 string += " " + fieldTypeString + " " + DecorateField(field.name(), structure) + ArrayString(fieldType) + ";\n";
187
188 if (padHelper)
189 {
190 string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
191 }
192 }
193
194 // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable
195 string += (isNameless ? "} " : "};\n");
196
197 return string;
198}
199
200void StructureHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
201{
202 if (name == "")
203 {
204 return; // Nameless structures don't have constructors
205 }
206
207 if (type.getStruct() && mStructNames.find(name) != mStructNames.end())
208 {
209 return; // Already added
210 }
211
212 TType ctorType = type;
213 ctorType.clearArrayness();
214 ctorType.setPrecision(EbpHigh);
215 ctorType.setQualifier(EvqTemporary);
216
217 typedef std::vector<TType> ParameterArray;
218 ParameterArray ctorParameters;
219
220 const TStructure* structure = type.getStruct();
221 if (structure)
222 {
223 mStructNames.insert(name);
224
225 // Add element index
226 storeStd140ElementIndex(*structure, false);
227 storeStd140ElementIndex(*structure, true);
228
229 const TString &structString = defineQualified(*structure, false, false);
230
231 if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == mStructDeclarations.end())
232 {
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";
237
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";
242
243 mStructDeclarations.push_back(structString);
244 mStructDeclarations.push_back(rowMajorString);
245 mStructDeclarations.push_back(std140String);
246 mStructDeclarations.push_back(std140RowMajorString);
247 }
248
249 const TFieldList &fields = structure->fields();
250 for (unsigned int i = 0; i < fields.size(); i++)
251 {
252 ctorParameters.push_back(*fields[i]->type());
253 }
254 }
255 else if (parameters)
256 {
257 for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
258 {
259 ctorParameters.push_back((*parameter)->getAsTyped()->getType());
260 }
261 }
262 else UNREACHABLE();
263
264 TString constructor;
265
266 if (ctorType.getStruct())
267 {
268 constructor += name + " " + name + "_ctor(";
269 }
270 else // Built-in type
271 {
272 constructor += TypeString(ctorType) + " " + name + "(";
273 }
274
275 for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
276 {
Geoff Lang74cafab2015-01-23 23:17:32 +0000277 const TType &type = ctorParameters[parameter];
Jamie Madill8daaba12014-06-13 10:04:33 -0400278
Geoff Lang74cafab2015-01-23 23:17:32 +0000279 constructor += TypeString(type) + " x" + str(parameter) + ArrayString(type);
Jamie Madill8daaba12014-06-13 10:04:33 -0400280
281 if (parameter < ctorParameters.size() - 1)
282 {
283 constructor += ", ";
284 }
285 }
286
287 constructor += ")\n"
288 "{\n";
289
290 if (ctorType.getStruct())
291 {
292 constructor += " " + name + " structure = {";
293 }
294 else
295 {
296 constructor += " return " + TypeString(ctorType) + "(";
297 }
298
299 if (ctorType.isMatrix() && ctorParameters.size() == 1)
300 {
301 int rows = ctorType.getRows();
302 int cols = ctorType.getCols();
303 const TType &parameter = ctorParameters[0];
304
305 if (parameter.isScalar())
306 {
Jamie Madillcf3af0b2014-08-01 17:22:16 -0400307 for (int col = 0; col < cols; col++)
Jamie Madill8daaba12014-06-13 10:04:33 -0400308 {
Jamie Madillcf3af0b2014-08-01 17:22:16 -0400309 for (int row = 0; row < rows; row++)
Jamie Madill8daaba12014-06-13 10:04:33 -0400310 {
311 constructor += TString((row == col) ? "x0" : "0.0");
312
313 if (row < rows - 1 || col < cols - 1)
314 {
315 constructor += ", ";
316 }
317 }
318 }
319 }
320 else if (parameter.isMatrix())
321 {
Jamie Madillf4e39bf2014-08-01 17:22:17 -0400322 for (int col = 0; col < cols; col++)
Jamie Madill8daaba12014-06-13 10:04:33 -0400323 {
Jamie Madillf4e39bf2014-08-01 17:22:17 -0400324 for (int row = 0; row < rows; row++)
Jamie Madill8daaba12014-06-13 10:04:33 -0400325 {
326 if (row < parameter.getRows() && col < parameter.getCols())
327 {
Jamie Madillf4e39bf2014-08-01 17:22:17 -0400328 constructor += TString("x0") + "[" + str(col) + "][" + str(row) + "]";
Jamie Madill8daaba12014-06-13 10:04:33 -0400329 }
330 else
331 {
332 constructor += TString((row == col) ? "1.0" : "0.0");
333 }
334
335 if (row < rows - 1 || col < cols - 1)
336 {
337 constructor += ", ";
338 }
339 }
340 }
341 }
342 else
343 {
344 ASSERT(rows == 2 && cols == 2 && parameter.isVector() && parameter.getNominalSize() == 4);
345
346 constructor += "x0";
347 }
348 }
349 else
350 {
351 size_t remainingComponents = ctorType.getObjectSize();
352 size_t parameterIndex = 0;
353
354 while (remainingComponents > 0)
355 {
356 const TType &parameter = ctorParameters[parameterIndex];
357 const size_t parameterSize = parameter.getObjectSize();
358 bool moreParameters = parameterIndex + 1 < ctorParameters.size();
359
360 constructor += "x" + str(parameterIndex);
361
362 if (ctorType.getStruct())
363 {
364 ASSERT(remainingComponents == parameterSize || moreParameters);
365 ASSERT(parameterSize <= remainingComponents);
366
367 remainingComponents -= parameterSize;
368 }
369 else if (parameter.isScalar())
370 {
371 remainingComponents -= parameter.getObjectSize();
372 }
373 else if (parameter.isVector())
374 {
375 if (remainingComponents == parameterSize || moreParameters)
376 {
377 ASSERT(parameterSize <= remainingComponents);
378 remainingComponents -= parameterSize;
379 }
380 else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
381 {
382 switch (remainingComponents)
383 {
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();
389 }
390
391 remainingComponents = 0;
392 }
393 else UNREACHABLE();
394 }
395 else if (parameter.isMatrix())
396 {
397 int column = 0;
398 while (remainingComponents > 0 && column < parameter.getCols())
399 {
400 constructor += "[" + str(column) + "]";
401
402 if (remainingComponents < static_cast<size_t>(parameter.getRows()))
403 {
404 switch (remainingComponents)
405 {
406 case 1: constructor += ".x"; break;
407 case 2: constructor += ".xy"; break;
408 case 3: constructor += ".xyz"; break;
409 default: UNREACHABLE();
410 }
411
412 remainingComponents = 0;
413 }
414 else
415 {
416 remainingComponents -= parameter.getRows();
417
418 if (remainingComponents > 0)
419 {
420 constructor += ", x" + str(parameterIndex);
421 }
422 }
423
424 column++;
425 }
426 }
427 else UNREACHABLE();
428
429 if (moreParameters)
430 {
431 parameterIndex++;
432 }
433
434 if (remainingComponents)
435 {
436 constructor += ", ";
437 }
438 }
439 }
440
441 if (ctorType.getStruct())
442 {
443 constructor += "};\n"
444 " return structure;\n"
445 "}\n";
446 }
447 else
448 {
449 constructor += ");\n"
450 "}\n";
451 }
452
453 mConstructors.insert(constructor);
454}
455
456std::string StructureHLSL::structsHeader() const
457{
458 TInfoSinkBase out;
459
460 for (size_t structIndex = 0; structIndex < mStructDeclarations.size(); structIndex++)
461 {
462 out << mStructDeclarations[structIndex];
463 }
464
Jamie Madill961d5e92014-06-20 15:23:34 -0400465 for (Constructors::const_iterator constructor = mConstructors.begin();
466 constructor != mConstructors.end();
467 constructor++)
Jamie Madill8daaba12014-06-13 10:04:33 -0400468 {
469 out << *constructor;
470 }
471
472 return out.str();
473}
474
475void StructureHLSL::storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking)
476{
Jamie Madill33a74bd2014-08-18 15:47:59 -0400477 Std140PaddingHelper padHelper = getPaddingHelper();
Jamie Madill8daaba12014-06-13 10:04:33 -0400478 const TFieldList &fields = structure.fields();
479
480 for (unsigned int i = 0; i < fields.size(); i++)
481 {
482 padHelper.prePadding(*fields[i]->type());
483 }
484
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();
488}
489
Jamie Madill9e5317f2014-06-20 14:56:37 -0400490}