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