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