From: John Kessenich Date: Fri, 15 Nov 2013 01:34:27 +0000 (+0000) Subject: Reflection: X-Git-Tag: upstream/0.1~832 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=12f9221e4425a0dc0f564119511862d89c62616e;p=platform%2Fupstream%2Fglslang.git 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 --- diff --git a/Test/baseResults/reflection.vert.out b/Test/baseResults/reflection.vert.out index dd72f3b..f5591ce 100644 --- a/Test/baseResults/reflection.vert.out +++ b/Test/baseResults/reflection.vert.out @@ -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 diff --git a/Test/reflection.vert b/Test/reflection.vert index 14f68ad..cd2625f 100644 --- a/Test/reflection.vert +++ b/Test/reflection.vert @@ -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; } diff --git a/Todo.txt b/Todo.txt index 7aff9fe..3438316 100644 --- a/Todo.txt +++ b/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 diff --git a/glslang/MachineIndependent/reflection.cpp b/glslang/MachineIndependent/reflection.cpp index 4c902f5..27cd53d 100644 --- a/glslang/MachineIndependent/reflection.cpp +++ b/glslang/MachineIndependent/reflection.cpp @@ -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 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 diff --git a/glslang/MachineIndependent/reflection.h b/glslang/MachineIndependent/reflection.h index 1b9a92a..430524f 100644 --- a/glslang/MachineIndependent/reflection.h +++ b/glslang/MachineIndependent/reflection.h @@ -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; diff --git a/glslang/Public/ShaderLang.h b/glslang/Public/ShaderLang.h index 9202647..d452614 100644 --- a/glslang/Public/ShaderLang.h +++ b/glslang/Public/ShaderLang.h @@ -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: