diff --git a/Test/baseResults/reflection.vert.out b/Test/baseResults/reflection.vert.out index dd02aead..5ae64c90 100644 --- a/Test/baseResults/reflection.vert.out +++ b/Test/baseResults/reflection.vert.out @@ -8,26 +8,54 @@ Linked vertex stage: Uniform reflection: -0:anonMember3: offset 32, type 35666, arraySize 1, index 0 -1:s.a: offset -1, type 35666, arraySize 1, index -1 -2:anonMember1: offset 0, type 35666, arraySize 1, index 0 -3:uf1: offset -1, type 35666, arraySize 1, index -1 -4:uf2: offset -1, type 35666, arraySize 1, index -1 -5:ablock.member3: offset 32, type 35666, arraySize 1, index 1 +0: anonMember3: offset 80, type 35666, arraySize 1, index 0 +1: s.a: offset -1, type 35666, arraySize 1, index -1 +2: ablock.scalar: offset 12, type 35666, arraySize 1, index 1 +3: m23: offset 16, type 35666, arraySize 1, index 0 +4: scalarAfterm23: offset 48, type 35666, arraySize 1, index 0 +5: c_m23: offset 16, type 35666, arraySize 1, index 2 +6: c_scalarAfterm23: offset 64, type 35666, arraySize 1, index 2 +7: scalarBeforeArray: offset 96, type 35666, arraySize 1, index 0 +8: floatArray: offset 112, type 35666, arraySize 5, index 0 +9: scalarAfterArray: offset 192, type 35666, arraySize 1, index 0 +10: ablock.memvec2: offset 48, type 35666, arraySize 1, index 1 +11: ablock.memf1: offset 56, type 35666, arraySize 1, index 1 +12: ablock.memf2: offset 60, type 35666, arraySize 1, index 1 +13: ablock.memf3: offset 64, type 35666, arraySize 1, index 1 +14: ablock.memvec2a: offset 72, type 35666, arraySize 1, index 1 +15: anonMember1: offset 0, type 35666, arraySize 1, index 0 +16: uf1: offset -1, type 35666, arraySize 1, index -1 +17: uf2: offset -1, type 35666, arraySize 1, index -1 +18: ablock.member3: offset 32, type 35666, arraySize 1, index 1 Uniform block reflection: 0: nameless: offset -1, type -1, arraySize 1, index -1 1: ablock: offset -1, type -1, arraySize 1, index -1 +2: c_nameless: offset -1, type -1, arraySize 1, index -1 Live names ablock: 1 -ablock.member3: 5 -anonMember1: 2 +ablock.member3: 18 +ablock.memf1: 11 +ablock.memf2: 12 +ablock.memf3: 13 +ablock.memvec2: 10 +ablock.memvec2a: 14 +ablock.scalar: 2 +anonMember1: 15 anonMember3: 0 +c_m23: 5 +c_nameless: 2 +c_scalarAfterm23: 6 +floatArray: 8 liveFunction1(: -1 liveFunction2(: -1 +m23: 3 nameless: 0 s.a: 1 -uf1: 3 -uf2: 4 +scalarAfterArray: 9 +scalarAfterm23: 4 +scalarBeforeArray: 7 +uf1: 16 +uf2: 17 diff --git a/Test/reflection.vert b/Test/reflection.vert index 79a6ef84..e8544d97 100644 --- a/Test/reflection.vert +++ b/Test/reflection.vert @@ -1,22 +1,41 @@ #version 440 core -uniform nameless { +layout(std140, row_major) uniform nameless { vec3 anonMember1; + mat3x2 m23; + int scalarAfterm23; vec4 anonDeadMember2; vec4 anonMember3; + int scalarBeforeArray; + float floatArray[5]; + int scalarAfterArray; }; -uniform named { +layout(std140, column_major) uniform c_nameless { + vec3 c_anonMember1; + mat3x2 c_m23; + int c_scalarAfterm23; + vec4 c_anonDeadMember2; + vec4 c_anonMember3; +}; + +layout(std140) uniform named { vec3 deadMember1; + int scalar; vec4 member2; vec4 member3; + vec2 memvec2; + float memf1; + bool memf2; + int memf3; + vec2 memvec2a; } ablock; -uniform namelessdead { +layout(std140) uniform namelessdead { int a; }; -uniform namedDead { +layout(std140) uniform namedDead { int b; } bblock; @@ -68,6 +87,17 @@ void main() liveFunction2(); f = anonMember3.z; f = s.a; + f = ablock.scalar; + f = m23[1].y + scalarAfterm23; + f = c_m23[1].y + c_scalarAfterm23; + f += scalarBeforeArray; + f += floatArray[2]; + f += scalarAfterArray; + f += ablock.memvec2.x; + f += ablock.memf1; + f += float(ablock.memf2); + f += ablock.memf3; + f += ablock.memvec2a.y; } else f = ufDead3; } diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index 1a74a4ec..50508620 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -490,6 +490,8 @@ typedef std::map::const_iterator TStructureMapIterator; class TType { public: POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) + + // for "empty" type (no args) or simple scalar/vector/matrix explicit TType(TBasicType t = EbtVoid, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0) : basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(0), structure(0), structureSize(0), fieldName(0), typeName(0) @@ -498,6 +500,7 @@ public: qualifier.clear(); qualifier.storage = q; } + // for explicit precision qualifier TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0) : basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(0), structure(0), structureSize(0), fieldName(0), typeName(0) @@ -508,7 +511,8 @@ public: qualifier.precision = p; assert(p >= 0 && p <= EpqHigh); } - explicit TType(const TPublicType &p) : + // for turning a TPublicType into a TType + explicit TType(const TPublicType& p) : basicType(p.basicType), vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), arraySizes(p.arraySizes), structure(0), structureSize(0), fieldName(0), typeName(0) { @@ -522,6 +526,23 @@ public: typeName = NewPoolTString(p.userDef->getTypeName().c_str()); } } + // to efficiently make a dereferenced type + // without ever duplicating the outer structure that will be thrown away + // and using only shallow copy + TType(const TType& type, int derefIndex) + { + if (! type.isArray() && (type.basicType == EbtStruct || type.basicType == EbtBlock)) { + // do a structure dereference + const TTypeList& memberList = *type.getStruct(); + shallowCopy(*memberList[derefIndex].type); + return; + } else { + // do an array/vector/matrix dereference + shallowCopy(type); + dereference(); + } + } + // for making structures, ... TType(TTypeList* userDef, const TString& n) : basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), arraySizes(0), structure(userDef), fieldName(0) diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 765c8858..89619b3d 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -500,13 +500,11 @@ TIntermTyped* TParseContext::handleBracketDereference(TSourceLoc loc, TIntermTyp result = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), loc); } else { // Insert valid dereferenced result - TType newType; - newType.shallowCopy(base->getType()); + TType newType(base->getType(), 0); // dereferenced type if (base->getType().getQualifier().storage == EvqConst && index->getQualifier().storage == EvqConst) newType.getQualifier().storage = EvqConst; else newType.getQualifier().storage = EvqTemporary; - newType.dereference(); result->setType(newType); if (anyIndexLimits) @@ -3024,9 +3022,7 @@ TIntermTyped* TParseContext::convertInitializerList(TSourceLoc loc, const TType& arrayType.shallowCopy(type); arrayType.setArraySizes(type); arrayType.changeArraySize(initList->getSequence().size()); - TType elementType; - elementType.shallowCopy(arrayType); // TODO: 4.3 simplification: arrays of arrays: combine this with deref. - elementType.dereference(); + TType elementType(arrayType, 0); // dereferenced type for (size_t i = 0; i < initList->getSequence().size(); ++i) { initList->getSequence()[i] = convertInitializerList(loc, elementType, initList->getSequence()[i]->getAsTyped()); if (initList->getSequence()[i] == 0) @@ -3049,9 +3045,7 @@ TIntermTyped* TParseContext::convertInitializerList(TSourceLoc loc, const TType& error(loc, "wrong number of matrix columns:", "initializer list", type.getCompleteString().c_str()); return 0; } - TType vectorType; - vectorType.shallowCopy(type); // TODO: 4.3 simplification: arrays of arrays: combine this with deref. - vectorType.dereference(); + TType vectorType(type, 0); // dereferenced type for (int i = 0; i < type.getMatrixCols(); ++i) { initList->getSequence()[i] = convertInitializerList(loc, vectorType, initList->getSequence()[i]->getAsTyped()); if (initList->getSequence()[i] == 0) @@ -3088,10 +3082,11 @@ TIntermTyped* TParseContext::addConstructor(TSourceLoc loc, TIntermNode* node, c if (op == EOpConstructStruct) memberTypes = type.getStruct()->begin(); - TType elementType; - elementType.shallowCopy(type); + const TType* elementType; if (type.isArray()) - elementType.dereference(); // TODO: 4.3 simplification: arrays of arrays: combine this with deref. + elementType = &TType(type, 0); // dereferenced type + else + elementType = &type; bool singleArg; if (aggrNode) { @@ -3107,7 +3102,7 @@ TIntermTyped* TParseContext::addConstructor(TSourceLoc loc, TIntermNode* node, c // If structure constructor or array constructor is being called // for only one parameter inside the structure, we need to call constructStruct function once. if (type.isArray()) - newNode = constructStruct(node, elementType, 1, node->getLoc()); + newNode = constructStruct(node, *elementType, 1, node->getLoc()); else if (op == EOpConstructStruct) newNode = constructStruct(node, *(*memberTypes).type, 1, node->getLoc()); else @@ -3135,7 +3130,7 @@ TIntermTyped* TParseContext::addConstructor(TSourceLoc loc, TIntermNode* node, c for (TIntermSequence::iterator p = sequenceVector.begin(); p != sequenceVector.end(); p++, paramCount++) { if (type.isArray()) - newNode = constructStruct(*p, elementType, paramCount+1, node->getLoc()); + newNode = constructStruct(*p, *elementType, paramCount+1, node->getLoc()); else if (op == EOpConstructStruct) newNode = constructStruct(*p, *(memberTypes[paramCount]).type, paramCount+1, node->getLoc()); else @@ -3724,9 +3719,7 @@ TIntermTyped* TParseContext::addConstMatrixNode(TSourceLoc loc, int index, TInte // TIntermTyped* TParseContext::addConstArrayNode(TSourceLoc loc, int index, TIntermTyped* node) { - TType arrayElementType; - arrayElementType.shallowCopy(node->getType()); // TODO: 4.3 simplification: arrays of arrays: combine this with deref. - arrayElementType.dereference(); + TType arrayElementType(node->getType(), 0); // dereferenced type if (index >= node->getType().getArraySize() || index < 0) { error(loc, "", "[", "array index '%d' out of range", index); diff --git a/glslang/MachineIndependent/reflection.cpp b/glslang/MachineIndependent/reflection.cpp index b27118cc..f7c25d0d 100644 --- a/glslang/MachineIndependent/reflection.cpp +++ b/glslang/MachineIndependent/reflection.cpp @@ -65,7 +65,7 @@ namespace glslang { // // The traverser: mostly pass through, except // - processing function-call nodes to push live functions onto the stack of functions to process -// - processing binary nodes to see if they are dereferences of aggregates to track +// - processing binary nodes to see if they are dereferences of an aggregates to track // - processing symbol nodes to see if they are non-aggregate objects to track // - processing selection nodes to trim semantically dead code // @@ -87,7 +87,7 @@ public: } } - // Add a simple uniform variable reference to the uniform database, no derefence involved. + // Add a simple uniform variable reference to the uniform database, no dereference involved. void addUniform(const TIntermSymbol& symbol) { if (reflection.nameToIndex.find(symbol.getName()) == reflection.nameToIndex.end()) { @@ -98,7 +98,126 @@ public: } } - // Add a complex uniform reference where blocks/struct/arrays are involved in tha access. + static const int baseAlignmentVec4Std140 = 16; + + // align a value: if 'value' is not aligned to 'alignment', move it up to a multiple of alignment + void align(int& value, int alignment) + { + int error = value % alignment; + if (error) + value += alignment - error; + } + + // return the size and alignment of a scalar + int getBaseAlignmentScalar(const TType& type, int& size) + { + switch (type.getBasicType()) { + case EbtDouble: size = 8; return 8; + default: size = 4; return 4; + } + } + + // Implement base-alignment and size rules from section 7.6.2.2 Standard Uniform Block Layout + // Operates recursively. + // If std140 is true, it does the rounding up to vec4 size required by std140, + // otherwise it does not, yielding std430 rules. + // + // Returns the size of the type. + int getBaseAlignment(const TType& type, int& size, bool std140) + { + int alignment; + + // rules 4, 6, and 8 + if (type.isArray()) { + TType derefType(type, 0); + alignment = getBaseAlignment(derefType, size, std140); + if (std140) + alignment = std::max(baseAlignmentVec4Std140, alignment); + align(size, alignment); + size *= type.getArraySize(); + return alignment; + } + + // rule 9 + if (type.getBasicType() == EbtStruct) { + const TTypeList& memberList = *type.getStruct(); + + int size = 0; + int maxAlignment = std140 ? baseAlignmentVec4Std140 : 0; + for (size_t m = 0; m < memberList.size(); ++m) { + int memberSize; + int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, std140); + maxAlignment = std::max(maxAlignment, memberAlignment); + align(size, memberAlignment); + size += memberSize; + } + + return maxAlignment; + } + + // rule 1 + if (type.isScalar()) + return getBaseAlignmentScalar(type, size); + + // rules 2 and 3 + if (type.isVector()) { + int scalarAlign = getBaseAlignmentScalar(type, size); + switch (type.getVectorSize()) { + case 2: + size *= 2; + return 2 * scalarAlign; + default: + size *= type.getVectorSize(); + return 4 * scalarAlign; + } + } + + // rules 5 and 7 + if (type.isMatrix()) { + TType derefType(type, 0); + + // rule 5: deref to row, not to column, meaning the size of vector is num columns instead of num rows + if (type.getQualifier().layoutMatrix == ElmRowMajor) + derefType.setElementType(derefType.getBasicType(), type.getMatrixCols(), 0, 0, 0); + + alignment = getBaseAlignment(derefType, size, std140); + if (std140) + alignment = std::max(baseAlignmentVec4Std140, alignment); + align(size, alignment); + if (type.getQualifier().layoutMatrix == ElmRowMajor) + size *= type.getMatrixRows(); + else + size *= type.getMatrixCols(); + + return alignment; + } + + assert(0); // all cases should be covered above + size = baseAlignmentVec4Std140; + return baseAlignmentVec4Std140; + } + + // Calculate the offset of a block member, using the recursively defined + // block offset rules. + int getBlockMemberOffset(const TType& blockType, int index) + { + // TODO: reflection performance: cache these results instead of recomputing them + + int offset = 0; + const TTypeList& memberList = *blockType.getStruct(); + int memberSize; + for (int m = 0; m < index; ++m) { + int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, blockType.getQualifier().layoutPacking == ElpStd140); + align(offset, memberAlignment); + offset += memberSize; + } + int memberAlignment = getBaseAlignment(*memberList[index].type, memberSize, blockType.getQualifier().layoutPacking == ElpStd140); + align(offset, memberAlignment); + + return offset; + } + + // Add a complex uniform reference where blocks/struct/arrays are involved in the access. void addDereferencedUniform(TIntermSymbol* base, TIntermBinary* node) { bool block = base->getBasicType() == EbtBlock; @@ -133,7 +252,7 @@ public: } int structIndex = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst(); if (block) - offset = structIndex * 16; // TODO: reflection: compute std140 offsets + offset = getBlockMemberOffset(base->getType(), structIndex); name.append((*base->getType().getStruct())[structIndex].type->getFieldName().c_str()); break; } @@ -312,7 +431,7 @@ void TReflection::dump() { printf("Uniform reflection:\n"); for (size_t i = 0; i < indexToUniform.size(); ++i) { - printf("%d:", (int)i); + printf("%d: ", (int)i); indexToUniform[i].dump(); } printf("\n");