MSL: Allow removing clip distance user varyings.

Only safe if user knows that subsequent shader stage will not read clip
distance.
This commit is contained in:
Hans-Kristian Arntzen 2020-04-20 09:48:20 +02:00
parent aa5fbc004b
commit ebf463674d
16 changed files with 300 additions and 2 deletions

View File

@ -323,7 +323,7 @@ if (SPIRV_CROSS_STATIC)
endif()
set(spirv-cross-abi-major 0)
set(spirv-cross-abi-minor 31)
set(spirv-cross-abi-minor 32)
set(spirv-cross-abi-patch 0)
if (SPIRV_CROSS_SHARED)

View File

@ -557,6 +557,7 @@ struct CLIArguments
bool msl_enable_frag_depth_builtin = true;
bool msl_enable_frag_stencil_ref_builtin = true;
uint32_t msl_enable_frag_output_mask = 0xffffffff;
bool msl_enable_clip_distance_user_varying = true;
bool glsl_emit_push_constant_as_ubo = false;
bool glsl_emit_ubo_as_plain_uniforms = false;
SmallVector<pair<uint32_t, uint32_t>> glsl_ext_framebuffer_fetch;
@ -663,6 +664,7 @@ static void print_help()
"\t[--msl-disable-frag-depth-builtin]\n"
"\t[--msl-disable-frag-stencil-ref-builtin]\n"
"\t[--msl-enable-frag-output-mask <mask>]\n"
"\t[--msl-no-clip-distance-user-varying]\n"
"\t[--hlsl]\n"
"\t[--reflect]\n"
"\t[--shader-model]\n"
@ -859,6 +861,7 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
msl_opts.enable_frag_depth_builtin = args.msl_enable_frag_depth_builtin;
msl_opts.enable_frag_stencil_ref_builtin = args.msl_enable_frag_stencil_ref_builtin;
msl_opts.enable_frag_output_mask = args.msl_enable_frag_output_mask;
msl_opts.enable_clip_distance_user_varying = args.msl_enable_clip_distance_user_varying;
msl_comp->set_msl_options(msl_opts);
for (auto &v : args.msl_discrete_descriptor_sets)
msl_comp->add_discrete_descriptor_set(v);
@ -1246,6 +1249,8 @@ static int main_inner(int argc, char *argv[])
[&args](CLIParser &) { args.msl_enable_frag_stencil_ref_builtin = false; });
cbs.add("--msl-enable-frag-output-mask",
[&args](CLIParser &parser) { args.msl_enable_frag_output_mask = parser.next_hex_uint(); });
cbs.add("--msl-no-clip-distance-user-varying",
[&args](CLIParser &) { args.msl_enable_clip_distance_user_varying = false; });
cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); });
cbs.add("--rename-entry-point", [&args](CLIParser &parser) {
auto old_name = parser.next_string();

View File

@ -0,0 +1,25 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 gl_Position [[position]];
float gl_ClipDistance [[clip_distance]] [2];
};
struct main0_in
{
float4 pos [[attribute(0)]];
};
vertex main0_out main0(main0_in in [[stage_in]])
{
main0_out out = {};
out.gl_Position = in.pos;
out.gl_ClipDistance[0] = in.pos.x;
out.gl_ClipDistance[1] = in.pos.y;
return out;
}

View File

@ -0,0 +1,20 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 gl_Position [[position]];
float gl_ClipDistance [[clip_distance]] [2];
};
vertex main0_out main0()
{
main0_out out = {};
out.gl_Position = float4(10.0);
out.gl_ClipDistance[0] = 1.0;
out.gl_ClipDistance[1] = 4.0;
return out;
}

View File

@ -0,0 +1,25 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 gl_Position [[position]];
float gl_ClipDistance [[clip_distance]] [2];
};
struct main0_in
{
float4 Position [[attribute(0)]];
};
vertex main0_out main0(main0_in in [[stage_in]])
{
main0_out out = {};
out.gl_Position = in.Position;
out.gl_ClipDistance[0] = in.Position.x;
out.gl_ClipDistance[1] = in.Position.y;
return out;
}

View File

