iris: Defer uploading sampler state tables until draw time
authorKenneth Graunke <kenneth@whitecape.org>
Tue, 4 Dec 2018 23:34:30 +0000 (15:34 -0800)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 7 Mar 2019 19:39:27 +0000 (11:39 -0800)
Gallium might call us multiple times to bind subsets of the samplers,
at which point we'd recreate the table a bunch of times.  It doesn't
really buy us anything to do it here - even if we defer to draw time,
the dirty tracking ensures we'll only do it on the first draw after a
bind_sampler_states() call.

We now use the number of samplers specified by the shader instead of
the binding count.  If this number changes, we flag sampler state as
dirty so we re-upload a table with the right number of entries.

This also fixes a bug where ice->state.need_border_colors was never
unset, so once something needed border colors, the pool would always
be pinned in all future batches.

v2: Explicitly flag sampler states as dirty, rather than assuming that
    bind_sampler_states() will be called if the program texture count
    changes.  While this may be true for st/mesa, it isn't the case for
    Gallium HUD.

Tested-by: Timur Kristóf <timur.kristof@gmail.com>
Tested-by: Andre Heider <a.heider@gmail.com>
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
src/gallium/drivers/iris/iris_context.h
src/gallium/drivers/iris/iris_program.c
src/gallium/drivers/iris/iris_state.c

