xref: /aosp_15_r20/external/mesa3d/src/asahi/lib/agx_bg_eot.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2022 Alyssa Rosenzweig
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include "agx_bg_eot.h"
7 #include "agx_compile.h"
8 #include "agx_device.h" /* for AGX_MEMORY_TYPE_SHADER */
9 #include "agx_nir_passes.h"
10 #include "agx_tilebuffer.h"
11 #include "nir.h"
12 #include "nir_builder.h"
13 #include "nir_intrinsics.h"
14 
15 static bool
lower_tex_handle_to_u0(nir_builder * b,nir_intrinsic_instr * intr,void * data)16 lower_tex_handle_to_u0(nir_builder *b, nir_intrinsic_instr *intr, void *data)
17 {
18    if (intr->intrinsic != nir_intrinsic_load_texture_handle_agx)
19       return false;
20 
21    b->cursor = nir_instr_remove(&intr->instr);
22    nir_def_rewrite_uses(
23       &intr->def,
24       nir_vec2(b, nir_imm_int(b, 0), nir_imul_imm(b, intr->src[0].ssa, 24)));
25 
26    return true;
27 }
28 
29 static struct agx_bg_eot_shader *
agx_compile_bg_eot_shader(struct agx_bg_eot_cache * cache,nir_shader * shader,struct agx_shader_key * key,struct agx_tilebuffer_layout * tib)30 agx_compile_bg_eot_shader(struct agx_bg_eot_cache *cache, nir_shader *shader,
31                           struct agx_shader_key *key,
32                           struct agx_tilebuffer_layout *tib)
33 {
34    agx_nir_lower_texture(shader);
35    agx_preprocess_nir(shader, cache->dev->libagx);
36    if (tib) {
37       unsigned bindless_base = 0;
38       agx_nir_lower_tilebuffer(shader, tib, NULL, &bindless_base, NULL, NULL);
39       agx_nir_lower_monolithic_msaa(shader, tib->nr_samples);
40       agx_nir_lower_multisampled_image_store(shader);
41       agx_nir_lower_texture(shader);
42 
43       nir_shader_intrinsics_pass(shader, lower_tex_handle_to_u0,
44                                  nir_metadata_control_flow, NULL);
45    }
46 
47    key->libagx = cache->dev->libagx;
48 
49    struct agx_bg_eot_shader *res = rzalloc(cache->ht, struct agx_bg_eot_shader);
50    struct agx_shader_part bin;
51    agx_compile_shader_nir(shader, key, NULL, &bin);
52 
53    res->info = bin.info;
54    res->ptr = agx_pool_upload_aligned_with_bo(&cache->pool, bin.binary,
55                                               bin.binary_size, 128, &res->bo);
56    free(bin.binary);
57    ralloc_free(shader);
58 
59    return res;
60 }
61 
62 static nir_def *
build_background_op(nir_builder * b,enum agx_bg_eot_op op,unsigned rt,unsigned nr,bool msaa,bool layered)63 build_background_op(nir_builder *b, enum agx_bg_eot_op op, unsigned rt,
64                     unsigned nr, bool msaa, bool layered)
65 {
66    if (op == AGX_BG_LOAD) {
67       nir_def *coord = nir_u2u32(b, nir_load_pixel_coord(b));
68 
69       if (layered) {
70          coord = nir_vec3(b, nir_channel(b, coord, 0), nir_channel(b, coord, 1),
71                           nir_load_layer_id(b));
72       }
73 
74       nir_tex_instr *tex = nir_tex_instr_create(b->shader, 2);
75       /* The type doesn't matter as long as it matches the store */
76       tex->dest_type = nir_type_uint32;
77       tex->sampler_dim = msaa ? GLSL_SAMPLER_DIM_MS : GLSL_SAMPLER_DIM_2D;
78       tex->is_array = layered;
79       tex->op = msaa ? nir_texop_txf_ms : nir_texop_txf;
80       tex->src[0] = nir_tex_src_for_ssa(nir_tex_src_coord, coord);
81 
82       /* Layer is necessarily already in-bounds so we do not want the compiler
83        * to clamp it, which would require reading the descriptor
84        */
85       tex->backend_flags = AGX_TEXTURE_FLAG_NO_CLAMP;
86 
87       if (msaa) {
88          tex->src[1] =
89             nir_tex_src_for_ssa(nir_tex_src_ms_index, nir_load_sample_id(b));
90          b->shader->info.fs.uses_sample_shading = true;
91       } else {
92          tex->src[1] = nir_tex_src_for_ssa(nir_tex_src_lod, nir_imm_int(b, 0));
93       }
94 
95       tex->coord_components = layered ? 3 : 2;
96       tex->texture_index = rt * 2;
97       nir_def_init(&tex->instr, &tex->def, 4, 32);
98       nir_builder_instr_insert(b, &tex->instr);
99 
100       return nir_trim_vector(b, &tex->def, nr);
101    } else {
102       assert(op == AGX_BG_CLEAR);
103 
104       return nir_load_preamble(b, nr, 32, 4 + (rt * 8));
105    }
106 }
107 
108 static struct agx_bg_eot_shader *
agx_build_background_shader(struct agx_bg_eot_cache * cache,struct agx_bg_eot_key * key)109 agx_build_background_shader(struct agx_bg_eot_cache *cache,
110                             struct agx_bg_eot_key *key)
111 {
112    nir_builder b = nir_builder_init_simple_shader(
113       MESA_SHADER_FRAGMENT, &agx_nir_options, "agx_background");
114    b.shader->info.fs.untyped_color_outputs = true;
115 
116    struct agx_shader_key compiler_key = {
117       .fs.ignore_tib_dependencies = true,
118       .reserved_preamble = key->reserved_preamble,
119    };
120 
121    for (unsigned rt = 0; rt < ARRAY_SIZE(key->op); ++rt) {
122       if (key->op[rt] == AGX_BG_EOT_NONE)
123          continue;
124 
125       unsigned nr = util_format_get_nr_components(key->tib.logical_format[rt]);
126       bool msaa = key->tib.nr_samples > 1;
127       bool layered = key->tib.layered;
128       assert(nr > 0);
129 
130       nir_store_output(
131          &b, build_background_op(&b, key->op[rt], rt, nr, msaa, layered),
132          nir_imm_int(&b, 0), .write_mask = BITFIELD_MASK(nr),
133          .src_type = nir_type_uint32,
134          .io_semantics.location = FRAG_RESULT_DATA0 + rt,
135          .io_semantics.num_slots = 1);
136 
137       b.shader->info.outputs_written |= BITFIELD64_BIT(FRAG_RESULT_DATA0 + rt);
138    }
139 
140    return agx_compile_bg_eot_shader(cache, b.shader, &compiler_key, &key->tib);
141 }
142 
143 static struct agx_bg_eot_shader *
agx_build_end_of_tile_shader(struct agx_bg_eot_cache * cache,struct agx_bg_eot_key * key)144 agx_build_end_of_tile_shader(struct agx_bg_eot_cache *cache,
145                              struct agx_bg_eot_key *key)
146 {
147    nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_COMPUTE,
148                                                   &agx_nir_options, "agx_eot");
149 
150    enum glsl_sampler_dim dim =
151       (key->tib.nr_samples > 1) ? GLSL_SAMPLER_DIM_MS : GLSL_SAMPLER_DIM_2D;
152 
153    for (unsigned rt = 0; rt < ARRAY_SIZE(key->op); ++rt) {
154       if (key->op[rt] == AGX_BG_EOT_NONE)
155          continue;
156 
157       /* The end-of-tile shader is unsuitable to handle spilled render targets.
158        * Skip them. If blits are needed with spilled render targets, other parts
159        * of the driver need to implement them.
160        */
161       if (key->tib.spilled[rt])
162          continue;
163 
164       assert(key->op[rt] == AGX_EOT_STORE);
165       unsigned offset_B = agx_tilebuffer_offset_B(&key->tib, rt);
166 
167       nir_def *layer = nir_undef(&b, 1, 16);
168       if (key->tib.layered)
169          layer = nir_u2u16(&b, nir_load_layer_id(&b));
170 
171       nir_image_store_block_agx(
172          &b, nir_imm_intN_t(&b, rt, 16), nir_imm_intN_t(&b, offset_B, 16),
173          layer, .format = agx_tilebuffer_physical_format(&key->tib, rt),
174          .image_dim = dim, .image_array = key->tib.layered);
175    }
176 
177    struct agx_shader_key compiler_key = {
178       .reserved_preamble = key->reserved_preamble,
179    };
180 
181    return agx_compile_bg_eot_shader(cache, b.shader, &compiler_key, NULL);
182 }
183 
184 struct agx_bg_eot_shader *
agx_get_bg_eot_shader(struct agx_bg_eot_cache * cache,struct agx_bg_eot_key * key)185 agx_get_bg_eot_shader(struct agx_bg_eot_cache *cache,
186                       struct agx_bg_eot_key *key)
187 {
188    struct hash_entry *ent = _mesa_hash_table_search(cache->ht, key);
189    if (ent)
190       return ent->data;
191 
192    struct agx_bg_eot_shader *ret = NULL;
193 
194    for (unsigned rt = 0; rt < ARRAY_SIZE(key->op); ++rt) {
195       if (key->op[rt] == AGX_EOT_STORE) {
196          ret = agx_build_end_of_tile_shader(cache, key);
197          break;
198       }
199    }
200 
201    if (!ret)
202       ret = agx_build_background_shader(cache, key);
203 
204    ret->key = *key;
205    _mesa_hash_table_insert(cache->ht, &ret->key, ret);
206    return ret;
207 }
208 
209 DERIVE_HASH_TABLE(agx_bg_eot_key);
210 
211 void
agx_bg_eot_init(struct agx_bg_eot_cache * cache,struct agx_device * dev)212 agx_bg_eot_init(struct agx_bg_eot_cache *cache, struct agx_device *dev)
213 {
214    agx_pool_init(&cache->pool, dev, AGX_BO_EXEC | AGX_BO_LOW_VA, true);
215    cache->ht = agx_bg_eot_key_table_create(NULL);
216    cache->dev = dev;
217 }
218 
219 void
agx_bg_eot_cleanup(struct agx_bg_eot_cache * cache)220 agx_bg_eot_cleanup(struct agx_bg_eot_cache *cache)
221 {
222    agx_pool_cleanup(&cache->pool);
223    _mesa_hash_table_destroy(cache->ht, NULL);
224    cache->ht = NULL;
225    cache->dev = NULL;
226 }
227