SPV: Fix array strides by explicitly computing them in the getBaseAlignment() algorithm.
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 654fe87..c17a73e 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -1707,25 +1707,25 @@
int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
{
int size;
- int stride = glslangIntermediate->getBaseAlignment(arrayType, size, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor);
- if (arrayType.isMatrix()) {
- // GLSL strides are set to alignments of the matrix flattened to individual rows/cols,
- // but SPV needs an array stride for the whole matrix, not the rows/cols
- if (matrixLayout == glslang::ElmRowMajor)
- stride *= arrayType.getMatrixRows();
- else
- stride *= arrayType.getMatrixCols();
- }
+ int stride;
+ glslangIntermediate->getBaseAlignment(arrayType, size, stride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor);
return stride;
}
-// Given a matrix type, returns the integer stride required for that matrix
+// Given a matrix type, or array (of array) of matrixes type, returns the integer stride required for that matrix
// when used as a member of an interface block
int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
{
+ glslang::TType elementType;
+ elementType.shallowCopy(matrixType);
+ elementType.clearArraySizes();
+
int size;
- return glslangIntermediate->getBaseAlignment(matrixType, size, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor);
+ int stride;
+ glslangIntermediate->getBaseAlignment(elementType, size, stride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor);
+
+ return stride;
}
// Given a member type of a struct, realign the current offset for it, and compute
@@ -1764,7 +1764,8 @@
// but possibly not yet correctly aligned.
int memberSize;
- int memberAlignment = glslangIntermediate->getBaseAlignment(memberType, memberSize, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor);
+ int dummyStride;
+ int memberAlignment = glslangIntermediate->getBaseAlignment(memberType, memberSize, dummyStride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor);
glslang::RoundToPow2(currentOffset, memberAlignment);
nextOffset = currentOffset + memberSize;
}
diff --git a/Test/baseResults/spv.layoutNested.vert.out b/Test/baseResults/spv.layoutNested.vert.out
index 54ed9b7..ac51aab 100644
--- a/Test/baseResults/spv.layoutNested.vert.out
+++ b/Test/baseResults/spv.layoutNested.vert.out
@@ -100,7 +100,7 @@
MemberDecorate 14(S) 1 Offset 16
MemberDecorate 14(S) 1 MatrixStride 16
MemberDecorate 14(S) 2 Offset 144
- Decorate 18 ArrayStride 16
+ Decorate 18 ArrayStride 480
MemberDecorate 19(Block140) 0 Offset 0
MemberDecorate 19(Block140) 1 Offset 16
MemberDecorate 19(Block140) 2 Offset 976
@@ -113,7 +113,7 @@
MemberDecorate 22(S) 1 Offset 16
MemberDecorate 22(S) 1 MatrixStride 8
MemberDecorate 22(S) 2 Offset 80
- Decorate 24 ArrayStride 16
+ Decorate 24 ArrayStride 288
MemberDecorate 25(Block430) 0 Offset 0
MemberDecorate 25(Block430) 1 Offset 16
MemberDecorate 25(Block430) 2 Offset 592
diff --git a/Test/sample.frag.out b/Test/sample.frag.out
index ebc450c..8885dba 100644
--- a/Test/sample.frag.out
+++ b/Test/sample.frag.out
@@ -1,15 +1,15 @@
-#### BEGIN COMPILER 0 INFO LOG ####
-0:? Sequence
-0:37 Function Definition: main( (void)
-0:37 Function Parameters:
-0:39 Sequence
-0:39 move second child to first child (4-component vector of float)
-0:39 'gl_FragColor' (FragColor 4-component vector of float)
-0:39 Construct vec4 (4-component vector of float)
-0:39 'color' (varying in 3-component vector of float)
-0:39 1.000000 (const float)
-
-#### END COMPILER 0 INFO LOG ####
-#### BEGIN LINKER INFO LOG ####
-
-#### END LINKER INFO LOG ####
+#### BEGIN COMPILER 0 INFO LOG ####
+0:? Sequence
+0:37 Function Definition: main( (void)
+0:37 Function Parameters:
+0:39 Sequence
+0:39 move second child to first child (4-component vector of float)
+0:39 'gl_FragColor' (FragColor 4-component vector of float)
+0:39 Construct vec4 (4-component vector of float)
+0:39 'color' (varying in 3-component vector of float)
+0:39 1.000000 (const float)
+
+#### END COMPILER 0 INFO LOG ####
+#### BEGIN LINKER INFO LOG ####
+
+#### END LINKER INFO LOG ####
diff --git a/Test/sample.vert.out b/Test/sample.vert.out
index ebb700d..aef6bb1 100644
--- a/Test/sample.vert.out
+++ b/Test/sample.vert.out
@@ -1,20 +1,20 @@
-#### BEGIN COMPILER 0 INFO LOG ####
-0:? Sequence
-0:37 Function Definition: main( (void)
-0:37 Function Parameters:
-0:39 Sequence
-0:39 move second child to first child (3-component vector of float)
-0:39 'color' (varying out 3-component vector of float)
-0:39 1.000000 (const float)
-0:39 1.000000 (const float)
-0:39 1.000000 (const float)
-0:41 move second child to first child (4-component vector of float)
-0:41 'gl_Position' (Position 4-component vector of float)
-0:41 matrix-times-vector (4-component vector of float)
-0:41 'gl_ModelViewProjectionMatrix' (uniform 4X4 matrix of float)
-0:41 'gl_Vertex' (attribute 4-component vector of float)
-
-#### END COMPILER 0 INFO LOG ####
-#### BEGIN LINKER INFO LOG ####
-
-#### END LINKER INFO LOG ####
+#### BEGIN COMPILER 0 INFO LOG ####
+0:? Sequence
+0:37 Function Definition: main( (void)
+0:37 Function Parameters:
+0:39 Sequence
+0:39 move second child to first child (3-component vector of float)
+0:39 'color' (varying out 3-component vector of float)
+0:39 1.000000 (const float)
+0:39 1.000000 (const float)
+0:39 1.000000 (const float)
+0:41 move second child to first child (4-component vector of float)
+0:41 'gl_Position' (Position 4-component vector of float)
+0:41 matrix-times-vector (4-component vector of float)
+0:41 'gl_ModelViewProjectionMatrix' (uniform 4X4 matrix of float)
+0:41 'gl_Vertex' (attribute 4-component vector of float)
+
+#### END COMPILER 0 INFO LOG ####
+#### BEGIN LINKER INFO LOG ####
+
+#### END LINKER INFO LOG ####
diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h
index df606ff..f169583 100644
--- a/glslang/Include/Types.h
+++ b/glslang/Include/Types.h
@@ -1206,6 +1206,10 @@
arraySizes = new TArraySizes;
*arraySizes = s;
}
+ void clearArraySizes()
+ {
+ arraySizes = 0;
+ }
void addArrayOuterSizes(const TArraySizes& s)
{
if (arraySizes == nullptr)
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 5836926..7d952c6 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -5353,7 +5353,8 @@
// modify just the children's view of matrix layout, if there is one for this member
TLayoutMatrix subMatrixLayout = typeList[member].type->getQualifier().layoutMatrix;
- int memberAlignment = intermediate.getBaseAlignment(*typeList[member].type, memberSize, qualifier.layoutPacking == ElpStd140,
+ int dummyStride;
+ int memberAlignment = intermediate.getBaseAlignment(*typeList[member].type, memberSize, dummyStride, qualifier.layoutPacking == ElpStd140,
subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor : qualifier.layoutMatrix == ElmRowMajor);
if (memberQualifier.hasOffset()) {
// "The specified offset must be a multiple
diff --git a/glslang/MachineIndependent/linkValidate.cpp b/glslang/MachineIndependent/linkValidate.cpp
index 1a543c1..7c96d22 100644
--- a/glslang/MachineIndependent/linkValidate.cpp
+++ b/glslang/MachineIndependent/linkValidate.cpp
@@ -858,8 +858,14 @@
// otherwise it does not, yielding std430 rules.
//
// The size is returned in the 'size' parameter
+//
+// The stride is only non-0 for arrays or matrices, and is the stride of the
+// top-level object nested within the type. E.g., for an array of matrices,
+// it is the distances needed between matrices, despite the rules saying the
+// stride comes from the flattening down to vectors.
+//
// Return value is the alignment of the type.
-int TIntermediate::getBaseAlignment(const TType& type, int& size, bool std140, bool rowMajor)
+int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, bool std140, bool rowMajor)
{
int alignment;
@@ -916,16 +922,23 @@
//
// 10. If the member is an array of S structures, the S elements of the array are laid
// out in order, according to rule (9).
+ //
+ // Assuming, for rule 10: The stride is the same as the size of an element.
- // rules 4, 6, and 8
+ stride = 0;
+ int dummyStride;
+
+ // rules 4, 6, 8, and 10
if (type.isArray()) {
// TODO: perf: this might be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness
TType derefType(type, 0);
- alignment = getBaseAlignment(derefType, size, std140, rowMajor);
+ alignment = getBaseAlignment(derefType, size, dummyStride, std140, rowMajor);
if (std140)
alignment = std::max(baseAlignmentVec4Std140, alignment);
RoundToPow2(size, alignment);
- size *= type.getOuterArraySize();
+ stride = size; // uses full matrix size for stride of an array of matrices (not quite what rule 6/8, but what's expected)
+ // uses the assumption for rule 10 in the comment above
+ size = stride * type.getOuterArraySize();
return alignment;
}
@@ -939,7 +952,7 @@
int memberSize;
// 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 = getBaseAlignment(*memberList[m].type, memberSize, std140,
+ int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, dummyStride, std140,
(subMatrixLayout != ElmNone) ? (subMatrixLayout == ElmRowMajor) : rowMajor);
maxAlignment = std::max(maxAlignment, memberAlignment);
RoundToPow2(size, memberAlignment);
@@ -971,14 +984,15 @@
// rule 5: deref to row, not to column, meaning the size of vector is num columns instead of num rows
TType derefType(type, 0, type.getQualifier().layoutMatrix == ElmRowMajor);
- alignment = getBaseAlignment(derefType, size, std140, rowMajor);
+ alignment = getBaseAlignment(derefType, size, dummyStride, std140, rowMajor);
if (std140)
alignment = std::max(baseAlignmentVec4Std140, alignment);
RoundToPow2(size, alignment);
+ stride = size; // use intra-matrix stride for stride of a just a matrix
if (rowMajor)
- size *= type.getMatrixRows();
+ size = stride * type.getMatrixRows();
else
- size *= type.getMatrixCols();
+ size = stride * type.getMatrixCols();
return alignment;
}
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index 9933594..043d31f 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -305,7 +305,7 @@
}
int addXfbBufferOffset(const TType&);
unsigned int computeTypeXfbSize(const TType&, bool& containsDouble) const;
- static int getBaseAlignment(const TType&, int& size, bool std140, bool rowMajor);
+ static int getBaseAlignment(const TType&, int& size, int& stride, bool std140, bool rowMajor);
protected:
void error(TInfoSink& infoSink, const char*);
diff --git a/glslang/MachineIndependent/reflection.cpp b/glslang/MachineIndependent/reflection.cpp
index 5a1479a..9ef6d02 100644
--- a/glslang/MachineIndependent/reflection.cpp
+++ b/glslang/MachineIndependent/reflection.cpp
@@ -121,11 +121,12 @@
return memberList[index].type->getQualifier().layoutOffset;
int memberSize;
+ int dummyStride;
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.getBaseAlignment(*memberList[m].type, memberSize, type.getQualifier().layoutPacking == ElpStd140,
+ int memberAlignment = intermediate.getBaseAlignment(*memberList[m].type, memberSize, dummyStride, type.getQualifier().layoutPacking == ElpStd140,
subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor : type.getQualifier().layoutMatrix == ElmRowMajor);
RoundToPow2(offset, memberAlignment);
if (m < index)
@@ -144,7 +145,8 @@
int lastOffset = getOffset(blockType, lastIndex);
int lastMemberSize;
- intermediate.getBaseAlignment(*memberList[lastIndex].type, lastMemberSize, blockType.getQualifier().layoutPacking == ElpStd140,
+ int dummyStride;
+ intermediate.getBaseAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride, blockType.getQualifier().layoutPacking == ElpStd140,
blockType.getQualifier().layoutMatrix == ElmRowMajor);
return lastOffset + lastMemberSize;