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