From: Vadim Girlin Date: Tue, 21 Aug 2012 11:39:25 +0000 (+0400) Subject: r600g: fix lockups with dual_src_blend v2 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=8d1a9a984f33d8e45f932a9f47cdd57da617a919;p=mesa.git r600g: fix lockups with dual_src_blend v2 Disable blending when dual_src_blend is enabled and number of color exports in the current fragment shader is less than 2. Fixes lockups with ext_framebuffer_multisample- alpha-to-coverage-dual-src-blend piglit test. Signed-off-by: Vadim Girlin --- diff --git a/src/gallium/drivers/r600/r600_pipe.c b/src/gallium/drivers/r600/r600_pipe.c index cf2983315b2..7936c475bb6 100644 --- a/src/gallium/drivers/r600/r600_pipe.c +++ b/src/gallium/drivers/r600/r600_pipe.c @@ -156,6 +156,9 @@ static void r600_destroy_context(struct pipe_context *context) { struct r600_context *rctx = (struct r600_context *)context; + if (rctx->no_blend) { + rctx->context.delete_blend_state(&rctx->context, rctx->no_blend); + } if (rctx->dummy_pixel_shader) { rctx->context.delete_fs_state(&rctx->context, rctx->dummy_pixel_shader); } @@ -195,6 +198,7 @@ static struct pipe_context *r600_create_context(struct pipe_screen *screen, void { struct r600_context *rctx = CALLOC_STRUCT(r600_context); struct r600_screen* rscreen = (struct r600_screen *)screen; + struct pipe_blend_state no_blend = {}; if (rctx == NULL) return NULL; @@ -296,6 +300,9 @@ static struct pipe_context *r600_create_context(struct pipe_screen *screen, void TGSI_INTERPOLATE_CONSTANT); rctx->context.bind_fs_state(&rctx->context, rctx->dummy_pixel_shader); + no_blend.rt[0].colormask = 0xF; + rctx->no_blend = rctx->context.create_blend_state(&rctx->context, &no_blend); + return &rctx->context; fail: diff --git a/src/gallium/drivers/r600/r600_pipe.h b/src/gallium/drivers/r600/r600_pipe.h index 7046573ab0b..3686521862e 100644 --- a/src/gallium/drivers/r600/r600_pipe.h +++ b/src/gallium/drivers/r600/r600_pipe.h @@ -389,6 +389,14 @@ struct r600_context { struct r600_cs_shader_state cs_shader_state; struct r600_sample_mask sample_mask; + /* current external blend state (from state tracker) */ + struct r600_pipe_blend *blend; + /* state with disabled blending - used internally with blend_override */ + struct r600_pipe_blend *no_blend; + + /* 1 - override current blend state with no_blend, 0 - use external state */ + unsigned blend_override; + struct radeon_winsys_cs *cs; struct r600_range *range; diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c index ba5e26c6411..0870cc7e958 100644 --- a/src/gallium/drivers/r600/r600_state_common.c +++ b/src/gallium/drivers/r600/r600_state_common.c @@ -165,19 +165,15 @@ static bool r600_conv_pipe_prim(unsigned pprim, unsigned *prim) } /* common state between evergreen and r600 */ -void r600_bind_blend_state(struct pipe_context *ctx, void *state) + +static void r600_bind_blend_state_internal(struct r600_context *rctx, + struct r600_pipe_blend *blend) { - struct r600_context *rctx = (struct r600_context *)ctx; - struct r600_pipe_blend *blend = (struct r600_pipe_blend *)state; struct r600_pipe_state *rstate; bool update_cb = false; - if (state == NULL) - return; rstate = &blend->rstate; rctx->states[rstate->id] = rstate; - rctx->dual_src_blend = blend->dual_src_blend; - rctx->alpha_to_one = blend->alpha_to_one; r600_context_pipe_state_set(rctx, rstate); if (rctx->cb_misc_state.blend_colormask != blend->cb_target_mask) { @@ -198,6 +194,22 @@ void r600_bind_blend_state(struct pipe_context *ctx, void *state) } } +void r600_bind_blend_state(struct pipe_context *ctx, void *state) +{ + struct r600_context *rctx = (struct r600_context *)ctx; + struct r600_pipe_blend *blend = (struct r600_pipe_blend *)state; + + if (blend == NULL) + return; + + rctx->blend = blend; + rctx->alpha_to_one = blend->alpha_to_one; + rctx->dual_src_blend = blend->dual_src_blend; + + if (!rctx->blend_override) + r600_bind_blend_state_internal(rctx, blend); +} + void r600_set_blend_color(struct pipe_context *ctx, const struct pipe_blend_color *state) { @@ -1024,7 +1036,7 @@ void r600_set_sample_mask(struct pipe_context *pipe, unsigned sample_mask) static void r600_update_derived_state(struct r600_context *rctx) { struct pipe_context * ctx = (struct pipe_context*)rctx; - unsigned ps_dirty = 0; + unsigned ps_dirty = 0, blend_override; if (!rctx->blitter->running) { /* Flush depth textures which need to be flushed. */ @@ -1052,7 +1064,16 @@ static void r600_update_derived_state(struct r600_context *rctx) if (ps_dirty) r600_context_pipe_state_set(rctx, &rctx->ps_shader->current->rstate); - + + blend_override = (rctx->dual_src_blend && + rctx->ps_shader->current->nr_ps_color_outputs < 2); + + if (blend_override != rctx->blend_override) { + rctx->blend_override = blend_override; + r600_bind_blend_state_internal(rctx, + blend_override ? rctx->no_blend : rctx->blend); + } + if (rctx->chip_class >= EVERGREEN) { evergreen_update_dual_export_state(rctx); } else {