Merge pull request #1885 from KhronosGroup/helper-invocation-rework

Helper invocation rework
This commit is contained in:
Hans-Kristian Arntzen 2022-03-04 12:36:21 +01:00 committed by GitHub
commit a1803778c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 218 additions and 27 deletions

View File

@ -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));
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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());
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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;
}

View File

@ -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):