Reflect pipeline outputs as well as inputs, optionally from other stages

* We add an option to reflect inputs from other stages than vertex, if only a
  later subset of the stages is linked into the program.
This commit is contained in:
baldurk 2019-01-29 16:04:44 +00:00
parent edf8212ab8
commit 0af5e3e346
17 changed files with 149 additions and 32 deletions

View file

@ -1971,7 +1971,22 @@ bool TProgram::buildReflection(int opts)
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]) {
@ -1990,8 +2005,10 @@ int TProgram::getNumUniformVariables() const { return ref
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(); }

View file

@ -97,7 +97,7 @@ public:
}
}
void addAttribute(const TIntermSymbol& base)
void addPipeInput(const TIntermSymbol& base)
{
if (processedDerefs.find(&base) == processedDerefs.end()) {
processedDerefs.insert(&base);
@ -107,8 +107,24 @@ public:
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));
}
}
}
@ -853,8 +869,11 @@ void TReflectionTraverser::visitSymbol(TIntermSymbol* base)
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);
}
//
@ -964,9 +983,14 @@ void TReflection::dump()
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) {

View file

@ -55,7 +55,8 @@ class TReflectionTraverser;
// 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;
@ -86,17 +87,27 @@ public:
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);
@ -127,11 +138,15 @@ protected:
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];
};

View file

@ -246,6 +246,7 @@ typedef enum {
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;
//
@ -737,8 +738,10 @@ public:
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)
@ -753,7 +756,7 @@ public:
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()
@ -828,17 +831,17 @@ public:
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();