Add a bit of extra book-keeping about blits and back-blits (from resource shadowing). If the app uploads all mipmap levels, as opposed to uploading the first level and then glGenerateMipmap(), we can discard the back-blit (as opposed to being naive and shadowing the resource for each mipmap level). Also, after a normal blit, we might as well flush the batch immediately, since there is not likely to be further rendering to the surface. Signed-off-by: Rob Clark <robdclark@gmail.com>tags/13.0-branchpoint
@@ -93,7 +93,9 @@ struct fd_batch { | |||
FD_BUFFER_ALL = FD_BUFFER_COLOR | FD_BUFFER_DEPTH | FD_BUFFER_STENCIL, | |||
} cleared, partial_cleared, restore, resolve; | |||
bool needs_flush; | |||
bool needs_flush : 1; | |||
bool blit : 1; | |||
bool back_blit : 1; /* only blit so far is resource shadowing back-blit */ | |||
/* To decide whether to render to system memory, keep track of the | |||
* number of draws, and whether any of them require multisample, |
@@ -161,16 +161,27 @@ struct fd_context { | |||
*/ | |||
struct fd_batch *batch; | |||
/* Are we in process of shadowing a resource? Used to detect recursion | |||
* in transfer_map, and skip unneeded synchronization. | |||
*/ | |||
bool in_shadow : 1; | |||
/* Ie. in blit situation where we no longer care about previous framebuffer | |||
* contents. Main point is to eliminate blits from fd_try_shadow_resource(). | |||
* For example, in case of texture upload + gen-mipmaps. | |||
*/ | |||
bool in_blit : 1; | |||
/* Keep track if WAIT_FOR_IDLE is needed for registers we need | |||
* to update via RMW: | |||
*/ | |||
bool needs_wfi; | |||
bool needs_wfi : 1; | |||
/* Do we need to re-emit RB_FRAME_BUFFER_DIMENSION? At least on a3xx | |||
* it is not a banked context register, so it needs a WFI to update. | |||
* Keep track if it has actually changed, to avoid unneeded WFI. | |||
* */ | |||
bool needs_rb_fbd; | |||
bool needs_rb_fbd : 1; | |||
struct pipe_scissor_state scissor; | |||
@@ -244,17 +255,6 @@ struct fd_context { | |||
bool cond_cond; /* inverted rendering condition */ | |||
uint cond_mode; | |||
/* Are we in process of shadowing a resource? Used to detect recursion | |||
* in transfer_map, and skip unneeded synchronization. | |||
*/ | |||
bool in_shadow; | |||
/* Ie. in blit situation where we no longer care about previous framebuffer | |||
* contents. Main point is to eliminate blits from fd_try_shadow_resource(). | |||
* For example, in case of texture upload + gen-mipmaps. | |||
*/ | |||
bool discard; | |||
struct pipe_debug_callback debug; | |||
/* GMEM/tile handling fxns: */ |
@@ -84,15 +84,19 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) | |||
return; | |||
} | |||
if (ctx->discard) { | |||
fd_batch_reset(ctx->batch); | |||
ctx->discard = false; | |||
if (ctx->in_blit) { | |||
fd_batch_reset(batch); | |||
ctx->dirty = ~0; | |||
} | |||
batch->blit = ctx->in_blit; | |||
batch->back_blit = ctx->in_shadow; | |||
/* NOTE: needs to be before resource_written(batch->query_buf), otherwise | |||
* query_buf may not be created yet. | |||
*/ | |||
fd_hw_query_set_stage(batch, batch->draw, FD_STAGE_DRAW); | |||
/* | |||
* Figure out the buffers/features we need: | |||
*/ | |||
@@ -219,9 +223,9 @@ fd_clear(struct pipe_context *pctx, unsigned buffers, | |||
if (!fd_render_condition_check(pctx)) | |||
return; | |||
if (ctx->discard) { | |||
fd_batch_reset(ctx->batch); | |||
ctx->discard = false; | |||
if (ctx->in_blit) { | |||
fd_batch_reset(batch); | |||
ctx->dirty = ~0; | |||
} | |||
/* for bookkeeping about which buffers have been cleared (and thus |
@@ -487,6 +487,12 @@ fd_resource_transfer_map(struct pipe_context *pctx, | |||
* to wait. | |||
*/ | |||
} else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { | |||
if ((usage & PIPE_TRANSFER_WRITE) && rsc->write_batch && | |||
rsc->write_batch->back_blit) { | |||
/* if only thing pending is a back-blit, we can discard it: */ | |||
fd_batch_reset(rsc->write_batch); | |||
} | |||
/* If the GPU is writing to the resource, or if it is reading from the | |||
* resource and we're trying to write to it, flush the renders. | |||
*/ | |||
@@ -1057,7 +1063,7 @@ fd_blitter_pipe_begin(struct fd_context *ctx, bool render_cond, bool discard) | |||
if (ctx->batch) | |||
fd_hw_query_set_stage(ctx->batch, ctx->batch->draw, FD_STAGE_BLIT); | |||
ctx->discard = discard; | |||
ctx->in_blit = discard; | |||
} | |||
static void | |||
@@ -1065,6 +1071,7 @@ fd_blitter_pipe_end(struct fd_context *ctx) | |||
{ | |||
if (ctx->batch) | |||
fd_hw_query_set_stage(ctx->batch, ctx->batch->draw, FD_STAGE_NULL); | |||
ctx->in_blit = false; | |||
} | |||
static void |
@@ -119,13 +119,28 @@ fd_set_framebuffer_state(struct pipe_context *pctx, | |||
struct pipe_framebuffer_state *cso; | |||
if (ctx->screen->reorder) { | |||
struct fd_batch *batch; | |||
if (likely(ctx->batch)) | |||
fd_hw_query_set_stage(ctx->batch, ctx->batch->draw, FD_STAGE_NULL); | |||
struct fd_batch *batch, *old_batch = NULL; | |||
fd_batch_reference(&old_batch, ctx->batch); | |||
if (likely(old_batch)) | |||
fd_hw_query_set_stage(old_batch, old_batch->draw, FD_STAGE_NULL); | |||
batch = fd_batch_from_fb(&ctx->screen->batch_cache, ctx, framebuffer); | |||
fd_batch_reference(&ctx->batch, NULL); | |||
ctx->batch = batch; | |||
ctx->dirty = ~0; | |||
if (old_batch && old_batch->blit && !old_batch->back_blit) { | |||
/* for blits, there is not really much point in hanging on | |||
* to the uncommitted batch (ie. you probably don't blit | |||
* multiple times to the same surface), so we might as | |||
* well go ahead and flush this one: | |||
*/ | |||
fd_batch_flush(old_batch); | |||
} | |||
fd_batch_reference(&old_batch, NULL); | |||
} else { | |||
DBG("%d: cbufs[0]=%p, zsbuf=%p", ctx->batch->needs_flush, | |||
framebuffer->cbufs[0], framebuffer->zsbuf); |