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