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