freedreno: clear vs scissor
The optimization of avoiding restore (mem2gmem) if there was a clear falls down a bit if you don't have a fullscreen scissor. We need to make the decision logic a bit more clever to keep track of *what* was cleared, so that we can (a) completely skip mem2gmem if entire buffer was cleared, or (b) skip mem2gmem on a per-tile basis for tiles that were completely cleared. Signed-off-by: Rob Clark <robclark@freedesktop.org>
This commit is contained in:
@@ -317,10 +317,10 @@ fd2_emit_tile_mem2gmem(struct fd_context *ctx, struct fd_tile *tile)
|
||||
OUT_RING(ring, CP_REG(REG_A2XX_PA_CL_CLIP_CNTL));
|
||||
OUT_RING(ring, 0x00000000);
|
||||
|
||||
if (ctx->restore & (FD_BUFFER_DEPTH | FD_BUFFER_STENCIL))
|
||||
if (fd_gmem_needs_restore(ctx, tile, FD_BUFFER_DEPTH | FD_BUFFER_STENCIL))
|
||||
emit_mem2gmem_surf(ctx, bin_w * bin_h, pfb->zsbuf);
|
||||
|
||||
if (ctx->restore & FD_BUFFER_COLOR)
|
||||
if (fd_gmem_needs_restore(ctx, tile, FD_BUFFER_COLOR))
|
||||
emit_mem2gmem_surf(ctx, 0, pfb->cbufs[0]);
|
||||
|
||||
/* TODO blob driver seems to toss in a CACHE_FLUSH after each DRAW_INDX.. */
|
||||
|
||||
@@ -566,10 +566,10 @@ fd3_emit_tile_mem2gmem(struct fd_context *ctx, struct fd_tile *tile)
|
||||
bin_w = gmem->bin_w;
|
||||
bin_h = gmem->bin_h;
|
||||
|
||||
if (ctx->restore & (FD_BUFFER_DEPTH | FD_BUFFER_STENCIL))
|
||||
if (fd_gmem_needs_restore(ctx, tile, FD_BUFFER_DEPTH | FD_BUFFER_STENCIL))
|
||||
emit_mem2gmem_surf(ctx, depth_base(ctx), pfb->zsbuf, bin_w);
|
||||
|
||||
if (ctx->restore & FD_BUFFER_COLOR)
|
||||
if (fd_gmem_needs_restore(ctx, tile, FD_BUFFER_COLOR))
|
||||
emit_mem2gmem_surf(ctx, 0, pfb->cbufs[0], bin_w);
|
||||
|
||||
OUT_PKT0(ring, REG_A3XX_GRAS_SC_CONTROL, 1);
|
||||
|
||||
@@ -100,7 +100,7 @@ fd_context_render(struct pipe_context *pctx)
|
||||
if (!ctx->needs_flush)
|
||||
return;
|
||||
|
||||
fd_gmem_render_tiles(pctx);
|
||||
fd_gmem_render_tiles(ctx);
|
||||
|
||||
DBG("%p/%p/%p", ctx->ring->start, ctx->ring->cur, ctx->ring->end);
|
||||
|
||||
@@ -111,7 +111,7 @@ fd_context_render(struct pipe_context *pctx)
|
||||
fd_context_next_rb(pctx);
|
||||
|
||||
ctx->needs_flush = false;
|
||||
ctx->cleared = ctx->restore = ctx->resolve = 0;
|
||||
ctx->cleared = ctx->partial_cleared = ctx->restore = ctx->resolve = 0;
|
||||
ctx->gmem_reason = 0;
|
||||
ctx->num_draws = 0;
|
||||
|
||||
|
||||
@@ -182,6 +182,10 @@ struct fd_context {
|
||||
* there was a glClear() that invalidated the entire previous buffer
|
||||
* contents. Keep track of which buffer(s) are cleared, or needs
|
||||
* restore. Masks of PIPE_CLEAR_*
|
||||
*
|
||||
* The 'cleared' bits will be set for buffers which are *entirely*
|
||||
* cleared, and 'partial_cleared' bits will be set if you must
|
||||
* check cleared_scissor.
|
||||
*/
|
||||
enum {
|
||||
/* align bitmask values w/ PIPE_CLEAR_*.. since that is convenient.. */
|
||||
@@ -189,7 +193,7 @@ struct fd_context {
|
||||
FD_BUFFER_DEPTH = PIPE_CLEAR_DEPTH,
|
||||
FD_BUFFER_STENCIL = PIPE_CLEAR_STENCIL,
|
||||
FD_BUFFER_ALL = FD_BUFFER_COLOR | FD_BUFFER_DEPTH | FD_BUFFER_STENCIL,
|
||||
} cleared, restore, resolve;
|
||||
} cleared, partial_cleared, restore, resolve;
|
||||
|
||||
bool needs_flush;
|
||||
|
||||
@@ -276,6 +280,14 @@ struct fd_context {
|
||||
*/
|
||||
struct pipe_scissor_state max_scissor;
|
||||
|
||||
/* Track the cleared scissor for color/depth/stencil, so we know
|
||||
* which, if any, tiles need to be restored (mem2gmem). Only valid
|
||||
* if the corresponding bit in ctx->cleared is set.
|
||||
*/
|
||||
struct {
|
||||
struct pipe_scissor_state color, depth, stencil;
|
||||
} cleared_scissor;
|
||||
|
||||
/* Current gmem/tiling configuration.. gets updated on render_tiles()
|
||||
* if out of date with current maximal-scissor/cpp:
|
||||
*/
|
||||
|
||||
@@ -107,7 +107,7 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
|
||||
ctx->stats.prims_emitted +=
|
||||
u_reduced_prims_for_vertices(info->mode, info->count);
|
||||
|
||||
/* any buffers that haven't been cleared, we need to restore: */
|
||||
/* any buffers that haven't been cleared yet, we need to restore: */
|
||||
ctx->restore |= buffers & (FD_BUFFER_ALL & ~ctx->cleared);
|
||||
/* and any buffers used, need to be resolved: */
|
||||
ctx->resolve |= buffers;
|
||||
@@ -145,8 +145,30 @@ fd_clear(struct pipe_context *pctx, unsigned buffers,
|
||||
{
|
||||
struct fd_context *ctx = fd_context(pctx);
|
||||
struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
|
||||
struct pipe_scissor_state *scissor = fd_context_get_scissor(ctx);
|
||||
unsigned cleared_buffers;
|
||||
|
||||
ctx->cleared |= buffers;
|
||||
/* for bookkeeping about which buffers have been cleared (and thus
|
||||
* can fully or partially skip mem2gmem) we need to ignore buffers
|
||||
* that have already had a draw, in case apps do silly things like
|
||||
* clear after draw (ie. if you only clear the color buffer, but
|
||||
* something like alpha-test causes side effects from the draw in
|
||||
* the depth buffer, etc)
|
||||
*/
|
||||
cleared_buffers = buffers & (FD_BUFFER_ALL & ~ctx->restore);
|
||||
|
||||
/* do we have full-screen scissor? */
|
||||
if (!memcmp(scissor, &ctx->disabled_scissor, sizeof(*scissor))) {
|
||||
ctx->cleared |= cleared_buffers;
|
||||
} else {
|
||||
ctx->partial_cleared |= cleared_buffers;
|
||||
if (cleared_buffers & PIPE_CLEAR_COLOR)
|
||||
ctx->cleared_scissor.color = *scissor;
|
||||
if (cleared_buffers & PIPE_CLEAR_DEPTH)
|
||||
ctx->cleared_scissor.depth = *scissor;
|
||||
if (cleared_buffers & PIPE_CLEAR_STENCIL)
|
||||
ctx->cleared_scissor.stencil = *scissor;
|
||||
}
|
||||
ctx->resolve |= buffers;
|
||||
ctx->needs_flush = true;
|
||||
|
||||
|
||||
@@ -314,9 +314,8 @@ render_sysmem(struct fd_context *ctx)
|
||||
}
|
||||
|
||||
void
|
||||
fd_gmem_render_tiles(struct pipe_context *pctx)
|
||||
fd_gmem_render_tiles(struct fd_context *ctx)
|
||||
{
|
||||
struct fd_context *ctx = fd_context(pctx);
|
||||
struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
|
||||
uint32_t timestamp = 0;
|
||||
bool sysmem = false;
|
||||
@@ -383,3 +382,48 @@ fd_gmem_render_tiles(struct pipe_context *pctx)
|
||||
|
||||
ctx->dirty = ~0;
|
||||
}
|
||||
|
||||
/* tile needs restore if it isn't completely contained within the
|
||||
* cleared scissor:
|
||||
*/
|
||||
static bool
|
||||
skip_restore(struct pipe_scissor_state *scissor, struct fd_tile *tile)
|
||||
{
|
||||
unsigned minx = tile->xoff;
|
||||
unsigned maxx = tile->xoff + tile->bin_w;
|
||||
unsigned miny = tile->yoff;
|
||||
unsigned maxy = tile->yoff + tile->bin_h;
|
||||
return (minx >= scissor->minx) && (maxx <= scissor->maxx) &&
|
||||
(miny >= scissor->miny) && (maxy <= scissor->maxy);
|
||||
}
|
||||
|
||||
/* When deciding whether a tile needs mem2gmem, we need to take into
|
||||
* account the scissor rect(s) that were cleared. To simplify we only
|
||||
* consider the last scissor rect for each buffer, since the common
|
||||
* case would be a single clear.
|
||||
*/
|
||||
bool
|
||||
fd_gmem_needs_restore(struct fd_context *ctx, struct fd_tile *tile,
|
||||
uint32_t buffers)
|
||||
{
|
||||
if (!(ctx->restore & buffers))
|
||||
return false;
|
||||
|
||||
/* if buffers partially cleared, then slow-path to figure out
|
||||
* if this particular tile needs restoring:
|
||||
*/
|
||||
if ((buffers & FD_BUFFER_COLOR) &&
|
||||
(ctx->partial_cleared & FD_BUFFER_COLOR) &&
|
||||
skip_restore(&ctx->cleared_scissor.color, tile))
|
||||
return false;
|
||||
if ((buffers & FD_BUFFER_DEPTH) &&
|
||||
(ctx->partial_cleared & FD_BUFFER_DEPTH) &&
|
||||
skip_restore(&ctx->cleared_scissor.depth, tile))
|
||||
return false;
|
||||
if ((buffers & FD_BUFFER_STENCIL) &&
|
||||
(ctx->partial_cleared & FD_BUFFER_STENCIL) &&
|
||||
skip_restore(&ctx->cleared_scissor.stencil, tile))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -55,6 +55,11 @@ struct fd_gmem_stateobj {
|
||||
bool has_zs; /* gmem config using depth/stencil? */
|
||||
};
|
||||
|
||||
void fd_gmem_render_tiles(struct pipe_context *pctx);
|
||||
struct fd_context;
|
||||
|
||||
void fd_gmem_render_tiles(struct fd_context *ctx);
|
||||
|
||||
bool fd_gmem_needs_restore(struct fd_context *ctx, struct fd_tile *tile,
|
||||
uint32_t buffers);
|
||||
|
||||
#endif /* FREEDRENO_GMEM_H_ */
|
||||
|
||||
Reference in New Issue
Block a user