The following assumes that HLSL source is used as an input for shader compilation, glslang is used to compile it to SPIRV, and then SPIRV-Cross is optionally used to compile the result to MSL/GLSL.
First, make sure you use min16floatN type instead of halfN type. This is necessary because glslang treats halfN type (with default compilation options) as floatN because unfortunately that's what DX10 does as well.
#define half min16float
#define half2 min16float2
#define half3 min16float3
#define half4 min16float4
Now, you have two options when compiling HLSL to SPIRV: default settings, and --hlsl-enable-16bit-types (aka EShMsgHlslEnable16BitTypes if you invoke glslang via C++).
By default, min16floatN types compile to floatN types in SPIRV, but the variables, including temporaries, will have RelaxedPrecision annotation in SPIRV:
OpDecorate %27 RelaxedPrecision
This is the behavior that you probably want when compiling to SPIRV directly for use in Vulkan! The decoration is optional, so devices that don't support 16-bit floating point computation are free to disregard this and use 32-bit floating point math instead.
You can also use SPIRV-Cross to cross-compile this to GLSL:
#version 450 es
precision mediump float;
precision highp int;
layout(location = 0) in vec4 input_color;
layout(location = 0) out vec4 _entryPointOutput;
(vec4
in the code above refers to mediump vec4
; ordinarily SPIRV-Cross would insert highp vec4
)
Unfortunately, SPIRV-Cross doesn't support RelaxedPrecision for MSL. To get around that, you need to enable 16-bit type support when building SPIRV for use with SPIRV-Cross, which will result in the actual half-precision types being emitted:
%half = OpTypeFloat 16
%v4half = OpTypeVector %half 4
Note that you can't use the resulting SPIRV in Vulkan if the device doesn't support VK_KHR_shader_float16_int8! Most older drivers don't. However, we don't care about this - we care about feeding this to SPIRV-Cross, which will happily translate this to halfN types when targeting Metal:
half4 _entryPointOutput [[color(0)]];
The danger of this approach is that using half
in constant buffers will result in actual half-precision types (with sizeof=2) emitted for Metal but not for other APIs, which will result in a different constant buffer layout. This can be prevented by querying SPIRV-Cross reflection information and making sure half types aren't used for uniform data.
You seem to be implying that there is an automated way to get from GLSL with mediump floats to SPIRV with explicit half types. Am I understanding correctly? If so, what is the command to do that?