• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 Alyssa Rosenzweig
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include "agx_meta.h"
7 #include "agx_device.h" /* for AGX_MEMORY_TYPE_SHADER */
8 #include "agx_nir_passes.h"
9 #include "agx_tilebuffer.h"
10 #include "nir.h"
11 #include "nir_builder.h"
12 #include "nir_intrinsics.h"
13 
14 static bool
lower_tex_handle_to_u0(nir_builder * b,nir_intrinsic_instr * intr,void * data)15 lower_tex_handle_to_u0(nir_builder *b, nir_intrinsic_instr *intr, void *data)
16 {
17    if (intr->intrinsic != nir_intrinsic_load_texture_handle_agx)
18       return false;
19 
20    b->cursor = nir_instr_remove(&intr->instr);
21    nir_def_rewrite_uses(
22       &intr->def,
23       nir_vec2(b, nir_imm_int(b, 0), nir_imul_imm(b, intr->src[0].ssa, 24)));
24 
25    return true;
26 }
27 
28 static struct agx_meta_shader *
agx_compile_meta_shader(struct agx_meta_cache * cache,nir_shader * shader,struct agx_shader_key * key,struct agx_tilebuffer_layout * tib)29 agx_compile_meta_shader(struct agx_meta_cache *cache, nir_shader *shader,
30                         struct agx_shader_key *key,
31                         struct agx_tilebuffer_layout *tib)
32 {
33    struct util_dynarray binary;
34    util_dynarray_init(&binary, NULL);
35 
36    agx_nir_lower_texture(shader);
37    agx_preprocess_nir(shader, cache->dev->libagx, false, NULL);
38    if (tib) {
39       unsigned bindless_base = 0;
40       agx_nir_lower_tilebuffer(shader, tib, NULL, &bindless_base, NULL, true);
41       agx_nir_lower_monolithic_msaa(
42          shader, &(struct agx_msaa_state){.nr_samples = tib->nr_samples});
43       agx_nir_lower_multisampled_image_store(shader);
44 
45       nir_shader_intrinsics_pass(
46          shader, lower_tex_handle_to_u0,
47          nir_metadata_dominance | nir_metadata_block_index, NULL);
48    }
49 
50    key->libagx = cache->dev->libagx;
51 
52    struct agx_meta_shader *res = rzalloc(cache->ht, struct agx_meta_shader);
53    agx_compile_shader_nir(shader, key, NULL, &binary, &res->info);
54 
55    res->ptr = agx_pool_upload_aligned_with_bo(&cache->pool, binary.data,
56                                               binary.size, 128, &res->bo);
57    util_dynarray_fini(&binary);
58    ralloc_free(shader);
59 
60    return res;
61 }
62 
63 static nir_def *
build_background_op(nir_builder * b,enum agx_meta_op op,unsigned rt,unsigned nr,bool msaa,bool layered)64 build_background_op(nir_builder *b, enum agx_meta_op op, unsigned rt,
65                     unsigned nr, bool msaa, bool layered)
66 {
67    if (op == AGX_META_OP_LOAD) {
68       nir_def *coord = nir_u2u32(b, nir_load_pixel_coord(b));
69 
70       if (layered) {
71          coord = nir_vec3(b, nir_channel(b, coord, 0), nir_channel(b, coord, 1),
72                           agx_internal_layer_id(b));
73       }
74 
75       nir_tex_instr *tex = nir_tex_instr_create(b->shader, 2);
76       /* The type doesn't matter as long as it matches the store */
77       tex->dest_type = nir_type_uint32;
78       tex->sampler_dim = msaa ? GLSL_SAMPLER_DIM_MS : GLSL_SAMPLER_DIM_2D;
79       tex->is_array = layered;
80       tex->op = msaa ? nir_texop_txf_ms : nir_texop_txf;
81       tex->src[0] = nir_tex_src_for_ssa(nir_tex_src_coord, coord);
82 
83       /* Layer is necessarily already in-bounds so we do not want the compiler
84        * to clamp it, which would require reading the descriptor
85        */
86       tex->backend_flags = AGX_TEXTURE_FLAG_NO_CLAMP;
87 
88       if (msaa) {
89          tex->src[1] =
90             nir_tex_src_for_ssa(nir_tex_src_ms_index, nir_load_sample_id(b));
91          b->shader->info.fs.uses_sample_shading = true;
92       } else {
93          tex->src[1] = nir_tex_src_for_ssa(nir_tex_src_lod, nir_imm_int(b, 0));
94       }
95 
96       tex->coord_components = layered ? 3 : 2;
97       tex->texture_index = rt * 2;
98       nir_def_init(&tex->instr, &tex->def, 4, 32);
99       nir_builder_instr_insert(b, &tex->instr);
100 
101       return nir_trim_vector(b, &tex->def, nr);
102    } else {
103       assert(op == AGX_META_OP_CLEAR);
104 
105       return nir_load_preamble(b, nr, 32, 4 + (rt * 8));
106    }
107 }
108 
109 static struct agx_meta_shader *
agx_build_background_shader(struct agx_meta_cache * cache,struct agx_meta_key * key)110 agx_build_background_shader(struct agx_meta_cache *cache,
111                             struct agx_meta_key *key)
112 {
113    nir_builder b = nir_builder_init_simple_shader(
114       MESA_SHADER_FRAGMENT, &agx_nir_options, "agx_background");
115    b.shader->info.fs.untyped_color_outputs = true;
116 
117    struct agx_shader_key compiler_key = {
118       .fs.ignore_tib_dependencies = true,
119       .reserved_preamble = key->reserved_preamble,
120    };
121 
122    for (unsigned rt = 0; rt < ARRAY_SIZE(key->op); ++rt) {
123       if (key->op[rt] == AGX_META_OP_NONE)
124          continue;
125 
126       unsigned nr = util_format_get_nr_components(key->tib.logical_format[rt]);
127       bool msaa = key->tib.nr_samples > 1;
128       bool layered = key->tib.layered;
129       assert(nr > 0);
130 
131       nir_store_output(
132          &b, build_background_op(&b, key->op[rt], rt, nr, msaa, layered),
133          nir_imm_int(&b, 0), .write_mask = BITFIELD_MASK(nr),
134          .src_type = nir_type_uint32,
135          .io_semantics.location = FRAG_RESULT_DATA0 + rt,
136          .io_semantics.num_slots = 1);
137 
138       b.shader->info.outputs_written |= BITFIELD64_BIT(FRAG_RESULT_DATA0 + rt);
139    }
140 
141    return agx_compile_meta_shader(cache, b.shader, &compiler_key, &key->tib);
142 }
143 
144 static struct agx_meta_shader *
agx_build_end_of_tile_shader(struct agx_meta_cache * cache,struct agx_meta_key * key)145 agx_build_end_of_tile_shader(struct agx_meta_cache *cache,
146                              struct agx_meta_key *key)
147 {
148    nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_COMPUTE,
149                                                   &agx_nir_options, "agx_eot");
150 
151    enum glsl_sampler_dim dim =
152       (key->tib.nr_samples > 1) ? GLSL_SAMPLER_DIM_MS : GLSL_SAMPLER_DIM_2D;
153 
154    for (unsigned rt = 0; rt < ARRAY_SIZE(key->op); ++rt) {
155       if (key->op[rt] == AGX_META_OP_NONE)
156          continue;
157 
158       /* The end-of-tile shader is unsuitable to handle spilled render targets.
159        * Skip them. If blits are needed with spilled render targets, other parts
160        * of the driver need to implement them.
161        */
162       if (key->tib.spilled[rt])
163          continue;
164 
165       assert(key->op[rt] == AGX_META_OP_STORE);
166       unsigned offset_B = agx_tilebuffer_offset_B(&key->tib, rt);
167 
168       nir_def *layer = nir_undef(&b, 1, 16);
169       if (key->tib.layered)
170          layer = nir_u2u16(&b, agx_internal_layer_id(&b));
171 
172       nir_block_image_store_agx(
173          &b, nir_imm_int(&b, rt), nir_imm_intN_t(&b, offset_B, 16), layer,
174          .format = agx_tilebuffer_physical_format(&key->tib, rt),
175          .image_dim = dim, .image_array = key->tib.layered);
176    }
177 
178    struct agx_shader_key compiler_key = {
179       .reserved_preamble = key->reserved_preamble,
180    };
181 
182    return agx_compile_meta_shader(cache, b.shader, &compiler_key, NULL);
183 }
184 
185 struct agx_meta_shader *
agx_get_meta_shader(struct agx_meta_cache * cache,struct agx_meta_key * key)186 agx_get_meta_shader(struct agx_meta_cache *cache, struct agx_meta_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_meta_shader *ret = NULL;
193 
194    for (unsigned rt = 0; rt < ARRAY_SIZE(key->op); ++rt) {
195       if (key->op[rt] == AGX_META_OP_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 static uint32_t
key_hash(const void * key)210 key_hash(const void *key)
211 {
212    return _mesa_hash_data(key, sizeof(struct agx_meta_key));
213 }
214 
215 static bool
key_compare(const void * a,const void * b)216 key_compare(const void *a, const void *b)
217 {
218    return memcmp(a, b, sizeof(struct agx_meta_key)) == 0;
219 }
220 
221 void
agx_meta_init(struct agx_meta_cache * cache,struct agx_device * dev)222 agx_meta_init(struct agx_meta_cache *cache, struct agx_device *dev)
223 {
224    agx_pool_init(&cache->pool, dev, AGX_BO_EXEC | AGX_BO_LOW_VA, true);
225    cache->ht = _mesa_hash_table_create(NULL, key_hash, key_compare);
226    cache->dev = dev;
227 }
228 
229 void
agx_meta_cleanup(struct agx_meta_cache * cache)230 agx_meta_cleanup(struct agx_meta_cache *cache)
231 {
232    agx_pool_cleanup(&cache->pool);
233    _mesa_hash_table_destroy(cache->ht, NULL);
234    cache->ht = NULL;
235    cache->dev = NULL;
236 }
237