#include "freedreno_gmem.h"
#include "freedreno_context.h"
#include "freedreno_resource.h"
+#include "freedreno_query_hw.h"
#include "freedreno_util.h"
/*
static uint32_t bin_width(struct fd_context *ctx)
{
- if (ctx->screen->gpu_id >= 300)
+ if (is_a4xx(ctx->screen))
+ return 1024;
+ if (is_a3xx(ctx->screen))
return 992;
return 512;
}
max_width /= 2;
}
- if (fd_mesa_debug & FD_DBG_DSCIS) {
+ if (fd_mesa_debug & FD_DBG_NOSCIS) {
minx = 0;
miny = 0;
width = pfb->width;
bin_w = align(width / nbins_x, 32);
}
- /* then find a bin height that satisfies the memory constraints:
+ /* then find a bin width/height that satisfies the memory
+ * constraints:
*/
while ((bin_w * bin_h * cpp) > gmem_size) {
- nbins_y++;
- bin_h = align(height / nbins_y, 32);
+ if (bin_w > bin_h) {
+ nbins_x++;
+ bin_w = align(width / nbins_x, 32);
+ } else {
+ nbins_y++;
+ bin_h = align(height / nbins_y, 32);
+ }
}
DBG("using %d bins of size %dx%d", nbins_x*nbins_y, bin_w, bin_h);
ctx->emit_tile_prep(ctx, tile);
- if (ctx->restore)
+ if (ctx->restore) {
+ fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_MEM2GMEM);
ctx->emit_tile_mem2gmem(ctx, tile);
+ fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_NULL);
+ }
ctx->emit_tile_renderprep(ctx, tile);
+ fd_hw_query_prepare_tile(ctx, i, ctx->ring);
+
/* emit IB to drawcmds: */
OUT_IB(ctx->ring, ctx->draw_start, ctx->draw_end);
fd_reset_wfi(ctx);
/* emit gmem2mem to transfer tile back to system memory: */
+ fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_GMEM2MEM);
ctx->emit_tile_gmem2mem(ctx, tile);
+ fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_NULL);
}
}
{
ctx->emit_sysmem_prep(ctx);
+ fd_hw_query_prepare_tile(ctx, 0, ctx->ring);
+
/* emit IB to drawcmds: */
OUT_IB(ctx->ring, ctx->draw_start, ctx->draw_end);
fd_reset_wfi(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;
+ uint32_t i, timestamp = 0;
bool sysmem = false;
if (ctx->emit_sysmem_prep) {
if (ctx->cleared || ctx->gmem_reason || (ctx->num_draws > 5)) {
DBG("GMEM: cleared=%x, gmem_reason=%x, num_draws=%u",
ctx->cleared, ctx->gmem_reason, ctx->num_draws);
- } else if (!(fd_mesa_debug & FD_DBG_DBYPASS)) {
+ } else if (!(fd_mesa_debug & FD_DBG_NOBYPASS)) {
sysmem = true;
}
}
+ /* close out the draw cmds by making sure any active queries are
+ * paused:
+ */
+ fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_NULL);
+
/* mark the end of the clear/draw cmds before emitting per-tile cmds: */
fd_ringmarker_mark(ctx->draw_end);
fd_ringmarker_mark(ctx->binning_end);
DBG("rendering sysmem (%s/%s)",
util_format_short_name(pipe_surface_format(pfb->cbufs[0])),
util_format_short_name(pipe_surface_format(pfb->zsbuf)));
+ fd_hw_query_prepare(ctx, 1);
render_sysmem(ctx);
ctx->stats.batch_sysmem++;
} else {
DBG("rendering %dx%d tiles (%s/%s)", gmem->nbins_x, gmem->nbins_y,
util_format_short_name(pipe_surface_format(pfb->cbufs[0])),
util_format_short_name(pipe_surface_format(pfb->zsbuf)));
+ fd_hw_query_prepare(ctx, gmem->nbins_x * gmem->nbins_y);
render_tiles(ctx);
ctx->stats.batch_gmem++;
}
/* update timestamps on render targets: */
timestamp = fd_ringbuffer_timestamp(ctx->ring);
- if (pfb->cbufs[0])
- fd_resource(pfb->cbufs[0]->texture)->timestamp = timestamp;
+ for (i = 0; i < pfb->nr_cbufs; i++)
+ if (pfb->cbufs[i])
+ fd_resource(pfb->cbufs[i]->texture)->timestamp = timestamp;
if (pfb->zsbuf)
fd_resource(pfb->zsbuf->texture)->timestamp = timestamp;
ctx->max_scissor.minx = ctx->max_scissor.miny = ~0;
ctx->max_scissor.maxx = ctx->max_scissor.maxy = 0;
- /* Note that because the per-tile setup and mem2gmem/gmem2mem are emitted
- * after the draw/clear calls, but executed before, we need to preemptively
- * flag some state as dirty before the first draw/clear call.
- *
- * TODO maybe we need to mark all state as dirty to not worry about state
- * being clobbered by other contexts?
+ 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:
*/
- ctx->dirty |= FD_DIRTY_ZSA |
- FD_DIRTY_RASTERIZER |
- FD_DIRTY_FRAMEBUFFER |
- FD_DIRTY_SAMPLE_MASK |
- FD_DIRTY_VIEWPORT |
- FD_DIRTY_CONSTBUF |
- FD_DIRTY_PROG |
- FD_DIRTY_SCISSOR |
- /* probably only needed if we need to mem2gmem on the next
- * draw.. but not sure if there is a good way to know?
- */
- FD_DIRTY_VERTTEX |
- FD_DIRTY_FRAGTEX |
- FD_DIRTY_BLEND;
-
- if (fd_mesa_debug & FD_DBG_DGMEM)
- ctx->dirty = 0xffffffff;
+ 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;
}