From 301c32caf4c656731006409720d521f4709e60ac Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 23 Jul 2018 13:56:40 -0700 Subject: [PATCH] v3d: Rework the ordering of how we clear things. First, figure out if we can just sneak the clear into the TLB clear, even if drawing has already happened (since we have job->load and job->clear to tell us), taking into account GFXH-1461. For any pieces we can't TLB clear, fall back to drawing a quad without flushing the scene. Fixes extra scene flushes in glmark2 due to GFXH-1461. --- src/gallium/drivers/v3d/v3dx_draw.c | 85 ++++++++++++++++++----------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/src/gallium/drivers/v3d/v3dx_draw.c b/src/gallium/drivers/v3d/v3dx_draw.c index e64f2c314e0..6aa58ceaafe 100644 --- a/src/gallium/drivers/v3d/v3dx_draw.c +++ b/src/gallium/drivers/v3d/v3dx_draw.c @@ -622,50 +622,58 @@ v3d_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) v3d_flush(pctx); } -/* GFXH-1461: If we were to emit a load of just depth or just stencil, then - * the clear for the other may get lost. Just fall back to drawing a quad in - * that case. +/** + * Implements gallium's clear() hook (glClear()) by drawing a pair of triangles. */ -static bool -v3d_gfxh1461_clear_workaround(struct v3d_context *v3d, - unsigned buffers, double depth, unsigned stencil) +static void +v3d_draw_clear(struct v3d_context *v3d, + unsigned buffers, + const union pipe_color_union *color, + double depth, unsigned stencil) { - unsigned zsclear = buffers & PIPE_CLEAR_DEPTHSTENCIL; - if (!zsclear || zsclear == PIPE_CLEAR_DEPTHSTENCIL) - return false; - static const union pipe_color_union dummy_color = {}; + /* The blitter util dereferences the color regardless, even though the + * gallium clear API may not pass one in when only Z/S are cleared. + */ + if (!color) + color = &dummy_color; + v3d_blitter_save(v3d); util_blitter_clear(v3d->blitter, v3d->framebuffer.width, v3d->framebuffer.height, - 1, - zsclear, - &dummy_color, depth, stencil); - return true; + util_framebuffer_get_num_layers(&v3d->framebuffer), + buffers, color, depth, stencil); } -static void -v3d_clear(struct pipe_context *pctx, unsigned buffers, - const union pipe_color_union *color, double depth, unsigned stencil) +/** + * Attempts to perform the GL clear by using the TLB's fast clear at the start + * of the frame. + */ +static unsigned +v3d_tlb_clear(struct v3d_job *job, unsigned buffers, + const union pipe_color_union *color, + double depth, unsigned stencil) { - struct v3d_context *v3d = v3d_context(pctx); - struct v3d_job *job = v3d_get_job_for_fbo(v3d); - - if (v3d_gfxh1461_clear_workaround(v3d, buffers, depth, stencil)) - buffers &= ~PIPE_CLEAR_DEPTHSTENCIL; + struct v3d_context *v3d = job->v3d; - if (!buffers) - return; + if (job->draw_calls_queued) { + /* If anything in the CL has drawn using the buffer, then the + * TLB clear we're trying to add now would happen before that + * drawing. + */ + buffers &= ~(job->load | job->store); + } - /* We can't flag new buffers for clearing once we've queued draws. We - * could avoid this by using the 3d engine to clear. + /* GFXH-1461: If we were to emit a load of just depth or just stencil, + * then the clear for the other may get lost. We need to decide now + * if it would be possible to need to emit a load of just one after + * we've set up our TLB clears. */ - if (job->draw_calls_queued) { - perf_debug("Flushing rendering to process new clear.\n"); - v3d_job_submit(v3d, job); - job = v3d_get_job_for_fbo(v3d); + unsigned zsclear = buffers & PIPE_CLEAR_DEPTHSTENCIL; + if (zsclear && zsclear != PIPE_CLEAR_DEPTHSTENCIL) { + buffers &= ~zsclear; } for (int i = 0; i < VC5_MAX_DRAW_BUFFERS; i++) { @@ -724,7 +732,7 @@ v3d_clear(struct pipe_context *pctx, unsigned buffers, rsc->initialized_buffers |= bit; } - unsigned zsclear = buffers & PIPE_CLEAR_DEPTHSTENCIL; + zsclear = buffers & PIPE_CLEAR_DEPTHSTENCIL; if (zsclear) { struct v3d_resource *rsc = v3d_resource(v3d->framebuffer.zsbuf->texture); @@ -745,6 +753,21 @@ v3d_clear(struct pipe_context *pctx, unsigned buffers, job->store |= buffers; v3d_start_draw(v3d); + + return buffers; +} + +static void +v3d_clear(struct pipe_context *pctx, unsigned buffers, + const union pipe_color_union *color, double depth, unsigned stencil) +{ + struct v3d_context *v3d = v3d_context(pctx); + struct v3d_job *job = v3d_get_job_for_fbo(v3d); + + buffers &= ~v3d_tlb_clear(job, buffers, color, depth, stencil); + + if (buffers) + v3d_draw_clear(v3d, buffers, color, depth, stencil); } static void -- 2.30.2