Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/angle/translator_gn/./../../../../third_party/angle/src/compiler/translator/glsl/OutputGLSLBase.cpp
Warning:line 812, column 17
Value stored to 'preString' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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