diff options
-rw-r--r-- | src/gallium/drivers/radeonsi/si_shader.h | 1 | ||||
-rw-r--r-- | src/gallium/drivers/radeonsi/si_state.c | 16 | ||||
-rw-r--r-- | src/gallium/drivers/radeonsi/si_state.h | 2 | ||||
-rw-r--r-- | src/gallium/drivers/radeonsi/si_state_shaders.c | 10 |
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, |