From 6f091e7c8f637b929bc96efe60b4a03134ee8bab Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Fri, 26 Apr 2019 13:05:44 +0200 Subject: [PATCH] GLSL: Support GL_EXT_scalar_block_layout. --- .../comp/buffer-reference.nocompat.vk.comp.vk | 2 +- ...packing-scalar.nocompat.invalid.vk.comp.vk | 147 ++++++++++++++++++ .../comp/buffer-reference.nocompat.vk.comp.vk | 2 +- ...packing-scalar.nocompat.invalid.vk.comp.vk | 147 ++++++++++++++++++ ...ct-packing-scalar.nocompat.invalid.vk.comp | 88 +++++++++++ spirv_cross.hpp | 4 +- spirv_glsl.cpp | 128 ++++++++------- spirv_glsl.hpp | 2 +- 8 files changed, 458 insertions(+), 62 deletions(-) create mode 100644 reference/opt/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk create mode 100644 reference/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk create mode 100644 shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp diff --git a/reference/opt/shaders/vulkan/comp/buffer-reference.nocompat.vk.comp.vk b/reference/opt/shaders/vulkan/comp/buffer-reference.nocompat.vk.comp.vk index 03f1ae69..dfcaac83 100644 --- a/reference/opt/shaders/vulkan/comp/buffer-reference.nocompat.vk.comp.vk +++ b/reference/opt/shaders/vulkan/comp/buffer-reference.nocompat.vk.comp.vk @@ -4,7 +4,7 @@ layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; layout(buffer_reference) buffer Node; -layout(buffer_reference, std140) buffer Node +layout(buffer_reference, std430) buffer Node { layout(offset = 0) int value; layout(offset = 16) Node next; diff --git a/reference/opt/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk b/reference/opt/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk new file mode 100644 index 00000000..d67e0bee --- /dev/null +++ b/reference/opt/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk @@ -0,0 +1,147 @@ +#version 310 es +#extension GL_EXT_scalar_block_layout : require +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +struct S0 +{ + vec2 a[1]; + float b; +}; + +struct S1 +{ + vec3 a; + float b; +}; + +struct S2 +{ + vec3 a[1]; + float b; +}; + +struct S3 +{ + vec2 a; + float b; +}; + +struct S4 +{ + vec2 c; +}; + +struct Content +{ + S0 m0s[1]; + S1 m1s[1]; + S2 m2s[1]; + S0 m0; + S1 m1; + S2 m2; + S3 m3; + float m4; + S4 m3s[8]; +}; + +struct S0_1 +{ + vec2 a[1]; + float b; +}; + +struct S1_1 +{ + vec3 a; + float b; +}; + +struct S2_1 +{ + vec3 a[1]; + float b; +}; + +struct S3_1 +{ + vec2 a; + float b; +}; + +struct S4_1 +{ + vec2 c; +}; + +struct Content_1 +{ + S0_1 m0s[1]; + S1_1 m1s[1]; + S2_1 m2s[1]; + S0_1 m0; + S1_1 m1; + S2_1 m2; + S3_1 m3; + float m4; + S4_1 m3s[8]; +}; + +layout(set = 0, binding = 1, scalar) restrict buffer SSBO1 +{ + Content content; + Content content1[2]; + Content content2; + mat2 m0; + mat2 m1; + mat2x3 m2[4]; + mat3x2 m3; + layout(row_major) mat2 m4; + layout(row_major) mat2 m5[9]; + layout(row_major) mat2x3 m6[4][2]; + layout(row_major) mat3x2 m7; + float array[]; +} ssbo_430; + +layout(set = 0, binding = 0, std140) restrict buffer SSBO0 +{ + Content_1 content; + Content_1 content1[2]; + Content_1 content2; + mat2 m0; + mat2 m1; + mat2x3 m2[4]; + mat3x2 m3; + layout(row_major) mat2 m4; + layout(row_major) mat2 m5[9]; + layout(row_major) mat2x3 m6[4][2]; + layout(row_major) mat3x2 m7; + float array[]; +} ssbo_140; + +void main() +{ + ssbo_430.content.m0s[0].a[0] = ssbo_140.content.m0s[0].a[0]; + ssbo_430.content.m0s[0].b = ssbo_140.content.m0s[0].b; + ssbo_430.content.m1s[0].a = ssbo_140.content.m1s[0].a; + ssbo_430.content.m1s[0].b = ssbo_140.content.m1s[0].b; + ssbo_430.content.m2s[0].a[0] = ssbo_140.content.m2s[0].a[0]; + ssbo_430.content.m2s[0].b = ssbo_140.content.m2s[0].b; + ssbo_430.content.m0.a[0] = ssbo_140.content.m0.a[0]; + ssbo_430.content.m0.b = ssbo_140.content.m0.b; + ssbo_430.content.m1.a = ssbo_140.content.m1.a; + ssbo_430.content.m1.b = ssbo_140.content.m1.b; + ssbo_430.content.m2.a[0] = ssbo_140.content.m2.a[0]; + ssbo_430.content.m2.b = ssbo_140.content.m2.b; + ssbo_430.content.m3.a = ssbo_140.content.m3.a; + ssbo_430.content.m3.b = ssbo_140.content.m3.b; + ssbo_430.content.m4 = ssbo_140.content.m4; + ssbo_430.content.m3s[0].c = ssbo_140.content.m3s[0].c; + ssbo_430.content.m3s[1].c = ssbo_140.content.m3s[1].c; + ssbo_430.content.m3s[2].c = ssbo_140.content.m3s[2].c; + ssbo_430.content.m3s[3].c = ssbo_140.content.m3s[3].c; + ssbo_430.content.m3s[4].c = ssbo_140.content.m3s[4].c; + ssbo_430.content.m3s[5].c = ssbo_140.content.m3s[5].c; + ssbo_430.content.m3s[6].c = ssbo_140.content.m3s[6].c; + ssbo_430.content.m3s[7].c = ssbo_140.content.m3s[7].c; +} + diff --git a/reference/shaders/vulkan/comp/buffer-reference.nocompat.vk.comp.vk b/reference/shaders/vulkan/comp/buffer-reference.nocompat.vk.comp.vk index ed180110..610d60cb 100644 --- a/reference/shaders/vulkan/comp/buffer-reference.nocompat.vk.comp.vk +++ b/reference/shaders/vulkan/comp/buffer-reference.nocompat.vk.comp.vk @@ -4,7 +4,7 @@ layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; layout(buffer_reference) buffer Node; -layout(buffer_reference, std140) buffer Node +layout(buffer_reference, std430) buffer Node { layout(offset = 0) int value; layout(offset = 16) Node next; diff --git a/reference/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk b/reference/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk new file mode 100644 index 00000000..d67e0bee --- /dev/null +++ b/reference/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk @@ -0,0 +1,147 @@ +#version 310 es +#extension GL_EXT_scalar_block_layout : require +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +struct S0 +{ + vec2 a[1]; + float b; +}; + +struct S1 +{ + vec3 a; + float b; +}; + +struct S2 +{ + vec3 a[1]; + float b; +}; + +struct S3 +{ + vec2 a; + float b; +}; + +struct S4 +{ + vec2 c; +}; + +struct Content +{ + S0 m0s[1]; + S1 m1s[1]; + S2 m2s[1]; + S0 m0; + S1 m1; + S2 m2; + S3 m3; + float m4; + S4 m3s[8]; +}; + +struct S0_1 +{ + vec2 a[1]; + float b; +}; + +struct S1_1 +{ + vec3 a; + float b; +}; + +struct S2_1 +{ + vec3 a[1]; + float b; +}; + +struct S3_1 +{ + vec2 a; + float b; +}; + +struct S4_1 +{ + vec2 c; +}; + +struct Content_1 +{ + S0_1 m0s[1]; + S1_1 m1s[1]; + S2_1 m2s[1]; + S0_1 m0; + S1_1 m1; + S2_1 m2; + S3_1 m3; + float m4; + S4_1 m3s[8]; +}; + +layout(set = 0, binding = 1, scalar) restrict buffer SSBO1 +{ + Content content; + Content content1[2]; + Content content2; + mat2 m0; + mat2 m1; + mat2x3 m2[4]; + mat3x2 m3; + layout(row_major) mat2 m4; + layout(row_major) mat2 m5[9]; + layout(row_major) mat2x3 m6[4][2]; + layout(row_major) mat3x2 m7; + float array[]; +} ssbo_430; + +layout(set = 0, binding = 0, std140) restrict buffer SSBO0 +{ + Content_1 content; + Content_1 content1[2]; + Content_1 content2; + mat2 m0; + mat2 m1; + mat2x3 m2[4]; + mat3x2 m3; + layout(row_major) mat2 m4; + layout(row_major) mat2 m5[9]; + layout(row_major) mat2x3 m6[4][2]; + layout(row_major) mat3x2 m7; + float array[]; +} ssbo_140; + +void main() +{ + ssbo_430.content.m0s[0].a[0] = ssbo_140.content.m0s[0].a[0]; + ssbo_430.content.m0s[0].b = ssbo_140.content.m0s[0].b; + ssbo_430.content.m1s[0].a = ssbo_140.content.m1s[0].a; + ssbo_430.content.m1s[0].b = ssbo_140.content.m1s[0].b; + ssbo_430.content.m2s[0].a[0] = ssbo_140.content.m2s[0].a[0]; + ssbo_430.content.m2s[0].b = ssbo_140.content.m2s[0].b; + ssbo_430.content.m0.a[0] = ssbo_140.content.m0.a[0]; + ssbo_430.content.m0.b = ssbo_140.content.m0.b; + ssbo_430.content.m1.a = ssbo_140.content.m1.a; + ssbo_430.content.m1.b = ssbo_140.content.m1.b; + ssbo_430.content.m2.a[0] = ssbo_140.content.m2.a[0]; + ssbo_430.content.m2.b = ssbo_140.content.m2.b; + ssbo_430.content.m3.a = ssbo_140.content.m3.a; + ssbo_430.content.m3.b = ssbo_140.content.m3.b; + ssbo_430.content.m4 = ssbo_140.content.m4; + ssbo_430.content.m3s[0].c = ssbo_140.content.m3s[0].c; + ssbo_430.content.m3s[1].c = ssbo_140.content.m3s[1].c; + ssbo_430.content.m3s[2].c = ssbo_140.content.m3s[2].c; + ssbo_430.content.m3s[3].c = ssbo_140.content.m3s[3].c; + ssbo_430.content.m3s[4].c = ssbo_140.content.m3s[4].c; + ssbo_430.content.m3s[5].c = ssbo_140.content.m3s[5].c; + ssbo_430.content.m3s[6].c = ssbo_140.content.m3s[6].c; + ssbo_430.content.m3s[7].c = ssbo_140.content.m3s[7].c; +} + diff --git a/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp b/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp new file mode 100644 index 00000000..808403d9 --- /dev/null +++ b/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp @@ -0,0 +1,88 @@ +#version 310 es +#extension GL_EXT_scalar_block_layout : require + +layout(local_size_x = 1) in; + +struct S0 +{ + vec2 a[1]; + float b; +}; + +struct S1 +{ + vec3 a; + float b; +}; + +struct S2 +{ + vec3 a[1]; + float b; +}; + +struct S3 +{ + vec2 a; + float b; +}; + +struct S4 +{ + vec2 c; +}; + +struct Content +{ + S0 m0s[1]; + S1 m1s[1]; + S2 m2s[1]; + S0 m0; + S1 m1; + S2 m2; + S3 m3; + float m4; + + S4 m3s[8]; +}; + +layout(binding = 1, scalar) restrict buffer SSBO1 +{ + Content content; + Content content1[2]; + Content content2; + + layout(column_major) mat2 m0; + layout(column_major) mat2 m1; + layout(column_major) mat2x3 m2[4]; + layout(column_major) mat3x2 m3; + layout(row_major) mat2 m4; + layout(row_major) mat2 m5[9]; + layout(row_major) mat2x3 m6[4][2]; + layout(row_major) mat3x2 m7; + float array[]; +} ssbo_430; + +layout(binding = 0, std140) restrict buffer SSBO0 +{ + Content content; + Content content1[2]; + Content content2; + + layout(column_major) mat2 m0; + layout(column_major) mat2 m1; + layout(column_major) mat2x3 m2[4]; + layout(column_major) mat3x2 m3; + layout(row_major) mat2 m4; + layout(row_major) mat2 m5[9]; + layout(row_major) mat2x3 m6[4][2]; + layout(row_major) mat3x2 m7; + + float array[]; +} ssbo_140; + +void main() +{ + ssbo_430.content = ssbo_140.content; +} + diff --git a/spirv_cross.hpp b/spirv_cross.hpp index e2cfad7d..4129e816 100644 --- a/spirv_cross.hpp +++ b/spirv_cross.hpp @@ -106,7 +106,9 @@ enum BufferPackingStandard BufferPackingStd140EnhancedLayout, BufferPackingStd430EnhancedLayout, BufferPackingHLSLCbuffer, - BufferPackingHLSLCbufferPackOffset + BufferPackingHLSLCbufferPackOffset, + BufferPackingScalar, + BufferPackingScalarEnhancedLayout }; struct EntryPoint diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index 454bd8a7..4616cfc4 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -106,6 +106,7 @@ static bool packing_has_flexible_offset(BufferPackingStandard packing) { case BufferPackingStd140: case BufferPackingStd430: + case BufferPackingScalar: case BufferPackingHLSLCbuffer: return false; @@ -114,6 +115,19 @@ static bool packing_has_flexible_offset(BufferPackingStandard packing) } } +static bool packing_is_scalar(BufferPackingStandard packing) +{ + switch (packing) + { + case BufferPackingScalar: + case BufferPackingScalarEnhancedLayout: + return true; + + default: + return false; + } +} + static BufferPackingStandard packing_to_substruct_packing(BufferPackingStandard packing) { switch (packing) @@ -124,6 +138,8 @@ static BufferPackingStandard packing_to_substruct_packing(BufferPackingStandard return BufferPackingStd430; case BufferPackingHLSLCbufferPackOffset: return BufferPackingHLSLCbuffer; + case BufferPackingScalarEnhancedLayout: + return BufferPackingScalar; default: return packing; } @@ -1045,6 +1061,10 @@ uint32_t CompilerGLSL::type_to_packed_alignment(const SPIRType &type, const Bits { const uint32_t base_alignment = type_to_packed_base_size(type, packing); + // Alignment requirement for scalar block layout is always the alignment for the most basic component. + if (packing_is_scalar(packing)) + return base_alignment; + // Vectors are *not* aligned in HLSL, but there's an extra rule where vectors cannot straddle // a vec4, this is handled outside since that part knows our current offset. if (type.columns == 1 && packing_is_hlsl(packing)) @@ -1168,27 +1188,34 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f { const uint32_t base_alignment = type_to_packed_base_size(type, packing); - if (type.columns == 1) - size = type.vecsize * base_alignment; - - if (flags.get(DecorationColMajor) && type.columns > 1) + if (packing_is_scalar(packing)) { - if (packing_is_vec4_padded(packing)) - size = type.columns * 4 * base_alignment; - else if (type.vecsize == 3) - size = type.columns * 4 * base_alignment; - else - size = type.columns * type.vecsize * base_alignment; + size = type.vecsize * type.columns * base_alignment; } - - if (flags.get(DecorationRowMajor) && type.vecsize > 1) + else { - if (packing_is_vec4_padded(packing)) - size = type.vecsize * 4 * base_alignment; - else if (type.columns == 3) - size = type.vecsize * 4 * base_alignment; - else - size = type.vecsize * type.columns * base_alignment; + if (type.columns == 1) + size = type.vecsize * base_alignment; + + if (flags.get(DecorationColMajor) && type.columns > 1) + { + if (packing_is_vec4_padded(packing)) + size = type.columns * 4 * base_alignment; + else if (type.vecsize == 3) + size = type.columns * 4 * base_alignment; + else + size = type.columns * type.vecsize * base_alignment; + } + + if (flags.get(DecorationRowMajor) && type.vecsize > 1) + { + if (packing_is_vec4_padded(packing)) + size = type.vecsize * 4 * base_alignment; + else if (type.columns == 3) + size = type.vecsize * 4 * base_alignment; + else + size = type.vecsize * type.columns * base_alignment; + } } } @@ -1436,37 +1463,11 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var) // If SPIR-V does not comply with either layout, we cannot really work around it. if (can_use_buffer_blocks && (ubo_block || emulated_ubo)) { - if (buffer_is_packing_standard(type, BufferPackingStd140)) - attr.push_back("std140"); - else if (buffer_is_packing_standard(type, BufferPackingStd140EnhancedLayout)) - { - attr.push_back("std140"); - // Fallback time. We might be able to use the ARB_enhanced_layouts to deal with this difference, - // however, we can only use layout(offset) on the block itself, not any substructs, so the substructs better be the appropriate layout. - // Enhanced layouts seem to always work in Vulkan GLSL, so no need for extensions there. - if (options.es && !options.vulkan_semantics) - SPIRV_CROSS_THROW("Uniform buffer block cannot be expressed as std140. ES-targets do " - "not support GL_ARB_enhanced_layouts."); - if (!options.es && !options.vulkan_semantics && options.version < 440) - require_extension_internal("GL_ARB_enhanced_layouts"); - - // This is a very last minute to check for this, but use this unused decoration to mark that we should emit - // explicit offsets for this block type. - // layout_for_variable() will be called before the actual buffer emit. - // The alternative is a full pass before codegen where we deduce this decoration, - // but then we are just doing the exact same work twice, and more complexity. - set_extended_decoration(type.self, SPIRVCrossDecorationPacked); - } - else - { - SPIRV_CROSS_THROW("Uniform buffer cannot be expressed as std140, even with enhanced layouts. You can try " - "flattening this block to " - "support a more flexible layout."); - } + attr.push_back(buffer_to_packing_standard(type, false)); } else if (can_use_buffer_blocks && (push_constant_block || ssbo_block)) { - attr.push_back(buffer_to_packing_standard(type)); + attr.push_back(buffer_to_packing_standard(type, true)); } // For images, the type itself adds a layout qualifer. @@ -1487,12 +1488,28 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var) return res; } -string CompilerGLSL::buffer_to_packing_standard(const SPIRType &type) +string CompilerGLSL::buffer_to_packing_standard(const SPIRType &type, bool check_std430) { - if (buffer_is_packing_standard(type, BufferPackingStd430)) + if (check_std430 && buffer_is_packing_standard(type, BufferPackingStd430)) return "std430"; else if (buffer_is_packing_standard(type, BufferPackingStd140)) return "std140"; + else if (options.vulkan_semantics && buffer_is_packing_standard(type, BufferPackingScalar)) + { + require_extension_internal("GL_EXT_scalar_block_layout"); + return "scalar"; + } + else if (check_std430 && buffer_is_packing_standard(type, BufferPackingStd430EnhancedLayout)) + { + if (options.es && !options.vulkan_semantics) + SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do " + "not support GL_ARB_enhanced_layouts."); + if (!options.es && !options.vulkan_semantics && options.version < 440) + require_extension_internal("GL_ARB_enhanced_layouts"); + + set_extended_decoration(type.self, SPIRVCrossDecorationPacked); + return "std430"; + } else if (buffer_is_packing_standard(type, BufferPackingStd140EnhancedLayout)) { // Fallback time. We might be able to use the ARB_enhanced_layouts to deal with this difference, @@ -1507,20 +1524,15 @@ string CompilerGLSL::buffer_to_packing_standard(const SPIRType &type) set_extended_decoration(type.self, SPIRVCrossDecorationPacked); return "std140"; } - else if (buffer_is_packing_standard(type, BufferPackingStd430EnhancedLayout)) + else if (options.vulkan_semantics && buffer_is_packing_standard(type, BufferPackingScalarEnhancedLayout)) { - if (options.es && !options.vulkan_semantics) - SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do " - "not support GL_ARB_enhanced_layouts."); - if (!options.es && !options.vulkan_semantics && options.version < 440) - require_extension_internal("GL_ARB_enhanced_layouts"); - set_extended_decoration(type.self, SPIRVCrossDecorationPacked); - return "std430"; + require_extension_internal("GL_EXT_scalar_block_layout"); + return "scalar"; } else { - SPIRV_CROSS_THROW("Buffer block cannot be expressed as neither std430 nor std140, even with enhanced " + SPIRV_CROSS_THROW("Buffer block cannot be expressed as any of std430, std140, scalar, even with enhanced " "layouts. You can try flattening this block to support a more flexible layout."); } } @@ -1644,7 +1656,7 @@ void CompilerGLSL::emit_buffer_reference_block(SPIRType &type, bool forward_decl if (!forward_declaration) { if (type.basetype == SPIRType::Struct) - statement("layout(buffer_reference, ", buffer_to_packing_standard(type), ") buffer ", buffer_name); + statement("layout(buffer_reference, ", buffer_to_packing_standard(type, true), ") buffer ", buffer_name); else statement("layout(buffer_reference) buffer ", buffer_name); diff --git a/spirv_glsl.hpp b/spirv_glsl.hpp index 3d0c7c9b..37012aa7 100644 --- a/spirv_glsl.hpp +++ b/spirv_glsl.hpp @@ -520,7 +520,7 @@ protected: bool buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing, uint32_t start_offset = 0, uint32_t end_offset = ~(0u)); - std::string buffer_to_packing_standard(const SPIRType &type); + std::string buffer_to_packing_standard(const SPIRType &type, bool enable_std430); uint32_t type_to_packed_base_size(const SPIRType &type, BufferPackingStandard packing); uint32_t type_to_packed_alignment(const SPIRType &type, const Bitset &flags, BufferPackingStandard packing);