asahi, agx: Implement dummy samplers
authorAlyssa Rosenzweig <alyssa@rosenzweig.io>
Fri, 3 Mar 2023 04:02:05 +0000 (23:02 -0500)
committerMarge Bot <emma+marge@anholt.net>
Sat, 11 Mar 2023 02:26:31 +0000 (02:26 +0000)
In NIR, texelFetch (txf) does not use a sampler, but in AGX, it does -- even
though the contents of the sampler are semantically irrelevant. Rather than
requiring the state tracker to bind a sampler anyway (indicated for texture
buffers with PIPE_CAP_TEXTURE_BUFFER_SAMPLER), just add a dummy sampler
ourselves if txf is used and there are otherwise no samplers. This is helpful
because PIPE_CAP_TEXTURE_BUFFER_SAMPLER isn't honoured by Rusticl or seemingly
mesa/st's PBO code, and after implementing this dummy sampler workaround in
Panfrost for Rusticl, I realized this CAP is silly and shouldn't exist in the
first place. (And I regret pushing for its reinclusion.)

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/21672>

src/asahi/compiler/agx_compile.c
src/asahi/compiler/agx_compile.h
src/gallium/drivers/asahi/agx_pipe.c
src/gallium/drivers/asahi/agx_state.c

index 0ea574e..cca0be0 100644 (file)
@@ -1326,6 +1326,12 @@ agx_emit_tex(agx_builder *b, nir_tex_instr *instr)
 
    bool txf = (instr->op == nir_texop_txf || instr->op == nir_texop_txf_ms);
 
+   /* txf loads a texture without an associated sampler, but in the hardware
+    * there is an associated load of a sampler. This requires that the driver
+    * upload a dummy sampler.
+    */
+   b->shader->out->needs_dummy_sampler |= txf;
+
    for (unsigned i = 0; i < instr->num_srcs; ++i) {
       agx_index index = agx_src_index(&instr->src[i].src);
 
index b3b1fcb..162fa6f 100644 (file)
@@ -124,6 +124,9 @@ struct agx_shader_info {
    /* Shader is incompatible with triangle merging */
    bool disable_tri_merging;
 
+   /* Shader needs a dummy sampler (for txf reads) */
+   bool needs_dummy_sampler;
+
    /* Number of 16-bit registers used by the main shader and preamble
     * respectively.
     */
index 20d3360..56a7dae 100644 (file)
@@ -1281,7 +1281,6 @@ agx_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
    case PIPE_CAP_SURFACE_SAMPLE_COUNT:
    case PIPE_CAP_SAMPLE_SHADING:
    case PIPE_CAP_TEXTURE_BUFFER_OBJECTS:
-   case PIPE_CAP_TEXTURE_BUFFER_SAMPLER:
    case PIPE_CAP_IMAGE_LOAD_FORMATTED:
    case PIPE_CAP_IMAGE_STORE_FORMATTED:
    case PIPE_CAP_COMPUTE:
index b6a055a..0cbd06a 100644 (file)
@@ -1753,6 +1753,10 @@ agx_build_pipeline(struct agx_batch *batch, struct agx_compiled_shader *cs,
    unsigned nr_textures = ctx->stage[stage].texture_count;
    unsigned nr_samplers = ctx->stage[stage].sampler_count;
    bool custom_borders = ctx->stage[stage].custom_borders;
+   bool dummy_sampler = cs->info.needs_dummy_sampler && (nr_samplers == 0);
+
+   if (dummy_sampler)
+      nr_samplers = 1;
 
    struct agx_ptr T_tex = agx_pool_alloc_aligned(
       &batch->pool, AGX_TEXTURE_LENGTH * nr_textures, 64);
@@ -1798,24 +1802,31 @@ agx_build_pipeline(struct agx_batch *batch, struct agx_compiled_shader *cs,
 
    /* TODO: Dirty track me to save some CPU cycles and maybe improve caching */
    uint8_t *out_sampler = T_samp.cpu;
-   for (unsigned i = 0; i < nr_samplers; ++i) {
-      struct agx_sampler_state *sampler = ctx->stage[stage].samplers[i];
-      struct agx_sampler_packed *out = (struct agx_sampler_packed *)out_sampler;
-
-      if (sampler) {
-         *out = sampler->desc;
-
-         if (custom_borders) {
-            memcpy(out_sampler + AGX_SAMPLER_LENGTH, &sampler->border,
-                   AGX_BORDER_LENGTH);
+   if (dummy_sampler) {
+      /* Configuration is irrelevant for the dummy sampler */
+      agx_pack(out_sampler, SAMPLER, cfg)
+         ;
+   } else {
+      for (unsigned i = 0; i < nr_samplers; ++i) {
+         struct agx_sampler_state *sampler = ctx->stage[stage].samplers[i];
+         struct agx_sampler_packed *out =
+            (struct agx_sampler_packed *)out_sampler;
+
+         if (sampler) {
+            *out = sampler->desc;
+
+            if (custom_borders) {
+               memcpy(out_sampler + AGX_SAMPLER_LENGTH, &sampler->border,
+                      AGX_BORDER_LENGTH);
+            } else {
+               assert(!sampler->uses_custom_border && "invalid combination");
+            }
          } else {
-            assert(!sampler->uses_custom_border && "invalid combination");
+            memset(out, 0, sampler_length);
          }
-      } else {
-         memset(out, 0, sampler_length);
-      }
 
-      out_sampler += sampler_length;
+         out_sampler += sampler_length;
+      }
    }
 
    struct agx_usc_builder b =