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:
parent
c0827e4532
commit
12f9221e44
@ -8,60 +8,39 @@ Linked vertex stage:
|
||||
|
||||
|
||||
Uniform reflection:
|
||||
0: image_ui2D: offset -1, type 9063, arraySize 1, index -1
|
||||
1: sampler_2D: offset -1, type 8b5e, arraySize 1, index -1
|
||||
2: sampler_2DMSArray: offset -1, type 910b, arraySize 1, index -1
|
||||
3: anonMember3: offset 80, type 8b52, arraySize 1, index 0
|
||||
4: s.a: offset -1, type 1404, arraySize 1, index -1
|
||||
5: ablock.scalar: offset 12, type 1404, arraySize 1, index 1
|
||||
6: m23: offset 16, type 8b67, arraySize 1, index 0
|
||||
7: scalarAfterm23: offset 48, type 1404, arraySize 1, index 0
|
||||
8: c_m23: offset 16, type 8b67, arraySize 1, index 2
|
||||
9: c_scalarAfterm23: offset 64, type 1404, arraySize 1, index 2
|
||||
10: scalarBeforeArray: offset 96, type 1404, arraySize 1, index 0
|
||||
11: floatArray: offset 112, type 1406, arraySize 5, index 0
|
||||
12: scalarAfterArray: offset 192, type 1404, arraySize 1, index 0
|
||||
13: ablock.memvec2: offset 48, type 8b50, arraySize 1, index 1
|
||||
14: ablock.memf1: offset 56, type 1406, arraySize 1, index 1
|
||||
15: ablock.memf2: offset 60, type 8b56, arraySize 1, index 1
|
||||
16: ablock.memf3: offset 64, type 1404, arraySize 1, index 1
|
||||
17: ablock.memvec2a: offset 72, type 8b50, arraySize 1, index 1
|
||||
18: anonMember1: offset 0, type 8b51, arraySize 1, index 0
|
||||
19: uf1: offset -1, type 1406, arraySize 1, index -1
|
||||
20: uf2: offset -1, type 1406, arraySize 1, index -1
|
||||
21: ablock.member3: offset 32, type 8b52, arraySize 1, index 1
|
||||
image_ui2D: offset -1, type 9063, size 1, index -1
|
||||
sampler_2D: offset -1, type 8b5e, size 1, index -1
|
||||
sampler_2DMSArray: offset -1, type 910b, size 1, index -1
|
||||
anonMember3: offset 80, type 8b52, size 1, index 0
|
||||
s.a: offset -1, type 1404, size 1, index -1
|
||||
ablock.scalar: offset 12, type 1404, size 1, index 1
|
||||
m23: offset 16, type 8b67, size 1, index 0
|
||||
scalarAfterm23: offset 48, type 1404, size 1, index 0
|
||||
c_m23: offset 16, type 8b67, size 1, index 2
|
||||
c_scalarAfterm23: offset 64, type 1404, size 1, index 2
|
||||
scalarBeforeArray: offset 96, type 1404, size 1, index 0
|
||||
floatArray: offset 112, type 1406, size 5, index 0
|
||||
scalarAfterArray: offset 192, type 1404, size 1, index 0
|
||||
ablock.memvec2: offset 48, type 8b50, size 1, index 1
|
||||
ablock.memf1: offset 56, type 1406, size 1, index 1
|
||||
ablock.memf2: offset 60, type 8b56, size 1, index 1
|
||||
ablock.memf3: offset 64, type 1404, size 1, index 1
|
||||
ablock.memvec2a: offset 72, type 8b50, size 1, index 1
|
||||
ablock.m22: offset 80, type 8b5a, size 7, index 1
|
||||
dm22: offset -1, type 8b5a, size 10, index -1
|
||||
m22: offset 208, type 8b5a, size 9, index 0
|
||||
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:
|
||||
0: nameless: offset -1, type ffffffff, arraySize 1, index -1
|
||||
1: ablock: offset -1, type ffffffff, arraySize 1, index -1
|
||||
2: c_nameless: offset -1, type ffffffff, arraySize 1, 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
|
||||
nameless: offset -1, type ffffffff, size 496, index -1
|
||||
ablock: offset -1, type ffffffff, size 304, index -1
|
||||
c_nameless: offset -1, type ffffffff, size 112, index -1
|
||||
nest: offset -1, type ffffffff, size 28, index -1
|
||||
|
||||
|
@ -9,6 +9,7 @@ layout(std140, row_major) uniform nameless {
|
||||
int scalarBeforeArray;
|
||||
float floatArray[5];
|
||||
int scalarAfterArray;
|
||||
mat2x2 m22[9];
|
||||
};
|
||||
|
||||
layout(std140, column_major) uniform c_nameless {
|
||||
@ -29,6 +30,7 @@ layout(std140) uniform named {
|
||||
bool memf2;
|
||||
int memf3;
|
||||
vec2 memvec2a;
|
||||
mat2x2 m22[7];
|
||||
} ablock;
|
||||
|
||||
layout(std140) uniform namelessdead {
|
||||
@ -39,6 +41,25 @@ layout(std140) uniform namedDead {
|
||||
int b;
|
||||
} 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 {
|
||||
int a;
|
||||
int dead;
|
||||
@ -55,6 +76,8 @@ uniform uimage2D image_ui2D;
|
||||
uniform sampler2D sampler_2D;
|
||||
uniform sampler2DMSArray sampler_2DMSArray;
|
||||
|
||||
uniform mat2 dm22[10];
|
||||
|
||||
const bool control = true;
|
||||
|
||||
void deadFunction()
|
||||
@ -87,7 +110,7 @@ void main()
|
||||
deadFunction();
|
||||
|
||||
float f;
|
||||
|
||||
int i;
|
||||
if (control) {
|
||||
liveFunction2();
|
||||
f = anonMember3.z;
|
||||
@ -103,6 +126,10 @@ void main()
|
||||
f += float(ablock.memf2);
|
||||
f += ablock.memf3;
|
||||
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
|
||||
f = ufDead3;
|
||||
}
|
||||
|
26
Todo.txt
26
Todo.txt
@ -20,6 +20,7 @@ Link Validation
|
||||
- 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.
|
||||
Intra-stage linking, single shader
|
||||
+ recursion for functions
|
||||
- limits checking:
|
||||
- number of texture image units
|
||||
- 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: read or write to both gl_ClipVertex and gl_ClipDistance
|
||||
- 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 max_vertices...
|
||||
- 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
|
||||
- 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: component aliasing (except desktop vertex shader inputs)
|
||||
Intra-stage linking, multiple shader
|
||||
+ Non ES: type consistency check of uniforms, globals, ins, and outs
|
||||
+ Non ES: value checking of global const initializers
|
||||
+ Non ES: value checking of uniform initializers
|
||||
+ Non ES: location match
|
||||
+ recursion for functions
|
||||
- Non ES: block matching
|
||||
- Non ES: component/binding/index/offset match check
|
||||
- Non ES: compute shader layout(local_size_*) matching
|
||||
- 4.4: overlapping transform/feedback offsets, offset/stride overflow checks, and stride matching
|
||||
Intra-stage linking, multiple shader (Non-ES)
|
||||
+ type consistency check of uniforms, globals, ins, and outs
|
||||
+ value checking of global const initializers
|
||||
+ value checking of uniform initializers
|
||||
+ location match
|
||||
- block matching
|
||||
- component/binding/index/offset match check
|
||||
- compute shader layout(local_size_*) matching
|
||||
+ mixed es/non-es profiles are an error
|
||||
- Non ES: Even the potential for recursion through subroutine uniforms is an error.
|
||||
- Non ES: matching redeclarations of interface blocks
|
||||
- 1.50: match between all explicit input array sizes and input primitive
|
||||
- matching redeclarations of interface blocks
|
||||
- 4.3: early_fragment_tests contradictions
|
||||
- 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
|
||||
|
||||
Shader Functionality to Implement/Finish
|
||||
|
@ -144,7 +144,7 @@ public:
|
||||
if (type.getBasicType() == EbtStruct) {
|
||||
const TTypeList& memberList = *type.getStruct();
|
||||
|
||||
int size = 0;
|
||||
size = 0;
|
||||
int maxAlignment = std140 ? baseAlignmentVec4Std140 : 0;
|
||||
for (size_t m = 0; m < memberList.size(); ++m) {
|
||||
int memberSize;
|
||||
@ -203,7 +203,7 @@ public:
|
||||
// block offset rules.
|
||||
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;
|
||||
const TTypeList& memberList = *blockType.getStruct();
|
||||
@ -219,55 +219,99 @@ public:
|
||||
return offset;
|
||||
}
|
||||
|
||||
// Add a complex uniform reference where blocks/struct/arrays are involved in the access.
|
||||
void addDereferencedUniform(TIntermSymbol* base, TIntermBinary* node)
|
||||
// Calculate the block data size.
|
||||
// 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 blockIndex = -1;
|
||||
bool anonymous = false;
|
||||
|
||||
// See if we need to record the block itself
|
||||
bool block = base->getBasicType() == EbtBlock;
|
||||
if (block) {
|
||||
// TODO: how is an array of blocks handled differently?
|
||||
anonymous = base->getName().compare(0, 6, "__anon") == 0;
|
||||
const TString& blockName = anonymous ? base->getType().getTypeName() : base->getName();
|
||||
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(blockName);
|
||||
if (it == reflection.nameToIndex.end()) {
|
||||
blockIndex = reflection.indexToUniformBlock.size();
|
||||
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
|
||||
blockIndex = it->second;
|
||||
}
|
||||
TString name;
|
||||
|
||||
switch (node->getOp()) {
|
||||
case EOpIndexDirect:
|
||||
// Process the dereference chain, backward, accumulating the pieces on a stack
|
||||
if (block)
|
||||
offset = 0;
|
||||
std::list<TString> derefs;
|
||||
for (TIntermBinary* visitNode = topNode; visitNode; visitNode = visitNode->getLeft()->getAsBinaryNode()) {
|
||||
int index;
|
||||
switch (visitNode->getOp()) {
|
||||
case EOpIndexIndirect:
|
||||
// TODO: reflection: handle array dereferences
|
||||
//name = base->getName();
|
||||
//name.append("[]");
|
||||
// TODO handle indirect references in mid-chain: enumerate all possibilities?
|
||||
derefs.push_back(TString("[") + String(0) + "]");
|
||||
break;
|
||||
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:
|
||||
{
|
||||
if (! anonymous) {
|
||||
name = base->getName();
|
||||
name.append(".");
|
||||
}
|
||||
int structIndex = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
|
||||
index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
|
||||
if (block)
|
||||
offset = getBlockMemberOffset(base->getType(), structIndex);
|
||||
name.append((*base->getType().getStruct())[structIndex].type->getFieldName().c_str());
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (reflection.nameToIndex.find(name) == reflection.nameToIndex.end()) {
|
||||
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.
|
||||
if (! oit->isReflectionGranularity(node->getLeft()->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);
|
||||
if (base && base->getQualifier().storage == EvqUniform)
|
||||
oit->addDereferencedUniform(base, node);
|
||||
@ -660,23 +705,19 @@ bool TReflection::addStage(EShLanguage, const TIntermediate& intermediate)
|
||||
void TReflection::dump()
|
||||
{
|
||||
printf("Uniform reflection:\n");
|
||||
for (size_t i = 0; i < indexToUniform.size(); ++i) {
|
||||
printf("%d: ", (int)i);
|
||||
for (size_t i = 0; i < indexToUniform.size(); ++i)
|
||||
indexToUniform[i].dump();
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Uniform block reflection:\n");
|
||||
for (size_t i = 0; i < indexToUniformBlock.size(); ++i) {
|
||||
printf("%d: ", (int)i);
|
||||
for (size_t i = 0; i < indexToUniformBlock.size(); ++i)
|
||||
indexToUniformBlock[i].dump();
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Live names\n");
|
||||
for (TNameToIndex::const_iterator it = nameToIndex.begin(); it != nameToIndex.end(); ++it)
|
||||
printf("%s: %d\n", it->first.c_str(), it->second);
|
||||
printf("\n");
|
||||
//printf("Live names\n");
|
||||
//for (TNameToIndex::const_iterator it = nameToIndex.begin(); it != nameToIndex.end(); ++it)
|
||||
// printf("%s: %d\n", it->first.c_str(), it->second);
|
||||
//printf("\n");
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
||||
|
@ -56,7 +56,7 @@ class TObjectReflection {
|
||||
public:
|
||||
TObjectReflection(const TString& pName, int pOffset, int pGLDefineType, int pSize, int 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;
|
||||
int offset;
|
||||
int glDefineType;
|
||||
|
@ -332,8 +332,8 @@ public:
|
||||
int getNumLiveUniformVariables(); // can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS)
|
||||
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* getUniformBlockName(int index); // can be used for glGetActiveUniformBlockName()
|
||||
int getUniformBlockSize(int index); // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE)
|
||||
const char* getUniformBlockName(int blockIndex); // can be used for glGetActiveUniformBlockName()
|
||||
int getUniformBlockSize(int blockIndex); // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE)
|
||||
int getUniformIndex(const char* name); // can be used for glGetUniformIndices()
|
||||
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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user