ReflectOptions |= EShReflectionStrictArraySuffix;
} else if (lowerword == "reflect-basic-array-suffix") {
ReflectOptions |= EShReflectionBasicArraySuffix;
+ } else if (lowerword == "reflect-intermediate-io") {
+ ReflectOptions |= EShReflectionIntermediateIO;
} else if (lowerword == "resource-set-bindings" || // synonyms
lowerword == "resource-set-binding" ||
lowerword == "rsb") {
" --no-storage-format | --nsf use Unknown image format\n"
" --reflect-strict-array-suffix use strict array suffix rules when reflecting\n"
" --reflect-basic-array-suffix arrays of basic types will have trailing [0]\n"
+ " --reflect-intermediate-io reflection includes inputs/outputs of linked shaders\n"
+ " rather than just vertex/fragment\n"
" --resource-set-binding [stage] name set binding\n"
" set descriptor set and binding for\n"
" individual resources\n"
cb: offset -1, type ffffffff, size 4, index -1, binding 51, stages 0
tb: offset -1, type ffffffff, size 4, index -1, binding 17, stages 0
-Vertex attribute reflection:
+Pipeline input reflection:
+
+Pipeline output reflection:
+@entryPointOutput: offset 0, type 8b52, size 0, index 0, binding -1, stages 0
cbuff1: offset -1, type ffffffff, size 24, index -1, binding 2, stages 0
cbuff2: offset -1, type ffffffff, size 24, index -1, binding 3, stages 0
-Vertex attribute reflection:
+Pipeline input reflection:
+
+Pipeline output reflection:
+psout.Color: offset 0, type 8b52, size 0, index 0, binding -1, stages 0
abl: offset -1, type ffffffff, size 4, index -1, binding -1, stages 0
abl2: offset -1, type ffffffff, size 4, index -1, binding -1, stages 0
-Vertex attribute reflection:
+Pipeline input reflection:
attributeFloat: offset 0, type 1406, size 0, index 0, binding -1, stages 0
attributeFloat2: offset 0, type 8b50, size 0, index 0, binding -1, stages 0
attributeFloat3: offset 0, type 8b51, size 0, index 0, binding -1, stages 0
attributeFloat4: offset 0, type 8b52, size 0, index 0, binding -1, stages 0
attributeMat4: offset 0, type 8b5c, size 0, index 0, binding -1, stages 0
+Pipeline output reflection:
+
cb: offset -1, type ffffffff, size 4, index -1, binding 51, stages 0
tb: offset -1, type ffffffff, size 4, index -1, binding 27, stages 0
-Vertex attribute reflection:
+Pipeline input reflection:
+
+Pipeline output reflection:
+@entryPointOutput: offset 0, type 8b52, size 0, index 0, binding -1, stages 0
--- /dev/null
+reflection.frag
+Uniform reflection:
+
+Uniform block reflection:
+
+Pipeline input reflection:
+
+Pipeline output reflection:
+
--- /dev/null
+reflection.frag
+Uniform reflection:
+
+Uniform block reflection:
+
+Pipeline input reflection:
+inval: offset 0, type 1406, size 0, index 0, binding -1, stages 0
+
+Pipeline output reflection:
+
Uniform block reflection:
VertexCollection: offset -1, type ffffffff, size 360, index -1, binding -1, stages 0
-Vertex attribute reflection:
+Pipeline input reflection:
gl_InstanceID: offset 0, type 1404, size 0, index 0, binding -1, stages 0
+Pipeline output reflection:
+outval: offset 0, type 1406, size 0, index 0, binding -1, stages 0
+
nested2: offset -1, type ffffffff, size 208, index -1, binding -1, stages 0
VertexCollection: offset -1, type ffffffff, size 360, index -1, binding -1, stages 0
-Vertex attribute reflection:
+Pipeline input reflection:
attributeFloat: offset 0, type 1406, size 0, index 0, binding -1, stages 0
attributeFloat2: offset 0, type 8b50, size 0, index 0, binding -1, stages 0
attributeFloat3: offset 0, type 8b51, size 0, index 0, binding -1, stages 0
attributeMat4: offset 0, type 8b5c, size 0, index 0, binding -1, stages 0
gl_InstanceID: offset 0, type 1404, size 0, index 0, binding -1, stages 0
+Pipeline output reflection:
+
--- /dev/null
+#version 440 core\r
+\r
+in float inval;\r
+\r
+void main()\r
+{\r
+ float f = inval;\r
+}\r
TriangleInfo t[5];\r
};\r
\r
+out float outval;\r
+\r
void main()\r
{\r
float f;\r
f += t[gl_InstanceID].v[gl_InstanceID].position[gl_InstanceID];\r
f += t[gl_InstanceID].v[gl_InstanceID].normal[gl_InstanceID];\r
TriangleInfo tlocal[5] = t;\r
+ outval = f;\r
}\r
TriangleInfo t[5];\r
};\r
\r
+out float outval;\r
+\r
void main()\r
{\r
liveFunction1(image_ui2D, sampler_2D, sampler_2DMSArray);\r
f += t[gl_InstanceID].v[gl_InstanceID].position[gl_InstanceID];\r
f += t[gl_InstanceID].v[gl_InstanceID].normal[gl_InstanceID];\r
TriangleInfo tlocal[5] = t;\r
+\r
+ outval = f;\r
}\r
echo Running reflection...
$EXE -l -q -C reflection.vert > $TARGETDIR/reflection.vert.out
diff -b $BASEDIR/reflection.vert.out $TARGETDIR/reflection.vert.out || HASERROR=1
-$EXE -l -q -C --reflect-strict-array-suffix --reflect-basic-array-suffix reflection.options.vert > $TARGETDIR/reflection.options.vert.out
+$EXE -l -q -C --reflect-strict-array-suffix --reflect-basic-array-suffix --reflect-intermediate-io reflection.options.vert > $TARGETDIR/reflection.options.vert.out
diff -b $BASEDIR/reflection.options.vert.out $TARGETDIR/reflection.options.vert.out || HASERROR=1
+$EXE -l -q -C reflection.frag > $TARGETDIR/reflection.frag.out
+diff -b $BASEDIR/reflection.frag.out $TARGETDIR/reflection.frag.out || HASERROR=1
+$EXE -l -q -C --reflect-strict-array-suffix --reflect-basic-array-suffix --reflect-intermediate-io reflection.frag > $TARGETDIR/reflection.options.frag.out
+diff -b $BASEDIR/reflection.options.frag.out $TARGETDIR/reflection.options.frag.out || HASERROR=1
$EXE -D -Od -e flizv -l -q -C -V -Od hlsl.reflection.vert > $TARGETDIR/hlsl.reflection.vert.out
diff -b $BASEDIR/hlsl.reflection.vert.out $TARGETDIR/hlsl.reflection.vert.out || HASERROR=1
$EXE -D -Od -e main -l -q -C -V -Od hlsl.reflection.binding.frag > $TARGETDIR/hlsl.reflection.binding.frag.out
if (! linked || reflection)
return false;
- reflection = new TReflection((EShReflectionOptions)opts);
+ int firstStage = EShLangVertex, lastStage = EShLangFragment;
+
+ if (opts & EShReflectionIntermediateIO) {
+ // if we're reflecting intermediate I/O, determine the first and last stage linked and use those as the
+ // boundaries for which stages generate pipeline inputs/outputs
+ firstStage = EShLangCount;
+ lastStage = 0;
+ for (int s = 0; s < EShLangCount; ++s) {
+ if (intermediate[s]) {
+ firstStage = std::min(firstStage, s);
+ lastStage = std::max(lastStage, s);
+ }
+ }
+ }
+
+ reflection = new TReflection((EShReflectionOptions)opts, (EShLanguage)firstStage, (EShLanguage)lastStage);
for (int s = 0; s < EShLangCount; ++s) {
if (intermediate[s]) {
const TObjectReflection& TProgram::getUniform(int index) const { return reflection->getUniform(index); }
int TProgram::getNumUniformBlocks() const { return reflection->getNumUniformBlocks(); }
const TObjectReflection& TProgram::getUniformBlock(int index) const { return reflection->getUniformBlock(index); }
-int TProgram::getNumAttributes() const { return reflection->getNumAttributes(); }
-const TObjectReflection& TProgram::getAttribute(int index) const { return reflection->getAttribute(index); }
+int TProgram::getNumPipeInputs() const { return reflection->getNumPipeInputs(); }
+const TObjectReflection& TProgram::getPipeInput(int index) const { return reflection->getPipeInput(index); }
+int TProgram::getNumPipeOutputs() const { return reflection->getNumPipeOutputs(); }
+const TObjectReflection& TProgram::getPipeOutput(int index) const { return reflection->getPipeOutput(index); }
void TProgram::dumpReflection() { reflection->dump(); }
}
}
- void addAttribute(const TIntermSymbol& base)
+ void addPipeInput(const TIntermSymbol& base)
{
if (processedDerefs.find(&base) == processedDerefs.end()) {
processedDerefs.insert(&base);
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
if (it == reflection.nameToIndex.end()) {
- reflection.nameToIndex[name.c_str()] = (int)reflection.indexToAttribute.size();
- reflection.indexToAttribute.push_back(TObjectReflection(name.c_str(), type, 0, mapToGlType(type), 0, 0));
+ reflection.nameToIndex[name.c_str()] = (int)reflection.indexToPipeInput.size();
+ reflection.indexToPipeInput.push_back(TObjectReflection(name.c_str(), type, 0, mapToGlType(type), 0, 0));
+ }
+ }
+ }
+
+ void addPipeOutput(const TIntermSymbol& base)
+ {
+ if (processedDerefs.find(&base) == processedDerefs.end()) {
+ processedDerefs.insert(&base);
+
+ const TString &name = base.getName();
+ const TType &type = base.getType();
+
+ TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
+ if (it == reflection.nameToIndex.end()) {
+ reflection.nameToIndex[name.c_str()] = (int)reflection.indexToPipeOutput.size();
+ reflection.indexToPipeOutput.push_back(TObjectReflection(name.c_str(), type, 0, mapToGlType(type), 0, 0));
}
}
}
if (base->getQualifier().storage == EvqUniform)
addUniform(*base);
- if (intermediate.getStage() == EShLangVertex && base->getQualifier().isPipeInput())
- addAttribute(*base);
+ if (intermediate.getStage() == reflection.firstStage && base->getQualifier().isPipeInput())
+ addPipeInput(*base);
+
+ if (intermediate.getStage() == reflection.lastStage && base->getQualifier().isPipeOutput())
+ addPipeOutput(*base);
}
//
indexToUniformBlock[i].dump();
printf("\n");
- printf("Vertex attribute reflection:\n");
- for (size_t i = 0; i < indexToAttribute.size(); ++i)
- indexToAttribute[i].dump();
+ printf("Pipeline input reflection:\n");
+ for (size_t i = 0; i < indexToPipeInput.size(); ++i)
+ indexToPipeInput[i].dump();
+ printf("\n");
+
+ printf("Pipeline output reflection:\n");
+ for (size_t i = 0; i < indexToPipeOutput.size(); ++i)
+ indexToPipeOutput[i].dump();
printf("\n");
if (getLocalSize(0) > 1) {
// The full reflection database
class TReflection {
public:
- TReflection(EShReflectionOptions opts) : options(opts), badReflection(TObjectReflection::badReflection())
+ TReflection(EShReflectionOptions opts, EShLanguage first, EShLanguage last)
+ : options(opts), firstStage(first), lastStage(last), badReflection(TObjectReflection::badReflection())
{
for (int dim=0; dim<3; ++dim)
localSize[dim] = 0;
return badReflection;
}
- // for mapping an attribute index to the attribute's description
- int getNumAttributes() { return (int)indexToAttribute.size(); }
- const TObjectReflection& getAttribute(int i) const
+ // for mapping an pipeline input index to the input's description
+ int getNumPipeInputs() { return (int)indexToPipeInput.size(); }
+ const TObjectReflection& getPipeInput(int i) const
{
- if (i >= 0 && i < (int)indexToAttribute.size())
- return indexToAttribute[i];
+ if (i >= 0 && i < (int)indexToPipeInput.size())
+ return indexToPipeInput[i];
else
return badReflection;
}
- // for mapping any name to its index (block names, uniform names and attribute names)
+ // for mapping an pipeline output index to the output's description
+ int getNumPipeOutputs() { return (int)indexToPipeOutput.size(); }
+ const TObjectReflection& getPipeOutput(int i) const
+ {
+ if (i >= 0 && i < (int)indexToPipeOutput.size())
+ return indexToPipeOutput[i];
+ else
+ return badReflection;
+ }
+
+ // for mapping any name to its index (block names, uniform names and input/output names)
int getIndex(const char* name) const
{
TNameToIndex::const_iterator it = nameToIndex.find(name);
EShReflectionOptions options;
+ EShLanguage firstStage;
+ EShLanguage lastStage;
+
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
TMapIndexToReflection indexToUniform;
TMapIndexToReflection indexToUniformBlock;
- TMapIndexToReflection indexToAttribute;
+ TMapIndexToReflection indexToPipeInput;
+ TMapIndexToReflection indexToPipeOutput;
unsigned int localSize[3];
};
EShReflectionDefault = 0, // default is original behaviour before options were added
EShReflectionStrictArraySuffix = (1 << 0), // reflection will follow stricter rules for array-of-structs suffixes
EShReflectionBasicArraySuffix = (1 << 1), // arrays of basic types will be appended with [0] as in GL reflection
+ EShReflectionIntermediateIO = (1 << 2), // reflect inputs and outputs to program, even with no vertex shader
} EShReflectionOptions;
//
const TObjectReflection& getUniform(int index) const;
int getNumUniformBlocks() const;
const TObjectReflection& getUniformBlock(int index) const;
- int getNumAttributes() const;
- const TObjectReflection& getAttribute(int index) const;
+ int getNumPipeInputs() const;
+ const TObjectReflection& getPipeInput(int index) const;
+ int getNumPipeOutputs() const;
+ const TObjectReflection& getPipeOutput(int index) const;
// Legacy Reflection Interface - expressed in terms of above interface
int getNumLiveUniformVariables() const // can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS)
int getNumLiveAttributes() const // can be used for glGetProgramiv(GL_ACTIVE_ATTRIBUTES)
{
- return getNumAttributes();
+ return getNumPipeInputs();
}
int getUniformIndex(const char* name) const // can be used for glGetUniformIndices()
const char* getAttributeName(int index) const // can be used for glGetActiveAttrib()
{
- return getAttribute(index).name.c_str();
+ return getPipeInput(index).name.c_str();
}
int getAttributeType(int index) const // can be used for glGetActiveAttrib()
{
- return getAttribute(index).glDefineType;
+ return getPipeInput(index).glDefineType;
}
const TType* getAttributeTType(int index) const // returns a TType*
{
- return getAttribute(index).getType();
+ return getPipeInput(index).getType();
}
void dumpReflection();