Skip to content
Snippets Groups Projects
Commit 12f9221e authored by John Kessenich's avatar John Kessenich
Browse files

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
parent c0827e45
No related branches found
No related tags found
No related merge requests found
......@@ -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;
}
......@@ -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;
}
// 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.
void addDereferencedUniform(TIntermSymbol* base, TIntermBinary* node)
// 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:
case EOpIndexIndirect:
// TODO: reflection: handle array dereferences
//name = base->getName();
//name.append("[]");
break;
case EOpIndexDirectStruct:
{
if (! anonymous) {
name = base->getName();
name.append(".");
// 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 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:
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 (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;
......
......@@ -328,17 +328,17 @@ public:
const char* getInfoDebugLog();
// Reflection Interface
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 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)
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)
int getUniformBufferOffset(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET)
int getUniformArraySize(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE)
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 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 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)
int getUniformBufferOffset(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET)
int getUniformArraySize(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE)
void dumpReflection();
protected:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment