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