diff --git a/Test/baseResults/hlsl.reflection.vert.out b/Test/baseResults/hlsl.reflection.vert.out index ea8d8690..3403bd35 100644 --- a/Test/baseResults/hlsl.reflection.vert.out +++ b/Test/baseResults/hlsl.reflection.vert.out @@ -15,45 +15,45 @@ foo.n1.a: offset 0, type 1406, size 1, index 3, binding -1, stages 1 foo.n2.b: offset 16, type 1406, size 1, index 3, binding -1, stages 1 foo.n2.c: offset 20, type 1406, size 1, index 3, binding -1, stages 1 foo.n2.d: offset 24, type 1406, size 1, index 3, binding -1, stages 1 -deepA.d2.d1[2].va: offset 376, type 8b50, size 2, index 1, binding -1, stages 1 +deepA.d2.d1[2].va: offset 440, type 8b50, size 2, index 1, binding -1, stages 1 deepB.d2.d1.va: offset 984, type 8b50, size 2, index 1, binding -1, stages 1 deepB.d2.d1[0].va: offset 984, type 8b50, size 2, index 1, binding -1, stages 1 -deepB.d2.d1[1].va: offset 984, type 8b50, size 2, index 1, binding -1, stages 1 -deepB.d2.d1[2].va: offset 984, type 8b50, size 2, index 1, binding -1, stages 1 -deepB.d2.d1[3].va: offset 984, type 8b50, size 2, index 1, binding -1, stages 1 +deepB.d2.d1[1].va: offset 1016, type 8b50, size 2, index 1, binding -1, stages 1 +deepB.d2.d1[2].va: offset 1048, type 8b50, size 2, index 1, binding -1, stages 1 +deepB.d2.d1[3].va: offset 1080, type 8b50, size 2, index 1, binding -1, stages 1 deepC.iv4: offset 1568, type 8b52, size 1, index 1, binding -1, stages 1 -deepC.d2.i: offset 1568, type 1404, size 1, index 1, binding -1, stages 1 -deepC.d2.d1[0].va: offset 1568, type 8b50, size 3, index 1, binding -1, stages 1 -deepC.d2.d1[0].b: offset 1568, type 8b56, size 1, index 1, binding -1, stages 1 -deepC.d2.d1[1].va: offset 1568, type 8b50, size 3, index 1, binding -1, stages 1 -deepC.d2.d1[1].b: offset 1568, type 8b56, size 1, index 1, binding -1, stages 1 -deepC.d2.d1[2].va: offset 1568, type 8b50, size 3, index 1, binding -1, stages 1 -deepC.d2.d1[2].b: offset 1568, type 8b56, size 1, index 1, binding -1, stages 1 -deepC.d2.d1[3].va: offset 1568, type 8b50, size 3, index 1, binding -1, stages 1 -deepC.d2.d1[3].b: offset 1568, type 8b56, size 1, index 1, binding -1, stages 1 -deepC.v3: offset 1568, type 8b54, size 1, index 1, binding -1, stages 1 +deepC.d2.i: offset 1584, type 1404, size 1, index 1, binding -1, stages 1 +deepC.d2.d1[0].va: offset 1592, type 8b50, size 3, index 1, binding -1, stages 1 +deepC.d2.d1[0].b: offset 1616, type 8b56, size 1, index 1, binding -1, stages 1 +deepC.d2.d1[1].va: offset 1624, type 8b50, size 3, index 1, binding -1, stages 1 +deepC.d2.d1[1].b: offset 1648, type 8b56, size 1, index 1, binding -1, stages 1 +deepC.d2.d1[2].va: offset 1656, type 8b50, size 3, index 1, binding -1, stages 1 +deepC.d2.d1[2].b: offset 1680, type 8b56, size 1, index 1, binding -1, stages 1 +deepC.d2.d1[3].va: offset 1688, type 8b50, size 3, index 1, binding -1, stages 1 +deepC.d2.d1[3].b: offset 1712, type 8b56, size 1, index 1, binding -1, stages 1 +deepC.v3: offset 1728, type 8b54, size 1, index 1, binding -1, stages 1 deepD[0].iv4: offset 2480, type 8b52, size 1, index 1, binding -1, stages 1 -deepD[0].d2.i: offset 2480, type 1404, size 1, index 1, binding -1, stages 1 -deepD[0].d2.d1[0].va: offset 2480, type 8b50, size 3, index 1, binding -1, stages 1 -deepD[0].d2.d1[0].b: offset 2480, type 8b56, size 1, index 1, binding -1, stages 1 -deepD[0].d2.d1[1].va: offset 2480, type 8b50, size 3, index 1, binding -1, stages 1 -deepD[0].d2.d1[1].b: offset 2480, type 8b56, size 1, index 1, binding -1, stages 1 -deepD[0].d2.d1[2].va: offset 2480, type 8b50, size 3, index 1, binding -1, stages 1 -deepD[0].d2.d1[2].b: offset 2480, type 8b56, size 1, index 1, binding -1, stages 1 -deepD[0].d2.d1[3].va: offset 2480, type 8b50, size 3, index 1, binding -1, stages 1 -deepD[0].d2.d1[3].b: offset 2480, type 8b56, size 1, index 1, binding -1, stages 1 -deepD[0].v3: offset 2480, type 8b54, size 1, index 1, binding -1, stages 1 -deepD[1].iv4: offset 2480, type 8b52, size 1, index 1, binding -1, stages 1 -deepD[1].d2.i: offset 2480, type 1404, size 1, index 1, binding -1, stages 1 -deepD[1].d2.d1[0].va: offset 2480, type 8b50, size 3, index 1, binding -1, stages 1 -deepD[1].d2.d1[0].b: offset 2480, type 8b56, size 1, index 1, binding -1, stages 1 -deepD[1].d2.d1[1].va: offset 2480, type 8b50, size 3, index 1, binding -1, stages 1 -deepD[1].d2.d1[1].b: offset 2480, type 8b56, size 1, index 1, binding -1, stages 1 -deepD[1].d2.d1[2].va: offset 2480, type 8b50, size 3, index 1, binding -1, stages 1 -deepD[1].d2.d1[2].b: offset 2480, type 8b56, size 1, index 1, binding -1, stages 1 -deepD[1].d2.d1[3].va: offset 2480, type 8b50, size 3, index 1, binding -1, stages 1 -deepD[1].d2.d1[3].b: offset 2480, type 8b56, size 1, index 1, binding -1, stages 1 -deepD[1].v3: offset 2480, type 8b54, size 1, index 1, binding -1, stages 1 +deepD[0].d2.i: offset 2496, type 1404, size 1, index 1, binding -1, stages 1 +deepD[0].d2.d1[0].va: offset 2504, type 8b50, size 3, index 1, binding -1, stages 1 +deepD[0].d2.d1[0].b: offset 2528, type 8b56, size 1, index 1, binding -1, stages 1 +deepD[0].d2.d1[1].va: offset 2536, type 8b50, size 3, index 1, binding -1, stages 1 +deepD[0].d2.d1[1].b: offset 2560, type 8b56, size 1, index 1, binding -1, stages 1 +deepD[0].d2.d1[2].va: offset 2568, type 8b50, size 3, index 1, binding -1, stages 1 +deepD[0].d2.d1[2].b: offset 2592, type 8b56, size 1, index 1, binding -1, stages 1 +deepD[0].d2.d1[3].va: offset 2600, type 8b50, size 3, index 1, binding -1, stages 1 +deepD[0].d2.d1[3].b: offset 2624, type 8b56, size 1, index 1, binding -1, stages 1 +deepD[0].v3: offset 2640, type 8b54, size 1, index 1, binding -1, stages 1 +deepD[1].iv4: offset 2784, type 8b52, size 1, index 1, binding -1, stages 1 +deepD[1].d2.i: offset 2800, type 1404, size 1, index 1, binding -1, stages 1 +deepD[1].d2.d1[0].va: offset 2808, type 8b50, size 3, index 1, binding -1, stages 1 +deepD[1].d2.d1[0].b: offset 2832, type 8b56, size 1, index 1, binding -1, stages 1 +deepD[1].d2.d1[1].va: offset 2840, type 8b50, size 3, index 1, binding -1, stages 1 +deepD[1].d2.d1[1].b: offset 2864, type 8b56, size 1, index 1, binding -1, stages 1 +deepD[1].d2.d1[2].va: offset 2872, type 8b50, size 3, index 1, binding -1, stages 1 +deepD[1].d2.d1[2].b: offset 2896, type 8b56, size 1, index 1, binding -1, stages 1 +deepD[1].d2.d1[3].va: offset 2904, type 8b50, size 3, index 1, binding -1, stages 1 +deepD[1].d2.d1[3].b: offset 2928, type 8b56, size 1, index 1, binding -1, stages 1 +deepD[1].v3: offset 2944, type 8b54, size 1, index 1, binding -1, stages 1 foo1: offset 0, type 1406, size 1, index 4, binding -1, stages 1 foo2: offset 0, type 1406, size 1, index 5, binding -1, stages 1 anonMember1: offset 0, type 8b51, size 1, index 0, binding -1, stages 1 diff --git a/Test/baseResults/reflection.vert.out b/Test/baseResults/reflection.vert.out index 52e16e60..5d135236 100644 --- a/Test/baseResults/reflection.vert.out +++ b/Test/baseResults/reflection.vert.out @@ -74,6 +74,16 @@ buf1.runtimeArray: offset 4, type 1406, size 4, index 12, binding -1, stages 1 buf2.runtimeArray.c: offset 8, type 1406, size 1, index 13, binding -1, stages 1 buf3.runtimeArray: offset 4, type 1406, size 0, index 14, binding -1, stages 1 buf4.runtimeArray.c: offset 8, type 1406, size 1, index 15, binding -1, stages 1 +nested2.a.n1.a: offset 16, type 1406, size 1, index 16, binding -1, stages 1 +nested2.a.n2.b: offset 32, type 1406, size 1, index 16, binding -1, stages 1 +nested2.a.n2.c: offset 36, type 1406, size 1, index 16, binding -1, stages 1 +nested2.a.n2.d: offset 40, type 1406, size 1, index 16, binding -1, stages 1 +nested2.b[0].a: offset 48, type 1406, size 1, index 16, binding -1, stages 1 +nested2.b[1].a: offset 64, type 1406, size 1, index 16, binding -1, stages 1 +nested2.b[2].a: offset 80, type 1406, size 1, index 16, binding -1, stages 1 +nested2.b[3].a: offset 96, type 1406, size 1, index 16, binding -1, stages 1 +nested2.c.a: offset 112, type 1406, size 1, index 16, binding -1, stages 1 +nested2.d.a: offset 144, type 1406, size 1, index 16, binding -1, stages 1 anonMember1: offset 0, type 8b51, size 1, index 0, binding -1, stages 1 uf1: offset -1, type 1406, size 1, index -1, binding -1, stages 1 uf2: offset -1, type 1406, size 1, index -1, binding -1, stages 1 @@ -96,6 +106,7 @@ buf1: offset -1, type ffffffff, size 4, index -1, binding -1, stages 0 buf2: offset -1, type ffffffff, size 4, index -1, binding -1, stages 0 buf3: offset -1, type ffffffff, size 4, index -1, binding -1, stages 0 buf4: offset -1, type ffffffff, size 4, index -1, binding -1, stages 0 +nested2: offset -1, type ffffffff, size 208, index -1, binding -1, stages 0 Vertex attribute reflection: attributeFloat: offset 0, type 1406, size 0, index 0, binding -1, stages 0 diff --git a/Test/reflection.vert b/Test/reflection.vert index 7549f081..9b3b45c9 100644 --- a/Test/reflection.vert +++ b/Test/reflection.vert @@ -60,6 +60,14 @@ layout(std140) uniform nested { N3 foo; } nest; +layout(std140) uniform nested2 { + vec4 padding; // offset 0, size 16 + N3 a; // offset 16, size 32 + N1 b[4]; // offset 48, size 64 + N1 c[2]; // offset 112, size 32 + N1 d[4]; // offset 144, size 64 +} nest2; + struct TS { int a; int dead; @@ -203,4 +211,9 @@ void main() f += buf2i.runtimeArray[3].c; f += buf3i.runtimeArray[gl_InstanceID]; f += buf4i.runtimeArray[gl_InstanceID].c; + + N3 n = nest2.a; + N1 b[4] = nest2.b; + f += nest2.c[1].a; + f += nest2.d[gl_InstanceID].a; } diff --git a/glslang/MachineIndependent/reflection.cpp b/glslang/MachineIndependent/reflection.cpp index 8cfc2acb..0b6ed396 100644 --- a/glslang/MachineIndependent/reflection.cpp +++ b/glslang/MachineIndependent/reflection.cpp @@ -113,6 +113,21 @@ public: } } + // shared calculation by getOffset and getOffsets + void updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize) + { + int dummyStride; + + // modify just the children's view of matrix layout, if there is one for this member + TLayoutMatrix subMatrixLayout = memberType.getQualifier().layoutMatrix; + int memberAlignment = intermediate.getMemberAlignment(memberType, memberSize, dummyStride, + parentType.getQualifier().layoutPacking, + subMatrixLayout != ElmNone + ? subMatrixLayout == ElmRowMajor + : parentType.getQualifier().layoutMatrix == ElmRowMajor); + RoundToPow2(offset, memberAlignment); + } + // Lookup or calculate the offset of a block member, using the recursively // defined block offset rules. int getOffset(const TType& type, int index) @@ -125,18 +140,11 @@ public: if (memberList[index].type->getQualifier().hasOffset()) return memberList[index].type->getQualifier().layoutOffset; - int memberSize; - int dummyStride; + int memberSize = 0; int offset = 0; for (int m = 0; m <= index; ++m) { - // modify just the children's view of matrix layout, if there is one for this member - TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix; - int memberAlignment = intermediate.getMemberAlignment(*memberList[m].type, memberSize, dummyStride, - type.getQualifier().layoutPacking, - subMatrixLayout != ElmNone - ? subMatrixLayout == ElmRowMajor - : type.getQualifier().layoutMatrix == ElmRowMajor); - RoundToPow2(offset, memberAlignment); + updateOffset(type, *memberList[m].type, offset, memberSize); + if (m < index) offset += memberSize; } @@ -144,6 +152,50 @@ public: return offset; } + // Lookup or calculate the offset of all block members at once, using the recursively + // defined block offset rules. + void getOffsets(const TType& type, TVector& offsets) + { + const TTypeList& memberList = *type.getStruct(); + + int memberSize = 0; + int offset = 0; + for (size_t m = 0; m < offsets.size(); ++m) { + // if the user supplied an offset, snap to it now + if (memberList[m].type->getQualifier().hasOffset()) + offset = memberList[m].type->getQualifier().layoutOffset; + + // calculate the offset of the next member and align the current offset to this member + updateOffset(type, *memberList[m].type, offset, memberSize); + + // save the offset of this member + offsets[m] = offset; + + // update for the next member + offset += memberSize; + } + } + + // Calculate the stride of an array type + int getArrayStride(const TType& baseType, const TType& type) + { + int dummySize; + int stride; + + // consider blocks to have 0 stride, so that all offsets are relative to the start of their block + if (type.getBasicType() == EbtBlock) + return 0; + + TLayoutMatrix subMatrixLayout = type.getQualifier().layoutMatrix; + intermediate.getMemberAlignment(type, dummySize, stride, + baseType.getQualifier().layoutPacking, + subMatrixLayout != ElmNone + ? subMatrixLayout == ElmRowMajor + : baseType.getQualifier().layoutMatrix == ElmRowMajor); + + return stride; + } + // Calculate the block data size. // Block arrayness is not taken into account, each element is backed by a separate buffer. int getBlockSize(const TType& blockType) @@ -179,7 +231,9 @@ public: terminalType = &visitNode->getType(); int index; switch (visitNode->getOp()) { - case EOpIndexIndirect: + case EOpIndexIndirect: { + int stride = getArrayStride(baseType, visitNode->getLeft()->getType()); + // Visit all the indices of this array, and for each one add on the remaining dereferencing for (int i = 0; i < std::max(visitNode->getLeft()->getType().getOuterArraySize(), 1); ++i) { TString newBaseName = name; @@ -189,14 +243,22 @@ public: ++nextDeref; TType derefType(*terminalType, 0); blowUpActiveAggregate(derefType, newBaseName, derefs, nextDeref, offset, blockIndex, arraySize); + + if (offset >= 0) + offset += stride; } // it was all completed in the recursive calls above return; + } case EOpIndexDirect: index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst(); - if (baseType.getBasicType() != EbtBlock) + if (baseType.getBasicType() != EbtBlock) { name.append(TString("[") + String(index) + "]"); + + if (offset >= 0) + offset += getArrayStride(baseType, visitNode->getLeft()->getType()) * index; + } break; case EOpIndexDirectStruct: index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst(); @@ -213,23 +275,43 @@ public: // if the terminalType is still too coarse a granularity, this is still an aggregate to expand, expand it... if (! isReflectionGranularity(*terminalType)) { + // the base offset of this node, that children are relative to + int baseOffset = offset; + if (terminalType->isArray()) { // Visit all the indices of this array, and for each one, // fully explode the remaining aggregate to dereference + + int stride = 0; + if (offset >= 0) + stride = getArrayStride(baseType, *terminalType); + for (int i = 0; i < std::max(terminalType->getOuterArraySize(), 1); ++i) { TString newBaseName = name; newBaseName.append(TString("[") + String(i) + "]"); TType derefType(*terminalType, 0); + if (offset >= 0) + offset = baseOffset + stride * i; blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0); } } else { // Visit all members of this aggregate, and for each one, // fully explode the remaining aggregate to dereference const TTypeList& typeList = *terminalType->getStruct(); + + TVector memberOffsets; + + if (baseOffset >= 0) { + memberOffsets.resize(typeList.size()); + getOffsets(*terminalType, memberOffsets); + } + for (int i = 0; i < (int)typeList.size(); ++i) { TString newBaseName = name; newBaseName.append(TString(".") + typeList[i].type->getFieldName()); TType derefType(*terminalType, i); + if (offset >= 0) + offset = baseOffset + memberOffsets[i]; blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0); } }