index 771c47ffcedf16fae3995ef7c55d6c986b17cc30..70a929178df4958c4fdc52e9e8aee9e161e78e0d 100644 (file)
@@ -575,8 +575,8 @@ struct iris_context {
       /** Do vertex shader uses edge flag ? */
       bool vs_needs_edge_flag;
 
-      /** Do any samplers (for any stage) need border color? */
-      bool need_border_colors;
+      /** Do any samplers need border color?  One bit per shader stage. */
+      uint8_t need_border_colors;
 
       struct pipe_stream_output_target *so_target[PIPE_MAX_SO_BUFFERS];
       bool streamout_active;
index 0ceaeb22d27ca84e6fadd2e8443f8699d731f4e7..9d1664029d997502bef54792379f7d224c576933 100644 (file)
@@ -1614,6 +1614,14 @@ bind_state(struct iris_context *ice,
    uint64_t dirty_bit = IRIS_DIRTY_UNCOMPILED_VS << stage;
    const uint64_t nos = ish ? ish->nos : 0;
 
+   const struct shader_info *old_info = iris_get_shader_info(ice, stage);
+   const struct shader_info *new_info = ish ? &ish->nir->info : NULL;
+
+   if ((old_info ? util_last_bit(old_info->textures_used) : 0) !=
+       (new_info ? util_last_bit(new_info->textures_used) : 0)) {
+      ice->state.dirty |= IRIS_DIRTY_SAMPLER_STATES_VS << stage;
+   }
+
    ice->shaders.uncompiled[stage] = ish;
    ice->state.dirty |= dirty_bit;
 
index 7e1ead707976b7568ced3d8751e48447b12e983f..0483bb8caa0f33da27b5b079b40fb55db862c126 100644 (file)
@@ -1437,19 +1437,7 @@ iris_create_sampler_state(struct pipe_context *ctx,
 
 /**
  * The pipe->bind_sampler_states() driver hook.
- *
- * Now that we know all the sampler states, we upload them all into a
- * contiguous area of GPU memory, for 3DSTATE_SAMPLER_STATE_POINTERS_*.
- * We also fill out the border color state pointers at this point.
- *
- * We could defer this work to draw time, but we assume that binding
- * will be less frequent than drawing.
  */
-// XXX: this may be a bad idea, need to make sure that st/mesa calls us
-// XXX: with the complete set of shaders.  If it makes multiple calls to
-// XXX: things one at a time, we could waste a lot of time assembling things.
-// XXX: it doesn't even BUY us anything to do it here, because we only flag
-// XXX: IRIS_DIRTY_SAMPLER_STATE when this is called...
 static void
 iris_bind_sampler_states(struct pipe_context *ctx,
                          enum pipe_shader_type p_stage,
@@ -1466,6 +1454,29 @@ iris_bind_sampler_states(struct pipe_context *ctx,
       shs->samplers[start + i] = states[i];
    }
 
+   ice->state.dirty |= IRIS_DIRTY_SAMPLER_STATES_VS << stage;
+}
+
+/**
+ * Upload the sampler states into a contiguous area of GPU memory, for
+ * for 3DSTATE_SAMPLER_STATE_POINTERS_*.
+ *
+ * Also fill out the border color state pointers.
+ */
+static void
+iris_upload_sampler_states(struct iris_context *ice, gl_shader_stage stage)
+{
+   struct iris_shader_state *shs = &ice->state.shaders[stage];
+   const struct shader_info *info = iris_get_shader_info(ice, stage);
+
+   /* We assume the state tracker will call pipe->bind_sampler_states()
+    * if the program's number of textures changes.
+    */
+   unsigned count = info ? util_last_bit(info->textures_used) : 0;
+
+   if (!count)
+      return;
+
    /* Assemble the SAMPLER_STATEs into a contiguous table that lives
     * in the dynamic state memory zone, so we can point to it via the
     * 3DSTATE_SAMPLER_STATE_POINTERS_* commands.
@@ -1483,6 +1494,8 @@ iris_bind_sampler_states(struct pipe_context *ctx,
    /* Make sure all land in the same BO */
    iris_border_color_pool_reserve(ice, IRIS_MAX_TEXTURE_SAMPLERS);
 
+   ice->state.need_border_colors &= ~(1 << stage);
+
    for (int i = 0; i < count; i++) {
       struct iris_sampler_state *state = shs->samplers[i];
 
@@ -1491,7 +1504,7 @@ iris_bind_sampler_states(struct pipe_context *ctx,
       } else if (!state->needs_border_color) {
          memcpy(map, state->sampler_state, 4 * GENX(SAMPLER_STATE_length));
       } else {
-         ice->state.need_border_colors = true;
+         ice->state.need_border_colors |= 1 << stage;
 
          /* Stream out the border color and merge the pointer. */
          uint32_t offset =
@@ -1508,8 +1521,6 @@ iris_bind_sampler_states(struct pipe_context *ctx,
 
       map += GENX(SAMPLER_STATE_length);
    }
-
-   ice->state.dirty |= IRIS_DIRTY_SAMPLER_STATES_VS << stage;
 }
 
 static enum isl_channel_select
@@ -4439,14 +4450,13 @@ iris_upload_dirty_render_state(struct iris_context *ice,
       }
    }
 
-   if (ice->state.need_border_colors)
-      iris_use_pinned_bo(batch, ice->state.border_color_pool.bo, false);
-
    for (int stage = 0; stage <= MESA_SHADER_FRAGMENT; stage++) {
       if (!(dirty & (IRIS_DIRTY_SAMPLER_STATES_VS << stage)) ||
           !ice->shaders.prog[stage])
          continue;
 
+      iris_upload_sampler_states(ice, stage);
+
       struct iris_shader_state *shs = &ice->state.shaders[stage];
       struct pipe_resource *res = shs->sampler_table.res;
       if (res)
@@ -4458,6 +4468,9 @@ iris_upload_dirty_render_state(struct iris_context *ice,
       }
    }
 
+   if (ice->state.need_border_colors)
+      iris_use_pinned_bo(batch, ice->state.border_color_pool.bo, false);
+
    if (dirty & IRIS_DIRTY_MULTISAMPLE) {
       iris_emit_cmd(batch, GENX(3DSTATE_MULTISAMPLE), ms) {
          ms.PixelLocation =
@@ -5101,6 +5114,9 @@ iris_upload_compute_state(struct iris_context *ice,
    if (dirty & IRIS_DIRTY_BINDINGS_CS)
       iris_populate_binding_table(ice, batch, MESA_SHADER_COMPUTE, false);
 
+   if (dirty & IRIS_DIRTY_SAMPLER_STATES_CS)
+      iris_upload_sampler_states(ice, MESA_SHADER_COMPUTE);
+
    iris_use_optional_res(batch, shs->sampler_table.res, false);
    iris_use_pinned_bo(batch, iris_resource_bo(shader->assembly.res), false);