MSL: Support SPV_EXT_demote_to_helper_invocation for MSL 2.3.

MSL 2.3 has everything needed to support this extension on all
platforms. The existing `discard_fragment()` function was given demote
semantics, similar to Direct3D, and the `simd_is_helper_thread()`
function was finally added to iOS.

I've left the old test alone. Should I remove it in favor of these?
This commit is contained in:
Chip Davis 2020-09-28 23:07:55 -05:00
parent 401af49326
commit 2219c4a392
11 changed files with 174 additions and 11 deletions

View File

@ -0,0 +1,22 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 FragColor [[color(0)]];
};
fragment main0_out main0()
{
main0_out out = {};
bool _15 = simd_is_helper_thread();
discard_fragment();
if (!_15)
{
out.FragColor = float4(1.0, 0.0, 0.0, 1.0);
}
return out;
}

View File

@ -0,0 +1,11 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
fragment void main0()
{
discard_fragment();
bool _9 = simd_is_helper_thread();
}

View File

@ -0,0 +1,11 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
fragment void main0()
{
discard_fragment();
bool _9 = simd_is_helper_thread();
}

View File

@ -0,0 +1,22 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 FragColor [[color(0)]];
};
fragment main0_out main0()
{
main0_out out = {};
bool _15 = simd_is_helper_thread();
discard_fragment();
if (!_15)
{
out.FragColor = float4(1.0, 0.0, 0.0, 1.0);
}
return out;
}

View File

@ -0,0 +1,12 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
fragment void main0()
{
discard_fragment();
bool _9 = simd_is_helper_thread();
bool helper = _9;
}

View File

@ -0,0 +1,12 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
fragment void main0()
{
discard_fragment();
bool _9 = simd_is_helper_thread();
bool helper = _9;
}

View File

@ -0,0 +1,41 @@
; SPIR-V
; Version: 1.3
; Generator: Khronos Glslang Reference Front End; 7
; Bound: 19
; Schema: 0
OpCapability Shader
OpCapability DemoteToHelperInvocationEXT
OpExtension "SPV_EXT_demote_to_helper_invocation"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %FragColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpSourceExtension "GL_EXT_demote_to_helper_invocation"
OpName %main "main"
OpName %FragColor "FragColor"
OpDecorate %FragColor Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%bool = OpTypeBool
%_ptr_Function_bool = OpTypePointer Function %bool
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%FragColor = OpVariable %_ptr_Output_v4float Output
%float_1 = OpConstant %float 1
%float_0 = OpConstant %float 0
%19 = OpConstantComposite %v4float %float_1 %float_0 %float_0 %float_1
%main = OpFunction %void None %3
%5 = OpLabel
%9 = OpIsHelperInvocationEXT %bool
OpDemoteToHelperInvocationEXT
%10 = OpLogicalNot %bool %9
OpSelectionMerge %12 None
OpBranchConditional %10 %11 %12
%11 = OpLabel
OpStore %FragColor %19
OpBranch %12
%12 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,8 @@
#version 450
#extension GL_EXT_demote_to_helper_invocation : require
void main()
{
demote;
bool helper = helperInvocationEXT();
}

View File

@ -0,0 +1,8 @@
#version 450
#extension GL_EXT_demote_to_helper_invocation : require
void main()
{
demote;
bool helper = helperInvocationEXT();
}

View File

@ -1120,7 +1120,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.demote_literal = "discard_fragment()";
backend.boolean_mix_function = "select";
backend.swizzle_is_function = false;
backend.shared_is_implied = false;
@ -7117,11 +7117,18 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
break;
}
// SPV_EXT_demote_to_helper_invocation
case OpDemoteToHelperInvocationEXT:
if (!msl_options.supports_msl_version(2, 3))
SPIRV_CROSS_THROW("discard_fragment() does not formally have demote semantics until MSL 2.3.");
CompilerGLSL::emit_instruction(instruction);
break;
case OpIsHelperInvocationEXT:
if (msl_options.is_ios())
SPIRV_CROSS_THROW("simd_is_helper_thread() is only supported on macOS.");
if (msl_options.is_ios() && !msl_options.supports_msl_version(2, 3))
SPIRV_CROSS_THROW("simd_is_helper_thread() requires MSL 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.");
SPIRV_CROSS_THROW("simd_is_helper_thread() requires MSL 2.1 on macOS.");
emit_op(ops[0], ops[1], "simd_is_helper_thread()", false);
break;

View File

@ -107,17 +107,17 @@ def print_msl_compiler_version():
except subprocess.CalledProcessError:
pass
def msl_compiler_supports_22():
def msl_compiler_supports_version(version):
try:
subprocess.check_call(['xcrun', '--sdk', 'macosx', 'metal', '-x', 'metal', '-std=macos-metal2.2', '-'],
subprocess.check_call(['xcrun', '--sdk', 'macosx', 'metal', '-x', 'metal', '-std=macos-metal' + version, '-'],
stdin = subprocess.DEVNULL, stdout = subprocess.DEVNULL, stderr = subprocess.DEVNULL)
print('Current SDK supports MSL 2.2. Enabling validation for MSL 2.2 shaders.')
print('Current SDK supports MSL {0}. Enabling validation for MSL {0} shaders.'.format(version))
return True
except OSError as e:
print('Failed to check if MSL 2.2 is not supported. It probably is not.')
print('Failed to check if MSL {} is not supported. It probably is not.'.format(version))
return False
except subprocess.CalledProcessError:
print('Current SDK does NOT support MSL 2.2. Disabling validation for MSL 2.2 shaders.')
print('Current SDK does NOT support MSL {0}. Disabling validation for MSL {0} shaders.'.format(version))
return False
def path_to_msl_standard(shader):
@ -128,6 +128,8 @@ def path_to_msl_standard(shader):
return '-std=ios-metal2.1'
elif '.msl22.' in shader:
return '-std=ios-metal2.2'
elif '.msl23.' in shader:
return '-std=ios-metal2.3'
elif '.msl11.' in shader:
return '-std=ios-metal1.1'
elif '.msl10.' in shader:
@ -141,6 +143,8 @@ def path_to_msl_standard(shader):
return '-std=macos-metal2.1'
elif '.msl22.' in shader:
return '-std=macos-metal2.2'
elif '.msl23.' in shader:
return '-std=macos-metal2.3'
elif '.msl11.' in shader:
return '-std=macos-metal1.1'
else:
@ -153,6 +157,8 @@ def path_to_msl_standard_cli(shader):
return '20100'
elif '.msl22.' in shader:
return '20200'
elif '.msl23.' in shader:
return '20300'
elif '.msl11.' in shader:
return '10100'
else:
@ -712,7 +718,8 @@ def test_shader_msl(stats, shader, args, paths):
# print('SPRIV shader: ' + spirv)
shader_is_msl22 = 'msl22' in joined_path
skip_validation = shader_is_msl22 and (not args.msl22)
shader_is_msl23 = 'msl23' in joined_path
skip_validation = (shader_is_msl22 and (not args.msl22)) or (shader_is_msl23 and (not args.msl23))
if '.invalid.' in joined_path:
skip_validation = True
@ -860,9 +867,11 @@ def main():
args.parallel = False
args.msl22 = False
args.msl23 = False
if args.msl:
print_msl_compiler_version()
args.msl22 = msl_compiler_supports_22()
args.msl22 = msl_compiler_supports_version('2.2')
args.msl23 = msl_compiler_supports_version('2.3')
backend = 'glsl'
if (args.msl or args.metal):