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