freedreno: track batch/blit types
authorRob Clark <robdclark@gmail.com>
Thu, 14 Jul 2016 14:32:02 +0000 (10:32 -0400)
committerRob Clark <robdclark@gmail.com>
Sat, 30 Jul 2016 13:23:42 +0000 (09:23 -0400)
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>
src/gallium/drivers/freedreno/freedreno_batch.h
src/gallium/drivers/freedreno/freedreno_context.h
src/gallium/drivers/freedreno/freedreno_draw.c
src/gallium/drivers/freedreno/freedreno_resource.c
src/gallium/drivers/freedreno/freedreno_state.c

index 228a1b72bf64d87006427935ec19a4ba1153147b..6be196534abffe4a7620cfc82a62fe898e0d5a20 100644 (file)
@@ -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,
index 45876259fd87c72006e444b9e6f1c371a5c91b94..7e25e57d43b6348769179a7336c3fa022c5284ba 100644 (file)
@@ -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: */
index fd3da1f20e5723efe36c175764769166ea2b53d1..dd4a720dd0ed700eb15ec26dbc98cf71fb97de55 100644 (file)
@@ -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
index b6c9488ec655afc22676a14a498a9e14329138c1..0e0305885a7355f08c83aab7e24b3718c59f4c43 100644 (file)
@@ -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
index 849ea08037dbe8d54ac4abdd7b7bc7f9601a0fa9..f83fd219f0a27073c594036bb5eef3b16575b89e 100644 (file)
@@ -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);