From f85e806e44799960eef036c1f7ca2007af61d9c5 Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Sat, 19 Dec 2015 13:57:10 -0700 Subject: [PATCH] SPV: Nested layouts: Recursively send around the top-level std140 or std430 packing. This also distinguishes between the same struct included in multiple parent packings. --- SPIRV/GlslangToSpv.cpp | 78 +++++++----- Test/baseResults/spv.layoutNested.vert.out | 138 +++++++++++++++++++++ Test/spv.layoutNested.vert | 31 +++++ Test/test-spirv-list | 1 + glslang/Include/revision.h | 2 +- 5 files changed, 216 insertions(+), 34 deletions(-) create mode 100644 Test/baseResults/spv.layoutNested.vert.out create mode 100644 Test/spv.layoutNested.vert diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index 27a9bc2fb..ca6a577a7 100755 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -91,11 +91,11 @@ protected: spv::Id createSpvVariable(const glslang::TIntermSymbol*); spv::Id getSampledType(const glslang::TSampler&); spv::Id convertGlslangToSpvType(const glslang::TType& type); - spv::Id convertGlslangToSpvType(const glslang::TType& type, bool explicitLayout); - bool requiresExplicitLayout(const glslang::TType& type) const; - int getArrayStride(const glslang::TType& arrayType); - int getMatrixStride(const glslang::TType& matrixType); - void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset); + spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking); + glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const; + int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking); + int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking); + void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset, glslang::TLayoutPacking); bool isShaderEntrypoint(const glslang::TIntermAggregate* node); void makeFunctions(const glslang::TIntermSequence&); @@ -140,7 +140,7 @@ protected: std::unordered_map symbolValues; std::unordered_set constReadOnlyParameters; // set of formal function parameters that have glslang qualifier constReadOnly, so we know they are not local function "const" that are write-once std::unordered_map functionMap; - std::unordered_map structMap; + std::unordered_map structMap[glslang::ElpStd430 + 1]; std::unordered_map > memberRemapper; // for mapping glslang block indices to spv indices (e.g., due to hidden members) std::stack breakForLoop; // false means break for switch std::stack loopTerminal; // code from the last part of a for loop: for(...; ...; terminal), needed for e.g., continue }; @@ -1455,12 +1455,12 @@ spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler) // recursive version of this function. spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type) { - return convertGlslangToSpvType(type, requiresExplicitLayout(type)); + return convertGlslangToSpvType(type, getExplicitLayout(type)); } // Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id. // explicitLayout can be kept the same throughout the heirarchical recursive walk. -spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, bool explicitLayout) +spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking explicitLayout) { spv::Id spvType = 0; @@ -1505,7 +1505,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty // If we've seen this struct type, return it const glslang::TTypeList* glslangStruct = type.getStruct(); std::vector structFields; - spvType = structMap[glslangStruct]; + spvType = structMap[explicitLayout][glslangStruct]; if (spvType) break; @@ -1530,7 +1530,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty // Make the SPIR-V type spvType = builder.makeStructType(structFields, type.getTypeName().c_str()); - structMap[glslangStruct] = spvType; + structMap[explicitLayout][glslangStruct] = spvType; // Name and decorate the non-hidden members int offset = -1; @@ -1552,18 +1552,17 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangType.getQualifier().layoutComponent); if (glslangType.getQualifier().hasXfbOffset()) builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangType.getQualifier().layoutXfbOffset); - else if (explicitLayout) { + else if (explicitLayout != glslang::ElpNone) { // figure out what to do with offset, which is accumulating int nextOffset; - updateMemberOffset(type, glslangType, offset, nextOffset); + updateMemberOffset(type, glslangType, offset, nextOffset, explicitLayout); if (offset >= 0) builder.addMemberDecoration(spvType, member, spv::DecorationOffset, offset); offset = nextOffset; } - if (glslangType.isMatrix() && explicitLayout) { - builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride, getMatrixStride(glslangType)); - } + if (glslangType.isMatrix() && explicitLayout != glslang::ElpNone) + builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride, getMatrixStride(glslangType, explicitLayout)); // built-in variable decorations spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangType.getQualifier().builtIn); @@ -1621,26 +1620,41 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty // except for the very top if it is an array of blocks; that array is // not laid out in memory in a way needing a stride. if (explicitLayout && type.getBasicType() != glslang::EbtBlock) - builder.addDecoration(spvType, spv::DecorationArrayStride, getArrayStride(type)); + builder.addDecoration(spvType, spv::DecorationArrayStride, getArrayStride(type, explicitLayout)); } return spvType; } -bool TGlslangToSpvTraverser::requiresExplicitLayout(const glslang::TType& type) const +// Decide whether or not this type should be +// decorated with offsets and strides, and if so +// whether std140 or std430 rules should be applied. +glslang::TLayoutPacking TGlslangToSpvTraverser::getExplicitLayout(const glslang::TType& type) const { - return type.getBasicType() == glslang::EbtBlock && - type.getQualifier().layoutPacking != glslang::ElpShared && - type.getQualifier().layoutPacking != glslang::ElpPacked && - (type.getQualifier().storage == glslang::EvqUniform || - type.getQualifier().storage == glslang::EvqBuffer); + // has to be a block + if (type.getBasicType() != glslang::EbtBlock) + return glslang::ElpNone; + + // has to be a uniform or buffer block + if (type.getQualifier().storage != glslang::EvqUniform && + type.getQualifier().storage != glslang::EvqBuffer) + return glslang::ElpNone; + + // return the layout to use + switch (type.getQualifier().layoutPacking) { + case glslang::ElpStd140: + case glslang::ElpStd430: + return type.getQualifier().layoutPacking; + default: + return glslang::ElpNone; + } } // Given an array type, returns the integer stride required for that array -int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType) +int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking explicitLayout) { int size; - int stride = glslangIntermediate->getBaseAlignment(arrayType, size, arrayType.getQualifier().layoutPacking == glslang::ElpStd140); + int stride = glslangIntermediate->getBaseAlignment(arrayType, size, explicitLayout == glslang::ElpStd140); 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 @@ -1655,10 +1669,10 @@ int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType) // Given a matrix 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) +int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking explicitLayout) { int size; - return glslangIntermediate->getBaseAlignment(matrixType, size, matrixType.getQualifier().layoutPacking == glslang::ElpStd140); + return glslangIntermediate->getBaseAlignment(matrixType, size, explicitLayout == glslang::ElpStd140); } // Given a member type of a struct, realign the current offset for it, and compute @@ -1667,14 +1681,12 @@ int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType) // 'currentOffset' should be passed in already initialized, ready to modify, and reflecting // the migration of data from nextOffset -> currentOffset. It should be -1 on the first call. // -1 means a non-forced member offset (no decoration needed). -void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset) +void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset, + glslang::TLayoutPacking explicitLayout) { // this will get a positive value when deemed necessary nextOffset = -1; - bool forceOffset = structType.getQualifier().layoutPacking == glslang::ElpStd140 || - structType.getQualifier().layoutPacking == glslang::ElpStd430; - // override anything in currentOffset with user-set offset if (memberType.getQualifier().hasOffset()) currentOffset = memberType.getQualifier().layoutOffset; @@ -1684,14 +1696,14 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType // once cross-compilation unit GLSL validation is done, as the original user // settings are needed in layoutOffset, and then the following will come into play. - if (! forceOffset) { + if (explicitLayout == glslang::ElpNone) { if (! memberType.getQualifier().hasOffset()) currentOffset = -1; return; } - // Getting this far means we are forcing offsets + // Getting this far means we need explicit offsets if (currentOffset < 0) currentOffset = 0; @@ -1699,7 +1711,7 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType // but possibly not yet correctly aligned. int memberSize; - int memberAlignment = glslangIntermediate->getBaseAlignment(memberType, memberSize, memberType.getQualifier().layoutPacking == glslang::ElpStd140); + int memberAlignment = glslangIntermediate->getBaseAlignment(memberType, memberSize, explicitLayout == glslang::ElpStd140); glslang::RoundToPow2(currentOffset, memberAlignment); nextOffset = currentOffset + memberSize; } diff --git a/Test/baseResults/spv.layoutNested.vert.out b/Test/baseResults/spv.layoutNested.vert.out new file mode 100644 index 000000000..007c02971 --- /dev/null +++ b/Test/baseResults/spv.layoutNested.vert.out @@ -0,0 +1,138 @@ +spv.layoutNested.vert +Warning, version 450 is not yet complete; most version-specific features are present, but some are missing. + + +Linked vertex stage: + + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 54 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Vertex 4 "main" 38 52 53 + Source GLSL 450 + Name 4 "main" + Name 13 "S" + MemberName 13(S) 0 "a" + MemberName 13(S) 1 "b" + MemberName 13(S) 2 "c" + Name 15 "s" + Name 18 "S" + MemberName 18(S) 0 "a" + MemberName 18(S) 1 "b" + MemberName 18(S) 2 "c" + Name 23 "Block140" + MemberName 23(Block140) 0 "u" + MemberName 23(Block140) 1 "s" + MemberName 23(Block140) 2 "v" + Name 25 "inst140" + Name 36 "gl_PerVertex" + MemberName 36(gl_PerVertex) 0 "gl_Position" + MemberName 36(gl_PerVertex) 1 "gl_PointSize" + MemberName 36(gl_PerVertex) 2 "gl_ClipDistance" + MemberName 36(gl_PerVertex) 3 "gl_CullDistance" + Name 38 "" + Name 45 "S" + MemberName 45(S) 0 "a" + MemberName 45(S) 1 "b" + MemberName 45(S) 2 "c" + Name 48 "Block430" + MemberName 48(Block430) 0 "u" + MemberName 48(Block430) 1 "s" + MemberName 48(Block430) 2 "v" + Name 50 "inst430" + Name 52 "gl_VertexID" + Name 53 "gl_InstanceID" + MemberDecorate 13(S) 1 ColMajor + Decorate 12 ArrayStride 32 + MemberDecorate 18(S) 0 Offset 0 + MemberDecorate 18(S) 1 ColMajor + MemberDecorate 18(S) 1 Offset 16 + MemberDecorate 18(S) 1 MatrixStride 16 + MemberDecorate 18(S) 2 Offset 144 + Decorate 22 ArrayStride 16 + MemberDecorate 23(Block140) 0 Offset 0 + MemberDecorate 23(Block140) 1 Offset 16 + MemberDecorate 23(Block140) 2 Offset 976 + Decorate 23(Block140) Block + Decorate 25(inst140) DescriptorSet 0 + Decorate 25(inst140) Binding 0 + MemberDecorate 36(gl_PerVertex) 0 BuiltIn Position + MemberDecorate 36(gl_PerVertex) 1 BuiltIn PointSize + MemberDecorate 36(gl_PerVertex) 2 BuiltIn ClipDistance + MemberDecorate 36(gl_PerVertex) 3 BuiltIn CullDistance + Decorate 36(gl_PerVertex) Block + Decorate 12 ArrayStride 16 + MemberDecorate 45(S) 0 Offset 0 + MemberDecorate 45(S) 1 ColMajor + MemberDecorate 45(S) 1 Offset 16 + MemberDecorate 45(S) 1 MatrixStride 8 + MemberDecorate 45(S) 2 Offset 80 + Decorate 47 ArrayStride 16 + MemberDecorate 48(Block430) 0 Offset 0 + MemberDecorate 48(Block430) 1 Offset 16 + MemberDecorate 48(Block430) 2 Offset 592 + Decorate 48(Block430) BufferBlock + Decorate 50(inst430) DescriptorSet 0 + Decorate 50(inst430) Binding 1 + Decorate 52(gl_VertexID) BuiltIn VertexId + Decorate 53(gl_InstanceID) BuiltIn InstanceId + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeInt 32 0 + 7: TypeVector 6(int) 3 + 8: TypeFloat 32 + 9: TypeVector 8(float) 2 + 10: TypeMatrix 9(fvec2) 2 + 11: 6(int) Constant 4 + 12: TypeArray 10 11 + 13(S): TypeStruct 7(ivec3) 12 6(int) + 14: TypePointer Private 13(S) + 15(s): 14(ptr) Variable Private + 16: TypeInt 32 1 + 17: 16(int) Constant 2 + 18(S): TypeStruct 7(ivec3) 12 6(int) + 19: 6(int) Constant 3 + 20: TypeArray 18(S) 19 + 21: 6(int) Constant 2 + 22: TypeArray 20 21 + 23(Block140): TypeStruct 16(int) 22 9(fvec2) + 24: TypePointer Uniform 23(Block140) + 25(inst140): 24(ptr) Variable Uniform + 26: 16(int) Constant 0 + 27: TypePointer Uniform 16(int) + 31: TypePointer Private 6(int) + 33: TypeVector 8(float) 4 + 34: 6(int) Constant 1 + 35: TypeArray 8(float) 34 +36(gl_PerVertex): TypeStruct 33(fvec4) 8(float) 35 35 + 37: TypePointer Output 36(gl_PerVertex) + 38: 37(ptr) Variable Output + 43: TypePointer Output 33(fvec4) + 45(S): TypeStruct 7(ivec3) 12 6(int) + 46: TypeArray 45(S) 19 + 47: TypeArray 46 21 + 48(Block430): TypeStruct 16(int) 47 9(fvec2) + 49: TypePointer Uniform 48(Block430) + 50(inst430): 49(ptr) Variable Uniform + 51: TypePointer Input 16(int) + 52(gl_VertexID): 51(ptr) Variable Input +53(gl_InstanceID): 51(ptr) Variable Input + 4(main): 2 Function None 3 + 5: Label + 28: 27(ptr) AccessChain 25(inst140) 26 + 29: 16(int) Load 28 + 30: 6(int) Bitcast 29 + 32: 31(ptr) AccessChain 15(s) 17 + Store 32 30 + 39: 31(ptr) AccessChain 15(s) 17 + 40: 6(int) Load 39 + 41: 8(float) ConvertUToF 40 + 42: 33(fvec4) CompositeConstruct 41 41 41 41 + 44: 43(ptr) AccessChain 38 26 + Store 44 42 + Return + FunctionEnd diff --git a/Test/spv.layoutNested.vert b/Test/spv.layoutNested.vert new file mode 100644 index 000000000..aa403fc50 --- /dev/null +++ b/Test/spv.layoutNested.vert @@ -0,0 +1,31 @@ +#version 450 + +// should get 3 SPV types: no layout, 140, and 430 +struct S +{ + highp uvec3 a; + mediump mat2 b[4]; + lowp uint c; +}; + +layout(set = 0, binding = 0, std140) uniform Block140 +{ + mediump int u; + S s[2][3]; + mediump vec2 v; +} inst140; + +layout(set = 0, binding = 1, std430) buffer Block430 +{ + mediump int u; + S s[2][3]; + mediump vec2 v; +} inst430; + +S s; + +void main() +{ + s.c = inst140.u; + gl_Position = vec4(s.c); +} diff --git a/Test/test-spirv-list b/Test/test-spirv-list index 32be4be69..799148db8 100644 --- a/Test/test-spirv-list +++ b/Test/test-spirv-list @@ -48,6 +48,7 @@ spv.forwardFun.frag spv.functionCall.frag spv.functionSemantics.frag spv.interpOps.frag +spv.layoutNested.vert spv.length.frag spv.localAggregates.frag spv.loops.frag diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h index e3418b101..42a916c13 100644 --- a/glslang/Include/revision.h +++ b/glslang/Include/revision.h @@ -2,5 +2,5 @@ // For the version, it uses the latest git tag followed by the number of commits. // For the date, it uses the current date (when then script is run). -#define GLSLANG_REVISION "SPIRV99.851" +#define GLSLANG_REVISION "SPIRV99.860" #define GLSLANG_DATE "19-Dec-2015"