ReflectOptions |= EShReflectionBasicArraySuffix;
} else if (lowerword == "reflect-intermediate-io") {
ReflectOptions |= EShReflectionIntermediateIO;
+ } else if (lowerword == "reflect-separate-buffers") {
+ ReflectOptions |= EShReflectionSeparateBuffers;
} else if (lowerword == "resource-set-bindings" || // synonyms
lowerword == "resource-set-binding" ||
lowerword == "rsb") {
" --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"
+ " --reflect-separate-buffers reflect buffer variables and blocks separately to uniforms\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, numMembers 1
tb: offset -1, type ffffffff, size 4, index -1, binding 17, stages 0, numMembers 1
+Buffer variable reflection:
+
+Buffer block reflection:
+
Pipeline input reflection:
Pipeline output reflection:
cbuff1: offset -1, type ffffffff, size 24, index -1, binding 2, stages 0, numMembers 3
cbuff2: offset -1, type ffffffff, size 24, index -1, binding 3, stages 0, numMembers 3
+Buffer variable reflection:
+
+Buffer block reflection:
+
Pipeline input reflection:
Pipeline output reflection:
abl: offset -1, type ffffffff, size 4, index -1, binding -1, stages 0, numMembers 1
abl2: offset -1, type ffffffff, size 4, index -1, binding -1, stages 0, numMembers 1
+Buffer variable reflection:
+
+Buffer block 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
cb: offset -1, type ffffffff, size 4, index -1, binding 51, stages 0, numMembers 1
tb: offset -1, type ffffffff, size 4, index -1, binding 27, stages 0, numMembers 1
+Buffer variable reflection:
+
+Buffer block reflection:
+
Pipeline input reflection:
Pipeline output reflection:
Uniform block reflection:
+Buffer variable reflection:
+
+Buffer block reflection:
+
Pipeline input reflection:
Pipeline output reflection:
Uniform block reflection:
+Buffer variable reflection:
+
+Buffer block reflection:
+
Pipeline input reflection:
inval: offset 0, type 1406, size 0, index 0, binding -1, stages 0
reflection.options.vert
Uniform reflection:
+UBO.verts[0].position[0]: offset 0, type 1406, size 1, index 0, binding -1, stages 1, arrayStride 4, topLevelArrayStride 24
+UBO.verts[1].position[0]: offset 24, type 1406, size 1, index 0, binding -1, stages 1, arrayStride 4, topLevelArrayStride 24
+UBO.flt[0]: offset 48, type 1406, size 8, index 0, binding -1, stages 1, arrayStride 4, topLevelArrayStride 4
+
+Uniform block reflection:
+UBO: offset -1, type ffffffff, size 80, index -1, binding -1, stages 0, numMembers 5
+
+Buffer variable reflection:
t[0].v[0].position[0]: offset 0, type 1406, size 3, index 0, binding -1, stages 1, arrayStride 4, topLevelArrayStride 72
t[0].v[1].position[0]: offset 24, type 1406, size 3, index 0, binding -1, stages 1, arrayStride 4, topLevelArrayStride 72
t[0].v[2].position[0]: offset 48, type 1406, size 3, index 0, binding -1, stages 1, arrayStride 4, topLevelArrayStride 72
MultipleArrays.vert[0].position[0]: offset 360, type 1406, size 1, index 1, binding -1, stages 1, arrayStride 4, topLevelArrayStride 24
MultipleArrays.f[0]: offset 480, type 1406, size 5, index 1, binding -1, stages 1, arrayStride 4, topLevelArrayStride 4
-Uniform block reflection:
+Buffer block reflection:
VertexCollection: offset -1, type ffffffff, size 360, index -1, binding -1, stages 0, numMembers 6
MultipleArrays: offset -1, type ffffffff, size 500, index -1, binding -1, stages 0, numMembers 9
nested2: offset -1, type ffffffff, size 208, index -1, binding -1, stages 0, numMembers 15
VertexCollection: offset -1, type ffffffff, size 360, index -1, binding -1, stages 0, numMembers 30
+Buffer variable reflection:
+
+Buffer block 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
float f[5];\r
} multiarray;\r
\r
+uniform UBO {\r
+ VertexInfo verts[2];\r
+ float flt[8];\r
+} ubo;\r
+\r
out float outval;\r
\r
void main()\r
f += multiarray.tri[gl_InstanceID].v[0].position[0];\r
f += multiarray.vert[gl_InstanceID].position[0];\r
f += multiarray.f[gl_InstanceID];\r
+ f += ubo.verts[gl_InstanceID].position[0];\r
+ f += ubo.flt[gl_InstanceID];\r
TriangleInfo tlocal[5] = t;\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 --reflect-intermediate-io reflection.options.vert > $TARGETDIR/reflection.options.vert.out
+$EXE -l -q -C --reflect-strict-array-suffix --reflect-basic-array-suffix --reflect-intermediate-io --reflect-separate-buffers 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
+$EXE -l -q -C --reflect-strict-array-suffix --reflect-basic-array-suffix --reflect-intermediate-io --reflect-separate-buffers 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
unsigned TProgram::getLocalSize(int dim) const { return reflection->getLocalSize(dim); }
int TProgram::getReflectionIndex(const char* name) const { return reflection->getIndex(name); }
-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(); }
-const TObjectReflection& TProgram::getUniformBlock(int index) const { return reflection->getUniformBlock(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); }
+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(); }
+const TObjectReflection& TProgram::getUniformBlock(int index) const { return reflection->getUniformBlock(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); }
+int TProgram::getNumBufferVariables() const { return reflection->getNumBufferVariables(); }
+const TObjectReflection& TProgram::getBufferVariable(int index) const { return reflection->getBufferVariable(index); }
+int TProgram::getNumBufferBlocks() const { return reflection->getNumStorageBuffers(); }
+const TObjectReflection& TProgram::getBufferBlock(int index) const { return reflection->getStorageBufferBlock(index); }
+int TProgram::getNumAtomicCounters() const { return reflection->getNumAtomicCounters(); }
+const TObjectReflection& TProgram::getAtomicCounter(int index) const { return reflection->getAtomicCounter(index); }
void TProgram::dumpReflection() { reflection->dump(); }
// Use a degenerate (empty) set of dereferences to immediately put as at the end of
// the dereference change expected by blowUpActiveAggregate.
TList<TIntermBinary*> derefs;
- blowUpActiveAggregate(base.getType(), base.getName(), derefs, derefs.end(), -1, -1, 0, 0);
+ blowUpActiveAggregate(base.getType(), base.getName(), derefs, derefs.end(), -1, -1, 0, 0,
+ base.getQualifier().storage);
}
}
// A value of 0 for arraySize will mean to use the full array's size.
void blowUpActiveAggregate(const TType& baseType, const TString& baseName, const TList<TIntermBinary*>& derefs,
TList<TIntermBinary*>::const_iterator deref, int offset, int blockIndex, int arraySize,
- int topLevelArrayStride)
+ int topLevelArrayStride, TStorageQualifier baseStorage)
{
// when strictArraySuffix is enabled, we closely follow the rules from ARB_program_interface_query.
// Broadly:
++nextDeref;
TType derefType(*terminalType, 0);
blowUpActiveAggregate(derefType, newBaseName, derefs, nextDeref, offset, blockIndex, arraySize,
- topLevelArrayStride);
+ topLevelArrayStride, baseStorage);
if (offset >= 0)
offset += stride;
offset = baseOffset + stride * i;
blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0,
- topLevelArrayStride);
+ topLevelArrayStride, baseStorage);
}
} else {
// Visit all members of this aggregate, and for each one,
}
blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0,
- arrayStride);
+ arrayStride, baseStorage);
}
}
if (arraySize == 0)
arraySize = mapToGlArraySize(*terminalType);
+ TReflection::TMapIndexToReflection& variables = reflection.GetVariableMapForStorage(baseStorage);
+
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
if (it == reflection.nameToIndex.end()) {
- reflection.nameToIndex[name.c_str()] = (int)reflection.indexToUniform.size();
-
- reflection.indexToUniform.push_back(TObjectReflection(name.c_str(), *terminalType, offset,
- mapToGlType(*terminalType),
- arraySize, blockIndex));
+ int uniformIndex = (int)variables.size();
+ reflection.nameToIndex[name.c_str()] = uniformIndex;
+ variables.push_back(TObjectReflection(name.c_str(), *terminalType, offset, mapToGlType(*terminalType),
+ arraySize, blockIndex));
if (terminalType->isArray()) {
- reflection.indexToUniform.back().arrayStride = getArrayStride(baseType, *terminalType);
+ variables.back().arrayStride = getArrayStride(baseType, *terminalType);
if (topLevelArrayStride == 0)
- topLevelArrayStride = reflection.indexToUniform.back().arrayStride;
+ topLevelArrayStride = variables.back().arrayStride;
}
- reflection.indexToUniform.back().topLevelArrayStride = topLevelArrayStride;
+ if ((reflection.options & EShReflectionSeparateBuffers) && terminalType->getBasicType() == EbtAtomicUint)
+ reflection.atomicCounterUniformIndices.push_back(uniformIndex);
+
+ variables.back().topLevelArrayStride = topLevelArrayStride;
} else if (arraySize > 1) {
- int& reflectedArraySize = reflection.indexToUniform[it->second].size;
+ int& reflectedArraySize = variables[it->second].size;
reflectedArraySize = std::max(arraySize, reflectedArraySize);
}
}
else
baseName = base->getName();
}
- blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.begin(), offset, blockIndex, arraySize, 0);
+ blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.begin(), offset, blockIndex, arraySize, 0,
+ base->getQualifier().storage);
}
int addBlockName(const TString& name, const TType& type, int size)
{
+ TReflection::TMapIndexToReflection& blocks = reflection.GetBlockMapForStorage(type.getQualifier().storage);
+
int blockIndex;
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
if (reflection.nameToIndex.find(name.c_str()) == reflection.nameToIndex.end()) {
- blockIndex = (int)reflection.indexToUniformBlock.size();
+ blockIndex = (int)blocks.size();
reflection.nameToIndex[name.c_str()] = blockIndex;
- reflection.indexToUniformBlock.push_back(TObjectReflection(name.c_str(), type, -1, -1, size, -1));
+ blocks.push_back(TObjectReflection(name.c_str(), type, -1, -1, size, -1));
- reflection.indexToUniformBlock.back().numMembers = countAggregateMembers(type);
+ blocks.back().numMembers = countAggregateMembers(type);
} else
blockIndex = it->second;
for (int i = 0; i < int(indexToUniform.size()); ++i) {
indexToUniform[i].stages = static_cast<EShLanguageMask>(indexToUniform[i].stages | 1 << intermediate.getStage());
}
+
+ for (int i = 0; i < int(indexToBufferVariable.size()); ++i) {
+ indexToBufferVariable[i].stages =
+ static_cast<EShLanguageMask>(indexToBufferVariable[i].stages | 1 << intermediate.getStage());
+ }
}
// Merge live symbols from 'intermediate' into the existing reflection database.
indexToUniformBlock[i].dump();
printf("\n");
+ printf("Buffer variable reflection:\n");
+ for (size_t i = 0; i < indexToBufferVariable.size(); ++i)
+ indexToBufferVariable[i].dump();
+ printf("\n");
+
+ printf("Buffer block reflection:\n");
+ for (size_t i = 0; i < indexToBufferBlock.size(); ++i)
+ indexToBufferBlock[i].dump();
+ printf("\n");
+
printf("Pipeline input reflection:\n");
for (size_t i = 0; i < indexToPipeInput.size(); ++i)
indexToPipeInput[i].dump();
return badReflection;
}
+ // for mapping from an atomic counter to the uniform index
+ int getNumAtomicCounters() const { return (int)atomicCounterUniformIndices.size(); }
+ const TObjectReflection& getAtomicCounter(int i) const
+ {
+ if (i >= 0 && i < (int)atomicCounterUniformIndices.size())
+ return getUniform(atomicCounterUniformIndices[i]);
+ else
+ return badReflection;
+ }
+
+ // for mapping a buffer variable index to a buffer variable object's description
+ int getNumBufferVariables() { return (int)indexToBufferVariable.size(); }
+ const TObjectReflection& getBufferVariable(int i) const
+ {
+ if (i >= 0 && i < (int)indexToBufferVariable.size())
+ return indexToBufferVariable[i];
+ else
+ return badReflection;
+ }
+
+ // for mapping a storage block index to the storage block's description
+ int getNumStorageBuffers() const { return (int)indexToBufferBlock.size(); }
+ const TObjectReflection& getStorageBufferBlock(int i) const
+ {
+ if (i >= 0 && i < (int)indexToBufferBlock.size())
+ return indexToBufferBlock[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
{
// Need a TString hash: typedef std::unordered_map<TString, int> TNameToIndex;
typedef std::map<std::string, int> TNameToIndex;
typedef std::vector<TObjectReflection> TMapIndexToReflection;
+ typedef std::vector<int> TIndices;
+
+ TMapIndexToReflection& GetBlockMapForStorage(TStorageQualifier storage)
+ {
+ if ((options & EShReflectionSeparateBuffers) && storage == EvqBuffer)
+ return indexToBufferBlock;
+ return indexToUniformBlock;
+ }
+ TMapIndexToReflection& GetVariableMapForStorage(TStorageQualifier storage)
+ {
+ if ((options & EShReflectionSeparateBuffers) && storage == EvqBuffer)
+ return indexToBufferVariable;
+ return indexToUniform;
+ }
EShReflectionOptions options;
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 indexToBufferVariable;
+ TMapIndexToReflection indexToBufferBlock;
TMapIndexToReflection indexToPipeInput;
TMapIndexToReflection indexToPipeOutput;
+ TIndices atomicCounterUniformIndices;
unsigned int localSize[3];
};
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
+ EShReflectionSeparateBuffers = (1 << 3), // buffer variables and buffer blocks are reflected separately
} EShReflectionOptions;
//
const TObjectReflection& getPipeInput(int index) const;
int getNumPipeOutputs() const;
const TObjectReflection& getPipeOutput(int index) const;
+ int getNumBufferVariables() const;
+ const TObjectReflection& getBufferVariable(int index) const;
+ int getNumBufferBlocks() const;
+ const TObjectReflection& getBufferBlock(int index) const;
+ int getNumAtomicCounters() const;
+ const TObjectReflection& getAtomicCounter(int index) const;
// Legacy Reflection Interface - expressed in terms of above interface
int getNumLiveUniformVariables() const // can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS)