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