Commit 725d736f authored by Rob Clark's avatar Rob Clark
Browse files

freedreno/a3xx: use cs patch instead of RFI+RMW



Since we now have the cmdstream patch mechanism needed for hw binning,
might as well also use it for RB_RENDER_CONTROL updates.  This avoids
the need to use RMW (and associated WFI) to update RB_RENDER_CONTROL.
Signed-off-by: default avatarRob Clark <robclark@freedesktop.org>
parent c0766528
......@@ -44,6 +44,8 @@ fd3_context_destroy(struct pipe_context *pctx)
fd3_prog_fini(pctx);
util_dynarray_fini(&fd3_ctx->rbrc_patches);
fd_bo_del(fd3_ctx->vs_pvt_mem);
fd_bo_del(fd3_ctx->fs_pvt_mem);
fd_bo_del(fd3_ctx->vsc_size_mem);
......@@ -119,6 +121,8 @@ fd3_context_create(struct pipe_screen *pscreen, void *priv)
if (!pctx)
return NULL;
util_dynarray_init(&fd3_ctx->rbrc_patches);
fd3_ctx->vs_pvt_mem = fd_bo_new(screen->dev, 0x2000,
DRM_FREEDRENO_GEM_TYPE_KMEM);
......
......@@ -36,6 +36,11 @@
struct fd3_context {
struct fd_context base;
/* Keep track of writes to RB_RENDER_CONTROL which need to be patched
* once we know whether or not to use GMEM, and GMEM tile pitch.
*/
struct util_dynarray rbrc_patches;
struct fd_bo *vs_pvt_mem, *fs_pvt_mem;
/* This only needs to be 4 * num_of_pipes bytes (ie. 32 bytes). We
......
......@@ -162,8 +162,9 @@ fd3_clear(struct fd_context *ctx, unsigned buffers,
OUT_RING(ring, A3XX_RB_BLEND_ALPHA_UINT(0xff) |
A3XX_RB_BLEND_ALPHA_FLOAT(1.0));
fd3_emit_rbrc_draw_state(ctx, ring,
A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC(FUNC_NEVER));
OUT_PKT0(ring, REG_A3XX_RB_RENDER_CONTROL, 1);
OUT_RINGP(ring, A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC(FUNC_NEVER),
&fd3_ctx->rbrc_patches);
if (buffers & PIPE_CLEAR_DEPTH) {
OUT_PKT0(ring, REG_A3XX_RB_DEPTH_CONTROL, 1);
......
......@@ -353,8 +353,19 @@ fd3_emit_state(struct fd_context *ctx, struct fd_ringbuffer *ring,
struct fd3_zsa_stateobj *zsa = fd3_zsa_stateobj(ctx->zsa);
struct pipe_stencil_ref *sr = &ctx->stencil_ref;
if (!binning)
fd3_emit_rbrc_draw_state(ctx, ring, zsa->rb_render_control);
if (!binning) {
struct fd3_context *fd3_ctx = fd3_context(ctx);
/* I suppose if we needed to (which I don't *think* we need
* to), we could emit this for binning pass too. But we
* would need to keep a different patch-list for binning
* vs render pass.
*/
OUT_PKT0(ring, REG_A3XX_RB_RENDER_CONTROL, 1);
OUT_RINGP(ring, zsa->rb_render_control,
&fd3_ctx->rbrc_patches);
}
OUT_PKT0(ring, REG_A3XX_RB_ALPHA_REF, 1);
OUT_RING(ring, zsa->rb_alpha_ref);
......
......@@ -62,28 +62,4 @@ void fd3_emit_state(struct fd_context *ctx, struct fd_ringbuffer *ring,
uint32_t dirty, bool binning);
void fd3_emit_restore(struct fd_context *ctx);
/* use RMW (read-modify-write) to update RB_RENDER_CONTROL since the
* GMEM/binning code is deciding on the bin-width (and whether to
* use binning) after the draw/clear state is emitted.
*/
#define RBRC_DRAW_STATE (A3XX_RB_RENDER_CONTROL_ALPHA_TEST | \
A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC__MASK)
static inline void
fd3_emit_rbrc_draw_state(struct fd_context *ctx,
struct fd_ringbuffer *ring, uint32_t val)
{
assert(!(val & ~RBRC_DRAW_STATE));
if (val != ctx->rmw.rbrc_draw) {
fd_rmw_wfi(ctx, ring);
OUT_PKT3(ring, CP_REG_RMW, 3);
OUT_RING(ring, REG_A3XX_RB_RENDER_CONTROL);
OUT_RING(ring, ~RBRC_DRAW_STATE);
OUT_RING(ring, val);
ctx->rmw.rbrc_draw = val;
}
}
#endif /* FD3_EMIT_H */
......@@ -544,6 +544,18 @@ patch_draws(struct fd_context *ctx, enum pc_di_vis_cull_mode vismode)
util_dynarray_resize(&ctx->draw_patches, 0);
}
static void
patch_rbrc(struct fd_context *ctx, uint32_t val)
{
struct fd3_context *fd3_ctx = fd3_context(ctx);
unsigned i;
for (i = 0; i < fd_patch_num_elements(&fd3_ctx->rbrc_patches); i++) {
struct fd_cs_patch *patch = fd_patch_element(&fd3_ctx->rbrc_patches, i);
*patch->cs = patch->val | val;
}
util_dynarray_resize(&fd3_ctx->rbrc_patches, 0);
}
/* for rendering directly to system memory: */
static void
fd3_emit_sysmem_prep(struct fd_context *ctx)
......@@ -563,10 +575,6 @@ fd3_emit_sysmem_prep(struct fd_context *ctx)
emit_mrt(ring, pfb->nr_cbufs, pfb->cbufs, NULL, 0);
OUT_PKT0(ring, REG_A3XX_RB_RENDER_CONTROL, 1);
OUT_RING(ring, A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC(FUNC_NEVER) |
A3XX_RB_RENDER_CONTROL_BIN_WIDTH(pitch));
/* setup scissor/offset for current tile: */
OUT_PKT0(ring, REG_A3XX_RB_WINDOW_OFFSET, 1);
OUT_RING(ring, A3XX_RB_WINDOW_OFFSET_X(0) |
......@@ -584,6 +592,7 @@ fd3_emit_sysmem_prep(struct fd_context *ctx)
A3XX_RB_MODE_CONTROL_MARB_CACHE_SPLIT_MODE);
patch_draws(ctx, IGNORE_VISIBILITY);
patch_rbrc(ctx, A3XX_RB_RENDER_CONTROL_BIN_WIDTH(pitch));
}
static void
......@@ -757,6 +766,9 @@ fd3_emit_tile_init(struct fd_context *ctx)
} else {
patch_draws(ctx, IGNORE_VISIBILITY);
}
patch_rbrc(ctx, A3XX_RB_RENDER_CONTROL_ENABLE_GMEM |
A3XX_RB_RENDER_CONTROL_BIN_WIDTH(gmem->bin_w));
}
/* before mem2gmem */
......@@ -837,11 +849,6 @@ fd3_emit_tile_renderprep(struct fd_context *ctx, struct fd_tile *tile)
emit_mrt(ring, pfb->nr_cbufs, pfb->cbufs, NULL, gmem->bin_w);
OUT_PKT0(ring, REG_A3XX_RB_RENDER_CONTROL, 1);
OUT_RING(ring, A3XX_RB_RENDER_CONTROL_ENABLE_GMEM |
A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC(FUNC_NEVER) |
A3XX_RB_RENDER_CONTROL_BIN_WIDTH(gmem->bin_w));
/* setup scissor/offset for current tile: */
OUT_PKT0(ring, REG_A3XX_RB_WINDOW_OFFSET, 1);
OUT_RING(ring, A3XX_RB_WINDOW_OFFSET_X(tile->xoff) |
......
......@@ -159,16 +159,7 @@ struct fd_context {
/* Keep track if WAIT_FOR_IDLE is needed for registers we need
* to update via RMW:
*/
struct {
bool need_wfi;
/* note: would be nicer to have in fd3_context, fd2_context,
* etc, because the registered modified via RMR differ across
* generation. But as long as it is a small set of registers
* that might be more hassle than it's worth.
*/
/* state for RB_RENDER_CONTROL: */
uint32_t rbrc_draw;
} rmw;
bool rmw_needs_wfi;
/* Keep track of DRAW initiators that need to be patched up depending
* on whether we using binning or not:
......@@ -277,17 +268,16 @@ fd_supported_prim(struct fd_context *ctx, unsigned prim)
static INLINE void
fd_reset_rmw_state(struct fd_context *ctx)
{
ctx->rmw.need_wfi = true;
ctx->rmw.rbrc_draw = ~0;
ctx->rmw_needs_wfi = true;
}
/* emit before a RMW a WAIT_FOR_IDLE only if needed: */
static inline void
fd_rmw_wfi(struct fd_context *ctx, struct fd_ringbuffer *ring)
{
if (ctx->rmw.need_wfi) {
if (ctx->rmw_needs_wfi) {
OUT_WFI(ring);
ctx->rmw.need_wfi = false;
ctx->rmw_needs_wfi = false;
}
}
......
......@@ -95,7 +95,7 @@ fd_draw(struct fd_context *ctx, struct fd_ringbuffer *ring,
emit_marker(ring, 7);
ctx->rmw.need_wfi = true;
ctx->rmw_needs_wfi = true;
}
#endif /* FREEDRENO_DRAW_H_ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment