allow renaming of shader entry point when creating SPIR-V
authorsteve-lunarg <steve_gh@khasekhemwy.net>
Mon, 31 Oct 2016 21:13:43 +0000 (15:13 -0600)
committersteve-lunarg <steve_gh@khasekhemwy.net>
Thu, 1 Dec 2016 15:51:43 +0000 (08:51 -0700)
Use "--source-entrypoint name" on the command line, or the
TShader::setSourceEntryPoint(char*) API.

When the name given to the above interfaces is detected in the
shader source, it will be renamed to the entry point name supplied
to the -e option or the TShader::setEntryPoint() method.

StandAlone/StandAlone.cpp
Test/baseResults/hlsl.entry.rename.frag.out [new file with mode: 0644]
Test/hlsl.entry.rename.frag [new file with mode: 0644]
Test/runtests
glslang/MachineIndependent/ShaderLang.cpp
glslang/Public/ShaderLang.h
hlsl/hlslGrammar.cpp
hlsl/hlslParseHelper.cpp
hlsl/hlslParseHelper.h

index 377e7cb..e6c0ab7 100644 (file)
@@ -160,6 +160,7 @@ int Options = 0;
 const char* ExecutableName = nullptr;
 const char* binaryFileName = nullptr;
 const char* entryPointName = nullptr;
+const char* sourceEntryPointName = nullptr;
 const char* shaderStageName = nullptr;
 
 std::array<unsigned int, EShLangCount> baseSamplerBinding;
@@ -300,6 +301,15 @@ void ProcessArguments(int argc, char* argv[])
                     } else if (lowerword == "no-storage-format" || // synonyms
                                lowerword == "nsf") {
                         Options |= EOptionNoStorageFormat;
+                    } else if (lowerword == "source-entrypoint" || // synonyms
+                               lowerword == "sep") {
+                        sourceEntryPointName = argv[1];
+                        if (argc > 0) {
+                            argc--;
+                            argv++;
+                        } else
+                            Error("no <entry-point> provided for --source-entrypoint");
+                        break;
                     } else {
                         usage();
                     }
@@ -547,6 +557,8 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
         shader->setStringsWithLengthsAndNames(compUnit.text, NULL, compUnit.fileNameList, 1);
         if (entryPointName) // HLSL todo: this needs to be tracked per compUnits
             shader->setEntryPoint(entryPointName);
+        if (sourceEntryPointName)
+            shader->setSourceEntryPoint(sourceEntryPointName);
 
         shader->setShiftSamplerBinding(baseSamplerBinding[compUnit.stage]);
         shader->setShiftTextureBinding(baseTextureBinding[compUnit.stage]);
@@ -963,6 +975,9 @@ void usage()
            "\n"
            "  --no-storage-format                     use Unknown image format\n"
            "  --nsf                                   synonym for --no-storage-format\n"
+           "\n"
+           "  --source-entrypoint name                the given shader source function is renamed to be the entry point given in -e\n"
+           "  --sep                                   synonym for --source-entrypoint\n"
            );
 
     exit(EFailUsage);
