2 // Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
3 // Copyright (C) 2013-2016 LunarG, Inc.
4 // Copyright (C) 2015-2016 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 namespace { // anonymous namespace for file-local functions and symbols
72 using namespace glslang;
74 // Create a language specific version of parseables.
75 TBuiltInParseables* CreateBuiltInParseables(TInfoSink& infoSink, EShSource source)
78 case EShSourceGlsl: return new TBuiltIns(); // GLSL builtIns
80 case EShSourceHlsl: return new TBuiltInParseablesHlsl(); // HLSL intrinsics
84 infoSink.info.message(EPrefixInternalError, "Unable to determine source language");
89 // Create a language specific version of a parse context.
90 TParseContextBase* CreateParseContext(TSymbolTable& symbolTable, TIntermediate& intermediate,
91 int version, EProfile profile, EShSource source,
92 EShLanguage language, TInfoSink& infoSink,
93 SpvVersion spvVersion, bool forwardCompatible, EShMessages messages,
94 bool parsingBuiltIns, const std::string sourceEntryPointName = "")
97 (void)sourceEntryPointName; // Unused argument.
102 intermediate.setEntryPointName("main");
103 return new TParseContext(symbolTable, intermediate, parsingBuiltIns, version, profile, spvVersion,
104 language, infoSink, forwardCompatible, messages);
108 return new HlslParseContext(symbolTable, intermediate, parsingBuiltIns, version, profile, spvVersion,
109 language, infoSink, sourceEntryPointName.c_str(), forwardCompatible, messages);
112 infoSink.info.message(EPrefixInternalError, "Unable to determine source language");
117 // Local mapping functions for making arrays of symbol tables....
119 const int VersionCount = 15; // index range in MapVersionToIndex
121 int MapVersionToIndex(int version)
126 case 100: index = 0; break;
127 case 110: index = 1; break;
128 case 120: index = 2; break;
129 case 130: index = 3; break;
130 case 140: index = 4; break;
131 case 150: index = 5; break;
132 case 300: index = 6; break;
133 case 330: index = 7; break;
134 case 400: index = 8; break;
135 case 410: index = 9; break;
136 case 420: index = 10; break;
137 case 430: index = 11; break;
138 case 440: index = 12; break;
139 case 310: index = 13; break;
140 case 450: index = 14; break;
144 assert(index < VersionCount);
149 const int SpvVersionCount = 3; // index range in MapSpvVersionToIndex
151 int MapSpvVersionToIndex(const SpvVersion& spvVersion)
155 if (spvVersion.openGl > 0)
157 else if (spvVersion.vulkan > 0)
160 assert(index < SpvVersionCount);
165 const int ProfileCount = 4; // index range in MapProfileToIndex
167 int MapProfileToIndex(EProfile profile)
172 case ENoProfile: index = 0; break;
173 case ECoreProfile: index = 1; break;
174 case ECompatibilityProfile: index = 2; break;
175 case EEsProfile: index = 3; break;
179 assert(index < ProfileCount);
184 const int SourceCount = 2;
186 int MapSourceToIndex(EShSource source)
191 case EShSourceGlsl: index = 0; break;
192 case EShSourceHlsl: index = 1; break;
196 assert(index < SourceCount);
201 // only one of these needed for non-ES; ES needs 2 for different precision defaults of built-ins
202 enum EPrecisionClass {
208 // A process-global symbol table per version per profile for built-ins common
209 // to multiple stages (languages), and a process-global symbol table per version
210 // per profile per stage for built-ins unique to each stage. They will be sparsely
211 // populated, so they will only be generated as needed.
213 // Each has a different set of built-ins, and we want to preserve that from
214 // compile to compile.
216 TSymbolTable* CommonSymbolTable[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EPcCount] = {};
217 TSymbolTable* SharedSymbolTables[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EShLangCount] = {};
219 TPoolAllocator* PerProcessGPA = 0;
222 // Parse and add to the given symbol table the content of the given shader string.
224 bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
225 EShSource source, TInfoSink& infoSink, TSymbolTable& symbolTable)
227 TIntermediate intermediate(language, version, profile);
229 intermediate.setSource(source);
231 std::unique_ptr<TParseContextBase> parseContext(CreateParseContext(symbolTable, intermediate, version, profile, source,
232 language, infoSink, spvVersion, true, EShMsgDefault,
235 TShader::ForbidIncluder includer;
236 TPpContext ppContext(*parseContext, "", includer);
237 TScanContext scanContext(*parseContext);
238 parseContext->setScanContext(&scanContext);
239 parseContext->setPpContext(&ppContext);
242 // Push the symbol table to give it an initial scope. This
243 // push should not have a corresponding pop, so that built-ins
244 // are preserved, and the test for an empty table fails.
249 const char* builtInShaders[2];
250 size_t builtInLengths[2];
251 builtInShaders[0] = builtIns.c_str();
252 builtInLengths[0] = builtIns.size();
254 if (builtInLengths[0] == 0)
257 TInputScanner input(1, builtInShaders, builtInLengths);
258 if (! parseContext->parseShaderStrings(ppContext, input) != 0) {
259 infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
260 printf("Unable to parse built-ins\n%s\n", infoSink.info.c_str());
261 printf("%s\n", builtInShaders[0]);
269 int CommonIndex(EProfile profile, EShLanguage language)
271 return (profile == EEsProfile && language == EShLangFragment) ? EPcFragment : EPcGeneral;
275 // To initialize per-stage shared tables, with the common table already complete.
277 void InitializeStageSymbolTable(TBuiltInParseables& builtInParseables, int version, EProfile profile, const SpvVersion& spvVersion,
278 EShLanguage language, EShSource source, TInfoSink& infoSink, TSymbolTable** commonTable,
279 TSymbolTable** symbolTables)
281 (*symbolTables[language]).adoptLevels(*commonTable[CommonIndex(profile, language)]);
282 InitializeSymbolTable(builtInParseables.getStageString(language), version, profile, spvVersion, language, source,
283 infoSink, *symbolTables[language]);
284 builtInParseables.identifyBuiltIns(version, profile, spvVersion, language, *symbolTables[language]);
285 if (profile == EEsProfile && version >= 300)
286 (*symbolTables[language]).setNoBuiltInRedeclarations();
288 (*symbolTables[language]).setSeparateNameSpaces();
292 // Initialize the full set of shareable symbol tables;
293 // The common (cross-stage) and those shareable per-stage.
295 bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TSymbolTable** symbolTables, int version, EProfile profile, const SpvVersion& spvVersion, EShSource source)
297 std::unique_ptr<TBuiltInParseables> builtInParseables(CreateBuiltInParseables(infoSink, source));
299 if (builtInParseables == nullptr)
302 builtInParseables->initialize(version, profile, spvVersion);
304 // do the common tables
305 InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangVertex, source,
306 infoSink, *commonTable[EPcGeneral]);
307 if (profile == EEsProfile)
308 InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangFragment, source,
309 infoSink, *commonTable[EPcFragment]);
311 // do the per-stage tables
313 // always have vertex and fragment
314 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangVertex, source,
315 infoSink, commonTable, symbolTables);
316 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangFragment, source,
317 infoSink, commonTable, symbolTables);
319 // check for tessellation
320 if ((profile != EEsProfile && version >= 150) ||
321 (profile == EEsProfile && version >= 310)) {
322 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessControl, source,
323 infoSink, commonTable, symbolTables);
324 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessEvaluation, source,
325 infoSink, commonTable, symbolTables);
328 // check for geometry
329 if ((profile != EEsProfile && version >= 150) ||
330 (profile == EEsProfile && version >= 310))
331 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangGeometry, source,
332 infoSink, commonTable, symbolTables);
335 if ((profile != EEsProfile && version >= 420) ||
336 (profile == EEsProfile && version >= 310))
337 InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCompute, source,
338 infoSink, commonTable, symbolTables);
343 bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& infoSink, TSymbolTable& symbolTable, int version,
344 EProfile profile, const SpvVersion& spvVersion, EShLanguage language, EShSource source)
346 std::unique_ptr<TBuiltInParseables> builtInParseables(CreateBuiltInParseables(infoSink, source));
348 if (builtInParseables == nullptr)
351 builtInParseables->initialize(*resources, version, profile, spvVersion, language);
352 InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, language, source, infoSink, symbolTable);
353 builtInParseables->identifyBuiltIns(version, profile, spvVersion, language, symbolTable, *resources);
359 // To do this on the fly, we want to leave the current state of our thread's
360 // pool allocator intact, so:
361 // - Switch to a new pool for parsing the built-ins
362 // - Do the parsing, which builds the symbol table, using the new pool
363 // - Switch to the process-global pool to save a copy the resulting symbol table
364 // - Free up the new pool used to parse the built-ins
365 // - Switch back to the original thread's pool
367 // This only gets done the first time any thread needs a particular symbol table
368 // (lazy evaluation).
370 void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& spvVersion, EShSource source)
374 // Make sure only one thread tries to do this at a time
375 glslang::GetGlobalLock();
377 // See if it's already been done for this version/profile combination
378 int versionIndex = MapVersionToIndex(version);
379 int spvVersionIndex = MapSpvVersionToIndex(spvVersion);
380 int profileIndex = MapProfileToIndex(profile);
381 int sourceIndex = MapSourceToIndex(source);
382 if (CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][EPcGeneral]) {
383 glslang::ReleaseGlobalLock();
388 // Switch to a new pool
389 TPoolAllocator& previousAllocator = GetThreadPoolAllocator();
390 TPoolAllocator* builtInPoolAllocator = new TPoolAllocator();
391 SetThreadPoolAllocator(*builtInPoolAllocator);
393 // Dynamically allocate the local symbol tables so we can control when they are deallocated WRT when the pool is popped.
394 TSymbolTable* commonTable[EPcCount];
395 TSymbolTable* stageTables[EShLangCount];
396 for (int precClass = 0; precClass < EPcCount; ++precClass)
397 commonTable[precClass] = new TSymbolTable;
398 for (int stage = 0; stage < EShLangCount; ++stage)
399 stageTables[stage] = new TSymbolTable;
401 // Generate the local symbol tables using the new pool
402 InitializeSymbolTables(infoSink, commonTable, stageTables, version, profile, spvVersion, source);
404 // Switch to the process-global pool
405 SetThreadPoolAllocator(*PerProcessGPA);
407 // Copy the local symbol tables from the new pool to the global tables using the process-global pool
408 for (int precClass = 0; precClass < EPcCount; ++precClass) {
409 if (! commonTable[precClass]->isEmpty()) {
410 CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass] = new TSymbolTable;
411 CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass]->copyTable(*commonTable[precClass]);
412 CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass]->readOnly();
415 for (int stage = 0; stage < EShLangCount; ++stage) {
416 if (! stageTables[stage]->isEmpty()) {
417 SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage] = new TSymbolTable;
418 SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->adoptLevels(*CommonSymbolTable
419 [versionIndex][spvVersionIndex][profileIndex][sourceIndex][CommonIndex(profile, (EShLanguage)stage)]);
420 SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->copyTable(*stageTables[stage]);
421 SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->readOnly();
425 // Clean up the local tables before deleting the pool they used.
426 for (int precClass = 0; precClass < EPcCount; ++precClass)
427 delete commonTable[precClass];
428 for (int stage = 0; stage < EShLangCount; ++stage)
429 delete stageTables[stage];
431 delete builtInPoolAllocator;
432 SetThreadPoolAllocator(previousAllocator);
434 glslang::ReleaseGlobalLock();
437 // Return true if the shader was correctly specified for version/profile/stage.
438 bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNotFirst, int defaultVersion,
439 EShSource source, int& version, EProfile& profile, const SpvVersion& spvVersion)
441 const int FirstProfileVersion = 150;
444 if (source == EShSourceHlsl) {
445 version = 450; // TODO: GLSL parser is still used for builtins.
446 profile = ECoreProfile; // allow doubles in prototype parsing
450 // Get a good version...
452 version = defaultVersion;
453 // infoSink.info.message(EPrefixWarning, "#version: statement missing; use #version on first line of shader");
456 // Get a good profile...
457 if (profile == ENoProfile) {
458 if (version == 300 || version == 310) {
460 infoSink.info.message(EPrefixError, "#version: versions 300 and 310 require specifying the 'es' profile");
461 profile = EEsProfile;
462 } else if (version == 100)
463 profile = EEsProfile;
464 else if (version >= FirstProfileVersion)
465 profile = ECoreProfile;
467 profile = ENoProfile;
469 // a profile was provided...
472 infoSink.info.message(EPrefixError, "#version: versions before 150 do not allow a profile token");
474 profile = EEsProfile;
476 profile = ENoProfile;
477 } else if (version == 300 || version == 310) {
478 if (profile != EEsProfile) {
480 infoSink.info.message(EPrefixError, "#version: versions 300 and 310 support only the es profile");
482 profile = EEsProfile;
484 if (profile == EEsProfile) {
486 infoSink.info.message(EPrefixError, "#version: only version 300 and 310 support the es profile");
487 if (version >= FirstProfileVersion)
488 profile = ECoreProfile;
490 profile = ENoProfile;
492 // else: typical desktop case... e.g., "#version 410 core"
496 // Correct for stage type...
498 case EShLangGeometry:
499 if ((profile == EEsProfile && version < 310) ||
500 (profile != EEsProfile && version < 150)) {
502 infoSink.info.message(EPrefixError, "#version: geometry shaders require es profile with version 310 or non-es profile with version 150 or above");
503 version = (profile == EEsProfile) ? 310 : 150;
504 if (profile == EEsProfile || profile == ENoProfile)
505 profile = ECoreProfile;
508 case EShLangTessControl:
509 case EShLangTessEvaluation:
510 if ((profile == EEsProfile && version < 310) ||
511 (profile != EEsProfile && version < 150)) {
513 infoSink.info.message(EPrefixError, "#version: tessellation shaders require es profile with version 310 or non-es profile with version 150 or above");
514 version = (profile == EEsProfile) ? 310 : 400; // 150 supports the extension, correction is to 400 which does not
515 if (profile == EEsProfile || profile == ENoProfile)
516 profile = ECoreProfile;
520 if ((profile == EEsProfile && version < 310) ||
521 (profile != EEsProfile && version < 420)) {
523 infoSink.info.message(EPrefixError, "#version: compute shaders require es profile with version 310 or above, or non-es profile with version 420 or above");
524 version = profile == EEsProfile ? 310 : 420;
531 if (profile == EEsProfile && version >= 300 && versionNotFirst) {
533 infoSink.info.message(EPrefixError, "#version: statement must appear first in es-profile shader; before comments or newlines");
536 // Check for SPIR-V compatibility
537 if (spvVersion.spv != 0) {
540 if (spvVersion.vulkan >= 100 && version < 310) {
542 infoSink.info.message(EPrefixError, "#version: ES shaders for Vulkan SPIR-V require version 310 or higher");
545 if (spvVersion.openGl >= 100) {
547 infoSink.info.message(EPrefixError, "#version: ES shaders for OpenGL SPIR-V are not supported");
551 case ECompatibilityProfile:
552 infoSink.info.message(EPrefixError, "#version: compilation for SPIR-V does not support the compatibility profile");
555 if (spvVersion.vulkan >= 100 && version < 140) {
557 infoSink.info.message(EPrefixError, "#version: Desktop shaders for Vulkan SPIR-V require version 140 or higher");
560 if (spvVersion.openGl >= 100 && version < 330) {
562 infoSink.info.message(EPrefixError, "#version: Desktop shaders for OpenGL SPIR-V require version 330 or higher");
569 // A meta check on the condition of the compiler itself...
575 // versions are complete
585 // versions are complete
595 infoSink.info << "Warning, version " << version << " is not yet complete; most version-specific features are present, but some are missing.\n";
599 infoSink.info << "Warning, version " << version << " is unknown.\n";
607 // This is the common setup and cleanup code for PreprocessDeferred and
609 // It takes any callable with a signature of
610 // bool (TParseContextBase& parseContext, TPpContext& ppContext,
611 // TInputScanner& input, bool versionWillBeError,
612 // TSymbolTable& , TIntermediate& ,
613 // EShOptimizationLevel , EShMessages );
614 // Which returns false if a failure was detected and true otherwise.
616 template<typename ProcessingContext>
617 bool ProcessDeferred(
619 const char* const shaderStrings[],
620 const int numStrings,
621 const int* inputLengths,
622 const char* const stringNames[],
623 const char* customPreamble,
624 const EShOptimizationLevel optLevel,
625 const TBuiltInResource* resources,
626 int defaultVersion, // use 100 for ES environment, 110 for desktop; this is the GLSL version, not SPIR-V or Vulkan
627 EProfile defaultProfile,
628 // set version/profile to defaultVersion/defaultProfile regardless of the #version
629 // directive in the source code
630 bool forceDefaultVersionAndProfile,
631 bool forwardCompatible, // give errors for use of deprecated features
632 EShMessages messages, // warnings/errors/AST; things to print out
633 TIntermediate& intermediate, // returned tree, etc.
634 ProcessingContext& processingContext,
635 bool requireNonempty,
636 TShader::Includer& includer,
637 const std::string sourceEntryPointName = ""
643 // This must be undone (.pop()) by the caller, after it finishes consuming the created tree.
644 GetThreadPoolAllocator().push();
649 // Move to length-based strings, rather than null-terminated strings.
650 // Also, add strings to include the preamble and to ensure the shader is not null,
651 // which lets the grammar accept what was a null (post preprocessing) shader.
653 // Shader will look like
654 // string 0: system preamble
655 // string 1: custom preamble
656 // string 2...numStrings+1: user's shader
657 // string numStrings+2: "int;"
658 const int numPre = 2;
659 const int numPost = requireNonempty? 1 : 0;
660 const int numTotal = numPre + numStrings + numPost;
661 size_t* lengths = new size_t[numTotal];
662 const char** strings = new const char*[numTotal];
663 const char** names = new const char*[numTotal];
664 for (int s = 0; s < numStrings; ++s) {
665 strings[s + numPre] = shaderStrings[s];
666 if (inputLengths == 0 || inputLengths[s] < 0)
667 lengths[s + numPre] = strlen(shaderStrings[s]);
669 lengths[s + numPre] = inputLengths[s];
671 if (stringNames != nullptr) {
672 for (int s = 0; s < numStrings; ++s)
673 names[s + numPre] = stringNames[s];
675 for (int s = 0; s < numStrings; ++s)
676 names[s + numPre] = nullptr;
679 // First, without using the preprocessor or parser, find the #version, so we know what
680 // symbol tables, processing rules, etc. to set up. This does not need the extra strings
681 // outlined above, just the user shader.
684 glslang::TInputScanner userInput(numStrings, &strings[numPre], &lengths[numPre]); // no preamble
685 bool versionNotFirstToken;
686 bool versionNotFirst = userInput.scanVersion(version, profile, versionNotFirstToken);
687 bool versionNotFound = version == 0;
688 if (forceDefaultVersionAndProfile) {
689 if (! (messages & EShMsgSuppressWarnings) && ! versionNotFound &&
690 (version != defaultVersion || profile != defaultProfile)) {
691 compiler->infoSink.info << "Warning, (version, profile) forced to be ("
692 << defaultVersion << ", " << ProfileName(defaultProfile)
693 << "), while in source code it is ("
694 << version << ", " << ProfileName(profile) << ")\n";
697 if (versionNotFound) {
698 versionNotFirstToken = false;
699 versionNotFirst = false;
700 versionNotFound = false;
702 version = defaultVersion;
703 profile = defaultProfile;
705 SpvVersion spvVersion;
706 if (messages & EShMsgSpvRules)
707 spvVersion.spv = 0x00010000; // TODO: eventually have this come from the outside
708 EShSource source = (messages & EShMsgReadHlsl) ? EShSourceHlsl : EShSourceGlsl;
709 if (messages & EShMsgVulkanRules)
710 spvVersion.vulkan = 100; // TODO: eventually have this come from the outside
711 else if (spvVersion.spv != 0)
712 spvVersion.openGl = 100; // TODO: eventually have this come from the outside
713 bool goodVersion = DeduceVersionProfile(compiler->infoSink, compiler->getLanguage(), versionNotFirst, defaultVersion, source, version, profile, spvVersion);
714 bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst));
715 bool warnVersionNotFirst = false;
716 if (! versionWillBeError && versionNotFirstToken) {
717 if (messages & EShMsgRelaxedErrors)
718 warnVersionNotFirst = true;
720 versionWillBeError = true;
723 intermediate.setSource(source);
724 intermediate.setVersion(version);
725 intermediate.setProfile(profile);
726 intermediate.setSpv(spvVersion);
727 if (spvVersion.vulkan >= 100)
728 intermediate.setOriginUpperLeft();
729 if (messages & EShMsgHlslOffsets) // source-language independent
730 intermediate.setHlslOffsets();
731 SetupBuiltinSymbolTable(version, profile, spvVersion, source);
733 TSymbolTable* cachedTable = SharedSymbolTables[MapVersionToIndex(version)]
734 [MapSpvVersionToIndex(spvVersion)]
735 [MapProfileToIndex(profile)]
736 [MapSourceToIndex(source)]
737 [compiler->getLanguage()];
739 // Dynamically allocate the symbol table so we can control when it is deallocated WRT the pool.
740 TSymbolTable* symbolTableMemory = new TSymbolTable;
741 TSymbolTable& symbolTable = *symbolTableMemory;
743 symbolTable.adoptLevels(*cachedTable);
745 // Add built-in symbols that are potentially context dependent;
746 // they get popped again further down.
747 if (! AddContextSpecificSymbols(resources, compiler->infoSink, symbolTable, version, profile, spvVersion,
748 compiler->getLanguage(), source))
752 // Now we can process the full shader under proper symbols and rules.
755 TParseContextBase* parseContext = CreateParseContext(symbolTable, intermediate, version, profile, source,
756 compiler->getLanguage(), compiler->infoSink,
757 spvVersion, forwardCompatible, messages, false, sourceEntryPointName);
759 TPpContext ppContext(*parseContext, names[numPre]? names[numPre]: "", includer);
761 // only GLSL (bison triggered, really) needs an externally set scan context
762 glslang::TScanContext scanContext(*parseContext);
763 if ((messages & EShMsgReadHlsl) == 0)
764 parseContext->setScanContext(&scanContext);
766 parseContext->setPpContext(&ppContext);
767 parseContext->setLimits(*resources);
769 parseContext->addError();
770 if (warnVersionNotFirst) {
773 parseContext->warn(loc, "Illegal to have non-comment, non-whitespace tokens before #version", "#version", "");
776 parseContext->initializeExtensionBehavior();
778 // Fill in the strings as outlined above.
779 std::string preamble;
780 parseContext->getPreamble(preamble);
781 strings[0] = preamble.c_str();
782 lengths[0] = strlen(strings[0]);
784 strings[1] = customPreamble;
785 lengths[1] = strlen(strings[1]);
788 if (requireNonempty) {
789 const int postIndex = numStrings + numPre;
790 strings[postIndex] = "\n int;";
791 lengths[postIndex] = strlen(strings[numStrings + numPre]);
792 names[postIndex] = nullptr;
794 TInputScanner fullInput(numStrings + numPre + numPost, strings, lengths, names, numPre, numPost);
796 // Push a new symbol allocation scope that will get used for the shader's globals.
799 bool success = processingContext(*parseContext, ppContext, fullInput,
800 versionWillBeError, symbolTable,
801 intermediate, optLevel, messages);
803 // Clean up the symbol table. The AST is self-sufficient now.
804 delete symbolTableMemory;
814 // Responsible for keeping track of the most recent source string and line in
815 // the preprocessor and outputting newlines appropriately if the source string
817 class SourceLineSynchronizer {
819 SourceLineSynchronizer(const std::function<int()>& lastSourceIndex,
820 std::stringstream* output)
821 : getLastSourceIndex(lastSourceIndex), output(output), lastSource(-1), lastLine(0) {}
822 // SourceLineSynchronizer(const SourceLineSynchronizer&) = delete;
823 // SourceLineSynchronizer& operator=(const SourceLineSynchronizer&) = delete;
825 // Sets the internally tracked source string index to that of the most
826 // recently read token. If we switched to a new source string, returns
827 // true and inserts a newline. Otherwise, returns false and outputs nothing.
828 bool syncToMostRecentString() {
829 if (getLastSourceIndex() != lastSource) {
830 // After switching to a new source string, we need to reset lastLine
831 // because line number resets every time a new source string is
832 // used. We also need to output a newline to separate the output
833 // from the previous source string (if there is one).
834 if (lastSource != -1 || lastLine != 0)
835 *output << std::endl;
836 lastSource = getLastSourceIndex();
843 // Calls syncToMostRecentString() and then sets the internally tracked line
844 // number to tokenLine. If we switched to a new line, returns true and inserts
845 // newlines appropriately. Otherwise, returns false and outputs nothing.
846 bool syncToLine(int tokenLine) {
847 syncToMostRecentString();
848 const bool newLineStarted = lastLine < tokenLine;
849 for (; lastLine < tokenLine; ++lastLine) {
850 if (lastLine > 0) *output << std::endl;
852 return newLineStarted;
855 // Sets the internally tracked line number to newLineNum.
856 void setLineNum(int newLineNum) { lastLine = newLineNum; }
859 SourceLineSynchronizer& operator=(const SourceLineSynchronizer&);
861 // A function for getting the index of the last valid source string we've
863 const std::function<int()> getLastSourceIndex;
864 // output stream for newlines.
865 std::stringstream* output;
866 // lastSource is the source string index (starting from 0) of the last token
867 // processed. It is tracked in order for newlines to be inserted when a new
868 // source string starts. -1 means we haven't started processing any source
871 // lastLine is the line number (starting from 1) of the last token processed.
872 // It is tracked in order for newlines to be inserted when a token appears
873 // on a new line. 0 means we haven't started processing any line in the
874 // current source string.
878 // DoPreprocessing is a valid ProcessingContext template argument,
879 // which only performs the preprocessing step of compilation.
880 // It places the result in the "string" argument to its constructor.
881 struct DoPreprocessing {
882 explicit DoPreprocessing(std::string* string): outputString(string) {}
883 bool operator()(TParseContextBase& parseContext, TPpContext& ppContext,
884 TInputScanner& input, bool versionWillBeError,
885 TSymbolTable&, TIntermediate&,
886 EShOptimizationLevel, EShMessages)
888 // This is a list of tokens that do not require a space before or after.
889 static const std::string unNeededSpaceTokens = ";()[]";
890 static const std::string noSpaceBeforeTokens = ",";
891 glslang::TPpToken ppToken;
893 parseContext.setScanner(&input);
894 ppContext.setInput(input, versionWillBeError);
896 std::stringstream outputStream;
897 SourceLineSynchronizer lineSync(
898 std::bind(&TInputScanner::getLastValidSourceIndex, &input), &outputStream);
900 parseContext.setExtensionCallback([&lineSync, &outputStream](
901 int line, const char* extension, const char* behavior) {
902 lineSync.syncToLine(line);
903 outputStream << "#extension " << extension << " : " << behavior;
906 parseContext.setLineCallback([&lineSync, &outputStream, &parseContext](
907 int curLineNum, int newLineNum, bool hasSource, int sourceNum, const char* sourceName) {
908 // SourceNum is the number of the source-string that is being parsed.
909 lineSync.syncToLine(curLineNum);
910 outputStream << "#line " << newLineNum;
913 if (sourceName != nullptr) {
914 outputStream << "\"" << sourceName << "\"";
916 outputStream << sourceNum;
919 if (parseContext.lineDirectiveShouldSetNextLine()) {
920 // newLineNum is the new line number for the line following the #line
921 // directive. So the new line number for the current line is
924 outputStream << std::endl;
925 // And we are at the next line of the #line directive now.
926 lineSync.setLineNum(newLineNum + 1);
929 parseContext.setVersionCallback(
930 [&lineSync, &outputStream](int line, int version, const char* str) {
931 lineSync.syncToLine(line);
932 outputStream << "#version " << version;
934 outputStream << " " << str;
938 parseContext.setPragmaCallback([&lineSync, &outputStream](
939 int line, const glslang::TVector<glslang::TString>& ops) {
940 lineSync.syncToLine(line);
941 outputStream << "#pragma ";
942 for(size_t i = 0; i < ops.size(); ++i) {
943 outputStream << ops[i];
947 parseContext.setErrorCallback([&lineSync, &outputStream](
948 int line, const char* errorMessage) {
949 lineSync.syncToLine(line);
950 outputStream << "#error " << errorMessage;
953 int lastToken = EndOfInput; // lastToken records the last token processed.
955 int token = ppContext.tokenize(ppToken);
956 if (token == EndOfInput)
959 bool isNewString = lineSync.syncToMostRecentString();
960 bool isNewLine = lineSync.syncToLine(ppToken.loc.line);
963 // Don't emit whitespace onto empty lines.
964 // Copy any whitespace characters at the start of a line
965 // from the input to the output.
966 outputStream << std::string(ppToken.loc.column - 1, ' ');
969 // Output a space in between tokens, but not at the start of a line,
970 // and also not around special tokens. This helps with readability
972 if (!isNewString && !isNewLine && lastToken != EndOfInput &&
973 (unNeededSpaceTokens.find((char)token) == std::string::npos) &&
974 (unNeededSpaceTokens.find((char)lastToken) == std::string::npos) &&
975 (noSpaceBeforeTokens.find((char)token) == std::string::npos)) {
979 outputStream << ppToken.name;
981 outputStream << std::endl;
982 *outputString = outputStream.str();
985 if (parseContext.getNumErrors() > 0) {
987 parseContext.infoSink.info.prefix(EPrefixError);
988 parseContext.infoSink.info << parseContext.getNumErrors() << " compilation errors. No code generated.\n\n";
992 std::string* outputString;
995 // DoFullParse is a valid ProcessingConext template argument for fully
996 // parsing the shader. It populates the "intermediate" with the AST.
998 bool operator()(TParseContextBase& parseContext, TPpContext& ppContext,
999 TInputScanner& fullInput, bool versionWillBeError,
1000 TSymbolTable&, TIntermediate& intermediate,
1001 EShOptimizationLevel optLevel, EShMessages messages)
1003 bool success = true;
1004 // Parse the full shader.
1005 if (! parseContext.parseShaderStrings(ppContext, fullInput, versionWillBeError))
1008 if (success && intermediate.getTreeRoot()) {
1009 if (optLevel == EShOptNoGeneration)
1010 parseContext.infoSink.info.message(EPrefixNone, "No errors. No code generation or linking was requested.");
1012 success = intermediate.postProcess(intermediate.getTreeRoot(), parseContext.getLanguage());
1013 } else if (! success) {
1014 parseContext.infoSink.info.prefix(EPrefixError);
1015 parseContext.infoSink.info << parseContext.getNumErrors() << " compilation errors. No code generated.\n\n";
1018 if (messages & EShMsgAST)
1019 intermediate.output(parseContext.infoSink, true);
1025 // Take a single compilation unit, and run the preprocessor on it.
1026 // Return: True if there were no issues found in preprocessing,
1027 // False if during preprocessing any unknown version, pragmas or
1028 // extensions were found.
1029 bool PreprocessDeferred(
1030 TCompiler* compiler,
1031 const char* const shaderStrings[],
1032 const int numStrings,
1033 const int* inputLengths,
1034 const char* const stringNames[],
1035 const char* preamble,
1036 const EShOptimizationLevel optLevel,
1037 const TBuiltInResource* resources,
1038 int defaultVersion, // use 100 for ES environment, 110 for desktop
1039 EProfile defaultProfile,
1040 bool forceDefaultVersionAndProfile,
1041 bool forwardCompatible, // give errors for use of deprecated features
1042 EShMessages messages, // warnings/errors/AST; things to print out
1043 TShader::Includer& includer,
1044 TIntermediate& intermediate, // returned tree, etc.
1045 std::string* outputString)
1047 DoPreprocessing parser(outputString);
1048 return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
1049 preamble, optLevel, resources, defaultVersion,
1050 defaultProfile, forceDefaultVersionAndProfile,
1051 forwardCompatible, messages, intermediate, parser,
1056 // do a partial compile on the given strings for a single compilation unit
1057 // for a potential deferred link into a single stage (and deferred full compile of that
1058 // stage through machine-dependent compilation).
1060 // all preprocessing, parsing, semantic checks, etc. for a single compilation unit
1063 // return: the tree and other information is filled into the intermediate argument,
1064 // and true is returned by the function for success.
1066 bool CompileDeferred(
1067 TCompiler* compiler,
1068 const char* const shaderStrings[],
1069 const int numStrings,
1070 const int* inputLengths,
1071 const char* const stringNames[],
1072 const char* preamble,
1073 const EShOptimizationLevel optLevel,
1074 const TBuiltInResource* resources,
1075 int defaultVersion, // use 100 for ES environment, 110 for desktop
1076 EProfile defaultProfile,
1077 bool forceDefaultVersionAndProfile,
1078 bool forwardCompatible, // give errors for use of deprecated features
1079 EShMessages messages, // warnings/errors/AST; things to print out
1080 TIntermediate& intermediate,// returned tree, etc.
1081 TShader::Includer& includer,
1082 const std::string sourceEntryPointName = "")
1085 return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
1086 preamble, optLevel, resources, defaultVersion,
1087 defaultProfile, forceDefaultVersionAndProfile,
1088 forwardCompatible, messages, intermediate, parser,
1089 true, includer, sourceEntryPointName);
1092 } // end anonymous namespace for local functions
1095 // ShInitialize() should be called exactly once per process, not per thread.
1099 glslang::InitGlobalLock();
1101 if (! InitProcess())
1104 if (! PerProcessGPA)
1105 PerProcessGPA = new TPoolAllocator();
1107 glslang::TScanContext::fillInKeywordMap();
1109 glslang::HlslScanContext::fillInKeywordMap();
1116 // Driver calls these to create and destroy compiler/linker
1120 ShHandle ShConstructCompiler(const EShLanguage language, int debugOptions)
1125 TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(language, debugOptions));
1127 return reinterpret_cast<void*>(base);
1130 ShHandle ShConstructLinker(const EShExecutable executable, int debugOptions)
1135 TShHandleBase* base = static_cast<TShHandleBase*>(ConstructLinker(executable, debugOptions));
1137 return reinterpret_cast<void*>(base);
1140 ShHandle ShConstructUniformMap()
1145 TShHandleBase* base = static_cast<TShHandleBase*>(ConstructUniformMap());
1147 return reinterpret_cast<void*>(base);
1150 void ShDestruct(ShHandle handle)
1155 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
1157 if (base->getAsCompiler())
1158 DeleteCompiler(base->getAsCompiler());
1159 else if (base->getAsLinker())
1160 DeleteLinker(base->getAsLinker());
1161 else if (base->getAsUniformMap())
1162 DeleteUniformMap(base->getAsUniformMap());
1166 // Cleanup symbol tables
1168 int __fastcall ShFinalize()
1170 for (int version = 0; version < VersionCount; ++version) {
1171 for (int spvVersion = 0; spvVersion < SpvVersionCount; ++spvVersion) {
1172 for (int p = 0; p < ProfileCount; ++p) {
1173 for (int source = 0; source < SourceCount; ++source) {
1174 for (int stage = 0; stage < EShLangCount; ++stage) {
1175 delete SharedSymbolTables[version][spvVersion][p][source][stage];
1176 SharedSymbolTables[version][spvVersion][p][source][stage] = 0;
1183 for (int version = 0; version < VersionCount; ++version) {
1184 for (int spvVersion = 0; spvVersion < SpvVersionCount; ++spvVersion) {
1185 for (int p = 0; p < ProfileCount; ++p) {
1186 for (int source = 0; source < SourceCount; ++source) {
1187 for (int pc = 0; pc < EPcCount; ++pc) {
1188 delete CommonSymbolTable[version][spvVersion][p][source][pc];
1189 CommonSymbolTable[version][spvVersion][p][source][pc] = 0;
1196 if (PerProcessGPA) {
1197 PerProcessGPA->popAll();
1198 delete PerProcessGPA;
1202 glslang::TScanContext::deleteKeywordMap();
1204 glslang::HlslScanContext::deleteKeywordMap();
1211 // Do a full compile on the given strings for a single compilation unit
1212 // forming a complete stage. The result of the machine dependent compilation
1213 // is left in the provided compile object.
1215 // Return: The return value is really boolean, indicating
1216 // success (1) or failure (0).
1219 const ShHandle handle,
1220 const char* const shaderStrings[],
1221 const int numStrings,
1222 const int* inputLengths,
1223 const EShOptimizationLevel optLevel,
1224 const TBuiltInResource* resources,
1225 int /*debugOptions*/,
1226 int defaultVersion, // use 100 for ES environment, 110 for desktop
1227 bool forwardCompatible, // give errors for use of deprecated features
1228 EShMessages messages // warnings/errors/AST; things to print out
1231 // Map the generic handle to the C++ object
1235 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1236 TCompiler* compiler = base->getAsCompiler();
1240 compiler->infoSink.info.erase();
1241 compiler->infoSink.debug.erase();
1243 TIntermediate intermediate(compiler->getLanguage());
1244 TShader::ForbidIncluder includer;
1245 bool success = CompileDeferred(compiler, shaderStrings, numStrings, inputLengths, nullptr,
1246 "", optLevel, resources, defaultVersion, ENoProfile, false,
1247 forwardCompatible, messages, intermediate, includer);
1250 // Call the machine dependent compiler
1252 if (success && intermediate.getTreeRoot() && optLevel != EShOptNoGeneration)
1253 success = compiler->compile(intermediate.getTreeRoot(), intermediate.getVersion(), intermediate.getProfile());
1255 intermediate.removeTree();
1257 // Throw away all the temporary memory used by the compilation process.
1258 // The push was done in the CompileDeferred() call above.
1259 GetThreadPoolAllocator().pop();
1261 return success ? 1 : 0;
1265 // Link the given compile objects.
1267 // Return: The return value of is really boolean, indicating
1268 // success or failure.
1271 const ShHandle linkHandle,
1272 const ShHandle compHandles[],
1273 const int numHandles)
1275 if (linkHandle == 0 || numHandles == 0)
1278 THandleList cObjects;
1280 for (int i = 0; i < numHandles; ++i) {
1281 if (compHandles[i] == 0)
1283 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(compHandles[i]);
1284 if (base->getAsLinker()) {
1285 cObjects.push_back(base->getAsLinker());
1287 if (base->getAsCompiler())
1288 cObjects.push_back(base->getAsCompiler());
1290 if (cObjects[i] == 0)
1294 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(linkHandle);
1295 TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
1300 linker->infoSink.info.erase();
1302 for (int i = 0; i < numHandles; ++i) {
1303 if (cObjects[i]->getAsCompiler()) {
1304 if (! cObjects[i]->getAsCompiler()->linkable()) {
1305 linker->infoSink.info.message(EPrefixError, "Not all shaders have valid object code.");
1311 bool ret = linker->link(cObjects);
1317 // ShSetEncrpytionMethod is a place-holder for specifying
1318 // how source code is encrypted.
1320 void ShSetEncryptionMethod(ShHandle handle)
1327 // Return any compiler/linker/uniformmap log of messages for the application.
1329 const char* ShGetInfoLog(const ShHandle handle)
1337 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
1338 TInfoSink* infoSink;
1340 if (base->getAsCompiler())
1341 infoSink = &(base->getAsCompiler()->getInfoSink());
1342 else if (base->getAsLinker())
1343 infoSink = &(base->getAsLinker()->getInfoSink());
1347 infoSink->info << infoSink->debug.c_str();
1348 return infoSink->info.c_str();
1352 // Return the resulting binary code from the link process. Structure
1353 // is machine dependent.
1355 const void* ShGetExecutable(const ShHandle handle)
1363 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1365 TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
1369 return linker->getObjectCode();
1373 // Let the linker know where the application said it's attributes are bound.
1374 // The linker does not use these values, they are remapped by the ICD or
1375 // hardware. It just needs them to know what's aliased.
1377 // Return: The return value of is really boolean, indicating
1378 // success or failure.
1380 int ShSetVirtualAttributeBindings(const ShHandle handle, const ShBindingTable* table)
1388 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1389 TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
1394 linker->setAppAttributeBindings(table);
1400 // Let the linker know where the predefined attributes have to live.
1402 int ShSetFixedAttributeBindings(const ShHandle handle, const ShBindingTable* table)
1410 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1411 TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
1416 linker->setFixedAttributeBindings(table);
1421 // Some attribute locations are off-limits to the linker...
1423 int ShExcludeAttributes(const ShHandle handle, int *attributes, int count)
1431 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1432 TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
1436 linker->setExcludedAttributes(attributes, count);
1442 // Return the index for OpenGL to use for knowing where a uniform lives.
1444 // Return: The return value of is really boolean, indicating
1445 // success or failure.
1447 int ShGetUniformLocation(const ShHandle handle, const char* name)
1455 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1456 TUniformMap* uniformMap= base->getAsUniformMap();
1457 if (uniformMap == 0)
1460 return uniformMap->getLocation(name);
1463 ////////////////////////////////////////////////////////////////////////////////////////////
1465 // Deferred-Lowering C++ Interface
1466 // -----------------------------------
1468 // Below is a new alternate C++ interface that might potentially replace the above
1469 // opaque handle-based interface.
1471 // See more detailed comment in ShaderLang.h
1476 #include "../Include/revision.h"
1478 const char* GetEsslVersionString()
1480 return "OpenGL ES GLSL 3.00 glslang LunarG Khronos." GLSLANG_REVISION " " GLSLANG_DATE;
1483 const char* GetGlslVersionString()
1485 return "4.20 glslang LunarG Khronos." GLSLANG_REVISION " " GLSLANG_DATE;
1488 int GetKhronosToolId()
1493 bool InitializeProcess()
1495 return ShInitialize() != 0;
1498 void FinalizeProcess()
1503 class TDeferredCompiler : public TCompiler {
1505 TDeferredCompiler(EShLanguage s, TInfoSink& i) : TCompiler(s, i) { }
1506 virtual bool compile(TIntermNode*, int = 0, EProfile = ENoProfile) { return true; }
1509 TShader::TShader(EShLanguage s)
1510 : pool(0), stage(s), lengths(nullptr), stringNames(nullptr), preamble("")
1512 infoSink = new TInfoSink;
1513 compiler = new TDeferredCompiler(stage, *infoSink);
1514 intermediate = new TIntermediate(s);
1521 delete intermediate;
1525 void TShader::setStrings(const char* const* s, int n)
1532 void TShader::setStringsWithLengths(const char* const* s, const int* l, int n)
1539 void TShader::setStringsWithLengthsAndNames(
1540 const char* const* s, const int* l, const char* const* names, int n)
1545 stringNames = names;
1548 void TShader::setEntryPoint(const char* entryPoint)
1550 intermediate->setEntryPointName(entryPoint);
1553 void TShader::setSourceEntryPoint(const char* name)
1555 sourceEntryPointName = name;
1558 void TShader::setShiftSamplerBinding(unsigned int base) { intermediate->setShiftSamplerBinding(base); }
1559 void TShader::setShiftTextureBinding(unsigned int base) { intermediate->setShiftTextureBinding(base); }
1560 void TShader::setShiftImageBinding(unsigned int base) { intermediate->setShiftImageBinding(base); }
1561 void TShader::setShiftUboBinding(unsigned int base) { intermediate->setShiftUboBinding(base); }
1562 void TShader::setShiftSsboBinding(unsigned int base) { intermediate->setShiftSsboBinding(base); }
1563 void TShader::setAutoMapBindings(bool map) { intermediate->setAutoMapBindings(map); }
1564 void TShader::setFlattenUniformArrays(bool flatten) { intermediate->setFlattenUniformArrays(flatten); }
1565 void TShader::setNoStorageFormat(bool useUnknownFormat) { intermediate->setNoStorageFormat(useUnknownFormat); }
1568 // Turn the shader strings into a parse tree in the TIntermediate.
1570 // Returns true for success.
1572 bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
1573 bool forwardCompatible, EShMessages messages, Includer& includer)
1578 pool = new TPoolAllocator();
1579 SetThreadPoolAllocator(*pool);
1583 return CompileDeferred(compiler, strings, numStrings, lengths, stringNames,
1584 preamble, EShOptNone, builtInResources, defaultVersion,
1585 defaultProfile, forceDefaultVersionAndProfile,
1586 forwardCompatible, messages, *intermediate, includer, sourceEntryPointName);
1589 bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion, bool forwardCompatible, EShMessages messages)
1591 return parse(builtInResources, defaultVersion, ENoProfile, false, forwardCompatible, messages);
1594 // Fill in a string with the result of preprocessing ShaderStrings
1595 // Returns true if all extensions, pragmas and version strings were valid.
1596 bool TShader::preprocess(const TBuiltInResource* builtInResources,
1597 int defaultVersion, EProfile defaultProfile,
1598 bool forceDefaultVersionAndProfile,
1599 bool forwardCompatible, EShMessages message,
1600 std::string* output_string,
1606 pool = new TPoolAllocator();
1607 SetThreadPoolAllocator(*pool);
1611 return PreprocessDeferred(compiler, strings, numStrings, lengths, stringNames, preamble,
1612 EShOptNone, builtInResources, defaultVersion,
1613 defaultProfile, forceDefaultVersionAndProfile,
1614 forwardCompatible, message, includer, *intermediate, output_string);
1617 const char* TShader::getInfoLog()
1619 return infoSink->info.c_str();
1622 const char* TShader::getInfoDebugLog()
1624 return infoSink->debug.c_str();
1627 TProgram::TProgram() : pool(0), reflection(0), ioMapper(nullptr), linked(false)
1629 infoSink = new TInfoSink;
1630 for (int s = 0; s < EShLangCount; ++s) {
1631 intermediate[s] = 0;
1632 newedIntermediate[s] = false;
1636 TProgram::~TProgram()
1642 for (int s = 0; s < EShLangCount; ++s)
1643 if (newedIntermediate[s])
1644 delete intermediate[s];
1650 // Merge the compilation units within each stage into a single TIntermediate.
1651 // All starting compilation units need to be the result of calling TShader::parse().
1653 // Return true for success.
1655 bool TProgram::link(EShMessages messages)
1663 pool = new TPoolAllocator();
1664 SetThreadPoolAllocator(*pool);
1666 for (int s = 0; s < EShLangCount; ++s) {
1667 if (! linkStage((EShLanguage)s, messages))
1671 // TODO: Link: cross-stage error checking
1677 // Merge the compilation units within the given stage into a single TIntermediate.
1679 // Return true for success.
1681 bool TProgram::linkStage(EShLanguage stage, EShMessages messages)
1683 if (stages[stage].size() == 0)
1686 int numEsShaders = 0, numNonEsShaders = 0;
1687 for (auto it = stages[stage].begin(); it != stages[stage].end(); ++it) {
1688 if ((*it)->intermediate->getProfile() == EEsProfile) {
1695 if (numEsShaders > 0 && numNonEsShaders > 0) {
1696 infoSink->info.message(EPrefixError, "Cannot mix ES profile with non-ES profile shaders");
1698 } else if (numEsShaders > 1) {
1699 infoSink->info.message(EPrefixError, "Cannot attach multiple ES shaders of the same type to a single program");
1704 // Be efficient for the common single compilation unit per stage case,
1705 // reusing it's TIntermediate instead of merging into a new one.
1707 TIntermediate *firstIntermediate = stages[stage].front()->intermediate;
1708 if (stages[stage].size() == 1)
1709 intermediate[stage] = firstIntermediate;
1711 intermediate[stage] = new TIntermediate(stage,
1712 firstIntermediate->getVersion(),
1713 firstIntermediate->getProfile());
1716 // The new TIntermediate must use the same origin as the original TIntermediates.
1717 // Otherwise linking will fail due to different coordinate systems.
1718 if (firstIntermediate->getOriginUpperLeft()) {
1719 intermediate[stage]->setOriginUpperLeft();
1721 intermediate[stage]->setSpv(firstIntermediate->getSpv());
1723 newedIntermediate[stage] = true;
1726 if (messages & EShMsgAST)
1727 infoSink->info << "\nLinked " << StageName(stage) << " stage:\n\n";
1729 if (stages[stage].size() > 1) {
1730 std::list<TShader*>::const_iterator it;
1731 for (it = stages[stage].begin(); it != stages[stage].end(); ++it)
1732 intermediate[stage]->merge(*infoSink, *(*it)->intermediate);
1735 intermediate[stage]->finalCheck(*infoSink, (messages & EShMsgKeepUncalled) != 0);
1737 if (messages & EShMsgAST)
1738 intermediate[stage]->output(*infoSink, true);
1740 return intermediate[stage]->getNumErrors() == 0;
1743 const char* TProgram::getInfoLog()
1745 return infoSink->info.c_str();
1748 const char* TProgram::getInfoDebugLog()
1750 return infoSink->debug.c_str();
1754 // Reflection implementation.
1757 bool TProgram::buildReflection()
1759 if (! linked || reflection)
1762 reflection = new TReflection;
1764 for (int s = 0; s < EShLangCount; ++s) {
1765 if (intermediate[s]) {
1766 if (! reflection->addStage((EShLanguage)s, *intermediate[s]))
1774 int TProgram::getNumLiveUniformVariables() const { return reflection->getNumUniforms(); }
1775 int TProgram::getNumLiveUniformBlocks() const { return reflection->getNumUniformBlocks(); }
1776 const char* TProgram::getUniformName(int index) const { return reflection->getUniform(index).name.c_str(); }
1777 const char* TProgram::getUniformBlockName(int index) const { return reflection->getUniformBlock(index).name.c_str(); }
1778 int TProgram::getUniformBlockSize(int index) const { return reflection->getUniformBlock(index).size; }
1779 int TProgram::getUniformIndex(const char* name) const { return reflection->getIndex(name); }
1780 int TProgram::getUniformBlockIndex(int index) const { return reflection->getUniform(index).index; }
1781 int TProgram::getUniformType(int index) const { return reflection->getUniform(index).glDefineType; }
1782 int TProgram::getUniformBufferOffset(int index) const { return reflection->getUniform(index).offset; }
1783 int TProgram::getUniformArraySize(int index) const { return reflection->getUniform(index).size; }
1784 int TProgram::getNumLiveAttributes() const { return reflection->getNumAttributes(); }
1785 const char* TProgram::getAttributeName(int index) const { return reflection->getAttribute(index).name.c_str(); }
1786 int TProgram::getAttributeType(int index) const { return reflection->getAttribute(index).glDefineType; }
1787 const TType* TProgram::getAttributeTType(int index) const { return reflection->getAttribute(index).getType(); }
1788 const TType* TProgram::getUniformTType(int index) const { return reflection->getUniform(index).getType(); }
1789 const TType* TProgram::getUniformBlockTType(int index) const { return reflection->getUniformBlock(index).getType(); }
1790 unsigned TProgram::getLocalSize(int dim) const { return reflection->getLocalSize(dim); }
1792 void TProgram::dumpReflection() { reflection->dump(); }
1795 // I/O mapping implementation.
1797 bool TProgram::mapIO(TIoMapResolver* resolver)
1799 if (! linked || ioMapper)
1802 ioMapper = new TIoMapper;
1804 for (int s = 0; s < EShLangCount; ++s) {
1805 if (intermediate[s]) {
1806 if (! ioMapper->addStage((EShLanguage)s, *intermediate[s], *infoSink, resolver))
1814 } // end namespace glslang