Reflection:

- correct block data size
 - handle deep dereference chains (block.member.member.member)
 - more clear interface argument names

(Still TBD: optimizing array size based on biggest used index and handling variable array index in middle of deep dereference chain)

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@24072 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2013-11-15 01:34:27 +00:00
parent c0827e4532
commit 12f9221e44
6 changed files with 167 additions and 120 deletions

View File

@ -8,60 +8,39 @@ Linked vertex stage:
Uniform reflection: Uniform reflection:
0: image_ui2D: offset -1, type 9063, arraySize 1, index -1 image_ui2D: offset -1, type 9063, size 1, index -1
1: sampler_2D: offset -1, type 8b5e, arraySize 1, index -1 sampler_2D: offset -1, type 8b5e, size 1, index -1
2: sampler_2DMSArray: offset -1, type 910b, arraySize 1, index -1 sampler_2DMSArray: offset -1, type 910b, size 1, index -1
3: anonMember3: offset 80, type 8b52, arraySize 1, index 0 anonMember3: offset 80, type 8b52, size 1, index 0
4: s.a: offset -1, type 1404, arraySize 1, index -1 s.a: offset -1, type 1404, size 1, index -1
5: ablock.scalar: offset 12, type 1404, arraySize 1, index 1 ablock.scalar: offset 12, type 1404, size 1, index 1
6: m23: offset 16, type 8b67, arraySize 1, index 0 m23: offset 16, type 8b67, size 1, index 0
7: scalarAfterm23: offset 48, type 1404, arraySize 1, index 0 scalarAfterm23: offset 48, type 1404, size 1, index 0
8: c_m23: offset 16, type 8b67, arraySize 1, index 2 c_m23: offset 16, type 8b67, size 1, index 2
9: c_scalarAfterm23: offset 64, type 1404, arraySize 1, index 2 c_scalarAfterm23: offset 64, type 1404, size 1, index 2
10: scalarBeforeArray: offset 96, type 1404, arraySize 1, index 0 scalarBeforeArray: offset 96, type 1404, size 1, index 0
11: floatArray: offset 112, type 1406, arraySize 5, index 0 floatArray: offset 112, type 1406, size 5, index 0
12: scalarAfterArray: offset 192, type 1404, arraySize 1, index 0 scalarAfterArray: offset 192, type 1404, size 1, index 0
13: ablock.memvec2: offset 48, type 8b50, arraySize 1, index 1 ablock.memvec2: offset 48, type 8b50, size 1, index 1
14: ablock.memf1: offset 56, type 1406, arraySize 1, index 1 ablock.memf1: offset 56, type 1406, size 1, index 1
15: ablock.memf2: offset 60, type 8b56, arraySize 1, index 1 ablock.memf2: offset 60, type 8b56, size 1, index 1
16: ablock.memf3: offset 64, type 1404, arraySize 1, index 1 ablock.memf3: offset 64, type 1404, size 1, index 1
17: ablock.memvec2a: offset 72, type 8b50, arraySize 1, index 1 ablock.memvec2a: offset 72, type 8b50, size 1, index 1
18: anonMember1: offset 0, type 8b51, arraySize 1, index 0 ablock.m22: offset 80, type 8b5a, size 7, index 1
19: uf1: offset -1, type 1406, arraySize 1, index -1 dm22: offset -1, type 8b5a, size 10, index -1
20: uf2: offset -1, type 1406, arraySize 1, index -1 m22: offset 208, type 8b5a, size 9, index 0
21: ablock.member3: offset 32, type 8b52, arraySize 1, index 1 nest.foo.n1.a: offset 0, type 1406, size 1, index 3
nest.foo.n2.b: offset 16, type 1406, size 1, index 3
nest.foo.n2.c: offset 20, type 1406, size 1, index 3
nest.foo.n2.d: offset 24, type 1406, size 1, index 3
anonMember1: offset 0, type 8b51, size 1, index 0
uf1: offset -1, type 1406, size 1, index -1
uf2: offset -1, type 1406, size 1, index -1
ablock.member3: offset 32, type 8b52, size 1, index 1
Uniform block reflection: Uniform block reflection:
0: nameless: offset -1, type ffffffff, arraySize 1, index -1 nameless: offset -1, type ffffffff, size 496, index -1
1: ablock: offset -1, type ffffffff, arraySize 1, index -1 ablock: offset -1, type ffffffff, size 304, index -1
2: c_nameless: offset -1, type ffffffff, arraySize 1, index -1 c_nameless: offset -1, type ffffffff, size 112, index -1
nest: offset -1, type ffffffff, size 28, index -1
Live names
ablock: 1
ablock.member3: 21
ablock.memf1: 14
ablock.memf2: 15
ablock.memf3: 16
ablock.memvec2: 13
ablock.memvec2a: 17
ablock.scalar: 5
anonMember1: 18
anonMember3: 3
c_m23: 8
c_nameless: 2
c_scalarAfterm23: 9
floatArray: 11
image_ui2D: 0
liveFunction1(uI21;s21;sA21;: -1
liveFunction2(: -1
m23: 6
nameless: 0
s.a: 4
sampler_2D: 1
sampler_2DMSArray: 2
scalarAfterArray: 12
scalarAfterm23: 7
scalarBeforeArray: 10
uf1: 19
uf2: 20

View File

@ -9,6 +9,7 @@ layout(std140, row_major) uniform nameless {
int scalarBeforeArray; int scalarBeforeArray;
float floatArray[5]; float floatArray[5];
int scalarAfterArray; int scalarAfterArray;
mat2x2 m22[9];
}; };
layout(std140, column_major) uniform c_nameless { layout(std140, column_major) uniform c_nameless {
@ -29,6 +30,7 @@ layout(std140) uniform named {
bool memf2; bool memf2;
int memf3; int memf3;
vec2 memvec2a; vec2 memvec2a;
mat2x2 m22[7];
} ablock; } ablock;
layout(std140) uniform namelessdead { layout(std140) uniform namelessdead {
@ -39,6 +41,25 @@ layout(std140) uniform namedDead {
int b; int b;
} bblock; } bblock;
struct N1 {
float a;
};
struct N2 {
float b;
float c;
float d;
};
struct N3 {
N1 n1;
N2 n2;
};
layout(std140) uniform nested {
N3 foo;
} nest;
struct TS { struct TS {
int a; int a;
int dead; int dead;
@ -55,6 +76,8 @@ uniform uimage2D image_ui2D;
uniform sampler2D sampler_2D; uniform sampler2D sampler_2D;
uniform sampler2DMSArray sampler_2DMSArray; uniform sampler2DMSArray sampler_2DMSArray;
uniform mat2 dm22[10];
const bool control = true; const bool control = true;
void deadFunction() void deadFunction()
@ -87,7 +110,7 @@ void main()
deadFunction(); deadFunction();
float f; float f;
int i;
if (control) { if (control) {
liveFunction2(); liveFunction2();
f = anonMember3.z; f = anonMember3.z;
@ -103,6 +126,10 @@ void main()
f += float(ablock.memf2); f += float(ablock.memf2);
f += ablock.memf3; f += ablock.memf3;
f += ablock.memvec2a.y; f += ablock.memvec2a.y;
f += ablock.m22[i][1][0];
f += dm22[3][0][1];
f += m22[2][1].y;
f += nest.foo.n1.a + nest.foo.n2.b + nest.foo.n2.c + nest.foo.n2.d;
} else } else
f = ufDead3; f = ufDead3;
} }

View File

@ -20,6 +20,7 @@ Link Validation
- 4.3: Allow mismatches in interpolation and auxiliary qualification across stages. - 4.3: Allow mismatches in interpolation and auxiliary qualification across stages.
- 4.4: A stage contains two different blocks, each with no instance name, where the blocks contain a member with the same name. - 4.4: A stage contains two different blocks, each with no instance name, where the blocks contain a member with the same name.
Intra-stage linking, single shader Intra-stage linking, single shader
+ recursion for functions
- limits checking: - limits checking:
- number of texture image units - number of texture image units
- texel offsets (or compile-time?) - texel offsets (or compile-time?)
@ -34,28 +35,27 @@ Link Validation
+ Non ES: geometry shader input array sizes and input layout qualifier declaration + Non ES: geometry shader input array sizes and input layout qualifier declaration
- Non ES: read or write to both gl_ClipVertex and gl_ClipDistance - Non ES: read or write to both gl_ClipVertex and gl_ClipDistance
- Non ES: write to only one of gl_FragColor, gl_FragData, or user-declared - Non ES: write to only one of gl_FragColor, gl_FragData, or user-declared
+ 1.50: match between all explicit input array sizes and input primitive
- 1.50: at least one geometry shader says input primitive and at least one says output primitive... - 1.50: at least one geometry shader says input primitive and at least one says output primitive...
- 1.50: at least one geometry shader says max_vertices... - 1.50: at least one geometry shader says max_vertices...
- 1.50: geometry shaders: max_vertices must be checked against gl_MaxGeometryOutputVertices (maybe at compile time) - 1.50: geometry shaders: max_vertices must be checked against gl_MaxGeometryOutputVertices (maybe at compile time)
+ 1.50: origin_upper_left and pixel_center_integer have to match + 1.50: origin_upper_left and pixel_center_integer have to match
- Even the potential for recursion through subroutine uniforms is an error.
- 4.4: An interface contains two different blocks, each with no instance name, where the blocks contain a member with the same name. - 4.4: An interface contains two different blocks, each with no instance name, where the blocks contain a member with the same name.
- 4.4: component aliasing (except desktop vertex shader inputs) - 4.4: component aliasing (except desktop vertex shader inputs)
Intra-stage linking, multiple shader - 4.4: overlapping transform/feedback offsets, offset/stride overflow checks, and stride matching
+ Non ES: type consistency check of uniforms, globals, ins, and outs Intra-stage linking, multiple shader (Non-ES)
+ Non ES: value checking of global const initializers + type consistency check of uniforms, globals, ins, and outs
+ Non ES: value checking of uniform initializers + value checking of global const initializers
+ Non ES: location match + value checking of uniform initializers
+ recursion for functions + location match
- Non ES: block matching - block matching
- Non ES: component/binding/index/offset match check - component/binding/index/offset match check
- Non ES: compute shader layout(local_size_*) matching - compute shader layout(local_size_*) matching
+ mixed es/non-es profiles are an error + mixed es/non-es profiles are an error
- Non ES: Even the potential for recursion through subroutine uniforms is an error. - matching redeclarations of interface blocks
- Non ES: matching redeclarations of interface blocks
- 1.50: match between all explicit input array sizes and input primitive
- 4.3: early_fragment_tests contradictions - 4.3: early_fragment_tests contradictions
- 4.3: implicit array sizing is cross shader within a stage - 4.3: implicit array sizing is cross shader within a stage
- 4.4: overlapping transform/feedback offsets, offset/stride overflow checks, and stride matching
- 4.4: If gl_FragCoord is redeclared in any fragment shader in a program, it must be redeclared in all the fragment shaders in that program that have a static use gl_FragCoord - 4.4: If gl_FragCoord is redeclared in any fragment shader in a program, it must be redeclared in all the fragment shaders in that program that have a static use gl_FragCoord
Shader Functionality to Implement/Finish Shader Functionality to Implement/Finish

View File

@ -144,7 +144,7 @@ public:
if (type.getBasicType() == EbtStruct) { if (type.getBasicType() == EbtStruct) {
const TTypeList& memberList = *type.getStruct(); const TTypeList& memberList = *type.getStruct();
int size = 0; size = 0;
int maxAlignment = std140 ? baseAlignmentVec4Std140 : 0; int maxAlignment = std140 ? baseAlignmentVec4Std140 : 0;
for (size_t m = 0; m < memberList.size(); ++m) { for (size_t m = 0; m < memberList.size(); ++m) {
int memberSize; int memberSize;
@ -203,7 +203,7 @@ public:
// block offset rules. // block offset rules.
int getBlockMemberOffset(const TType& blockType, int index) int getBlockMemberOffset(const TType& blockType, int index)
{ {
// TODO: reflection performance: cache these results instead of recomputing them // TODO: reflection performance: cache intermediate results instead of recomputing them
int offset = 0; int offset = 0;
const TTypeList& memberList = *blockType.getStruct(); const TTypeList& memberList = *blockType.getStruct();
@ -219,55 +219,99 @@ public:
return offset; return offset;
} }
// Add a complex uniform reference where blocks/struct/arrays are involved in the access. // Calculate the block data size.
void addDereferencedUniform(TIntermSymbol* base, TIntermBinary* node) // Arrayness is not taken into account, each element is backed by a separate buffer.
int getBlockSize(const TType& blockType)
{
int size = 0;
const TTypeList& memberList = *blockType.getStruct();
int memberSize;
for (size_t m = 0; m < memberList.size(); ++m) {
int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, blockType.getQualifier().layoutPacking == ElpStd140);
align(size, memberAlignment);
size += memberSize;
}
return size;
}
// Add a complex uniform reference where blocks/struct/arrays are involved in the access.
// Handles the situation where the left node is at too coarse a granularity to be a single
// uniform, while the result of the operation at 'node' is at the right granuarity.
//
// Note: Simpler things like the following are already handled elsewhere:
// - a simple non-array, non-struct variable
// - a variable that's an array of non-struct
//
// So, this code is for cases like
// - a struct/block holding a member (member is array or not)
// - an array of struct
// - structs/arrays containing the above
//
void addDereferencedUniform(TIntermSymbol* base, TIntermBinary* topNode)
{ {
bool block = base->getBasicType() == EbtBlock;
int offset = -1; int offset = -1;
int blockIndex = -1; int blockIndex = -1;
bool anonymous = false; bool anonymous = false;
// See if we need to record the block itself
bool block = base->getBasicType() == EbtBlock;
if (block) { if (block) {
// TODO: how is an array of blocks handled differently?
anonymous = base->getName().compare(0, 6, "__anon") == 0; anonymous = base->getName().compare(0, 6, "__anon") == 0;
const TString& blockName = anonymous ? base->getType().getTypeName() : base->getName(); const TString& blockName = anonymous ? base->getType().getTypeName() : base->getName();
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(blockName); TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(blockName);
if (it == reflection.nameToIndex.end()) { if (it == reflection.nameToIndex.end()) {
blockIndex = reflection.indexToUniformBlock.size(); blockIndex = reflection.indexToUniformBlock.size();
reflection.nameToIndex[blockName] = blockIndex; reflection.nameToIndex[blockName] = blockIndex;
reflection.indexToUniformBlock.push_back(TObjectReflection(blockName, -1, -1, 1, -1)); reflection.indexToUniformBlock.push_back(TObjectReflection(blockName, offset, -1, getBlockSize(base->getType()), -1));
} else } else
blockIndex = it->second; blockIndex = it->second;
} }
TString name;
switch (node->getOp()) { // Process the dereference chain, backward, accumulating the pieces on a stack
case EOpIndexDirect: if (block)
case EOpIndexIndirect: offset = 0;
// TODO: reflection: handle array dereferences std::list<TString> derefs;
//name = base->getName(); for (TIntermBinary* visitNode = topNode; visitNode; visitNode = visitNode->getLeft()->getAsBinaryNode()) {
//name.append("[]"); int index;
break; switch (visitNode->getOp()) {
case EOpIndexDirectStruct: case EOpIndexIndirect:
{ // TODO handle indirect references in mid-chain: enumerate all possibilities?
if (! anonymous) { derefs.push_back(TString("[") + String(0) + "]");
name = base->getName(); break;
name.append("."); case EOpIndexDirect:
// TODO: reflection: track the highest used index for an array, to reduce the array's size
index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
derefs.push_back(TString("[") + String(index) + "]");
break;
case EOpIndexDirectStruct:
index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
if (block)
offset += getBlockMemberOffset(visitNode->getLeft()->getType(), index);
derefs.push_back(TString(""));
if (visitNode->getLeft()->getAsSymbolNode() != base || ! anonymous)
derefs.back().append(".");
derefs.back().append((*visitNode->getLeft()->getType().getStruct())[index].type->getFieldName().c_str());
break;
default:
break;
} }
int structIndex = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
if (block)
offset = getBlockMemberOffset(base->getType(), structIndex);
name.append((*base->getType().getStruct())[structIndex].type->getFieldName().c_str());
break;
}
default:
break;
} }
// TODO: reflection: handle deeper dereference chains than just one dereference // Put the dereference chain together, forward (reversing the stack)
TString name;
if (! anonymous)
name = base->getName();
while (! derefs.empty()) {
name += derefs.back();
derefs.pop_back();
}
if (name.size() > 0) { if (name.size() > 0) {
if (reflection.nameToIndex.find(name) == reflection.nameToIndex.end()) { if (reflection.nameToIndex.find(name) == reflection.nameToIndex.end()) {
reflection.nameToIndex[name] = reflection.indexToUniform.size(); reflection.nameToIndex[name] = reflection.indexToUniform.size();
reflection.indexToUniform.push_back(TObjectReflection(name, offset, mapToGlType(node->getType()), mapToGlArraySize(node->getType()), blockIndex)); reflection.indexToUniform.push_back(TObjectReflection(name, offset, mapToGlType(topNode->getType()), mapToGlArraySize(topNode->getType()), blockIndex));
} }
} }
} }
@ -585,7 +629,8 @@ bool LiveBinary(bool /* preVisit */, TIntermBinary* node, TIntermTraverser* it)
// this operation, and pick it up when the left side is visited. // this operation, and pick it up when the left side is visited.
if (! oit->isReflectionGranularity(node->getLeft()->getType()) && if (! oit->isReflectionGranularity(node->getLeft()->getType()) &&
oit->isReflectionGranularity(node->getType())) { oit->isReflectionGranularity(node->getType())) {
// right granularity; see if this really is a uniform-based dereference // right granularity; see if this really is a uniform-based dereference,
// and if so, process it
TIntermSymbol* base = oit->findBase(node); TIntermSymbol* base = oit->findBase(node);
if (base && base->getQualifier().storage == EvqUniform) if (base && base->getQualifier().storage == EvqUniform)
oit->addDereferencedUniform(base, node); oit->addDereferencedUniform(base, node);
@ -660,23 +705,19 @@ bool TReflection::addStage(EShLanguage, const TIntermediate& intermediate)
void TReflection::dump() void TReflection::dump()
{ {
printf("Uniform reflection:\n"); printf("Uniform reflection:\n");
for (size_t i = 0; i < indexToUniform.size(); ++i) { for (size_t i = 0; i < indexToUniform.size(); ++i)
printf("%d: ", (int)i);
indexToUniform[i].dump(); indexToUniform[i].dump();
}
printf("\n"); printf("\n");
printf("Uniform block reflection:\n"); printf("Uniform block reflection:\n");
for (size_t i = 0; i < indexToUniformBlock.size(); ++i) { for (size_t i = 0; i < indexToUniformBlock.size(); ++i)
printf("%d: ", (int)i);
indexToUniformBlock[i].dump(); indexToUniformBlock[i].dump();
}
printf("\n"); printf("\n");
printf("Live names\n"); //printf("Live names\n");
for (TNameToIndex::const_iterator it = nameToIndex.begin(); it != nameToIndex.end(); ++it) //for (TNameToIndex::const_iterator it = nameToIndex.begin(); it != nameToIndex.end(); ++it)
printf("%s: %d\n", it->first.c_str(), it->second); // printf("%s: %d\n", it->first.c_str(), it->second);
printf("\n"); //printf("\n");
} }
} // end namespace glslang } // end namespace glslang

View File

@ -56,7 +56,7 @@ class TObjectReflection {
public: public:
TObjectReflection(const TString& pName, int pOffset, int pGLDefineType, int pSize, int pIndex) : TObjectReflection(const TString& pName, int pOffset, int pGLDefineType, int pSize, int pIndex) :
name(pName), offset(pOffset), glDefineType(pGLDefineType), size(pSize), index(pIndex) { } name(pName), offset(pOffset), glDefineType(pGLDefineType), size(pSize), index(pIndex) { }
void dump() const { printf("%s: offset %d, type %x, arraySize %d, index %d\n", name.c_str(), offset, glDefineType, size, index); } void dump() const { printf("%s: offset %d, type %x, size %d, index %d\n", name.c_str(), offset, glDefineType, size, index); }
TString name; TString name;
int offset; int offset;
int glDefineType; int glDefineType;

View File

@ -328,17 +328,17 @@ public:
const char* getInfoDebugLog(); const char* getInfoDebugLog();
// Reflection Interface // Reflection Interface
bool buildReflection(); // call first, to do liveness analysis, index mapping, etc.; returns false on failure bool buildReflection(); // call first, to do liveness analysis, index mapping, etc.; returns false on failure
int getNumLiveUniformVariables(); // can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS) int getNumLiveUniformVariables(); // can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS)
int getNumLiveUniformBlocks(); // can be used for glGetProgramiv(GL_ACTIVE_UNIFORM_BLOCKS) int getNumLiveUniformBlocks(); // can be used for glGetProgramiv(GL_ACTIVE_UNIFORM_BLOCKS)
const char* getUniformName(int index); // can be used for "name" part of glGetActiveUniform() const char* getUniformName(int index); // can be used for "name" part of glGetActiveUniform()
const char* getUniformBlockName(int index); // can be used for glGetActiveUniformBlockName() const char* getUniformBlockName(int blockIndex); // can be used for glGetActiveUniformBlockName()
int getUniformBlockSize(int index); // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE) int getUniformBlockSize(int blockIndex); // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE)
int getUniformIndex(const char* name); // can be used for glGetUniformIndices() int getUniformIndex(const char* name); // can be used for glGetUniformIndices()
int getUniformBlockIndex(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX) int getUniformBlockIndex(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX)
int getUniformType(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE) int getUniformType(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE)
int getUniformBufferOffset(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET) int getUniformBufferOffset(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET)
int getUniformArraySize(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE) int getUniformArraySize(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE)
void dumpReflection(); void dumpReflection();
protected: protected: