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