diff --git a/Test/baseResults/hlsl.entry.rename.frag.out b/Test/baseResults/hlsl.entry.rename.frag.out
new file mode 100644 (file)
index 0000000..0cfc925
--- /dev/null
@@ -0,0 +1,119 @@
+../Test/hlsl.entry.rename.frag
+Shader version: 450
+gl_FragCoord origin is upper left
+0:? Sequence
+0:7  Function Definition: not_the_entry_point( (temp void)
+0:7    Function Parameters: 
+0:11  Function Definition: main_in_spv( (temp structure{temp 4-component vector of float Color})
+0:11    Function Parameters: 
+0:?     Sequence
+0:13      move second child to first child (temp 4-component vector of float)
+0:13        Color: direct index for structure (temp 4-component vector of float)
+0:13          'psout' (temp structure{temp 4-component vector of float Color})
+0:13          Constant:
+0:13            0 (const int)
+0:13        Constant:
+0:13          0.000000
+0:13          0.000000
+0:13          0.000000
+0:13          0.000000
+0:14      Sequence
+0:14        Sequence
+0:14          move second child to first child (temp 4-component vector of float)
+0:?             'Color' (layout(location=0 ) out 4-component vector of float)
+0:14            Color: direct index for structure (temp 4-component vector of float)
+0:14              'psout' (temp structure{temp 4-component vector of float Color})
+0:14              Constant:
+0:14                0 (const int)
+0:14        Branch: Return
+0:?   Linker Objects
+0:?     'Color' (layout(location=0 ) out 4-component vector of float)
+0:?     'anon@0' (layout(row_major std140 ) uniform block{layout(offset=0 ) uniform int also_not_the_entry_point})
+
+
+Linked fragment stage:
+
+
+Shader version: 450
+gl_FragCoord origin is upper left
+0:? Sequence
+0:7  Function Definition: not_the_entry_point( (temp void)
+0:7    Function Parameters: 
+0:11  Function Definition: main_in_spv( (temp structure{temp 4-component vector of float Color})
+0:11    Function Parameters: 
+0:?     Sequence
+0:13      move second child to first child (temp 4-component vector of float)
+0:13        Color: direct index for structure (temp 4-component vector of float)
+0:13          'psout' (temp structure{temp 4-component vector of float Color})
+0:13          Constant:
+0:13            0 (const int)
+0:13        Constant:
+0:13          0.000000
+0:13          0.000000
+0:13          0.000000
+0:13          0.000000
+0:14      Sequence
+0:14        Sequence
+0:14          move second child to first child (temp 4-component vector of float)
+0:?             'Color' (layout(location=0 ) out 4-component vector of float)
+0:14            Color: direct index for structure (temp 4-component vector of float)
+0:14              'psout' (temp structure{temp 4-component vector of float Color})
+0:14              Constant:
+0:14                0 (const int)
+0:14        Branch: Return
+0:?   Linker Objects
+0:?     'Color' (layout(location=0 ) out 4-component vector of float)
+0:?     'anon@0' (layout(row_major std140 ) uniform block{layout(offset=0 ) uniform int also_not_the_entry_point})
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 27
+
+                              Capability Shader
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main_in_spv" 20
+                              ExecutionMode 4 OriginUpperLeft
+                              Name 4  "main_in_spv"
+                              Name 6  "not_the_entry_point("
+                              Name 10  "PS_OUTPUT"
+                              MemberName 10(PS_OUTPUT) 0  "Color"
+                              Name 12  "psout"
+                              Name 20  "Color"
+                              Name 24  "$Global"
+                              MemberName 24($Global) 0  "also_not_the_entry_point"
+                              Name 26  ""
+                              Decorate 20(Color) Location 0
+                              MemberDecorate 24($Global) 0 Offset 0
+                              Decorate 24($Global) Block
+                              Decorate 26 DescriptorSet 0
+               2:             TypeVoid
+               3:             TypeFunction 2
+               8:             TypeFloat 32
+               9:             TypeVector 8(float) 4
+   10(PS_OUTPUT):             TypeStruct 9(fvec4)
+              11:             TypePointer Function 10(PS_OUTPUT)
+              13:             TypeInt 32 1
+              14:     13(int) Constant 0
+              15:    8(float) Constant 0
+              16:    9(fvec4) ConstantComposite 15 15 15 15
+              17:             TypePointer Function 9(fvec4)
+              19:             TypePointer Output 9(fvec4)
+       20(Color):     19(ptr) Variable Output
+     24($Global):             TypeStruct 13(int)
+              25:             TypePointer Uniform 24($Global)
+              26:     25(ptr) Variable Uniform
+  4(main_in_spv):           2 Function None 3
+               5:             Label
+       12(psout):     11(ptr) Variable Function
+              18:     17(ptr) AccessChain 12(psout) 14
+                              Store 18 16
+              21:     17(ptr) AccessChain 12(psout) 14
+              22:    9(fvec4) Load 21
+                              Store 20(Color) 22
+                              Return
+                              FunctionEnd
+6(not_the_entry_point():           2 Function None 3
+               7:             Label
+                              Return
+                              FunctionEnd
diff --git a/Test/hlsl.entry.rename.frag b/Test/hlsl.entry.rename.frag
new file mode 100644 (file)
index 0000000..188dfc5
--- /dev/null
@@ -0,0 +1,15 @@
+
+struct PS_OUTPUT
+{
+    float4 Color : SV_Target0;
+};
+
+void not_the_entry_point() { }
+int also_not_the_entry_point;
+
+PS_OUTPUT main()
+{
+    PS_OUTPUT psout;
+    psout.Color = 0;
+    return psout;
+}
index 0640391..78c630c 100755 (executable)
@@ -45,6 +45,13 @@ $EXE -i -C *.vert *.geom *.frag *.tes* *.comp > singleThread.out
 $EXE -i -C *.vert *.geom *.frag *.tes* *.comp -t > multiThread.out
 diff singleThread.out multiThread.out || HASERROR=1
 
+
+#
+# entry point renaming tests
+#
+$EXE -i -H -V -D -e main_in_spv --source-entrypoint main ../Test/hlsl.entry.rename.frag > $TARGETDIR/hlsl.entry.rename.frag.out
+diff -b $BASEDIR/hlsl.entry.rename.frag.out $TARGETDIR/hlsl.entry.rename.frag.out || HASERROR=1
+
 if [ $HASERROR -eq 0 ]
 then
     echo Tests Succeeded.
index cc21b2e..ef45987 100644 (file)
@@ -86,7 +86,7 @@ TParseContextBase* CreateParseContext(TSymbolTable& symbolTable, TIntermediate&
                                       int version, EProfile profile, EShSource source,
                                       EShLanguage language, TInfoSink& infoSink,
                                       SpvVersion spvVersion, bool forwardCompatible, EShMessages messages,
-                                      bool parsingBuiltIns)
+                                      bool parsingBuiltIns, const std::string sourceEntryPointName = "")
 {
     switch (source) {
     case EShSourceGlsl:
@@ -96,7 +96,7 @@ TParseContextBase* CreateParseContext(TSymbolTable& symbolTable, TIntermediate&
 
     case EShSourceHlsl:
         return new HlslParseContext(symbolTable, intermediate, parsingBuiltIns, version, profile, spvVersion,
-                                    language, infoSink, forwardCompatible, messages);
+                                    language, infoSink, sourceEntryPointName.c_str(), forwardCompatible, messages);
     default:
         infoSink.info.message(EPrefixInternalError, "Unable to determine source language");
         return nullptr;
@@ -616,7 +616,8 @@ bool ProcessDeferred(
     TIntermediate& intermediate, // returned tree, etc.
     ProcessingContext& processingContext,
     bool requireNonempty,
-    TShader::Includer& includer
+    TShader::Includer& includer,
+    const std::string sourceEntryPointName = ""
     )
 {
     if (! InitThread())
@@ -733,7 +734,7 @@ bool ProcessDeferred(
 
     TParseContextBase* parseContext = CreateParseContext(symbolTable, intermediate, version, profile, source,
                                                          compiler->getLanguage(), compiler->infoSink,
-                                                         spvVersion, forwardCompatible, messages, false);
+                                                         spvVersion, forwardCompatible, messages, false, sourceEntryPointName);
 
     TPpContext ppContext(*parseContext, names[numPre]? names[numPre]: "", includer);
 
@@ -1054,14 +1055,15 @@ bool CompileDeferred(
     bool forwardCompatible,     // give errors for use of deprecated features
     EShMessages messages,       // warnings/errors/AST; things to print out
     TIntermediate& intermediate,// returned tree, etc.
-    TShader::Includer& includer)
+    TShader::Includer& includer,
+    const std::string sourceEntryPointName = "")
 {
     DoFullParse parser;
     return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
                            preamble, optLevel, resources, defaultVersion,
                            defaultProfile, forceDefaultVersionAndProfile,
                            forwardCompatible, messages, intermediate, parser,
-                           true, includer);
+                           true, includer, sourceEntryPointName);
 }
 
 } // end anonymous namespace for local functions
@@ -1479,7 +1481,7 @@ public:
     virtual bool compile(TIntermNode*, int = 0, EProfile = ENoProfile) { return true; }
 };
 
-TShader::TShader(EShLanguage s) 
+TShader::TShader(EShLanguage s)
     : pool(0), stage(s), lengths(nullptr), stringNames(nullptr), preamble("")
 {
     infoSink = new TInfoSink;
@@ -1523,6 +1525,11 @@ void TShader::setEntryPoint(const char* entryPoint)
     intermediate->setEntryPointName(entryPoint);
 }
 
+void TShader::setSourceEntryPoint(const char* name)
+{
+    sourceEntryPointName = name;
+}
+
 void TShader::setShiftSamplerBinding(unsigned int base) { intermediate->setShiftSamplerBinding(base); }
 void TShader::setShiftTextureBinding(unsigned int base) { intermediate->setShiftTextureBinding(base); }
 void TShader::setShiftImageBinding(unsigned int base)   { intermediate->setShiftImageBinding(base); }
@@ -1550,7 +1557,7 @@ bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion
     return CompileDeferred(compiler, strings, numStrings, lengths, stringNames,
                            preamble, EShOptNone, builtInResources, defaultVersion,
                            defaultProfile, forceDefaultVersionAndProfile,
-                           forwardCompatible, messages, *intermediate, includer);
+                           forwardCompatible, messages, *intermediate, includer, sourceEntryPointName);
 }
 
 bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion, bool forwardCompatible, EShMessages messages)
