diff options
author | Bill Hollings <bill.hollings@brenwill.com> | 2021-11-12 22:17:00 +0300 |
---|---|---|
committer | Bill Hollings <bill.hollings@brenwill.com> | 2021-11-12 22:17:00 +0300 |
commit | 248e9ae9ed583f37b2bc5205535a9530fd2ac90b (patch) | |
tree | 52d1343dea5321239257467ac59b0e05bc5c7b75 | |
parent | 401296d3b8fc60193e99ccabb81eb3e4fe2dd802 (diff) |
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.
-rw-r--r-- | reference/opt/shaders-msl/frag/depth-out-early-frag-tests.frag | 19 | ||||
-rw-r--r-- | reference/opt/shaders-msl/frag/depth-out-no-early-frag-tests.frag | 19 | ||||
-rw-r--r-- | reference/shaders-msl/frag/depth-out-early-frag-tests.frag | 19 | ||||
-rw-r--r-- | reference/shaders-msl/frag/depth-out-no-early-frag-tests.frag | 19 | ||||
-rw-r--r-- | shaders-msl/frag/depth-out-early-frag-tests.frag | 11 | ||||
-rw-r--r-- | shaders-msl/frag/depth-out-no-early-frag-tests.frag | 10 | ||||
-rw-r--r-- | spirv_msl.cpp | 23 | ||||
-rw-r--r-- | spirv_msl.hpp | 2 |
8 files changed, 115 insertions, 7 deletions
diff --git a/reference/opt/shaders-msl/frag/depth-out-early-frag-tests.frag b/reference/opt/shaders-msl/frag/depth-out-early-frag-tests.frag new file mode 100644 index 00000000..21884d81 --- /dev/null +++ b/reference/opt/shaders-msl/frag/depth-out-early-frag-tests.frag @@ -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; +} + diff --git a/reference/opt/shaders-msl/frag/depth-out-no-early-frag-tests.frag b/reference/opt/shaders-msl/frag/depth-out-no-early-frag-tests.frag new file mode 100644 index 00000000..57d810fa --- /dev/null +++ b/reference/opt/shaders-msl/frag/depth-out-no-early-frag-tests.frag @@ -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; +} + diff --git a/reference/shaders-msl/frag/depth-out-early-frag-tests.frag b/reference/shaders-msl/frag/depth-out-early-frag-tests.frag new file mode 100644 index 00000000..21884d81 --- /dev/null +++ b/reference/shaders-msl/frag/depth-out-early-frag-tests.frag @@ -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; +} + diff --git a/reference/shaders-msl/frag/depth-out-no-early-frag-tests.frag b/reference/shaders-msl/frag/depth-out-no-early-frag-tests.frag new file mode 100644 index 00000000..57d810fa --- /dev/null +++ b/reference/shaders-msl/frag/depth-out-no-early-frag-tests.frag @@ -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; +} + diff --git a/shaders-msl/frag/depth-out-early-frag-tests.frag b/shaders-msl/frag/depth-out-early-frag-tests.frag new file mode 100644 index 00000000..4208d79a --- /dev/null +++ b/shaders-msl/frag/depth-out-early-frag-tests.frag @@ -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; +} diff --git a/shaders-msl/frag/depth-out-no-early-frag-tests.frag b/shaders-msl/frag/depth-out-no-early-frag-tests.frag new file mode 100644 index 00000000..84502079 --- /dev/null +++ b/shaders-msl/frag/depth-out-no-early-frag-tests.frag @@ -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; +} diff --git a/spirv_msl.cpp b/spirv_msl.cpp index b08bb86f..fabf2e9c 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -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) { diff --git a/spirv_msl.hpp b/spirv_msl.hpp index d1d2ef3e..f01cceaf 100644 --- a/spirv_msl.hpp +++ b/spirv_msl.hpp @@ -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; |