@ -0,0 +1,45 @@
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct VSOut
{
float4 pos;
float2 clip;
};
struct main0_out
{
float4 gl_Position [[position]];
float gl_ClipDistance [[clip_distance]] [2];
};
struct main0_in
{
float4 pos [[attribute(0)]];
};
static inline __attribute__((always_inline))
VSOut _main(thread const float4& pos)
{
VSOut vout;
vout.pos = pos;
vout.clip = pos.xy;
return vout;
}
vertex main0_out main0(main0_in in [[stage_in]])
{
main0_out out = {};
float4 pos = in.pos;
float4 param = pos;
VSOut flattenTemp = _main(param);
out.gl_Position = flattenTemp.pos;
out.gl_ClipDistance[0] = flattenTemp.clip.x;
out.gl_ClipDistance[1] = flattenTemp.clip.y;
return out;
}

View File

@ -0,0 +1,20 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 gl_Position [[position]];
float gl_ClipDistance [[clip_distance]] [2];
};
vertex main0_out main0()
{
main0_out out = {};
out.gl_Position = float4(10.0);
out.gl_ClipDistance[0] = 1.0;
out.gl_ClipDistance[1] = 4.0;
return out;
}

View File

@ -0,0 +1,25 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 gl_Position [[position]];
float gl_ClipDistance [[clip_distance]] [2];
};
struct main0_in
{
float4 Position [[attribute(0)]];
};
vertex main0_out main0(main0_in in [[stage_in]])
{
main0_out out = {};
out.gl_Position = in.Position;
out.gl_ClipDistance[0] = in.Position.x;
out.gl_ClipDistance[1] = in.Position.y;
return out;
}

View File

@ -0,0 +1,91 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 8
; Bound: 56
; Schema: 0
OpCapability Shader
OpCapability ClipDistance
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main" %pos_1 %_entryPointOutput_pos %_entryPointOutput_clip
OpSource HLSL 500
OpName %main "main"
OpName %VSOut "VSOut"
OpMemberName %VSOut 0 "pos"
OpMemberName %VSOut 1 "clip"
OpName %_main_vf4_ "@main(vf4;"
OpName %pos "pos"
OpName %vout "vout"
OpName %pos_0 "pos"
OpName %pos_1 "pos"
OpName %flattenTemp "flattenTemp"
OpName %param "param"
OpName %_entryPointOutput_pos "@entryPointOutput.pos"
OpName %_entryPointOutput_clip "@entryPointOutput.clip"
OpDecorate %pos_1 Location 0
OpDecorate %_entryPointOutput_pos BuiltIn Position
OpDecorate %_entryPointOutput_clip BuiltIn ClipDistance
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Function_v4float = OpTypePointer Function %v4float
%v2float = OpTypeVector %float 2
%VSOut = OpTypeStruct %v4float %v2float
%11 = OpTypeFunction %VSOut %_ptr_Function_v4float
%_ptr_Function_VSOut = OpTypePointer Function %VSOut
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%int_1 = OpConstant %int 1
%_ptr_Function_v2float = OpTypePointer Function %v2float
%_ptr_Input_v4float = OpTypePointer Input %v4float
%pos_1 = OpVariable %_ptr_Input_v4float Input
%_ptr_Output_v4float = OpTypePointer Output %v4float
%_entryPointOutput_pos = OpVariable %_ptr_Output_v4float Output
%uint = OpTypeInt 32 0
%uint_2 = OpConstant %uint 2
%_arr_float_uint_2 = OpTypeArray %float %uint_2
%_ptr_Output__arr_float_uint_2 = OpTypePointer Output %_arr_float_uint_2
%_entryPointOutput_clip = OpVariable %_ptr_Output__arr_float_uint_2 Output
%uint_0 = OpConstant %uint 0
%_ptr_Function_float = OpTypePointer Function %float
%_ptr_Output_float = OpTypePointer Output %float
%uint_1 = OpConstant %uint 1
%main = OpFunction %void None %3
%5 = OpLabel
%pos_0 = OpVariable %_ptr_Function_v4float Function
%flattenTemp = OpVariable %_ptr_Function_VSOut Function
%param = OpVariable %_ptr_Function_v4float Function
%32 = OpLoad %v4float %pos_1
OpStore %pos_0 %32
%35 = OpLoad %v4float %pos_0
OpStore %param %35
%36 = OpFunctionCall %VSOut %_main_vf4_ %param
OpStore %flattenTemp %36
%39 = OpAccessChain %_ptr_Function_v4float %flattenTemp %int_0
%40 = OpLoad %v4float %39
OpStore %_entryPointOutput_pos %40
%48 = OpAccessChain %_ptr_Function_float %flattenTemp %int_1 %uint_0
%49 = OpLoad %float %48
%51 = OpAccessChain %_ptr_Output_float %_entryPointOutput_clip %int_0
OpStore %51 %49
%53 = OpAccessChain %_ptr_Function_float %flattenTemp %int_1 %uint_1
%54 = OpLoad %float %53
%55 = OpAccessChain %_ptr_Output_float %_entryPointOutput_clip %int_1
OpStore %55 %54
OpReturn
OpFunctionEnd
%_main_vf4_ = OpFunction %VSOut None %11
%pos = OpFunctionParameter %_ptr_Function_v4float
%14 = OpLabel
%vout = OpVariable %_ptr_Function_VSOut Function
%19 = OpLoad %v4float %pos
%20 = OpAccessChain %_ptr_Function_v4float %vout %int_0
OpStore %20 %19
%22 = OpLoad %v4float %pos
%23 = OpVectorShuffle %v2float %22 %22 0 1
%25 = OpAccessChain %_ptr_Function_v2float %vout %int_1
OpStore %25 %23
%26 = OpLoad %VSOut %vout
OpReturnValue %26
OpFunctionEnd

View File

@ -0,0 +1,10 @@
#version 450
void main()
{
gl_Position = vec4(10.0);
gl_ClipDistance[0] = 1.0;
gl_ClipDistance[1] = 4.0;
//gl_CullDistance[0] = 4.0;
//gl_CullDistance[1] = 9.0;
}

View File

@ -0,0 +1,15 @@
#version 450
layout(location = 0) in vec4 Position;
out gl_PerVertex
{
vec4 gl_Position;
float gl_ClipDistance[2];
};
void main()
{
gl_Position = Position;
gl_ClipDistance[0] = Position.x;
gl_ClipDistance[1] = Position.y;
}

View File

@ -627,6 +627,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
case SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_STENCIL_REF_BUILTIN:
options->msl.enable_frag_stencil_ref_builtin = value != 0;
break;
case SPVC_COMPILER_OPTION_MSL_ENABLE_CLIP_DISTANCE_USER_VARYING:
options->msl.enable_clip_distance_user_varying = value != 0;
break;
#endif
default:

View File

@ -33,7 +33,7 @@ extern "C" {
/* Bumped if ABI or API breaks backwards compatibility. */
#define SPVC_C_API_VERSION_MAJOR 0
/* Bumped if APIs or enumerations are added in a backwards compatible way. */
#define SPVC_C_API_VERSION_MINOR 31
#define SPVC_C_API_VERSION_MINOR 32
/* Bumped if internal implementation details change. */
#define SPVC_C_API_VERSION_PATCH 0
@ -585,6 +585,7 @@ typedef enum spvc_compiler_option
SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_OUTPUT_MASK = 56 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_DEPTH_BUILTIN = 57 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_STENCIL_REF_BUILTIN = 58 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_ENABLE_CLIP_DISTANCE_USER_VARYING = 59 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
} spvc_compiler_option;

View File

@ -1752,6 +1752,9 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
// When we flatten, we flatten directly from the "out" struct,
// not from a function variable.
flatten_from_ib_var = true;
if (!msl_options.enable_clip_distance_user_varying)
return;
}
else if (!meta.strip_array)
{
@ -1957,6 +1960,9 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
// When we flatten, we flatten directly from the "out" struct,
// not from a function variable.
flatten_from_ib_var = true;
if (!msl_options.enable_clip_distance_user_varying)
return;
}
for (uint32_t i = 0; i < elem_cnt; i++)

View File

@ -320,6 +320,10 @@ public:
// May reduce performance in scenarios where arrays are copied around as value-types.
bool force_native_arrays = false;
// If a shader writes clip distance, also emit user varyings which
// can be read in subsequent stages.
bool enable_clip_distance_user_varying = true;
bool is_ios()
{
return platform == iOS;

View File

@ -264,6 +264,8 @@ def cross_compile_msl(shader, spirv, opt, iterations, paths):
msl_args.append('--msl-disable-frag-stencil-ref-builtin')
msl_args.append('--msl-enable-frag-output-mask')
msl_args.append('0x000000ca')
if '.no-user-varying.' in shader:
msl_args.append('--msl-no-clip-distance-user-varying')
subprocess.check_call(msl_args)