Reflection will crash when the VS input symbol defines the same name with FS output...
authorChow <laddoc@outlook.com>
Wed, 18 Sep 2019 06:04:29 +0000 (14:04 +0800)
committerChow <laddoc@outlook.com>
Wed, 18 Sep 2019 06:04:29 +0000 (14:04 +0800)
[PURPOSE]:
The current process design for Uniform / Block / Pipe IO symbols reflection (during program linking) is as following :

1.1 using a global mapper called 'TNameToIndex' to store all the relationship of name (of symbols) to their indexes (in their own MapIndexToReflection vectors).

1.2 TNameToIndex mapper will be used during program linking and helps to check and merge duplicate symbols within each stage ( Uniform, Block and Pipe IO)

1.3 Different types of symbols will have their own index mapping storage. All those symbols will share TNameToIndex as a general searching mapper.

1.4 Only IN in first stage and OUT in last stage will be dealed within traversing functions.

Now, here we meet those problems:

2.1 In and Out variables for pipelines are mapping to different MapIndexToReflection vector (ioItems), but they may still have same names within the general symbol search mapper : TNameToIndex.

2.2 Then, when there are same symbols of IN in VS and OUT in FS, TNameToIndex could not tell the difference because it only stores one local index for one symbol (1:1) as a pair of KeyValue.

[What fixed]:

Seperate I/O from other symbols like Uniform and Block (it is wrong to keep them all in TNameToIndex), and save in new searching mappers called pipeInNameToIndex and pipeOutNameToIndex.

Expose new top-level functions defined as getReflectionPipeIOIndex and getPipeIOIndex for users who need to query Pipe I/O information (As they may reach those things through getUniformIndex and getReflectionIndex now, which is a confused way.)

As there are 2 mappers for above symbols, users needs to input second argument when they wanna reach those pipe I/O parameters, that's also why we need to modify GET functions either.

[Test Case]:

The shader is as following:

######### VS ############
layout(location = 0) in vec4 g_position;
layout(location = 1) in vec4 g_color;
out StageData {
vec4 color;
} g_vs_out;
void main() {
gl_Position = g_position;
g_vs_out.color = g_color;
}

########### FS #############
in StageData {
vec4 color;
} g_fs_in;
layout(location = 0) out vec4 g_color;
void main() {
g_color = g_fs_in.color;
}

glslang/MachineIndependent/ShaderLang.cpp
glslang/MachineIndependent/reflection.cpp
glslang/MachineIndependent/reflection.h
glslang/Public/ShaderLang.h

index f63305e..9b3cdc6 100755 (executable)
@@ -2048,6 +2048,9 @@ bool TProgram::buildReflection(int opts)
 
 unsigned TProgram::getLocalSize(int dim) const                        { return reflection->getLocalSize(dim); }
 int TProgram::getReflectionIndex(const char* name) const              { return reflection->getIndex(name); }
+int TProgram::getReflectionPipeIOIndex(const char* name, const bool inOrOut) const
+                                                                      { return reflection->getPipeIOIndex(name, inOrOut); }
+
 int TProgram::getNumUniformVariables() const                          { return reflection->getNumUniforms(); }
 const TObjectReflection& TProgram::getUniform(int index) const        { return reflection->getUniform(index); }
 int TProgram::getNumUniformBlocks() const                             { return reflection->getNumUniformBlocks(); }
index f2be2ff..9f1089d 100644 (file)
@@ -112,6 +112,10 @@ public:
             TReflection::TMapIndexToReflection &ioItems =
                 input ? reflection.indexToPipeInput : reflection.indexToPipeOutput;
 
+
+            TReflection::TNameToIndex &ioMapper =
+                input ? reflection.pipeInNameToIndex : reflection.pipeOutNameToIndex;
+
             if (reflection.options & EShReflectionUnwrapIOBlocks) {
                 bool anonymous = IsAnonymous(name);
 
@@ -129,12 +133,13 @@ public:
                     blowUpIOAggregate(input, baseName, type);
                 }
             } else {
-                TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
-                if (it == reflection.nameToIndex.end()) {
-                    reflection.nameToIndex[name.c_str()] = (int)ioItems.size();
+                TReflection::TNameToIndex::const_iterator it = ioMapper.find(name.c_str());
+                if (it == ioMapper.end()) {
+                    // seperate pipe i/o params from uniforms and blocks
+                    // in is only for input in first stage as out is only for last stage. check traverse in call stack.
+                    ioMapper[name.c_str()] = ioItems.size();
                     ioItems.push_back(
                         TObjectReflection(name.c_str(), type, 0, mapToGlType(type), mapToGlArraySize(type), 0));
-
                     EShLanguageMask& stages = ioItems.back().stages;
                     stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
                 } else {
index e3561a9..efdc893 100644 (file)
@@ -152,6 +152,20 @@ public:
     // see getIndex(const char*)
     int getIndex(const TString& name) const { return getIndex(name.c_str()); }
 
+
+    // for mapping any name to its index (only pipe input/output names)
+    int getPipeIOIndex(const char* name, const bool inOrOut) const
+    {
+        TNameToIndex::const_iterator it = inOrOut ? pipeInNameToIndex.find(name) : pipeOutNameToIndex.find(name);
+        if (it == (inOrOut ? pipeInNameToIndex.end() : pipeOutNameToIndex.end()))
+            return -1;
+        else
+            return it->second;
+    }
+
+    // see gePipeIOIndex(const char*, const bool)
+    int getPipeIOIndex(const TString& name, const bool inOrOut) const { return getPipeIOIndex(name.c_str(), inOrOut); }
+
     // Thread local size
     unsigned getLocalSize(int dim) const { return dim <= 2 ? localSize[dim] : 0; }
 
@@ -189,6 +203,8 @@ protected:
 
     TObjectReflection badReflection; // return for queries of -1 or generally out of range; has expected descriptions with in it for this
     TNameToIndex nameToIndex;        // maps names to indexes; can hold all types of data: uniform/buffer and which function names have been processed
+    TNameToIndex pipeInNameToIndex;  // maps pipe in names to indexes, this is a fix to seperate pipe I/O from uniforms and buffers.
+    TNameToIndex pipeOutNameToIndex; // maps pipe out names to indexes, this is a fix to seperate pipe I/O from uniforms and buffers.
     TMapIndexToReflection indexToUniform;
     TMapIndexToReflection indexToUniformBlock;
     TMapIndexToReflection indexToBufferVariable;
index a071d78..bb06acc 100755 (executable)
@@ -789,6 +789,7 @@ public:
     bool buildReflection(int opts = EShReflectionDefault);
     unsigned getLocalSize(int dim) const;                  // return dim'th local size
     int getReflectionIndex(const char *name) const;
+    int getReflectionPipeIOIndex(const char* name, const bool inOrOut) const;
     int getNumUniformVariables() const;
     const TObjectReflection& getUniform(int index) const;
     int getNumUniformBlocks() const;
@@ -818,6 +819,9 @@ public:
     // can be used for glGetUniformIndices()
     int getUniformIndex(const char *name) const        { return getReflectionIndex(name); }
 
+    int getPipeIOIndex(const char *name, const bool inOrOut) const
+                                                       { return getReflectionPipeIOIndex(name, inOrOut); }
+
     // can be used for "name" part of glGetActiveUniform()
     const char *getUniformName(int index) const        { return getUniform(index).name.c_str(); }