summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarek Olšák <[email protected]>2015-08-29 22:59:23 +0200
committerEmil Velikov <[email protected]>2015-09-06 18:31:12 +0100
commit1aea7812b0c55f82d0411cefba8a821d7b84b504 (patch)
tree1aa19f0923648eb4b9e7e0806a5077dae705020e
parentf0180a37d79a881b02d164f4f9ff22143928cbaf (diff)
radeonsi: fix a Unigine Heaven hang when drirc is missing
Cc: 10.6 11.0 <[email protected]> Reviewed-by: Alex Deucher <[email protected]> Acked-by: Christian König <[email protected]> (cherry picked from commit 9b510a9652297a63677f1d55b2bf444694fd94e1)
-rw-r--r--src/gallium/drivers/radeonsi/si_shader.h1
-rw-r--r--src/gallium/drivers/radeonsi/si_state.c16
-rw-r--r--src/gallium/drivers/radeonsi/si_state.h2
-rw-r--r--src/gallium/drivers/radeonsi/si_state_shaders.c10
4 files changed, 28 insertions, 1 deletions
diff --git a/src/gallium/drivers/radeonsi/si_shader.h b/src/gallium/drivers/radeonsi/si_shader.h
index cd845c12e64..511ee7333f3 100644
--- a/src/gallium/drivers/radeonsi/si_shader.h
+++ b/src/gallium/drivers/radeonsi/si_shader.h
@@ -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:
diff --git a/src/gallium/drivers/radeonsi/si_state.c b/src/gallium/drivers/radeonsi/si_state.c
index c923ea7e154..e610b48d80b 100644
--- a/src/gallium/drivers/radeonsi/si_state.c
+++ b/src/gallium/drivers/radeonsi/si_state.c
@@ -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));
diff --git a/src/gallium/drivers/radeonsi/si_state.h b/src/gallium/drivers/radeonsi/si_state.h
index b8f63c5dd36..8fa65dc780c 100644
--- a/src/gallium/drivers/radeonsi/si_state.h
+++ b/src/gallium/drivers/radeonsi/si_state.h
@@ -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,
diff --git a/src/gallium/drivers/radeonsi/si_state_shaders.c b/src/gallium/drivers/radeonsi/si_state_shaders.c
index 0347014948d..cb6aeb99101 100644
--- a/src/gallium/drivers/radeonsi/si_state_shaders.c
+++ b/src/gallium/drivers/radeonsi/si_state_shaders.c
@@ -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,