From 2fba284b4e66cdb91b30b2acb3420a25f5418deb Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Mon, 23 Oct 2023 13:34:23 +0200 Subject: [PATCH] MSL: Improve handling of sample masks. --- .../frag/post-depth-coverage.ios.msl2.frag | 2 +- .../frag/post-depth-coverage.msl23.frag | 2 +- ...nd-out.fixed-sample-mask.force-sample.frag | 2 +- ...ple-mask-in-and-out.fixed-sample-mask.frag | 2 +- .../asm/frag/sample-mask-not-array.asm.frag | 45 ++++++++++++++++++- ...sample-mask-load-store-array-uint.asm.frag | 4 +- .../sample-mask-load-store-array.asm.frag | 4 +- .../frag/post-depth-coverage.ios.msl2.frag | 2 +- .../frag/post-depth-coverage.msl23.frag | 2 +- ...nd-out.fixed-sample-mask.force-sample.frag | 2 +- ...ple-mask-in-and-out.fixed-sample-mask.frag | 2 +- .../asm/frag/sample-mask-not-array.asm.frag | 45 ++++++++++++++++++- spirv_glsl.cpp | 7 +-- spirv_msl.cpp | 26 +++++++++-- 14 files changed, 124 insertions(+), 23 deletions(-) diff --git a/reference/opt/shaders-msl/frag/post-depth-coverage.ios.msl2.frag b/reference/opt/shaders-msl/frag/post-depth-coverage.ios.msl2.frag index 3b2885e2e..d40e2a344 100644 --- a/reference/opt/shaders-msl/frag/post-depth-coverage.ios.msl2.frag +++ b/reference/opt/shaders-msl/frag/post-depth-coverage.ios.msl2.frag @@ -11,7 +11,7 @@ struct main0_out [[ early_fragment_tests ]] fragment main0_out main0(uint gl_SampleMaskIn [[sample_mask, post_depth_coverage]]) { main0_out out = {}; - out.FragColor = float4(float(gl_SampleMaskIn)); + out.FragColor = float4(float(int(gl_SampleMaskIn))); return out; } diff --git a/reference/opt/shaders-msl/frag/post-depth-coverage.msl23.frag b/reference/opt/shaders-msl/frag/post-depth-coverage.msl23.frag index 3b2885e2e..d40e2a344 100644 --- a/reference/opt/shaders-msl/frag/post-depth-coverage.msl23.frag +++ b/reference/opt/shaders-msl/frag/post-depth-coverage.msl23.frag @@ -11,7 +11,7 @@ struct main0_out [[ early_fragment_tests ]] fragment main0_out main0(uint gl_SampleMaskIn [[sample_mask, post_depth_coverage]]) { main0_out out = {}; - out.FragColor = float4(float(gl_SampleMaskIn)); + out.FragColor = float4(float(int(gl_SampleMaskIn))); return out; } diff --git a/reference/opt/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.force-sample.frag b/reference/opt/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.force-sample.frag index 626fe4c79..aab186ed0 100644 --- a/reference/opt/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.force-sample.frag +++ b/reference/opt/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.force-sample.frag @@ -13,7 +13,7 @@ fragment main0_out main0(uint gl_SampleMaskIn [[sample_mask]], uint gl_SampleID { main0_out out = {}; out.FragColor = float4(1.0); - out.gl_SampleMask = (gl_SampleMaskIn & 0x22 & (1 << gl_SampleID)); + out.gl_SampleMask = int((gl_SampleMaskIn & 0x22 & (1 << gl_SampleID))); out.gl_SampleMask &= 0x22; return out; } diff --git a/reference/opt/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.frag b/reference/opt/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.frag index f478901b6..0f18da5de 100644 --- a/reference/opt/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.frag +++ b/reference/opt/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.frag @@ -13,7 +13,7 @@ fragment main0_out main0(uint gl_SampleMaskIn [[sample_mask]]) { main0_out out = {}; out.FragColor = float4(1.0); - out.gl_SampleMask = (gl_SampleMaskIn & 0x22); + out.gl_SampleMask = int((gl_SampleMaskIn & 0x22)); out.gl_SampleMask &= 0x22; return out; } diff --git a/reference/opt/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag b/reference/opt/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag index 790ad27a1..cbd9124cc 100644 --- a/reference/opt/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag +++ b/reference/opt/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag @@ -1,8 +1,49 @@ +#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 type_View { float4x4 View_TranslatedWorldToClip; @@ -489,12 +530,12 @@ fragment main0_out main0(main0_in in [[stage_in]], constant type_View& View [[bu if (View.View_NumSceneColorMSAASamples > 1) { _268 = _255 * float4(float(View.View_NumSceneColorMSAASamples) * 0.25); - _269 = gl_SampleMaskIn & 15u; + _269 = (spvUnsafeArray({ uint(gl_SampleMaskIn) }))[0] & 15u; } else { _268 = _255; - _269 = gl_SampleMaskIn; + _269 = (spvUnsafeArray({ uint(gl_SampleMaskIn) }))[0]; } out.out_var_SV_Target0 = _268; out.gl_SampleMask = _269; diff --git a/reference/shaders-msl-no-opt/asm/frag/sample-mask-load-store-array-uint.asm.frag b/reference/shaders-msl-no-opt/asm/frag/sample-mask-load-store-array-uint.asm.frag index 026ee28a5..083e36515 100644 --- a/reference/shaders-msl-no-opt/asm/frag/sample-mask-load-store-array-uint.asm.frag +++ b/reference/shaders-msl-no-opt/asm/frag/sample-mask-load-store-array-uint.asm.frag @@ -52,8 +52,8 @@ struct main0_out fragment main0_out main0(uint gl_SampleMaskIn [[sample_mask]]) { main0_out out = {}; - spvUnsafeArray copy_sample_mask = gl_SampleMaskIn; - out.gl_SampleMask = copy_sample_mask; + spvUnsafeArray copy_sample_mask = spvUnsafeArray({ uint(gl_SampleMaskIn) }); + out.gl_SampleMask = copy_sample_mask[0]; return out; } diff --git a/reference/shaders-msl-no-opt/asm/frag/sample-mask-load-store-array.asm.frag b/reference/shaders-msl-no-opt/asm/frag/sample-mask-load-store-array.asm.frag index b6ed48f75..6eb5ae710 100644 --- a/reference/shaders-msl-no-opt/asm/frag/sample-mask-load-store-array.asm.frag +++ b/reference/shaders-msl-no-opt/asm/frag/sample-mask-load-store-array.asm.frag @@ -52,8 +52,8 @@ struct main0_out fragment main0_out main0(uint gl_SampleMaskIn [[sample_mask]]) { main0_out out = {}; - spvUnsafeArray copy_sample_mask = gl_SampleMaskIn; - out.gl_SampleMask = copy_sample_mask; + spvUnsafeArray copy_sample_mask = spvUnsafeArray({ int(gl_SampleMaskIn) }); + out.gl_SampleMask = copy_sample_mask[0]; return out; } diff --git a/reference/shaders-msl/frag/post-depth-coverage.ios.msl2.frag b/reference/shaders-msl/frag/post-depth-coverage.ios.msl2.frag index 3b2885e2e..d40e2a344 100644 --- a/reference/shaders-msl/frag/post-depth-coverage.ios.msl2.frag +++ b/reference/shaders-msl/frag/post-depth-coverage.ios.msl2.frag @@ -11,7 +11,7 @@ struct main0_out [[ early_fragment_tests ]] fragment main0_out main0(uint gl_SampleMaskIn [[sample_mask, post_depth_coverage]]) { main0_out out = {}; - out.FragColor = float4(float(gl_SampleMaskIn)); + out.FragColor = float4(float(int(gl_SampleMaskIn))); return out; } diff --git a/reference/shaders-msl/frag/post-depth-coverage.msl23.frag b/reference/shaders-msl/frag/post-depth-coverage.msl23.frag index 3b2885e2e..d40e2a344 100644 --- a/reference/shaders-msl/frag/post-depth-coverage.msl23.frag +++ b/reference/shaders-msl/frag/post-depth-coverage.msl23.frag @@ -11,7 +11,7 @@ struct main0_out [[ early_fragment_tests ]] fragment main0_out main0(uint gl_SampleMaskIn [[sample_mask, post_depth_coverage]]) { main0_out out = {}; - out.FragColor = float4(float(gl_SampleMaskIn)); + out.FragColor = float4(float(int(gl_SampleMaskIn))); return out; } diff --git a/reference/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.force-sample.frag b/reference/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.force-sample.frag index 626fe4c79..aab186ed0 100644 --- a/reference/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.force-sample.frag +++ b/reference/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.force-sample.frag @@ -13,7 +13,7 @@ fragment main0_out main0(uint gl_SampleMaskIn [[sample_mask]], uint gl_SampleID { main0_out out = {}; out.FragColor = float4(1.0); - out.gl_SampleMask = (gl_SampleMaskIn & 0x22 & (1 << gl_SampleID)); + out.gl_SampleMask = int((gl_SampleMaskIn & 0x22 & (1 << gl_SampleID))); out.gl_SampleMask &= 0x22; return out; } diff --git a/reference/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.frag b/reference/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.frag index f478901b6..0f18da5de 100644 --- a/reference/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.frag +++ b/reference/shaders-msl/frag/sample-mask-in-and-out.fixed-sample-mask.frag @@ -13,7 +13,7 @@ fragment main0_out main0(uint gl_SampleMaskIn [[sample_mask]]) { main0_out out = {}; out.FragColor = float4(1.0); - out.gl_SampleMask = (gl_SampleMaskIn & 0x22); + out.gl_SampleMask = int((gl_SampleMaskIn & 0x22)); out.gl_SampleMask &= 0x22; return out; } diff --git a/reference/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag b/reference/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag index 72a9c58a6..90c944f34 100644 --- a/reference/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag +++ b/reference/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag @@ -1,8 +1,49 @@ +#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 type_View { float4x4 View_TranslatedWorldToClip; @@ -489,12 +530,12 @@ fragment main0_out main0(main0_in in [[stage_in]], constant type_View& View [[bu if (View.View_NumSceneColorMSAASamples > 1) { _268 = _255 * float4(float(View.View_NumSceneColorMSAASamples) * 0.25); - _269 = gl_SampleMaskIn & 15u; + _269 = (spvUnsafeArray({ uint(gl_SampleMaskIn) }))[0] & 15u; } else { _268 = _255; - _269 = gl_SampleMaskIn; + _269 = (spvUnsafeArray({ uint(gl_SampleMaskIn) }))[0]; } out.out_var_SV_Target0 = _268; out.gl_SampleMask = _269; diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index fa1e55bf0..ef87c012c 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -10158,10 +10158,11 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice if (!pending_array_enclose) expr += "]"; } - // Some builtins are arrays in SPIR-V but not in other languages, e.g. gl_SampleMask[] is an array in SPIR-V but not in Metal. - // By throwing away the index, we imply the index was 0, which it must be for gl_SampleMask. - else if (!builtin_translates_to_nonarray(BuiltIn(get_decoration(base, DecorationBuiltIn)))) + else if (index_is_literal || !builtin_translates_to_nonarray(BuiltIn(get_decoration(base, DecorationBuiltIn)))) { + // Some builtins are arrays in SPIR-V but not in other languages, e.g. gl_SampleMask[] is an array in SPIR-V but not in Metal. + // By throwing away the index, we imply the index was 0, which it must be for gl_SampleMask. + // For literal indices we are working on composites, so we ignore this since we have already converted to proper array. append_index(index, is_literal); } diff --git a/spirv_msl.cpp b/spirv_msl.cpp index 5605d1724..b52750e85 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -4911,9 +4911,18 @@ void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_exp bool transpose = lhs_e && lhs_e->need_transpose; - // No physical type remapping, and no packed type, so can just emit a store directly. - if (!lhs_remapped_type && !lhs_packed_type) + if (has_decoration(lhs_expression, DecorationBuiltIn) && + BuiltIn(get_decoration(lhs_expression, DecorationBuiltIn)) == BuiltInSampleMask && + type_is_top_level_array(type)) { + // Storing an array to SampleMask, have to remove the array-ness before storing. + statement(to_expression(lhs_expression), " = ", to_enclosed_unpacked_expression(rhs_expression), "[0];"); + register_write(lhs_expression); + } + else if (!lhs_remapped_type && !lhs_packed_type) + { + // No physical type remapping, and no packed type, so can just emit a store directly. + // We might not be dealing with remapped physical types or packed types, // but we might be doing a clean store to a row-major matrix. // In this case, we just flip transpose states, and emit the store, a transpose must be in the RHS expression, if any. @@ -17178,6 +17187,7 @@ void CompilerMSL::cast_from_variable_load(uint32_t source_id, std::string &expr, case BuiltInInstanceIndex: case BuiltInBaseInstance: case BuiltInBaseVertex: + case BuiltInSampleMask: expected_type = SPIRType::UInt; expected_width = 32; break; @@ -17195,9 +17205,17 @@ void CompilerMSL::cast_from_variable_load(uint32_t source_id, std::string &expr, break; } - if (expected_type != expr_type.basetype) + if (type_is_top_level_array(expr_type) && builtin == BuiltInSampleMask) + { + // Needs special handling. + auto wrap_expr = join(type_to_glsl(expr_type), "({ "); + wrap_expr += join(type_to_glsl(get(expr_type.parent_type)), "(", expr, ")"); + wrap_expr += " })"; + expr = std::move(wrap_expr); + } + else if (expected_type != expr_type.basetype) { - if (!expr_type.array.empty() && (builtin == BuiltInTessLevelInner || builtin == BuiltInTessLevelOuter)) + if (type_is_top_level_array(expr_type) && (builtin == BuiltInTessLevelInner || builtin == BuiltInTessLevelOuter)) { // Triggers when loading TessLevel directly as an array. // Need explicit padding + cast.