diff --git a/CMakeLists.txt b/CMakeLists.txt index da3e0ebf..7250603d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -323,7 +323,7 @@ if (SPIRV_CROSS_STATIC) endif() set(spirv-cross-abi-major 0) -set(spirv-cross-abi-minor 36) +set(spirv-cross-abi-minor 37) set(spirv-cross-abi-patch 0) if (SPIRV_CROSS_SHARED) diff --git a/main.cpp b/main.cpp index 578a5b0c..06d911fd 100644 --- a/main.cpp +++ b/main.cpp @@ -563,6 +563,7 @@ struct CLIArguments uint32_t msl_additional_fixed_sample_mask = 0xffffffff; bool glsl_emit_push_constant_as_ubo = false; bool glsl_emit_ubo_as_plain_uniforms = false; + bool glsl_force_flattened_io_blocks = false; SmallVector> glsl_ext_framebuffer_fetch; bool vulkan_glsl_disable_ext_samplerless_texture_functions = false; bool emit_line_directives = false; @@ -674,6 +675,7 @@ static void print_help_glsl() "\t[--no-420pack-extension]:\n\t\tDo not make use of GL_ARB_shading_language_420pack in older GL targets to support layout(binding).\n" "\t[--remap-variable-type ]:\n\t\tRemaps a variable type based on name.\n" "\t\tPrimary use case is supporting external samplers in ESSL for video rendering on Android where you could remap a texture to a YUV one.\n" + "\t[--glsl-force-flattened-io-blocks]:\n\t\tAlways flatten I/O blocks and structs.\n" ); // clang-format on } @@ -1131,6 +1133,7 @@ static string compile_iteration(const CLIArguments &args, std::vector opts.vertex.support_nonzero_base_instance = args.support_nonzero_baseinstance; opts.emit_push_constant_as_uniform_buffer = args.glsl_emit_push_constant_as_ubo; opts.emit_uniform_buffer_as_plain_uniforms = args.glsl_emit_ubo_as_plain_uniforms; + opts.force_flattened_io_blocks = args.glsl_force_flattened_io_blocks; opts.emit_line_directives = args.emit_line_directives; opts.enable_storage_image_qualifier_deduction = args.enable_storage_image_qualifier_deduction; opts.force_zero_initialized_variables = args.force_zero_initialized_variables; @@ -1319,6 +1322,7 @@ static int main_inner(int argc, char *argv[]) cbs.add("--metal", [&args](CLIParser &) { args.msl = true; }); // Legacy compatibility cbs.add("--glsl-emit-push-constant-as-ubo", [&args](CLIParser &) { args.glsl_emit_push_constant_as_ubo = true; }); cbs.add("--glsl-emit-ubo-as-plain-uniforms", [&args](CLIParser &) { args.glsl_emit_ubo_as_plain_uniforms = true; }); + cbs.add("--glsl-force-flattened-io-blocks", [&args](CLIParser &) { args.glsl_force_flattened_io_blocks = true; }); cbs.add("--glsl-remap-ext-framebuffer-fetch", [&args](CLIParser &parser) { uint32_t input_index = parser.next_uint(); uint32_t color_attachment = parser.next_uint(); diff --git a/reference/shaders-no-opt/vert/io-blocks.force-flattened-io.vert b/reference/shaders-no-opt/vert/io-blocks.force-flattened-io.vert new file mode 100644 index 00000000..604de8a2 --- /dev/null +++ b/reference/shaders-no-opt/vert/io-blocks.force-flattened-io.vert @@ -0,0 +1,25 @@ +#version 450 + +struct Foo +{ + vec4 bar[2]; + vec4 baz[2]; +}; + +out vec4 _14_foo_bar[2]; +out vec4 _14_foo_baz[2]; +out vec4 _14_foo2_bar[2]; +out vec4 _14_foo2_baz[2]; +out vec4 foo3_bar[2]; +out vec4 foo3_baz[2]; + +void main() +{ + _14_foo_bar[0] = vec4(1.0); + _14_foo_baz[1] = vec4(2.0); + _14_foo2_bar[0] = vec4(3.0); + _14_foo2_baz[1] = vec4(4.0); + foo3_bar[0] = vec4(5.0); + foo3_baz[1] = vec4(6.0); +} + diff --git a/shaders-no-opt/vert/io-blocks.force-flattened-io.vert b/shaders-no-opt/vert/io-blocks.force-flattened-io.vert new file mode 100644 index 00000000..e308a9f2 --- /dev/null +++ b/shaders-no-opt/vert/io-blocks.force-flattened-io.vert @@ -0,0 +1,25 @@ +#version 450 + +struct Foo +{ + vec4 bar[2]; + vec4 baz[2]; +}; + +layout(location = 0) out Vertex +{ + Foo foo; + Foo foo2; +}; + +layout(location = 8) out Foo foo3; + +void main() +{ + foo.bar[0] = vec4(1.0); + foo.baz[1] = vec4(2.0); + foo2.bar[0] = vec4(3.0); + foo2.baz[1] = vec4(4.0); + foo3.bar[0] = vec4(5.0); + foo3.baz[1] = vec4(6.0); +} diff --git a/spirv_cross_c.cpp b/spirv_cross_c.cpp index c7d1361b..d1d759f8 100644 --- a/spirv_cross_c.cpp +++ b/spirv_cross_c.cpp @@ -459,6 +459,9 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c case SPVC_COMPILER_OPTION_GLSL_EMIT_UNIFORM_BUFFER_AS_PLAIN_UNIFORMS: options->glsl.emit_uniform_buffer_as_plain_uniforms = value != 0; break; + case SPVC_COMPILER_OPTION_GLSL_FORCE_FLATTENED_IO_BLOCKS: + options->glsl.force_flattened_io_blocks = value != 0; + break; #endif #if SPIRV_CROSS_C_API_HLSL diff --git a/spirv_cross_c.h b/spirv_cross_c.h index 0ea8bf69..e8d1397a 100644 --- a/spirv_cross_c.h +++ b/spirv_cross_c.h @@ -33,7 +33,7 @@ extern "C" { /* Bumped if ABI or API breaks backwards compatibility. */ #define SPVC_C_API_VERSION_MAJOR 0 /* Bumped if APIs or enumerations are added in a backwards compatible way. */ -#define SPVC_C_API_VERSION_MINOR 36 +#define SPVC_C_API_VERSION_MINOR 37 /* Bumped if internal implementation details change. */ #define SPVC_C_API_VERSION_PATCH 0 @@ -634,6 +634,8 @@ typedef enum spvc_compiler_option SPVC_COMPILER_OPTION_MSL_VERTEX_FOR_TESSELLATION = 64 | SPVC_COMPILER_OPTION_MSL_BIT, SPVC_COMPILER_OPTION_MSL_VERTEX_INDEX_TYPE = 65 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_GLSL_FORCE_FLATTENED_IO_BLOCKS = 66 | SPVC_COMPILER_OPTION_GLSL_BIT, + SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff } spvc_compiler_option; diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index 72a9e93b..dc733065 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -2232,7 +2232,8 @@ void CompilerGLSL::emit_interface_block(const SPIRVariable &var) // ESSL earlier than 310 and GLSL earlier than 150 did not support // I/O variables which are struct types. // To support this, flatten the struct into separate varyings instead. - if ((options.es && options.version < 310) || (!options.es && options.version < 150)) + if (options.force_flattened_io_blocks || (options.es && options.version < 310) || + (!options.es && options.version < 150)) { // I/O blocks on ES require version 310 with Android Extension Pack extensions, or core version 320. // On desktop, I/O blocks were introduced with geometry shaders in GL 3.2 (GLSL 150). @@ -2292,7 +2293,8 @@ void CompilerGLSL::emit_interface_block(const SPIRVariable &var) // I/O variables which are struct types. // To support this, flatten the struct into separate varyings instead. if (type.basetype == SPIRType::Struct && - ((options.es && options.version < 310) || (!options.es && options.version < 150))) + (options.force_flattened_io_blocks || (options.es && options.version < 310) || + (!options.es && options.version < 150))) { emit_flattened_io_block(var, qual); } diff --git a/spirv_glsl.hpp b/spirv_glsl.hpp index 5f6227f8..c3837434 100644 --- a/spirv_glsl.hpp +++ b/spirv_glsl.hpp @@ -121,6 +121,10 @@ public: // which would otherwise be uninitialized will now be initialized to 0 instead. bool force_zero_initialized_variables = false; + // In GLSL, force use of I/O block flattening, similar to + // what happens on legacy GLSL targets for blocks and structs. + bool force_flattened_io_blocks = false; + enum Precision { DontCare, diff --git a/test_shaders.py b/test_shaders.py index ea208123..d647f5d7 100755 --- a/test_shaders.py +++ b/test_shaders.py @@ -501,6 +501,8 @@ def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, fl extra_args += ['--glsl-remap-ext-framebuffer-fetch', '3', '3'] if '.zero-initialize.' in shader: extra_args += ['--force-zero-initialized-variables'] + if '.force-flattened-io.' in shader: + extra_args += ['--glsl-force-flattened-io-blocks'] spirv_cross_path = paths.spirv_cross