\r
\r
Uniform reflection:\r
-0: image_ui2D: offset -1, type 9063, arraySize 1, index -1\r
-1: sampler_2D: offset -1, type 8b5e, arraySize 1, index -1\r
-2: sampler_2DMSArray: offset -1, type 910b, arraySize 1, index -1\r
-3: anonMember3: offset 80, type 8b52, arraySize 1, index 0\r
-4: s.a: offset -1, type 1404, arraySize 1, index -1\r
-5: ablock.scalar: offset 12, type 1404, arraySize 1, index 1\r
-6: m23: offset 16, type 8b67, arraySize 1, index 0\r
-7: scalarAfterm23: offset 48, type 1404, arraySize 1, index 0\r
-8: c_m23: offset 16, type 8b67, arraySize 1, index 2\r
-9: c_scalarAfterm23: offset 64, type 1404, arraySize 1, index 2\r
-10: scalarBeforeArray: offset 96, type 1404, arraySize 1, index 0\r
-11: floatArray: offset 112, type 1406, arraySize 5, index 0\r
-12: scalarAfterArray: offset 192, type 1404, arraySize 1, index 0\r
-13: ablock.memvec2: offset 48, type 8b50, arraySize 1, index 1\r
-14: ablock.memf1: offset 56, type 1406, arraySize 1, index 1\r
-15: ablock.memf2: offset 60, type 8b56, arraySize 1, index 1\r
-16: ablock.memf3: offset 64, type 1404, arraySize 1, index 1\r
-17: ablock.memvec2a: offset 72, type 8b50, arraySize 1, index 1\r
-18: anonMember1: offset 0, type 8b51, arraySize 1, index 0\r
-19: uf1: offset -1, type 1406, arraySize 1, index -1\r
-20: uf2: offset -1, type 1406, arraySize 1, index -1\r
-21: ablock.member3: offset 32, type 8b52, arraySize 1, index 1\r
+image_ui2D: offset -1, type 9063, size 1, index -1\r
+sampler_2D: offset -1, type 8b5e, size 1, index -1\r
+sampler_2DMSArray: offset -1, type 910b, size 1, index -1\r
+anonMember3: offset 80, type 8b52, size 1, index 0\r
+s.a: offset -1, type 1404, size 1, index -1\r
+ablock.scalar: offset 12, type 1404, size 1, index 1\r
+m23: offset 16, type 8b67, size 1, index 0\r
+scalarAfterm23: offset 48, type 1404, size 1, index 0\r
+c_m23: offset 16, type 8b67, size 1, index 2\r
+c_scalarAfterm23: offset 64, type 1404, size 1, index 2\r
+scalarBeforeArray: offset 96, type 1404, size 1, index 0\r
+floatArray: offset 112, type 1406, size 5, index 0\r
+scalarAfterArray: offset 192, type 1404, size 1, index 0\r
+ablock.memvec2: offset 48, type 8b50, size 1, index 1\r
+ablock.memf1: offset 56, type 1406, size 1, index 1\r
+ablock.memf2: offset 60, type 8b56, size 1, index 1\r
+ablock.memf3: offset 64, type 1404, size 1, index 1\r
+ablock.memvec2a: offset 72, type 8b50, size 1, index 1\r
+ablock.m22: offset 80, type 8b5a, size 7, index 1\r
+dm22: offset -1, type 8b5a, size 10, index -1\r
+m22: offset 208, type 8b5a, size 9, index 0\r
+nest.foo.n1.a: offset 0, type 1406, size 1, index 3\r
+nest.foo.n2.b: offset 16, type 1406, size 1, index 3\r
+nest.foo.n2.c: offset 20, type 1406, size 1, index 3\r
+nest.foo.n2.d: offset 24, type 1406, size 1, index 3\r
+anonMember1: offset 0, type 8b51, size 1, index 0\r
+uf1: offset -1, type 1406, size 1, index -1\r
+uf2: offset -1, type 1406, size 1, index -1\r
+ablock.member3: offset 32, type 8b52, size 1, index 1\r
\r
Uniform block reflection:\r
-0: nameless: offset -1, type ffffffff, arraySize 1, index -1\r
-1: ablock: offset -1, type ffffffff, arraySize 1, index -1\r
-2: c_nameless: offset -1, type ffffffff, arraySize 1, index -1\r
-\r
-Live names\r
-ablock: 1\r
-ablock.member3: 21\r
-ablock.memf1: 14\r
-ablock.memf2: 15\r
-ablock.memf3: 16\r
-ablock.memvec2: 13\r
-ablock.memvec2a: 17\r
-ablock.scalar: 5\r
-anonMember1: 18\r
-anonMember3: 3\r
-c_m23: 8\r
-c_nameless: 2\r
-c_scalarAfterm23: 9\r
-floatArray: 11\r
-image_ui2D: 0\r
-liveFunction1(uI21;s21;sA21;: -1\r
-liveFunction2(: -1\r
-m23: 6\r
-nameless: 0\r
-s.a: 4\r
-sampler_2D: 1\r
-sampler_2DMSArray: 2\r
-scalarAfterArray: 12\r
-scalarAfterm23: 7\r
-scalarBeforeArray: 10\r
-uf1: 19\r
-uf2: 20\r
+nameless: offset -1, type ffffffff, size 496, index -1\r
+ablock: offset -1, type ffffffff, size 304, index -1\r
+c_nameless: offset -1, type ffffffff, size 112, index -1\r
+nest: offset -1, type ffffffff, size 28, index -1\r
\r
int scalarBeforeArray;\r
float floatArray[5];\r
int scalarAfterArray;\r
+ mat2x2 m22[9];\r
};\r
\r
layout(std140, column_major) uniform c_nameless {\r
bool memf2;\r
int memf3;\r
vec2 memvec2a;\r
+ mat2x2 m22[7];\r
} ablock;\r
\r
layout(std140) uniform namelessdead {\r
int b;\r
} bblock;\r
\r
+struct N1 {\r
+ float a;\r
+};\r
+\r
+struct N2 {\r
+ float b;\r
+ float c;\r
+ float d;\r
+};\r
+\r
+struct N3 {\r
+ N1 n1;\r
+ N2 n2;\r
+};\r
+\r
+layout(std140) uniform nested {\r
+ N3 foo;\r
+} nest;\r
+\r
struct TS {\r
int a;\r
int dead;\r
uniform sampler2D sampler_2D;\r
uniform sampler2DMSArray sampler_2DMSArray;\r
\r
+uniform mat2 dm22[10];\r
+\r
const bool control = true;\r
\r
void deadFunction()\r
deadFunction();\r
\r
float f;\r
-\r
+ int i;\r
if (control) {\r
liveFunction2();\r
f = anonMember3.z;\r
f += float(ablock.memf2);\r
f += ablock.memf3;\r
f += ablock.memvec2a.y;\r
+ f += ablock.m22[i][1][0];\r
+ f += dm22[3][0][1];\r
+ f += m22[2][1].y;\r
+ f += nest.foo.n1.a + nest.foo.n2.b + nest.foo.n2.c + nest.foo.n2.d;\r
} else\r
f = ufDead3;\r
}\r
- 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?)
+ 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
if (type.getBasicType() == EbtStruct) {\r
const TTypeList& memberList = *type.getStruct();\r
\r
- int size = 0;\r
+ size = 0;\r
int maxAlignment = std140 ? baseAlignmentVec4Std140 : 0;\r
for (size_t m = 0; m < memberList.size(); ++m) {\r
int memberSize;\r
// block offset rules.\r
int getBlockMemberOffset(const TType& blockType, int index)\r
{\r
- // TODO: reflection performance: cache these results instead of recomputing them\r
+ // TODO: reflection performance: cache intermediate results instead of recomputing them\r
\r
int offset = 0;\r
const TTypeList& memberList = *blockType.getStruct(); \r
return offset;\r
}\r
\r
+ // Calculate the block data size.\r
+ // Arrayness is not taken into account, each element is backed by a separate buffer.\r
+ int getBlockSize(const TType& blockType)\r
+ {\r
+ int size = 0;\r
+ const TTypeList& memberList = *blockType.getStruct(); \r
+ int memberSize;\r
+ for (size_t m = 0; m < memberList.size(); ++m) {\r
+ int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, blockType.getQualifier().layoutPacking == ElpStd140);\r
+ align(size, memberAlignment);\r
+ size += memberSize;\r
+ }\r
+\r
+ return size;\r
+ }\r
+\r
// Add a complex uniform reference where blocks/struct/arrays are involved in the access.\r
- void addDereferencedUniform(TIntermSymbol* base, TIntermBinary* node)\r
+ // Handles the situation where the left node is at too coarse a granularity to be a single \r
+ // uniform, while the result of the operation at 'node' is at the right granuarity.\r
+ //\r
+ // Note: Simpler things like the following are already handled elsewhere:\r
+ // - a simple non-array, non-struct variable\r
+ // - a variable that's an array of non-struct\r
+ //\r
+ // So, this code is for cases like \r
+ // - a struct/block holding a member (member is array or not)\r
+ // - an array of struct\r
+ // - structs/arrays containing the above\r
+ //\r
+ void addDereferencedUniform(TIntermSymbol* base, TIntermBinary* topNode)\r
{\r
- bool block = base->getBasicType() == EbtBlock;\r
int offset = -1;\r
int blockIndex = -1;\r
bool anonymous = false;\r
+\r
+ // See if we need to record the block itself\r
+ bool block = base->getBasicType() == EbtBlock;\r
if (block) {\r
+ // TODO: how is an array of blocks handled differently?\r
anonymous = base->getName().compare(0, 6, "__anon") == 0;\r
const TString& blockName = anonymous ? base->getType().getTypeName() : base->getName();\r
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(blockName);\r
if (it == reflection.nameToIndex.end()) {\r
blockIndex = reflection.indexToUniformBlock.size();\r
reflection.nameToIndex[blockName] = blockIndex;\r
- reflection.indexToUniformBlock.push_back(TObjectReflection(blockName, -1, -1, 1, -1));\r
+ reflection.indexToUniformBlock.push_back(TObjectReflection(blockName, offset, -1, getBlockSize(base->getType()), -1));\r
} else\r
blockIndex = it->second;\r
}\r
- TString name;\r
\r
- switch (node->getOp()) {\r
- case EOpIndexDirect:\r
- case EOpIndexIndirect:\r
- // TODO: reflection: handle array dereferences\r
- //name = base->getName();\r
- //name.append("[]");\r
- break;\r
- case EOpIndexDirectStruct:\r
- {\r
- if (! anonymous) {\r
- name = base->getName();\r
- name.append(".");\r
+ // Process the dereference chain, backward, accumulating the pieces on a stack\r
+ if (block)\r
+ offset = 0;\r
+ std::list<TString> derefs;\r
+ for (TIntermBinary* visitNode = topNode; visitNode; visitNode = visitNode->getLeft()->getAsBinaryNode()) {\r
+ int index;\r
+ switch (visitNode->getOp()) {\r
+ case EOpIndexIndirect:\r
+ // TODO handle indirect references in mid-chain: enumerate all possibilities?\r
+ derefs.push_back(TString("[") + String(0) + "]");\r
+ break;\r
+ case EOpIndexDirect:\r
+ // TODO: reflection: track the highest used index for an array, to reduce the array's size\r
+ index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();\r
+ derefs.push_back(TString("[") + String(index) + "]");\r
+ break;\r
+ case EOpIndexDirectStruct:\r
+ index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();\r
+ if (block)\r
+ offset += getBlockMemberOffset(visitNode->getLeft()->getType(), index);\r
+ derefs.push_back(TString(""));\r
+ if (visitNode->getLeft()->getAsSymbolNode() != base || ! anonymous)\r
+ derefs.back().append(".");\r
+ derefs.back().append((*visitNode->getLeft()->getType().getStruct())[index].type->getFieldName().c_str());\r
+ break;\r
+ default:\r
+ break;\r
}\r
- int structIndex = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();\r
- if (block)\r
- offset = getBlockMemberOffset(base->getType(), structIndex);\r
- name.append((*base->getType().getStruct())[structIndex].type->getFieldName().c_str());\r
- break;\r
- }\r
- default:\r
- break;\r
}\r
\r
- // TODO: reflection: handle deeper dereference chains than just one dereference\r
+ // Put the dereference chain together, forward (reversing the stack)\r
+ TString name;\r
+ if (! anonymous)\r
+ name = base->getName();\r
+ while (! derefs.empty()) {\r
+ name += derefs.back();\r
+ derefs.pop_back();\r
+ }\r
\r
if (name.size() > 0) {\r
if (reflection.nameToIndex.find(name) == reflection.nameToIndex.end()) {\r
reflection.nameToIndex[name] = reflection.indexToUniform.size(); \r
- reflection.indexToUniform.push_back(TObjectReflection(name, offset, mapToGlType(node->getType()), mapToGlArraySize(node->getType()), blockIndex));\r
+ reflection.indexToUniform.push_back(TObjectReflection(name, offset, mapToGlType(topNode->getType()), mapToGlArraySize(topNode->getType()), blockIndex));\r
}\r
}\r
}\r
// this operation, and pick it up when the left side is visited.\r
if (! oit->isReflectionGranularity(node->getLeft()->getType()) &&\r
oit->isReflectionGranularity(node->getType())) { \r
- // right granularity; see if this really is a uniform-based dereference\r
+ // right granularity; see if this really is a uniform-based dereference,\r
+ // and if so, process it\r
TIntermSymbol* base = oit->findBase(node);\r
if (base && base->getQualifier().storage == EvqUniform)\r
oit->addDereferencedUniform(base, node);\r
void TReflection::dump()\r
{\r
printf("Uniform reflection:\n");\r
- for (size_t i = 0; i < indexToUniform.size(); ++i) {\r
- printf("%d: ", (int)i);\r
+ for (size_t i = 0; i < indexToUniform.size(); ++i)\r
indexToUniform[i].dump();\r
- }\r
printf("\n");\r
\r
printf("Uniform block reflection:\n");\r
- for (size_t i = 0; i < indexToUniformBlock.size(); ++i) {\r
- printf("%d: ", (int)i);\r
+ for (size_t i = 0; i < indexToUniformBlock.size(); ++i)\r
indexToUniformBlock[i].dump();\r
- }\r
printf("\n");\r
\r
- printf("Live names\n");\r
- for (TNameToIndex::const_iterator it = nameToIndex.begin(); it != nameToIndex.end(); ++it)\r
- printf("%s: %d\n", it->first.c_str(), it->second);\r
- printf("\n");\r
+ //printf("Live names\n");\r
+ //for (TNameToIndex::const_iterator it = nameToIndex.begin(); it != nameToIndex.end(); ++it)\r
+ // printf("%s: %d\n", it->first.c_str(), it->second);\r
+ //printf("\n");\r
}\r
\r
} // end namespace glslang\r
public:\r
TObjectReflection(const TString& pName, int pOffset, int pGLDefineType, int pSize, int pIndex) : \r
name(pName), offset(pOffset), glDefineType(pGLDefineType), size(pSize), index(pIndex) { }\r
- void dump() const { printf("%s: offset %d, type %x, arraySize %d, index %d\n", name.c_str(), offset, glDefineType, size, index); }\r
+ void dump() const { printf("%s: offset %d, type %x, size %d, index %d\n", name.c_str(), offset, glDefineType, size, index); }\r
TString name;\r
int offset;\r
int glDefineType;\r
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: