1 //
2 // Copyright 2002 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 "angle_gl.h"
10 #include "common/debug.h"
11 #include "common/mathutil.h"
12 #include "compiler/translator/Compiler.h"
13 #include "compiler/translator/util.h"
14
15 #include <cfloat>
16
17 namespace sh
18 {
19
20 namespace
21 {
22
isSingleStatement(TIntermNode * node)23 bool isSingleStatement(TIntermNode *node)
24 {
25 if (node->getAsFunctionDefinition())
26 {
27 return false;
28 }
29 else if (node->getAsBlock())
30 {
31 return false;
32 }
33 else if (node->getAsIfElseNode())
34 {
35 return false;
36 }
37 else if (node->getAsLoopNode())
38 {
39 return false;
40 }
41 else if (node->getAsSwitchNode())
42 {
43 return false;
44 }
45 else if (node->getAsCaseNode())
46 {
47 return false;
48 }
49 else if (node->getAsPreprocessorDirective())
50 {
51 return false;
52 }
53 return true;
54 }
55
56 class CommaSeparatedListItemPrefixGenerator
57 {
58 public:
CommaSeparatedListItemPrefixGenerator()59 CommaSeparatedListItemPrefixGenerator() : mFirst(true) {}
60
61 private:
62 bool mFirst;
63
64 template <typename Stream>
65 friend Stream &operator<<(Stream &out, CommaSeparatedListItemPrefixGenerator &gen);
66 };
67
68 template <typename Stream>
operator <<(Stream & out,CommaSeparatedListItemPrefixGenerator & gen)69 Stream &operator<<(Stream &out, CommaSeparatedListItemPrefixGenerator &gen)
70 {
71 if (gen.mFirst)
72 {
73 gen.mFirst = false;
74 }
75 else
76 {
77 out << ", ";
78 }
79 return out;
80 }
81
82 } // namespace
83
TOutputGLSLBase(TInfoSinkBase & objSink,ShArrayIndexClampingStrategy clampingStrategy,ShHashFunction64 hashFunction,NameMap & nameMap,TSymbolTable * symbolTable,sh::GLenum shaderType,int shaderVersion,ShShaderOutput output,ShCompileOptions compileOptions)84 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 ShCompileOptions compileOptions)
93 : TIntermTraverser(true, true, true, symbolTable),
94 mObjSink(objSink),
95 mDeclaringVariable(false),
96 mClampingStrategy(clampingStrategy),
97 mHashFunction(hashFunction),
98 mNameMap(nameMap),
99 mShaderType(shaderType),
100 mShaderVersion(shaderVersion),
101 mOutput(output),
102 mCompileOptions(compileOptions)
103 {}
104
writeInvariantQualifier(const TType & type)105 void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
106 {
107 if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
108 {
109 TInfoSinkBase &out = objSink();
110 out << "invariant ";
111 }
112 }
113
writePreciseQualifier(const TType & type)114 void TOutputGLSLBase::writePreciseQualifier(const TType &type)
115 {
116 TInfoSinkBase &out = objSink();
117 out << "precise ";
118 }
119
writeFloat(TInfoSinkBase & out,float f)120 void TOutputGLSLBase::writeFloat(TInfoSinkBase &out, float f)
121 {
122 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300)
123 {
124 out << "uintBitsToFloat(" << gl::bitCast<uint32_t>(f) << "u)";
125 }
126 else
127 {
128 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
129 }
130 }
131
writeTriplet(Visit visit,const char * preStr,const char * inStr,const char * postStr)132 void TOutputGLSLBase::writeTriplet(Visit visit,
133 const char *preStr,
134 const char *inStr,
135 const char *postStr)
136 {
137 TInfoSinkBase &out = objSink();
138 if (visit == PreVisit && preStr)
139 out << preStr;
140 else if (visit == InVisit && inStr)
141 out << inStr;
142 else if (visit == PostVisit && postStr)
143 out << postStr;
144 }
145
writeBuiltInFunctionTriplet(Visit visit,TOperator op,bool useEmulatedFunction)146 void TOutputGLSLBase::writeBuiltInFunctionTriplet(Visit visit,
147 TOperator op,
148 bool useEmulatedFunction)
149 {
150 TInfoSinkBase &out = objSink();
151 if (visit == PreVisit)
152 {
153 const char *opStr(GetOperatorString(op));
154 if (useEmulatedFunction)
155 {
156 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
157 }
158 else
159 {
160 out << opStr;
161 }
162 out << "(";
163 }
164 else
165 {
166 writeTriplet(visit, nullptr, ", ", ")");
167 }
168 }
169
170 // Outputs what goes inside layout(), except for location and binding qualifiers, as they are
171 // handled differently between GL GLSL and Vulkan GLSL.
getCommonLayoutQualifiers(TIntermTyped * variable)172 std::string TOutputGLSLBase::getCommonLayoutQualifiers(TIntermTyped *variable)
173 {
174 std::ostringstream out;
175 CommaSeparatedListItemPrefixGenerator listItemPrefix;
176
177 const TType &type = variable->getType();
178 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
179
180 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
181 IsVarying(type.getQualifier()))
182 {
183 if (type.getQualifier() == EvqFragmentOut && layoutQualifier.index >= 0)
184 {
185 out << listItemPrefix << "index = " << layoutQualifier.index;
186 }
187 }
188
189 if (type.getQualifier() == EvqFragmentOut)
190 {
191 if (layoutQualifier.yuv == true)
192 {
193 out << listItemPrefix << "yuv";
194 }
195 }
196
197 if (IsImage(type.getBasicType()))
198 {
199 if (layoutQualifier.imageInternalFormat != EiifUnspecified)
200 {
201 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
202 out << listItemPrefix
203 << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
204 }
205 }
206
207 if (IsAtomicCounter(type.getBasicType()))
208 {
209 out << listItemPrefix << "offset = " << layoutQualifier.offset;
210 }
211
212 return out.str();
213 }
214
215 // Outputs memory qualifiers applied to images, buffers and its fields, as well as image function
216 // arguments.
getMemoryQualifiers(const TType & type)217 std::string TOutputGLSLBase::getMemoryQualifiers(const TType &type)
218 {
219 std::ostringstream out;
220
221 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
222 if (memoryQualifier.readonly)
223 {
224 out << "readonly ";
225 }
226
227 if (memoryQualifier.writeonly)
228 {
229 out << "writeonly ";
230 }
231
232 if (memoryQualifier.coherent)
233 {
234 out << "coherent ";
235 }
236
237 if (memoryQualifier.restrictQualifier)
238 {
239 out << "restrict ";
240 }
241
242 if (memoryQualifier.volatileQualifier)
243 {
244 out << "volatile ";
245 }
246
247 return out.str();
248 }
249
writeLayoutQualifier(TIntermTyped * variable)250 void TOutputGLSLBase::writeLayoutQualifier(TIntermTyped *variable)
251 {
252 const TType &type = variable->getType();
253
254 if (!NeedsToWriteLayoutQualifier(type))
255 {
256 return;
257 }
258
259 if (type.getBasicType() == EbtInterfaceBlock)
260 {
261 declareInterfaceBlockLayout(type);
262 return;
263 }
264
265 TInfoSinkBase &out = objSink();
266 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
267 out << "layout(";
268
269 CommaSeparatedListItemPrefixGenerator listItemPrefix;
270
271 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
272 IsVarying(type.getQualifier()))
273 {
274 if (layoutQualifier.location >= 0)
275 {
276 out << listItemPrefix << "location = " << layoutQualifier.location;
277 }
278 }
279
280 if (IsOpaqueType(type.getBasicType()))
281 {
282 if (layoutQualifier.binding >= 0)
283 {
284 out << listItemPrefix << "binding = " << layoutQualifier.binding;
285 }
286 }
287
288 std::string otherQualifiers = getCommonLayoutQualifiers(variable);
289 if (!otherQualifiers.empty())
290 {
291 out << listItemPrefix << otherQualifiers;
292 }
293
294 out << ") ";
295 }
296
writeFieldLayoutQualifier(const TField * field)297 void TOutputGLSLBase::writeFieldLayoutQualifier(const TField *field)
298 {
299 if (!field->type()->isMatrix() && !field->type()->isStructureContainingMatrices())
300 {
301 return;
302 }
303
304 TInfoSinkBase &out = objSink();
305
306 out << "layout(";
307 switch (field->type()->getLayoutQualifier().matrixPacking)
308 {
309 case EmpUnspecified:
310 case EmpColumnMajor:
311 // Default matrix packing is column major.
312 out << "column_major";
313 break;
314
315 case EmpRowMajor:
316 out << "row_major";
317 break;
318
319 default:
320 UNREACHABLE();
321 break;
322 }
323 out << ") ";
324 }
325
writeQualifier(TQualifier qualifier,const TType & type,const TSymbol * symbol)326 void TOutputGLSLBase::writeQualifier(TQualifier qualifier, const TType &type, const TSymbol *symbol)
327 {
328 const char *result = mapQualifierToString(qualifier);
329 if (result && result[0] != '\0')
330 {
331 objSink() << result << " ";
332 }
333
334 objSink() << getMemoryQualifiers(type);
335 }
336
mapQualifierToString(TQualifier qualifier)337 const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
338 {
339 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
340 (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
341 {
342 switch (qualifier)
343 {
344 // The return string is consistent with sh::getQualifierString() from
345 // BaseTypes.h minus the "centroid" keyword.
346 case EvqCentroid:
347 return "";
348 case EvqCentroidIn:
349 return "smooth in";
350 case EvqCentroidOut:
351 return "smooth out";
352 default:
353 break;
354 }
355 }
356 if (sh::IsGLSL130OrNewer(mOutput))
357 {
358 switch (qualifier)
359 {
360 case EvqAttribute:
361 return "in";
362 case EvqVaryingIn:
363 return "in";
364 case EvqVaryingOut:
365 return "out";
366 default:
367 break;
368 }
369 }
370 return sh::getQualifierString(qualifier);
371 }
372
writeVariableType(const TType & type,const TSymbol * symbol,bool isFunctionArgument)373 void TOutputGLSLBase::writeVariableType(const TType &type,
374 const TSymbol *symbol,
375 bool isFunctionArgument)
376 {
377 TQualifier qualifier = type.getQualifier();
378 TInfoSinkBase &out = objSink();
379 if (type.isInvariant())
380 {
381 writeInvariantQualifier(type);
382 }
383 if (type.isPrecise())
384 {
385 writePreciseQualifier(type);
386 }
387 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
388 {
389 writeQualifier(qualifier, type, symbol);
390 }
391 if (isFunctionArgument)
392 {
393 // Function arguments are the only place (other than image/SSBO/field declaration) where
394 // memory qualifiers can appear.
395 out << getMemoryQualifiers(type);
396 }
397
398 // Declare the struct.
399 if (type.isStructSpecifier())
400 {
401 const TStructure *structure = type.getStruct();
402
403 declareStruct(structure);
404 }
405 else if (type.getBasicType() == EbtInterfaceBlock)
406 {
407 declareInterfaceBlock(type);
408 }
409 else
410 {
411 if (writeVariablePrecision(type.getPrecision()))
412 out << " ";
413 out << getTypeName(type);
414 }
415 }
416
writeFunctionParameters(const TFunction * func)417 void TOutputGLSLBase::writeFunctionParameters(const TFunction *func)
418 {
419 TInfoSinkBase &out = objSink();
420 size_t paramCount = func->getParamCount();
421 for (size_t i = 0; i < paramCount; ++i)
422 {
423 const TVariable *param = func->getParam(i);
424 const TType &type = param->getType();
425 writeVariableType(type, param, true);
426
427 if (param->symbolType() != SymbolType::Empty)
428 out << " " << hashName(param);
429 if (type.isArray())
430 out << ArrayString(type);
431
432 // Put a comma if this is not the last argument.
433 if (i != paramCount - 1)
434 out << ", ";
435 }
436 }
437
writeConstantUnion(const TType & type,const TConstantUnion * pConstUnion)438 const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
439 const TConstantUnion *pConstUnion)
440 {
441 TInfoSinkBase &out = objSink();
442
443 if (type.getBasicType() == EbtStruct)
444 {
445 const TStructure *structure = type.getStruct();
446 out << hashName(structure) << "(";
447
448 const TFieldList &fields = structure->fields();
449 for (size_t i = 0; i < fields.size(); ++i)
450 {
451 const TType *fieldType = fields[i]->type();
452 ASSERT(fieldType != nullptr);
453 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
454 if (i != fields.size() - 1)
455 out << ", ";
456 }
457 out << ")";
458 }
459 else
460 {
461 size_t size = type.getObjectSize();
462 bool writeType = size > 1;
463 if (writeType)
464 out << getTypeName(type) << "(";
465 for (size_t i = 0; i < size; ++i, ++pConstUnion)
466 {
467 switch (pConstUnion->getType())
468 {
469 case EbtFloat:
470 writeFloat(out, pConstUnion->getFConst());
471 break;
472 case EbtInt:
473 out << pConstUnion->getIConst();
474 break;
475 case EbtUInt:
476 out << pConstUnion->getUConst() << "u";
477 break;
478 case EbtBool:
479 out << pConstUnion->getBConst();
480 break;
481 case EbtYuvCscStandardEXT:
482 out << getYuvCscStandardEXTString(pConstUnion->getYuvCscStandardEXTConst());
483 break;
484 default:
485 UNREACHABLE();
486 }
487 if (i != size - 1)
488 out << ", ";
489 }
490 if (writeType)
491 out << ")";
492 }
493 return pConstUnion;
494 }
495
writeConstructorTriplet(Visit visit,const TType & type)496 void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
497 {
498 TInfoSinkBase &out = objSink();
499 if (visit == PreVisit)
500 {
501 if (type.isArray())
502 {
503 out << getTypeName(type);
504 out << ArrayString(type);
505 out << "(";
506 }
507 else
508 {
509 out << getTypeName(type) << "(";
510 }
511 }
512 else
513 {
514 writeTriplet(visit, nullptr, ", ", ")");
515 }
516 }
517
visitSymbol(TIntermSymbol * node)518 void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
519 {
520 TInfoSinkBase &out = objSink();
521 out << hashName(&node->variable());
522
523 if (mDeclaringVariable && node->getType().isArray())
524 out << ArrayString(node->getType());
525 }
526
visitConstantUnion(TIntermConstantUnion * node)527 void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
528 {
529 writeConstantUnion(node->getType(), node->getConstantValue());
530 }
531
visitSwizzle(Visit visit,TIntermSwizzle * node)532 bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
533 {
534 TInfoSinkBase &out = objSink();
535 if (visit == PostVisit)
536 {
537 out << ".";
538 node->writeOffsetsAsXYZW(&out);
539 }
540 return true;
541 }
542
visitBinary(Visit visit,TIntermBinary * node)543 bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
544 {
545 bool visitChildren = true;
546 TInfoSinkBase &out = objSink();
547 switch (node->getOp())
548 {
549 case EOpComma:
550 writeTriplet(visit, "(", ", ", ")");
551 break;
552 case EOpInitialize:
553 if (visit == InVisit)
554 {
555 out << " = ";
556 // RHS of initialize is not being declared.
557 mDeclaringVariable = false;
558 }
559 break;
560 case EOpAssign:
561 writeTriplet(visit, "(", " = ", ")");
562 break;
563 case EOpAddAssign:
564 writeTriplet(visit, "(", " += ", ")");
565 break;
566 case EOpSubAssign:
567 writeTriplet(visit, "(", " -= ", ")");
568 break;
569 case EOpDivAssign:
570 writeTriplet(visit, "(", " /= ", ")");
571 break;
572 case EOpIModAssign:
573 writeTriplet(visit, "(", " %= ", ")");
574 break;
575 // Notice the fall-through.
576 case EOpMulAssign:
577 case EOpVectorTimesMatrixAssign:
578 case EOpVectorTimesScalarAssign:
579 case EOpMatrixTimesScalarAssign:
580 case EOpMatrixTimesMatrixAssign:
581 writeTriplet(visit, "(", " *= ", ")");
582 break;
583 case EOpBitShiftLeftAssign:
584 writeTriplet(visit, "(", " <<= ", ")");
585 break;
586 case EOpBitShiftRightAssign:
587 writeTriplet(visit, "(", " >>= ", ")");
588 break;
589 case EOpBitwiseAndAssign:
590 writeTriplet(visit, "(", " &= ", ")");
591 break;
592 case EOpBitwiseXorAssign:
593 writeTriplet(visit, "(", " ^= ", ")");
594 break;
595 case EOpBitwiseOrAssign:
596 writeTriplet(visit, "(", " |= ", ")");
597 break;
598
599 case EOpIndexDirect:
600 writeTriplet(visit, nullptr, "[", "]");
601 break;
602 case EOpIndexIndirect:
603 if (node->getAddIndexClamp())
604 {
605 if (visit == InVisit)
606 {
607 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
608 out << "[int(clamp(float(";
609 else
610 out << "[webgl_int_clamp(";
611 }
612 else if (visit == PostVisit)
613 {
614 TIntermTyped *left = node->getLeft();
615 TType leftType = left->getType();
616
617 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
618 out << "), 0.0, float(";
619 else
620 out << ", 0, ";
621
622 if (leftType.isUnsizedArray())
623 {
624 // For runtime-sized arrays in ESSL 3.10 we need to call the length method
625 // to get the length to clamp against. See ESSL 3.10 section 4.1.9. Note
626 // that a runtime-sized array expression is guaranteed not to have side
627 // effects, so it's fine to add the expression to the output twice.
628 ASSERT(mShaderVersion >= 310);
629 ASSERT(!left->hasSideEffects());
630 left->traverse(this);
631 out << ".length() - 1";
632 }
633 else
634 {
635 int maxSize;
636 if (leftType.isArray())
637 {
638 maxSize = static_cast<int>(leftType.getOutermostArraySize()) - 1;
639 }
640 else
641 {
642 maxSize = leftType.getNominalSize() - 1;
643 }
644 out << maxSize;
645 }
646 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
647 out << ")))]";
648 else
649 out << ")]";
650 }
651 }
652 else
653 {
654 writeTriplet(visit, nullptr, "[", "]");
655 }
656 break;
657 case EOpIndexDirectStruct:
658 if (visit == InVisit)
659 {
660 // Here we are writing out "foo.bar", where "foo" is struct
661 // and "bar" is field. In AST, it is represented as a binary
662 // node, where left child represents "foo" and right child "bar".
663 // The node itself represents ".". The struct field "bar" is
664 // actually stored as an index into TStructure::fields.
665 out << ".";
666 const TStructure *structure = node->getLeft()->getType().getStruct();
667 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
668 const TField *field = structure->fields()[index->getIConst(0)];
669
670 out << hashFieldName(field);
671 visitChildren = false;
672 }
673 break;
674 case EOpIndexDirectInterfaceBlock:
675 if (visit == InVisit)
676 {
677 out << ".";
678 const TInterfaceBlock *interfaceBlock =
679 node->getLeft()->getType().getInterfaceBlock();
680 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
681 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
682 out << hashFieldName(field);
683 visitChildren = false;
684 }
685 break;
686
687 case EOpAdd:
688 writeTriplet(visit, "(", " + ", ")");
689 break;
690 case EOpSub:
691 writeTriplet(visit, "(", " - ", ")");
692 break;
693 case EOpMul:
694 writeTriplet(visit, "(", " * ", ")");
695 break;
696 case EOpDiv:
697 writeTriplet(visit, "(", " / ", ")");
698 break;
699 case EOpIMod:
700 writeTriplet(visit, "(", " % ", ")");
701 break;
702 case EOpBitShiftLeft:
703 writeTriplet(visit, "(", " << ", ")");
704 break;
705 case EOpBitShiftRight:
706 writeTriplet(visit, "(", " >> ", ")");
707 break;
708 case EOpBitwiseAnd:
709 writeTriplet(visit, "(", " & ", ")");
710 break;
711 case EOpBitwiseXor:
712 writeTriplet(visit, "(", " ^ ", ")");
713 break;
714 case EOpBitwiseOr:
715 writeTriplet(visit, "(", " | ", ")");
716 break;
717
718 case EOpEqual:
719 writeTriplet(visit, "(", " == ", ")");
720 break;
721 case EOpNotEqual:
722 writeTriplet(visit, "(", " != ", ")");
723 break;
724 case EOpLessThan:
725 writeTriplet(visit, "(", " < ", ")");
726 break;
727 case EOpGreaterThan:
728 writeTriplet(visit, "(", " > ", ")");
729 break;
730 case EOpLessThanEqual:
731 writeTriplet(visit, "(", " <= ", ")");
732 break;
733 case EOpGreaterThanEqual:
734 writeTriplet(visit, "(", " >= ", ")");
735 break;
736
737 // Notice the fall-through.
738 case EOpVectorTimesScalar:
739 case EOpVectorTimesMatrix:
740 case EOpMatrixTimesVector:
741 case EOpMatrixTimesScalar:
742 case EOpMatrixTimesMatrix:
743 writeTriplet(visit, "(", " * ", ")");
744 break;
745
746 case EOpLogicalOr:
747 writeTriplet(visit, "(", " || ", ")");
748 break;
749 case EOpLogicalXor:
750 writeTriplet(visit, "(", " ^^ ", ")");
751 break;
752 case EOpLogicalAnd:
753 writeTriplet(visit, "(", " && ", ")");
754 break;
755 default:
756 UNREACHABLE();
757 }
758
759 return visitChildren;
760 }
761
visitUnary(Visit visit,TIntermUnary * node)762 bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
763 {
764 const char *preString = "";
765 const char *postString = ")";
766
767 switch (node->getOp())
768 {
769 case EOpNegative:
770 preString = "(-";
771 break;
772 case EOpPositive:
773 preString = "(+";
774 break;
775 case EOpLogicalNot:
776 preString = "(!";
777 break;
778 case EOpBitwiseNot:
779 preString = "(~";
780 break;
781
782 case EOpPostIncrement:
783 preString = "(";
784 postString = "++)";
785 break;
786 case EOpPostDecrement:
787 preString = "(";
788 postString = "--)";
789 break;
790 case EOpPreIncrement:
791 preString = "(++";
792 break;
793 case EOpPreDecrement:
794 preString = "(--";
795 break;
796 case EOpArrayLength:
797 preString = "((";
798 postString = ").length())";
799 break;
800
801 case EOpRadians:
802 case EOpDegrees:
803 case EOpSin:
804 case EOpCos:
805 case EOpTan:
806 case EOpAsin:
807 case EOpAcos:
808 case EOpAtan:
809 case EOpSinh:
810 case EOpCosh:
811 case EOpTanh:
812 case EOpAsinh:
813 case EOpAcosh:
814 case EOpAtanh:
815 case EOpExp:
816 case EOpLog:
817 case EOpExp2:
818 case EOpLog2:
819 case EOpSqrt:
820 case EOpInversesqrt:
821 case EOpAbs:
822 case EOpSign:
823 case EOpFloor:
824 case EOpTrunc:
825 case EOpRound:
826 case EOpRoundEven:
827 case EOpCeil:
828 case EOpFract:
829 case EOpIsnan:
830 case EOpIsinf:
831 case EOpFloatBitsToInt:
832 case EOpFloatBitsToUint:
833 case EOpIntBitsToFloat:
834 case EOpUintBitsToFloat:
835 case EOpPackSnorm2x16:
836 case EOpPackUnorm2x16:
837 case EOpPackHalf2x16:
838 case EOpUnpackSnorm2x16:
839 case EOpUnpackUnorm2x16:
840 case EOpUnpackHalf2x16:
841 case EOpPackUnorm4x8:
842 case EOpPackSnorm4x8:
843 case EOpUnpackUnorm4x8:
844 case EOpUnpackSnorm4x8:
845 case EOpLength:
846 case EOpNormalize:
847 case EOpDFdx:
848 case EOpDFdy:
849 case EOpFwidth:
850 case EOpTranspose:
851 case EOpDeterminant:
852 case EOpInverse:
853 case EOpAny:
854 case EOpAll:
855 case EOpLogicalNotComponentWise:
856 case EOpBitfieldReverse:
857 case EOpBitCount:
858 case EOpFindLSB:
859 case EOpFindMSB:
860 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
861 return true;
862 default:
863 UNREACHABLE();
864 }
865
866 writeTriplet(visit, preString, nullptr, postString);
867
868 return true;
869 }
870
visitTernary(Visit visit,TIntermTernary * node)871 bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
872 {
873 TInfoSinkBase &out = objSink();
874 // Notice two brackets at the beginning and end. The outer ones
875 // encapsulate the whole ternary expression. This preserves the
876 // order of precedence when ternary expressions are used in a
877 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
878 out << "((";
879 node->getCondition()->traverse(this);
880 out << ") ? (";
881 node->getTrueExpression()->traverse(this);
882 out << ") : (";
883 node->getFalseExpression()->traverse(this);
884 out << "))";
885 return false;
886 }
887
visitIfElse(Visit visit,TIntermIfElse * node)888 bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
889 {
890 TInfoSinkBase &out = objSink();
891
892 out << "if (";
893 node->getCondition()->traverse(this);
894 out << ")\n";
895
896 visitCodeBlock(node->getTrueBlock());
897
898 if (node->getFalseBlock())
899 {
900 out << "else\n";
901 visitCodeBlock(node->getFalseBlock());
902 }
903 return false;
904 }
905
visitSwitch(Visit visit,TIntermSwitch * node)906 bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
907 {
908 ASSERT(node->getStatementList());
909 writeTriplet(visit, "switch (", ") ", nullptr);
910 // The curly braces get written when visiting the statementList aggregate
911 return true;
912 }
913
visitCase(Visit visit,TIntermCase * node)914 bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
915 {
916 if (node->hasCondition())
917 {
918 writeTriplet(visit, "case (", nullptr, "):\n");
919 return true;
920 }
921 else
922 {
923 TInfoSinkBase &out = objSink();
924 out << "default:\n";
925 return false;
926 }
927 }
928
visitBlock(Visit visit,TIntermBlock * node)929 bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
930 {
931 TInfoSinkBase &out = objSink();
932 // Scope the blocks except when at the global scope.
933 if (getCurrentTraversalDepth() > 0)
934 {
935 out << "{\n";
936 }
937
938 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
939 iter != node->getSequence()->end(); ++iter)
940 {
941 TIntermNode *curNode = *iter;
942 ASSERT(curNode != nullptr);
943 curNode->traverse(this);
944
945 if (isSingleStatement(curNode))
946 out << ";\n";
947 }
948
949 // Scope the blocks except when at the global scope.
950 if (getCurrentTraversalDepth() > 0)
951 {
952 out << "}\n";
953 }
954 return false;
955 }
956
visitFunctionDefinition(Visit visit,TIntermFunctionDefinition * node)957 bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
958 {
959 TIntermFunctionPrototype *prototype = node->getFunctionPrototype();
960 prototype->traverse(this);
961 visitCodeBlock(node->getBody());
962
963 // Fully processed; no need to visit children.
964 return false;
965 }
966
visitGlobalQualifierDeclaration(Visit visit,TIntermGlobalQualifierDeclaration * node)967 bool TOutputGLSLBase::visitGlobalQualifierDeclaration(Visit visit,
968 TIntermGlobalQualifierDeclaration *node)
969 {
970 TInfoSinkBase &out = objSink();
971 ASSERT(visit == PreVisit);
972 const TIntermSymbol *symbol = node->getSymbol();
973 out << (node->isPrecise() ? "precise " : "invariant ") << hashName(&symbol->variable());
974 return false;
975 }
976
visitFunctionPrototype(TIntermFunctionPrototype * node)977 void TOutputGLSLBase::visitFunctionPrototype(TIntermFunctionPrototype *node)
978 {
979 TInfoSinkBase &out = objSink();
980
981 const TType &type = node->getType();
982 writeVariableType(type, node->getFunction(), false);
983 if (type.isArray())
984 out << ArrayString(type);
985
986 out << " " << hashFunctionNameIfNeeded(node->getFunction());
987
988 out << "(";
989 writeFunctionParameters(node->getFunction());
990 out << ")";
991 }
992
visitAggregate(Visit visit,TIntermAggregate * node)993 bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
994 {
995 bool visitChildren = true;
996 TInfoSinkBase &out = objSink();
997 switch (node->getOp())
998 {
999 case EOpCallFunctionInAST:
1000 case EOpCallInternalRawFunction:
1001 case EOpCallBuiltInFunction:
1002 // Function call.
1003 if (visit == PreVisit)
1004 {
1005 if (node->getOp() == EOpCallBuiltInFunction)
1006 {
1007 out << translateTextureFunction(node->getFunction()->name(), mCompileOptions);
1008 }
1009 else
1010 {
1011 out << hashFunctionNameIfNeeded(node->getFunction());
1012 }
1013 out << "(";
1014 }
1015 else if (visit == InVisit)
1016 out << ", ";
1017 else
1018 out << ")";
1019 break;
1020 case EOpConstruct:
1021 writeConstructorTriplet(visit, node->getType());
1022 break;
1023
1024 case EOpEqualComponentWise:
1025 case EOpNotEqualComponentWise:
1026 case EOpLessThanComponentWise:
1027 case EOpGreaterThanComponentWise:
1028 case EOpLessThanEqualComponentWise:
1029 case EOpGreaterThanEqualComponentWise:
1030 case EOpMod:
1031 case EOpModf:
1032 case EOpPow:
1033 case EOpAtan:
1034 case EOpMin:
1035 case EOpMax:
1036 case EOpClamp:
1037 case EOpMix:
1038 case EOpStep:
1039 case EOpSmoothstep:
1040 case EOpFma:
1041 case EOpFrexp:
1042 case EOpLdexp:
1043 case EOpDistance:
1044 case EOpDot:
1045 case EOpCross:
1046 case EOpFaceforward:
1047 case EOpReflect:
1048 case EOpRefract:
1049 case EOpMulMatrixComponentWise:
1050 case EOpOuterProduct:
1051 case EOpBitfieldExtract:
1052 case EOpBitfieldInsert:
1053 case EOpUaddCarry:
1054 case EOpUsubBorrow:
1055 case EOpUmulExtended:
1056 case EOpImulExtended:
1057 case EOpBarrier:
1058 case EOpMemoryBarrier:
1059 case EOpMemoryBarrierAtomicCounter:
1060 case EOpMemoryBarrierBuffer:
1061 case EOpMemoryBarrierImage:
1062 case EOpMemoryBarrierShared:
1063 case EOpGroupMemoryBarrier:
1064 case EOpAtomicAdd:
1065 case EOpAtomicMin:
1066 case EOpAtomicMax:
1067 case EOpAtomicAnd:
1068 case EOpAtomicOr:
1069 case EOpAtomicXor:
1070 case EOpAtomicExchange:
1071 case EOpAtomicCompSwap:
1072 case EOpEmitVertex:
1073 case EOpEndPrimitive:
1074 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
1075 break;
1076 default:
1077 UNREACHABLE();
1078 }
1079 return visitChildren;
1080 }
1081
visitDeclaration(Visit visit,TIntermDeclaration * node)1082 bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1083 {
1084 TInfoSinkBase &out = objSink();
1085
1086 // Variable declaration.
1087 if (visit == PreVisit)
1088 {
1089 const TIntermSequence &sequence = *(node->getSequence());
1090 TIntermTyped *variable = sequence.front()->getAsTyped();
1091 TIntermSymbol *symbolNode = variable->getAsSymbolNode();
1092 if (!symbolNode || (symbolNode->getName() != "gl_ClipDistance" &&
1093 symbolNode->getName() != "gl_CullDistance"))
1094 {
1095 // gl_Clip/CullDistance re-declaration doesn't need layout.
1096 writeLayoutQualifier(variable);
1097 }
1098 writeVariableType(variable->getType(), symbolNode ? &symbolNode->variable() : nullptr,
1099 false);
1100 if (variable->getAsSymbolNode() == nullptr ||
1101 variable->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty)
1102 {
1103 out << " ";
1104 }
1105 mDeclaringVariable = true;
1106 }
1107 else if (visit == InVisit)
1108 {
1109 UNREACHABLE();
1110 }
1111 else
1112 {
1113 mDeclaringVariable = false;
1114 }
1115 return true;
1116 }
1117
visitLoop(Visit visit,TIntermLoop * node)1118 bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
1119 {
1120 TInfoSinkBase &out = objSink();
1121
1122 TLoopType loopType = node->getType();
1123
1124 if (loopType == ELoopFor) // for loop
1125 {
1126 out << "for (";
1127 if (node->getInit())
1128 node->getInit()->traverse(this);
1129 out << "; ";
1130
1131 if (node->getCondition())
1132 node->getCondition()->traverse(this);
1133 out << "; ";
1134
1135 if (node->getExpression())
1136 node->getExpression()->traverse(this);
1137 out << ")\n";
1138
1139 visitCodeBlock(node->getBody());
1140 }
1141 else if (loopType == ELoopWhile) // while loop
1142 {
1143 out << "while (";
1144 ASSERT(node->getCondition() != nullptr);
1145 node->getCondition()->traverse(this);
1146 out << ")\n";
1147
1148 visitCodeBlock(node->getBody());
1149 }
1150 else // do-while loop
1151 {
1152 ASSERT(loopType == ELoopDoWhile);
1153 out << "do\n";
1154
1155 visitCodeBlock(node->getBody());
1156
1157 out << "while (";
1158 ASSERT(node->getCondition() != nullptr);
1159 node->getCondition()->traverse(this);
1160 out << ");\n";
1161 }
1162
1163 // No need to visit children. They have been already processed in
1164 // this function.
1165 return false;
1166 }
1167
visitBranch(Visit visit,TIntermBranch * node)1168 bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
1169 {
1170 switch (node->getFlowOp())
1171 {
1172 case EOpKill:
1173 writeTriplet(visit, "discard", nullptr, nullptr);
1174 break;
1175 case EOpBreak:
1176 writeTriplet(visit, "break", nullptr, nullptr);
1177 break;
1178 case EOpContinue:
1179 writeTriplet(visit, "continue", nullptr, nullptr);
1180 break;
1181 case EOpReturn:
1182 writeTriplet(visit, "return ", nullptr, nullptr);
1183 break;
1184 default:
1185 UNREACHABLE();
1186 }
1187
1188 return true;
1189 }
1190
visitCodeBlock(TIntermBlock * node)1191 void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
1192 {
1193 TInfoSinkBase &out = objSink();
1194 if (node != nullptr)
1195 {
1196 node->traverse(this);
1197 // Single statements not part of a sequence need to be terminated
1198 // with semi-colon.
1199 if (isSingleStatement(node))
1200 out << ";\n";
1201 }
1202 else
1203 {
1204 out << "{\n}\n"; // Empty code block.
1205 }
1206 }
1207
visitPreprocessorDirective(TIntermPreprocessorDirective * node)1208 void TOutputGLSLBase::visitPreprocessorDirective(TIntermPreprocessorDirective *node)
1209 {
1210 TInfoSinkBase &out = objSink();
1211
1212 out << "\n";
1213
1214 switch (node->getDirective())
1215 {
1216 case PreprocessorDirective::Define:
1217 out << "#define";
1218 break;
1219 case PreprocessorDirective::Endif:
1220 out << "#endif";
1221 break;
1222 case PreprocessorDirective::If:
1223 out << "#if";
1224 break;
1225 case PreprocessorDirective::Ifdef:
1226 out << "#ifdef";
1227 break;
1228
1229 default:
1230 UNREACHABLE();
1231 break;
1232 }
1233
1234 if (!node->getCommand().empty())
1235 {
1236 out << " " << node->getCommand();
1237 }
1238
1239 out << "\n";
1240 }
1241
getTypeName(const TType & type)1242 ImmutableString TOutputGLSLBase::getTypeName(const TType &type)
1243 {
1244 if (type.getBasicType() == EbtSamplerVideoWEBGL)
1245 {
1246 // TODO(http://anglebug.com/3889): translate SamplerVideoWEBGL into different token
1247 // when necessary (e.g. on Android devices)
1248 return ImmutableString("sampler2D");
1249 }
1250
1251 return GetTypeName(type, mHashFunction, &mNameMap);
1252 }
1253
hashName(const TSymbol * symbol)1254 ImmutableString TOutputGLSLBase::hashName(const TSymbol *symbol)
1255 {
1256 return HashName(symbol, mHashFunction, &mNameMap);
1257 }
1258
hashFieldName(const TField * field)1259 ImmutableString TOutputGLSLBase::hashFieldName(const TField *field)
1260 {
1261 ASSERT(field->symbolType() != SymbolType::Empty);
1262 if (field->symbolType() == SymbolType::UserDefined)
1263 {
1264 return HashName(field->name(), mHashFunction, &mNameMap);
1265 }
1266
1267 return field->name();
1268 }
1269
hashFunctionNameIfNeeded(const TFunction * func)1270 ImmutableString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunction *func)
1271 {
1272 if (func->isMain())
1273 {
1274 return func->name();
1275 }
1276 else
1277 {
1278 return hashName(func);
1279 }
1280 }
1281
declareStruct(const TStructure * structure)1282 void TOutputGLSLBase::declareStruct(const TStructure *structure)
1283 {
1284 TInfoSinkBase &out = objSink();
1285
1286 out << "struct ";
1287
1288 if (structure->symbolType() != SymbolType::Empty)
1289 {
1290 out << hashName(structure) << " ";
1291 }
1292 out << "{\n";
1293 const TFieldList &fields = structure->fields();
1294 for (size_t i = 0; i < fields.size(); ++i)
1295 {
1296 const TField *field = fields[i];
1297 if (writeVariablePrecision(field->type()->getPrecision()))
1298 out << " ";
1299 out << getTypeName(*field->type()) << " " << hashFieldName(field);
1300 if (field->type()->isArray())
1301 out << ArrayString(*field->type());
1302 out << ";\n";
1303 }
1304 out << "}";
1305 }
1306
declareInterfaceBlockLayout(const TType & type)1307 void TOutputGLSLBase::declareInterfaceBlockLayout(const TType &type)
1308 {
1309 // 4.4.5 Uniform and Shader Storage Block Layout Qualifiers in GLSL 4.5 spec.
1310 // Layout qualifiers can be used for uniform and shader storage blocks,
1311 // but not for non-block uniform declarations.
1312 if (IsShaderIoBlock(type.getQualifier()))
1313 {
1314 return;
1315 }
1316
1317 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
1318 TInfoSinkBase &out = objSink();
1319
1320 out << "layout(";
1321
1322 switch (interfaceBlock->blockStorage())
1323 {
1324 case EbsUnspecified:
1325 case EbsShared:
1326 // Default block storage is shared.
1327 out << "shared";
1328 break;
1329
1330 case EbsPacked:
1331 out << "packed";
1332 break;
1333
1334 case EbsStd140:
1335 out << "std140";
1336 break;
1337
1338 case EbsStd430:
1339 out << "std430";
1340 break;
1341
1342 default:
1343 UNREACHABLE();
1344 break;
1345 }
1346
1347 if (interfaceBlock->blockBinding() >= 0)
1348 {
1349 out << ", ";
1350 out << "binding = " << interfaceBlock->blockBinding();
1351 }
1352
1353 out << ") ";
1354 }
1355
getVariableInterpolation(TQualifier qualifier)1356 const char *getVariableInterpolation(TQualifier qualifier)
1357 {
1358 switch (qualifier)
1359 {
1360 case EvqSmoothOut:
1361 return "smooth out ";
1362 case EvqFlatOut:
1363 return "flat out ";
1364 case EvqNoPerspectiveOut:
1365 return "noperspective out ";
1366 case EvqCentroidOut:
1367 return "centroid out ";
1368 case EvqSmoothIn:
1369 return "smooth in ";
1370 case EvqFlatIn:
1371 return "flat in ";
1372 case EvqNoPerspectiveIn:
1373 return "noperspective in ";
1374 case EvqCentroidIn:
1375 return "centroid in ";
1376 default:
1377 break;
1378 }
1379 return nullptr;
1380 }
1381
declareInterfaceBlock(const TType & type)1382 void TOutputGLSLBase::declareInterfaceBlock(const TType &type)
1383 {
1384 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
1385 TInfoSinkBase &out = objSink();
1386
1387 out << hashName(interfaceBlock) << "{\n";
1388 const TFieldList &fields = interfaceBlock->fields();
1389 for (const TField *field : fields)
1390 {
1391 if (!IsShaderIoBlock(type.getQualifier()) && type.getQualifier() != EvqPatchIn &&
1392 type.getQualifier() != EvqPatchOut)
1393 {
1394 writeFieldLayoutQualifier(field);
1395 }
1396 out << getMemoryQualifiers(*field->type());
1397 if (writeVariablePrecision(field->type()->getPrecision()))
1398 out << " ";
1399
1400 const char *qualifier = getVariableInterpolation(field->type()->getQualifier());
1401 if (qualifier != nullptr)
1402 out << qualifier;
1403
1404 out << getTypeName(*field->type()) << " " << hashFieldName(field);
1405
1406 if (field->type()->isArray())
1407 out << ArrayString(*field->type());
1408 out << ";\n";
1409 }
1410 out << "}";
1411 }
1412
WriteGeometryShaderLayoutQualifiers(TInfoSinkBase & out,sh::TLayoutPrimitiveType inputPrimitive,int invocations,sh::TLayoutPrimitiveType outputPrimitive,int maxVertices)1413 void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
1414 sh::TLayoutPrimitiveType inputPrimitive,
1415 int invocations,
1416 sh::TLayoutPrimitiveType outputPrimitive,
1417 int maxVertices)
1418 {
1419 // Omit 'invocations = 1'
1420 if (inputPrimitive != EptUndefined || invocations > 1)
1421 {
1422 out << "layout (";
1423
1424 if (inputPrimitive != EptUndefined)
1425 {
1426 out << getGeometryShaderPrimitiveTypeString(inputPrimitive);
1427 }
1428
1429 if (invocations > 1)
1430 {
1431 if (inputPrimitive != EptUndefined)
1432 {
1433 out << ", ";
1434 }
1435 out << "invocations = " << invocations;
1436 }
1437 out << ") in;\n";
1438 }
1439
1440 if (outputPrimitive != EptUndefined || maxVertices != -1)
1441 {
1442 out << "layout (";
1443
1444 if (outputPrimitive != EptUndefined)
1445 {
1446 out << getGeometryShaderPrimitiveTypeString(outputPrimitive);
1447 }
1448
1449 if (maxVertices != -1)
1450 {
1451 if (outputPrimitive != EptUndefined)
1452 {
1453 out << ", ";
1454 }
1455 out << "max_vertices = " << maxVertices;
1456 }
1457 out << ") out;\n";
1458 }
1459 }
1460
WriteTessControlShaderLayoutQualifiers(TInfoSinkBase & out,int inputVertices)1461 void WriteTessControlShaderLayoutQualifiers(TInfoSinkBase &out, int inputVertices)
1462 {
1463 if (inputVertices != 0)
1464 {
1465 out << "layout (vertices = " << inputVertices << ") out;\n";
1466 }
1467 }
1468
WriteTessEvaluationShaderLayoutQualifiers(TInfoSinkBase & out,sh::TLayoutTessEvaluationType inputPrimitive,sh::TLayoutTessEvaluationType inputVertexSpacing,sh::TLayoutTessEvaluationType inputOrdering,sh::TLayoutTessEvaluationType inputPoint)1469 void WriteTessEvaluationShaderLayoutQualifiers(TInfoSinkBase &out,
1470 sh::TLayoutTessEvaluationType inputPrimitive,
1471 sh::TLayoutTessEvaluationType inputVertexSpacing,
1472 sh::TLayoutTessEvaluationType inputOrdering,
1473 sh::TLayoutTessEvaluationType inputPoint)
1474 {
1475 if (inputPrimitive != EtetUndefined)
1476 {
1477 out << "layout (";
1478 out << getTessEvaluationShaderTypeString(inputPrimitive);
1479 if (inputVertexSpacing != EtetUndefined)
1480 {
1481 out << ", " << getTessEvaluationShaderTypeString(inputVertexSpacing);
1482 }
1483 if (inputOrdering != EtetUndefined)
1484 {
1485 out << ", " << getTessEvaluationShaderTypeString(inputOrdering);
1486 }
1487 if (inputPoint != EtetUndefined)
1488 {
1489 out << ", " << getTessEvaluationShaderTypeString(inputPoint);
1490 }
1491 out << ") in;\n";
1492 }
1493 }
1494
1495 // If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
1496 // variables with specified layout qualifiers are copied. Additional checks are needed against the
1497 // type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
1498 // TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
1499 // NeedsToWriteLayoutQualifier.
NeedsToWriteLayoutQualifier(const TType & type)1500 bool NeedsToWriteLayoutQualifier(const TType &type)
1501 {
1502 if (type.getBasicType() == EbtInterfaceBlock)
1503 {
1504 return true;
1505 }
1506
1507 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
1508
1509 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
1510 IsVarying(type.getQualifier())) &&
1511 layoutQualifier.location >= 0)
1512 {
1513 return true;
1514 }
1515
1516 if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true)
1517 {
1518 return true;
1519 }
1520
1521 if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
1522 {
1523 return true;
1524 }
1525
1526 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
1527 {
1528 return true;
1529 }
1530 return false;
1531 }
1532
1533 } // namespace sh
1534