ilo: skip 3DSTATE_INDEX_BUFFER when possible 92/7492/1
authorChia-I Wu <olvaffe@gmail.com>
Sat, 13 Jul 2013 19:56:44 +0000 (03:56 +0800)
committerChia-I Wu <olvaffe@gmail.com>
Sat, 13 Jul 2013 21:59:52 +0000 (05:59 +0800)
When only the offset to the index buffer is changed, we can skip the
3DSTATE_INDEX_BUFFER if we always use 0 for the offset, and add
(offset / index_size) to Start Vertex Location in 3DPRIMITIVE.

src/gallium/drivers/ilo/ilo_3d.c
src/gallium/drivers/ilo/ilo_gpe.h
src/gallium/drivers/ilo/ilo_gpe_gen6.c
src/gallium/drivers/ilo/ilo_state.c

index b8cb24f..5b120e7 100644 (file)
@@ -536,7 +536,7 @@ ilo_check_restart_index(const struct ilo_context *ilo, unsigned restart_index)
       return true;
 
    /* Note: indices must be unsigned byte, unsigned short or unsigned int */
-   switch (ilo->ib.state.index_size) {
+   switch (ilo->ib.index_size) {
    case 1:
       return ((restart_index & 0xff) == 0xff);
       break;
@@ -605,21 +605,21 @@ ilo_draw_vbo_with_sw_restart(struct pipe_context *pipe,
       return;
    }
 
-   if (ilo->ib.state.buffer) {
+   if (ilo->ib.buffer) {
       struct pipe_transfer *transfer;
       const void *map;
 
-      map = pipe_buffer_map(pipe, ilo->ib.state.buffer,
+      map = pipe_buffer_map(pipe, ilo->ib.buffer,
             PIPE_TRANSFER_READ, &transfer);
 
-      sub_prim_count = ilo_find_sub_primitives(map + ilo->ib.state.offset,
-            ilo->ib.state.index_size, info, restart_info);
+      sub_prim_count = ilo_find_sub_primitives(map + ilo->ib.offset,
+            ilo->ib.index_size, info, restart_info);
 
       pipe_buffer_unmap(pipe, transfer);
    }
    else {
-      sub_prim_count = ilo_find_sub_primitives(ilo->ib.state.user_buffer,
-            ilo->ib.state.index_size, info, restart_info);
+      sub_prim_count = ilo_find_sub_primitives(ilo->ib.user_buffer,
+               ilo->ib.index_size, info, restart_info);
    }
 
    info = restart_info;
index 27fa57e..73a9430 100644 (file)
@@ -63,9 +63,15 @@ struct ilo_vb_state {
 };
 
 struct ilo_ib_state {
-   struct pipe_index_buffer state;
+   struct pipe_resource *buffer;
+   const void *user_buffer;
+   unsigned offset;
+   unsigned index_size;
 
-   struct pipe_resource *resource;
+   /* these are not valid until the state is finalized */
+   struct pipe_resource *hw_resource;
+   unsigned hw_index_size;
+   /* an offset to be added to pipe_draw_info::start */
    int64_t draw_start_offset;
 };
 
index 4e1bd55..442bef1 100644 (file)
@@ -1033,7 +1033,7 @@ gen6_emit_3DSTATE_INDEX_BUFFER(const struct ilo_dev_info *dev,
 {
    const uint32_t cmd = ILO_GPE_CMD(0x3, 0x0, 0x0a);
    const uint8_t cmd_len = 3;
-   const struct ilo_buffer *buf = ilo_buffer(ib->resource);
+   struct ilo_buffer *buf = ilo_buffer(ib->hw_resource);
    uint32_t start_offset, end_offset;
    int format;
 
@@ -1042,7 +1042,7 @@ gen6_emit_3DSTATE_INDEX_BUFFER(const struct ilo_dev_info *dev,
    if (!buf)
       return;
 
-   format = gen6_translate_index_size(ib->state.index_size);
+   format = gen6_translate_index_size(ib->hw_index_size);
 
    /*
     * set start_offset to 0 here and adjust pipe_draw_info::start with
@@ -1052,7 +1052,7 @@ gen6_emit_3DSTATE_INDEX_BUFFER(const struct ilo_dev_info *dev,
    end_offset = buf->bo_size;
 
    /* end_offset must also be aligned and is inclusive */
-   end_offset -= (end_offset % ib->state.index_size);
+   end_offset -= (end_offset % ib->hw_index_size);
    end_offset--;
 
    ilo_cp_begin(cp, cmd_len);
index 070bc28..59cc8ff 100644 (file)
@@ -128,39 +128,53 @@ finalize_constant_buffers(struct ilo_context *ilo)
 static void
 finalize_index_buffer(struct ilo_context *ilo)
 {
-   struct pipe_resource *res;
-   unsigned offset, size;
-   bool uploaded = false;
+   const struct pipe_resource *current_hw_res = ilo->ib.hw_resource;
+   const bool need_upload = (ilo->draw->indexed &&
+         (ilo->ib.user_buffer || ilo->ib.offset % ilo->ib.index_size));
 
-   if (!ilo->draw->indexed)
+   if (!(ilo->dirty & ILO_DIRTY_IB) && !need_upload)
       return;
 
-   res = ilo->ib.resource;
-   offset = ilo->ib.state.index_size * ilo->draw->start;
-   size = ilo->ib.state.index_size * ilo->draw->count;
+   if (need_upload) {
+      const unsigned offset = ilo->ib.index_size * ilo->draw->start;
+      const unsigned size = ilo->ib.index_size * ilo->draw->count;
+      unsigned hw_offset;
 
-   if (ilo->ib.state.user_buffer) {
-      u_upload_data(ilo->uploader, 0, size,
-            ilo->ib.state.user_buffer + offset, &offset, &res);
-      uploaded = true;
-   }
-   else if (unlikely(ilo->ib.state.offset % ilo->ib.state.index_size)) {
-      u_upload_buffer(ilo->uploader, 0, ilo->ib.state.offset + offset, size,
-            ilo->ib.state.buffer, &offset, &res);
-      uploaded = true;
-   }
-
-   if (uploaded) {
-      ilo->ib.resource = res;
+      if (ilo->ib.user_buffer) {
+         u_upload_data(ilo->uploader, 0, size,
+               ilo->ib.user_buffer + offset, &hw_offset, &ilo->ib.hw_resource);
+      }
+      else {
+         u_upload_buffer(ilo->uploader, 0, ilo->ib.offset + offset, size,
+               ilo->ib.buffer, &hw_offset, &ilo->ib.hw_resource);
+      }
 
-      assert(offset % ilo->ib.state.index_size == 0);
-      ilo->ib.draw_start_offset = offset / ilo->ib.state.index_size;
+      /* the HW offset should be aligned */
+      assert(hw_offset % ilo->ib.index_size == 0);
+      ilo->ib.draw_start_offset = hw_offset / ilo->ib.index_size;
 
-      /* could be negative */
+      /*
+       * INDEX[ilo->draw->start] in the original buffer is INDEX[0] in the HW
+       * resource
+       */
       ilo->ib.draw_start_offset -= ilo->draw->start;
+   }
+   else {
+      pipe_resource_reference(&ilo->ib.hw_resource, ilo->ib.buffer);
 
-      ilo->dirty |= ILO_DIRTY_IB;
+      /* note that index size may be zero when the draw is not indexed */
+      if (ilo->draw->indexed)
+         ilo->ib.draw_start_offset = ilo->ib.offset / ilo->ib.index_size;
+      else
+         ilo->ib.draw_start_offset = 0;
    }
+
+   /* treat the IB as clean if the HW states do not change */
+   if (ilo->ib.hw_resource == current_hw_res &&
+       ilo->ib.hw_index_size == ilo->ib.index_size)
+      ilo->dirty &= ~ILO_DIRTY_IB;
+   else
+      ilo->ib.hw_index_size = ilo->ib.index_size;
 }
 
 /**
@@ -906,28 +920,16 @@ ilo_set_index_buffer(struct pipe_context *pipe,
    struct ilo_context *ilo = ilo_context(pipe);
 
    if (state) {
-      pipe_resource_reference(&ilo->ib.state.buffer, state->buffer);
-      ilo->ib.state.offset = state->offset;
-      ilo->ib.state.index_size = state->index_size;
-
-      /* state->offset does not apply for user buffer */
-      ilo->ib.state.user_buffer = state->user_buffer;
-
-      /*
-       * when there is no state->buffer or state->offset is misaligned,
-       * ilo_finalize_3d_states() will set these to the valid values
-       */
-      pipe_resource_reference(&ilo->ib.resource, state->buffer);
-      ilo->ib.draw_start_offset = state->offset / state->index_size;
+      pipe_resource_reference(&ilo->ib.buffer, state->buffer);
+      ilo->ib.user_buffer = state->user_buffer;
+      ilo->ib.offset = state->offset;
+      ilo->ib.index_size = state->index_size;
    }
    else {
-      pipe_resource_reference(&ilo->ib.state.buffer, NULL);
-      ilo->ib.state.offset = 0;
-      ilo->ib.state.index_size = 0;
-      ilo->ib.state.user_buffer = NULL;
-
-      pipe_resource_reference(&ilo->ib.resource, NULL);
-      ilo->ib.draw_start_offset = 0;
+      pipe_resource_reference(&ilo->ib.buffer, NULL);
+      ilo->ib.user_buffer = NULL;
+      ilo->ib.offset = 0;
+      ilo->ib.index_size = 0;
    }
 
    ilo->dirty |= ILO_DIRTY_IB;
@@ -1302,8 +1304,8 @@ ilo_cleanup_states(struct ilo_context *ilo)
          pipe_resource_reference(&ilo->vb.states[i].buffer, NULL);
    }
 
-   pipe_resource_reference(&ilo->ib.state.buffer, NULL);
-   pipe_resource_reference(&ilo->ib.resource, NULL);
+   pipe_resource_reference(&ilo->ib.buffer, NULL);
+   pipe_resource_reference(&ilo->ib.hw_resource, NULL);
 
    for (i = 0; i < ilo->so.count; i++)
       pipe_so_target_reference(&ilo->so.states[i], NULL);
@@ -1358,9 +1360,19 @@ ilo_mark_states_with_resource_dirty(struct ilo_context *ilo,
          }
       }
 
-      if (ilo->ib.state.buffer == res)
+      if (ilo->ib.buffer == res) {
          states |= ILO_DIRTY_IB;
 
+         /*
+          * finalize_index_buffer() has an optimization that clears
+          * ILO_DIRTY_IB when the HW states do not change.  However, it fails
+          * to flush the VF cache when the HW states do not change, but the
+          * contents of the IB has changed.  Here, we set the index size to an
+          * invalid value to avoid the optimization.
+          */
+         ilo->ib.hw_index_size = 0;
+      }
+
       for (i = 0; i < ilo->so.count; i++) {
          if (ilo->so.states[i]->buffer == res) {
             states |= ILO_DIRTY_SO;