1 /*
2 * Copyright 2022 Alyssa Rosenzweig
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "compiler/nir/nir.h"
7 #include "compiler/nir/nir_builder.h"
8 #include "agx_compiler.h"
9
10 /* Fragment shaders with side effects require special handling to ensure the
11 * side effects execute as intended. By default, they require late depth
12 * testing, to ensure the side effects happen even for killed pixels. To handle,
13 * the driver inserts a dummy `gl_FragDepth = gl_Position.z` in shaders that
14 * don't otherwise write their depth, forcing a late depth test.
15 *
16 * For side effects with force early testing forced, the sample mask is written
17 * at the *beginning* of the shader.
18 */
19
20 #define ALL_SAMPLES (0xFF)
21
22 static void
insert_z_write(nir_builder * b)23 insert_z_write(nir_builder *b)
24 {
25 /* When forcing depth test to NEVER, force Z to NaN. This works around the
26 * hardware discarding depth=NEVER.
27 *
28 * TODO: Check if Apple has a better way of handling this.
29 */
30 nir_def *bias = nir_bcsel(b, nir_ine_imm(b, nir_load_depth_never_agx(b), 0),
31 nir_imm_float(b, NAN), nir_imm_float(b, -0.0));
32
33 nir_def *z = nir_fadd(b, bias, nir_load_frag_coord_zw(b, .component = 2));
34
35 nir_store_output(b, z, nir_imm_int(b, 0),
36 .io_semantics.location = FRAG_RESULT_DEPTH,
37 .src_type = nir_type_float32);
38
39 b->shader->info.outputs_written |= BITFIELD64_BIT(FRAG_RESULT_DEPTH);
40 }
41
42 static bool
pass(struct nir_builder * b,nir_intrinsic_instr * intr,void * data)43 pass(struct nir_builder *b, nir_intrinsic_instr *intr, void *data)
44 {
45 if (intr->intrinsic != nir_intrinsic_store_output)
46 return false;
47
48 /* Only lower once */
49 bool *done = data;
50 if (*done)
51 return false;
52 *done = true;
53
54 b->cursor = nir_before_instr(&intr->instr);
55 insert_z_write(b);
56 return true;
57 }
58
59 bool
agx_nir_lower_frag_sidefx(nir_shader * s)60 agx_nir_lower_frag_sidefx(nir_shader *s)
61 {
62 assert(s->info.stage == MESA_SHADER_FRAGMENT);
63
64 /* If there are no side effects, there's nothing to lower */
65 if (!s->info.writes_memory)
66 return false;
67
68 /* Lower writes from helper invocations with the common pass. The hardware
69 * will predicate simple writes for us, but that fails with sample shading so
70 * we do that in software too.
71 */
72 NIR_PASS(_, s, nir_lower_helper_writes, s->info.fs.uses_sample_shading);
73
74 bool writes_zs =
75 s->info.outputs_written &
76 (BITFIELD64_BIT(FRAG_RESULT_STENCIL) | BITFIELD64_BIT(FRAG_RESULT_DEPTH));
77
78 /* If the shader wants early fragment tests, the sample mask lowering pass
79 * will trigger an early test at the beginning of the shader. This lets us
80 * use a Passthrough punch type, instead of Opaque which may result in the
81 * shader getting skipped incorrectly and then the side effects not kicking
82 * in. But this happens there to avoid it happening twice with a discard.
83 */
84 if (s->info.fs.early_fragment_tests)
85 return false;
86
87 /* If depth/stencil feedback is already used, we're done */
88 if (writes_zs)
89 return false;
90
91 bool done = false;
92 nir_shader_intrinsics_pass(s, pass, nir_metadata_control_flow, &done);
93
94 /* If there's no render targets written, just put the write at the end */
95 if (!done) {
96 nir_function_impl *impl = nir_shader_get_entrypoint(s);
97 nir_builder b = nir_builder_at(nir_after_impl(impl));
98
99 insert_z_write(&b);
100 }
101
102 return true;
103 }
104