• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3 // Copyright (C) 2013-2016 LunarG, Inc.
4 // Copyright (C) 2015-2020 Google, Inc.
5 //
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
10 // are met:
11 //
12 //    Redistributions of source code must retain the above copyright
13 //    notice, this list of conditions and the following disclaimer.
14 //
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.
19 //
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.
23 //
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.
36 //
37 
38 //
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.
43 //
44 #include <cstring>
45 #include <iostream>
46 #include <sstream>
47 #include <memory>
48 #include "SymbolTable.h"
49 #include "ParseHelper.h"
50 #include "Scan.h"
51 #include "ScanContext.h"
52 
53 #ifdef ENABLE_HLSL
54 #include "../HLSL/hlslParseHelper.h"
55 #include "../HLSL/hlslParseables.h"
56 #include "../HLSL/hlslScanContext.h"
57 #endif
58 
59 #include "../Include/ShHandle.h"
60 #include "../../OGLCompilersDLL/InitializeDll.h"
61 
62 #include "preprocessor/PpContext.h"
63 
64 #define SH_EXPORTING
65 #include "../Public/ShaderLang.h"
66 #include "reflection.h"
67 #include "iomapper.h"
68 #include "Initialize.h"
69 
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"
74 
75 // Build-time generated includes
76 #include "glslang/build_info.h"
77 
78 namespace { // anonymous namespace for file-local functions and symbols
79 
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;
83 
84 using namespace glslang;
85 
86 // Create a language specific version of parseables.
CreateBuiltInParseables(TInfoSink & infoSink,EShSource source)87 TBuiltInParseables* CreateBuiltInParseables(TInfoSink& infoSink, EShSource source)
88 {
89     switch (source) {
90     case EShSourceGlsl: return new TBuiltIns();              // GLSL builtIns
91 #ifdef ENABLE_HLSL
92     case EShSourceHlsl: return new TBuiltInParseablesHlsl(); // HLSL intrinsics
93 #endif
94 
95     default:
96         infoSink.info.message(EPrefixInternalError, "Unable to determine source language");
97         return nullptr;
98     }
99 }
100 
101 // Create a language specific version of a parse context.
CreateParseContext(TSymbolTable & symbolTable,TIntermediate & intermediate,int version,EProfile profile,EShSource source,EShLanguage language,TInfoSink & infoSink,SpvVersion spvVersion,bool forwardCompatible,EShMessages messages,bool parsingBuiltIns,std::string sourceEntryPointName="")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 = "")
107 {
108     switch (source) {
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);
115     }
116 #ifdef ENABLE_HLSL
117     case EShSourceHlsl:
118         return new HlslParseContext(symbolTable, intermediate, parsingBuiltIns, version, profile, spvVersion,
119                                     language, infoSink, sourceEntryPointName.c_str(), forwardCompatible, messages);
120 #endif
121     default:
122         infoSink.info.message(EPrefixInternalError, "Unable to determine source language");
123         return nullptr;
124     }
125 }
126 
127 // Local mapping functions for making arrays of symbol tables....
128 
129 const int VersionCount = 17;  // index range in MapVersionToIndex
130 
MapVersionToIndex(int version)131 int MapVersionToIndex(int version)
132 {
133     int index = 0;
134 
135     switch (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;
155     }
156 
157     assert(index < VersionCount);
158 
159     return index;
160 }
161 
162 const int SpvVersionCount = 4;  // index range in MapSpvVersionToIndex
163 
MapSpvVersionToIndex(const SpvVersion & spvVersion)164 int MapSpvVersionToIndex(const SpvVersion& spvVersion)
165 {
166     int index = 0;
167 
168     if (spvVersion.openGl > 0)
169         index = 1;
170     else if (spvVersion.vulkan > 0) {
171         if (!spvVersion.vulkanRelaxed)
172             index = 2;
173         else
174             index = 3;
175     }
176 
177     assert(index < SpvVersionCount);
178 
179     return index;
180 }
181 
182 const int ProfileCount = 4;   // index range in MapProfileToIndex
183 
MapProfileToIndex(EProfile profile)184 int MapProfileToIndex(EProfile profile)
185 {
186     int index = 0;
187 
188     switch (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;
193     default:                               break;
194     }
195 
196     assert(index < ProfileCount);
197 
198     return index;
199 }
200 
201 const int SourceCount = 2;
202 
MapSourceToIndex(EShSource source)203 int MapSourceToIndex(EShSource source)
204 {
205     int index = 0;
206 
207     switch (source) {
208     case EShSourceGlsl: index = 0; break;
209     case EShSourceHlsl: index = 1; break;
210     default:                       break;
211     }
212 
213     assert(index < SourceCount);
214 
215     return index;
216 }
217 
218 // only one of these needed for non-ES; ES needs 2 for different precision defaults of built-ins
219 enum EPrecisionClass {
220     EPcGeneral,
221     EPcFragment,
222     EPcCount
223 };
224 
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.
229 //
230 // Each has a different set of built-ins, and we want to preserve that from
231 // compile to compile.
232 //
233 TSymbolTable* CommonSymbolTable[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EPcCount] = {};
234 TSymbolTable* SharedSymbolTables[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EShLangCount] = {};
235 
236 TPoolAllocator* PerProcessGPA = nullptr;
237 
238 //
239 // Parse and add to the given symbol table the content of the given shader string.
240 //
InitializeSymbolTable(const TString & builtIns,int version,EProfile profile,const SpvVersion & spvVersion,EShLanguage language,EShSource source,TInfoSink & infoSink,TSymbolTable & symbolTable)241 bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
242                            EShSource source, TInfoSink& infoSink, TSymbolTable& symbolTable)
243 {
244     TIntermediate intermediate(language, version, profile);
245 
246     intermediate.setSource(source);
247 
248     std::unique_ptr<TParseContextBase> parseContext(CreateParseContext(symbolTable, intermediate, version, profile, source,
249                                                                        language, infoSink, spvVersion, true, EShMsgDefault,
250                                                                        true));
251 
252     TShader::ForbidIncluder includer;
253     TPpContext ppContext(*parseContext, "", includer);
254     TScanContext scanContext(*parseContext);
255     parseContext->setScanContext(&scanContext);
256     parseContext->setPpContext(&ppContext);
257 
258     //
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.
262     //
263 
264     symbolTable.push();
265 
266     const char* builtInShaders[2];
267     size_t builtInLengths[2];
268     builtInShaders[0] = builtIns.c_str();
269     builtInLengths[0] = builtIns.size();
270 
271     if (builtInLengths[0] == 0)
272         return true;
273 
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]);
279 
280         return false;
281     }
282 
283     return true;
284 }
285 
CommonIndex(EProfile profile,EShLanguage language)286 int CommonIndex(EProfile profile, EShLanguage language)
287 {
288     return (profile == EEsProfile && language == EShLangFragment) ? EPcFragment : EPcGeneral;
289 }
290 
291 //
292 // To initialize per-stage shared tables, with the common table already complete.
293 //
InitializeStageSymbolTable(TBuiltInParseables & builtInParseables,int version,EProfile profile,const SpvVersion & spvVersion,EShLanguage language,EShSource source,TInfoSink & infoSink,TSymbolTable ** commonTable,TSymbolTable ** symbolTables)294 void InitializeStageSymbolTable(TBuiltInParseables& builtInParseables, int version, EProfile profile, const SpvVersion& spvVersion,
295                                 EShLanguage language, EShSource source, TInfoSink& infoSink, TSymbolTable** commonTable,
296                                 TSymbolTable** symbolTables)
297 {
298 #ifdef GLSLANG_WEB
299     profile = EEsProfile;
300     version = 310;
301 #endif
302 
303     (*symbolTables[language]).adoptLevels(*commonTable[CommonIndex(profile, language)]);
304     InitializeSymbolTable(builtInParseables.getStageString(language), version, profile, spvVersion, language, source,
305                           infoSink, *symbolTables[language]);
306     builtInParseables.identifyBuiltIns(version, profile, spvVersion, language, *symbolTables[language]);
307     if (profile == EEsProfile && version >= 300)
308         (*symbolTables[language]).setNoBuiltInRedeclarations();
309     if (version == 110)
310         (*symbolTables[language]).setSeparateNameSpaces();
311 }
312 
313 //
314 // Initialize the full set of shareable symbol tables;
315 // The common (cross-stage) and those shareable per-stage.
316 //
InitializeSymbolTables(TInfoSink & infoSink,TSymbolTable ** commonTable,TSymbolTable ** symbolTables,int version,EProfile profile,const SpvVersion & spvVersion,EShSource source)317 bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable,  TSymbolTable** symbolTables, int version, EProfile profile, const SpvVersion& spvVersion, EShSource source)
318 {
319 #ifdef GLSLANG_WEB
320     profile = EEsProfile;
321     version = 310;
322 #endif
323 
324     std::unique_ptr<TBuiltInParseables> builtInParseables(CreateBuiltInParseables(infoSink, source));
325 
326     if (builtInParseables == nullptr)
327         return false;
328 
329     builtInParseables->initialize(version, profile, spvVersion);
330 
331     // do the common tables
332     InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangVertex, source,
333                           infoSink, *commonTable[EPcGeneral]);
334     if (profile == EEsProfile)
335         InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangFragment, source,
336                               infoSink, *commonTable[EPcFragment]);
337 
338     // do the per-stage tables
339 
340     // always have vertex and fragment
341     InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangVertex, source,
342                                infoSink, commonTable, symbolTables);
343     InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangFragment, source,
344                                infoSink, commonTable, symbolTables);
345 
346 #ifndef GLSLANG_WEB
347     // check for tessellation
348     if ((profile != EEsProfile && version >= 150) ||
349         (profile == EEsProfile && version >= 310)) {
350         InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessControl, source,
351                                    infoSink, commonTable, symbolTables);
352         InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessEvaluation, source,
353                                    infoSink, commonTable, symbolTables);
354     }
355 
356     // check for geometry
357     if ((profile != EEsProfile && version >= 150) ||
358         (profile == EEsProfile && version >= 310))
359         InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangGeometry, source,
360                                    infoSink, commonTable, symbolTables);
361 
362     // check for compute
363     if ((profile != EEsProfile && version >= 420) ||
364         (profile == EEsProfile && version >= 310))
365         InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCompute, source,
366                                    infoSink, commonTable, symbolTables);
367 
368     // check for ray tracing stages
369     if (profile != EEsProfile && version >= 450) {
370         InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangRayGen, source,
371             infoSink, commonTable, symbolTables);
372         InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangIntersect, source,
373             infoSink, commonTable, symbolTables);
374         InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangAnyHit, source,
375             infoSink, commonTable, symbolTables);
376         InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangClosestHit, source,
377             infoSink, commonTable, symbolTables);
378         InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangMiss, source,
379             infoSink, commonTable, symbolTables);
380         InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCallable, source,
381             infoSink, commonTable, symbolTables);
382     }
383 
384     // check for mesh
385     if ((profile != EEsProfile && version >= 450) ||
386         (profile == EEsProfile && version >= 320))
387         InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangMesh, source,
388                                    infoSink, commonTable, symbolTables);
389 
390     // check for task
391     if ((profile != EEsProfile && version >= 450) ||
392         (profile == EEsProfile && version >= 320))
393         InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTask, source,
394                                    infoSink, commonTable, symbolTables);
395 #endif // !GLSLANG_WEB
396 
397     return true;
398 }
399 
AddContextSpecificSymbols(const TBuiltInResource * resources,TInfoSink & infoSink,TSymbolTable & symbolTable,int version,EProfile profile,const SpvVersion & spvVersion,EShLanguage language,EShSource source)400 bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& infoSink, TSymbolTable& symbolTable, int version,
401                                EProfile profile, const SpvVersion& spvVersion, EShLanguage language, EShSource source)
402 {
403     std::unique_ptr<TBuiltInParseables> builtInParseables(CreateBuiltInParseables(infoSink, source));
404 
405     if (builtInParseables == nullptr)
406         return false;
407 
408     builtInParseables->initialize(*resources, version, profile, spvVersion, language);
409     InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, language, source, infoSink, symbolTable);
410     builtInParseables->identifyBuiltIns(version, profile, spvVersion, language, symbolTable, *resources);
411 
412     return true;
413 }
414 
415 //
416 // To do this on the fly, we want to leave the current state of our thread's
417 // pool allocator intact, so:
418 //  - Switch to a new pool for parsing the built-ins
419 //  - Do the parsing, which builds the symbol table, using the new pool
420 //  - Switch to the process-global pool to save a copy of the resulting symbol table
421 //  - Free up the new pool used to parse the built-ins
422 //  - Switch back to the original thread's pool
423 //
424 // This only gets done the first time any thread needs a particular symbol table
425 // (lazy evaluation).
426 //
SetupBuiltinSymbolTable(int version,EProfile profile,const SpvVersion & spvVersion,EShSource source)427 void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& spvVersion, EShSource source)
428 {
429     TInfoSink infoSink;
430 
431     // Make sure only one thread tries to do this at a time
432     glslang::GetGlobalLock();
433 
434     // See if it's already been done for this version/profile combination
435     int versionIndex = MapVersionToIndex(version);
436     int spvVersionIndex = MapSpvVersionToIndex(spvVersion);
437     int profileIndex = MapProfileToIndex(profile);
438     int sourceIndex = MapSourceToIndex(source);
439     if (CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][EPcGeneral]) {
440         glslang::ReleaseGlobalLock();
441 
442         return;
443     }
444 
445     // Switch to a new pool
446     TPoolAllocator& previousAllocator = GetThreadPoolAllocator();
447     TPoolAllocator* builtInPoolAllocator = new TPoolAllocator;
448     SetThreadPoolAllocator(builtInPoolAllocator);
449 
450     // Dynamically allocate the local symbol tables so we can control when they are deallocated WRT when the pool is popped.
451     TSymbolTable* commonTable[EPcCount];
452     TSymbolTable* stageTables[EShLangCount];
453     for (int precClass = 0; precClass < EPcCount; ++precClass)
454         commonTable[precClass] = new TSymbolTable;
455     for (int stage = 0; stage < EShLangCount; ++stage)
456         stageTables[stage] = new TSymbolTable;
457 
458     // Generate the local symbol tables using the new pool
459     InitializeSymbolTables(infoSink, commonTable, stageTables, version, profile, spvVersion, source);
460 
461     // Switch to the process-global pool
462     SetThreadPoolAllocator(PerProcessGPA);
463 
464     // Copy the local symbol tables from the new pool to the global tables using the process-global pool
465     for (int precClass = 0; precClass < EPcCount; ++precClass) {
466         if (! commonTable[precClass]->isEmpty()) {
467             CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass] = new TSymbolTable;
468             CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass]->copyTable(*commonTable[precClass]);
469             CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass]->readOnly();
470         }
471     }
472     for (int stage = 0; stage < EShLangCount; ++stage) {
473         if (! stageTables[stage]->isEmpty()) {
474             SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage] = new TSymbolTable;
475             SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->adoptLevels(*CommonSymbolTable
476                               [versionIndex][spvVersionIndex][profileIndex][sourceIndex][CommonIndex(profile, (EShLanguage)stage)]);
477             SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->copyTable(*stageTables[stage]);
478             SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->readOnly();
479         }
480     }
481 
482     // Clean up the local tables before deleting the pool they used.
483     for (int precClass = 0; precClass < EPcCount; ++precClass)
484         delete commonTable[precClass];
485     for (int stage = 0; stage < EShLangCount; ++stage)
486         delete stageTables[stage];
487 
488     delete builtInPoolAllocator;
489     SetThreadPoolAllocator(&previousAllocator);
490 
491     glslang::ReleaseGlobalLock();
492 }
493 
494 // Function to Print all builtins
DumpBuiltinSymbolTable(TInfoSink & infoSink,const TSymbolTable & symbolTable)495 void DumpBuiltinSymbolTable(TInfoSink& infoSink, const TSymbolTable& symbolTable)
496 {
497 #if !defined(GLSLANG_WEB)
498     infoSink.debug << "BuiltinSymbolTable {\n";
499 
500     symbolTable.dump(infoSink, true);
501 
502     infoSink.debug << "}\n";
503 #endif
504 }
505 
506 // Return true if the shader was correctly specified for version/profile/stage.
DeduceVersionProfile(TInfoSink & infoSink,EShLanguage stage,bool versionNotFirst,int defaultVersion,EShSource source,int & version,EProfile & profile,const SpvVersion & spvVersion)507 bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNotFirst, int defaultVersion,
508                           EShSource source, int& version, EProfile& profile, const SpvVersion& spvVersion)
509 {
510     const int FirstProfileVersion = 150;
511     bool correct = true;
512 
513     if (source == EShSourceHlsl) {
514         version = 500;          // shader model; currently a characteristic of glslang, not the input
515         profile = ECoreProfile; // allow doubles in prototype parsing
516         return correct;
517     }
518 
519     // Get a version...
520     if (version == 0) {
521         version = defaultVersion;
522         // infoSink.info.message(EPrefixWarning, "#version: statement missing; use #version on first line of shader");
523     }
524 
525     // Get a good profile...
526     if (profile == ENoProfile) {
527         if (version == 300 || version == 310 || version == 320) {
528             correct = false;
529             infoSink.info.message(EPrefixError, "#version: versions 300, 310, and 320 require specifying the 'es' profile");
530             profile = EEsProfile;
531         } else if (version == 100)
532             profile = EEsProfile;
533         else if (version >= FirstProfileVersion)
534             profile = ECoreProfile;
535         else
536             profile = ENoProfile;
537     } else {
538         // a profile was provided...
539         if (version < 150) {
540             correct = false;
541             infoSink.info.message(EPrefixError, "#version: versions before 150 do not allow a profile token");
542             if (version == 100)
543                 profile = EEsProfile;
544             else
545                 profile = ENoProfile;
546         } else if (version == 300 || version == 310 || version == 320) {
547             if (profile != EEsProfile) {
548                 correct = false;
549                 infoSink.info.message(EPrefixError, "#version: versions 300, 310, and 320 support only the es profile");
550             }
551             profile = EEsProfile;
552         } else {
553             if (profile == EEsProfile) {
554                 correct = false;
555                 infoSink.info.message(EPrefixError, "#version: only version 300, 310, and 320 support the es profile");
556                 if (version >= FirstProfileVersion)
557                     profile = ECoreProfile;
558                 else
559                     profile = ENoProfile;
560             }
561             // else: typical desktop case... e.g., "#version 410 core"
562         }
563     }
564 
565     // Fix version...
566     switch (version) {
567     // ES versions
568     case 100: break;
569     case 300: break;
570     case 310: break;
571     case 320: break;
572 
573     // desktop versions
574     case 110: break;
575     case 120: break;
576     case 130: break;
577     case 140: break;
578     case 150: break;
579     case 330: break;
580     case 400: break;
581     case 410: break;
582     case 420: break;
583     case 430: break;
584     case 440: break;
585     case 450: break;
586     case 460: break;
587 
588     // unknown version
589     default:
590         correct = false;
591         infoSink.info.message(EPrefixError, "version not supported");
592         if (profile == EEsProfile)
593             version = 310;
594         else {
595             version = 450;
596             profile = ECoreProfile;
597         }
598         break;
599     }
600 
601 #if !defined(GLSLANG_WEB)
602     // Correct for stage type...
603     switch (stage) {
604     case EShLangGeometry:
605         if ((profile == EEsProfile && version < 310) ||
606             (profile != EEsProfile && version < 150)) {
607             correct = false;
608             infoSink.info.message(EPrefixError, "#version: geometry shaders require es profile with version 310 or non-es profile with version 150 or above");
609             version = (profile == EEsProfile) ? 310 : 150;
610             if (profile == EEsProfile || profile == ENoProfile)
611                 profile = ECoreProfile;
612         }
613         break;
614     case EShLangTessControl:
615     case EShLangTessEvaluation:
616         if ((profile == EEsProfile && version < 310) ||
617             (profile != EEsProfile && version < 150)) {
618             correct = false;
619             infoSink.info.message(EPrefixError, "#version: tessellation shaders require es profile with version 310 or non-es profile with version 150 or above");
620             version = (profile == EEsProfile) ? 310 : 400; // 150 supports the extension, correction is to 400 which does not
621             if (profile == EEsProfile || profile == ENoProfile)
622                 profile = ECoreProfile;
623         }
624         break;
625     case EShLangCompute:
626         if ((profile == EEsProfile && version < 310) ||
627             (profile != EEsProfile && version < 420)) {
628             correct = false;
629             infoSink.info.message(EPrefixError, "#version: compute shaders require es profile with version 310 or above, or non-es profile with version 420 or above");
630             version = profile == EEsProfile ? 310 : 420;
631         }
632         break;
633     case EShLangRayGen:
634     case EShLangIntersect:
635     case EShLangAnyHit:
636     case EShLangClosestHit:
637     case EShLangMiss:
638     case EShLangCallable:
639         if (profile == EEsProfile || version < 460) {
640             correct = false;
641             infoSink.info.message(EPrefixError, "#version: ray tracing shaders require non-es profile with version 460 or above");
642             version = 460;
643         }
644         break;
645     case EShLangMesh:
646     case EShLangTask:
647         if ((profile == EEsProfile && version < 320) ||
648             (profile != EEsProfile && version < 450)) {
649             correct = false;
650             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");
651             version = profile == EEsProfile ? 320 : 450;
652         }
653     default:
654         break;
655     }
656 
657     if (profile == EEsProfile && version >= 300 && versionNotFirst) {
658         correct = false;
659         infoSink.info.message(EPrefixError, "#version: statement must appear first in es-profile shader; before comments or newlines");
660     }
661 
662     // Check for SPIR-V compatibility
663     if (spvVersion.spv != 0) {
664         switch (profile) {
665         case EEsProfile:
666             if (version < 310) {
667                 correct = false;
668                 infoSink.info.message(EPrefixError, "#version: ES shaders for SPIR-V require version 310 or higher");
669                 version = 310;
670             }
671             break;
672         case ECompatibilityProfile:
673             infoSink.info.message(EPrefixError, "#version: compilation for SPIR-V does not support the compatibility profile");
674             break;
675         default:
676             if (spvVersion.vulkan > 0 && version < 140) {
677                 correct = false;
678                 infoSink.info.message(EPrefixError, "#version: Desktop shaders for Vulkan SPIR-V require version 140 or higher");
679                 version = 140;
680             }
681             if (spvVersion.openGl >= 100 && version < 330) {
682                 correct = false;
683                 infoSink.info.message(EPrefixError, "#version: Desktop shaders for OpenGL SPIR-V require version 330 or higher");
684                 version = 330;
685             }
686             break;
687         }
688     }
689 #endif
690 
691     return correct;
692 }
693 
694 // There are multiple paths in for setting environment stuff.
695 // TEnvironment takes precedence, for what it sets, so sort all this out.
696 // Ideally, the internal code could be made to use TEnvironment, but for
697 // now, translate it to the historically used parameters.
TranslateEnvironment(const TEnvironment * environment,EShMessages & messages,EShSource & source,EShLanguage & stage,SpvVersion & spvVersion)698 void TranslateEnvironment(const TEnvironment* environment, EShMessages& messages, EShSource& source,
699                           EShLanguage& stage, SpvVersion& spvVersion)
700 {
701     // Set up environmental defaults, first ignoring 'environment'.
702     if (messages & EShMsgSpvRules)
703         spvVersion.spv = EShTargetSpv_1_0;
704     if (messages & EShMsgVulkanRules) {
705         spvVersion.vulkan = EShTargetVulkan_1_0;
706         spvVersion.vulkanGlsl = 100;
707     } else if (spvVersion.spv != 0)
708         spvVersion.openGl = 100;
709 
710     // Now, override, based on any content set in 'environment'.
711     // 'environment' must be cleared to ESh*None settings when items
712     // are not being set.
713     if (environment != nullptr) {
714         // input language
715         if (environment->input.languageFamily != EShSourceNone) {
716             stage = environment->input.stage;
717             switch (environment->input.dialect) {
718             case EShClientNone:
719                 break;
720             case EShClientVulkan:
721                 spvVersion.vulkanGlsl = environment->input.dialectVersion;
722                 spvVersion.vulkanRelaxed = environment->input.vulkanRulesRelaxed;
723                 break;
724             case EShClientOpenGL:
725                 spvVersion.openGl = environment->input.dialectVersion;
726                 break;
727             case EShClientCount:
728                 assert(0);
729                 break;
730             }
731             switch (environment->input.languageFamily) {
732             case EShSourceNone:
733                 break;
734             case EShSourceGlsl:
735                 source = EShSourceGlsl;
736                 messages = static_cast<EShMessages>(messages & ~EShMsgReadHlsl);
737                 break;
738             case EShSourceHlsl:
739                 source = EShSourceHlsl;
740                 messages = static_cast<EShMessages>(messages | EShMsgReadHlsl);
741                 break;
742             case EShSourceCount:
743                 assert(0);
744                 break;
745             }
746         }
747 
748         // client
749         switch (environment->client.client) {
750         case EShClientVulkan:
751             spvVersion.vulkan = environment->client.version;
752             break;
753         default:
754             break;
755         }
756 
757         // generated code
758         switch (environment->target.language) {
759         case EshTargetSpv:
760             spvVersion.spv = environment->target.version;
761             break;
762         default:
763             break;
764         }
765     }
766 }
767 
768 // Most processes are recorded when set in the intermediate representation,
769 // These are the few that are not.
RecordProcesses(TIntermediate & intermediate,EShMessages messages,const std::string & sourceEntryPointName)770 void RecordProcesses(TIntermediate& intermediate, EShMessages messages, const std::string& sourceEntryPointName)
771 {
772     if ((messages & EShMsgRelaxedErrors) != 0)
773         intermediate.addProcess("relaxed-errors");
774     if ((messages & EShMsgSuppressWarnings) != 0)
775         intermediate.addProcess("suppress-warnings");
776     if ((messages & EShMsgKeepUncalled) != 0)
777         intermediate.addProcess("keep-uncalled");
778     if (sourceEntryPointName.size() > 0) {
779         intermediate.addProcess("source-entrypoint");
780         intermediate.addProcessArgument(sourceEntryPointName);
781     }
782 }
783 
784 // This is the common setup and cleanup code for PreprocessDeferred and
785 // CompileDeferred.
786 // It takes any callable with a signature of
787 //  bool (TParseContextBase& parseContext, TPpContext& ppContext,
788 //                  TInputScanner& input, bool versionWillBeError,
789 //                  TSymbolTable& , TIntermediate& ,
790 //                  EShOptimizationLevel , EShMessages );
791 // Which returns false if a failure was detected and true otherwise.
792 //
793 template<typename ProcessingContext>
ProcessDeferred(TCompiler * compiler,const char * const shaderStrings[],const int numStrings,const int * inputLengths,const char * const stringNames[],const char * customPreamble,const EShOptimizationLevel optLevel,const TBuiltInResource * resources,int defaultVersion,EProfile defaultProfile,bool forceDefaultVersionAndProfile,int overrideVersion,bool forwardCompatible,EShMessages messages,TIntermediate & intermediate,ProcessingContext & processingContext,bool requireNonempty,TShader::Includer & includer,const std::string sourceEntryPointName="",const TEnvironment * environment=nullptr)794 bool ProcessDeferred(
795     TCompiler* compiler,
796     const char* const shaderStrings[],
797     const int numStrings,
798     const int* inputLengths,
799     const char* const stringNames[],
800     const char* customPreamble,
801     const EShOptimizationLevel optLevel,
802     const TBuiltInResource* resources,
803     int defaultVersion,  // use 100 for ES environment, 110 for desktop; this is the GLSL version, not SPIR-V or Vulkan
804     EProfile defaultProfile,
805     // set version/profile to defaultVersion/defaultProfile regardless of the #version
806     // directive in the source code
807     bool forceDefaultVersionAndProfile,
808     int overrideVersion, // overrides version specified by #verison or default version
809     bool forwardCompatible,     // give errors for use of deprecated features
810     EShMessages messages,       // warnings/errors/AST; things to print out
811     TIntermediate& intermediate, // returned tree, etc.
812     ProcessingContext& processingContext,
813     bool requireNonempty,
814     TShader::Includer& includer,
815     const std::string sourceEntryPointName = "",
816     const TEnvironment* environment = nullptr)  // optional way of fully setting all versions, overriding the above
817 {
818     // This must be undone (.pop()) by the caller, after it finishes consuming the created tree.
819     GetThreadPoolAllocator().push();
820 
821     if (numStrings == 0)
822         return true;
823 
824     // Move to length-based strings, rather than null-terminated strings.
825     // Also, add strings to include the preamble and to ensure the shader is not null,
826     // which lets the grammar accept what was a null (post preprocessing) shader.
827     //
828     // Shader will look like
829     //   string 0:                system preamble
830     //   string 1:                custom preamble
831     //   string 2...numStrings+1: user's shader
832     //   string numStrings+2:     "int;"
833     const int numPre = 2;
834     const int numPost = requireNonempty? 1 : 0;
835     const int numTotal = numPre + numStrings + numPost;
836     std::unique_ptr<size_t[]> lengths(new size_t[numTotal]);
837     std::unique_ptr<const char*[]> strings(new const char*[numTotal]);
838     std::unique_ptr<const char*[]> names(new const char*[numTotal]);
839     for (int s = 0; s < numStrings; ++s) {
840         strings[s + numPre] = shaderStrings[s];
841         if (inputLengths == nullptr || inputLengths[s] < 0)
842             lengths[s + numPre] = strlen(shaderStrings[s]);
843         else
844             lengths[s + numPre] = inputLengths[s];
845     }
846     if (stringNames != nullptr) {
847         for (int s = 0; s < numStrings; ++s)
848             names[s + numPre] = stringNames[s];
849     } else {
850         for (int s = 0; s < numStrings; ++s)
851             names[s + numPre] = nullptr;
852     }
853 
854     // Get all the stages, languages, clients, and other environment
855     // stuff sorted out.
856     EShSource sourceGuess = (messages & EShMsgReadHlsl) != 0 ? EShSourceHlsl : EShSourceGlsl;
857     SpvVersion spvVersion;
858     EShLanguage stage = compiler->getLanguage();
859     TranslateEnvironment(environment, messages, sourceGuess, stage, spvVersion);
860 #ifdef ENABLE_HLSL
861     EShSource source = sourceGuess;
862     if (environment != nullptr && environment->target.hlslFunctionality1)
863         intermediate.setHlslFunctionality1();
864 #else
865     const EShSource source = EShSourceGlsl;
866 #endif
867     // First, without using the preprocessor or parser, find the #version, so we know what
868     // symbol tables, processing rules, etc. to set up.  This does not need the extra strings
869     // outlined above, just the user shader, after the system and user preambles.
870     glslang::TInputScanner userInput(numStrings, &strings[numPre], &lengths[numPre]);
871     int version = 0;
872     EProfile profile = ENoProfile;
873     bool versionNotFirstToken = false;
874     bool versionNotFirst = (source == EShSourceHlsl)
875                                 ? true
876                                 : userInput.scanVersion(version, profile, versionNotFirstToken);
877     bool versionNotFound = version == 0;
878     if (forceDefaultVersionAndProfile && source == EShSourceGlsl) {
879 #if !defined(GLSLANG_WEB)
880         if (! (messages & EShMsgSuppressWarnings) && ! versionNotFound &&
881             (version != defaultVersion || profile != defaultProfile)) {
882             compiler->infoSink.info << "Warning, (version, profile) forced to be ("
883                                     << defaultVersion << ", " << ProfileName(defaultProfile)
884                                     << "), while in source code it is ("
885                                     << version << ", " << ProfileName(profile) << ")\n";
886         }
887 #endif
888         if (versionNotFound) {
889             versionNotFirstToken = false;
890             versionNotFirst = false;
891             versionNotFound = false;
892         }
893         version = defaultVersion;
894         profile = defaultProfile;
895     }
896     if (source == EShSourceGlsl && overrideVersion != 0) {
897         version = overrideVersion;
898     }
899 
900     bool goodVersion = DeduceVersionProfile(compiler->infoSink, stage,
901                                             versionNotFirst, defaultVersion, source, version, profile, spvVersion);
902 #ifdef GLSLANG_WEB
903     profile = EEsProfile;
904     version = 310;
905 #endif
906 
907     bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst));
908 #if !defined(GLSLANG_WEB)
909     bool warnVersionNotFirst = false;
910     if (! versionWillBeError && versionNotFirstToken) {
911         if (messages & EShMsgRelaxedErrors)
912             warnVersionNotFirst = true;
913         else
914             versionWillBeError = true;
915     }
916 #endif
917 
918     intermediate.setSource(source);
919     intermediate.setVersion(version);
920     intermediate.setProfile(profile);
921     intermediate.setSpv(spvVersion);
922     RecordProcesses(intermediate, messages, sourceEntryPointName);
923     if (spvVersion.vulkan > 0)
924         intermediate.setOriginUpperLeft();
925 #ifdef ENABLE_HLSL
926     if ((messages & EShMsgHlslOffsets) || source == EShSourceHlsl)
927         intermediate.setHlslOffsets();
928 #endif
929     if (messages & EShMsgDebugInfo) {
930         intermediate.setSourceFile(names[numPre]);
931         for (int s = 0; s < numStrings; ++s) {
932             // The string may not be null-terminated, so make sure we provide
933             // the length along with the string.
934             intermediate.addSourceText(strings[numPre + s], lengths[numPre + s]);
935         }
936     }
937     SetupBuiltinSymbolTable(version, profile, spvVersion, source);
938 
939     TSymbolTable* cachedTable = SharedSymbolTables[MapVersionToIndex(version)]
940                                                   [MapSpvVersionToIndex(spvVersion)]
941                                                   [MapProfileToIndex(profile)]
942                                                   [MapSourceToIndex(source)]
943                                                   [stage];
944 
945     // Dynamically allocate the symbol table so we can control when it is deallocated WRT the pool.
946     std::unique_ptr<TSymbolTable> symbolTable(new TSymbolTable);
947     if (cachedTable)
948         symbolTable->adoptLevels(*cachedTable);
949 
950     if (intermediate.getUniqueId() != 0)
951         symbolTable->overwriteUniqueId(intermediate.getUniqueId());
952 
953     // Add built-in symbols that are potentially context dependent;
954     // they get popped again further down.
955     if (! AddContextSpecificSymbols(resources, compiler->infoSink, *symbolTable, version, profile, spvVersion,
956                                     stage, source)) {
957         return false;
958     }
959 
960     if (messages & EShMsgBuiltinSymbolTable)
961         DumpBuiltinSymbolTable(compiler->infoSink, *symbolTable);
962 
963     //
964     // Now we can process the full shader under proper symbols and rules.
965     //
966 
967     std::unique_ptr<TParseContextBase> parseContext(CreateParseContext(*symbolTable, intermediate, version, profile, source,
968                                                     stage, compiler->infoSink,
969                                                     spvVersion, forwardCompatible, messages, false, sourceEntryPointName));
970     TPpContext ppContext(*parseContext, names[numPre] ? names[numPre] : "", includer);
971 
972     // only GLSL (bison triggered, really) needs an externally set scan context
973     glslang::TScanContext scanContext(*parseContext);
974     if (source == EShSourceGlsl)
975         parseContext->setScanContext(&scanContext);
976 
977     parseContext->setPpContext(&ppContext);
978     parseContext->setLimits(*resources);
979     if (! goodVersion)
980         parseContext->addError();
981 #if !defined(GLSLANG_WEB)
982     if (warnVersionNotFirst) {
983         TSourceLoc loc;
984         loc.init();
985         parseContext->warn(loc, "Illegal to have non-comment, non-whitespace tokens before #version", "#version", "");
986     }
987 #endif
988 
989     parseContext->initializeExtensionBehavior();
990 
991     // Fill in the strings as outlined above.
992     std::string preamble;
993     parseContext->getPreamble(preamble);
994     strings[0] = preamble.c_str();
995     lengths[0] = strlen(strings[0]);
996     names[0] = nullptr;
997     strings[1] = customPreamble;
998     lengths[1] = strlen(strings[1]);
999     names[1] = nullptr;
1000     assert(2 == numPre);
1001     if (requireNonempty) {
1002         const int postIndex = numStrings + numPre;
1003         strings[postIndex] = "\n int;";
1004         lengths[postIndex] = strlen(strings[numStrings + numPre]);
1005         names[postIndex] = nullptr;
1006     }
1007     TInputScanner fullInput(numStrings + numPre + numPost, strings.get(), lengths.get(), names.get(), numPre, numPost);
1008 
1009     // Push a new symbol allocation scope that will get used for the shader's globals.
1010     symbolTable->push();
1011 
1012     bool success = processingContext(*parseContext, ppContext, fullInput,
1013                                      versionWillBeError, *symbolTable,
1014                                      intermediate, optLevel, messages);
1015     intermediate.setUniqueId(symbolTable->getMaxSymbolId());
1016     return success;
1017 }
1018 
1019 #if !defined(GLSLANG_WEB)
1020 
1021 // Responsible for keeping track of the most recent source string and line in
1022 // the preprocessor and outputting newlines appropriately if the source string
1023 // or line changes.
1024 class SourceLineSynchronizer {
1025 public:
SourceLineSynchronizer(const std::function<int ()> & lastSourceIndex,std::string * output)1026     SourceLineSynchronizer(const std::function<int()>& lastSourceIndex,
1027                            std::string* output)
1028       : getLastSourceIndex(lastSourceIndex), output(output), lastSource(-1), lastLine(0) {}
1029 //    SourceLineSynchronizer(const SourceLineSynchronizer&) = delete;
1030 //    SourceLineSynchronizer& operator=(const SourceLineSynchronizer&) = delete;
1031 
1032     // Sets the internally tracked source string index to that of the most
1033     // recently read token. If we switched to a new source string, returns
1034     // true and inserts a newline. Otherwise, returns false and outputs nothing.
syncToMostRecentString()1035     bool syncToMostRecentString() {
1036         if (getLastSourceIndex() != lastSource) {
1037             // After switching to a new source string, we need to reset lastLine
1038             // because line number resets every time a new source string is
1039             // used. We also need to output a newline to separate the output
1040             // from the previous source string (if there is one).
1041             if (lastSource != -1 || lastLine != 0)
1042                 *output += '\n';
1043             lastSource = getLastSourceIndex();
1044             lastLine = -1;
1045             return true;
1046         }
1047         return false;
1048     }
1049 
1050     // Calls syncToMostRecentString() and then sets the internally tracked line
1051     // number to tokenLine. If we switched to a new line, returns true and inserts
1052     // newlines appropriately. Otherwise, returns false and outputs nothing.
syncToLine(int tokenLine)1053     bool syncToLine(int tokenLine) {
1054         syncToMostRecentString();
1055         const bool newLineStarted = lastLine < tokenLine;
1056         for (; lastLine < tokenLine; ++lastLine) {
1057             if (lastLine > 0) *output += '\n';
1058         }
1059         return newLineStarted;
1060     }
1061 
1062     // Sets the internally tracked line number to newLineNum.
setLineNum(int newLineNum)1063     void setLineNum(int newLineNum) { lastLine = newLineNum; }
1064 
1065 private:
1066     SourceLineSynchronizer& operator=(const SourceLineSynchronizer&);
1067 
1068     // A function for getting the index of the last valid source string we've
1069     // read tokens from.
1070     const std::function<int()> getLastSourceIndex;
1071     // output string for newlines.
1072     std::string* output;
1073     // lastSource is the source string index (starting from 0) of the last token
1074     // processed. It is tracked in order for newlines to be inserted when a new
1075     // source string starts. -1 means we haven't started processing any source
1076     // string.
1077     int lastSource;
1078     // lastLine is the line number (starting from 1) of the last token processed.
1079     // It is tracked in order for newlines to be inserted when a token appears
1080     // on a new line. 0 means we haven't started processing any line in the
1081     // current source string.
1082     int lastLine;
1083 };
1084 
1085 // DoPreprocessing is a valid ProcessingContext template argument,
1086 // which only performs the preprocessing step of compilation.
1087 // It places the result in the "string" argument to its constructor.
1088 //
1089 // This is not an officially supported or fully working path.
1090 struct DoPreprocessing {
DoPreprocessing__anon4317404b0111::DoPreprocessing1091     explicit DoPreprocessing(std::string* string): outputString(string) {}
operator ()__anon4317404b0111::DoPreprocessing1092     bool operator()(TParseContextBase& parseContext, TPpContext& ppContext,
1093                     TInputScanner& input, bool versionWillBeError,
1094                     TSymbolTable&, TIntermediate&,
1095                     EShOptimizationLevel, EShMessages)
1096     {
1097         // This is a list of tokens that do not require a space before or after.
1098         static const std::string unNeededSpaceTokens = ";()[]";
1099         static const std::string noSpaceBeforeTokens = ",";
1100         glslang::TPpToken ppToken;
1101 
1102         parseContext.setScanner(&input);
1103         ppContext.setInput(input, versionWillBeError);
1104 
1105         std::string outputBuffer;
1106         SourceLineSynchronizer lineSync(
1107             std::bind(&TInputScanner::getLastValidSourceIndex, &input), &outputBuffer);
1108 
1109         parseContext.setExtensionCallback([&lineSync, &outputBuffer](
1110             int line, const char* extension, const char* behavior) {
1111                 lineSync.syncToLine(line);
1112                 outputBuffer += "#extension ";
1113                 outputBuffer += extension;
1114                 outputBuffer += " : ";
1115                 outputBuffer += behavior;
1116         });
1117 
1118         parseContext.setLineCallback([&lineSync, &outputBuffer, &parseContext](
1119             int curLineNum, int newLineNum, bool hasSource, int sourceNum, const char* sourceName) {
1120             // SourceNum is the number of the source-string that is being parsed.
1121             lineSync.syncToLine(curLineNum);
1122             outputBuffer += "#line ";
1123             outputBuffer += std::to_string(newLineNum);
1124             if (hasSource) {
1125                 outputBuffer += ' ';
1126                 if (sourceName != nullptr) {
1127                     outputBuffer += '\"';
1128                     outputBuffer += sourceName;
1129                     outputBuffer += '\"';
1130                 } else {
1131                     outputBuffer += std::to_string(sourceNum);
1132                 }
1133             }
1134             if (parseContext.lineDirectiveShouldSetNextLine()) {
1135                 // newLineNum is the new line number for the line following the #line
1136                 // directive. So the new line number for the current line is
1137                 newLineNum -= 1;
1138             }
1139             outputBuffer += '\n';
1140             // And we are at the next line of the #line directive now.
1141             lineSync.setLineNum(newLineNum + 1);
1142         });
1143 
1144         parseContext.setVersionCallback(
1145             [&lineSync, &outputBuffer](int line, int version, const char* str) {
1146                 lineSync.syncToLine(line);
1147                 outputBuffer += "#version ";
1148                 outputBuffer += std::to_string(version);
1149                 if (str) {
1150                     outputBuffer += ' ';
1151                     outputBuffer += str;
1152                 }
1153             });
1154 
1155         parseContext.setPragmaCallback([&lineSync, &outputBuffer](
1156             int line, const glslang::TVector<glslang::TString>& ops) {
1157                 lineSync.syncToLine(line);
1158                 outputBuffer += "#pragma ";
1159                 for(size_t i = 0; i < ops.size(); ++i) {
1160                     outputBuffer += ops[i].c_str();
1161                 }
1162         });
1163 
1164         parseContext.setErrorCallback([&lineSync, &outputBuffer](
1165             int line, const char* errorMessage) {
1166                 lineSync.syncToLine(line);
1167                 outputBuffer += "#error ";
1168                 outputBuffer += errorMessage;
1169         });
1170 
1171         int lastToken = EndOfInput; // lastToken records the last token processed.
1172         do {
1173             int token = ppContext.tokenize(ppToken);
1174             if (token == EndOfInput)
1175                 break;
1176 
1177             bool isNewString = lineSync.syncToMostRecentString();
1178             bool isNewLine = lineSync.syncToLine(ppToken.loc.line);
1179 
1180             if (isNewLine) {
1181                 // Don't emit whitespace onto empty lines.
1182                 // Copy any whitespace characters at the start of a line
1183                 // from the input to the output.
1184                 outputBuffer += std::string(ppToken.loc.column - 1, ' ');
1185             }
1186 
1187             // Output a space in between tokens, but not at the start of a line,
1188             // and also not around special tokens. This helps with readability
1189             // and consistency.
1190             if (!isNewString && !isNewLine && lastToken != EndOfInput &&
1191                 (unNeededSpaceTokens.find((char)token) == std::string::npos) &&
1192                 (unNeededSpaceTokens.find((char)lastToken) == std::string::npos) &&
1193                 (noSpaceBeforeTokens.find((char)token) == std::string::npos)) {
1194                 outputBuffer += ' ';
1195             }
1196             lastToken = token;
1197             if (token == PpAtomConstString)
1198                 outputBuffer += "\"";
1199             outputBuffer += ppToken.name;
1200             if (token == PpAtomConstString)
1201                 outputBuffer += "\"";
1202         } while (true);
1203         outputBuffer += '\n';
1204         *outputString = std::move(outputBuffer);
1205 
1206         bool success = true;
1207         if (parseContext.getNumErrors() > 0) {
1208             success = false;
1209             parseContext.infoSink.info.prefix(EPrefixError);
1210             parseContext.infoSink.info << parseContext.getNumErrors() << " compilation errors.  No code generated.\n\n";
1211         }
1212         return success;
1213     }
1214     std::string* outputString;
1215 };
1216 
1217 #endif
1218 
1219 // DoFullParse is a valid ProcessingConext template argument for fully
1220 // parsing the shader.  It populates the "intermediate" with the AST.
1221 struct DoFullParse{
operator ()__anon4317404b0111::DoFullParse1222   bool operator()(TParseContextBase& parseContext, TPpContext& ppContext,
1223                   TInputScanner& fullInput, bool versionWillBeError,
1224                   TSymbolTable&, TIntermediate& intermediate,
1225                   EShOptimizationLevel optLevel, EShMessages messages)
1226     {
1227         bool success = true;
1228         // Parse the full shader.
1229         if (! parseContext.parseShaderStrings(ppContext, fullInput, versionWillBeError))
1230             success = false;
1231 
1232         if (success && intermediate.getTreeRoot()) {
1233             if (optLevel == EShOptNoGeneration)
1234                 parseContext.infoSink.info.message(EPrefixNone, "No errors.  No code generation or linking was requested.");
1235             else
1236                 success = intermediate.postProcess(intermediate.getTreeRoot(), parseContext.getLanguage());
1237         } else if (! success) {
1238             parseContext.infoSink.info.prefix(EPrefixError);
1239             parseContext.infoSink.info << parseContext.getNumErrors() << " compilation errors.  No code generated.\n\n";
1240         }
1241 
1242         if (messages & EShMsgAST)
1243             intermediate.output(parseContext.infoSink, true);
1244 
1245         return success;
1246     }
1247 };
1248 
1249 #if !defined(GLSLANG_WEB)
1250 // Take a single compilation unit, and run the preprocessor on it.
1251 // Return: True if there were no issues found in preprocessing,
1252 //         False if during preprocessing any unknown version, pragmas or
1253 //         extensions were found.
1254 //
1255 // NOTE: Doing just preprocessing to obtain a correct preprocessed shader string
1256 // is not an officially supported or fully working path.
PreprocessDeferred(TCompiler * compiler,const char * const shaderStrings[],const int numStrings,const int * inputLengths,const char * const stringNames[],const char * preamble,const EShOptimizationLevel optLevel,const TBuiltInResource * resources,int defaultVersion,EProfile defaultProfile,bool forceDefaultVersionAndProfile,int overrideVersion,bool forwardCompatible,EShMessages messages,TShader::Includer & includer,TIntermediate & intermediate,std::string * outputString,TEnvironment * environment=nullptr)1257 bool PreprocessDeferred(
1258     TCompiler* compiler,
1259     const char* const shaderStrings[],
1260     const int numStrings,
1261     const int* inputLengths,
1262     const char* const stringNames[],
1263     const char* preamble,
1264     const EShOptimizationLevel optLevel,
1265     const TBuiltInResource* resources,
1266     int defaultVersion,         // use 100 for ES environment, 110 for desktop
1267     EProfile defaultProfile,
1268     bool forceDefaultVersionAndProfile,
1269     int overrideVersion,        // use 0 if not overriding GLSL version
1270     bool forwardCompatible,     // give errors for use of deprecated features
1271     EShMessages messages,       // warnings/errors/AST; things to print out
1272     TShader::Includer& includer,
1273     TIntermediate& intermediate, // returned tree, etc.
1274     std::string* outputString,
1275     TEnvironment* environment = nullptr)
1276 {
1277     DoPreprocessing parser(outputString);
1278     return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
1279                            preamble, optLevel, resources, defaultVersion,
1280                            defaultProfile, forceDefaultVersionAndProfile, overrideVersion,
1281                            forwardCompatible, messages, intermediate, parser,
1282                            false, includer, "", environment);
1283 }
1284 #endif
1285 
1286 //
1287 // do a partial compile on the given strings for a single compilation unit
1288 // for a potential deferred link into a single stage (and deferred full compile of that
1289 // stage through machine-dependent compilation).
1290 //
1291 // all preprocessing, parsing, semantic checks, etc. for a single compilation unit
1292 // are done here.
1293 //
1294 // return:  the tree and other information is filled into the intermediate argument,
1295 //          and true is returned by the function for success.
1296 //
CompileDeferred(TCompiler * compiler,const char * const shaderStrings[],const int numStrings,const int * inputLengths,const char * const stringNames[],const char * preamble,const EShOptimizationLevel optLevel,const TBuiltInResource * resources,int defaultVersion,EProfile defaultProfile,bool forceDefaultVersionAndProfile,int overrideVersion,bool forwardCompatible,EShMessages messages,TIntermediate & intermediate,TShader::Includer & includer,const std::string sourceEntryPointName="",TEnvironment * environment=nullptr)1297 bool CompileDeferred(
1298     TCompiler* compiler,
1299     const char* const shaderStrings[],
1300     const int numStrings,
1301     const int* inputLengths,
1302     const char* const stringNames[],
1303     const char* preamble,
1304     const EShOptimizationLevel optLevel,
1305     const TBuiltInResource* resources,
1306     int defaultVersion,         // use 100 for ES environment, 110 for desktop
1307     EProfile defaultProfile,
1308     bool forceDefaultVersionAndProfile,
1309     int overrideVersion,        // use 0 if not overriding GLSL version
1310     bool forwardCompatible,     // give errors for use of deprecated features
1311     EShMessages messages,       // warnings/errors/AST; things to print out
1312     TIntermediate& intermediate,// returned tree, etc.
1313     TShader::Includer& includer,
1314     const std::string sourceEntryPointName = "",
1315     TEnvironment* environment = nullptr)
1316 {
1317     DoFullParse parser;
1318     return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
1319                            preamble, optLevel, resources, defaultVersion,
1320                            defaultProfile, forceDefaultVersionAndProfile, overrideVersion,
1321                            forwardCompatible, messages, intermediate, parser,
1322                            true, includer, sourceEntryPointName, environment);
1323 }
1324 
1325 } // end anonymous namespace for local functions
1326 
1327 //
1328 // ShInitialize() should be called exactly once per process, not per thread.
1329 //
ShInitialize()1330 int ShInitialize()
1331 {
1332     glslang::InitGlobalLock();
1333 
1334     if (! InitProcess())
1335         return 0;
1336 
1337     glslang::GetGlobalLock();
1338     ++NumberOfClients;
1339 
1340     if (PerProcessGPA == nullptr)
1341         PerProcessGPA = new TPoolAllocator();
1342 
1343     glslang::TScanContext::fillInKeywordMap();
1344 #ifdef ENABLE_HLSL
1345     glslang::HlslScanContext::fillInKeywordMap();
1346 #endif
1347 
1348     glslang::ReleaseGlobalLock();
1349     return 1;
1350 }
1351 
1352 //
1353 // Driver calls these to create and destroy compiler/linker
1354 // objects.
1355 //
1356 
ShConstructCompiler(const EShLanguage language,int debugOptions)1357 ShHandle ShConstructCompiler(const EShLanguage language, int debugOptions)
1358 {
1359     if (!InitThread())
1360         return nullptr;
1361 
1362     TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(language, debugOptions));
1363 
1364     return reinterpret_cast<void*>(base);
1365 }
1366 
ShConstructLinker(const EShExecutable executable,int debugOptions)1367 ShHandle ShConstructLinker(const EShExecutable executable, int debugOptions)
1368 {
1369     if (!InitThread())
1370         return nullptr;
1371 
1372     TShHandleBase* base = static_cast<TShHandleBase*>(ConstructLinker(executable, debugOptions));
1373 
1374     return reinterpret_cast<void*>(base);
1375 }
1376 
ShConstructUniformMap()1377 ShHandle ShConstructUniformMap()
1378 {
1379     if (!InitThread())
1380         return nullptr;
1381 
1382     TShHandleBase* base = static_cast<TShHandleBase*>(ConstructUniformMap());
1383 
1384     return reinterpret_cast<void*>(base);
1385 }
1386 
ShDestruct(ShHandle handle)1387 void ShDestruct(ShHandle handle)
1388 {
1389     if (handle == nullptr)
1390         return;
1391 
1392     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
1393 
1394     if (base->getAsCompiler())
1395         DeleteCompiler(base->getAsCompiler());
1396     else if (base->getAsLinker())
1397         DeleteLinker(base->getAsLinker());
1398     else if (base->getAsUniformMap())
1399         DeleteUniformMap(base->getAsUniformMap());
1400 }
1401 
1402 //
1403 // Cleanup symbol tables
1404 //
ShFinalize()1405 int ShFinalize()
1406 {
1407     glslang::GetGlobalLock();
1408     --NumberOfClients;
1409     assert(NumberOfClients >= 0);
1410     bool finalize = NumberOfClients == 0;
1411     if (! finalize) {
1412         glslang::ReleaseGlobalLock();
1413         return 1;
1414     }
1415 
1416     for (int version = 0; version < VersionCount; ++version) {
1417         for (int spvVersion = 0; spvVersion < SpvVersionCount; ++spvVersion) {
1418             for (int p = 0; p < ProfileCount; ++p) {
1419                 for (int source = 0; source < SourceCount; ++source) {
1420                     for (int stage = 0; stage < EShLangCount; ++stage) {
1421                         delete SharedSymbolTables[version][spvVersion][p][source][stage];
1422                         SharedSymbolTables[version][spvVersion][p][source][stage] = nullptr;
1423                     }
1424                 }
1425             }
1426         }
1427     }
1428 
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 pc = 0; pc < EPcCount; ++pc) {
1434                         delete CommonSymbolTable[version][spvVersion][p][source][pc];
1435                         CommonSymbolTable[version][spvVersion][p][source][pc] = nullptr;
1436                     }
1437                 }
1438             }
1439         }
1440     }
1441 
1442     if (PerProcessGPA != nullptr) {
1443         delete PerProcessGPA;
1444         PerProcessGPA = nullptr;
1445     }
1446 
1447     glslang::TScanContext::deleteKeywordMap();
1448 #ifdef ENABLE_HLSL
1449     glslang::HlslScanContext::deleteKeywordMap();
1450 #endif
1451 
1452     glslang::ReleaseGlobalLock();
1453     return 1;
1454 }
1455 
1456 //
1457 // Do a full compile on the given strings for a single compilation unit
1458 // forming a complete stage.  The result of the machine dependent compilation
1459 // is left in the provided compile object.
1460 //
1461 // Return:  The return value is really boolean, indicating
1462 // success (1) or failure (0).
1463 //
ShCompile(const ShHandle handle,const char * const shaderStrings[],const int numStrings,const int * inputLengths,const EShOptimizationLevel optLevel,const TBuiltInResource * resources,int,int defaultVersion,bool forwardCompatible,EShMessages messages)1464 int ShCompile(
1465     const ShHandle handle,
1466     const char* const shaderStrings[],
1467     const int numStrings,
1468     const int* inputLengths,
1469     const EShOptimizationLevel optLevel,
1470     const TBuiltInResource* resources,
1471     int /*debugOptions*/,
1472     int defaultVersion,        // use 100 for ES environment, 110 for desktop
1473     bool forwardCompatible,    // give errors for use of deprecated features
1474     EShMessages messages       // warnings/errors/AST; things to print out
1475     )
1476 {
1477     // Map the generic handle to the C++ object
1478     if (handle == nullptr)
1479         return 0;
1480 
1481     TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1482     TCompiler* compiler = base->getAsCompiler();
1483     if (compiler == nullptr)
1484         return 0;
1485 
1486     SetThreadPoolAllocator(compiler->getPool());
1487 
1488     compiler->infoSink.info.erase();
1489     compiler->infoSink.debug.erase();
1490 
1491     TIntermediate intermediate(compiler->getLanguage());
1492     TShader::ForbidIncluder includer;
1493     bool success = CompileDeferred(compiler, shaderStrings, numStrings, inputLengths, nullptr,
1494                                    "", optLevel, resources, defaultVersion, ENoProfile, false, 0,
1495                                    forwardCompatible, messages, intermediate, includer);
1496 
1497     //
1498     // Call the machine dependent compiler
1499     //
1500     if (success && intermediate.getTreeRoot() && optLevel != EShOptNoGeneration)
1501         success = compiler->compile(intermediate.getTreeRoot(), intermediate.getVersion(), intermediate.getProfile());
1502 
1503     intermediate.removeTree();
1504 
1505     // Throw away all the temporary memory used by the compilation process.
1506     // The push was done in the CompileDeferred() call above.
1507     GetThreadPoolAllocator().pop();
1508 
1509     return success ? 1 : 0;
1510 }
1511 
1512 //
1513 // Link the given compile objects.
1514 //
1515 // Return:  The return value of is really boolean, indicating
1516 // success or failure.
1517 //
ShLinkExt(const ShHandle linkHandle,const ShHandle compHandles[],const int numHandles)1518 int ShLinkExt(
1519     const ShHandle linkHandle,
1520     const ShHandle compHandles[],
1521     const int numHandles)
1522 {
1523     if (linkHandle == nullptr || numHandles == 0)
1524         return 0;
1525 
1526     THandleList cObjects;
1527 
1528     for (int i = 0; i < numHandles; ++i) {
1529         if (compHandles[i] == nullptr)
1530             return 0;
1531         TShHandleBase* base = reinterpret_cast<TShHandleBase*>(compHandles[i]);
1532         if (base->getAsLinker()) {
1533             cObjects.push_back(base->getAsLinker());
1534         }
1535         if (base->getAsCompiler())
1536             cObjects.push_back(base->getAsCompiler());
1537 
1538         if (cObjects[i] == nullptr)
1539             return 0;
1540     }
1541 
1542     TShHandleBase* base = reinterpret_cast<TShHandleBase*>(linkHandle);
1543     TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
1544 
1545     SetThreadPoolAllocator(linker->getPool());
1546 
1547     if (linker == nullptr)
1548         return 0;
1549 
1550     linker->infoSink.info.erase();
1551 
1552     for (int i = 0; i < numHandles; ++i) {
1553         if (cObjects[i]->getAsCompiler()) {
1554             if (! cObjects[i]->getAsCompiler()->linkable()) {
1555                 linker->infoSink.info.message(EPrefixError, "Not all shaders have valid object code.");
1556                 return 0;
1557             }
1558         }
1559     }
1560 
1561     bool ret = linker->link(cObjects);
1562 
1563     return ret ? 1 : 0;
1564 }
1565 
1566 //
1567 // ShSetEncrpytionMethod is a place-holder for specifying
1568 // how source code is encrypted.
1569 //
ShSetEncryptionMethod(ShHandle handle)1570 void ShSetEncryptionMethod(ShHandle handle)
1571 {
1572     if (handle == nullptr)
1573         return;
1574 }
1575 
1576 //
1577 // Return any compiler/linker/uniformmap log of messages for the application.
1578 //
ShGetInfoLog(const ShHandle handle)1579 const char* ShGetInfoLog(const ShHandle handle)
1580 {
1581     if (handle == nullptr)
1582         return nullptr;
1583 
1584     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
1585     TInfoSink* infoSink;
1586 
1587     if (base->getAsCompiler())
1588         infoSink = &(base->getAsCompiler()->getInfoSink());
1589     else if (base->getAsLinker())
1590         infoSink = &(base->getAsLinker()->getInfoSink());
1591     else
1592         return nullptr;
1593 
1594     infoSink->info << infoSink->debug.c_str();
1595     return infoSink->info.c_str();
1596 }
1597 
1598 //
1599 // Return the resulting binary code from the link process.  Structure
1600 // is machine dependent.
1601 //
ShGetExecutable(const ShHandle handle)1602 const void* ShGetExecutable(const ShHandle handle)
1603 {
1604     if (handle == nullptr)
1605         return nullptr;
1606 
1607     TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1608 
1609     TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
1610     if (linker == nullptr)
1611         return nullptr;
1612 
1613     return linker->getObjectCode();
1614 }
1615 
1616 //
1617 // Let the linker know where the application said it's attributes are bound.
1618 // The linker does not use these values, they are remapped by the ICD or
1619 // hardware.  It just needs them to know what's aliased.
1620 //
1621 // Return:  The return value of is really boolean, indicating
1622 // success or failure.
1623 //
ShSetVirtualAttributeBindings(const ShHandle handle,const ShBindingTable * table)1624 int ShSetVirtualAttributeBindings(const ShHandle handle, const ShBindingTable* table)
1625 {
1626     if (handle == nullptr)
1627         return 0;
1628 
1629     TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1630     TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
1631 
1632     if (linker == nullptr)
1633         return 0;
1634 
1635     linker->setAppAttributeBindings(table);
1636 
1637     return 1;
1638 }
1639 
1640 //
1641 // Let the linker know where the predefined attributes have to live.
1642 //
ShSetFixedAttributeBindings(const ShHandle handle,const ShBindingTable * table)1643 int ShSetFixedAttributeBindings(const ShHandle handle, const ShBindingTable* table)
1644 {
1645     if (handle == nullptr)
1646         return 0;
1647 
1648     TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1649     TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
1650 
1651     if (linker == nullptr)
1652         return 0;
1653 
1654     linker->setFixedAttributeBindings(table);
1655     return 1;
1656 }
1657 
1658 //
1659 // Some attribute locations are off-limits to the linker...
1660 //
ShExcludeAttributes(const ShHandle handle,int * attributes,int count)1661 int ShExcludeAttributes(const ShHandle handle, int *attributes, int count)
1662 {
1663     if (handle == nullptr)
1664         return 0;
1665 
1666     TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1667     TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
1668     if (linker == nullptr)
1669         return 0;
1670 
1671     linker->setExcludedAttributes(attributes, count);
1672 
1673     return 1;
1674 }
1675 
1676 //
1677 // Return the index for OpenGL to use for knowing where a uniform lives.
1678 //
1679 // Return:  The return value of is really boolean, indicating
1680 // success or failure.
1681 //
ShGetUniformLocation(const ShHandle handle,const char * name)1682 int ShGetUniformLocation(const ShHandle handle, const char* name)
1683 {
1684     if (handle == nullptr)
1685         return -1;
1686 
1687     TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
1688     TUniformMap* uniformMap= base->getAsUniformMap();
1689     if (uniformMap == nullptr)
1690         return -1;
1691 
1692     return uniformMap->getLocation(name);
1693 }
1694 
1695 ////////////////////////////////////////////////////////////////////////////////////////////
1696 //
1697 // Deferred-Lowering C++ Interface
1698 // -----------------------------------
1699 //
1700 // Below is a new alternate C++ interface that might potentially replace the above
1701 // opaque handle-based interface.
1702 //
1703 // See more detailed comment in ShaderLang.h
1704 //
1705 
1706 namespace glslang {
1707 
GetVersion()1708 Version GetVersion()
1709 {
1710     Version version;
1711     version.major = GLSLANG_VERSION_MAJOR;
1712     version.minor = GLSLANG_VERSION_MINOR;
1713     version.patch = GLSLANG_VERSION_PATCH;
1714     version.flavor = GLSLANG_VERSION_FLAVOR;
1715     return version;
1716 }
1717 
1718 #define QUOTE(s) #s
1719 #define STR(n) QUOTE(n)
1720 
GetEsslVersionString()1721 const char* GetEsslVersionString()
1722 {
1723     return "OpenGL ES GLSL 3.20 glslang Khronos. " STR(GLSLANG_VERSION_MAJOR) "." STR(GLSLANG_VERSION_MINOR) "." STR(
1724         GLSLANG_VERSION_PATCH) GLSLANG_VERSION_FLAVOR;
1725 }
1726 
GetGlslVersionString()1727 const char* GetGlslVersionString()
1728 {
1729     return "4.60 glslang Khronos. " STR(GLSLANG_VERSION_MAJOR) "." STR(GLSLANG_VERSION_MINOR) "." STR(
1730         GLSLANG_VERSION_PATCH) GLSLANG_VERSION_FLAVOR;
1731 }
1732 
GetKhronosToolId()1733 int GetKhronosToolId()
1734 {
1735     return 8;
1736 }
1737 
InitializeProcess()1738 bool InitializeProcess()
1739 {
1740     return ShInitialize() != 0;
1741 }
1742 
FinalizeProcess()1743 void FinalizeProcess()
1744 {
1745     ShFinalize();
1746 }
1747 
1748 class TDeferredCompiler : public TCompiler {
1749 public:
TDeferredCompiler(EShLanguage s,TInfoSink & i)1750     TDeferredCompiler(EShLanguage s, TInfoSink& i) : TCompiler(s, i) { }
compile(TIntermNode *,int=0,EProfile=ENoProfile)1751     virtual bool compile(TIntermNode*, int = 0, EProfile = ENoProfile) { return true; }
1752 };
1753 
TShader(EShLanguage s)1754 TShader::TShader(EShLanguage s)
1755     : stage(s), lengths(nullptr), stringNames(nullptr), preamble(""), overrideVersion(0)
1756 {
1757     pool = new TPoolAllocator;
1758     infoSink = new TInfoSink;
1759     compiler = new TDeferredCompiler(stage, *infoSink);
1760     intermediate = new TIntermediate(s);
1761 
1762     // clear environment (avoid constructors in them for use in a C interface)
1763     environment.input.languageFamily = EShSourceNone;
1764     environment.input.dialect = EShClientNone;
1765     environment.input.vulkanRulesRelaxed = false;
1766     environment.client.client = EShClientNone;
1767     environment.target.language = EShTargetNone;
1768     environment.target.hlslFunctionality1 = false;
1769 }
1770 
~TShader()1771 TShader::~TShader()
1772 {
1773     delete infoSink;
1774     delete compiler;
1775     delete intermediate;
1776     delete pool;
1777 }
1778 
setStrings(const char * const * s,int n)1779 void TShader::setStrings(const char* const* s, int n)
1780 {
1781     strings = s;
1782     numStrings = n;
1783     lengths = nullptr;
1784 }
1785 
setStringsWithLengths(const char * const * s,const int * l,int n)1786 void TShader::setStringsWithLengths(const char* const* s, const int* l, int n)
1787 {
1788     strings = s;
1789     numStrings = n;
1790     lengths = l;
1791 }
1792 
setStringsWithLengthsAndNames(const char * const * s,const int * l,const char * const * names,int n)1793 void TShader::setStringsWithLengthsAndNames(
1794     const char* const* s, const int* l, const char* const* names, int n)
1795 {
1796     strings = s;
1797     numStrings = n;
1798     lengths = l;
1799     stringNames = names;
1800 }
1801 
setEntryPoint(const char * entryPoint)1802 void TShader::setEntryPoint(const char* entryPoint)
1803 {
1804     intermediate->setEntryPointName(entryPoint);
1805 }
1806 
setSourceEntryPoint(const char * name)1807 void TShader::setSourceEntryPoint(const char* name)
1808 {
1809     sourceEntryPointName = name;
1810 }
1811 
1812 // Log initial settings and transforms.
1813 // See comment for class TProcesses.
addProcesses(const std::vector<std::string> & p)1814 void TShader::addProcesses(const std::vector<std::string>& p)
1815 {
1816     intermediate->addProcesses(p);
1817 }
1818 
setUniqueId(unsigned long long id)1819 void  TShader::setUniqueId(unsigned long long id)
1820 {
1821     intermediate->setUniqueId(id);
1822 }
1823 
setOverrideVersion(int version)1824 void TShader::setOverrideVersion(int version)
1825 {
1826     overrideVersion = version;
1827 }
1828 
setDebugInfo(bool debugInfo)1829 void TShader::setDebugInfo(bool debugInfo)              { intermediate->setDebugInfo(debugInfo); }
setInvertY(bool invert)1830 void TShader::setInvertY(bool invert)                   { intermediate->setInvertY(invert); }
setDxPositionW(bool invert)1831 void TShader::setDxPositionW(bool invert)               { intermediate->setDxPositionW(invert); }
setEnhancedMsgs()1832 void TShader::setEnhancedMsgs()                         { intermediate->setEnhancedMsgs(); }
setNanMinMaxClamp(bool useNonNan)1833 void TShader::setNanMinMaxClamp(bool useNonNan)         { intermediate->setNanMinMaxClamp(useNonNan); }
1834 
1835 #ifndef GLSLANG_WEB
1836 
1837 // Set binding base for given resource type
setShiftBinding(TResourceType res,unsigned int base)1838 void TShader::setShiftBinding(TResourceType res, unsigned int base) {
1839     intermediate->setShiftBinding(res, base);
1840 }
1841 
1842 // Set binding base for given resource type for a given binding set.
setShiftBindingForSet(TResourceType res,unsigned int base,unsigned int set)1843 void TShader::setShiftBindingForSet(TResourceType res, unsigned int base, unsigned int set) {
1844     intermediate->setShiftBindingForSet(res, base, set);
1845 }
1846 
1847 // Set binding base for sampler types
setShiftSamplerBinding(unsigned int base)1848 void TShader::setShiftSamplerBinding(unsigned int base) { setShiftBinding(EResSampler, base); }
1849 // Set binding base for texture types (SRV)
setShiftTextureBinding(unsigned int base)1850 void TShader::setShiftTextureBinding(unsigned int base) { setShiftBinding(EResTexture, base); }
1851 // Set binding base for image types
setShiftImageBinding(unsigned int base)1852 void TShader::setShiftImageBinding(unsigned int base)   { setShiftBinding(EResImage, base); }
1853 // Set binding base for uniform buffer objects (CBV)
setShiftUboBinding(unsigned int base)1854 void TShader::setShiftUboBinding(unsigned int base)     { setShiftBinding(EResUbo, base); }
1855 // Synonym for setShiftUboBinding, to match HLSL language.
setShiftCbufferBinding(unsigned int base)1856 void TShader::setShiftCbufferBinding(unsigned int base) { setShiftBinding(EResUbo, base); }
1857 // Set binding base for UAV (unordered access view)
setShiftUavBinding(unsigned int base)1858 void TShader::setShiftUavBinding(unsigned int base)     { setShiftBinding(EResUav, base); }
1859 // Set binding base for SSBOs
setShiftSsboBinding(unsigned int base)1860 void TShader::setShiftSsboBinding(unsigned int base)    { setShiftBinding(EResSsbo, base); }
1861 // Enables binding automapping using TIoMapper
setAutoMapBindings(bool map)1862 void TShader::setAutoMapBindings(bool map)              { intermediate->setAutoMapBindings(map); }
1863 // Enables position.Y output negation in vertex shader
1864 
1865 // Fragile: currently within one stage: simple auto-assignment of location
setAutoMapLocations(bool map)1866 void TShader::setAutoMapLocations(bool map)             { intermediate->setAutoMapLocations(map); }
addUniformLocationOverride(const char * name,int loc)1867 void TShader::addUniformLocationOverride(const char* name, int loc)
1868 {
1869     intermediate->addUniformLocationOverride(name, loc);
1870 }
setUniformLocationBase(int base)1871 void TShader::setUniformLocationBase(int base)
1872 {
1873     intermediate->setUniformLocationBase(base);
1874 }
setNoStorageFormat(bool useUnknownFormat)1875 void TShader::setNoStorageFormat(bool useUnknownFormat) { intermediate->setNoStorageFormat(useUnknownFormat); }
setResourceSetBinding(const std::vector<std::string> & base)1876 void TShader::setResourceSetBinding(const std::vector<std::string>& base)   { intermediate->setResourceSetBinding(base); }
setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode)1877 void TShader::setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { intermediate->setTextureSamplerTransformMode(mode); }
1878 #endif
1879 
addBlockStorageOverride(const char * nameStr,TBlockStorageClass backing)1880 void TShader::addBlockStorageOverride(const char* nameStr, TBlockStorageClass backing) { intermediate->addBlockStorageOverride(nameStr, backing); }
1881 
setGlobalUniformBlockName(const char * name)1882 void TShader::setGlobalUniformBlockName(const char* name) { intermediate->setGlobalUniformBlockName(name); }
setGlobalUniformSet(unsigned int set)1883 void TShader::setGlobalUniformSet(unsigned int set) { intermediate->setGlobalUniformSet(set); }
setGlobalUniformBinding(unsigned int binding)1884 void TShader::setGlobalUniformBinding(unsigned int binding) { intermediate->setGlobalUniformBinding(binding); }
1885 
setAtomicCounterBlockName(const char * name)1886 void TShader::setAtomicCounterBlockName(const char* name) { intermediate->setAtomicCounterBlockName(name); }
setAtomicCounterBlockSet(unsigned int set)1887 void TShader::setAtomicCounterBlockSet(unsigned int set) { intermediate->setAtomicCounterBlockSet(set); }
1888 
1889 #ifdef ENABLE_HLSL
1890 // See comment above TDefaultHlslIoMapper in iomapper.cpp:
setHlslIoMapping(bool hlslIoMap)1891 void TShader::setHlslIoMapping(bool hlslIoMap)          { intermediate->setHlslIoMapping(hlslIoMap); }
setFlattenUniformArrays(bool flatten)1892 void TShader::setFlattenUniformArrays(bool flatten)     { intermediate->setFlattenUniformArrays(flatten); }
1893 #endif
1894 
1895 //
1896 // Turn the shader strings into a parse tree in the TIntermediate.
1897 //
1898 // Returns true for success.
1899 //
parse(const TBuiltInResource * builtInResources,int defaultVersion,EProfile defaultProfile,bool forceDefaultVersionAndProfile,bool forwardCompatible,EShMessages messages,Includer & includer)1900 bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
1901                     bool forwardCompatible, EShMessages messages, Includer& includer)
1902 {
1903     if (! InitThread())
1904         return false;
1905     SetThreadPoolAllocator(pool);
1906 
1907     if (! preamble)
1908         preamble = "";
1909 
1910     return CompileDeferred(compiler, strings, numStrings, lengths, stringNames,
1911                            preamble, EShOptNone, builtInResources, defaultVersion,
1912                            defaultProfile, forceDefaultVersionAndProfile, overrideVersion,
1913                            forwardCompatible, messages, *intermediate, includer, sourceEntryPointName,
1914                            &environment);
1915 }
1916 
1917 #if !defined(GLSLANG_WEB)
1918 // Fill in a string with the result of preprocessing ShaderStrings
1919 // Returns true if all extensions, pragmas and version strings were valid.
1920 //
1921 // NOTE: Doing just preprocessing to obtain a correct preprocessed shader string
1922 // is not an officially supported or fully working path.
preprocess(const TBuiltInResource * builtInResources,int defaultVersion,EProfile defaultProfile,bool forceDefaultVersionAndProfile,bool forwardCompatible,EShMessages message,std::string * output_string,Includer & includer)1923 bool TShader::preprocess(const TBuiltInResource* builtInResources,
1924                          int defaultVersion, EProfile defaultProfile,
1925                          bool forceDefaultVersionAndProfile,
1926                          bool forwardCompatible, EShMessages message,
1927                          std::string* output_string,
1928                          Includer& includer)
1929 {
1930     if (! InitThread())
1931         return false;
1932     SetThreadPoolAllocator(pool);
1933 
1934     if (! preamble)
1935         preamble = "";
1936 
1937     return PreprocessDeferred(compiler, strings, numStrings, lengths, stringNames, preamble,
1938                               EShOptNone, builtInResources, defaultVersion,
1939                               defaultProfile, forceDefaultVersionAndProfile, overrideVersion,
1940                               forwardCompatible, message, includer, *intermediate, output_string,
1941                               &environment);
1942 }
1943 #endif
1944 
getInfoLog()1945 const char* TShader::getInfoLog()
1946 {
1947     return infoSink->info.c_str();
1948 }
1949 
getInfoDebugLog()1950 const char* TShader::getInfoDebugLog()
1951 {
1952     return infoSink->debug.c_str();
1953 }
1954 
TProgram()1955 TProgram::TProgram() :
1956 #if !defined(GLSLANG_WEB)
1957     reflection(nullptr),
1958 #endif
1959     linked(false)
1960 {
1961     pool = new TPoolAllocator;
1962     infoSink = new TInfoSink;
1963     for (int s = 0; s < EShLangCount; ++s) {
1964         intermediate[s] = nullptr;
1965         newedIntermediate[s] = false;
1966     }
1967 }
1968 
~TProgram()1969 TProgram::~TProgram()
1970 {
1971     delete infoSink;
1972 #if !defined(GLSLANG_WEB)
1973     delete reflection;
1974 #endif
1975 
1976     for (int s = 0; s < EShLangCount; ++s)
1977         if (newedIntermediate[s])
1978             delete intermediate[s];
1979 
1980     delete pool;
1981 }
1982 
1983 //
1984 // Merge the compilation units within each stage into a single TIntermediate.
1985 // All starting compilation units need to be the result of calling TShader::parse().
1986 //
1987 // Return true for success.
1988 //
link(EShMessages messages)1989 bool TProgram::link(EShMessages messages)
1990 {
1991     if (linked)
1992         return false;
1993     linked = true;
1994 
1995     bool error = false;
1996 
1997     SetThreadPoolAllocator(pool);
1998 
1999     for (int s = 0; s < EShLangCount; ++s) {
2000         if (! linkStage((EShLanguage)s, messages))
2001             error = true;
2002     }
2003 
2004     if (!error) {
2005         if (! crossStageCheck(messages))
2006             error = true;
2007     }
2008 
2009     return ! error;
2010 }
2011 
2012 //
2013 // Merge the compilation units within the given stage into a single TIntermediate.
2014 //
2015 // Return true for success.
2016 //
linkStage(EShLanguage stage,EShMessages messages)2017 bool TProgram::linkStage(EShLanguage stage, EShMessages messages)
2018 {
2019     if (stages[stage].size() == 0)
2020         return true;
2021 
2022 #if !defined(GLSLANG_WEB)
2023     int numEsShaders = 0, numNonEsShaders = 0;
2024     for (auto it = stages[stage].begin(); it != stages[stage].end(); ++it) {
2025         if ((*it)->intermediate->getProfile() == EEsProfile) {
2026             numEsShaders++;
2027         } else {
2028             numNonEsShaders++;
2029         }
2030     }
2031 
2032     if (numEsShaders > 0 && numNonEsShaders > 0) {
2033         infoSink->info.message(EPrefixError, "Cannot mix ES profile with non-ES profile shaders");
2034         return false;
2035     } else if (numEsShaders > 1) {
2036         infoSink->info.message(EPrefixError, "Cannot attach multiple ES shaders of the same type to a single program");
2037         return false;
2038     }
2039 
2040     //
2041     // Be efficient for the common single compilation unit per stage case,
2042     // reusing it's TIntermediate instead of merging into a new one.
2043     //
2044     TIntermediate *firstIntermediate = stages[stage].front()->intermediate;
2045     if (stages[stage].size() == 1)
2046         intermediate[stage] = firstIntermediate;
2047     else {
2048         intermediate[stage] = new TIntermediate(stage,
2049                                                 firstIntermediate->getVersion(),
2050                                                 firstIntermediate->getProfile());
2051         intermediate[stage]->setLimits(firstIntermediate->getLimits());
2052         if (firstIntermediate->getEnhancedMsgs())
2053             intermediate[stage]->setEnhancedMsgs();
2054 
2055         // The new TIntermediate must use the same origin as the original TIntermediates.
2056         // Otherwise linking will fail due to different coordinate systems.
2057         if (firstIntermediate->getOriginUpperLeft()) {
2058             intermediate[stage]->setOriginUpperLeft();
2059         }
2060         intermediate[stage]->setSpv(firstIntermediate->getSpv());
2061 
2062         newedIntermediate[stage] = true;
2063     }
2064 
2065     if (messages & EShMsgAST)
2066         infoSink->info << "\nLinked " << StageName(stage) << " stage:\n\n";
2067 
2068     if (stages[stage].size() > 1) {
2069         std::list<TShader*>::const_iterator it;
2070         for (it = stages[stage].begin(); it != stages[stage].end(); ++it)
2071             intermediate[stage]->merge(*infoSink, *(*it)->intermediate);
2072     }
2073 #else
2074     intermediate[stage] = stages[stage].front()->intermediate;
2075 #endif
2076     intermediate[stage]->finalCheck(*infoSink, (messages & EShMsgKeepUncalled) != 0);
2077 
2078     if (messages & EShMsgAST)
2079         intermediate[stage]->output(*infoSink, true);
2080 
2081     return intermediate[stage]->getNumErrors() == 0;
2082 }
2083 
2084 //
2085 // Check that there are no errors in linker objects accross stages
2086 //
2087 // Return true if no errors.
2088 //
crossStageCheck(EShMessages)2089 bool TProgram::crossStageCheck(EShMessages) {
2090 
2091     // make temporary intermediates to hold the linkage symbols for each linking interface
2092     // while we do the checks
2093     // Independent interfaces are:
2094     //                  all uniform variables and blocks
2095     //                  all buffer blocks
2096     //                  all in/out on a stage boundary
2097 
2098     TVector<TIntermediate*> activeStages;
2099     for (int s = 0; s < EShLangCount; ++s) {
2100         if (intermediate[s])
2101             activeStages.push_back(intermediate[s]);
2102     }
2103 
2104     // no extra linking if there is only one stage
2105     if (! (activeStages.size() > 1))
2106         return true;
2107 
2108     // setup temporary tree to hold unfirom objects from different stages
2109     TIntermediate* firstIntermediate = activeStages.front();
2110     TIntermediate uniforms(EShLangCount,
2111                            firstIntermediate->getVersion(),
2112                            firstIntermediate->getProfile());
2113     uniforms.setSpv(firstIntermediate->getSpv());
2114 
2115     TIntermAggregate uniformObjects(EOpLinkerObjects);
2116     TIntermAggregate root(EOpSequence);
2117     root.getSequence().push_back(&uniformObjects);
2118     uniforms.setTreeRoot(&root);
2119 
2120     bool error = false;
2121 
2122     // merge uniforms from all stages into a single intermediate
2123     for (unsigned int i = 0; i < activeStages.size(); ++i) {
2124         uniforms.mergeUniformObjects(*infoSink, *activeStages[i]);
2125     }
2126     error |= uniforms.getNumErrors() != 0;
2127 
2128     // copy final definition of global block back into each stage
2129     for (unsigned int i = 0; i < activeStages.size(); ++i) {
2130         // We only want to merge into already existing global uniform blocks.
2131         // A stage that doesn't already know about the global doesn't care about it's content.
2132         // Otherwise we end up pointing to the same object between different stages
2133         // and that will break binding/set remappings
2134         bool mergeExistingOnly = true;
2135         activeStages[i]->mergeGlobalUniformBlocks(*infoSink, uniforms, mergeExistingOnly);
2136     }
2137 
2138     // compare cross stage symbols for each stage boundary
2139     for (unsigned int i = 1; i < activeStages.size(); ++i) {
2140         activeStages[i - 1]->checkStageIO(*infoSink, *activeStages[i]);
2141         error |= (activeStages[i - 1]->getNumErrors() != 0);
2142     }
2143 
2144     return !error;
2145 }
2146 
getInfoLog()2147 const char* TProgram::getInfoLog()
2148 {
2149     return infoSink->info.c_str();
2150 }
2151 
getInfoDebugLog()2152 const char* TProgram::getInfoDebugLog()
2153 {
2154     return infoSink->debug.c_str();
2155 }
2156 
2157 #if !defined(GLSLANG_WEB)
2158 
2159 //
2160 // Reflection implementation.
2161 //
2162 
buildReflection(int opts)2163 bool TProgram::buildReflection(int opts)
2164 {
2165     if (! linked || reflection != nullptr)
2166         return false;
2167 
2168     int firstStage = EShLangVertex, lastStage = EShLangFragment;
2169 
2170     if (opts & EShReflectionIntermediateIO) {
2171         // if we're reflecting intermediate I/O, determine the first and last stage linked and use those as the
2172         // boundaries for which stages generate pipeline inputs/outputs
2173         firstStage = EShLangCount;
2174         lastStage = 0;
2175         for (int s = 0; s < EShLangCount; ++s) {
2176             if (intermediate[s]) {
2177                 firstStage = std::min(firstStage, s);
2178                 lastStage = std::max(lastStage, s);
2179             }
2180         }
2181     }
2182 
2183     reflection = new TReflection((EShReflectionOptions)opts, (EShLanguage)firstStage, (EShLanguage)lastStage);
2184 
2185     for (int s = 0; s < EShLangCount; ++s) {
2186         if (intermediate[s]) {
2187             if (! reflection->addStage((EShLanguage)s, *intermediate[s]))
2188                 return false;
2189         }
2190     }
2191 
2192     return true;
2193 }
2194 
getLocalSize(int dim) const2195 unsigned TProgram::getLocalSize(int dim) const                        { return reflection->getLocalSize(dim); }
getReflectionIndex(const char * name) const2196 int TProgram::getReflectionIndex(const char* name) const              { return reflection->getIndex(name); }
getReflectionPipeIOIndex(const char * name,const bool inOrOut) const2197 int TProgram::getReflectionPipeIOIndex(const char* name, const bool inOrOut) const
2198                                                                       { return reflection->getPipeIOIndex(name, inOrOut); }
2199 
getNumUniformVariables() const2200 int TProgram::getNumUniformVariables() const                          { return reflection->getNumUniforms(); }
getUniform(int index) const2201 const TObjectReflection& TProgram::getUniform(int index) const        { return reflection->getUniform(index); }
getNumUniformBlocks() const2202 int TProgram::getNumUniformBlocks() const                             { return reflection->getNumUniformBlocks(); }
getUniformBlock(int index) const2203 const TObjectReflection& TProgram::getUniformBlock(int index) const   { return reflection->getUniformBlock(index); }
getNumPipeInputs() const2204 int TProgram::getNumPipeInputs() const                                { return reflection->getNumPipeInputs(); }
getPipeInput(int index) const2205 const TObjectReflection& TProgram::getPipeInput(int index) const      { return reflection->getPipeInput(index); }
getNumPipeOutputs() const2206 int TProgram::getNumPipeOutputs() const                               { return reflection->getNumPipeOutputs(); }
getPipeOutput(int index) const2207 const TObjectReflection& TProgram::getPipeOutput(int index) const     { return reflection->getPipeOutput(index); }
getNumBufferVariables() const2208 int TProgram::getNumBufferVariables() const                           { return reflection->getNumBufferVariables(); }
getBufferVariable(int index) const2209 const TObjectReflection& TProgram::getBufferVariable(int index) const { return reflection->getBufferVariable(index); }
getNumBufferBlocks() const2210 int TProgram::getNumBufferBlocks() const                              { return reflection->getNumStorageBuffers(); }
getBufferBlock(int index) const2211 const TObjectReflection& TProgram::getBufferBlock(int index) const    { return reflection->getStorageBufferBlock(index); }
getNumAtomicCounters() const2212 int TProgram::getNumAtomicCounters() const                            { return reflection->getNumAtomicCounters(); }
getAtomicCounter(int index) const2213 const TObjectReflection& TProgram::getAtomicCounter(int index) const  { return reflection->getAtomicCounter(index); }
dumpReflection()2214 void TProgram::dumpReflection() { if (reflection != nullptr) reflection->dump(); }
2215 
2216 //
2217 // I/O mapping implementation.
2218 //
mapIO(TIoMapResolver * pResolver,TIoMapper * pIoMapper)2219 bool TProgram::mapIO(TIoMapResolver* pResolver, TIoMapper* pIoMapper)
2220 {
2221     if (! linked)
2222         return false;
2223     TIoMapper* ioMapper = nullptr;
2224     TIoMapper defaultIOMapper;
2225     if (pIoMapper == nullptr)
2226         ioMapper = &defaultIOMapper;
2227     else
2228         ioMapper = pIoMapper;
2229     for (int s = 0; s < EShLangCount; ++s) {
2230         if (intermediate[s]) {
2231             if (! ioMapper->addStage((EShLanguage)s, *intermediate[s], *infoSink, pResolver))
2232                 return false;
2233         }
2234     }
2235 
2236     return ioMapper->doMap(pResolver, *infoSink);
2237 }
2238 
2239 #endif // !GLSLANG_WEB
2240 
2241 } // end namespace glslang
2242