From cab7335e649922695a316d2f299b71c244a88dd3 Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Sun, 23 Aug 2020 16:44:41 -0500 Subject: [PATCH] MSL: Don't set the layer for multiview if the device doesn't support it. Some older iOS devices don't support layered rendering. In that case, don't set `[[render_target_array_index]]`, because the compiler will reject the shader in that case. The client will then have to unroll the render pass manually. --- CMakeLists.txt | 2 +- main.cpp | 6 ++ ...asic.multiview.no-layered.nocompat.vk.frag | 73 +++++++++++++++++++ ...view.multiview.no-layered.nocompat.vk.vert | 28 +++++++ ...asic.multiview.no-layered.nocompat.vk.frag | 73 +++++++++++++++++++ ...view.multiview.no-layered.nocompat.vk.vert | 28 +++++++ ...asic.multiview.no-layered.nocompat.vk.frag | 14 ++++ ...view.multiview.no-layered.nocompat.vk.vert | 14 ++++ spirv_cross_c.cpp | 4 + spirv_cross_c.h | 4 +- spirv_msl.cpp | 15 +++- spirv_msl.hpp | 1 + test_shaders.py | 2 + 13 files changed, 260 insertions(+), 4 deletions(-) create mode 100644 reference/opt/shaders-msl/vulkan/frag/basic.multiview.no-layered.nocompat.vk.frag create mode 100644 reference/opt/shaders-msl/vulkan/vert/multiview.multiview.no-layered.nocompat.vk.vert create mode 100644 reference/shaders-msl/vulkan/frag/basic.multiview.no-layered.nocompat.vk.frag create mode 100644 reference/shaders-msl/vulkan/vert/multiview.multiview.no-layered.nocompat.vk.vert create mode 100644 shaders-msl/vulkan/frag/basic.multiview.no-layered.nocompat.vk.frag create mode 100644 shaders-msl/vulkan/vert/multiview.multiview.no-layered.nocompat.vk.vert diff --git a/CMakeLists.txt b/CMakeLists.txt index 7250603d..214672d7 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 37) +set(spirv-cross-abi-minor 38) set(spirv-cross-abi-patch 0) if (SPIRV_CROSS_SHARED) diff --git a/main.cpp b/main.cpp index 06d911fd..c1098184 100644 --- a/main.cpp +++ b/main.cpp @@ -549,6 +549,7 @@ struct CLIArguments bool msl_invariant_float_math = false; bool msl_emulate_cube_array = false; bool msl_multiview = false; + bool msl_multiview_layered_rendering = true; bool msl_view_index_from_device_index = false; bool msl_dispatch_base = false; bool msl_decoration_binding = false; @@ -732,6 +733,8 @@ static void print_help_msl() "\t[--msl-device-argument-buffer ]:\n\t\tUse device address space to hold indirect argument buffers instead of constant.\n" "\t\tComes up when trying to support argument buffers which are larger than 64 KiB.\n" "\t[--msl-multiview]:\n\t\tEnable SPV_KHR_multiview emulation.\n" + "\t[--msl-multiview-no-layered-rendering]:\n\t\tDon't set [[render_target_array_index]] in multiview shaders.\n" + "\t\tUseful for devices which don't support layered rendering. Only effective when --msl-multiview is enabled.\n" "\t[--msl-view-index-from-device-index]:\n\t\tTreat the view index as the device index instead.\n" "\t\tFor multi-GPU rendering.\n" "\t[--msl-dispatch-base]:\n\t\tAdd support for vkCmdDispatchBase() or similar APIs.\n" @@ -987,6 +990,7 @@ static string compile_iteration(const CLIArguments &args, std::vector msl_opts.argument_buffers = args.msl_argument_buffers; msl_opts.texture_buffer_native = args.msl_texture_buffer_native; msl_opts.multiview = args.msl_multiview; + msl_opts.multiview_layered_rendering = args.msl_multiview_layered_rendering; msl_opts.view_index_from_device_index = args.msl_view_index_from_device_index; msl_opts.dispatch_base = args.msl_dispatch_base; msl_opts.enable_decoration_binding = args.msl_decoration_binding; @@ -1366,6 +1370,8 @@ static int main_inner(int argc, char *argv[]) cbs.add("--msl-invariant-float-math", [&args](CLIParser &) { args.msl_invariant_float_math = true; }); cbs.add("--msl-emulate-cube-array", [&args](CLIParser &) { args.msl_emulate_cube_array = true; }); cbs.add("--msl-multiview", [&args](CLIParser &) { args.msl_multiview = true; }); + cbs.add("--msl-multiview-no-layered-rendering", + [&args](CLIParser &) { args.msl_multiview_layered_rendering = false; }); cbs.add("--msl-view-index-from-device-index", [&args](CLIParser &) { args.msl_view_index_from_device_index = true; }); cbs.add("--msl-dispatch-base", [&args](CLIParser &) { args.msl_dispatch_base = true; }); diff --git a/reference/opt/shaders-msl/vulkan/frag/basic.multiview.no-layered.nocompat.vk.frag b/reference/opt/shaders-msl/vulkan/frag/basic.multiview.no-layered.nocompat.vk.frag new file mode 100644 index 00000000..f0935f6d --- /dev/null +++ b/reference/opt/shaders-msl/vulkan/frag/basic.multiview.no-layered.nocompat.vk.frag @@ -0,0 +1,73 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + float4 vColor [[user(locn0)]]; + float2 vTex_0 [[user(locn1)]]; + float2 vTex_1 [[user(locn2)]]; + float2 vTex_2 [[user(locn3)]]; + float2 vTex_3 [[user(locn4)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant uint* spvViewMask [[buffer(24)]], texture2d uTex [[texture(0)]], sampler uTexSmplr [[sampler(0)]]) +{ + main0_out out = {}; + spvUnsafeArray vTex = {}; + vTex[0] = in.vTex_0; + vTex[1] = in.vTex_1; + vTex[2] = in.vTex_2; + vTex[3] = in.vTex_3; + const uint gl_ViewIndex = spvViewMask[0]; + out.FragColor = in.vColor * uTex.sample(uTexSmplr, vTex[int(gl_ViewIndex)]); + return out; +} + diff --git a/reference/opt/shaders-msl/vulkan/vert/multiview.multiview.no-layered.nocompat.vk.vert b/reference/opt/shaders-msl/vulkan/vert/multiview.multiview.no-layered.nocompat.vk.vert new file mode 100644 index 00000000..8959afe8 --- /dev/null +++ b/reference/opt/shaders-msl/vulkan/vert/multiview.multiview.no-layered.nocompat.vk.vert @@ -0,0 +1,28 @@ +#include +#include + +using namespace metal; + +struct MVPs +{ + float4x4 MVP[2]; +}; + +struct main0_out +{ + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 Position [[attribute(0)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]], constant uint* spvViewMask [[buffer(24)]], constant MVPs& _19 [[buffer(0)]]) +{ + main0_out out = {}; + const uint gl_ViewIndex = spvViewMask[0]; + out.gl_Position = _19.MVP[int(gl_ViewIndex)] * in.Position; + return out; +} + diff --git a/reference/shaders-msl/vulkan/frag/basic.multiview.no-layered.nocompat.vk.frag b/reference/shaders-msl/vulkan/frag/basic.multiview.no-layered.nocompat.vk.frag new file mode 100644 index 00000000..f0935f6d --- /dev/null +++ b/reference/shaders-msl/vulkan/frag/basic.multiview.no-layered.nocompat.vk.frag @@ -0,0 +1,73 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + float4 vColor [[user(locn0)]]; + float2 vTex_0 [[user(locn1)]]; + float2 vTex_1 [[user(locn2)]]; + float2 vTex_2 [[user(locn3)]]; + float2 vTex_3 [[user(locn4)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant uint* spvViewMask [[buffer(24)]], texture2d uTex [[texture(0)]], sampler uTexSmplr [[sampler(0)]]) +{ + main0_out out = {}; + spvUnsafeArray vTex = {}; + vTex[0] = in.vTex_0; + vTex[1] = in.vTex_1; + vTex[2] = in.vTex_2; + vTex[3] = in.vTex_3; + const uint gl_ViewIndex = spvViewMask[0]; + out.FragColor = in.vColor * uTex.sample(uTexSmplr, vTex[int(gl_ViewIndex)]); + return out; +} + diff --git a/reference/shaders-msl/vulkan/vert/multiview.multiview.no-layered.nocompat.vk.vert b/reference/shaders-msl/vulkan/vert/multiview.multiview.no-layered.nocompat.vk.vert new file mode 100644 index 00000000..8959afe8 --- /dev/null +++ b/reference/shaders-msl/vulkan/vert/multiview.multiview.no-layered.nocompat.vk.vert @@ -0,0 +1,28 @@ +#include +#include + +using namespace metal; + +struct MVPs +{ + float4x4 MVP[2]; +}; + +struct main0_out +{ + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 Position [[attribute(0)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]], constant uint* spvViewMask [[buffer(24)]], constant MVPs& _19 [[buffer(0)]]) +{ + main0_out out = {}; + const uint gl_ViewIndex = spvViewMask[0]; + out.gl_Position = _19.MVP[int(gl_ViewIndex)] * in.Position; + return out; +} + diff --git a/shaders-msl/vulkan/frag/basic.multiview.no-layered.nocompat.vk.frag b/shaders-msl/vulkan/frag/basic.multiview.no-layered.nocompat.vk.frag new file mode 100644 index 00000000..963493b8 --- /dev/null +++ b/shaders-msl/vulkan/frag/basic.multiview.no-layered.nocompat.vk.frag @@ -0,0 +1,14 @@ +#version 310 es +#extension GL_EXT_multiview : require +precision mediump float; + +layout(location = 0) in vec4 vColor; +layout(location = 1) in vec2 vTex[4]; +layout(binding = 0) uniform sampler2D uTex; +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = vColor * texture(uTex, vTex[gl_ViewIndex]); +} + diff --git a/shaders-msl/vulkan/vert/multiview.multiview.no-layered.nocompat.vk.vert b/shaders-msl/vulkan/vert/multiview.multiview.no-layered.nocompat.vk.vert new file mode 100644 index 00000000..eb1bc766 --- /dev/null +++ b/shaders-msl/vulkan/vert/multiview.multiview.no-layered.nocompat.vk.vert @@ -0,0 +1,14 @@ +#version 310 es +#extension GL_EXT_multiview : require + +layout(std140, binding = 0) uniform MVPs +{ + mat4 MVP[2]; +}; + +layout(location = 0) in vec4 Position; + +void main() +{ + gl_Position = MVP[gl_ViewIndex] * Position; +} diff --git a/spirv_cross_c.cpp b/spirv_cross_c.cpp index d1d759f8..7cf79392 100644 --- a/spirv_cross_c.cpp +++ b/spirv_cross_c.cpp @@ -658,6 +658,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c case SPVC_COMPILER_OPTION_MSL_VERTEX_INDEX_TYPE: options->msl.vertex_index_type = static_cast(value); break; + + case SPVC_COMPILER_OPTION_MSL_MULTIVIEW_LAYERED_RENDERING: + options->msl.multiview_layered_rendering = value != 0; + break; #endif default: diff --git a/spirv_cross_c.h b/spirv_cross_c.h index e8d1397a..bb199144 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 37 +#define SPVC_C_API_VERSION_MINOR 38 /* Bumped if internal implementation details change. */ #define SPVC_C_API_VERSION_PATCH 0 @@ -636,6 +636,8 @@ typedef enum spvc_compiler_option SPVC_COMPILER_OPTION_GLSL_FORCE_FLATTENED_IO_BLOCKS = 66 | SPVC_COMPILER_OPTION_GLSL_BIT, + SPVC_COMPILER_OPTION_MSL_MULTIVIEW_LAYERED_RENDERING = 67 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff } spvc_compiler_option; diff --git a/spirv_msl.cpp b/spirv_msl.cpp index 50bcf6aa..bd844b8f 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -146,6 +146,7 @@ void CompilerMSL::build_implicit_builtins() bool need_subgroup_ge_mask = !msl_options.is_ios() && (active_input_builtins.get(BuiltInSubgroupGeMask) || active_input_builtins.get(BuiltInSubgroupGtMask)); bool need_multiview = get_execution_model() == ExecutionModelVertex && !msl_options.view_index_from_device_index && + msl_options.multiview_layered_rendering && (msl_options.multiview || active_input_builtins.get(BuiltInViewIndex)); bool need_dispatch_base = msl_options.dispatch_base && get_execution_model() == ExecutionModelGLCompute && @@ -9242,7 +9243,7 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in switch (builtin) { case BuiltInViewIndex: - if (!msl_options.multiview) + if (!msl_options.multiview || !msl_options.multiview_layered_rendering) break; /* fallthrough */ case BuiltInFrontFacing: @@ -9660,7 +9661,8 @@ bool CompilerMSL::is_direct_input_builtin(BuiltIn bi_type) case BuiltInBaryCoordNoPerspNV: return false; case BuiltInViewIndex: - return get_execution_model() == ExecutionModelFragment && msl_options.multiview; + return get_execution_model() == ExecutionModelFragment && msl_options.multiview && + msl_options.multiview_layered_rendering; // Any stage function in case BuiltInDeviceIndex: case BuiltInSubgroupEqMask: @@ -10430,6 +10432,15 @@ void CompilerMSL::fix_up_shader_inputs_outputs() // Since every physical device is rendering a different view, // there's no need for layered rendering here. } + else if (!msl_options.multiview_layered_rendering) + { + // In this case, the views are rendered one at a time. The view index, then, + // is just the first part of the "view mask". + entry_func.fixup_hooks_in.push_back([=]() { + statement("const ", builtin_type_decl(bi_type), " ", to_expression(var_id), " = ", + to_expression(view_mask_buffer_id), "[0];"); + }); + } else if (get_execution_model() == ExecutionModelFragment) { // Because we adjusted the view index in the vertex shader, we have to diff --git a/spirv_msl.hpp b/spirv_msl.hpp index 2d4b0be7..9098d830 100644 --- a/spirv_msl.hpp +++ b/spirv_msl.hpp @@ -290,6 +290,7 @@ public: bool swizzle_texture_samples = false; bool tess_domain_origin_lower_left = false; bool multiview = false; + bool multiview_layered_rendering = true; bool view_index_from_device_index = false; bool dispatch_base = false; bool texture_1D_as_2D = false; diff --git a/test_shaders.py b/test_shaders.py index d647f5d7..71e9361f 100755 --- a/test_shaders.py +++ b/test_shaders.py @@ -232,6 +232,8 @@ def cross_compile_msl(shader, spirv, opt, iterations, paths): msl_args.append('--emit-line-directives') if '.multiview.' in shader: msl_args.append('--msl-multiview') + if '.no-layered.' in shader: + msl_args.append('--msl-multiview-no-layered-rendering') if '.viewfromdev.' in shader: msl_args.append('--msl-view-index-from-device-index') if '.dispatchbase.' in shader: