diff --git a/reference/opt/shaders-msl/frag/post-depth-coverage.ios.msl2.frag b/reference/opt/shaders-msl/frag/post-depth-coverage.ios.msl2.frag new file mode 100644 index 00000000..3b2885e2 --- /dev/null +++ b/reference/opt/shaders-msl/frag/post-depth-coverage.ios.msl2.frag @@ -0,0 +1,17 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +[[ early_fragment_tests ]] fragment main0_out main0(uint gl_SampleMaskIn [[sample_mask, post_depth_coverage]]) +{ + main0_out out = {}; + out.FragColor = float4(float(gl_SampleMaskIn)); + return out; +} + diff --git a/reference/opt/shaders/frag/post-depth-coverage.frag b/reference/opt/shaders/frag/post-depth-coverage.frag new file mode 100644 index 00000000..3e78fcd0 --- /dev/null +++ b/reference/opt/shaders/frag/post-depth-coverage.frag @@ -0,0 +1,11 @@ +#version 450 +#extension GL_ARB_post_depth_coverage : require +layout(early_fragment_tests, post_depth_coverage) in; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = vec4(float(gl_SampleMaskIn[0])); +} + diff --git a/reference/shaders-msl/frag/post-depth-coverage.ios.msl2.frag b/reference/shaders-msl/frag/post-depth-coverage.ios.msl2.frag new file mode 100644 index 00000000..3b2885e2 --- /dev/null +++ b/reference/shaders-msl/frag/post-depth-coverage.ios.msl2.frag @@ -0,0 +1,17 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +[[ early_fragment_tests ]] fragment main0_out main0(uint gl_SampleMaskIn [[sample_mask, post_depth_coverage]]) +{ + main0_out out = {}; + out.FragColor = float4(float(gl_SampleMaskIn)); + return out; +} + diff --git a/reference/shaders/frag/post-depth-coverage.frag b/reference/shaders/frag/post-depth-coverage.frag new file mode 100644 index 00000000..3e78fcd0 --- /dev/null +++ b/reference/shaders/frag/post-depth-coverage.frag @@ -0,0 +1,11 @@ +#version 450 +#extension GL_ARB_post_depth_coverage : require +layout(early_fragment_tests, post_depth_coverage) in; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = vec4(float(gl_SampleMaskIn[0])); +} + diff --git a/shaders-msl/frag/post-depth-coverage.ios.msl2.frag b/shaders-msl/frag/post-depth-coverage.ios.msl2.frag new file mode 100644 index 00000000..4f134b4f --- /dev/null +++ b/shaders-msl/frag/post-depth-coverage.ios.msl2.frag @@ -0,0 +1,11 @@ +#version 450 +#extension GL_ARB_post_depth_coverage : require + +layout(post_depth_coverage) in; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = vec4(gl_SampleMaskIn[0]); +} diff --git a/shaders/frag/post-depth-coverage.frag b/shaders/frag/post-depth-coverage.frag new file mode 100644 index 00000000..4f134b4f --- /dev/null +++ b/shaders/frag/post-depth-coverage.frag @@ -0,0 +1,11 @@ +#version 450 +#extension GL_ARB_post_depth_coverage : require + +layout(post_depth_coverage) in; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = vec4(gl_SampleMaskIn[0]); +} diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index 14d23863..74d8f51c 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -600,6 +600,10 @@ void CompilerGLSL::emit_header() require_extension_internal("GL_ARB_shader_image_load_store"); } + // Needed for: layout(post_depth_coverage) in; + if (execution.flags.get(ExecutionModePostDepthCoverage)) + require_extension_internal("GL_ARB_post_depth_coverage"); + for (auto &ext : forced_extensions) { if (ext == "GL_EXT_shader_explicit_arithmetic_types_float16") @@ -763,6 +767,8 @@ void CompilerGLSL::emit_header() if (execution.flags.get(ExecutionModeEarlyFragmentTests)) inputs.push_back("early_fragment_tests"); + if (execution.flags.get(ExecutionModePostDepthCoverage)) + inputs.push_back("post_depth_coverage"); if (!options.es && execution.flags.get(ExecutionModeDepthGreater)) statement("layout(depth_greater) out float gl_FragDepth;"); diff --git a/spirv_msl.cpp b/spirv_msl.cpp index eaee10a0..5b3a624a 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -6165,8 +6165,10 @@ string CompilerMSL::func_type_decl(SPIRType &type) execution.output_vertices, ") ]] vertex"); break; case ExecutionModelFragment: - entry_type = - execution.flags.get(ExecutionModeEarlyFragmentTests) ? "[[ early_fragment_tests ]] fragment" : "fragment"; + entry_type = execution.flags.get(ExecutionModeEarlyFragmentTests) || + execution.flags.get(ExecutionModePostDepthCoverage) ? + "[[ early_fragment_tests ]] fragment" : + "fragment"; break; case ExecutionModelTessellationControl: if (!msl_options.supports_msl_version(1, 2)) @@ -6330,6 +6332,7 @@ string CompilerMSL::entry_point_arg_stage_in() void CompilerMSL::entry_point_args_builtin(string &ep_args) { // Builtin variables + SmallVector, 8> active_builtins; ir.for_each_typed_id([&](uint32_t var_id, SPIRVariable &var) { auto bi_type = BuiltIn(get_decoration(var_id, DecorationBuiltIn)); @@ -6344,6 +6347,9 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args) if (!active_input_builtins.get(bi_type) || !interface_variable_exists_in_entry_point(var_id)) return; + // Remember this variable. We may need to correct its type. + active_builtins.push_back(make_pair(&var, bi_type)); + // These builtins are emitted specially. If we pass this branch, the builtin directly matches // a MSL builtin. if (bi_type != BuiltInSamplePosition && bi_type != BuiltInHelperInvocation && @@ -6363,11 +6369,26 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args) ep_args += ", "; ep_args += builtin_type_decl(bi_type, var_id) + " " + to_expression(var_id); - ep_args += " [[" + builtin_qualifier(bi_type) + "]]"; + ep_args += " [[" + builtin_qualifier(bi_type); + if (bi_type == BuiltInSampleMask && get_entry_point().flags.get(ExecutionModePostDepthCoverage)) + { + if (!msl_options.supports_msl_version(2)) + SPIRV_CROSS_THROW("Post-depth coverage requires Metal 2.0."); + if (!msl_options.is_ios()) + SPIRV_CROSS_THROW("Post-depth coverage is only supported on iOS."); + ep_args += ", post_depth_coverage"; + } + ep_args += "]]"; } } }); + // Correct the types of all encountered active builtins. We couldn't do this before + // because ensure_correct_builtin_type() may increase the bound, which isn't allowed + // while iterating over IDs. + for (auto &var : active_builtins) + var.first->basetype = ensure_correct_builtin_type(var.first->basetype, var.second); + // Vertex and instance index built-ins if (needs_vertex_idx_arg) ep_args += built_in_func_arg(BuiltInVertexIndex, !ep_args.empty());