Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/KhronosGroup/SPIRV-Cross.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans-Kristian Arntzen <post@arntzen-software.no>2022-03-04 14:36:21 +0300
committerGitHub <noreply@github.com>2022-03-04 14:36:21 +0300
commita1803778c2c88078bffd2642c3c9f95fab56d0a5 (patch)
treea77554382a3fb2de1d20ea0b4d0912df7c1feba2
parent6c7a40822f0f55d4045e3e854d25c0466eb64e9b (diff)
parentb192b8887a5f0d53c8ebd66407346c52f82f075b (diff)
Merge pull request #1885 from KhronosGroup/helper-invocation-rework
Helper invocation rework
-rw-r--r--reference/opt/shaders-msl/frag/helper-invocation.msl21.frag3
-rw-r--r--reference/shaders-hlsl-no-opt/frag/helper-invocation.fxconly.nofxc.frag26
-rw-r--r--reference/shaders-hlsl-no-opt/frag/volatile-helper-invocation.fxconly.nofxc.spv16.frag29
-rw-r--r--reference/shaders-msl-no-opt/frag/volatile-helper-invocation.msl23.spv16.frag23
-rw-r--r--reference/shaders-msl/frag/helper-invocation.msl21.frag7
-rw-r--r--reference/shaders-no-opt/vulkan/frag/volatile-helper-invocation.vk.nocompat.spv16.frag.vk16
-rw-r--r--shaders-hlsl-no-opt/frag/helper-invocation.fxconly.nofxc.frag11
-rw-r--r--shaders-hlsl-no-opt/frag/volatile-helper-invocation.fxconly.nofxc.spv16.frag11
-rw-r--r--shaders-msl-no-opt/frag/volatile-helper-invocation.msl23.spv16.frag11
-rw-r--r--shaders-no-opt/vulkan/frag/volatile-helper-invocation.vk.nocompat.spv16.frag11
-rw-r--r--spirv_common.hpp1
-rw-r--r--spirv_glsl.cpp17
-rw-r--r--spirv_hlsl.cpp22
-rw-r--r--spirv_msl.cpp26
-rwxr-xr-xtest_shaders.py31
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):