From 743999523492f40f171b17c9f77b37c72cc752f4 Mon Sep 17 00:00:00 2001 From: Vadim Girlin Date: Fri, 29 Jul 2011 13:19:33 +0400 Subject: [PATCH] gallium: vertex buffer optimization Avoid uploading excessive amounts of vertex data with indexed rendering when indices count is much less than index range (max_index-min_index+1). E.g. with "Cogs" game typical case is 4 indices and >4000 range. Copy required data only to separate buffer. FIXME: Not all possible cases are handled (index sizes etc). --- src/gallium/auxiliary/util/u_vbuf_mgr.c | 76 ++++++++++++++++++++++++++ src/gallium/auxiliary/util/u_vbuf_mgr.h | 7 +++ src/gallium/drivers/r600/r600_state_common.c | 5 ++ 3 files changed, 88 insertions(+), 0 deletions(-) diff --git a/src/gallium/auxiliary/util/u_vbuf_mgr.c b/src/gallium/auxiliary/util/u_vbuf_mgr.c index 19eb689..b0a495c 100644 --- a/src/gallium/auxiliary/util/u_vbuf_mgr.c +++ b/src/gallium/auxiliary/util/u_vbuf_mgr.c @@ -83,6 +83,7 @@ struct u_vbuf_mgr_priv { boolean any_user_vbs; boolean incompatible_vb_layout; + boolean optimized_vb; }; static void u_vbuf_mgr_init_format_caps(struct u_vbuf_mgr_priv *mgr) @@ -612,6 +613,74 @@ static void u_vbuf_mgr_compute_max_index(struct u_vbuf_mgr_priv *mgr) } } +/* Avoid uploading too much unneeded vertex data when using indexed + * rendering. If number of vertices in the range (max_index-min_index+1) + * is much higher than indices count, then it's better to create new vertex + * buffer and copy selected vertices only. + * FIXME: Not all possible cases are handled. + */ +boolean +u_vbuf_mgr_draw_optimize(struct u_vbuf_mgr *mgrb, + struct pipe_index_buffer* ib, + const struct pipe_draw_info *info, + struct pipe_draw_info *o_info) +{ + const int opt_threshold = 100; + + struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb; + if (info->indexed && ib->buffer && u_vbuf_resource(ib->buffer)->user_ptr + && ib->index_size==2) { + unsigned short * ib_ptr = (unsigned short *)u_vbuf_resource(ib->buffer)->user_ptr; + int num_vtx = info->max_index-info->min_index+1; + int num_ind = info->count; + if (num_vtx/num_ind > opt_threshold) { + if (mgrb->nr_vertex_buffers==1) { + struct pipe_vertex_buffer * vb = &mgr->b.vertex_buffer[0]; + struct pipe_resource *new_vb; + if (vb->buffer && u_vbuf_resource(vb->buffer)->user_ptr) { + int q; + for (q=0;qve->count;q++) { + if (mgr->ve->ve[q].src_offset>=vb->stride) return false; + } + + { + void * vb_ptr = u_vbuf_resource(vb->buffer)->user_ptr; + unsigned vb_size = vb->stride*num_ind; + void * vb_data; + unsigned i; + + vb_data = malloc(vb_size); + for (i=0;istride*i,((char*)vb_ptr) + vb->stride*index + vb->buffer_offset, vb->stride); + } + + mgr->optimized_vb = TRUE; + + new_vb = pipe_user_buffer_create(mgr->pipe->screen,vb_data, + vb_size, PIPE_BIND_VERTEX_BUFFER); + + pipe_resource_reference(&mgrb->saved_vertex_buffer, mgrb->vertex_buffer[0].buffer); + pipe_resource_reference(&mgrb->vertex_buffer[0].buffer, new_vb); + pipe_resource_reference(&new_vb,NULL); + + pipe_resource_reference(&ib->buffer,NULL); + + *o_info = *info; + o_info->indexed = FALSE; + o_info->min_index=0; + o_info->max_index=num_ind-1; + mgrb->vertex_buffer[0].buffer_offset = 0; + + return TRUE; + } + } + } + } + } + return FALSE; +} + enum u_vbuf_return_flags u_vbuf_mgr_draw_begin(struct u_vbuf_mgr *mgrb, const struct pipe_draw_info *info) @@ -652,6 +721,13 @@ void u_vbuf_mgr_draw_end(struct u_vbuf_mgr *mgrb) struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb; unsigned i; + if (mgr->optimized_vb) { + void * ptr = u_vbuf_resource(mgrb->vertex_buffer[0].buffer)->user_ptr; + pipe_resource_reference(&mgrb->vertex_buffer[0].buffer, mgrb->saved_vertex_buffer); + free(ptr); + mgr->optimized_vb=false; + } + /* buffer offsets were modified in u_vbuf_upload_buffers */ if (mgr->any_user_vbs) { for (i = 0; i < mgr->b.nr_vertex_buffers; i++) diff --git a/src/gallium/auxiliary/util/u_vbuf_mgr.h b/src/gallium/auxiliary/util/u_vbuf_mgr.h index 4e63724..b3d35ac 100644 --- a/src/gallium/auxiliary/util/u_vbuf_mgr.h +++ b/src/gallium/auxiliary/util/u_vbuf_mgr.h @@ -45,6 +45,7 @@ struct u_vbuf_mgr { * May contain user buffers. */ struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS]; unsigned nr_vertex_buffers; + struct pipe_resource *saved_vertex_buffer; /* Contains only real vertex buffers. * Hardware drivers should use real_vertex_buffers[i] @@ -110,6 +111,12 @@ void u_vbuf_mgr_set_vertex_buffers(struct u_vbuf_mgr *mgr, unsigned count, const struct pipe_vertex_buffer *bufs); +boolean +u_vbuf_mgr_draw_optimize(struct u_vbuf_mgr *mgrb, + struct pipe_index_buffer* ib, + const struct pipe_draw_info *info, + struct pipe_draw_info *o_info); + enum u_vbuf_return_flags u_vbuf_mgr_draw_begin(struct u_vbuf_mgr *mgr, const struct pipe_draw_info *info); diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c index 408eaed..d63e8dc 100644 --- a/src/gallium/drivers/r600/r600_state_common.c +++ b/src/gallium/drivers/r600/r600_state_common.c @@ -559,12 +559,17 @@ void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info) struct r600_resource *rbuffer; struct r600_draw rdraw; struct r600_drawl draw; + struct pipe_draw_info o_info; unsigned prim, mask; if (!rctx->blit) { if (rctx->have_depth_fb || rctx->have_depth_texture) r600_flush_depth_textures(rctx); } + + if (u_vbuf_mgr_draw_optimize(rctx->vbuf_mgr, &rctx->index_buffer, info, &o_info)) + info = &o_info; + u_vbuf_mgr_draw_begin(rctx->vbuf_mgr, info); r600_vertex_buffer_update(rctx); -- 1.7.6