MSL: Don't output depth and stencil values with explicit early fragment tests.
Fragment shaders that require explicit early fragment tests are incompatible with specifying depth and stencil values within the shader. If explicit early fragment tests is specified, remove the depth and stencil outputs from the output structure, and replace them with dummy local variables. Add CompilerMSL:uses_explicit_early_fragment_test() function to consolidate testing for whether early fragment tests are required. Add two unit tests for depth-out with, and without, early fragment tests.
This commit is contained in:
parent
401296d3b8
commit
248e9ae9ed
@ -0,0 +1,19 @@
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
float4 color_out [[color(0)]];
|
||||
};
|
||||
|
||||
[[ early_fragment_tests ]] fragment main0_out main0()
|
||||
{
|
||||
float gl_FragDepth;
|
||||
main0_out out = {};
|
||||
out.color_out = float4(1.0, 0.0, 0.0, 1.0);
|
||||
gl_FragDepth = 0.699999988079071044921875;
|
||||
return out;
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
float4 color_out [[color(0)]];
|
||||
float gl_FragDepth [[depth(less)]];
|
||||
};
|
||||
|
||||
fragment main0_out main0()
|
||||
{
|
||||
main0_out out = {};
|
||||
out.color_out = float4(1.0, 0.0, 0.0, 1.0);
|
||||
out.gl_FragDepth = 0.699999988079071044921875;
|
||||
return out;
|
||||
}
|
||||
|
19
reference/shaders-msl/frag/depth-out-early-frag-tests.frag
Normal file
19
reference/shaders-msl/frag/depth-out-early-frag-tests.frag
Normal file
@ -0,0 +1,19 @@
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
float4 color_out [[color(0)]];
|
||||
};
|
||||
|
||||
[[ early_fragment_tests ]] fragment main0_out main0()
|
||||
{
|
||||
float gl_FragDepth;
|
||||
main0_out out = {};
|
||||
out.color_out = float4(1.0, 0.0, 0.0, 1.0);
|
||||
gl_FragDepth = 0.699999988079071044921875;
|
||||
return out;
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
float4 color_out [[color(0)]];
|
||||
float gl_FragDepth [[depth(less)]];
|
||||
};
|
||||
|
||||
fragment main0_out main0()
|
||||
{
|
||||
main0_out out = {};
|
||||
out.color_out = float4(1.0, 0.0, 0.0, 1.0);
|
||||
out.gl_FragDepth = 0.699999988079071044921875;
|
||||
return out;
|
||||
}
|
||||
|
11
shaders-msl/frag/depth-out-early-frag-tests.frag
Normal file
11
shaders-msl/frag/depth-out-early-frag-tests.frag
Normal file
@ -0,0 +1,11 @@
|
||||
#version 430
|
||||
layout(depth_less) out float gl_FragDepth;
|
||||
layout(early_fragment_tests) in;
|
||||
|
||||
layout(location = 0) out vec4 color_out;
|
||||
|
||||
void main()
|
||||
{
|
||||
color_out = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
gl_FragDepth = 0.699999988079071044921875;
|
||||
}
|
10
shaders-msl/frag/depth-out-no-early-frag-tests.frag
Normal file
10
shaders-msl/frag/depth-out-no-early-frag-tests.frag
Normal file
@ -0,0 +1,10 @@
|
||||
#version 430
|
||||
layout(depth_less) out float gl_FragDepth;
|
||||
|
||||
layout(location = 0) out vec4 color_out;
|
||||
|
||||
void main()
|
||||
{
|
||||
color_out = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
gl_FragDepth = 0.699999988079071044921875;
|
||||
}
|
@ -3364,16 +3364,22 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
|
||||
// It's not enough to simply avoid marking fragment outputs if the pipeline won't
|
||||
// accept them. We can't put them in the struct at all, or otherwise the compiler
|
||||
// complains that the outputs weren't explicitly marked.
|
||||
// Frag depth and stencil outputs are incompatible with explicit early fragment tests.
|
||||
// In GLSL, depth and stencil outputs are just ignored when explicit early fragment tests are required.
|
||||
// In Metal, it's a compilation error, so we need to exclude them from the output struct.
|
||||
if (get_execution_model() == ExecutionModelFragment && storage == StorageClassOutput && !patch &&
|
||||
((is_builtin && ((bi_type == BuiltInFragDepth && !msl_options.enable_frag_depth_builtin) ||
|
||||
(bi_type == BuiltInFragStencilRefEXT && !msl_options.enable_frag_stencil_ref_builtin))) ||
|
||||
((is_builtin && ((bi_type == BuiltInFragDepth && (!msl_options.enable_frag_depth_builtin || uses_explicit_early_fragment_test())) ||
|
||||
(bi_type == BuiltInFragStencilRefEXT && (!msl_options.enable_frag_stencil_ref_builtin || uses_explicit_early_fragment_test())))) ||
|
||||
(!is_builtin && !(msl_options.enable_frag_output_mask & (1 << location)))))
|
||||
{
|
||||
hidden = true;
|
||||
disabled_frag_outputs.push_back(var_id);
|
||||
// If a builtin, force it to have the proper name.
|
||||
// If a builtin, force it to have the proper name, and mark it as not part of the output struct.
|
||||
if (is_builtin)
|
||||
{
|
||||
set_name(var_id, builtin_to_glsl(bi_type, StorageClassFunction));
|
||||
mask_stage_output_by_builtin(bi_type);
|
||||
}
|
||||
}
|
||||
|
||||
// Barycentric inputs must be emitted in stage-in, because they can have interpolation arguments.
|
||||
@ -11156,10 +11162,7 @@ string CompilerMSL::func_type_decl(SPIRType &type)
|
||||
execution.output_vertices, ") ]] vertex");
|
||||
break;
|
||||
case ExecutionModelFragment:
|
||||
entry_type = execution.flags.get(ExecutionModeEarlyFragmentTests) ||
|
||||
execution.flags.get(ExecutionModePostDepthCoverage) ?
|
||||
"[[ early_fragment_tests ]] fragment" :
|
||||
"fragment";
|
||||
entry_type = uses_explicit_early_fragment_test() ? "[[ early_fragment_tests ]] fragment" : "fragment";
|
||||
break;
|
||||
case ExecutionModelTessellationControl:
|
||||
if (!msl_options.supports_msl_version(1, 2))
|
||||
@ -11179,6 +11182,12 @@ string CompilerMSL::func_type_decl(SPIRType &type)
|
||||
return entry_type + " " + return_type;
|
||||
}
|
||||
|
||||
bool CompilerMSL::uses_explicit_early_fragment_test()
|
||||
{
|
||||
auto &ep_flags = get_entry_point().flags;
|
||||
return ep_flags.get(ExecutionModeEarlyFragmentTests) || ep_flags.get(ExecutionModePostDepthCoverage);
|
||||
}
|
||||
|
||||
// In MSL, address space qualifiers are required for all pointer or reference variables
|
||||
string CompilerMSL::get_argument_address_space(const SPIRVariable &argument)
|
||||
{
|
||||
|
@ -932,6 +932,8 @@ protected:
|
||||
void build_implicit_builtins();
|
||||
uint32_t build_constant_uint_array_pointer();
|
||||
void emit_entry_point_declarations() override;
|
||||
bool uses_explicit_early_fragment_test();
|
||||
|
||||
uint32_t builtin_frag_coord_id = 0;
|
||||
uint32_t builtin_sample_id_id = 0;
|
||||
uint32_t builtin_sample_mask_id = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user