From 7da39ed968d35687a935267b7fd18c489f8e4ca6 Mon Sep 17 00:00:00 2001 From: Jeff Bolz Date: Wed, 14 Nov 2018 09:30:53 -0600 Subject: [PATCH] Implement GL_EXT_scalar_block_layout --- SPIRV/GlslangToSpv.cpp | 9 +- Test/baseResults/300.vert.out | 2 +- Test/baseResults/310.vert.out | 2 +- Test/baseResults/420.vert.out | 2 +- Test/baseResults/430.vert.out | 6 +- Test/baseResults/440.frag.out | 12 +-- Test/baseResults/spv.scalarlayout.frag.out | 80 ++++++++++++++++++ .../spv.scalarlayoutfloat16.frag.out | 72 ++++++++++++++++ Test/spv.scalarlayout.frag | 32 +++++++ Test/spv.scalarlayoutfloat16.frag | 31 +++++++ glslang/Include/Types.h | 2 + glslang/MachineIndependent/ParseHelper.cpp | 26 ++++-- glslang/MachineIndependent/Versions.cpp | 2 + glslang/MachineIndependent/Versions.h | 1 + glslang/MachineIndependent/linkValidate.cpp | 84 ++++++++++++++++++- .../MachineIndependent/localintermediate.h | 4 +- glslang/MachineIndependent/reflection.cpp | 16 ++-- gtests/Spv.FromFile.cpp | 2 + hlsl/hlslParseHelper.cpp | 16 ++-- 19 files changed, 356 insertions(+), 45 deletions(-) create mode 100644 Test/baseResults/spv.scalarlayout.frag.out create mode 100644 Test/baseResults/spv.scalarlayoutfloat16.frag.out create mode 100644 Test/spv.scalarlayout.frag create mode 100644 Test/spv.scalarlayoutfloat16.frag diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index c58013b5c..a93a4ed85 100755 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -3459,6 +3459,7 @@ glslang::TLayoutPacking TGlslangToSpvTraverser::getExplicitLayout(const glslang: switch (type.getQualifier().layoutPacking) { case glslang::ElpStd140: case glslang::ElpStd430: + case glslang::ElpScalar: return type.getQualifier().layoutPacking; default: return glslang::ElpNone; @@ -3470,7 +3471,7 @@ int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glsl { int size; int stride; - glslangIntermediate->getBaseAlignment(arrayType, size, stride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor); + glslangIntermediate->getMemberAlignment(arrayType, size, stride, explicitLayout, matrixLayout == glslang::ElmRowMajor); return stride; } @@ -3485,7 +3486,7 @@ int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, gl int size; int stride; - glslangIntermediate->getBaseAlignment(elementType, size, stride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor); + glslangIntermediate->getMemberAlignment(elementType, size, stride, explicitLayout, matrixLayout == glslang::ElmRowMajor); return stride; } @@ -3527,7 +3528,7 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType int memberSize; int dummyStride; - int memberAlignment = glslangIntermediate->getBaseAlignment(memberType, memberSize, dummyStride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor); + int memberAlignment = glslangIntermediate->getMemberAlignment(memberType, memberSize, dummyStride, explicitLayout, matrixLayout == glslang::ElmRowMajor); // Adjust alignment for HLSL rules // TODO: make this consistent in early phases of code: @@ -3546,7 +3547,7 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType glslang::RoundToPow2(currentOffset, memberAlignment); // Bump up to vec4 if there is a bad straddle - if (glslangIntermediate->improperStraddle(memberType, memberSize, currentOffset)) + if (explicitLayout != glslang::ElpScalar && glslangIntermediate->improperStraddle(memberType, memberSize, currentOffset)) glslang::RoundToPow2(currentOffset, 16); nextOffset = currentOffset + memberSize; diff --git a/Test/baseResults/300.vert.out b/Test/baseResults/300.vert.out index 95ebb92e3..d8c9e16b2 100644 --- a/Test/baseResults/300.vert.out +++ b/Test/baseResults/300.vert.out @@ -39,7 +39,7 @@ ERROR: 0:168: 'Binst' : cannot add storage, auxiliary, memory, interpolation, la ERROR: 0:169: 'Bblock' : cannot add storage, auxiliary, memory, interpolation, layout, or precision qualifier to an existing variable ERROR: 0:170: 'Bfoo' : cannot add storage, auxiliary, memory, interpolation, layout, or precision qualifier to an existing variable ERROR: 0:172: 'std430' : not supported for this version or the enabled extensions -ERROR: 0:172: 'std430' : requires the 'buffer' storage qualifier +ERROR: 0:172: 'std430 requires the buffer storage qualifier' : required extension not requested: GL_EXT_scalar_block_layout ERROR: 0:175: '' : array size required ERROR: 0:185: 'assign' : cannot convert from ' temp 4-element array of highp float' to ' temp 3-element array of highp float' ERROR: 0:186: 'assign' : cannot convert from ' temp 3-element array of highp float' to ' temp 4-element array of highp float' diff --git a/Test/baseResults/310.vert.out b/Test/baseResults/310.vert.out index 21fa27b90..baf098708 100644 --- a/Test/baseResults/310.vert.out +++ b/Test/baseResults/310.vert.out @@ -15,7 +15,7 @@ ERROR: 0:78: 'vertex-shader array-of-struct output' : not supported with this pr ERROR: 0:79: 'vertex-shader array-of-struct output' : not supported with this profile: es ERROR: 0:81: 'vertex-shader struct output containing an array' : not supported with this profile: es ERROR: 0:83: 'vertex-shader struct output containing structure' : not supported with this profile: es -ERROR: 0:85: 'std430' : requires the 'buffer' storage qualifier +ERROR: 0:85: 'std430 requires the buffer storage qualifier' : required extension not requested: GL_EXT_scalar_block_layout ERROR: 0:97: 's' : member of block cannot be or contain a sampler, image, or atomic_uint type ERROR: 0:105: 'location' : overlapping use of location 12 ERROR: 0:107: 'input block' : not supported in this stage: vertex diff --git a/Test/baseResults/420.vert.out b/Test/baseResults/420.vert.out index 25bce16cc..22577ab05 100644 --- a/Test/baseResults/420.vert.out +++ b/Test/baseResults/420.vert.out @@ -46,7 +46,7 @@ ERROR: 0:142: 'r8_snorm' : does not apply to signed integer images ERROR: 0:143: 'rgba32ui' : does not apply to signed integer images ERROR: 0:144: 'r8ui' : does not apply to signed integer images ERROR: 0:147: 'offset on block member' : not supported for this version or the enabled extensions -ERROR: 0:147: 'offset/align' : can only be used with std140 or std430 layout packing +ERROR: 0:147: 'offset/align' : can only be used with std140, std430, or scalar layout packing ERROR: 0:157: 'textureQueryLevels' : no matching overloaded function found ERROR: 0:157: 'assign' : cannot convert from ' const float' to ' temp int' ERROR: 0:158: 'textureQueryLevels' : no matching overloaded function found diff --git a/Test/baseResults/430.vert.out b/Test/baseResults/430.vert.out index 29ffb01aa..f57a39c1f 100644 --- a/Test/baseResults/430.vert.out +++ b/Test/baseResults/430.vert.out @@ -27,9 +27,9 @@ ERROR: 0:64: 'uniform buffer-member align' : not supported for this version or t ERROR: 0:65: 'uniform buffer-member align' : not supported for this version or the enabled extensions ERROR: 0:65: 'offset on block member' : not supported for this version or the enabled extensions ERROR: 0:66: 'offset on block member' : not supported for this version or the enabled extensions -ERROR: 0:64: 'align' : can only be used with std140 or std430 layout packing -ERROR: 0:65: 'offset/align' : can only be used with std140 or std430 layout packing -ERROR: 0:66: 'offset/align' : can only be used with std140 or std430 layout packing +ERROR: 0:64: 'align' : can only be used with std140, std430, or scalar layout packing +ERROR: 0:65: 'offset/align' : can only be used with std140, std430, or scalar layout packing +ERROR: 0:66: 'offset/align' : can only be used with std140, std430, or scalar layout packing ERROR: 0:71: 'offset on block member' : not supported for this version or the enabled extensions ERROR: 0:74: 'gl_MaxTransformFeedbackBuffers' : required extension not requested: GL_ARB_enhanced_layouts ERROR: 0:75: 'gl_MaxTransformFeedbackInterleavedComponents' : required extension not requested: GL_ARB_enhanced_layouts diff --git a/Test/baseResults/440.frag.out b/Test/baseResults/440.frag.out index 18e014f92..1ac6e7c68 100644 --- a/Test/baseResults/440.frag.out +++ b/Test/baseResults/440.frag.out @@ -21,11 +21,11 @@ ERROR: 0:38: 'offset' : only applies to block members, not blocks ERROR: 0:39: 'output block' : not supported in this stage: fragment ERROR: 0:39: 'layout' : offset/align can only be used on a uniform or buffer ERROR: 0:39: 'offset' : only applies to block members, not blocks -ERROR: 0:42: 'align' : can only be used with std140 or std430 layout packing -ERROR: 0:43: 'align' : can only be used with std140 or std430 layout packing +ERROR: 0:42: 'align' : can only be used with std140, std430, or scalar layout packing +ERROR: 0:43: 'align' : can only be used with std140, std430, or scalar layout packing ERROR: 0:43: 'layout' : offset/align can only be used on a uniform or buffer ERROR: 0:44: 'output block' : not supported in this stage: fragment -ERROR: 0:44: 'align' : can only be used with std140 or std430 layout packing +ERROR: 0:44: 'align' : can only be used with std140, std430, or scalar layout packing ERROR: 0:44: 'layout' : offset/align can only be used on a uniform or buffer ERROR: 0:46: 'offset' : cannot specify on a variable declaration ERROR: 0:47: 'layout' : offset/align can only be used on a uniform or buffer @@ -36,9 +36,9 @@ ERROR: 0:52: 'layout' : offset/align can only be used on a uniform or buffer ERROR: 0:54: 'layout' : matrix or packing qualifiers can only be used on a uniform or buffer ERROR: 0:55: 'layout' : cannot specify packing on a variable declaration ERROR: 0:57: 'align' : must be a power of 2 -ERROR: 0:58: 'offset/align' : can only be used with std140 or std430 layout packing -ERROR: 0:62: 'offset/align' : can only be used with std140 or std430 layout packing -ERROR: 0:63: 'offset/align' : can only be used with std140 or std430 layout packing +ERROR: 0:58: 'offset/align' : can only be used with std140, std430, or scalar layout packing +ERROR: 0:62: 'offset/align' : can only be used with std140, std430, or scalar layout packing +ERROR: 0:63: 'offset/align' : can only be used with std140, std430, or scalar layout packing ERROR: 0:62: 'layout' : offset/align can only be used on a uniform or buffer ERROR: 0:63: 'layout' : offset/align can only be used on a uniform or buffer ERROR: 0:84: 'align' : must be a power of 2 diff --git a/Test/baseResults/spv.scalarlayout.frag.out b/Test/baseResults/spv.scalarlayout.frag.out new file mode 100644 index 000000000..2935e1a09 --- /dev/null +++ b/Test/baseResults/spv.scalarlayout.frag.out @@ -0,0 +1,80 @@ +spv.scalarlayout.frag +error: SPIRV-Tools Validation Errors +error: Structure id 17 decorated as Block for variable in Uniform storage class must follow standard uniform buffer layout rules: member 1 at offset 4 is not aligned to 8 + %B1 = OpTypeStruct %float %v2float %v3float %_arr_float_uint_2 %mat2v3float %_arr_mat2v3float_uint_2 %float %S %_arr_S_uint_2 + +// Module Version 10000 +// Generated by (magic number): 80007 +// Id's are bound by 20 + + Capability Shader + Capability Float64 + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" + ExecutionMode 4 OriginUpperLeft + Source GLSL 450 + SourceExtension "GL_EXT_scalar_block_layout" + Name 4 "main" + Name 15 "S" + MemberName 15(S) 0 "a" + MemberName 15(S) 1 "b" + MemberName 15(S) 2 "c" + MemberName 15(S) 3 "d" + MemberName 15(S) 4 "e" + MemberName 15(S) 5 "f" + Name 17 "B1" + MemberName 17(B1) 0 "a" + MemberName 17(B1) 1 "b" + MemberName 17(B1) 2 "c" + MemberName 17(B1) 3 "d" + MemberName 17(B1) 4 "e" + MemberName 17(B1) 5 "f" + MemberName 17(B1) 6 "g" + MemberName 17(B1) 7 "h" + MemberName 17(B1) 8 "i" + Name 19 "" + Decorate 11 ArrayStride 4 + Decorate 13 ArrayStride 24 + MemberDecorate 15(S) 0 Offset 0 + MemberDecorate 15(S) 1 Offset 4 + MemberDecorate 15(S) 2 Offset 16 + MemberDecorate 15(S) 3 Offset 24 + MemberDecorate 15(S) 4 Offset 28 + MemberDecorate 15(S) 5 Offset 40 + Decorate 16 ArrayStride 48 + MemberDecorate 17(B1) 0 Offset 0 + MemberDecorate 17(B1) 1 Offset 4 + MemberDecorate 17(B1) 2 Offset 12 + MemberDecorate 17(B1) 3 Offset 24 + MemberDecorate 17(B1) 4 ColMajor + MemberDecorate 17(B1) 4 Offset 32 + MemberDecorate 17(B1) 4 MatrixStride 12 + MemberDecorate 17(B1) 5 ColMajor + MemberDecorate 17(B1) 5 Offset 56 + MemberDecorate 17(B1) 5 MatrixStride 12 + MemberDecorate 17(B1) 6 Offset 104 + MemberDecorate 17(B1) 7 Offset 112 + MemberDecorate 17(B1) 8 Offset 160 + Decorate 17(B1) Block + Decorate 19 DescriptorSet 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 2 + 8: TypeVector 6(float) 3 + 9: TypeInt 32 0 + 10: 9(int) Constant 2 + 11: TypeArray 6(float) 10 + 12: TypeMatrix 8(fvec3) 2 + 13: TypeArray 12 10 + 14: TypeFloat 64 + 15(S): TypeStruct 6(float) 7(fvec2) 14(float64_t) 6(float) 8(fvec3) 6(float) + 16: TypeArray 15(S) 10 + 17(B1): TypeStruct 6(float) 7(fvec2) 8(fvec3) 11 12 13 6(float) 15(S) 16 + 18: TypePointer Uniform 17(B1) + 19: 18(ptr) Variable Uniform + 4(main): 2 Function None 3 + 5: Label + Return + FunctionEnd diff --git a/Test/baseResults/spv.scalarlayoutfloat16.frag.out b/Test/baseResults/spv.scalarlayoutfloat16.frag.out new file mode 100644 index 000000000..9118636f2 --- /dev/null +++ b/Test/baseResults/spv.scalarlayoutfloat16.frag.out @@ -0,0 +1,72 @@ +spv.scalarlayoutfloat16.frag +error: SPIRV-Tools Validation Errors +error: Structure id 15 decorated as Block for variable in Uniform storage class must follow standard uniform buffer layout rules: member 1 at offset 2 is not aligned to 4 + %B1 = OpTypeStruct %half %v2half %v3half %_arr_half_uint_2 %half %S %_arr_S_uint_2 + +// Module Version 10000 +// Generated by (magic number): 80007 +// Id's are bound by 18 + + Capability Shader + Capability Float64 + Capability StorageUniform16 + Extension "SPV_KHR_16bit_storage" + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" + ExecutionMode 4 OriginUpperLeft + Source GLSL 450 + SourceExtension "GL_EXT_scalar_block_layout" + SourceExtension "GL_EXT_shader_16bit_storage" + Name 4 "main" + Name 13 "S" + MemberName 13(S) 0 "a" + MemberName 13(S) 1 "b" + MemberName 13(S) 2 "c" + MemberName 13(S) 3 "d" + MemberName 13(S) 4 "e" + MemberName 13(S) 5 "f" + Name 15 "B1" + MemberName 15(B1) 0 "a" + MemberName 15(B1) 1 "b" + MemberName 15(B1) 2 "c" + MemberName 15(B1) 3 "d" + MemberName 15(B1) 4 "g" + MemberName 15(B1) 5 "h" + MemberName 15(B1) 6 "i" + Name 17 "" + Decorate 11 ArrayStride 2 + MemberDecorate 13(S) 0 Offset 0 + MemberDecorate 13(S) 1 Offset 2 + MemberDecorate 13(S) 2 Offset 8 + MemberDecorate 13(S) 3 Offset 16 + MemberDecorate 13(S) 4 Offset 18 + MemberDecorate 13(S) 5 Offset 24 + Decorate 14 ArrayStride 32 + MemberDecorate 15(B1) 0 Offset 0 + MemberDecorate 15(B1) 1 Offset 2 + MemberDecorate 15(B1) 2 Offset 6 + MemberDecorate 15(B1) 3 Offset 12 + MemberDecorate 15(B1) 4 Offset 16 + MemberDecorate 15(B1) 5 Offset 24 + MemberDecorate 15(B1) 6 Offset 56 + Decorate 15(B1) Block + Decorate 17 DescriptorSet 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 16 + 7: TypeVector 6(float16_t) 2 + 8: TypeVector 6(float16_t) 3 + 9: TypeInt 32 0 + 10: 9(int) Constant 2 + 11: TypeArray 6(float16_t) 10 + 12: TypeFloat 64 + 13(S): TypeStruct 6(float16_t) 7(f16vec2) 12(float64_t) 6(float16_t) 8(f16vec3) 6(float16_t) + 14: TypeArray 13(S) 10 + 15(B1): TypeStruct 6(float16_t) 7(f16vec2) 8(f16vec3) 11 6(float16_t) 13(S) 14 + 16: TypePointer Uniform 15(B1) + 17: 16(ptr) Variable Uniform + 4(main): 2 Function None 3 + 5: Label + Return + FunctionEnd diff --git a/Test/spv.scalarlayout.frag b/Test/spv.scalarlayout.frag new file mode 100644 index 000000000..c7ecf5025 --- /dev/null +++ b/Test/spv.scalarlayout.frag @@ -0,0 +1,32 @@ +#version 450 core + +#extension GL_EXT_scalar_block_layout : enable + +// Block memory layout +struct S +{ + float a; // offset 0 + vec2 b; // offset 4 + double c; // offset 16 + float d; // offset 24 + vec3 e; // offset 28 + float f; // offset 40 + // size = 44, align = 8 +}; + +layout(column_major, scalar) uniform B1 +{ + float a; // offset = 0 + vec2 b; // offset = 4 + vec3 c; // offset = 12 + float d[2]; // offset = 24 + mat2x3 e; // offset = 32, takes 24 bytes, matrixstride = 12 + mat2x3 f[2]; // offset = 56, takes 48 bytes, matrixstride = 12, arraystride = 24 + float g; // offset = 104 + S h; // offset = 112 (aligned to multiple of 8) + S i[2]; // offset = 160 (aligned to multiple of 8) stride = 48 +}; + +void main() +{ +} diff --git a/Test/spv.scalarlayoutfloat16.frag b/Test/spv.scalarlayoutfloat16.frag new file mode 100644 index 000000000..ff8709737 --- /dev/null +++ b/Test/spv.scalarlayoutfloat16.frag @@ -0,0 +1,31 @@ +#version 450 core + +#extension GL_EXT_shader_16bit_storage: enable +#extension GL_EXT_scalar_block_layout : enable + +// Block memory layout +struct S +{ + float16_t a; // offset 0 + f16vec2 b; // offset 2 + double c; // offset 8 + float16_t d; // offset 16 + f16vec3 e; // offset 18 + float16_t f; // offset 24 + // size = 26, align = 8 +}; + +layout(column_major, scalar) uniform B1 +{ + float16_t a; // offset = 0 + f16vec2 b; // offset = 2 + f16vec3 c; // offset = 6 + float16_t d[2]; // offset = 12 stride = 2 + float16_t g; // offset = 16 + S h; // offset = 24 (aligned to multiple of 8) + S i[2]; // offset = 56 (aligned to multiple of 8) stride = 32 +}; + +void main() +{ +} diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index ae9cf4021..b8b2c6fd1 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -277,6 +277,7 @@ enum TLayoutPacking { ElpStd140, ElpStd430, ElpPacked, + ElpScalar, ElpCount // If expanding, see bitfield width below }; @@ -951,6 +952,7 @@ public: case ElpShared: return "shared"; case ElpStd140: return "std140"; case ElpStd430: return "std430"; + case ElpScalar: return "scalar"; default: return "none"; } } diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 56b45cabc..24bd417f7 100755 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -4611,6 +4611,12 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi publicType.qualifier.layoutPacking = ElpStd430; return; } + if (id == TQualifier::getLayoutPackingString(ElpScalar)) { + requireVulkan(loc, "scalar"); + requireExtensions(loc, 1, &E_GL_EXT_scalar_block_layout, "scalar block layout"); + publicType.qualifier.layoutPacking = ElpScalar; + return; + } // TODO: compile-time performance: may need to stop doing linear searches for (TLayoutFormat format = (TLayoutFormat)(ElfNone + 1); format < ElfCount; format = (TLayoutFormat)(format + 1)) { if (id == TQualifier::getLayoutFormatString(format)) { @@ -6784,8 +6790,10 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con // "The align qualifier can only be used on blocks or block members, and only for blocks declared with std140 or std430 layouts." if (currentBlockQualifier.hasAlign()) { - if (defaultQualification.layoutPacking != ElpStd140 && defaultQualification.layoutPacking != ElpStd430) { - error(loc, "can only be used with std140 or std430 layout packing", "align", ""); + if (defaultQualification.layoutPacking != ElpStd140 && + defaultQualification.layoutPacking != ElpStd430 && + defaultQualification.layoutPacking != ElpScalar) { + error(loc, "can only be used with std140, std430, or scalar layout packing", "align", ""); defaultQualification.layoutAlign = -1; } } @@ -6834,8 +6842,10 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con // "The offset qualifier can only be used on block members of blocks declared with std140 or std430 layouts." // "The align qualifier can only be used on blocks or block members, and only for blocks declared with std140 or std430 layouts." if (memberQualifier.hasAlign() || memberQualifier.hasOffset()) { - if (defaultQualification.layoutPacking != ElpStd140 && defaultQualification.layoutPacking != ElpStd430) - error(memberLoc, "can only be used with std140 or std430 layout packing", "offset/align", ""); + if (defaultQualification.layoutPacking != ElpStd140 && + defaultQualification.layoutPacking != ElpStd430 && + defaultQualification.layoutPacking != ElpScalar) + error(memberLoc, "can only be used with std140, std430, or scalar layout packing", "offset/align", ""); } #ifdef NV_EXTENSIONS @@ -6946,7 +6956,7 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q profileRequires(loc, EEsProfile, 300, nullptr, "uniform block"); profileRequires(loc, ENoProfile, 140, nullptr, "uniform block"); if (currentBlockQualifier.layoutPacking == ElpStd430 && ! currentBlockQualifier.layoutPushConstant) - error(loc, "requires the 'buffer' storage qualifier", "std430", ""); + requireExtensions(loc, 1, &E_GL_EXT_scalar_block_layout, "std430 requires the buffer storage qualifier"); break; case EvqBuffer: requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, "buffer block"); @@ -7145,7 +7155,7 @@ void TParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& typ { if (!qualifier.isUniformOrBuffer() && !qualifier.isTaskMemory()) return; - if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430) + if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430 && qualifier.layoutPacking != ElpScalar) return; int offset = 0; @@ -7159,8 +7169,8 @@ void TParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& typ // modify just the children's view of matrix layout, if there is one for this member TLayoutMatrix subMatrixLayout = typeList[member].type->getQualifier().layoutMatrix; int dummyStride; - int memberAlignment = intermediate.getBaseAlignment(*typeList[member].type, memberSize, dummyStride, qualifier.layoutPacking == ElpStd140, - subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor : qualifier.layoutMatrix == ElmRowMajor); + int memberAlignment = intermediate.getMemberAlignment(*typeList[member].type, memberSize, dummyStride, qualifier.layoutPacking, + subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor : qualifier.layoutMatrix == ElmRowMajor); if (memberQualifier.hasOffset()) { // "The specified offset must be a multiple // of the base alignment of the type of the block member it qualifies, or a compile-time error results." diff --git a/glslang/MachineIndependent/Versions.cpp b/glslang/MachineIndependent/Versions.cpp index 66fa3e25e..89c033370 100644 --- a/glslang/MachineIndependent/Versions.cpp +++ b/glslang/MachineIndependent/Versions.cpp @@ -204,6 +204,7 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_EXT_control_flow_attributes] = EBhDisable; extensionBehavior[E_GL_EXT_nonuniform_qualifier] = EBhDisable; extensionBehavior[E_GL_EXT_samplerless_texture_functions] = EBhDisable; + extensionBehavior[E_GL_EXT_scalar_block_layout] = EBhDisable; extensionBehavior[E_GL_EXT_shader_16bit_storage] = EBhDisable; extensionBehavior[E_GL_EXT_shader_8bit_storage] = EBhDisable; @@ -378,6 +379,7 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_EXT_shader_16bit_storage 1\n" "#define GL_EXT_shader_8bit_storage 1\n" "#define GL_EXT_samplerless_texture_functions 1\n" + "#define GL_EXT_scalar_block_layout 1\n" // GL_KHR_shader_subgroup "#define GL_KHR_shader_subgroup_basic 1\n" diff --git a/glslang/MachineIndependent/Versions.h b/glslang/MachineIndependent/Versions.h index 85c93c0ac..df10f0f4a 100644 --- a/glslang/MachineIndependent/Versions.h +++ b/glslang/MachineIndependent/Versions.h @@ -166,6 +166,7 @@ const char* const E_GL_EXT_post_depth_coverage = "GL_EXT_post_depth const char* const E_GL_EXT_control_flow_attributes = "GL_EXT_control_flow_attributes"; const char* const E_GL_EXT_nonuniform_qualifier = "GL_EXT_nonuniform_qualifier"; const char* const E_GL_EXT_samplerless_texture_functions = "GL_EXT_samplerless_texture_functions"; +const char* const E_GL_EXT_scalar_block_layout = "GL_EXT_scalar_block_layout"; // Arrays of extensions for the above viewportEXTs duplications diff --git a/glslang/MachineIndependent/linkValidate.cpp b/glslang/MachineIndependent/linkValidate.cpp index 8630128f7..82e7c6e7e 100644 --- a/glslang/MachineIndependent/linkValidate.cpp +++ b/glslang/MachineIndependent/linkValidate.cpp @@ -1372,10 +1372,11 @@ int TIntermediate::getBaseAlignmentScalar(const TType& type, int& size) // stride comes from the flattening down to vectors. // // Return value is the alignment of the type. -int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, bool std140, bool rowMajor) +int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor) { int alignment; + bool std140 = layoutPacking == glslang::ElpStd140; // When using the std140 storage layout, structures will be laid out in buffer // storage with its members stored in monotonically increasing order based on their // location in the declaration. A structure and each structure member have a base @@ -1439,7 +1440,7 @@ int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, b 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, dummyStride, std140, rowMajor); + alignment = getBaseAlignment(derefType, size, dummyStride, layoutPacking, rowMajor); if (std140) alignment = std::max(baseAlignmentVec4Std140, alignment); RoundToPow2(size, alignment); @@ -1459,7 +1460,7 @@ int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, b 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, dummyStride, std140, + int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, dummyStride, layoutPacking, (subMatrixLayout != ElmNone) ? (subMatrixLayout == ElmRowMajor) : rowMajor); maxAlignment = std::max(maxAlignment, memberAlignment); RoundToPow2(size, memberAlignment); @@ -1498,7 +1499,7 @@ int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, b // rule 5: deref to row, not to column, meaning the size of vector is num columns instead of num rows TType derefType(type, 0, rowMajor); - alignment = getBaseAlignment(derefType, size, dummyStride, std140, rowMajor); + alignment = getBaseAlignment(derefType, size, dummyStride, layoutPacking, rowMajor); if (std140) alignment = std::max(baseAlignmentVec4Std140, alignment); RoundToPow2(size, alignment); @@ -1526,4 +1527,79 @@ bool TIntermediate::improperStraddle(const TType& type, int size, int offset) : offset % 16 != 0; } +int TIntermediate::getScalarAlignment(const TType& type, int& size, int& stride, bool rowMajor) +{ + int alignment; + + stride = 0; + int dummyStride; + + if (type.isArray()) { + TType derefType(type, 0); + alignment = getScalarAlignment(derefType, size, dummyStride, rowMajor); + + stride = size; + RoundToPow2(stride, alignment); + + size = stride * (type.getOuterArraySize() - 1) + size; + return alignment; + } + + if (type.getBasicType() == EbtStruct) { + const TTypeList& memberList = *type.getStruct(); + + size = 0; + int maxAlignment = 0; + for (size_t m = 0; m < memberList.size(); ++m) { + 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 = getScalarAlignment(*memberList[m].type, memberSize, dummyStride, + (subMatrixLayout != ElmNone) ? (subMatrixLayout == ElmRowMajor) : rowMajor); + maxAlignment = std::max(maxAlignment, memberAlignment); + RoundToPow2(size, memberAlignment); + size += memberSize; + } + + return maxAlignment; + } + + if (type.isScalar()) + return getBaseAlignmentScalar(type, size); + + if (type.isVector()) { + int scalarAlign = getBaseAlignmentScalar(type, size); + + size *= type.getVectorSize(); + return scalarAlign; + } + + if (type.isMatrix()) { + TType derefType(type, 0, rowMajor); + + alignment = getScalarAlignment(derefType, size, dummyStride, rowMajor); + + stride = size; // use intra-matrix stride for stride of a just a matrix + if (rowMajor) + size = stride * type.getMatrixRows(); + else + size = stride * type.getMatrixCols(); + + return alignment; + } + + assert(0); // all cases should be covered above + size = 1; + return 1; +} + +int TIntermediate::getMemberAlignment(const TType& type, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor) +{ + if (layoutPacking == glslang::ElpScalar) { + return getScalarAlignment(type, size, stride, rowMajor); + } else { + return getBaseAlignment(type, size, stride, layoutPacking, rowMajor); + } +} + } // end namespace glslang diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index 99f777f11..762b31085 100755 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -634,7 +634,9 @@ public: int addXfbBufferOffset(const TType&); unsigned int computeTypeXfbSize(const TType&, bool& containsDouble) const; static int getBaseAlignmentScalar(const TType&, int& size); - static int getBaseAlignment(const TType&, int& size, int& stride, bool std140, bool rowMajor); + static int getBaseAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor); + static int getScalarAlignment(const TType&, int& size, int& stride, bool rowMajor); + static int getMemberAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor); static bool improperStraddle(const TType& type, int size, int offset); bool promote(TIntermOperator*); diff --git a/glslang/MachineIndependent/reflection.cpp b/glslang/MachineIndependent/reflection.cpp index 5d59f2895..8cfc2acb8 100644 --- a/glslang/MachineIndependent/reflection.cpp +++ b/glslang/MachineIndependent/reflection.cpp @@ -131,11 +131,11 @@ public: 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, dummyStride, - type.getQualifier().layoutPacking == ElpStd140, - subMatrixLayout != ElmNone - ? subMatrixLayout == ElmRowMajor - : type.getQualifier().layoutMatrix == ElmRowMajor); + int memberAlignment = intermediate.getMemberAlignment(*memberList[m].type, memberSize, dummyStride, + type.getQualifier().layoutPacking, + subMatrixLayout != ElmNone + ? subMatrixLayout == ElmRowMajor + : type.getQualifier().layoutMatrix == ElmRowMajor); RoundToPow2(offset, memberAlignment); if (m < index) offset += memberSize; @@ -154,9 +154,9 @@ public: int lastMemberSize; int dummyStride; - intermediate.getBaseAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride, - blockType.getQualifier().layoutPacking == ElpStd140, - blockType.getQualifier().layoutMatrix == ElmRowMajor); + intermediate.getMemberAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride, + blockType.getQualifier().layoutPacking, + blockType.getQualifier().layoutMatrix == ElmRowMajor); return lastOffset + lastMemberSize; } diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp index bc05eede9..410f8ed0f 100644 --- a/gtests/Spv.FromFile.cpp +++ b/gtests/Spv.FromFile.cpp @@ -309,6 +309,8 @@ INSTANTIATE_TEST_CASE_P( "spv.sampleId.frag", "spv.samplePosition.frag", "spv.sampleMaskOverrideCoverage.frag", + "spv.scalarlayout.frag", + "spv.scalarlayoutfloat16.frag", "spv.shaderBallot.comp", "spv.shaderDrawParams.vert", "spv.shaderGroupVote.comp", diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index ac2943284..11a7965e1 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -3477,8 +3477,8 @@ void HlslParseContext::decomposeStructBufferMethods(const TSourceLoc& loc, TInte if (argStride != nullptr) { int size; int stride; - intermediate.getBaseAlignment(argArray->getType(), size, stride, false, - argArray->getType().getQualifier().layoutMatrix == ElmRowMajor); + intermediate.getMemberAlignment(argArray->getType(), size, stride, argArray->getType().getQualifier().layoutPacking, + argArray->getType().getQualifier().layoutMatrix == ElmRowMajor); TIntermTyped* assign = intermediate.addAssign(EOpAssign, argStride, intermediate.addConstantUnion(stride, loc, true), loc); @@ -8679,7 +8679,7 @@ void HlslParseContext::fixBlockUniformOffsets(const TQualifier& qualifier, TType { if (! qualifier.isUniformOrBuffer()) return; - if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430) + if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430 && qualifier.layoutPacking != ElpScalar) return; int offset = 0; @@ -8693,11 +8693,11 @@ void HlslParseContext::fixBlockUniformOffsets(const TQualifier& qualifier, TType // modify just the children's view of matrix layout, if there is one for this member TLayoutMatrix subMatrixLayout = typeList[member].type->getQualifier().layoutMatrix; int dummyStride; - int memberAlignment = intermediate.getBaseAlignment(*typeList[member].type, memberSize, dummyStride, - qualifier.layoutPacking == ElpStd140, - subMatrixLayout != ElmNone - ? subMatrixLayout == ElmRowMajor - : qualifier.layoutMatrix == ElmRowMajor); + int memberAlignment = intermediate.getMemberAlignment(*typeList[member].type, memberSize, dummyStride, + qualifier.layoutPacking, + subMatrixLayout != ElmNone + ? subMatrixLayout == ElmRowMajor + : qualifier.layoutMatrix == ElmRowMajor); if (memberQualifier.hasOffset()) { // "The specified offset must be a multiple // of the base alignment of the type of the block member it qualifies, or a compile-time error results."