agx/lower_tilebuffer: Support spilled layered RTs
authorAlyssa Rosenzweig <alyssa@rosenzweig.io>
Mon, 28 Aug 2023 12:36:40 +0000 (08:36 -0400)
committerAlyssa Rosenzweig <alyssa@rosenzweig.io>
Sun, 1 Oct 2023 16:37:55 +0000 (12:37 -0400)
If we spill render targets with a layered framebuffer, our spilled targets are
assumed to be 2D Arrays (in general). We need to use arrayed image operations to
load/store from these. The layer is given by the layer as read in the fragemnt
shader. This handles the eMRT portion of layered rendering.

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
src/asahi/lib/agx_meta.c
src/asahi/lib/agx_nir_lower_tilebuffer.c
src/asahi/lib/agx_tilebuffer.h
src/gallium/drivers/asahi/agx_state.c

index 12e828c..5f49025 100644 (file)
@@ -20,7 +20,7 @@ agx_compile_meta_shader(struct agx_meta_cache *cache, nir_shader *shader,
    agx_preprocess_nir(shader, false, false, NULL);
    if (tib) {
       unsigned bindless_base = 0;
-      agx_nir_lower_tilebuffer(shader, tib, NULL, &bindless_base, NULL);
+      agx_nir_lower_tilebuffer(shader, tib, NULL, &bindless_base, NULL, true);
       agx_nir_lower_monolithic_msaa(
          shader, &(struct agx_msaa_state){.nr_samples = tib->nr_samples});
    }
index 4bb6b05..763b3cf 100644 (file)
@@ -22,6 +22,7 @@ struct ctx {
    bool *translucent;
    unsigned bindless_base;
    bool any_memory_stores;
+   bool layer_id_sr;
    uint8_t outputs_written;
 };
 
@@ -131,14 +132,21 @@ dim_for_rt(nir_builder *b, unsigned nr_samples, nir_def **sample)
 }
 
 static nir_def *
-image_coords(nir_builder *b)
+image_coords(nir_builder *b, nir_def *layer_id)
 {
-   return nir_pad_vector(b, nir_u2u32(b, nir_load_pixel_coord(b)), 4);
+   nir_def *xy = nir_u2u32(b, nir_load_pixel_coord(b));
+   nir_def *vec = nir_pad_vector(b, xy, 4);
+
+   if (layer_id)
+      vec = nir_vector_insert_imm(b, vec, layer_id, 2);
+
+   return vec;
 }
 
 static void
 store_memory(nir_builder *b, unsigned bindless_base, unsigned nr_samples,
-             enum pipe_format format, unsigned rt, nir_def *value)
+             nir_def *layer_id, enum pipe_format format, unsigned rt,
+             nir_def *value)
 {
    /* Force bindless for multisampled image writes since they will be lowered
     * with a descriptor crawl later.
@@ -150,7 +158,7 @@ store_memory(nir_builder *b, unsigned bindless_base, unsigned nr_samples,
 
    nir_def *sample;
    enum glsl_sampler_dim dim = dim_for_rt(b, nr_samples, &sample);
-   nir_def *coords = image_coords(b);
+   nir_def *coords = image_coords(b, layer_id);
 
    nir_begin_invocation_interlock(b);
 
@@ -163,12 +171,12 @@ store_memory(nir_builder *b, unsigned bindless_base, unsigned nr_samples,
    }
 
    if (bindless) {
-      nir_bindless_image_store(
-         b, image, coords, sample, value, lod, .image_dim = dim,
-         .image_array = false /* TODO */, .format = format);
+      nir_bindless_image_store(b, image, coords, sample, value, lod,
+                               .image_dim = dim, .image_array = !!layer_id,
+                               .format = format);
    } else {
       nir_image_store(b, image, coords, sample, value, lod, .image_dim = dim,
-                      .image_array = false /* TODO */, .format = format);
+                      .image_array = !!layer_id, .format = format);
    }
 
    if (nr_samples > 1)
