r600g: fix lockups with dual_src_blend v2
authorVadim Girlin <vadimgirlin@gmail.com>
Tue, 21 Aug 2012 11:39:25 +0000 (15:39 +0400)
committerVadim Girlin <vadimgirlin@gmail.com>
Wed, 22 Aug 2012 08:12:22 +0000 (12:12 +0400)
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 <vadimgirlin@gmail.com>
src/gallium/drivers/r600/r600_pipe.c
src/gallium/drivers/r600/r600_pipe.h
src/gallium/drivers/r600/r600_state_common.c

index cf2983315b2e1f8a26e434bd3215759bc8dc683e..7936c475bb6db040ba2b0961e843299f9d00f724 100644 (file)
@@ -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:
index 7046573ab0baa88f43fd89f2c020cb56e1085e95..3686521862ed5264e536367c653ef4743fe28da9 100644 (file)
@@ -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;
index ba5e26c64111d1b5f867a2246dcb325e04384786..0870cc7e9583c5fbd21299b101942b6288e0060a 100644 (file)
@@ -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 {