From: Chia-I Wu Date: Sat, 13 Jul 2013 19:56:44 +0000 (+0800) Subject: ilo: skip 3DSTATE_INDEX_BUFFER when possible X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=62c546bbf87afe32e49c100e245e04bc35304481;p=mesa.git ilo: skip 3DSTATE_INDEX_BUFFER when possible 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. --- diff --git a/src/gallium/drivers/ilo/ilo_3d.c b/src/gallium/drivers/ilo/ilo_3d.c index b8cb24f0f71..5b120e77d09 100644 --- a/src/gallium/drivers/ilo/ilo_3d.c +++ b/src/gallium/drivers/ilo/ilo_3d.c @@ -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; diff --git a/src/gallium/drivers/ilo/ilo_gpe.h b/src/gallium/drivers/ilo/ilo_gpe.h index 27fa57e2d38..73a94304bf4 100644 --- a/src/gallium/drivers/ilo/ilo_gpe.h +++ b/src/gallium/drivers/ilo/ilo_gpe.h @@ -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; }; diff --git a/src/gallium/drivers/ilo/ilo_gpe_gen6.c b/src/gallium/drivers/ilo/ilo_gpe_gen6.c index 4e1bd55343b..442bef18913 100644 --- a/src/gallium/drivers/ilo/ilo_gpe_gen6.c +++ b/src/gallium/drivers/ilo/ilo_gpe_gen6.c @@ -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); diff --git a/src/gallium/drivers/ilo/ilo_state.c b/src/gallium/drivers/ilo/ilo_state.c index 070bc288528..59cc8ff3621 100644 --- a/src/gallium/drivers/ilo/ilo_state.c +++ b/src/gallium/drivers/ilo/ilo_state.c @@ -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;