Line data Source code
1 : //
2 : // Copyright (c) 2002-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 :
7 : #include "compiler/translator/OutputGLSLBase.h"
8 :
9 : #include "common/debug.h"
10 : #include "common/mathutil.h"
11 :
12 : #include <cfloat>
13 :
14 : namespace sh
15 : {
16 :
17 : namespace
18 : {
19 0 : TString arrayBrackets(const TType &type)
20 : {
21 0 : ASSERT(type.isArray());
22 0 : TInfoSinkBase out;
23 0 : out << "[" << type.getArraySize() << "]";
24 0 : return TString(out.c_str());
25 : }
26 :
27 0 : bool isSingleStatement(TIntermNode *node)
28 : {
29 0 : if (node->getAsFunctionDefinition())
30 : {
31 0 : return false;
32 : }
33 0 : else if (node->getAsBlock())
34 : {
35 0 : return false;
36 : }
37 0 : else if (node->getAsIfElseNode())
38 : {
39 0 : return false;
40 : }
41 0 : else if (node->getAsLoopNode())
42 : {
43 0 : return false;
44 : }
45 0 : else if (node->getAsSwitchNode())
46 : {
47 0 : return false;
48 : }
49 0 : else if (node->getAsCaseNode())
50 : {
51 0 : return false;
52 : }
53 0 : return true;
54 : }
55 :
56 : // If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
57 : // variables with specified layout qualifiers are copied. Additional checks are needed against the
58 : // type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
59 : // TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
60 : // NeedsToWriteLayoutQualifier.
61 0 : bool NeedsToWriteLayoutQualifier(const TType &type)
62 : {
63 0 : if (type.getBasicType() == EbtInterfaceBlock)
64 : {
65 0 : return false;
66 : }
67 :
68 0 : const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
69 :
70 0 : if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) &&
71 0 : layoutQualifier.location >= 0)
72 : {
73 0 : return true;
74 : }
75 0 : if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
76 : {
77 0 : return true;
78 : }
79 0 : return false;
80 : }
81 :
82 : } // namespace
83 :
84 0 : TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
85 : ShArrayIndexClampingStrategy clampingStrategy,
86 : ShHashFunction64 hashFunction,
87 : NameMap &nameMap,
88 : TSymbolTable &symbolTable,
89 : sh::GLenum shaderType,
90 : int shaderVersion,
91 : ShShaderOutput output,
92 0 : ShCompileOptions compileOptions)
93 : : TIntermTraverser(true, true, true),
94 : mObjSink(objSink),
95 : mDeclaringVariables(false),
96 : mClampingStrategy(clampingStrategy),
97 : mHashFunction(hashFunction),
98 : mNameMap(nameMap),
99 : mSymbolTable(symbolTable),
100 : mShaderType(shaderType),
101 : mShaderVersion(shaderVersion),
102 : mOutput(output),
103 0 : mCompileOptions(compileOptions)
104 : {
105 0 : }
106 :
107 0 : void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
108 : {
109 0 : if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
110 : {
111 0 : TInfoSinkBase &out = objSink();
112 0 : out << "invariant ";
113 : }
114 0 : }
115 :
116 0 : void TOutputGLSLBase::writeFloat(TInfoSinkBase &out, float f)
117 : {
118 0 : if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300)
119 : {
120 0 : out << "uintBitsToFloat(" << gl::bitCast<uint32_t>(f) << "u)";
121 : }
122 : else
123 : {
124 0 : out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
125 : }
126 0 : }
127 :
128 0 : void TOutputGLSLBase::writeTriplet(
129 : Visit visit, const char *preStr, const char *inStr, const char *postStr)
130 : {
131 0 : TInfoSinkBase &out = objSink();
132 0 : if (visit == PreVisit && preStr)
133 0 : out << preStr;
134 0 : else if (visit == InVisit && inStr)
135 0 : out << inStr;
136 0 : else if (visit == PostVisit && postStr)
137 0 : out << postStr;
138 0 : }
139 :
140 0 : void TOutputGLSLBase::writeBuiltInFunctionTriplet(
141 : Visit visit, const char *preStr, bool useEmulatedFunction)
142 : {
143 : TString preString = useEmulatedFunction ?
144 0 : BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
145 0 : writeTriplet(visit, preString.c_str(), ", ", ")");
146 0 : }
147 :
148 0 : void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
149 : {
150 0 : if (!NeedsToWriteLayoutQualifier(type))
151 : {
152 0 : return;
153 : }
154 :
155 0 : TInfoSinkBase &out = objSink();
156 0 : const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
157 0 : out << "layout(";
158 :
159 0 : if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
160 : {
161 0 : if (layoutQualifier.location >= 0)
162 : {
163 0 : out << "location = " << layoutQualifier.location;
164 : }
165 : }
166 :
167 0 : if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
168 : {
169 0 : ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
170 0 : out << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
171 : }
172 :
173 0 : out << ") ";
174 : }
175 :
176 0 : const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
177 : {
178 0 : if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
179 0 : (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
180 : {
181 0 : switch (qualifier)
182 : {
183 : // The return string is consistent with sh::getQualifierString() from
184 : // BaseTypes.h minus the "centroid" keyword.
185 : case EvqCentroid:
186 0 : return "";
187 : case EvqCentroidIn:
188 0 : return "smooth in";
189 : case EvqCentroidOut:
190 0 : return "smooth out";
191 : default:
192 0 : break;
193 : }
194 : }
195 0 : if (sh::IsGLSL130OrNewer(mOutput))
196 : {
197 0 : switch (qualifier)
198 : {
199 : case EvqAttribute:
200 0 : return "in";
201 : case EvqVaryingIn:
202 0 : return "in";
203 : case EvqVaryingOut:
204 0 : return "out";
205 : default:
206 0 : break;
207 : }
208 : }
209 0 : return sh::getQualifierString(qualifier);
210 : }
211 :
212 0 : void TOutputGLSLBase::writeVariableType(const TType &type)
213 : {
214 0 : TQualifier qualifier = type.getQualifier();
215 0 : TInfoSinkBase &out = objSink();
216 0 : if (type.isInvariant())
217 : {
218 0 : writeInvariantQualifier(type);
219 : }
220 0 : if (type.getBasicType() == EbtInterfaceBlock)
221 : {
222 0 : TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
223 0 : declareInterfaceBlockLayout(interfaceBlock);
224 : }
225 0 : if (qualifier != EvqTemporary && qualifier != EvqGlobal)
226 : {
227 0 : const char *qualifierString = mapQualifierToString(qualifier);
228 0 : if (qualifierString && qualifierString[0] != '\0')
229 : {
230 0 : out << qualifierString << " ";
231 : }
232 : }
233 :
234 0 : const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
235 0 : if (memoryQualifier.readonly)
236 : {
237 0 : ASSERT(IsImage(type.getBasicType()));
238 0 : out << "readonly ";
239 : }
240 :
241 0 : if (memoryQualifier.writeonly)
242 : {
243 0 : ASSERT(IsImage(type.getBasicType()));
244 0 : out << "writeonly ";
245 : }
246 :
247 0 : if (memoryQualifier.coherent)
248 : {
249 0 : ASSERT(IsImage(type.getBasicType()));
250 0 : out << "coherent ";
251 : }
252 :
253 0 : if (memoryQualifier.restrictQualifier)
254 : {
255 0 : ASSERT(IsImage(type.getBasicType()));
256 0 : out << "restrict ";
257 : }
258 :
259 0 : if (memoryQualifier.volatileQualifier)
260 : {
261 0 : ASSERT(IsImage(type.getBasicType()));
262 0 : out << "volatile ";
263 : }
264 :
265 : // Declare the struct if we have not done so already.
266 0 : if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
267 : {
268 0 : TStructure *structure = type.getStruct();
269 :
270 0 : declareStruct(structure);
271 :
272 0 : if (!structure->name().empty())
273 : {
274 0 : mDeclaredStructs.insert(structure->uniqueId());
275 : }
276 : }
277 0 : else if (type.getBasicType() == EbtInterfaceBlock)
278 : {
279 0 : TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
280 0 : declareInterfaceBlock(interfaceBlock);
281 : }
282 : else
283 : {
284 0 : if (writeVariablePrecision(type.getPrecision()))
285 0 : out << " ";
286 0 : out << getTypeName(type);
287 : }
288 0 : }
289 :
290 0 : void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
291 : {
292 0 : TInfoSinkBase &out = objSink();
293 0 : for (TIntermSequence::const_iterator iter = args.begin();
294 0 : iter != args.end(); ++iter)
295 : {
296 0 : const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
297 0 : ASSERT(arg != NULL);
298 :
299 0 : const TType &type = arg->getType();
300 0 : writeVariableType(type);
301 :
302 0 : if (!arg->getName().getString().empty())
303 0 : out << " " << hashName(arg->getName());
304 0 : if (type.isArray())
305 0 : out << arrayBrackets(type);
306 :
307 : // Put a comma if this is not the last argument.
308 0 : if (iter != args.end() - 1)
309 0 : out << ", ";
310 : }
311 0 : }
312 :
313 0 : const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
314 : const TType &type, const TConstantUnion *pConstUnion)
315 : {
316 0 : TInfoSinkBase &out = objSink();
317 :
318 0 : if (type.getBasicType() == EbtStruct)
319 : {
320 0 : const TStructure *structure = type.getStruct();
321 0 : out << hashName(TName(structure->name())) << "(";
322 :
323 0 : const TFieldList &fields = structure->fields();
324 0 : for (size_t i = 0; i < fields.size(); ++i)
325 : {
326 0 : const TType *fieldType = fields[i]->type();
327 0 : ASSERT(fieldType != NULL);
328 0 : pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
329 0 : if (i != fields.size() - 1)
330 0 : out << ", ";
331 : }
332 0 : out << ")";
333 : }
334 : else
335 : {
336 0 : size_t size = type.getObjectSize();
337 0 : bool writeType = size > 1;
338 0 : if (writeType)
339 0 : out << getTypeName(type) << "(";
340 0 : for (size_t i = 0; i < size; ++i, ++pConstUnion)
341 : {
342 0 : switch (pConstUnion->getType())
343 : {
344 : case EbtFloat:
345 0 : writeFloat(out, pConstUnion->getFConst());
346 0 : break;
347 : case EbtInt:
348 0 : out << pConstUnion->getIConst();
349 0 : break;
350 : case EbtUInt:
351 0 : out << pConstUnion->getUConst() << "u";
352 0 : break;
353 : case EbtBool:
354 0 : out << pConstUnion->getBConst();
355 0 : break;
356 0 : default: UNREACHABLE();
357 : }
358 0 : if (i != size - 1)
359 0 : out << ", ";
360 : }
361 0 : if (writeType)
362 0 : out << ")";
363 : }
364 0 : return pConstUnion;
365 : }
366 :
367 0 : void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
368 : {
369 0 : TInfoSinkBase &out = objSink();
370 0 : if (visit == PreVisit)
371 : {
372 0 : if (type.isArray())
373 : {
374 0 : out << getTypeName(type);
375 0 : out << arrayBrackets(type);
376 0 : out << "(";
377 : }
378 : else
379 : {
380 0 : out << getTypeName(type) << "(";
381 : }
382 : }
383 : else
384 : {
385 0 : writeTriplet(visit, nullptr, ", ", ")");
386 : }
387 0 : }
388 :
389 0 : void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
390 : {
391 0 : TInfoSinkBase &out = objSink();
392 0 : out << hashVariableName(node->getName());
393 :
394 0 : if (mDeclaringVariables && node->getType().isArray())
395 0 : out << arrayBrackets(node->getType());
396 0 : }
397 :
398 0 : void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
399 : {
400 0 : writeConstantUnion(node->getType(), node->getUnionArrayPointer());
401 0 : }
402 :
403 0 : bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
404 : {
405 0 : TInfoSinkBase &out = objSink();
406 0 : if (visit == PostVisit)
407 : {
408 0 : out << ".";
409 0 : node->writeOffsetsAsXYZW(&out);
410 : }
411 0 : return true;
412 : }
413 :
414 0 : bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
415 : {
416 0 : bool visitChildren = true;
417 0 : TInfoSinkBase &out = objSink();
418 0 : switch (node->getOp())
419 : {
420 : case EOpComma:
421 0 : writeTriplet(visit, "(", ", ", ")");
422 0 : break;
423 : case EOpInitialize:
424 0 : if (visit == InVisit)
425 : {
426 0 : out << " = ";
427 : // RHS of initialize is not being declared.
428 0 : mDeclaringVariables = false;
429 : }
430 0 : break;
431 : case EOpAssign:
432 0 : writeTriplet(visit, "(", " = ", ")");
433 0 : break;
434 : case EOpAddAssign:
435 0 : writeTriplet(visit, "(", " += ", ")");
436 0 : break;
437 : case EOpSubAssign:
438 0 : writeTriplet(visit, "(", " -= ", ")");
439 0 : break;
440 : case EOpDivAssign:
441 0 : writeTriplet(visit, "(", " /= ", ")");
442 0 : break;
443 : case EOpIModAssign:
444 0 : writeTriplet(visit, "(", " %= ", ")");
445 0 : break;
446 : // Notice the fall-through.
447 : case EOpMulAssign:
448 : case EOpVectorTimesMatrixAssign:
449 : case EOpVectorTimesScalarAssign:
450 : case EOpMatrixTimesScalarAssign:
451 : case EOpMatrixTimesMatrixAssign:
452 0 : writeTriplet(visit, "(", " *= ", ")");
453 0 : break;
454 : case EOpBitShiftLeftAssign:
455 0 : writeTriplet(visit, "(", " <<= ", ")");
456 0 : break;
457 : case EOpBitShiftRightAssign:
458 0 : writeTriplet(visit, "(", " >>= ", ")");
459 0 : break;
460 : case EOpBitwiseAndAssign:
461 0 : writeTriplet(visit, "(", " &= ", ")");
462 0 : break;
463 : case EOpBitwiseXorAssign:
464 0 : writeTriplet(visit, "(", " ^= ", ")");
465 0 : break;
466 : case EOpBitwiseOrAssign:
467 0 : writeTriplet(visit, "(", " |= ", ")");
468 0 : break;
469 :
470 : case EOpIndexDirect:
471 0 : writeTriplet(visit, NULL, "[", "]");
472 0 : break;
473 : case EOpIndexIndirect:
474 0 : if (node->getAddIndexClamp())
475 : {
476 0 : if (visit == InVisit)
477 : {
478 0 : if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
479 0 : out << "[int(clamp(float(";
480 : else
481 0 : out << "[webgl_int_clamp(";
482 : }
483 0 : else if (visit == PostVisit)
484 : {
485 : int maxSize;
486 0 : TIntermTyped *left = node->getLeft();
487 0 : TType leftType = left->getType();
488 :
489 0 : if (left->isArray())
490 : {
491 : // The shader will fail validation if the array length is not > 0.
492 0 : maxSize = static_cast<int>(leftType.getArraySize()) - 1;
493 : }
494 : else
495 : {
496 0 : maxSize = leftType.getNominalSize() - 1;
497 : }
498 :
499 0 : if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
500 0 : out << "), 0.0, float(" << maxSize << ")))]";
501 : else
502 0 : out << ", 0, " << maxSize << ")]";
503 : }
504 : }
505 : else
506 : {
507 0 : writeTriplet(visit, NULL, "[", "]");
508 : }
509 0 : break;
510 : case EOpIndexDirectStruct:
511 0 : if (visit == InVisit)
512 : {
513 : // Here we are writing out "foo.bar", where "foo" is struct
514 : // and "bar" is field. In AST, it is represented as a binary
515 : // node, where left child represents "foo" and right child "bar".
516 : // The node itself represents ".". The struct field "bar" is
517 : // actually stored as an index into TStructure::fields.
518 0 : out << ".";
519 0 : const TStructure *structure = node->getLeft()->getType().getStruct();
520 0 : const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
521 0 : const TField *field = structure->fields()[index->getIConst(0)];
522 :
523 0 : TString fieldName = field->name();
524 0 : if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
525 0 : fieldName = hashName(TName(fieldName));
526 :
527 0 : out << fieldName;
528 0 : visitChildren = false;
529 : }
530 0 : break;
531 : case EOpIndexDirectInterfaceBlock:
532 0 : if (visit == InVisit)
533 : {
534 0 : out << ".";
535 : const TInterfaceBlock *interfaceBlock =
536 0 : node->getLeft()->getType().getInterfaceBlock();
537 0 : const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
538 0 : const TField *field = interfaceBlock->fields()[index->getIConst(0)];
539 :
540 0 : TString fieldName = field->name();
541 0 : ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
542 0 : fieldName = hashName(TName(fieldName));
543 :
544 0 : out << fieldName;
545 0 : visitChildren = false;
546 : }
547 0 : break;
548 :
549 : case EOpAdd:
550 0 : writeTriplet(visit, "(", " + ", ")");
551 0 : break;
552 : case EOpSub:
553 0 : writeTriplet(visit, "(", " - ", ")");
554 0 : break;
555 : case EOpMul:
556 0 : writeTriplet(visit, "(", " * ", ")");
557 0 : break;
558 : case EOpDiv:
559 0 : writeTriplet(visit, "(", " / ", ")");
560 0 : break;
561 : case EOpIMod:
562 0 : writeTriplet(visit, "(", " % ", ")");
563 0 : break;
564 : case EOpBitShiftLeft:
565 0 : writeTriplet(visit, "(", " << ", ")");
566 0 : break;
567 : case EOpBitShiftRight:
568 0 : writeTriplet(visit, "(", " >> ", ")");
569 0 : break;
570 : case EOpBitwiseAnd:
571 0 : writeTriplet(visit, "(", " & ", ")");
572 0 : break;
573 : case EOpBitwiseXor:
574 0 : writeTriplet(visit, "(", " ^ ", ")");
575 0 : break;
576 : case EOpBitwiseOr:
577 0 : writeTriplet(visit, "(", " | ", ")");
578 0 : break;
579 :
580 : case EOpEqual:
581 0 : writeTriplet(visit, "(", " == ", ")");
582 0 : break;
583 : case EOpNotEqual:
584 0 : writeTriplet(visit, "(", " != ", ")");
585 0 : break;
586 : case EOpLessThan:
587 0 : writeTriplet(visit, "(", " < ", ")");
588 0 : break;
589 : case EOpGreaterThan:
590 0 : writeTriplet(visit, "(", " > ", ")");
591 0 : break;
592 : case EOpLessThanEqual:
593 0 : writeTriplet(visit, "(", " <= ", ")");
594 0 : break;
595 : case EOpGreaterThanEqual:
596 0 : writeTriplet(visit, "(", " >= ", ")");
597 0 : break;
598 :
599 : // Notice the fall-through.
600 : case EOpVectorTimesScalar:
601 : case EOpVectorTimesMatrix:
602 : case EOpMatrixTimesVector:
603 : case EOpMatrixTimesScalar:
604 : case EOpMatrixTimesMatrix:
605 0 : writeTriplet(visit, "(", " * ", ")");
606 0 : break;
607 :
608 : case EOpLogicalOr:
609 0 : writeTriplet(visit, "(", " || ", ")");
610 0 : break;
611 : case EOpLogicalXor:
612 0 : writeTriplet(visit, "(", " ^^ ", ")");
613 0 : break;
614 : case EOpLogicalAnd:
615 0 : writeTriplet(visit, "(", " && ", ")");
616 0 : break;
617 : default:
618 0 : UNREACHABLE();
619 : }
620 :
621 0 : return visitChildren;
622 : }
623 :
624 0 : bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
625 : {
626 0 : TString preString;
627 0 : TString postString = ")";
628 :
629 0 : switch (node->getOp())
630 : {
631 0 : case EOpNegative: preString = "(-"; break;
632 0 : case EOpPositive: preString = "(+"; break;
633 0 : case EOpVectorLogicalNot: preString = "not("; break;
634 0 : case EOpLogicalNot: preString = "(!"; break;
635 0 : case EOpBitwiseNot: preString = "(~"; break;
636 :
637 0 : case EOpPostIncrement: preString = "("; postString = "++)"; break;
638 0 : case EOpPostDecrement: preString = "("; postString = "--)"; break;
639 0 : case EOpPreIncrement: preString = "(++"; break;
640 0 : case EOpPreDecrement: preString = "(--"; break;
641 :
642 : case EOpRadians:
643 0 : preString = "radians(";
644 0 : break;
645 : case EOpDegrees:
646 0 : preString = "degrees(";
647 0 : break;
648 : case EOpSin:
649 0 : preString = "sin(";
650 0 : break;
651 : case EOpCos:
652 0 : preString = "cos(";
653 0 : break;
654 : case EOpTan:
655 0 : preString = "tan(";
656 0 : break;
657 : case EOpAsin:
658 0 : preString = "asin(";
659 0 : break;
660 : case EOpAcos:
661 0 : preString = "acos(";
662 0 : break;
663 : case EOpAtan:
664 0 : preString = "atan(";
665 0 : break;
666 :
667 : case EOpSinh:
668 0 : preString = "sinh(";
669 0 : break;
670 : case EOpCosh:
671 0 : preString = "cosh(";
672 0 : break;
673 : case EOpTanh:
674 0 : preString = "tanh(";
675 0 : break;
676 : case EOpAsinh:
677 0 : preString = "asinh(";
678 0 : break;
679 : case EOpAcosh:
680 0 : preString = "acosh(";
681 0 : break;
682 : case EOpAtanh:
683 0 : preString = "atanh(";
684 0 : break;
685 :
686 : case EOpExp:
687 0 : preString = "exp(";
688 0 : break;
689 : case EOpLog:
690 0 : preString = "log(";
691 0 : break;
692 : case EOpExp2:
693 0 : preString = "exp2(";
694 0 : break;
695 : case EOpLog2:
696 0 : preString = "log2(";
697 0 : break;
698 : case EOpSqrt:
699 0 : preString = "sqrt(";
700 0 : break;
701 : case EOpInverseSqrt:
702 0 : preString = "inversesqrt(";
703 0 : break;
704 :
705 : case EOpAbs:
706 0 : preString = "abs(";
707 0 : break;
708 : case EOpSign:
709 0 : preString = "sign(";
710 0 : break;
711 : case EOpFloor:
712 0 : preString = "floor(";
713 0 : break;
714 : case EOpTrunc:
715 0 : preString = "trunc(";
716 0 : break;
717 : case EOpRound:
718 0 : preString = "round(";
719 0 : break;
720 : case EOpRoundEven:
721 0 : preString = "roundEven(";
722 0 : break;
723 : case EOpCeil:
724 0 : preString = "ceil(";
725 0 : break;
726 : case EOpFract:
727 0 : preString = "fract(";
728 0 : break;
729 : case EOpIsNan:
730 0 : preString = "isnan(";
731 0 : break;
732 : case EOpIsInf:
733 0 : preString = "isinf(";
734 0 : break;
735 :
736 : case EOpFloatBitsToInt:
737 0 : preString = "floatBitsToInt(";
738 0 : break;
739 : case EOpFloatBitsToUint:
740 0 : preString = "floatBitsToUint(";
741 0 : break;
742 : case EOpIntBitsToFloat:
743 0 : preString = "intBitsToFloat(";
744 0 : break;
745 : case EOpUintBitsToFloat:
746 0 : preString = "uintBitsToFloat(";
747 0 : break;
748 :
749 : case EOpPackSnorm2x16:
750 0 : preString = "packSnorm2x16(";
751 0 : break;
752 : case EOpPackUnorm2x16:
753 0 : preString = "packUnorm2x16(";
754 0 : break;
755 : case EOpPackHalf2x16:
756 0 : preString = "packHalf2x16(";
757 0 : break;
758 : case EOpUnpackSnorm2x16:
759 0 : preString = "unpackSnorm2x16(";
760 0 : break;
761 : case EOpUnpackUnorm2x16:
762 0 : preString = "unpackUnorm2x16(";
763 0 : break;
764 : case EOpUnpackHalf2x16:
765 0 : preString = "unpackHalf2x16(";
766 0 : break;
767 :
768 : case EOpLength:
769 0 : preString = "length(";
770 0 : break;
771 : case EOpNormalize:
772 0 : preString = "normalize(";
773 0 : break;
774 :
775 : case EOpDFdx:
776 0 : preString = "dFdx(";
777 0 : break;
778 : case EOpDFdy:
779 0 : preString = "dFdy(";
780 0 : break;
781 : case EOpFwidth:
782 0 : preString = "fwidth(";
783 0 : break;
784 :
785 : case EOpTranspose:
786 0 : preString = "transpose(";
787 0 : break;
788 : case EOpDeterminant:
789 0 : preString = "determinant(";
790 0 : break;
791 : case EOpInverse:
792 0 : preString = "inverse(";
793 0 : break;
794 :
795 : case EOpAny:
796 0 : preString = "any(";
797 0 : break;
798 : case EOpAll:
799 0 : preString = "all(";
800 0 : break;
801 :
802 : default:
803 0 : UNREACHABLE();
804 : }
805 :
806 0 : if (visit == PreVisit && node->getUseEmulatedFunction())
807 0 : preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
808 0 : writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
809 :
810 0 : return true;
811 : }
812 :
813 0 : bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
814 : {
815 0 : TInfoSinkBase &out = objSink();
816 : // Notice two brackets at the beginning and end. The outer ones
817 : // encapsulate the whole ternary expression. This preserves the
818 : // order of precedence when ternary expressions are used in a
819 : // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
820 0 : out << "((";
821 0 : node->getCondition()->traverse(this);
822 0 : out << ") ? (";
823 0 : node->getTrueExpression()->traverse(this);
824 0 : out << ") : (";
825 0 : node->getFalseExpression()->traverse(this);
826 0 : out << "))";
827 0 : return false;
828 : }
829 :
830 0 : bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
831 : {
832 0 : TInfoSinkBase &out = objSink();
833 :
834 0 : out << "if (";
835 0 : node->getCondition()->traverse(this);
836 0 : out << ")\n";
837 :
838 0 : incrementDepth(node);
839 0 : visitCodeBlock(node->getTrueBlock());
840 :
841 0 : if (node->getFalseBlock())
842 : {
843 0 : out << "else\n";
844 0 : visitCodeBlock(node->getFalseBlock());
845 : }
846 0 : decrementDepth();
847 0 : return false;
848 : }
849 :
850 0 : bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
851 : {
852 0 : if (node->getStatementList())
853 : {
854 0 : writeTriplet(visit, "switch (", ") ", nullptr);
855 : // The curly braces get written when visiting the statementList aggregate
856 : }
857 : else
858 : {
859 : // No statementList, so it won't output curly braces
860 0 : writeTriplet(visit, "switch (", ") {", "}\n");
861 : }
862 0 : return true;
863 : }
864 :
865 0 : bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
866 : {
867 0 : if (node->hasCondition())
868 : {
869 0 : writeTriplet(visit, "case (", nullptr, "):\n");
870 0 : return true;
871 : }
872 : else
873 : {
874 0 : TInfoSinkBase &out = objSink();
875 0 : out << "default:\n";
876 0 : return false;
877 : }
878 : }
879 :
880 0 : bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
881 : {
882 0 : TInfoSinkBase &out = objSink();
883 : // Scope the blocks except when at the global scope.
884 0 : if (mDepth > 0)
885 : {
886 0 : out << "{\n";
887 : }
888 :
889 0 : incrementDepth(node);
890 0 : for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
891 0 : iter != node->getSequence()->end(); ++iter)
892 : {
893 0 : TIntermNode *curNode = *iter;
894 0 : ASSERT(curNode != nullptr);
895 0 : curNode->traverse(this);
896 :
897 0 : if (isSingleStatement(curNode))
898 0 : out << ";\n";
899 : }
900 0 : decrementDepth();
901 :
902 : // Scope the blocks except when at the global scope.
903 0 : if (mDepth > 0)
904 : {
905 0 : out << "}\n";
906 : }
907 0 : return false;
908 : }
909 :
910 0 : bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
911 : {
912 0 : TInfoSinkBase &out = objSink();
913 :
914 0 : ASSERT(visit == PreVisit);
915 : {
916 0 : const TType &type = node->getType();
917 0 : writeVariableType(type);
918 0 : if (type.isArray())
919 0 : out << arrayBrackets(type);
920 : }
921 :
922 0 : out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
923 :
924 0 : incrementDepth(node);
925 :
926 : // Traverse function parameters.
927 0 : TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
928 0 : ASSERT(params->getOp() == EOpParameters);
929 0 : params->traverse(this);
930 :
931 : // Traverse function body.
932 0 : visitCodeBlock(node->getBody());
933 0 : decrementDepth();
934 :
935 : // Fully processed; no need to visit children.
936 0 : return false;
937 : }
938 :
939 0 : bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
940 : {
941 0 : bool visitChildren = true;
942 0 : TInfoSinkBase &out = objSink();
943 0 : bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
944 0 : switch (node->getOp())
945 : {
946 : case EOpPrototype:
947 : // Function declaration.
948 0 : ASSERT(visit == PreVisit);
949 : {
950 0 : const TType &type = node->getType();
951 0 : writeVariableType(type);
952 0 : if (type.isArray())
953 0 : out << arrayBrackets(type);
954 : }
955 :
956 0 : out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
957 :
958 0 : out << "(";
959 0 : writeFunctionParameters(*(node->getSequence()));
960 0 : out << ")";
961 :
962 0 : visitChildren = false;
963 0 : break;
964 : case EOpFunctionCall:
965 : // Function call.
966 0 : if (visit == PreVisit)
967 0 : out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
968 0 : else if (visit == InVisit)
969 0 : out << ", ";
970 : else
971 0 : out << ")";
972 0 : break;
973 : case EOpParameters:
974 : // Function parameters.
975 0 : ASSERT(visit == PreVisit);
976 0 : out << "(";
977 0 : writeFunctionParameters(*(node->getSequence()));
978 0 : out << ")";
979 0 : visitChildren = false;
980 0 : break;
981 : case EOpInvariantDeclaration:
982 : // Invariant declaration.
983 0 : ASSERT(visit == PreVisit);
984 : {
985 0 : const TIntermSequence *sequence = node->getSequence();
986 0 : ASSERT(sequence && sequence->size() == 1);
987 0 : const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
988 0 : ASSERT(symbol);
989 0 : out << "invariant " << hashVariableName(symbol->getName());
990 : }
991 0 : visitChildren = false;
992 0 : break;
993 : case EOpConstructFloat:
994 : case EOpConstructVec2:
995 : case EOpConstructVec3:
996 : case EOpConstructVec4:
997 : case EOpConstructBool:
998 : case EOpConstructBVec2:
999 : case EOpConstructBVec3:
1000 : case EOpConstructBVec4:
1001 : case EOpConstructInt:
1002 : case EOpConstructIVec2:
1003 : case EOpConstructIVec3:
1004 : case EOpConstructIVec4:
1005 : case EOpConstructUInt:
1006 : case EOpConstructUVec2:
1007 : case EOpConstructUVec3:
1008 : case EOpConstructUVec4:
1009 : case EOpConstructMat2:
1010 : case EOpConstructMat2x3:
1011 : case EOpConstructMat2x4:
1012 : case EOpConstructMat3x2:
1013 : case EOpConstructMat3:
1014 : case EOpConstructMat3x4:
1015 : case EOpConstructMat4x2:
1016 : case EOpConstructMat4x3:
1017 : case EOpConstructMat4:
1018 : case EOpConstructStruct:
1019 0 : writeConstructorTriplet(visit, node->getType());
1020 0 : break;
1021 :
1022 : case EOpOuterProduct:
1023 0 : writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
1024 0 : break;
1025 :
1026 : case EOpLessThan:
1027 0 : writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
1028 0 : break;
1029 : case EOpGreaterThan:
1030 0 : writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
1031 0 : break;
1032 : case EOpLessThanEqual:
1033 0 : writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
1034 0 : break;
1035 : case EOpGreaterThanEqual:
1036 0 : writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
1037 0 : break;
1038 : case EOpVectorEqual:
1039 0 : writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
1040 0 : break;
1041 : case EOpVectorNotEqual:
1042 0 : writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
1043 0 : break;
1044 :
1045 : case EOpMod:
1046 0 : writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
1047 0 : break;
1048 : case EOpModf:
1049 0 : writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
1050 0 : break;
1051 : case EOpPow:
1052 0 : writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
1053 0 : break;
1054 : case EOpAtan:
1055 0 : writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
1056 0 : break;
1057 : case EOpMin:
1058 0 : writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
1059 0 : break;
1060 : case EOpMax:
1061 0 : writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
1062 0 : break;
1063 : case EOpClamp:
1064 0 : writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
1065 0 : break;
1066 : case EOpMix:
1067 0 : writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
1068 0 : break;
1069 : case EOpStep:
1070 0 : writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
1071 0 : break;
1072 : case EOpSmoothStep:
1073 0 : writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1074 0 : break;
1075 : case EOpDistance:
1076 0 : writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1077 0 : break;
1078 : case EOpDot:
1079 0 : writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1080 0 : break;
1081 : case EOpCross:
1082 0 : writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1083 0 : break;
1084 : case EOpFaceForward:
1085 0 : writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1086 0 : break;
1087 : case EOpReflect:
1088 0 : writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1089 0 : break;
1090 : case EOpRefract:
1091 0 : writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1092 0 : break;
1093 : case EOpMul:
1094 0 : writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1095 0 : break;
1096 :
1097 : default:
1098 0 : UNREACHABLE();
1099 : }
1100 0 : return visitChildren;
1101 : }
1102 :
1103 0 : bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1104 : {
1105 0 : TInfoSinkBase &out = objSink();
1106 :
1107 : // Variable declaration.
1108 0 : if (visit == PreVisit)
1109 : {
1110 0 : const TIntermSequence &sequence = *(node->getSequence());
1111 0 : const TIntermTyped *variable = sequence.front()->getAsTyped();
1112 0 : writeLayoutQualifier(variable->getType());
1113 0 : writeVariableType(variable->getType());
1114 0 : out << " ";
1115 0 : mDeclaringVariables = true;
1116 : }
1117 0 : else if (visit == InVisit)
1118 : {
1119 0 : out << ", ";
1120 0 : mDeclaringVariables = true;
1121 : }
1122 : else
1123 : {
1124 0 : mDeclaringVariables = false;
1125 : }
1126 0 : return true;
1127 : }
1128 :
1129 0 : bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
1130 : {
1131 0 : TInfoSinkBase &out = objSink();
1132 :
1133 0 : incrementDepth(node);
1134 :
1135 0 : TLoopType loopType = node->getType();
1136 :
1137 0 : if (loopType == ELoopFor) // for loop
1138 : {
1139 0 : out << "for (";
1140 0 : if (node->getInit())
1141 0 : node->getInit()->traverse(this);
1142 0 : out << "; ";
1143 :
1144 0 : if (node->getCondition())
1145 0 : node->getCondition()->traverse(this);
1146 0 : out << "; ";
1147 :
1148 0 : if (node->getExpression())
1149 0 : node->getExpression()->traverse(this);
1150 0 : out << ")\n";
1151 :
1152 0 : visitCodeBlock(node->getBody());
1153 : }
1154 0 : else if (loopType == ELoopWhile) // while loop
1155 : {
1156 0 : out << "while (";
1157 0 : ASSERT(node->getCondition() != NULL);
1158 0 : node->getCondition()->traverse(this);
1159 0 : out << ")\n";
1160 :
1161 0 : visitCodeBlock(node->getBody());
1162 : }
1163 : else // do-while loop
1164 : {
1165 0 : ASSERT(loopType == ELoopDoWhile);
1166 0 : out << "do\n";
1167 :
1168 0 : visitCodeBlock(node->getBody());
1169 :
1170 0 : out << "while (";
1171 0 : ASSERT(node->getCondition() != NULL);
1172 0 : node->getCondition()->traverse(this);
1173 0 : out << ");\n";
1174 : }
1175 :
1176 0 : decrementDepth();
1177 :
1178 : // No need to visit children. They have been already processed in
1179 : // this function.
1180 0 : return false;
1181 : }
1182 :
1183 0 : bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
1184 : {
1185 0 : switch (node->getFlowOp())
1186 : {
1187 : case EOpKill:
1188 0 : writeTriplet(visit, "discard", NULL, NULL);
1189 0 : break;
1190 : case EOpBreak:
1191 0 : writeTriplet(visit, "break", NULL, NULL);
1192 0 : break;
1193 : case EOpContinue:
1194 0 : writeTriplet(visit, "continue", NULL, NULL);
1195 0 : break;
1196 : case EOpReturn:
1197 0 : writeTriplet(visit, "return ", NULL, NULL);
1198 0 : break;
1199 : default:
1200 0 : UNREACHABLE();
1201 : }
1202 :
1203 0 : return true;
1204 : }
1205 :
1206 0 : void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
1207 : {
1208 0 : TInfoSinkBase &out = objSink();
1209 0 : if (node != NULL)
1210 : {
1211 0 : node->traverse(this);
1212 : // Single statements not part of a sequence need to be terminated
1213 : // with semi-colon.
1214 0 : if (isSingleStatement(node))
1215 0 : out << ";\n";
1216 : }
1217 : else
1218 : {
1219 0 : out << "{\n}\n"; // Empty code block.
1220 : }
1221 0 : }
1222 :
1223 0 : TString TOutputGLSLBase::getTypeName(const TType &type)
1224 : {
1225 0 : if (type.getBasicType() == EbtStruct)
1226 0 : return hashName(TName(type.getStruct()->name()));
1227 : else
1228 0 : return type.getBuiltInTypeNameString();
1229 : }
1230 :
1231 0 : TString TOutputGLSLBase::hashName(const TName &name)
1232 : {
1233 0 : if (name.getString().empty())
1234 : {
1235 0 : ASSERT(!name.isInternal());
1236 0 : return name.getString();
1237 : }
1238 0 : if (name.isInternal())
1239 : {
1240 : // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1241 : // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1242 : // as well.
1243 : // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1244 : // names don't conflict with user-defined names from WebGL.
1245 0 : return "webgl_angle_" + name.getString();
1246 : }
1247 0 : if (mHashFunction == nullptr)
1248 : {
1249 0 : return name.getString();
1250 : }
1251 0 : NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
1252 0 : if (it != mNameMap.end())
1253 0 : return it->second.c_str();
1254 0 : TString hashedName = TIntermTraverser::hash(name.getString(), mHashFunction);
1255 0 : mNameMap[name.getString().c_str()] = hashedName.c_str();
1256 0 : return hashedName;
1257 : }
1258 :
1259 0 : TString TOutputGLSLBase::hashVariableName(const TName &name)
1260 : {
1261 0 : if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
1262 0 : return name.getString();
1263 0 : return hashName(name);
1264 : }
1265 :
1266 0 : TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
1267 : {
1268 0 : TString mangledStr = mangledName.getString();
1269 0 : TString name = TFunction::unmangleName(mangledStr);
1270 0 : if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
1271 0 : return translateTextureFunction(name);
1272 0 : if (mangledName.isInternal())
1273 : {
1274 : // Internal function names are outputted as-is - they may refer to functions manually added
1275 : // to the output shader source that are not included in the AST at all.
1276 0 : return name;
1277 : }
1278 : else
1279 : {
1280 0 : TName nameObj(name);
1281 0 : return hashName(nameObj);
1282 : }
1283 : }
1284 :
1285 0 : bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
1286 : {
1287 0 : ASSERT(structure);
1288 0 : if (structure->name().empty())
1289 : {
1290 0 : return false;
1291 : }
1292 :
1293 0 : return (mDeclaredStructs.count(structure->uniqueId()) > 0);
1294 : }
1295 :
1296 0 : void TOutputGLSLBase::declareStruct(const TStructure *structure)
1297 : {
1298 0 : TInfoSinkBase &out = objSink();
1299 :
1300 0 : out << "struct " << hashName(TName(structure->name())) << "{\n";
1301 0 : const TFieldList &fields = structure->fields();
1302 0 : for (size_t i = 0; i < fields.size(); ++i)
1303 : {
1304 0 : const TField *field = fields[i];
1305 0 : if (writeVariablePrecision(field->type()->getPrecision()))
1306 0 : out << " ";
1307 0 : out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
1308 0 : if (field->type()->isArray())
1309 0 : out << arrayBrackets(*field->type());
1310 0 : out << ";\n";
1311 : }
1312 0 : out << "}";
1313 0 : }
1314 :
1315 0 : void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1316 : {
1317 0 : TInfoSinkBase &out = objSink();
1318 :
1319 0 : out << "layout(";
1320 :
1321 0 : switch (interfaceBlock->blockStorage())
1322 : {
1323 : case EbsUnspecified:
1324 : case EbsShared:
1325 : // Default block storage is shared.
1326 0 : out << "shared";
1327 0 : break;
1328 :
1329 : case EbsPacked:
1330 0 : out << "packed";
1331 0 : break;
1332 :
1333 : case EbsStd140:
1334 0 : out << "std140";
1335 0 : break;
1336 :
1337 : default:
1338 0 : UNREACHABLE();
1339 : break;
1340 : }
1341 :
1342 0 : out << ", ";
1343 :
1344 0 : switch (interfaceBlock->matrixPacking())
1345 : {
1346 : case EmpUnspecified:
1347 : case EmpColumnMajor:
1348 : // Default matrix packing is column major.
1349 0 : out << "column_major";
1350 0 : break;
1351 :
1352 : case EmpRowMajor:
1353 0 : out << "row_major";
1354 0 : break;
1355 :
1356 : default:
1357 0 : UNREACHABLE();
1358 : break;
1359 : }
1360 :
1361 0 : out << ") ";
1362 0 : }
1363 :
1364 0 : void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1365 : {
1366 0 : TInfoSinkBase &out = objSink();
1367 :
1368 0 : out << hashName(TName(interfaceBlock->name())) << "{\n";
1369 0 : const TFieldList &fields = interfaceBlock->fields();
1370 0 : for (size_t i = 0; i < fields.size(); ++i)
1371 : {
1372 0 : const TField *field = fields[i];
1373 0 : if (writeVariablePrecision(field->type()->getPrecision()))
1374 0 : out << " ";
1375 0 : out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
1376 0 : if (field->type()->isArray())
1377 0 : out << arrayBrackets(*field->type());
1378 0 : out << ";\n";
1379 : }
1380 0 : out << "}";
1381 0 : }
1382 :
1383 : } // namespace sh
|