From 8ab47b435319c05521bdfced6da6ce72850a2dd7 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 23 Dec 2013 09:59:42 -0500 Subject: freedreno/a3xx: fix blend state corruption issue Using RMW on banked context registers is not safe. The value read could be the wrong one. So if there has been a DRAW_IDX launched, the RMW must be preceded by a WAIT_FOR_IDLE to ensure the read part of RMW sees the correct value. To avoid unnecessary WFI's, keep track if there is a need for WFI, and only emit one if needed. Furthermore, keep track if we even need to update the register in the first place. And to cut down on the amount of RMW to avoid excessive WFI's, at the tiling/GMEM level we can always overwrite RB_RENDER_CONTROL, as the state at beginning of draw/clear cmds (which we IB to) is always undefined. In the draw/clear commands, we always still use RMW (with WFI if needed), but only if the register value actually changes. (At points where the current value cannot be known, the saved value is reset to ~0, which includes bits outside of RBRC_DRAW_STATE, so there never is chance for confusion.) Signed-off-by: Rob Clark --- src/gallium/drivers/freedreno/freedreno_context.h | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'src/gallium/drivers/freedreno/freedreno_context.h') diff --git a/src/gallium/drivers/freedreno/freedreno_context.h b/src/gallium/drivers/freedreno/freedreno_context.h index db37f9cb8a3..a8abbca7a62 100644 --- a/src/gallium/drivers/freedreno/freedreno_context.h +++ b/src/gallium/drivers/freedreno/freedreno_context.h @@ -38,6 +38,7 @@ #include "freedreno_screen.h" #include "freedreno_gmem.h" +#include "freedreno_util.h" struct fd_vertex_stateobj; @@ -150,6 +151,20 @@ struct fd_context { struct fd_ringbuffer *ring; struct fd_ringmarker *draw_start, *draw_end; + /* 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; + struct pipe_scissor_state scissor; /* we don't have a disable/enable bit for scissor, so instead we keep @@ -249,6 +264,23 @@ fd_supported_prim(struct fd_context *ctx, unsigned prim) return (1 << prim) & ctx->primtype_mask; } +static INLINE void +fd_reset_rmw_state(struct fd_context *ctx) +{ + ctx->rmw.need_wfi = true; + ctx->rmw.rbrc_draw = ~0; +} + +/* 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) { + OUT_WFI(ring); + ctx->rmw.need_wfi = false; + } +} + struct pipe_context * fd_context_init(struct fd_context *ctx, struct pipe_screen *pscreen, const uint8_t *primtypes, void *priv); -- cgit v1.2.3