index 6793cdd..851e115 100644 (file)
@@ -304,6 +304,7 @@ public:
         const char* const* s, const int* l, const char* const* names, int n);
     void setPreamble(const char* s) { preamble = s; }
     void setEntryPoint(const char* entryPoint);
+    void setSourceEntryPoint(const char* sourceEntryPointName);
     void setShiftSamplerBinding(unsigned int base);
     void setShiftTextureBinding(unsigned int base);
     void setShiftImageBinding(unsigned int base);
@@ -437,6 +438,9 @@ protected:
     const char* preamble;
     int numStrings;
 
+    // a function in the source string can be renamed FROM this TO the name given in setEntryPoint.
+    std::string sourceEntryPointName;
+
     friend class TProgram;
 
 private:
index 10dfcc8..61fb4dd 100755 (executable)
@@ -308,8 +308,13 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node)
     // identifier
     HlslToken idToken;
     while (acceptIdentifier(idToken)) {
+        TString* fnName = idToken.string;
+
+        // Potentially rename shader entry point function.  No-op most of the time.
+        parseContext.renameShaderFunction(fnName);
+
         // function_parameters
-        TFunction& function = *new TFunction(idToken.string, declaredType);
+        TFunction& function = *new TFunction(fnName, declaredType);
         if (acceptFunctionParameters(function)) {
             // post_decls
             acceptPostDecls(function.getWritableType().getQualifier());
index 8685dcd..c307408 100755 (executable)
@@ -51,6 +51,7 @@ namespace glslang {
 
 HlslParseContext::HlslParseContext(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins,
                                    int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TInfoSink& infoSink,
+                                   const TString sourceEntryPointName,
                                    bool forwardCompatible, EShMessages messages) :
     TParseContextBase(symbolTable, interm, parsingBuiltins, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
     contextPragma(true, false),
@@ -58,7 +59,8 @@ HlslParseContext::HlslParseContext(TSymbolTable& symbolTable, TIntermediate& int
     postEntryPointReturn(false),
     limits(resources.limits),
     entryPointOutput(nullptr),
-    nextInLocation(0), nextOutLocation(0)
+    nextInLocation(0), nextOutLocation(0),
+    sourceEntryPointName(sourceEntryPointName)
 {
     globalUniformDefaults.clear();
     globalUniformDefaults.layoutMatrix = ElmRowMajor;
@@ -5539,4 +5541,13 @@ TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* ex
     return switchNode;
 }
 
+// Potentially rename shader entry point function
+void HlslParseContext::renameShaderFunction(TString*& name) const
+{
+    // Replace the entry point name given in the shader with the real entry point name,
+    // if there is a substitution.
+    if (name != nullptr && *name == sourceEntryPointName)
+        name = new TString(intermediate.getEntryPointName().c_str());
+}
+
 } // end namespace glslang
index 246c7c4..f9cb0d3 100755 (executable)
@@ -47,6 +47,7 @@ class HlslParseContext : public TParseContextBase {
 public:
     HlslParseContext(TSymbolTable&, TIntermediate&, bool parsingBuiltins,
                      int version, EProfile, const SpvVersion& spvVersion, EShLanguage, TInfoSink&,
+                     const TString sourceEntryPointName,
                      bool forwardCompatible = false, EShMessages messages = EShMsgDefault);
     virtual ~HlslParseContext();
     void initializeExtensionBehavior();
@@ -165,6 +166,9 @@ public:
     bool handleOutputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
     bool handleInputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
 
+    // Potentially rename shader entry point function
+    void renameShaderFunction(TString*& name) const;
+
 protected:
     void inheritGlobalDefaults(TQualifier& dst) const;
     TVariable* makeInternalVariable(const char* name, const TType&) const;
@@ -251,6 +255,8 @@ protected:
     TMap<int, TVector<TVariable*>> flattenMap;
     unsigned int nextInLocation;
     unsigned int nextOutLocation;
+
+    TString sourceEntryPointName;
 };
 
 } // end namespace glslang