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