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);
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);
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
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);
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);
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 */
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)
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) |
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
} 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 */
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) |
/* 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:
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;
}
}
emit_marker(ring, 7);
- ctx->rmw.need_wfi = true;
+ ctx->rmw_needs_wfi = true;
}
#endif /* FREEDRENO_DRAW_H_ */