ShaderLang.cpp 78 KB

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