2 // Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
3 // Copyright (C) 2013-2016 LunarG, Inc.
4 // Copyright (C) 2015-2020 Google, Inc.
6 // All rights reserved.
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
12 // Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
15 // Redistributions in binary form must reproduce the above
16 // copyright notice, this list of conditions and the following
17 // disclaimer in the documentation and/or other materials provided
18 // with the distribution.
20 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
21 // contributors may be used to endorse or promote products derived
22 // from this software without specific prior written permission.
24 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 // POSSIBILITY OF SUCH DAMAGE.
39 // Implement the top-level of interface to the compiler/linker,
40 // as defined in ShaderLang.h
41 // This is the platform independent interface between an OGL driver
42 // and the shading language compiler/linker.
48 #include "SymbolTable.h"
49 #include "ParseHelper.h"
51 #include "ScanContext.h"
54 #include "../HLSL/hlslParseHelper.h"
55 #include "../HLSL/hlslParseables.h"
56 #include "../HLSL/hlslScanContext.h"
59 #include "../Include/ShHandle.h"
60 #include "../../OGLCompilersDLL/InitializeDll.h"
62 #include "preprocessor/PpContext.h"
65 #include "../Public/ShaderLang.h"
66 #include "reflection.h"
68 #include "Initialize.h"
70 // TODO: this really shouldn't be here, it is only because of the trial addition
71 // of printing pre-processed tokens, which requires knowing the string literal
72 // token to print ", but none of that seems appropriate for this file.
73 #include "preprocessor/PpTokens.h"
75 // Build-time generated includes
76 #include "glslang/build_info.h"
78 namespace { // anonymous namespace for file-local functions and symbols
80 // Total number of successful initializers of glslang: a refcount
81 // Shared global; access should be protected by a global mutex/critical section.
82 int NumberOfClients = 0;
84 using namespace glslang;
86 // Create a language specific version of parseables.
87 TBuiltInParseables* CreateBuiltInParseables(TInfoSink& infoSink, EShSource source)
90 case EShSourceGlsl: return new TBuiltIns(); // GLSL builtIns
92 case EShSourceHlsl: return new TBuiltInParseablesHlsl(); // HLSL intrinsics
96 infoSink.info.message(EPrefixInternalError, "Unable to determine source language");
101 // Create a language specific version of a parse context.
102 TParseContextBase* CreateParseContext(TSymbolTable& symbolTable, TIntermediate& intermediate,
103 int version, EProfile profile, EShSource source,
104 EShLanguage language, TInfoSink& infoSink,
105 SpvVersion spvVersion, bool forwardCompatible, EShMessages messages,
106 bool parsingBuiltIns, std::string sourceEntryPointName = "")
109 case EShSourceGlsl: {
110 if (sourceEntryPointName.size() == 0)
111 intermediate.setEntryPointName("main");
112 TString entryPoint = sourceEntryPointName.c_str();
113 return new TParseContext(symbolTable, intermediate, parsingBuiltIns, version, profile, spvVersion,
114 language, infoSink, forwardCompatible, messages, &entryPoint);
118 return new HlslParseContext(symbolTable, intermediate, parsingBuiltIns, version, profile, spvVersion,
119 language, infoSink, sourceEntryPointName.c_str(), forwardCompatible, messages);
122 infoSink.info.message(EPrefixInternalError, "Unable to determine source language");
127 // Local mapping functions for making arrays of symbol tables....
129 const int VersionCount = 17; // index range in MapVersionToIndex
131 int MapVersionToIndex(int version)
136 case 100: index = 0; break;
137 case 110: index = 1; break;
138 case 120: index = 2; break;
139 case 130: index = 3; break;
140 case 140: index = 4; break;
141 case 150: index = 5; break;
142 case 300: index = 6; break;
143 case 330: index = 7; break;
144 case 400: index = 8; break;
145 case 410: index = 9; break;
146 case 420: index = 10; break;
147 case 430: index = 11; break;
148 case 440: index = 12; break;
149 case 310: index = 13; break;
150 case 450: index = 14; break;
151 case 500: index = 0; break; // HLSL
152 case 320: index = 15; break;
153 case 460: index = 16; break;
154 default: assert(0); break;
157 assert(index < VersionCount);
162 const int SpvVersionCount = 4; // index range in MapSpvVersionToIndex
164 int MapSpvVersionToIndex(const SpvVersion& spvVersion)
168 if (spvVersion.openGl > 0)
170 else if (spvVersion.vulkan > 0) {
171 if (!spvVersion.vulkanRelaxed)
177 assert(index < SpvVersionCount);
182 const int ProfileCount = 4; // index range in MapProfileToIndex
184 int MapProfileToIndex(EProfile profile)
189 case ENoProfile: index = 0; break;
190 case ECoreProfile: index = 1; break;
191 case ECompatibilityProfile: index = 2; break;
192 case EEsProfile: index = 3; break;
196 assert(index < ProfileCount);
201 const int SourceCount = 2;
203 int MapSourceToIndex(EShSource source)
208 case EShSourceGlsl: index = 0; break;
209 case EShSourceHlsl: index = 1; break;
213 assert(index < SourceCount);
218 // only one of these needed for non-ES; ES needs 2 for different precision defaults of built-ins
219 enum EPrecisionClass {
225 // A process-global symbol table per version per profile for built-ins common
226 // to multiple stages (languages), and a process-global symbol table per version
227 // per profile per stage for built-ins unique to each stage. They will be sparsely
228 // populated, so they will only be generated as needed.
230 // Each has a different set of built-ins, and we want to preserve that from
231 // compile to compile.
233 TSymbolTable* CommonSymbolTable[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EPcCount] = {};
234 TSymbolTable* SharedSymbolTables[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EShLangCount] = {};
236 TPoolAllocator* PerProcessGPA = nullptr;
239 // Parse and add to the given symbol table the content of the given shader string.
241 bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
242 EShSource source, TInfoSink& infoSink, TSymbolTable& symbolTable)
244 TIntermediate intermediate(language, version, profile);
246 intermediate.setSource(source);
248 std::unique_ptr<TParseContextBase> parseContext(CreateParseContext(symbolTable, intermediate, version, profile, source,
249 language, infoSink, spvVersion, true, EShMsgDefault,
252 TShader::ForbidIncluder includer;
253 TPpContext ppContext(*parseContext, "", includer);
254 TScanContext scanContext(*parseContext);
255 parseContext->setScanContext(&scanContext);
256 parseContext->setPpContext(&ppContext);
259 // Push the symbol table to give it an initial scope. This
260 // push should not have a corresponding pop, so that built-ins
261 // are preserved, and the test for an empty table fails.
266 const char* builtInShaders[2];
267 size_t builtInLengths[2];
268 builtInShaders[0] = builtIns.c_str();
269 builtInLengths[0] = builtIns.size();
271 if (builtInLengths[0] == 0)
274 TInputScanner input(1, builtInShaders, builtInLengths);
275 if (! parseContext->parseShaderStrings(ppContext, input) != 0) {
276 infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
277 printf("Unable to parse built-ins\n%s\n", infoSink.info.c_str());
278 printf("%s\n", builtInShaders[0]);
286 int CommonIndex(EProfile profile, EShLanguage language)
288 return (profile == EEsProfile && language == EShLangFragment) ? EPcFragment : EPcGeneral;
292 // To initialize per-stage shared tables, with the common table already complete.
294 void InitializeStageSymbolTable(TBuiltInParseables& builtInParseables, int version, EProfile profile, const SpvVersion& spvVersion,
295 EShLanguage language, EShSource source, TInfoSink& infoSink, TSymbolTable** commonTable,
296 TSymbolTable** symbolTables)
299 profile = EEsProfile;
301 #elif defined(GLSLANG_ANGLE)
302 profile = ECoreProfile;
306 (*symbolTables[language]).adoptLevels(*commonTable[CommonIndex(profile, language)]);
307 InitializeSymbolTable(builtInParseables.getStageString(language), version, profile, spvVersion, language, source,
308 infoSink, *symbolTables[language]);
309 builtInParseables.identifyBuiltIns(version, profile, spvVersion, language, *symbolTables[language]);
310 if (profile == EEsProfile && version >= 300)
311 (*symbolTables[language]).setNoBuiltInRedeclarations();
313 (*symbolTables[language]).setSeparateNameSpaces();
317 // Initialize the full set of shareable symbol tables;
318 // The common (cross-stage) and those shareable per-stage.
320 bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TSymbolTable** symbolTables, int version, EProfile profile, const SpvVersion& spvVersion, EShSource source)
323 profile = EEsProfile;
325 #elif defined(GLSLANG_ANGLE)
326 profile = ECoreProfile;
330 std::unique_ptr<TBuiltInParseables> builtInParseables(CreateBuiltInParseables(infoSink, source));
332 if (builtInParseables == nullptr)
335 builtInParseables->initialize(version, profile, spvVersion);
337 // do the common tables
338 InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangVertex, source,
339 infoSink, *commonTable[EPcGeneral]);
340 if (profile == EEsProfile)
341 InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangFragment, source,
342 infoSink, *commonTable[EPcFragment]);
344 // do the per-stage tables
346 // always have vertex and fragment
347 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangVertex, source,
348 infoSink, commonTable, symbolTables);
349 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangFragment, source,
350 infoSink, commonTable, symbolTables);
353 // check for tessellation
354 if ((profile != EEsProfile && version >= 150) ||
355 (profile == EEsProfile && version >= 310)) {
356 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessControl, source,
357 infoSink, commonTable, symbolTables);
358 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessEvaluation, source,
359 infoSink, commonTable, symbolTables);
362 // check for geometry
363 if ((profile != EEsProfile && version >= 150) ||
364 (profile == EEsProfile && version >= 310))
365 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangGeometry, source,
366 infoSink, commonTable, symbolTables);
369 if ((profile != EEsProfile && version >= 420) ||
370 (profile == EEsProfile && version >= 310))
371 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCompute, source,
372 infoSink, commonTable, symbolTables);
374 #ifndef GLSLANG_ANGLE
375 // check for ray tracing stages
376 if (profile != EEsProfile && version >= 450) {
377 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangRayGen, source,
378 infoSink, commonTable, symbolTables);
379 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangIntersect, source,
380 infoSink, commonTable, symbolTables);
381 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangAnyHit, source,
382 infoSink, commonTable, symbolTables);
383 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangClosestHit, source,
384 infoSink, commonTable, symbolTables);
385 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangMiss, source,
386 infoSink, commonTable, symbolTables);
387 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCallable, source,
388 infoSink, commonTable, symbolTables);
392 if ((profile != EEsProfile && version >= 450) ||
393 (profile == EEsProfile && version >= 320))
394 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangMeshNV, source,
395 infoSink, commonTable, symbolTables);
398 if ((profile != EEsProfile && version >= 450) ||
399 (profile == EEsProfile && version >= 320))
400 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTaskNV, source,
401 infoSink, commonTable, symbolTables);
402 #endif // !GLSLANG_ANGLE
403 #endif // !GLSLANG_WEB
408 bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& infoSink, TSymbolTable& symbolTable, int version,
409 EProfile profile, const SpvVersion& spvVersion, EShLanguage language, EShSource source)
411 std::unique_ptr<TBuiltInParseables> builtInParseables(CreateBuiltInParseables(infoSink, source));
413 if (builtInParseables == nullptr)
416 builtInParseables->initialize(*resources, version, profile, spvVersion, language);
417 InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, language, source, infoSink, symbolTable);
418 builtInParseables->identifyBuiltIns(version, profile, spvVersion, language, symbolTable, *resources);
424 // To do this on the fly, we want to leave the current state of our thread's
425 // pool allocator intact, so:
426 // - Switch to a new pool for parsing the built-ins
427 // - Do the parsing, which builds the symbol table, using the new pool
428 // - Switch to the process-global pool to save a copy of the resulting symbol table
429 // - Free up the new pool used to parse the built-ins
430 // - Switch back to the original thread's pool
432 // This only gets done the first time any thread needs a particular symbol table
433 // (lazy evaluation).
435 void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& spvVersion, EShSource source)
439 // Make sure only one thread tries to do this at a time
440 glslang::GetGlobalLock();
442 // See if it's already been done for this version/profile combination
443 int versionIndex = MapVersionToIndex(version);
444 int spvVersionIndex = MapSpvVersionToIndex(spvVersion);
445 int profileIndex = MapProfileToIndex(profile);
446 int sourceIndex = MapSourceToIndex(source);
447 if (CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][EPcGeneral]) {
448 glslang::ReleaseGlobalLock();
453 // Switch to a new pool
454 TPoolAllocator& previousAllocator = GetThreadPoolAllocator();
455 TPoolAllocator* builtInPoolAllocator = new TPoolAllocator;
456 SetThreadPoolAllocator(builtInPoolAllocator);
458 // Dynamically allocate the local symbol tables so we can control when they are deallocated WRT when the pool is popped.
459 TSymbolTable* commonTable[EPcCount];
460 TSymbolTable* stageTables[EShLangCount];
461 for (int precClass = 0; precClass < EPcCount; ++precClass)
462 commonTable[precClass] = new TSymbolTable;
463 for (int stage = 0; stage < EShLangCount; ++stage)
464 stageTables[stage] = new TSymbolTable;
466 // Generate the local symbol tables using the new pool
467 InitializeSymbolTables(infoSink, commonTable, stageTables, version, profile, spvVersion, source);
469 // Switch to the process-global pool
470 SetThreadPoolAllocator(PerProcessGPA);
472 // Copy the local symbol tables from the new pool to the global tables using the process-global pool
473 for (int precClass = 0; precClass < EPcCount; ++precClass) {
474 if (! commonTable[precClass]->isEmpty()) {
475 CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass] = new TSymbolTable;
476 CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass]->copyTable(*commonTable[precClass]);
477 CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass]->readOnly();
480 for (int stage = 0; stage < EShLangCount; ++stage) {
481 if (! stageTables[stage]->isEmpty()) {
482 SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage] = new TSymbolTable;
483 SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->adoptLevels(*CommonSymbolTable
484 [versionIndex][spvVersionIndex][profileIndex][sourceIndex][CommonIndex(profile, (EShLanguage)stage)]);
485 SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->copyTable(*stageTables[stage]);
486 SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->readOnly();
490 // Clean up the local tables before deleting the pool they used.
491 for (int precClass = 0; precClass < EPcCount; ++precClass)
492 delete commonTable[precClass];
493 for (int stage = 0; stage < EShLangCount; ++stage)
494 delete stageTables[stage];
496 delete builtInPoolAllocator;
497 SetThreadPoolAllocator(&previousAllocator);
499 glslang::ReleaseGlobalLock();
502 // Function to Print all builtins
503 void DumpBuiltinSymbolTable(TInfoSink& infoSink, const TSymbolTable& symbolTable)
505 #if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE)
506 infoSink.debug << "BuiltinSymbolTable {\n";
508 symbolTable.dump(infoSink, true);
510 infoSink.debug << "}\n";
514 // Return true if the shader was correctly specified for version/profile/stage.
515 bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNotFirst, int defaultVersion,
516 EShSource source, int& version, EProfile& profile, const SpvVersion& spvVersion)
518 const int FirstProfileVersion = 150;
521 if (source == EShSourceHlsl) {
522 version = 500; // shader model; currently a characteristic of glslang, not the input
523 profile = ECoreProfile; // allow doubles in prototype parsing
529 version = defaultVersion;
530 // infoSink.info.message(EPrefixWarning, "#version: statement missing; use #version on first line of shader");
533 // Get a good profile...
534 if (profile == ENoProfile) {
535 if (version == 300 || version == 310 || version == 320) {
537 infoSink.info.message(EPrefixError, "#version: versions 300, 310, and 320 require specifying the 'es' profile");
538 profile = EEsProfile;
539 } else if (version == 100)
540 profile = EEsProfile;
541 else if (version >= FirstProfileVersion)
542 profile = ECoreProfile;
544 profile = ENoProfile;
546 // a profile was provided...
549 infoSink.info.message(EPrefixError, "#version: versions before 150 do not allow a profile token");
551 profile = EEsProfile;
553 profile = ENoProfile;
554 } else if (version == 300 || version == 310 || version == 320) {
555 if (profile != EEsProfile) {
557 infoSink.info.message(EPrefixError, "#version: versions 300, 310, and 320 support only the es profile");
559 profile = EEsProfile;
561 if (profile == EEsProfile) {
563 infoSink.info.message(EPrefixError, "#version: only version 300, 310, and 320 support the es profile");
564 if (version >= FirstProfileVersion)
565 profile = ECoreProfile;
567 profile = ENoProfile;
569 // else: typical desktop case... e.g., "#version 410 core"
599 infoSink.info.message(EPrefixError, "version not supported");
600 if (profile == EEsProfile)
604 profile = ECoreProfile;
609 #if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE)
610 // Correct for stage type...
612 case EShLangGeometry:
613 if ((profile == EEsProfile && version < 310) ||
614 (profile != EEsProfile && version < 150)) {
616 infoSink.info.message(EPrefixError, "#version: geometry shaders require es profile with version 310 or non-es profile with version 150 or above");
617 version = (profile == EEsProfile) ? 310 : 150;
618 if (profile == EEsProfile || profile == ENoProfile)
619 profile = ECoreProfile;
622 case EShLangTessControl:
623 case EShLangTessEvaluation:
624 if ((profile == EEsProfile && version < 310) ||
625 (profile != EEsProfile && version < 150)) {
627 infoSink.info.message(EPrefixError, "#version: tessellation shaders require es profile with version 310 or non-es profile with version 150 or above");
628 version = (profile == EEsProfile) ? 310 : 400; // 150 supports the extension, correction is to 400 which does not
629 if (profile == EEsProfile || profile == ENoProfile)
630 profile = ECoreProfile;
634 if ((profile == EEsProfile && version < 310) ||
635 (profile != EEsProfile && version < 420)) {
637 infoSink.info.message(EPrefixError, "#version: compute shaders require es profile with version 310 or above, or non-es profile with version 420 or above");
638 version = profile == EEsProfile ? 310 : 420;
642 case EShLangIntersect:
644 case EShLangClosestHit:
646 case EShLangCallable:
647 if (profile == EEsProfile || version < 460) {
649 infoSink.info.message(EPrefixError, "#version: ray tracing shaders require non-es profile with version 460 or above");
655 if ((profile == EEsProfile && version < 320) ||
656 (profile != EEsProfile && version < 450)) {
658 infoSink.info.message(EPrefixError, "#version: mesh/task shaders require es profile with version 320 or above, or non-es profile with version 450 or above");
659 version = profile == EEsProfile ? 320 : 450;
665 if (profile == EEsProfile && version >= 300 && versionNotFirst) {
667 infoSink.info.message(EPrefixError, "#version: statement must appear first in es-profile shader; before comments or newlines");
670 // Check for SPIR-V compatibility
671 if (spvVersion.spv != 0) {
676 infoSink.info.message(EPrefixError, "#version: ES shaders for SPIR-V require version 310 or higher");
680 case ECompatibilityProfile:
681 infoSink.info.message(EPrefixError, "#version: compilation for SPIR-V does not support the compatibility profile");
684 if (spvVersion.vulkan > 0 && version < 140) {
686 infoSink.info.message(EPrefixError, "#version: Desktop shaders for Vulkan SPIR-V require version 140 or higher");
689 if (spvVersion.openGl >= 100 && version < 330) {
691 infoSink.info.message(EPrefixError, "#version: Desktop shaders for OpenGL SPIR-V require version 330 or higher");
702 // There are multiple paths in for setting environment stuff.
703 // TEnvironment takes precedence, for what it sets, so sort all this out.
704 // Ideally, the internal code could be made to use TEnvironment, but for
705 // now, translate it to the historically used parameters.
706 void TranslateEnvironment(const TEnvironment* environment, EShMessages& messages, EShSource& source,
707 EShLanguage& stage, SpvVersion& spvVersion)
709 // Set up environmental defaults, first ignoring 'environment'.
710 if (messages & EShMsgSpvRules)
711 spvVersion.spv = EShTargetSpv_1_0;
712 if (messages & EShMsgVulkanRules) {
713 spvVersion.vulkan = EShTargetVulkan_1_0;
714 spvVersion.vulkanGlsl = 100;
715 } else if (spvVersion.spv != 0)
716 spvVersion.openGl = 100;
718 // Now, override, based on any content set in 'environment'.
719 // 'environment' must be cleared to ESh*None settings when items
720 // are not being set.
721 if (environment != nullptr) {
723 if (environment->input.languageFamily != EShSourceNone) {
724 stage = environment->input.stage;
725 switch (environment->input.dialect) {
728 case EShClientVulkan:
729 spvVersion.vulkanGlsl = environment->input.dialectVersion;
730 spvVersion.vulkanRelaxed = environment->input.vulkanRulesRelaxed;
732 case EShClientOpenGL:
733 spvVersion.openGl = environment->input.dialectVersion;
739 switch (environment->input.languageFamily) {
743 source = EShSourceGlsl;
744 messages = static_cast<EShMessages>(messages & ~EShMsgReadHlsl);
747 source = EShSourceHlsl;
748 messages = static_cast<EShMessages>(messages | EShMsgReadHlsl);
757 switch (environment->client.client) {
758 case EShClientVulkan:
759 spvVersion.vulkan = environment->client.version;
766 switch (environment->target.language) {
768 spvVersion.spv = environment->target.version;
776 // Most processes are recorded when set in the intermediate representation,
777 // These are the few that are not.
778 void RecordProcesses(TIntermediate& intermediate, EShMessages messages, const std::string& sourceEntryPointName)
780 if ((messages & EShMsgRelaxedErrors) != 0)
781 intermediate.addProcess("relaxed-errors");
782 if ((messages & EShMsgSuppressWarnings) != 0)
783 intermediate.addProcess("suppress-warnings");
784 if ((messages & EShMsgKeepUncalled) != 0)
785 intermediate.addProcess("keep-uncalled");
786 if (sourceEntryPointName.size() > 0) {
787 intermediate.addProcess("source-entrypoint");
788 intermediate.addProcessArgument(sourceEntryPointName);
792 // This is the common setup and cleanup code for PreprocessDeferred and
794 // It takes any callable with a signature of
795 // bool (TParseContextBase& parseContext, TPpContext& ppContext,
796 // TInputScanner& input, bool versionWillBeError,
797 // TSymbolTable& , TIntermediate& ,
798 // EShOptimizationLevel , EShMessages );
799 // Which returns false if a failure was detected and true otherwise.
801 template<typename ProcessingContext>
802 bool ProcessDeferred(
804 const char* const shaderStrings[],
805 const int numStrings,
806 const int* inputLengths,
807 const char* const stringNames[],
808 const char* customPreamble,
809 const EShOptimizationLevel optLevel,
810 const TBuiltInResource* resources,
811 int defaultVersion, // use 100 for ES environment, 110 for desktop; this is the GLSL version, not SPIR-V or Vulkan
812 EProfile defaultProfile,
813 // set version/profile to defaultVersion/defaultProfile regardless of the #version
814 // directive in the source code
815 bool forceDefaultVersionAndProfile,
816 int overrideVersion, // overrides version specified by #verison or default version
817 bool forwardCompatible, // give errors for use of deprecated features
818 EShMessages messages, // warnings/errors/AST; things to print out
819 TIntermediate& intermediate, // returned tree, etc.
820 ProcessingContext& processingContext,
821 bool requireNonempty,
822 TShader::Includer& includer,
823 const std::string sourceEntryPointName = "",
824 const TEnvironment* environment = nullptr) // optional way of fully setting all versions, overriding the above
826 // This must be undone (.pop()) by the caller, after it finishes consuming the created tree.
827 GetThreadPoolAllocator().push();
832 // Move to length-based strings, rather than null-terminated strings.
833 // Also, add strings to include the preamble and to ensure the shader is not null,
834 // which lets the grammar accept what was a null (post preprocessing) shader.
836 // Shader will look like
837 // string 0: system preamble
838 // string 1: custom preamble
839 // string 2...numStrings+1: user's shader
840 // string numStrings+2: "int;"
841 const int numPre = 2;
842 const int numPost = requireNonempty? 1 : 0;
843 const int numTotal = numPre + numStrings + numPost;
844 std::unique_ptr<size_t[]> lengths(new size_t[numTotal]);
845 std::unique_ptr<const char*[]> strings(new const char*[numTotal]);
846 std::unique_ptr<const char*[]> names(new const char*[numTotal]);
847 for (int s = 0; s < numStrings; ++s) {
848 strings[s + numPre] = shaderStrings[s];
849 if (inputLengths == nullptr || inputLengths[s] < 0)
850 lengths[s + numPre] = strlen(shaderStrings[s]);
852 lengths[s + numPre] = inputLengths[s];
854 if (stringNames != nullptr) {
855 for (int s = 0; s < numStrings; ++s)
856 names[s + numPre] = stringNames[s];
858 for (int s = 0; s < numStrings; ++s)
859 names[s + numPre] = nullptr;
862 // Get all the stages, languages, clients, and other environment
864 EShSource sourceGuess = (messages & EShMsgReadHlsl) != 0 ? EShSourceHlsl : EShSourceGlsl;
865 SpvVersion spvVersion;
866 EShLanguage stage = compiler->getLanguage();
867 TranslateEnvironment(environment, messages, sourceGuess, stage, spvVersion);
869 EShSource source = sourceGuess;
870 if (environment != nullptr && environment->target.hlslFunctionality1)
871 intermediate.setHlslFunctionality1();
873 const EShSource source = EShSourceGlsl;
875 // First, without using the preprocessor or parser, find the #version, so we know what
876 // symbol tables, processing rules, etc. to set up. This does not need the extra strings
877 // outlined above, just the user shader, after the system and user preambles.
878 glslang::TInputScanner userInput(numStrings, &strings[numPre], &lengths[numPre]);
880 EProfile profile = ENoProfile;
881 bool versionNotFirstToken = false;
882 bool versionNotFirst = (source == EShSourceHlsl)
884 : userInput.scanVersion(version, profile, versionNotFirstToken);
885 bool versionNotFound = version == 0;
886 if (forceDefaultVersionAndProfile && source == EShSourceGlsl) {
887 #if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE)
888 if (! (messages & EShMsgSuppressWarnings) && ! versionNotFound &&
889 (version != defaultVersion || profile != defaultProfile)) {
890 compiler->infoSink.info << "Warning, (version, profile) forced to be ("
891 << defaultVersion << ", " << ProfileName(defaultProfile)
892 << "), while in source code it is ("
893 << version << ", " << ProfileName(profile) << ")\n";
896 if (versionNotFound) {
897 versionNotFirstToken = false;
898 versionNotFirst = false;
899 versionNotFound = false;
901 version = defaultVersion;
902 profile = defaultProfile;
904 if (source == EShSourceGlsl && overrideVersion != 0) {
905 version = overrideVersion;
908 bool goodVersion = DeduceVersionProfile(compiler->infoSink, stage,
909 versionNotFirst, defaultVersion, source, version, profile, spvVersion);
911 profile = EEsProfile;
913 #elif defined(GLSLANG_ANGLE)
914 profile = ECoreProfile;
918 bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst));
919 #if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE)
920 bool warnVersionNotFirst = false;
921 if (! versionWillBeError && versionNotFirstToken) {
922 if (messages & EShMsgRelaxedErrors)
923 warnVersionNotFirst = true;
925 versionWillBeError = true;
929 intermediate.setSource(source);
930 intermediate.setVersion(version);
931 intermediate.setProfile(profile);
932 intermediate.setSpv(spvVersion);
933 RecordProcesses(intermediate, messages, sourceEntryPointName);
934 if (spvVersion.vulkan > 0)
935 intermediate.setOriginUpperLeft();
937 if ((messages & EShMsgHlslOffsets) || source == EShSourceHlsl)
938 intermediate.setHlslOffsets();
940 if (messages & EShMsgDebugInfo) {
941 intermediate.setSourceFile(names[numPre]);
942 for (int s = 0; s < numStrings; ++s) {
943 // The string may not be null-terminated, so make sure we provide
944 // the length along with the string.
945 intermediate.addSourceText(strings[numPre + s], lengths[numPre + s]);
948 SetupBuiltinSymbolTable(version, profile, spvVersion, source);
950 TSymbolTable* cachedTable = SharedSymbolTables[MapVersionToIndex(version)]
951 [MapSpvVersionToIndex(spvVersion)]
952 [MapProfileToIndex(profile)]
953 [MapSourceToIndex(source)]
956 // Dynamically allocate the symbol table so we can control when it is deallocated WRT the pool.
957 std::unique_ptr<TSymbolTable> symbolTable(new TSymbolTable);
959 symbolTable->adoptLevels(*cachedTable);
961 if (intermediate.getUniqueId() != 0)
962 symbolTable->overwriteUniqueId(intermediate.getUniqueId());
964 // Add built-in symbols that are potentially context dependent;
965 // they get popped again further down.
966 if (! AddContextSpecificSymbols(resources, compiler->infoSink, *symbolTable, version, profile, spvVersion,
971 if (messages & EShMsgBuiltinSymbolTable)
972 DumpBuiltinSymbolTable(compiler->infoSink, *symbolTable);
975 // Now we can process the full shader under proper symbols and rules.
978 std::unique_ptr<TParseContextBase> parseContext(CreateParseContext(*symbolTable, intermediate, version, profile, source,
979 stage, compiler->infoSink,
980 spvVersion, forwardCompatible, messages, false, sourceEntryPointName));
981 TPpContext ppContext(*parseContext, names[numPre] ? names[numPre] : "", includer);
983 // only GLSL (bison triggered, really) needs an externally set scan context
984 glslang::TScanContext scanContext(*parseContext);
985 if (source == EShSourceGlsl)
986 parseContext->setScanContext(&scanContext);
988 parseContext->setPpContext(&ppContext);
989 parseContext->setLimits(*resources);
991 parseContext->addError();
992 #if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE)
993 if (warnVersionNotFirst) {
996 parseContext->warn(loc, "Illegal to have non-comment, non-whitespace tokens before #version", "#version", "");
1000 parseContext->initializeExtensionBehavior();
1002 // Fill in the strings as outlined above.
1003 std::string preamble;
1004 parseContext->getPreamble(preamble);
1005 strings[0] = preamble.c_str();
1006 lengths[0] = strlen(strings[0]);
1008 strings[1] = customPreamble;
1009 lengths[1] = strlen(strings[1]);
1011 assert(2 == numPre);
1012 if (requireNonempty) {
1013 const int postIndex = numStrings + numPre;
1014 strings[postIndex] = "\n int;";
1015 lengths[postIndex] = strlen(strings[numStrings + numPre]);
1016 names[postIndex] = nullptr;
1018 TInputScanner fullInput(numStrings + numPre + numPost, strings.get(), lengths.get(), names.get(), numPre, numPost);
1020 // Push a new symbol allocation scope that will get used for the shader's globals.
1021 symbolTable->push();
1023 bool success = processingContext(*parseContext, ppContext, fullInput,
1024 versionWillBeError, *symbolTable,
1025 intermediate, optLevel, messages);
1026 intermediate.setUniqueId(symbolTable->getMaxSymbolId());
1030 #if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE)
1032 // Responsible for keeping track of the most recent source string and line in
1033 // the preprocessor and outputting newlines appropriately if the source string
1035 class SourceLineSynchronizer {
1037 SourceLineSynchronizer(const std::function<int()>& lastSourceIndex,
1038 std::string* output)
1039 : getLastSourceIndex(lastSourceIndex), output(output), lastSource(-1), lastLine(0) {}
1040 // SourceLineSynchronizer(const SourceLineSynchronizer&) = delete;
1041 // SourceLineSynchronizer& operator=(const SourceLineSynchronizer&) = delete;
1043 // Sets the internally tracked source string index to that of the most
1044 // recently read token. If we switched to a new source string, returns
1045 // true and inserts a newline. Otherwise, returns false and outputs nothing.
1046 bool syncToMostRecentString() {
1047 if (getLastSourceIndex() != lastSource) {
1048 // After switching to a new source string, we need to reset lastLine
1049 // because line number resets every time a new source string is
1050 // used. We also need to output a newline to separate the output
1051 // from the previous source string (if there is one).
1052 if (lastSource != -1 || lastLine != 0)
1054 lastSource = getLastSourceIndex();
1061 // Calls syncToMostRecentString() and then sets the internally tracked line
1062 // number to tokenLine. If we switched to a new line, returns true and inserts
1063 // newlines appropriately. Otherwise, returns false and outputs nothing.
1064 bool syncToLine(int tokenLine) {
1065 syncToMostRecentString();
1066 const bool newLineStarted = lastLine < tokenLine;
1067 for (; lastLine < tokenLine; ++lastLine) {
1068 if (lastLine > 0) *output += '\n';
1070 return newLineStarted;
1073 // Sets the internally tracked line number to newLineNum.
1074 void setLineNum(int newLineNum) { lastLine = newLineNum; }
1077 SourceLineSynchronizer& operator=(const SourceLineSynchronizer&);
1079 // A function for getting the index of the last valid source string we've
1080 // read tokens from.
1081 const std::function<int()> getLastSourceIndex;
1082 // output string for newlines.
1083 std::string* output;
1084 // lastSource is the source string index (starting from 0) of the last token
1085 // processed. It is tracked in order for newlines to be inserted when a new
1086 // source string starts. -1 means we haven't started processing any source
1089 // lastLine is the line number (starting from 1) of the last token processed.
1090 // It is tracked in order for newlines to be inserted when a token appears
1091 // on a new line. 0 means we haven't started processing any line in the
1092 // current source string.
1096 // DoPreprocessing is a valid ProcessingContext template argument,
1097 // which only performs the preprocessing step of compilation.
1098 // It places the result in the "string" argument to its constructor.
1100 // This is not an officially supported or fully working path.
1101 struct DoPreprocessing {
1102 explicit DoPreprocessing(std::string* string): outputString(string) {}
1103 bool operator()(TParseContextBase& parseContext, TPpContext& ppContext,
1104 TInputScanner& input, bool versionWillBeError,
1105 TSymbolTable&, TIntermediate&,
1106 EShOptimizationLevel, EShMessages)
1108 // This is a list of tokens that do not require a space before or after.
1109 static const std::string unNeededSpaceTokens = ";()[]";
1110 static const std::string noSpaceBeforeTokens = ",";
1111 glslang::TPpToken ppToken;
1113 parseContext.setScanner(&input);
1114 ppContext.setInput(input, versionWillBeError);
1116 std::string outputBuffer;
1117 SourceLineSynchronizer lineSync(
1118 std::bind(&TInputScanner::getLastValidSourceIndex, &input), &outputBuffer);
1120 parseContext.setExtensionCallback([&lineSync, &outputBuffer](
1121 int line, const char* extension, const char* behavior) {
1122 lineSync.syncToLine(line);
1123 outputBuffer += "#extension ";
1124 outputBuffer += extension;
1125 outputBuffer += " : ";
1126 outputBuffer += behavior;
1129 parseContext.setLineCallback([&lineSync, &outputBuffer, &parseContext](
1130 int curLineNum, int newLineNum, bool hasSource, int sourceNum, const char* sourceName) {
1131 // SourceNum is the number of the source-string that is being parsed.
1132 lineSync.syncToLine(curLineNum);
1133 outputBuffer += "#line ";
1134 outputBuffer += std::to_string(newLineNum);
1136 outputBuffer += ' ';
1137 if (sourceName != nullptr) {
1138 outputBuffer += '\"';
1139 outputBuffer += sourceName;
1140 outputBuffer += '\"';
1142 outputBuffer += std::to_string(sourceNum);
1145 if (parseContext.lineDirectiveShouldSetNextLine()) {
1146 // newLineNum is the new line number for the line following the #line
1147 // directive. So the new line number for the current line is
1150 outputBuffer += '\n';
1151 // And we are at the next line of the #line directive now.
1152 lineSync.setLineNum(newLineNum + 1);
1155 parseContext.setVersionCallback(
1156 [&lineSync, &outputBuffer](int line, int version, const char* str) {
1157 lineSync.syncToLine(line);
1158 outputBuffer += "#version ";
1159 outputBuffer += std::to_string(version);
1161 outputBuffer += ' ';
1162 outputBuffer += str;
1166 parseContext.setPragmaCallback([&lineSync, &outputBuffer](
1167 int line, const glslang::TVector<glslang::TString>& ops) {
1168 lineSync.syncToLine(line);
1169 outputBuffer += "#pragma ";
1170 for(size_t i = 0; i < ops.size(); ++i) {
1171 outputBuffer += ops[i].c_str();
1175 parseContext.setErrorCallback([&lineSync, &outputBuffer](
1176 int line, const char* errorMessage) {
1177 lineSync.syncToLine(line);
1178 outputBuffer += "#error ";
1179 outputBuffer += errorMessage;
1182 int lastToken = EndOfInput; // lastToken records the last token processed.
1184 int token = ppContext.tokenize(ppToken);
1185 if (token == EndOfInput)
1188 bool isNewString = lineSync.syncToMostRecentString();
1189 bool isNewLine = lineSync.syncToLine(ppToken.loc.line);
1192 // Don't emit whitespace onto empty lines.
1193 // Copy any whitespace characters at the start of a line
1194 // from the input to the output.
1195 outputBuffer += std::string(ppToken.loc.column - 1, ' ');
1198 // Output a space in between tokens, but not at the start of a line,
1199 // and also not around special tokens. This helps with readability
1201 if (!isNewString && !isNewLine && lastToken != EndOfInput &&
1202 (unNeededSpaceTokens.find((char)token) == std::string::npos) &&
1203 (unNeededSpaceTokens.find((char)lastToken) == std::string::npos) &&
1204 (noSpaceBeforeTokens.find((char)token) == std::string::npos)) {
1205 outputBuffer += ' ';
1208 if (token == PpAtomConstString)
1209 outputBuffer += "\"";
1210 outputBuffer += ppToken.name;
1211 if (token == PpAtomConstString)
1212 outputBuffer += "\"";
1214 outputBuffer += '\n';
1215 *outputString = std::move(outputBuffer);
1217 bool success = true;
1218 if (parseContext.getNumErrors() > 0) {
1220 parseContext.infoSink.info.prefix(EPrefixError);
1221 parseContext.infoSink.info << parseContext.getNumErrors() << " compilation errors. No code generated.\n\n";
1225 std::string* outputString;
1230 // DoFullParse is a valid ProcessingConext template argument for fully
1231 // parsing the shader. It populates the "intermediate" with the AST.
1233 bool operator()(TParseContextBase& parseContext, TPpContext& ppContext,
1234 TInputScanner& fullInput, bool versionWillBeError,
1235 TSymbolTable&, TIntermediate& intermediate,
1236 EShOptimizationLevel optLevel, EShMessages messages)
1238 bool success = true;
1239 // Parse the full shader.
1240 if (! parseContext.parseShaderStrings(ppContext, fullInput, versionWillBeError))
1243 if (success && intermediate.getTreeRoot()) {
1244 if (optLevel == EShOptNoGeneration)
1245 parseContext.infoSink.info.message(EPrefixNone, "No errors. No code generation or linking was requested.");
1247 success = intermediate.postProcess(intermediate.getTreeRoot(), parseContext.getLanguage());
1248 } else if (! success) {
1249 parseContext.infoSink.info.prefix(EPrefixError);
1250 parseContext.infoSink.info << parseContext.getNumErrors() << " compilation errors. No code generated.\n\n";
1253 #ifndef GLSLANG_ANGLE
1254 if (messages & EShMsgAST)
1255 intermediate.output(parseContext.infoSink, true);
1262 #if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE)
1263 // Take a single compilation unit, and run the preprocessor on it.
1264 // Return: True if there were no issues found in preprocessing,
1265 // False if during preprocessing any unknown version, pragmas or
1266 // extensions were found.
1268 // NOTE: Doing just preprocessing to obtain a correct preprocessed shader string
1269 // is not an officially supported or fully working path.
1270 bool PreprocessDeferred(
1271 TCompiler* compiler,
1272 const char* const shaderStrings[],
1273 const int numStrings,
1274 const int* inputLengths,
1275 const char* const stringNames[],
1276 const char* preamble,
1277 const EShOptimizationLevel optLevel,
1278 const TBuiltInResource* resources,
1279 int defaultVersion, // use 100 for ES environment, 110 for desktop
1280 EProfile defaultProfile,
1281 bool forceDefaultVersionAndProfile,
1282 int overrideVersion, // use 0 if not overriding GLSL version
1283 bool forwardCompatible, // give errors for use of deprecated features
1284 EShMessages messages, // warnings/errors/AST; things to print out
1285 TShader::Includer& includer,
1286 TIntermediate& intermediate, // returned tree, etc.
1287 std::string* outputString,
1288 TEnvironment* environment = nullptr)
1290 DoPreprocessing parser(outputString);
1291 return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
1292 preamble, optLevel, resources, defaultVersion,
1293 defaultProfile, forceDefaultVersionAndProfile, overrideVersion,
1294 forwardCompatible, messages, intermediate, parser,
1295 false, includer, "", environment);
1300 // do a partial compile on the given strings for a single compilation unit
1301 // for a potential deferred link into a single stage (and deferred full compile of that
1302 // stage through machine-dependent compilation).
1304 // all preprocessing, parsing, semantic checks, etc. for a single compilation unit
1307 // return: the tree and other information is filled into the intermediate argument,
1308 // and true is returned by the function for success.
1310 bool CompileDeferred(
1311 TCompiler* compiler,
1312 const char* const shaderStrings[],
1313 const int numStrings,
1314 const int* inputLengths,
1315 const char* const stringNames[],
1316 const char* preamble,
1317 const EShOptimizationLevel optLevel,
1318 const TBuiltInResource* resources,
1319 int defaultVersion, // use 100 for ES environment, 110 for desktop
1320 EProfile defaultProfile,
1321 bool forceDefaultVersionAndProfile,
1322 int overrideVersion, // use 0 if not overriding GLSL version
1323 bool forwardCompatible, // give errors for use of deprecated features
1324 EShMessages messages, // warnings/errors/AST; things to print out
1325 TIntermediate& intermediate,// returned tree, etc.
1326 TShader::Includer& includer,
1327 const std::string sourceEntryPointName = "",
1328 TEnvironment* environment = nullptr)
1331 return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
1332 preamble, optLevel, resources, defaultVersion,
1333 defaultProfile, forceDefaultVersionAndProfile, overrideVersion,
1334 forwardCompatible, messages, intermediate, parser,
1335 true, includer, sourceEntryPointName, environment);
1338 } // end anonymous namespace for local functions
1341 // ShInitialize() should be called exactly once per process, not per thread.
1345 glslang::InitGlobalLock();
1347 if (! InitProcess())
1350 glslang::GetGlobalLock();
1353 if (PerProcessGPA == nullptr)
1354 PerProcessGPA = new TPoolAllocator();
1356 glslang::TScanContext::fillInKeywordMap();
1358 glslang::HlslScanContext::fillInKeywordMap();
1361 glslang::ReleaseGlobalLock();
1366 // Driver calls these to create and destroy compiler/linker
1370 ShHandle ShConstructCompiler(const EShLanguage language, int debugOptions)
1375 TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(language, debugOptions));
1377 return reinterpret_cast<void*>(base);
1380 ShHandle ShConstructLinker(const EShExecutable executable, int debugOptions)
1385 TShHandleBase* base = static_cast<TShHandleBase*>(ConstructLinker(executable, debugOptions));
1387 return reinterpret_cast<void*>(base);
1390 ShHandle ShConstructUniformMap()
1395 TShHandleBase* base = static_cast<TShHandleBase*>(ConstructUniformMap());
1397 return reinterpret_cast<void*>(base);
1400 void ShDestruct(ShHandle handle)
1405 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
1407 if (base->getAsCompiler())
1408 DeleteCompiler(base->getAsCompiler());
1409 else if (base->getAsLinker())
1410 DeleteLinker(base->getAsLinker());
1411 else if (base->getAsUniformMap())
1412 DeleteUniformMap(base->getAsUniformMap());
1416 // Cleanup symbol tables
1420 glslang::GetGlobalLock();
1422 assert(NumberOfClients >= 0);
1423 bool finalize = NumberOfClients == 0;
1425 glslang::ReleaseGlobalLock();
1429 for (int version = 0; version < VersionCount; ++version) {
1430 for (int spvVersion = 0; spvVersion < SpvVersionCount; ++spvVersion) {
1431 for (int p = 0; p < ProfileCount; ++p) {
1432 for (int source = 0; source < SourceCount; ++source) {
1433 for (int stage = 0; stage < EShLangCount; ++stage) {
1434 delete SharedSymbolTables[version][spvVersion][p][source][stage];
1435 SharedSymbolTables[version][spvVersion][p][source][stage] = 0;
1442 for (int version = 0; version < VersionCount; ++version) {
1443 for (int spvVersion = 0; spvVersion < SpvVersionCount; ++spvVersion) {
1444 for (int p = 0; p < ProfileCount; ++p) {
1445 for (int source = 0; source < SourceCount; ++source) {
1446 for (int pc = 0; pc < EPcCount; ++pc) {
1447 delete CommonSymbolTable[version][spvVersion][p][source][pc];
1448 CommonSymbolTable[version][spvVersion][p][source][pc] = 0;
1455 if (PerProcessGPA != nullptr) {
1456 delete PerProcessGPA;
1457 PerProcessGPA = nullptr;
1460 glslang::TScanContext::deleteKeywordMap();
1462 glslang::HlslScanContext::deleteKeywordMap();
1465 glslang::ReleaseGlobalLock();
1470 // Do a full compile on the given strings for a single compilation unit
1471 // forming a complete stage. The result of the machine dependent compilation
1472 // is left in the provided compile object.
1474 // Return: The return value is really boolean, indicating
1475 // success (1) or failure (0).
1478 const ShHandle handle,
1479 const char* const shaderStrings[],
1480 const int numStrings,
1481 const int* inputLengths,
1482 const EShOptimizationLevel optLevel,
1483 const TBuiltInResource* resources,
1484 int /*debugOptions*/,
1485 int defaultVersion, // use 100 for ES environment, 110 for desktop
1486 bool forwardCompatible, // give errors for use of deprecated features
1487 EShMessages messages // warnings/errors/AST; things to print out
1490 // Map the generic handle to the C++ object
1494 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1495 TCompiler* compiler = base->getAsCompiler();
1499 SetThreadPoolAllocator(compiler->getPool());
1501 compiler->infoSink.info.erase();
1502 compiler->infoSink.debug.erase();
1504 TIntermediate intermediate(compiler->getLanguage());
1505 TShader::ForbidIncluder includer;
1506 bool success = CompileDeferred(compiler, shaderStrings, numStrings, inputLengths, nullptr,
1507 "", optLevel, resources, defaultVersion, ENoProfile, false, 0,
1508 forwardCompatible, messages, intermediate, includer);
1511 // Call the machine dependent compiler
1513 if (success && intermediate.getTreeRoot() && optLevel != EShOptNoGeneration)
1514 success = compiler->compile(intermediate.getTreeRoot(), intermediate.getVersion(), intermediate.getProfile());
1516 intermediate.removeTree();
1518 // Throw away all the temporary memory used by the compilation process.
1519 // The push was done in the CompileDeferred() call above.
1520 GetThreadPoolAllocator().pop();
1522 return success ? 1 : 0;
1526 // Link the given compile objects.
1528 // Return: The return value of is really boolean, indicating
1529 // success or failure.
1532 const ShHandle linkHandle,
1533 const ShHandle compHandles[],
1534 const int numHandles)
1536 if (linkHandle == 0 || numHandles == 0)
1539 THandleList cObjects;
1541 for (int i = 0; i < numHandles; ++i) {
1542 if (compHandles[i] == 0)
1544 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(compHandles[i]);
1545 if (base->getAsLinker()) {
1546 cObjects.push_back(base->getAsLinker());
1548 if (base->getAsCompiler())
1549 cObjects.push_back(base->getAsCompiler());
1551 if (cObjects[i] == 0)
1555 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(linkHandle);
1556 TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
1558 SetThreadPoolAllocator(linker->getPool());
1563 linker->infoSink.info.erase();
1565 for (int i = 0; i < numHandles; ++i) {
1566 if (cObjects[i]->getAsCompiler()) {
1567 if (! cObjects[i]->getAsCompiler()->linkable()) {
1568 linker->infoSink.info.message(EPrefixError, "Not all shaders have valid object code.");
1574 bool ret = linker->link(cObjects);
1580 // ShSetEncrpytionMethod is a place-holder for specifying
1581 // how source code is encrypted.
1583 void ShSetEncryptionMethod(ShHandle handle)
1590 // Return any compiler/linker/uniformmap log of messages for the application.
1592 const char* ShGetInfoLog(const ShHandle handle)
1597 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
1598 TInfoSink* infoSink;
1600 if (base->getAsCompiler())
1601 infoSink = &(base->getAsCompiler()->getInfoSink());
1602 else if (base->getAsLinker())
1603 infoSink = &(base->getAsLinker()->getInfoSink());
1607 infoSink->info << infoSink->debug.c_str();
1608 return infoSink->info.c_str();
1612 // Return the resulting binary code from the link process. Structure
1613 // is machine dependent.
1615 const void* ShGetExecutable(const ShHandle handle)
1620 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1622 TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
1626 return linker->getObjectCode();
1630 // Let the linker know where the application said it's attributes are bound.
1631 // The linker does not use these values, they are remapped by the ICD or
1632 // hardware. It just needs them to know what's aliased.
1634 // Return: The return value of is really boolean, indicating
1635 // success or failure.
1637 int ShSetVirtualAttributeBindings(const ShHandle handle, const ShBindingTable* table)
1642 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1643 TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
1648 linker->setAppAttributeBindings(table);
1654 // Let the linker know where the predefined attributes have to live.
1656 int ShSetFixedAttributeBindings(const ShHandle handle, const ShBindingTable* table)
1661 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1662 TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
1667 linker->setFixedAttributeBindings(table);
1672 // Some attribute locations are off-limits to the linker...
1674 int ShExcludeAttributes(const ShHandle handle, int *attributes, int count)
1679 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1680 TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
1684 linker->setExcludedAttributes(attributes, count);
1690 // Return the index for OpenGL to use for knowing where a uniform lives.
1692 // Return: The return value of is really boolean, indicating
1693 // success or failure.
1695 int ShGetUniformLocation(const ShHandle handle, const char* name)
1700 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1701 TUniformMap* uniformMap= base->getAsUniformMap();
1702 if (uniformMap == 0)
1705 return uniformMap->getLocation(name);
1708 ////////////////////////////////////////////////////////////////////////////////////////////
1710 // Deferred-Lowering C++ Interface
1711 // -----------------------------------
1713 // Below is a new alternate C++ interface that might potentially replace the above
1714 // opaque handle-based interface.
1716 // See more detailed comment in ShaderLang.h
1721 Version GetVersion()
1724 version.major = GLSLANG_VERSION_MAJOR;
1725 version.minor = GLSLANG_VERSION_MINOR;
1726 version.patch = GLSLANG_VERSION_PATCH;
1727 version.flavor = GLSLANG_VERSION_FLAVOR;
1732 #define STR(n) QUOTE(n)
1734 const char* GetEsslVersionString()
1736 return "OpenGL ES GLSL 3.20 glslang Khronos. " STR(GLSLANG_VERSION_MAJOR) "." STR(GLSLANG_VERSION_MINOR) "." STR(
1737 GLSLANG_VERSION_PATCH) GLSLANG_VERSION_FLAVOR;
1740 const char* GetGlslVersionString()
1742 return "4.60 glslang Khronos. " STR(GLSLANG_VERSION_MAJOR) "." STR(GLSLANG_VERSION_MINOR) "." STR(
1743 GLSLANG_VERSION_PATCH) GLSLANG_VERSION_FLAVOR;
1746 int GetKhronosToolId()
1751 bool InitializeProcess()
1753 return ShInitialize() != 0;
1756 void FinalizeProcess()
1761 class TDeferredCompiler : public TCompiler {
1763 TDeferredCompiler(EShLanguage s, TInfoSink& i) : TCompiler(s, i) { }
1764 virtual bool compile(TIntermNode*, int = 0, EProfile = ENoProfile) { return true; }
1767 TShader::TShader(EShLanguage s)
1768 : stage(s), lengths(nullptr), stringNames(nullptr), preamble(""), overrideVersion(0)
1770 pool = new TPoolAllocator;
1771 infoSink = new TInfoSink;
1772 compiler = new TDeferredCompiler(stage, *infoSink);
1773 intermediate = new TIntermediate(s);
1775 // clear environment (avoid constructors in them for use in a C interface)
1776 environment.input.languageFamily = EShSourceNone;
1777 environment.input.dialect = EShClientNone;
1778 environment.input.vulkanRulesRelaxed = false;
1779 environment.client.client = EShClientNone;
1780 environment.target.language = EShTargetNone;
1781 environment.target.hlslFunctionality1 = false;
1788 delete intermediate;
1792 void TShader::setStrings(const char* const* s, int n)
1799 void TShader::setStringsWithLengths(const char* const* s, const int* l, int n)
1806 void TShader::setStringsWithLengthsAndNames(
1807 const char* const* s, const int* l, const char* const* names, int n)
1812 stringNames = names;
1815 void TShader::setEntryPoint(const char* entryPoint)
1817 intermediate->setEntryPointName(entryPoint);
1820 void TShader::setSourceEntryPoint(const char* name)
1822 sourceEntryPointName = name;
1825 // Log initial settings and transforms.
1826 // See comment for class TProcesses.
1827 void TShader::addProcesses(const std::vector<std::string>& p)
1829 intermediate->addProcesses(p);
1832 void TShader::setUniqueId(unsigned long long id)
1834 intermediate->setUniqueId(id);
1837 void TShader::setOverrideVersion(int version)
1839 overrideVersion = version;
1842 void TShader::setDebugInfo(bool debugInfo) { intermediate->setDebugInfo(debugInfo); }
1843 void TShader::setInvertY(bool invert) { intermediate->setInvertY(invert); }
1844 void TShader::setDxPositionW(bool invert) { intermediate->setDxPositionW(invert); }
1845 void TShader::setEnhancedMsgs() { intermediate->setEnhancedMsgs(); }
1846 void TShader::setNanMinMaxClamp(bool useNonNan) { intermediate->setNanMinMaxClamp(useNonNan); }
1850 // Set binding base for given resource type
1851 void TShader::setShiftBinding(TResourceType res, unsigned int base) {
1852 intermediate->setShiftBinding(res, base);
1855 // Set binding base for given resource type for a given binding set.
1856 void TShader::setShiftBindingForSet(TResourceType res, unsigned int base, unsigned int set) {
1857 intermediate->setShiftBindingForSet(res, base, set);
1860 // Set binding base for sampler types
1861 void TShader::setShiftSamplerBinding(unsigned int base) { setShiftBinding(EResSampler, base); }
1862 // Set binding base for texture types (SRV)
1863 void TShader::setShiftTextureBinding(unsigned int base) { setShiftBinding(EResTexture, base); }
1864 // Set binding base for image types
1865 void TShader::setShiftImageBinding(unsigned int base) { setShiftBinding(EResImage, base); }
1866 // Set binding base for uniform buffer objects (CBV)
1867 void TShader::setShiftUboBinding(unsigned int base) { setShiftBinding(EResUbo, base); }
1868 // Synonym for setShiftUboBinding, to match HLSL language.
1869 void TShader::setShiftCbufferBinding(unsigned int base) { setShiftBinding(EResUbo, base); }
1870 // Set binding base for UAV (unordered access view)
1871 void TShader::setShiftUavBinding(unsigned int base) { setShiftBinding(EResUav, base); }
1872 // Set binding base for SSBOs
1873 void TShader::setShiftSsboBinding(unsigned int base) { setShiftBinding(EResSsbo, base); }
1874 // Enables binding automapping using TIoMapper
1875 void TShader::setAutoMapBindings(bool map) { intermediate->setAutoMapBindings(map); }
1876 // Enables position.Y output negation in vertex shader
1878 // Fragile: currently within one stage: simple auto-assignment of location
1879 void TShader::setAutoMapLocations(bool map) { intermediate->setAutoMapLocations(map); }
1880 void TShader::addUniformLocationOverride(const char* name, int loc)
1882 intermediate->addUniformLocationOverride(name, loc);
1884 void TShader::setUniformLocationBase(int base)
1886 intermediate->setUniformLocationBase(base);
1888 void TShader::setNoStorageFormat(bool useUnknownFormat) { intermediate->setNoStorageFormat(useUnknownFormat); }
1889 void TShader::setResourceSetBinding(const std::vector<std::string>& base) { intermediate->setResourceSetBinding(base); }
1890 void TShader::setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { intermediate->setTextureSamplerTransformMode(mode); }
1893 void TShader::addBlockStorageOverride(const char* nameStr, TBlockStorageClass backing) { intermediate->addBlockStorageOverride(nameStr, backing); }
1895 void TShader::setGlobalUniformBlockName(const char* name) { intermediate->setGlobalUniformBlockName(name); }
1896 void TShader::setGlobalUniformSet(unsigned int set) { intermediate->setGlobalUniformSet(set); }
1897 void TShader::setGlobalUniformBinding(unsigned int binding) { intermediate->setGlobalUniformBinding(binding); }
1899 void TShader::setAtomicCounterBlockName(const char* name) { intermediate->setAtomicCounterBlockName(name); }
1900 void TShader::setAtomicCounterBlockSet(unsigned int set) { intermediate->setAtomicCounterBlockSet(set); }
1903 // See comment above TDefaultHlslIoMapper in iomapper.cpp:
1904 void TShader::setHlslIoMapping(bool hlslIoMap) { intermediate->setHlslIoMapping(hlslIoMap); }
1905 void TShader::setFlattenUniformArrays(bool flatten) { intermediate->setFlattenUniformArrays(flatten); }
1909 // Turn the shader strings into a parse tree in the TIntermediate.
1911 // Returns true for success.
1913 bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
1914 bool forwardCompatible, EShMessages messages, Includer& includer)
1918 SetThreadPoolAllocator(pool);
1923 return CompileDeferred(compiler, strings, numStrings, lengths, stringNames,
1924 preamble, EShOptNone, builtInResources, defaultVersion,
1925 defaultProfile, forceDefaultVersionAndProfile, overrideVersion,
1926 forwardCompatible, messages, *intermediate, includer, sourceEntryPointName,
1930 #if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE)
1931 // Fill in a string with the result of preprocessing ShaderStrings
1932 // Returns true if all extensions, pragmas and version strings were valid.
1934 // NOTE: Doing just preprocessing to obtain a correct preprocessed shader string
1935 // is not an officially supported or fully working path.
1936 bool TShader::preprocess(const TBuiltInResource* builtInResources,
1937 int defaultVersion, EProfile defaultProfile,
1938 bool forceDefaultVersionAndProfile,
1939 bool forwardCompatible, EShMessages message,
1940 std::string* output_string,
1945 SetThreadPoolAllocator(pool);
1950 return PreprocessDeferred(compiler, strings, numStrings, lengths, stringNames, preamble,
1951 EShOptNone, builtInResources, defaultVersion,
1952 defaultProfile, forceDefaultVersionAndProfile, overrideVersion,
1953 forwardCompatible, message, includer, *intermediate, output_string,
1958 const char* TShader::getInfoLog()
1960 return infoSink->info.c_str();
1963 const char* TShader::getInfoDebugLog()
1965 return infoSink->debug.c_str();
1968 TProgram::TProgram() :
1969 #if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE)
1974 pool = new TPoolAllocator;
1975 infoSink = new TInfoSink;
1976 for (int s = 0; s < EShLangCount; ++s) {
1977 intermediate[s] = 0;
1978 newedIntermediate[s] = false;
1982 TProgram::~TProgram()
1985 #if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE)
1989 for (int s = 0; s < EShLangCount; ++s)
1990 if (newedIntermediate[s])
1991 delete intermediate[s];
1997 // Merge the compilation units within each stage into a single TIntermediate.
1998 // All starting compilation units need to be the result of calling TShader::parse().
2000 // Return true for success.
2002 bool TProgram::link(EShMessages messages)
2010 SetThreadPoolAllocator(pool);
2012 for (int s = 0; s < EShLangCount; ++s) {
2013 if (! linkStage((EShLanguage)s, messages))
2018 if (! crossStageCheck(messages))
2026 // Merge the compilation units within the given stage into a single TIntermediate.
2028 // Return true for success.
2030 bool TProgram::linkStage(EShLanguage stage, EShMessages messages)
2032 if (stages[stage].size() == 0)
2035 #if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE)
2036 int numEsShaders = 0, numNonEsShaders = 0;
2037 for (auto it = stages[stage].begin(); it != stages[stage].end(); ++it) {
2038 if ((*it)->intermediate->getProfile() == EEsProfile) {
2045 if (numEsShaders > 0 && numNonEsShaders > 0) {
2046 infoSink->info.message(EPrefixError, "Cannot mix ES profile with non-ES profile shaders");
2048 } else if (numEsShaders > 1) {
2049 infoSink->info.message(EPrefixError, "Cannot attach multiple ES shaders of the same type to a single program");
2054 // Be efficient for the common single compilation unit per stage case,
2055 // reusing it's TIntermediate instead of merging into a new one.
2057 TIntermediate *firstIntermediate = stages[stage].front()->intermediate;
2058 if (stages[stage].size() == 1)
2059 intermediate[stage] = firstIntermediate;
2061 intermediate[stage] = new TIntermediate(stage,
2062 firstIntermediate->getVersion(),
2063 firstIntermediate->getProfile());
2064 intermediate[stage]->setLimits(firstIntermediate->getLimits());
2065 if (firstIntermediate->getEnhancedMsgs())
2066 intermediate[stage]->setEnhancedMsgs();
2068 // The new TIntermediate must use the same origin as the original TIntermediates.
2069 // Otherwise linking will fail due to different coordinate systems.
2070 if (firstIntermediate->getOriginUpperLeft()) {
2071 intermediate[stage]->setOriginUpperLeft();
2073 intermediate[stage]->setSpv(firstIntermediate->getSpv());
2075 newedIntermediate[stage] = true;
2078 if (messages & EShMsgAST)
2079 infoSink->info << "\nLinked " << StageName(stage) << " stage:\n\n";
2081 if (stages[stage].size() > 1) {
2082 std::list<TShader*>::const_iterator it;
2083 for (it = stages[stage].begin(); it != stages[stage].end(); ++it)
2084 intermediate[stage]->merge(*infoSink, *(*it)->intermediate);
2087 intermediate[stage] = stages[stage].front()->intermediate;
2089 intermediate[stage]->finalCheck(*infoSink, (messages & EShMsgKeepUncalled) != 0);
2091 #ifndef GLSLANG_ANGLE
2092 if (messages & EShMsgAST)
2093 intermediate[stage]->output(*infoSink, true);
2096 return intermediate[stage]->getNumErrors() == 0;
2100 // Check that there are no errors in linker objects accross stages
2102 // Return true if no errors.
2104 bool TProgram::crossStageCheck(EShMessages) {
2106 // make temporary intermediates to hold the linkage symbols for each linking interface
2107 // while we do the checks
2108 // Independent interfaces are:
2109 // all uniform variables and blocks
2110 // all buffer blocks
2111 // all in/out on a stage boundary
2113 TVector<TIntermediate*> activeStages;
2114 for (int s = 0; s < EShLangCount; ++s) {
2115 if (intermediate[s])
2116 activeStages.push_back(intermediate[s]);
2119 // no extra linking if there is only one stage
2120 if (! (activeStages.size() > 1))
2123 // setup temporary tree to hold unfirom objects from different stages
2124 TIntermediate* firstIntermediate = activeStages.front();
2125 TIntermediate uniforms(EShLangCount,
2126 firstIntermediate->getVersion(),
2127 firstIntermediate->getProfile());
2128 uniforms.setSpv(firstIntermediate->getSpv());
2130 TIntermAggregate uniformObjects(EOpLinkerObjects);
2131 TIntermAggregate root(EOpSequence);
2132 root.getSequence().push_back(&uniformObjects);
2133 uniforms.setTreeRoot(&root);
2137 // merge uniforms from all stages into a single intermediate
2138 for (unsigned int i = 0; i < activeStages.size(); ++i) {
2139 uniforms.mergeUniformObjects(*infoSink, *activeStages[i]);
2141 error |= uniforms.getNumErrors() != 0;
2143 // copy final definition of global block back into each stage
2144 for (unsigned int i = 0; i < activeStages.size(); ++i) {
2145 // We only want to merge into already existing global uniform blocks.
2146 // A stage that doesn't already know about the global doesn't care about it's content.
2147 // Otherwise we end up pointing to the same object between different stages
2148 // and that will break binding/set remappings
2149 bool mergeExistingOnly = true;
2150 activeStages[i]->mergeGlobalUniformBlocks(*infoSink, uniforms, mergeExistingOnly);
2153 // compare cross stage symbols for each stage boundary
2154 for (unsigned int i = 1; i < activeStages.size(); ++i) {
2155 activeStages[i - 1]->checkStageIO(*infoSink, *activeStages[i]);
2156 error |= (activeStages[i - 1]->getNumErrors() != 0);
2162 const char* TProgram::getInfoLog()
2164 return infoSink->info.c_str();
2167 const char* TProgram::getInfoDebugLog()
2169 return infoSink->debug.c_str();
2172 #if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE)
2175 // Reflection implementation.
2178 bool TProgram::buildReflection(int opts)
2180 if (! linked || reflection != nullptr)
2183 int firstStage = EShLangVertex, lastStage = EShLangFragment;
2185 if (opts & EShReflectionIntermediateIO) {
2186 // if we're reflecting intermediate I/O, determine the first and last stage linked and use those as the
2187 // boundaries for which stages generate pipeline inputs/outputs
2188 firstStage = EShLangCount;
2190 for (int s = 0; s < EShLangCount; ++s) {
2191 if (intermediate[s]) {
2192 firstStage = std::min(firstStage, s);
2193 lastStage = std::max(lastStage, s);
2198 reflection = new TReflection((EShReflectionOptions)opts, (EShLanguage)firstStage, (EShLanguage)lastStage);
2200 for (int s = 0; s < EShLangCount; ++s) {
2201 if (intermediate[s]) {
2202 if (! reflection->addStage((EShLanguage)s, *intermediate[s]))
2210 unsigned TProgram::getLocalSize(int dim) const { return reflection->getLocalSize(dim); }
2211 int TProgram::getReflectionIndex(const char* name) const { return reflection->getIndex(name); }
2212 int TProgram::getReflectionPipeIOIndex(const char* name, const bool inOrOut) const
2213 { return reflection->getPipeIOIndex(name, inOrOut); }
2215 int TProgram::getNumUniformVariables() const { return reflection->getNumUniforms(); }
2216 const TObjectReflection& TProgram::getUniform(int index) const { return reflection->getUniform(index); }
2217 int TProgram::getNumUniformBlocks() const { return reflection->getNumUniformBlocks(); }
2218 const TObjectReflection& TProgram::getUniformBlock(int index) const { return reflection->getUniformBlock(index); }
2219 int TProgram::getNumPipeInputs() const { return reflection->getNumPipeInputs(); }
2220 const TObjectReflection& TProgram::getPipeInput(int index) const { return reflection->getPipeInput(index); }
2221 int TProgram::getNumPipeOutputs() const { return reflection->getNumPipeOutputs(); }
2222 const TObjectReflection& TProgram::getPipeOutput(int index) const { return reflection->getPipeOutput(index); }
2223 int TProgram::getNumBufferVariables() const { return reflection->getNumBufferVariables(); }
2224 const TObjectReflection& TProgram::getBufferVariable(int index) const { return reflection->getBufferVariable(index); }
2225 int TProgram::getNumBufferBlocks() const { return reflection->getNumStorageBuffers(); }
2226 const TObjectReflection& TProgram::getBufferBlock(int index) const { return reflection->getStorageBufferBlock(index); }
2227 int TProgram::getNumAtomicCounters() const { return reflection->getNumAtomicCounters(); }
2228 const TObjectReflection& TProgram::getAtomicCounter(int index) const { return reflection->getAtomicCounter(index); }
2229 void TProgram::dumpReflection() { if (reflection != nullptr) reflection->dump(); }
2232 // I/O mapping implementation.
2234 bool TProgram::mapIO(TIoMapResolver* pResolver, TIoMapper* pIoMapper)
2238 TIoMapper* ioMapper = nullptr;
2239 TIoMapper defaultIOMapper;
2240 if (pIoMapper == nullptr)
2241 ioMapper = &defaultIOMapper;
2243 ioMapper = pIoMapper;
2244 for (int s = 0; s < EShLangCount; ++s) {
2245 if (intermediate[s]) {
2246 if (! ioMapper->addStage((EShLanguage)s, *intermediate[s], *infoSink, pResolver))
2251 return ioMapper->doMap(pResolver, *infoSink);
2254 #endif // !GLSLANG_WEB && !GLSLANG_ANGLE
2256 } // end namespace glslang