diff options
author | Hans-Kristian Arntzen <post@arntzen-software.no> | 2022-03-04 14:36:21 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-04 14:36:21 +0300 |
commit | a1803778c2c88078bffd2642c3c9f95fab56d0a5 (patch) | |
tree | a77554382a3fb2de1d20ea0b4d0912df7c1feba2 | |
parent | 6c7a40822f0f55d4045e3e854d25c0466eb64e9b (diff) | |
parent | b192b8887a5f0d53c8ebd66407346c52f82f075b (diff) |
Merge pull request #1885 from KhronosGroup/helper-invocation-rework
Helper invocation rework
15 files changed, 218 insertions, 27 deletions
diff --git a/reference/opt/shaders-msl/frag/helper-invocation.msl21.frag b/reference/opt/shaders-msl/frag/helper-invocation.msl21.frag index a833fa08..9d876df1 100644 --- a/reference/opt/shaders-msl/frag/helper-invocation.msl21.frag +++ b/reference/opt/shaders-msl/frag/helper-invocation.msl21.frag @@ -16,9 +16,8 @@ struct main0_in fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> uSampler [[texture(0)]], sampler uSamplerSmplr [[sampler(0)]]) { main0_out out = {}; - bool gl_HelperInvocation = simd_is_helper_thread(); float4 _52; - if (!gl_HelperInvocation) + if (!simd_is_helper_thread()) { _52 = uSampler.sample(uSamplerSmplr, in.vUV, level(0.0)); } diff --git a/reference/shaders-hlsl-no-opt/frag/helper-invocation.fxconly.nofxc.frag b/reference/shaders-hlsl-no-opt/frag/helper-invocation.fxconly.nofxc.frag new file mode 100644 index 00000000..ad61b21e --- /dev/null +++ b/reference/shaders-hlsl-no-opt/frag/helper-invocation.fxconly.nofxc.frag @@ -0,0 +1,26 @@ +static float FragColor; + +struct SPIRV_Cross_Input +{ +}; + +struct SPIRV_Cross_Output +{ + float FragColor : SV_Target0; +}; + +void frag_main() +{ + FragColor = float(IsHelperLane()); + discard; + bool _16 = IsHelperLane(); + FragColor = float(_16); +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/reference/shaders-hlsl-no-opt/frag/volatile-helper-invocation.fxconly.nofxc.spv16.frag b/reference/shaders-hlsl-no-opt/frag/volatile-helper-invocation.fxconly.nofxc.spv16.frag new file mode 100644 index 00000000..1311c863 --- /dev/null +++ b/reference/shaders-hlsl-no-opt/frag/volatile-helper-invocation.fxconly.nofxc.spv16.frag @@ -0,0 +1,29 @@ +static float FragColor; + +struct SPIRV_Cross_Input +{ +}; + +struct SPIRV_Cross_Output +{ + float FragColor : SV_Target0; +}; + +void frag_main() +{ + bool _12 = IsHelperLane(); + float _15 = float(_12); + FragColor = _15; + discard; + bool _16 = IsHelperLane(); + float _17 = float(_16); + FragColor = _17; +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/reference/shaders-msl-no-opt/frag/volatile-helper-invocation.msl23.spv16.frag b/reference/shaders-msl-no-opt/frag/volatile-helper-invocation.msl23.spv16.frag new file mode 100644 index 00000000..eef92efe --- /dev/null +++ b/reference/shaders-msl-no-opt/frag/volatile-helper-invocation.msl23.spv16.frag @@ -0,0 +1,23 @@ +#include <metal_stdlib> +#include <simd/simd.h> + +using namespace metal; + +struct main0_out +{ + float FragColor [[color(0)]]; +}; + +fragment main0_out main0() +{ + main0_out out = {}; + bool _12 = simd_is_helper_thread(); + float _15 = float(_12); + out.FragColor = _15; + discard_fragment(); + bool _16 = simd_is_helper_thread(); + float _17 = float(_16); + out.FragColor = _17; + return out; +} + diff --git a/reference/shaders-msl/frag/helper-invocation.msl21.frag b/reference/shaders-msl/frag/helper-invocation.msl21.frag index 7cf97a25..36d14239 100644 --- a/reference/shaders-msl/frag/helper-invocation.msl21.frag +++ b/reference/shaders-msl/frag/helper-invocation.msl21.frag @@ -16,10 +16,10 @@ struct main0_in }; static inline __attribute__((always_inline)) -float4 foo(thread bool& gl_HelperInvocation, texture2d<float> uSampler, sampler uSamplerSmplr, thread float2& vUV) +float4 foo(texture2d<float> uSampler, sampler uSamplerSmplr, thread float2& vUV) { float4 color; - if (!gl_HelperInvocation) + if (!simd_is_helper_thread()) { color = uSampler.sample(uSamplerSmplr, vUV, level(0.0)); } @@ -33,8 +33,7 @@ float4 foo(thread bool& gl_HelperInvocation, texture2d<float> uSampler, sampler fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> uSampler [[texture(0)]], sampler uSamplerSmplr [[sampler(0)]]) { main0_out out = {}; - bool gl_HelperInvocation = simd_is_helper_thread(); - out.FragColor = foo(gl_HelperInvocation, uSampler, uSamplerSmplr, in.vUV); + out.FragColor = foo(uSampler, uSamplerSmplr, in.vUV); return out; } diff --git a/reference/shaders-no-opt/vulkan/frag/volatile-helper-invocation.vk.nocompat.spv16.frag.vk b/reference/shaders-no-opt/vulkan/frag/volatile-helper-invocation.vk.nocompat.spv16.frag.vk new file mode 100644 index 00000000..73b0f9b0 --- /dev/null +++ b/reference/shaders-no-opt/vulkan/frag/volatile-helper-invocation.vk.nocompat.spv16.frag.vk @@ -0,0 +1,16 @@ +#version 450 +#extension GL_EXT_demote_to_helper_invocation : require + +layout(location = 0) out float FragColor; + +void main() +{ + bool _12 = gl_HelperInvocation; + float _15 = float(_12); + FragColor = _15; + demote; + bool _16 = gl_HelperInvocation; + float _17 = float(_16); + FragColor = _17; +} + diff --git a/shaders-hlsl-no-opt/frag/helper-invocation.fxconly.nofxc.frag b/shaders-hlsl-no-opt/frag/helper-invocation.fxconly.nofxc.frag new file mode 100644 index 00000000..6f70c772 --- /dev/null +++ b/shaders-hlsl-no-opt/frag/helper-invocation.fxconly.nofxc.frag @@ -0,0 +1,11 @@ +#version 450 +#extension GL_EXT_demote_to_helper_invocation : require + +layout(location = 0) out float FragColor; + +void main() +{ + FragColor = float(gl_HelperInvocation); + demote; + FragColor = float(helperInvocationEXT()); +} diff --git a/shaders-hlsl-no-opt/frag/volatile-helper-invocation.fxconly.nofxc.spv16.frag b/shaders-hlsl-no-opt/frag/volatile-helper-invocation.fxconly.nofxc.spv16.frag new file mode 100644 index 00000000..9a8d9d20 --- /dev/null +++ b/shaders-hlsl-no-opt/frag/volatile-helper-invocation.fxconly.nofxc.spv16.frag @@ -0,0 +1,11 @@ +#version 450 +#extension GL_EXT_demote_to_helper_invocation : require + +layout(location = 0) out float FragColor; + +void main() +{ + FragColor = float(gl_HelperInvocation); + demote; + FragColor = float(gl_HelperInvocation); +} diff --git a/shaders-msl-no-opt/frag/volatile-helper-invocation.msl23.spv16.frag b/shaders-msl-no-opt/frag/volatile-helper-invocation.msl23.spv16.frag new file mode 100644 index 00000000..9a8d9d20 --- /dev/null +++ b/shaders-msl-no-opt/frag/volatile-helper-invocation.msl23.spv16.frag @@ -0,0 +1,11 @@ +#version 450 +#extension GL_EXT_demote_to_helper_invocation : require + +layout(location = 0) out float FragColor; + +void main() +{ + FragColor = float(gl_HelperInvocation); + demote; + FragColor = float(gl_HelperInvocation); +} diff --git a/shaders-no-opt/vulkan/frag/volatile-helper-invocation.vk.nocompat.spv16.frag b/shaders-no-opt/vulkan/frag/volatile-helper-invocation.vk.nocompat.spv16.frag new file mode 100644 index 00000000..9a8d9d20 --- /dev/null +++ b/shaders-no-opt/vulkan/frag/volatile-helper-invocation.vk.nocompat.spv16.frag @@ -0,0 +1,11 @@ +#version 450 +#extension GL_EXT_demote_to_helper_invocation : require + +layout(location = 0) out float FragColor; + +void main() +{ + FragColor = float(gl_HelperInvocation); + demote; + FragColor = float(gl_HelperInvocation); +} diff --git a/spirv_common.hpp b/spirv_common.hpp index f568d7dc..4aaa7148 100644 --- a/spirv_common.hpp +++ b/spirv_common.hpp @@ -1072,7 +1072,6 @@ struct SPIRVariable : IVariant // Temporaries which can remain forwarded as long as this variable is not modified. SmallVector<ID> dependees; - bool forwardable = true; bool deferred_declaration = false; bool phi_variable = false; diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index 4c465133..52cef4ec 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -9585,8 +9585,11 @@ bool CompilerGLSL::should_forward(uint32_t id) const // This is important because otherwise we'll get local sampler copies (highp sampler2D foo = bar) that are invalid in OpenGL GLSL auto *var = maybe_get<SPIRVariable>(id); - if (var && var->forwardable) - return true; + if (var) + { + // Never forward volatile variables, e.g. SPIR-V 1.6 IsHelperInvocation. + return !has_decoration(id, DecorationVolatile); + } // For debugging emit temporary variables for all expressions if (options.force_temporary) @@ -9599,6 +9602,12 @@ bool CompilerGLSL::should_forward(uint32_t id) const if (expr && expr->expression_dependencies.size() >= max_expression_dependencies) return false; + if (expr && expr->loaded_from && has_decoration(expr->loaded_from, DecorationVolatile)) + { + // Never forward volatile variables. + return false; + } + // Immutable expression can always be forwarded. if (is_immutable(id)) return true; @@ -12089,7 +12098,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) pure = false; } - if (var && var->forwardable) + if (var) { bool forward = forced_temporaries.find(id) == end(forced_temporaries); auto &e = emit_op(result_type, id, imgexpr, forward); @@ -12850,6 +12859,8 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) if (!options.vulkan_semantics) SPIRV_CROSS_THROW("GL_EXT_demote_to_helper_invocation is only supported in Vulkan GLSL."); require_extension_internal("GL_EXT_demote_to_helper_invocation"); + // Helper lane state with demote is volatile by nature. + // Do not forward this. emit_op(ops[0], ops[1], "helperInvocationEXT()", false); break; diff --git a/spirv_hlsl.cpp b/spirv_hlsl.cpp index 646fce33..253d6ad0 100644 --- a/spirv_hlsl.cpp +++ b/spirv_hlsl.cpp @@ -728,6 +728,11 @@ void CompilerHLSL::emit_builtin_inputs_in_struct() // Handled specially. break; + case BuiltInHelperInvocation: + if (hlsl_options.shader_model < 50 || (get_entry_point().model != ExecutionModelFragment && get_entry_point().model != ExecutionModelGLCompute)) + SPIRV_CROSS_THROW("Helper Invocation input is only supported in PS 5.0 or higher."); + break; + case BuiltInClipDistance: // HLSL is a bit weird here, use SV_ClipDistance0, SV_ClipDistance1 and so on with vectors. for (uint32_t clip = 0; clip < clip_distance_count; clip += 4) @@ -984,6 +989,8 @@ std::string CompilerHLSL::builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClas return "WaveGetLaneIndex()"; case BuiltInSubgroupSize: return "WaveGetLaneCount()"; + case BuiltInHelperInvocation: + return "IsHelperLane()"; default: return CompilerGLSL::builtin_to_glsl(builtin, storage); @@ -1103,6 +1110,11 @@ void CompilerHLSL::emit_builtin_variables() type = "uint4"; break; + case BuiltInHelperInvocation: + if (hlsl_options.shader_model < 50) + SPIRV_CROSS_THROW("Need SM 5.0 for Helper Invocation."); + break; + case BuiltInClipDistance: array_size = clip_distance_count; type = "float"; @@ -2521,6 +2533,7 @@ void CompilerHLSL::emit_hlsl_entry_point() case BuiltInPointCoord: case BuiltInSubgroupSize: case BuiltInSubgroupLocalInvocationId: + case BuiltInHelperInvocation: break; case BuiltInSubgroupEqMask: @@ -5346,7 +5359,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) image_format_to_components(get<SPIRType>(var->basetype).image.format), imgexpr); } - if (var && var->forwardable) + if (var) { bool forward = forced_temporaries.find(id) == end(forced_temporaries); auto &e = emit_op(result_type, id, imgexpr, forward); @@ -5590,7 +5603,12 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) } case OpIsHelperInvocationEXT: - SPIRV_CROSS_THROW("helperInvocationEXT() is not supported in HLSL."); + if (hlsl_options.shader_model < 50 || (get_entry_point().model != ExecutionModelFragment && get_entry_point().model != ExecutionModelGLCompute)) + SPIRV_CROSS_THROW("Helper Invocation input is only supported in PS 5.0 or higher."); + // Helper lane state with demote is volatile by nature. + // Do not forward this. + emit_op(ops[0], ops[1], "IsHelperLane()", false); + break; case OpBeginInvocationInterlockEXT: case OpEndInvocationInterlockEXT: diff --git a/spirv_msl.cpp b/spirv_msl.cpp index 4eeb3b7f..8ea27d5f 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -1548,6 +1548,14 @@ void CompilerMSL::extract_global_variables_from_functions() // Uniforms unordered_set<uint32_t> global_var_ids; ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) { + // Some builtins resolve directly to a function call which does not need any declared variables. + // Skip these. + if (var.storage == StorageClassInput && has_decoration(var.self, DecorationBuiltIn) && + BuiltIn(get_decoration(var.self, DecorationBuiltIn)) == BuiltInHelperInvocation) + { + return; + } + if (var.storage == StorageClassInput || var.storage == StorageClassOutput || var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant || var.storage == StorageClassPushConstant || var.storage == StorageClassStorageBuffer) @@ -12163,16 +12171,6 @@ void CompilerMSL::fix_up_shader_inputs_outputs() }); } break; - case BuiltInHelperInvocation: - if (msl_options.is_ios() && !msl_options.supports_msl_version(2, 3)) - SPIRV_CROSS_THROW("simd_is_helper_thread() requires version 2.3 on iOS."); - else if (msl_options.is_macos() && !msl_options.supports_msl_version(2, 1)) - SPIRV_CROSS_THROW("simd_is_helper_thread() requires version 2.1 on macOS."); - - entry_func.fixup_hooks_in.push_back([=]() { - statement(builtin_type_decl(bi_type), " ", to_expression(var_id), " = simd_is_helper_thread();"); - }); - break; case BuiltInInvocationId: // This is direct-mapped without multi-patch workgroups. if (get_execution_model() != ExecutionModelTessellationControl || !msl_options.multi_patch_workgroup) @@ -14467,6 +14465,14 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage) } break; + case BuiltInHelperInvocation: + if (msl_options.is_ios() && !msl_options.supports_msl_version(2, 3)) + SPIRV_CROSS_THROW("simd_is_helper_thread() requires version 2.3 on iOS."); + else if (msl_options.is_macos() && !msl_options.supports_msl_version(2, 1)) + SPIRV_CROSS_THROW("simd_is_helper_thread() requires version 2.1 on macOS."); + // In SPIR-V 1.6 with Volatile HelperInvocation, we cannot emit a fixup early. + return "simd_is_helper_thread()"; + default: break; } diff --git a/test_shaders.py b/test_shaders.py index 49038939..2726ae75 100755 --- a/test_shaders.py +++ b/test_shaders.py @@ -192,8 +192,18 @@ def cross_compile_msl(shader, spirv, opt, iterations, paths): spirv_path = create_temporary() msl_path = create_temporary(os.path.basename(shader)) + spirv_16 = '.spv16.' in shader spirv_14 = '.spv14.' in shader - spirv_env = 'vulkan1.1spv1.4' if spirv_14 else 'vulkan1.1' + + if spirv_16: + spirv_env = 'spv1.6' + glslang_env = 'spirv1.6' + elif spirv_14: + spirv_env = 'vulkan1.1spv1.4' + glslang_env = 'spirv1.4' + else: + spirv_env = 'vulkan1.1' + glslang_env = 'vulkan1.1' spirv_cmd = [paths.spirv_as, '--target-env', spirv_env, '-o', spirv_path, shader] if '.preserve.' in shader: @@ -202,7 +212,6 @@ def cross_compile_msl(shader, spirv, opt, iterations, paths): if spirv: subprocess.check_call(spirv_cmd) else: - glslang_env = 'spirv1.4' if spirv_14 else 'vulkan1.1' subprocess.check_call([paths.glslang, '--amb' ,'--target-env', glslang_env, '-V', '-o', spirv_path, shader]) if opt and (not shader_is_invalid_spirv(shader)): @@ -442,8 +451,19 @@ def cross_compile_hlsl(shader, spirv, opt, force_no_external_validation, iterati spirv_path = create_temporary() hlsl_path = create_temporary(os.path.basename(shader)) + spirv_16 = '.spv16.' in shader spirv_14 = '.spv14.' in shader - spirv_env = 'vulkan1.1spv1.4' if spirv_14 else 'vulkan1.1' + + if spirv_16: + spirv_env = 'spv1.6' + glslang_env = 'spirv1.6' + elif spirv_14: + spirv_env = 'vulkan1.1spv1.4' + glslang_env = 'spirv1.4' + else: + spirv_env = 'vulkan1.1' + glslang_env = 'vulkan1.1' + spirv_cmd = [paths.spirv_as, '--target-env', spirv_env, '-o', spirv_path, shader] if '.preserve.' in shader: spirv_cmd.append('--preserve-numeric-ids') @@ -451,7 +471,6 @@ def cross_compile_hlsl(shader, spirv, opt, force_no_external_validation, iterati if spirv: subprocess.check_call(spirv_cmd) else: - glslang_env = 'spirv1.4' if spirv_14 else 'vulkan1.1' subprocess.check_call([paths.glslang, '--amb', '--target-env', glslang_env, '-V', '-o', spirv_path, shader]) if opt and (not shader_is_invalid_spirv(hlsl_path)): @@ -526,10 +545,13 @@ def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, fl spirv_14 = '.spv14.' in shader if spirv_16: spirv_env = 'spv1.6' + glslang_env = 'spirv1.6' elif spirv_14: spirv_env = 'vulkan1.1spv1.4' + glslang_env = 'spirv1.4' else: spirv_env = 'vulkan1.1' + glslang_env = 'vulkan1.1' if vulkan or spirv: vulkan_glsl_path = create_temporary('vk' + os.path.basename(shader)) @@ -541,7 +563,6 @@ def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, fl if spirv: subprocess.check_call(spirv_cmd) else: - glslang_env = 'spirv1.4' if spirv_14 else 'vulkan1.1' subprocess.check_call([paths.glslang, '--amb', '--target-env', glslang_env, '-V', '-o', spirv_path, shader]) if opt and (not invalid_spirv): |