iris: Skip emitting 3DSTATE_INDEX_BUFFER if possible
authorKenneth Graunke <kenneth@whitecape.org>
Sat, 16 Feb 2019 08:57:54 +0000 (00:57 -0800)
committerKenneth Graunke <kenneth@whitecape.org>
Wed, 31 Jul 2019 22:14:10 +0000 (15:14 -0700)
We were emitting 3DSTATE_INDEX_BUFFER on every indexed draw, even if
back-to-back draws referred to the same index buffer.  This improves
drawoverhead scores in the DrawElements cases by about 10%, by giving
us even more minimal batches.

src/gallium/drivers/iris/iris_context.c
src/gallium/drivers/iris/iris_context.h
src/gallium/drivers/iris/iris_state.c

index a0f3aa8c2e2b9015e91b5aeeb919acff0c748253..8710f010ebfce4961eba049bc3f820df82adfc65 100644 (file)
@@ -100,6 +100,7 @@ iris_lost_context_state(struct iris_batch *batch)
    ice->state.dirty = ~0ull;
    memset(ice->state.last_grid, 0, sizeof(ice->state.last_grid));
    batch->last_surface_base_address = ~0ull;
+   ice->vtbl.lost_genx_state(ice, batch);
 }
 
 static enum pipe_reset_status
index 638e30e9d9013a5a052d6b8112acb3e296d62938..16946582dcb5c735b879153c6e0cfe44c6a63c53 100644 (file)
@@ -481,6 +481,7 @@ struct iris_vtable {
    void (*populate_cs_key)(const struct iris_context *ice,
                            struct brw_cs_prog_key *key);
    uint32_t (*mocs)(const struct iris_bo *bo);
+   void (*lost_genx_state)(struct iris_context *ice, struct iris_batch *batch);
 };
 
 /**
index dddf50bf9214e6461ca54c2b5ea7d3e01b995d48..ea38225f01a747159d955b0f50f16d946fa65c8a 100644 (file)
@@ -784,6 +784,7 @@ struct iris_depth_buffer_state {
  */
 struct iris_genx_state {
    struct iris_vertex_buffer_state vertex_buffers[33];
+   uint32_t last_index_buffer[GENX(3DSTATE_INDEX_BUFFER_length)];
 
    struct iris_depth_buffer_state depth_buffer;
 
@@ -4249,13 +4250,7 @@ iris_restore_render_saved_bos(struct iris_context *ice,
       pin_depth_and_stencil_buffers(batch, cso_fb->zsbuf, ice->state.cso_zsa);
    }
 
-   if (draw->index_size == 0 && ice->state.last_res.index_buffer) {
-      /* This draw didn't emit a new index buffer, so we are inheriting the
-       * older index buffer.  This draw didn't need it, but future ones may.
-       */
-      struct iris_bo *bo = iris_resource_bo(ice->state.last_res.index_buffer);
-      iris_use_pinned_bo(batch, bo, false);
-   }
+   iris_use_optional_res(batch, ice->state.last_res.index_buffer, false);
 
    if (clean & IRIS_DIRTY_VERTEX_BUFFERS) {
       uint64_t bound = ice->state.bound_vertex_buffers;
@@ -5185,13 +5180,21 @@ iris_upload_render_state(struct iris_context *ice,
          offset = 0;
       }
 
+      struct iris_genx_state *genx = ice->state.genx;
       struct iris_bo *bo = iris_resource_bo(ice->state.last_res.index_buffer);
 
-      iris_emit_cmd(batch, GENX(3DSTATE_INDEX_BUFFER), ib) {
+      uint32_t ib_packet[GENX(3DSTATE_INDEX_BUFFER_length)];
+      iris_pack_command(GENX(3DSTATE_INDEX_BUFFER), ib_packet, ib) {
          ib.IndexFormat = draw->index_size >> 1;
          ib.MOCS = mocs(bo);
          ib.BufferSize = bo->size - offset;
-         ib.BufferStartingAddress = ro_bo(bo, offset);
+         ib.BufferStartingAddress = ro_bo(NULL, bo->gtt_offset + offset);
+      }
+
+      if (memcmp(genx->last_index_buffer, ib_packet, sizeof(ib_packet)) != 0) {
+         memcpy(genx->last_index_buffer, ib_packet, sizeof(ib_packet));
+         iris_batch_emit(batch, ib_packet, sizeof(ib_packet));
+         iris_use_pinned_bo(batch, bo, false);
       }
 
       /* The VF cache key only uses 32-bits, see vertex buffer comment above */
@@ -5633,8 +5636,10 @@ iris_rebind_buffer(struct iris_context *ice,
       }
    }
 
-   /* No need to handle these:
-    * - PIPE_BIND_INDEX_BUFFER (emitted for every indexed draw)
+   /* We don't need to handle PIPE_BIND_INDEX_BUFFER here: we re-emit
+    * the 3DSTATE_INDEX_BUFFER packet whenever the address changes.
+    *
+    * There is also no need to handle these:
     * - PIPE_BIND_COMMAND_ARGS_BUFFER (emitted for every indirect draw)
     * - PIPE_BIND_QUERY_BUFFER (no persistent state references)
     */
@@ -6385,6 +6390,14 @@ gen9_toggle_preemption(struct iris_context *ice,
 }
 #endif
 
+static void
+iris_lost_genx_state(struct iris_context *ice, struct iris_batch *batch)
+{
+   struct iris_genx_state *genx = ice->state.genx;
+
+   memset(genx->last_index_buffer, 0, sizeof(genx->last_index_buffer));
+}
+
 void
 genX(init_state)(struct iris_context *ice)
 {
@@ -6459,6 +6472,7 @@ genX(init_state)(struct iris_context *ice)
    ice->vtbl.populate_fs_key = iris_populate_fs_key;
    ice->vtbl.populate_cs_key = iris_populate_cs_key;
    ice->vtbl.mocs = mocs;
+   ice->vtbl.lost_genx_state = iris_lost_genx_state;
 
    ice->state.dirty = ~0ull;