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