radeonsi: fix a Unigine Heaven hang when drirc is missing
authorMarek Olšák <marek.olsak@amd.com>
Sat, 29 Aug 2015 20:59:23 +0000 (22:59 +0200)
committerMarek Olšák <marek.olsak@amd.com>
Tue, 1 Sep 2015 19:51:13 +0000 (21:51 +0200)
Cc: 10.6 11.0 <mesa-stable@lists.freedesktop.org>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Acked-by: Christian König <christian.koenig@amd.com>
src/gallium/drivers/radeonsi/si_shader.h
src/gallium/drivers/radeonsi/si_state.c
src/gallium/drivers/radeonsi/si_state.h
src/gallium/drivers/radeonsi/si_state_shaders.c

index 423b849..ad32473 100644 (file)
@@ -190,6 +190,7 @@ struct si_shader_selector {
        uint64_t        inputs_read;
        uint64_t        outputs_written;
        uint32_t        patch_outputs_written;
+       uint32_t        ps_colors_written;
 };
 
 /* Valid shader configurations:
index 806ab5f..1ca5e46 100644 (file)
@@ -29,6 +29,7 @@
 #include "sid.h"
 #include "radeon/r600_cs.h"
 
+#include "util/u_dual_blend.h"
 #include "util/u_format.h"
 #include "util/u_format_s3tc.h"
 #include "util/u_memory.h"
@@ -233,8 +234,10 @@ static unsigned si_pack_float_12p4(float x)
  * - The COLOR1 format isn't INVALID because of possible dual-source blending,
  *   so COLOR1 is enabled pretty much all the time.
  * So CB_TARGET_MASK is the only register that can disable COLOR1.
+ *
+ * Another reason is to avoid a hang with dual source blending.
  */
-static void si_update_fb_blend_state(struct si_context *sctx)
+void si_update_fb_blend_state(struct si_context *sctx)
 {
        struct si_pm4_state *pm4;
        struct si_state_blend *blend = sctx->queued.named.blend;
@@ -252,6 +255,16 @@ static void si_update_fb_blend_state(struct si_context *sctx)
                        mask |= 0xf << (4*i);
        mask &= blend->cb_target_mask;
 
+       /* Avoid a hang that happens when dual source blending is enabled
+        * but there is not enough color outputs. This is undefined behavior,
+        * so disable color writes completely.
+        *
+        * Reproducible with Unigine Heaven 4.0 and drirc missing.
+        */
+       if (blend->dual_src_blend &&
+           (sctx->ps_shader->ps_colors_written & 0x3) != 0x3)
+               mask = 0;
+
        si_pm4_set_reg(pm4, R_028238_CB_TARGET_MASK, mask);
        si_pm4_set_state(sctx, fb_blend, pm4);
 }
@@ -343,6 +356,7 @@ static void *si_create_blend_state_mode(struct pipe_context *ctx,
                return NULL;
 
        blend->alpha_to_one = state->alpha_to_one;
+       blend->dual_src_blend = util_blend_state_is_dual(state, 0);
 
        if (state->logicop_enable) {
                color_control |= S_028808_ROP3(state->logicop_func | (state->logicop_func << 4));
index 118c562..242db8a 100644 (file)
@@ -39,6 +39,7 @@ struct si_state_blend {
        struct si_pm4_state     pm4;
        uint32_t                cb_target_mask;
        bool                    alpha_to_one;
+       bool                    dual_src_blend;
 };
 
 struct si_state_sample_mask {
@@ -251,6 +252,7 @@ void si_shader_change_notify(struct si_context *sctx);
 /* si_state.c */
 struct si_shader_selector;
 
+void si_update_fb_blend_state(struct si_context *sctx);
 boolean si_is_format_supported(struct pipe_screen *screen,
                                enum pipe_format format,
                                enum pipe_texture_target target,
index a09f588..b223e06 100644 (file)
@@ -713,6 +713,15 @@ static void *si_create_shader_state(struct pipe_context *ctx,
                        }
                }
                break;
+       case PIPE_SHADER_FRAGMENT:
+               for (i = 0; i < sel->info.num_outputs; i++) {
+                       unsigned name = sel->info.output_semantic_name[i];
+                       unsigned index = sel->info.output_semantic_index[i];
+
+                       if (name == TGSI_SEMANTIC_COLOR)
+                               sel->ps_colors_written |= 1 << index;
+               }
+               break;
        }
 
        if (sscreen->b.debug_flags & DBG_PRECOMPILE)
@@ -840,6 +849,7 @@ static void si_bind_ps_shader(struct pipe_context *ctx, void *state)
        }
 
        sctx->ps_shader = sel;
+       si_update_fb_blend_state(sctx);
 }
 
 static void si_delete_shader_selector(struct pipe_context *ctx,