@@ -179,7 +187,7 @@ store_memory(nir_builder *b, unsigned bindless_base, unsigned nr_samples,
 
 static nir_def *
 load_memory(nir_builder *b, unsigned bindless_base, unsigned nr_samples,
-            uint8_t comps, uint8_t bit_size, unsigned rt,
+            nir_def *layer_id, uint8_t comps, uint8_t bit_size, unsigned rt,
             enum pipe_format format)
 {
    bool bindless = false;
@@ -189,7 +197,7 @@ load_memory(nir_builder *b, unsigned bindless_base, unsigned nr_samples,
 
    nir_def *sample;
    enum glsl_sampler_dim dim = dim_for_rt(b, nr_samples, &sample);
-   nir_def *coords = image_coords(b);
+   nir_def *coords = image_coords(b, layer_id);
 
    /* Ensure pixels below this one have written out their results */
    nir_begin_invocation_interlock(b);
@@ -197,10 +205,10 @@ load_memory(nir_builder *b, unsigned bindless_base, unsigned nr_samples,
    if (bindless) {
       return nir_bindless_image_load(
          b, comps, bit_size, image, coords, sample, lod, .image_dim = dim,
-         .image_array = false /* TODO */, .format = format);
+         .image_array = !!layer_id, .format = format);
    } else {
       return nir_image_load(b, comps, bit_size, image, coords, sample, lod,
-                            .image_dim = dim, .image_array = false /* TODO */,
+                            .image_dim = dim, .image_array = !!layer_id,
                             .format = format);
    }
 }
@@ -215,6 +223,23 @@ agx_internal_layer_id(nir_builder *b)
 }
 
 static nir_def *
+tib_layer_id(nir_builder *b, struct ctx *ctx)
+{
+   if (!ctx->tib->layered) {
+      /* If we're not layered, there's no explicit layer ID */
+      return NULL;
+   } else if (ctx->layer_id_sr) {
+      return agx_internal_layer_id(b);
+   } else {
+      /* Otherwise, the layer ID is loaded as a flat varying. */
+      b->shader->info.inputs_read |= VARYING_BIT_LAYER;
+
+      return nir_load_input(b, 1, 32, nir_imm_int(b, 0),
+                            .io_semantics.location = VARYING_SLOT_LAYER);
+   }
+}
+
+static nir_def *
 tib_impl(nir_builder *b, nir_instr *instr, void *data)
 {
    struct ctx *ctx = data;
@@ -268,8 +293,8 @@ tib_impl(nir_builder *b, nir_instr *instr, void *data)
       value = nir_trim_vector(b, intr->src[0].ssa, comps);
 
       if (tib->spilled[rt]) {
-         store_memory(b, ctx->bindless_base, tib->nr_samples, logical_format,
-                      rt, value);
+         store_memory(b, ctx->bindless_base, tib->nr_samples,
+                      tib_layer_id(b, ctx), logical_format, rt, value);
          ctx->any_memory_stores = true;
       } else {
          store_tilebuffer(b, tib, format, logical_format, rt, value,
@@ -289,7 +314,8 @@ tib_impl(nir_builder *b, nir_instr *instr, void *data)
          *(ctx->translucent) = true;
 
          return load_memory(b, ctx->bindless_base, tib->nr_samples,
-                            intr->num_components, bit_size, rt, logical_format);
+                            tib_layer_id(b, ctx), intr->num_components,
+                            bit_size, rt, logical_format);
       } else {
          return load_tilebuffer(b, tib, intr->num_components, bit_size, rt,
                                 format, logical_format);
@@ -300,7 +326,7 @@ tib_impl(nir_builder *b, nir_instr *instr, void *data)
 bool
 agx_nir_lower_tilebuffer(nir_shader *shader, struct agx_tilebuffer_layout *tib,
                          uint8_t *colormasks, unsigned *bindless_base,
-                         bool *translucent)
+                         bool *translucent, bool layer_id_sr)
 {
    assert(shader->info.stage == MESA_SHADER_FRAGMENT);
 
@@ -308,6 +334,7 @@ agx_nir_lower_tilebuffer(nir_shader *shader, struct agx_tilebuffer_layout *tib,
       .tib = tib,
       .colormasks = colormasks,
       .translucent = translucent,
+      .layer_id_sr = layer_id_sr,
    };
 
    /* Allocate 1 texture + 1 PBE descriptor for each spilled descriptor */
index 6092c70..3ad3dea 100644 (file)
@@ -91,7 +91,7 @@ agx_build_tilebuffer_layout(enum pipe_format *formats, uint8_t nr_cbufs,
 bool agx_nir_lower_tilebuffer(struct nir_shader *shader,
                               struct agx_tilebuffer_layout *tib,
                               uint8_t *colormasks, unsigned *bindless_base,
-                              bool *translucent);
+                              bool *translucent, bool layer_id_sr);
 
 struct nir_def *agx_internal_layer_id(struct nir_builder *b);
 
index 67426c0..7868940 100644 (file)
@@ -1620,7 +1620,7 @@ agx_compile_variant(struct agx_device *dev, struct agx_uncompiled_shader *so,
                                (2 * BITSET_LAST_BIT(nir->info.images_used));
       unsigned rt_spill = rt_spill_base;
       NIR_PASS_V(nir, agx_nir_lower_tilebuffer, &tib, colormasks, &rt_spill,
-                 &force_translucent);
+                 &force_translucent, false);
 
       /* If anything spilled, we have bindless texture */
       so->internal_bindless |= (rt_spill != rt_spill_base);