1 /*
2 * Copyright 2023 Alyssa Rosenzweig
3 * Copyright 2021 Intel Corporation
4 * SPDX-License-Identifier: MIT
5 */
6
7 #include "agx_tilebuffer.h"
8 #include "nir.h"
9 #include "nir_builder.h"
10
11 /*
12 * Lower alpha-to-coverage to sample_mask and some math. May run on either a
13 * monolithic pixel shader or a fragment epilogue.
14 */
15 bool
agx_nir_lower_alpha_to_coverage(nir_shader * shader,uint8_t nr_samples)16 agx_nir_lower_alpha_to_coverage(nir_shader *shader, uint8_t nr_samples)
17 {
18 /* nir_lower_io_to_temporaries ensures that stores are in the last block */
19 nir_function_impl *impl = nir_shader_get_entrypoint(shader);
20 nir_block *block = nir_impl_last_block(impl);
21
22 /* The store is probably at the end of the block, so search in reverse. */
23 nir_intrinsic_instr *store = NULL;
24 nir_foreach_instr_reverse(instr, block) {
25 if (instr->type != nir_instr_type_intrinsic)
26 continue;
27
28 nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
29 if (intr->intrinsic != nir_intrinsic_store_output)
30 continue;
31
32 nir_io_semantics sem = nir_intrinsic_io_semantics(intr);
33 if (sem.location != FRAG_RESULT_DATA0)
34 continue;
35 if (sem.dual_source_blend_index != 0)
36 continue;
37
38 store = intr;
39 break;
40 }
41
42 /* If render target 0 isn't written, the alpha value input to
43 * alpha-to-coverage is undefined. We assume that the alpha would be 1.0,
44 * which would effectively disable alpha-to-coverage, skipping the lowering.
45 *
46 * Similarly, if there are less than 4 components, alpha is undefined.
47 */
48 nir_def *rgba = store ? store->src[0].ssa : NULL;
49 if (!rgba || rgba->num_components < 4) {
50 nir_metadata_preserve(impl, nir_metadata_all);
51 return false;
52 }
53
54 nir_builder _b = nir_builder_at(nir_before_instr(&store->instr));
55 nir_builder *b = &_b;
56
57 /* Calculate a coverage mask (alpha * nr_samples) bits set. The way we do
58 * this isn't particularly clever:
59 *
60 * # of bits = (unsigned int) (alpha * nr_samples)
61 * mask = (1 << (# of bits)) - 1
62 */
63 nir_def *alpha = nir_channel(b, rgba, 3);
64 nir_def *bits = nir_f2u32(b, nir_fmul_imm(b, alpha, nr_samples));
65 nir_def *mask =
66 nir_iadd_imm(b, nir_ishl(b, nir_imm_intN_t(b, 1, 16), bits), -1);
67
68 /* Discard samples that aren't covered */
69 nir_discard_agx(b, nir_inot(b, mask));
70 shader->info.fs.uses_discard = true;
71 nir_metadata_preserve(impl, nir_metadata_control_flow);
72 return true;
73 }
74
75 /*
76 * Modify the inputs to store_output instructions in a pixel shader when
77 * alpha-to-one is used. May run on either a monolithic pixel shader or a
78 * fragment epilogue.
79 */
80 bool
agx_nir_lower_alpha_to_one(nir_shader * shader)81 agx_nir_lower_alpha_to_one(nir_shader *shader)
82 {
83 bool progress = false;
84
85 /* nir_lower_io_to_temporaries ensures that stores are in the last block */
86 nir_function_impl *impl = nir_shader_get_entrypoint(shader);
87 nir_block *block = nir_impl_last_block(impl);
88
89 nir_foreach_instr(instr, block) {
90 if (instr->type != nir_instr_type_intrinsic)
91 continue;
92
93 nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
94 if (intr->intrinsic != nir_intrinsic_store_output)
95 continue;
96
97 /* The OpenGL spec is a bit confusing here, but seemingly alpha-to-one
98 * applies to all render targets. Piglit
99 * ext_framebuffer_multisample-draw-buffers-alpha-to-one checks this.
100 *
101 * Even more confusingly, it seems to apply to dual-source blending too.
102 * ext_framebuffer_multisample-alpha-to-one-dual-src-blend checks this.
103 */
104 nir_io_semantics sem = nir_intrinsic_io_semantics(intr);
105 if (sem.location < FRAG_RESULT_DATA0)
106 continue;
107
108 nir_def *rgba = intr->src[0].ssa;
109 if (rgba->num_components < 4)
110 continue;
111
112 nir_builder b = nir_builder_at(nir_before_instr(instr));
113 nir_def *rgb1 = nir_vector_insert_imm(
114 &b, rgba, nir_imm_floatN_t(&b, 1.0, rgba->bit_size), 3);
115
116 nir_src_rewrite(&intr->src[0], rgb1);
117 progress = true;
118 }
119
120 if (progress) {
121 nir_metadata_preserve(impl, nir_metadata_control_flow);
122 } else {
123 nir_metadata_preserve(impl, nir_metadata_all);
124 }
125
126 return progress;
127 }
128