From b8478d7eaca8bf8f67ad9d81e91d49eba66b7334 Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Mon, 8 Jun 2015 18:31:23 +0000 Subject: [PATCH] glslang: Allow programmatically prepending code to a shader without worrying about #version being first, to implement command-line-defined macros. From Dejan Mircevski . git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@31448 e7fa87d3-cd2b-0410-9028-fcbf551c1848 --- glslang/MachineIndependent/ShaderLang.cpp | 40 ++++++++++++++--------- glslang/Public/ShaderLang.h | 12 ++++--- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp index e87fd41a..bc773d63 100644 --- a/glslang/MachineIndependent/ShaderLang.cpp +++ b/glslang/MachineIndependent/ShaderLang.cpp @@ -435,6 +435,7 @@ bool CompileDeferred( const char* const shaderStrings[], const int numStrings, const int* inputLengths, + const char* customPreamble, const EShOptimizationLevel optLevel, const TBuiltInResource* resources, int defaultVersion, // use 100 for ES environment, 110 for desktop @@ -457,18 +458,20 @@ bool CompileDeferred( // which lets the grammar accept what was a null (post preprocessing) shader. // // Shader will look like - // string 0: preamble - // string 1...numStrings: user's shader - // string numStrings+1: "int;" - // - size_t* lengths = new size_t[numStrings + 2]; - const char** strings = new const char*[numStrings + 2]; + // string 0: system preamble + // string 1: custom preamble + // string 2...numStrings+1: user's shader + // string numStrings+2: "int;" + const int numPre = 2; + const int numPost = 1; + size_t* lengths = new size_t[numStrings + numPre + numPost]; + const char** strings = new const char*[numStrings + numPre + numPost]; for (int s = 0; s < numStrings; ++s) { - strings[s + 1] = shaderStrings[s]; + strings[s + numPre] = shaderStrings[s]; if (inputLengths == 0 || inputLengths[s] < 0) - lengths[s + 1] = strlen(shaderStrings[s]); + lengths[s + numPre] = strlen(shaderStrings[s]); else - lengths[s + 1] = inputLengths[s]; + lengths[s + numPre] = inputLengths[s]; } // First, without using the preprocessor or parser, find the #version, so we know what @@ -476,7 +479,7 @@ bool CompileDeferred( // outlined above, just the user shader. int version; EProfile profile; - glslang::TInputScanner userInput(numStrings, &strings[1], &lengths[1]); // no preamble + glslang::TInputScanner userInput(numStrings, &strings[numPre], &lengths[numPre]); // no preamble bool versionNotFirstToken; bool versionNotFirst = userInput.scanVersion(version, profile, versionNotFirstToken); bool versionNotFound = version == 0; @@ -534,9 +537,12 @@ bool CompileDeferred( // Fill in the strings as outlined above. strings[0] = parseContext.getPreamble(); lengths[0] = strlen(strings[0]); - strings[numStrings + 1] = "\n int;"; - lengths[numStrings + 1] = strlen(strings[numStrings + 1]); - TInputScanner fullInput(numStrings + 2, strings, lengths, 1, 1); + strings[1] = customPreamble; + lengths[1] = strlen(strings[1]); + assert(2 == numPre); + strings[numStrings + numPre] = "\n int;"; + lengths[numStrings + numPre] = strlen(strings[numStrings + numPre]); + TInputScanner fullInput(numStrings + numPre + numPost, strings, lengths, numPre, numPost); // Push a new symbol allocation scope that will get used for the shader's globals. symbolTable.push(); @@ -707,7 +713,7 @@ int ShCompile( compiler->infoSink.debug.erase(); TIntermediate intermediate(compiler->getLanguage()); - bool success = CompileDeferred(compiler, shaderStrings, numStrings, inputLengths, optLevel, resources, defaultVersion, forwardCompatible, messages, intermediate); + bool success = CompileDeferred(compiler, shaderStrings, numStrings, inputLengths, "", optLevel, resources, defaultVersion, forwardCompatible, messages, intermediate); // // Call the machine dependent compiler @@ -966,7 +972,7 @@ public: }; TShader::TShader(EShLanguage s) - : pool(0), stage(s) + : pool(0), stage(s), preamble("") { infoSink = new TInfoSink; compiler = new TDeferredCompiler(stage, *infoSink); @@ -993,8 +999,10 @@ bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion pool = new TPoolAllocator(); SetThreadPoolAllocator(*pool); + if (! preamble) + preamble = ""; - return CompileDeferred(compiler, strings, numStrings, nullptr, EShOptNone, builtInResources, defaultVersion, forwardCompatible, messages, *intermediate); + return CompileDeferred(compiler, strings, numStrings, nullptr, preamble, EShOptNone, builtInResources, defaultVersion, forwardCompatible, messages, *intermediate); } const char* TShader::getInfoLog() diff --git a/glslang/Public/ShaderLang.h b/glslang/Public/ShaderLang.h index 4ca1c0d5..c1829f7e 100644 --- a/glslang/Public/ShaderLang.h +++ b/glslang/Public/ShaderLang.h @@ -263,11 +263,13 @@ bool InitializeProcess(); // Call once per process to tear down everything void FinalizeProcess(); -// Make one TShader per shader that you will link into a program. Then -// provide the shader through setStrings(), then call parse(), then query -// the info logs. +// Make one TShader per shader that you will link into a program. Then provide +// the shader through setStrings(), then call parse(), then query the info logs. +// Optionally use setPreamble() to set a special shader string that will be +// processed before all others but won't affect the validity of #version. // -// N.B.: Does not yet support having the same TShader instance being linked into multiple programs. +// N.B.: Does not yet support having the same TShader instance being linked into +// multiple programs. // // N.B.: Destruct a linked program *before* destructing the shaders linked into it. // @@ -276,6 +278,7 @@ public: explicit TShader(EShLanguage); virtual ~TShader(); void setStrings(const char* const* s, int n) { strings = s; numStrings = n; } + void setPreamble(const char* s) { preamble = s; } bool parse(const TBuiltInResource*, int defaultVersion, bool forwardCompatible, EShMessages); const char* getInfoLog(); @@ -290,6 +293,7 @@ protected: TIntermediate* intermediate; TInfoSink* infoSink; const char* const* strings; + const char* preamble; int numStrings; friend class TProgram;