Merge pull request #1885 from KhronosGroup/helper-invocation-rework
Helper invocation rework
This commit is contained in:
commit
a1803778c2
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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):
|
||||
|
Loading…
Reference in New Issue
Block a user