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