From 50dce10c5d57ac05a78c48670e66155c4493d983 Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Sat, 13 Jul 2019 15:57:33 -0500 Subject: [PATCH] Support the SPV_EXT_demote_to_helper_invocation extension. This extension provides a new operation which causes a fragment to be discarded without terminating the fragment shader invocation. The invocation for the discarded fragment becomes a helper invocation, so that derivatives will remain defined. The old `HelperInvocation` builtin becomes undefined when this occurs, so a second new instruction queries the current helper invocation status. This is only fully supported for GLSL. HLSL doesn't support the `IsHelperInvocation` operation and MSL doesn't support the `DemoteToHelperInvocation` op. Fixes #1052. --- .../opt/shaders-hlsl/frag/demote-to-helper.frag | 9 +++++++++ ...demote-to-helper.vk.nocompat.msl21.invalid.frag | 9 +++++++++ .../frag/demote-to-helper.vk.nocompat.frag.vk | 9 +++++++++ reference/shaders-hlsl/frag/demote-to-helper.frag | 9 +++++++++ ...demote-to-helper.vk.nocompat.msl21.invalid.frag | 10 ++++++++++ .../frag/demote-to-helper.vk.nocompat.frag.vk | 9 +++++++++ shaders-hlsl/frag/demote-to-helper.frag | 7 +++++++ ...demote-to-helper.vk.nocompat.msl21.invalid.frag | 8 ++++++++ .../vulkan/frag/demote-to-helper.vk.nocompat.frag | 8 ++++++++ spirv_glsl.cpp | 14 ++++++++++++++ spirv_glsl.hpp | 1 + spirv_hlsl.cpp | 4 ++++ spirv_msl.cpp | 9 +++++++++ 13 files changed, 106 insertions(+) create mode 100644 reference/opt/shaders-hlsl/frag/demote-to-helper.frag create mode 100644 reference/opt/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag create mode 100644 reference/opt/shaders/vulkan/frag/demote-to-helper.vk.nocompat.frag.vk create mode 100644 reference/shaders-hlsl/frag/demote-to-helper.frag create mode 100644 reference/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag create mode 100644 reference/shaders/vulkan/frag/demote-to-helper.vk.nocompat.frag.vk create mode 100644 shaders-hlsl/frag/demote-to-helper.frag create mode 100644 shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag create mode 100644 shaders/vulkan/frag/demote-to-helper.vk.nocompat.frag diff --git a/reference/opt/shaders-hlsl/frag/demote-to-helper.frag b/reference/opt/shaders-hlsl/frag/demote-to-helper.frag new file mode 100644 index 00000000..743a4228 --- /dev/null +++ b/reference/opt/shaders-hlsl/frag/demote-to-helper.frag @@ -0,0 +1,9 @@ +void frag_main() +{ + discard; +} + +void main() +{ + frag_main(); +} diff --git a/reference/opt/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag b/reference/opt/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag new file mode 100644 index 00000000..92ac1d9f --- /dev/null +++ b/reference/opt/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag @@ -0,0 +1,9 @@ +#include +#include + +using namespace metal; + +fragment void main0() +{ +} + diff --git a/reference/opt/shaders/vulkan/frag/demote-to-helper.vk.nocompat.frag.vk b/reference/opt/shaders/vulkan/frag/demote-to-helper.vk.nocompat.frag.vk new file mode 100644 index 00000000..430e76f4 --- /dev/null +++ b/reference/opt/shaders/vulkan/frag/demote-to-helper.vk.nocompat.frag.vk @@ -0,0 +1,9 @@ +#version 450 +#extension GL_EXT_demote_to_helper_invocation : require + +void main() +{ + demote; + bool helper = helperInvocationEXT(); +} + diff --git a/reference/shaders-hlsl/frag/demote-to-helper.frag b/reference/shaders-hlsl/frag/demote-to-helper.frag new file mode 100644 index 00000000..743a4228 --- /dev/null +++ b/reference/shaders-hlsl/frag/demote-to-helper.frag @@ -0,0 +1,9 @@ +void frag_main() +{ + discard; +} + +void main() +{ + frag_main(); +} diff --git a/reference/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag b/reference/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag new file mode 100644 index 00000000..9704a368 --- /dev/null +++ b/reference/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag @@ -0,0 +1,10 @@ +#include +#include + +using namespace metal; + +fragment void main0() +{ + bool helper = simd_is_helper_thread(); +} + diff --git a/reference/shaders/vulkan/frag/demote-to-helper.vk.nocompat.frag.vk b/reference/shaders/vulkan/frag/demote-to-helper.vk.nocompat.frag.vk new file mode 100644 index 00000000..430e76f4 --- /dev/null +++ b/reference/shaders/vulkan/frag/demote-to-helper.vk.nocompat.frag.vk @@ -0,0 +1,9 @@ +#version 450 +#extension GL_EXT_demote_to_helper_invocation : require + +void main() +{ + demote; + bool helper = helperInvocationEXT(); +} + diff --git a/shaders-hlsl/frag/demote-to-helper.frag b/shaders-hlsl/frag/demote-to-helper.frag new file mode 100644 index 00000000..bdfef6f9 --- /dev/null +++ b/shaders-hlsl/frag/demote-to-helper.frag @@ -0,0 +1,7 @@ +#version 450 +#extension GL_EXT_demote_to_helper_invocation : require + +void main() +{ + demote; +} diff --git a/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag b/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag new file mode 100644 index 00000000..8cce059b --- /dev/null +++ b/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag @@ -0,0 +1,8 @@ +#version 450 +#extension GL_EXT_demote_to_helper_invocation : require + +void main() +{ + //demote; // FIXME: Not implemented for MSL + bool helper = helperInvocationEXT(); +} diff --git a/shaders/vulkan/frag/demote-to-helper.vk.nocompat.frag b/shaders/vulkan/frag/demote-to-helper.vk.nocompat.frag new file mode 100644 index 00000000..8b8bb61f --- /dev/null +++ b/shaders/vulkan/frag/demote-to-helper.vk.nocompat.frag @@ -0,0 +1,8 @@ +#version 450 +#extension GL_EXT_demote_to_helper_invocation : require + +void main() +{ + demote; + bool helper = helperInvocationEXT(); +} diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index 8592456d..68d91761 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -9778,6 +9778,20 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) case OpNoLine: break; + case OpDemoteToHelperInvocationEXT: + 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"); + statement(backend.demote_literal, ";"); + break; + + case OpIsHelperInvocationEXT: + 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"); + emit_op(ops[0], ops[1], "helperInvocationEXT()", true); + break; + default: statement("// unimplemented op ", instruction.op); break; diff --git a/spirv_glsl.hpp b/spirv_glsl.hpp index 77c13602..c6649987 100644 --- a/spirv_glsl.hpp +++ b/spirv_glsl.hpp @@ -369,6 +369,7 @@ protected: struct BackendVariations { std::string discard_literal = "discard"; + std::string demote_literal = "demote"; std::string null_pointer_literal = ""; bool float_literal_suffix = false; bool double_literal_suffix = true; diff --git a/spirv_hlsl.cpp b/spirv_hlsl.cpp index 227b7cdd..b1bc5b13 100644 --- a/spirv_hlsl.cpp +++ b/spirv_hlsl.cpp @@ -4663,6 +4663,9 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) break; } + case OpIsHelperInvocationEXT: + SPIRV_CROSS_THROW("helperInvocationEXT() is not supported in HLSL."); + default: CompilerGLSL::emit_instruction(instruction); break; @@ -4819,6 +4822,7 @@ string CompilerHLSL::compile() backend.uint16_t_literal_suffix = "u"; backend.basic_int_type = "int"; backend.basic_uint_type = "uint"; + backend.demote_literal = "discard"; backend.boolean_mix_function = ""; backend.swizzle_is_function = false; backend.shared_is_implied = true; diff --git a/spirv_msl.cpp b/spirv_msl.cpp index 33ffd8de..7e806ae6 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -757,6 +757,7 @@ string CompilerMSL::compile() backend.basic_int16_type = "short"; backend.basic_uint16_type = "ushort"; backend.discard_literal = "discard_fragment()"; + backend.demote_literal = "unsupported-demote"; backend.boolean_mix_function = "select"; backend.swizzle_is_function = false; backend.shared_is_implied = false; @@ -4467,6 +4468,14 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) break; } + case OpIsHelperInvocationEXT: + if (msl_options.is_ios()) + SPIRV_CROSS_THROW("simd_is_helper_thread() is only supported on macOS."); + 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."); + emit_op(ops[0], ops[1], "simd_is_helper_thread()", true); + break; + default: CompilerGLSL::emit_instruction(instruction); break;