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.
This commit is contained in:
parent
fb71a337a2
commit
50dce10c5d
9
reference/opt/shaders-hlsl/frag/demote-to-helper.frag
Normal file
9
reference/opt/shaders-hlsl/frag/demote-to-helper.frag
Normal file
@ -0,0 +1,9 @@
|
||||
void frag_main()
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
frag_main();
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
fragment void main0()
|
||||
{
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
#version 450
|
||||
#extension GL_EXT_demote_to_helper_invocation : require
|
||||
|
||||
void main()
|
||||
{
|
||||
demote;
|
||||
bool helper = helperInvocationEXT();
|
||||
}
|
||||
|
9
reference/shaders-hlsl/frag/demote-to-helper.frag
Normal file
9
reference/shaders-hlsl/frag/demote-to-helper.frag
Normal file
@ -0,0 +1,9 @@
|
||||
void frag_main()
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
frag_main();
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
fragment void main0()
|
||||
{
|
||||
bool helper = simd_is_helper_thread();
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
#version 450
|
||||
#extension GL_EXT_demote_to_helper_invocation : require
|
||||
|
||||
void main()
|
||||
{
|
||||
demote;
|
||||
bool helper = helperInvocationEXT();
|
||||
}
|
||||
|
7
shaders-hlsl/frag/demote-to-helper.frag
Normal file
7
shaders-hlsl/frag/demote-to-helper.frag
Normal file
@ -0,0 +1,7 @@
|
||||
#version 450
|
||||
#extension GL_EXT_demote_to_helper_invocation : require
|
||||
|
||||
void main()
|
||||
{
|
||||
demote;
|
||||
}
|
@ -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();
|
||||
}
|
8
shaders/vulkan/frag/demote-to-helper.vk.nocompat.frag
Normal file
8
shaders/vulkan/frag/demote-to-helper.vk.nocompat.frag
Normal file
@ -0,0 +1,8 @@
|
||||
#version 450
|
||||
#extension GL_EXT_demote_to_helper_invocation : require
|
||||
|
||||
void main()
|
||||
{
|
||||
demote;
|
||||
bool helper = helperInvocationEXT();
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user