diff options
author | Jerome Glisse <[email protected]> | 2013-02-08 16:02:32 -0500 |
---|---|---|
committer | Jerome Glisse <[email protected]> | 2013-02-12 17:03:56 -0500 |
commit | 974b482acaf62ced1e8981761a8bda252bd51fe1 (patch) | |
tree | a264943597a145f582934fbad15b7e776aa12553 /src | |
parent | 496928a442cec980b534bc5da2523b3632b21b61 (diff) |
r600g: fix lockup when hyperz & alpha test are enabled together. v3
Seems that alpha test being enabled confuse the GPU on the order in
which it should perform the Z testing. So force the order programmed
throught db shader control.
v2: Only force z order when alpha test is enabled
v3: Update db shader when binding new dsa + spelling fix
Signed-off-by: Jerome Glisse <[email protected]>
Reviewed-by: Marek Olšák <[email protected]>
Diffstat (limited to 'src')
-rw-r--r-- | src/gallium/drivers/r600/evergreen_state.c | 25 | ||||
-rw-r--r-- | src/gallium/drivers/r600/r600_state.c | 22 | ||||
-rw-r--r-- | src/gallium/drivers/r600/r600_state_common.c | 5 |
3 files changed, 49 insertions, 3 deletions
diff --git a/src/gallium/drivers/r600/evergreen_state.c b/src/gallium/drivers/r600/evergreen_state.c index 211c2183bff..29b22ab4c34 100644 --- a/src/gallium/drivers/r600/evergreen_state.c +++ b/src/gallium/drivers/r600/evergreen_state.c @@ -2251,6 +2251,13 @@ static void evergreen_emit_db_misc_state(struct r600_context *rctx, struct r600_ if (rctx->db_state.rsurf && rctx->db_state.rsurf->htile_enabled) { /* FORCE_OFF means HiZ/HiS are determined by DB_SHADER_CONTROL */ db_render_override |= S_02800C_FORCE_HIZ_ENABLE(V_02800C_FORCE_OFF); + /* This is to fix a lockup when hyperz and alpha test are enabled at + * the same time somehow GPU get confuse on which order to pick for + * z test + */ + if (rctx->alphatest_state.sx_alpha_test_control) { + db_render_override |= S_02800C_FORCE_SHADER_Z_ORDER(1); + } } else { db_render_override |= S_02800C_FORCE_HIZ_ENABLE(V_02800C_FORCE_DISABLE); } @@ -3240,7 +3247,7 @@ void evergreen_pipe_shader_ps(struct pipe_context *ctx, struct r600_pipe_shader struct r600_context *rctx = (struct r600_context *)ctx; struct r600_pipe_state *rstate = &shader->rstate; struct r600_shader *rshader = &shader->shader; - unsigned i, exports_ps, num_cout, spi_ps_in_control_0, spi_input_z, spi_ps_in_control_1, db_shader_control; + unsigned i, exports_ps, num_cout, spi_ps_in_control_0, spi_input_z, spi_ps_in_control_1, db_shader_control = 0; int pos_index = -1, face_index = -1; int ninterp = 0; boolean have_linear = FALSE, have_centroid = FALSE, have_perspective = FALSE; @@ -3250,7 +3257,6 @@ void evergreen_pipe_shader_ps(struct pipe_context *ctx, struct r600_pipe_shader rstate->nregs = 0; - db_shader_control = S_02880C_Z_ORDER(V_02880C_EARLY_Z_THEN_LATE_Z); for (i = 0; i < rshader->ninput; i++) { /* evergreen NUM_INTERP only contains values interpolated into the LDS, POSITION goes via GPRs from the SC so isn't counted */ @@ -3484,6 +3490,21 @@ void evergreen_update_db_shader_control(struct r600_context * rctx) V_02880C_EXPORT_DB_FULL) | S_02880C_ALPHA_TO_MASK_DISABLE(rctx->framebuffer.cb0_is_integer); + /* When alpha test is enabled we can't trust the hw to make the proper + * decision on the order in which ztest should be run related to fragment + * shader execution. + * + * If alpha test is enabled perform early z rejection (RE_Z) but don't early + * write to the zbuffer. Write to zbuffer is delayed after fragment shader + * execution and thus after alpha test so if discarded by the alpha test + * the z value is not written. + */ + if (rctx->alphatest_state.sx_alpha_test_control) { + db_shader_control |= S_02880C_Z_ORDER(V_02880C_RE_Z); + } else { + db_shader_control |= S_02880C_Z_ORDER(V_02880C_EARLY_Z_THEN_LATE_Z); + } + if (db_shader_control != rctx->db_misc_state.db_shader_control) { rctx->db_misc_state.db_shader_control = db_shader_control; rctx->db_misc_state.atom.dirty = true; diff --git a/src/gallium/drivers/r600/r600_state.c b/src/gallium/drivers/r600/r600_state.c index 532285024f1..3f359fb0dd7 100644 --- a/src/gallium/drivers/r600/r600_state.c +++ b/src/gallium/drivers/r600/r600_state.c @@ -1966,6 +1966,13 @@ static void r600_emit_db_misc_state(struct r600_context *rctx, struct r600_atom if (rctx->db_state.rsurf && rctx->db_state.rsurf->htile_enabled) { /* FORCE_OFF means HiZ/HiS are determined by DB_SHADER_CONTROL */ db_render_override |= S_028D10_FORCE_HIZ_ENABLE(V_028D10_FORCE_OFF); + /* This is to fix a lockup when hyperz and alpha test are enabled at + * the same time somehow GPU get confuse on which order to pick for + * z test + */ + if (rctx->alphatest_state.sx_alpha_test_control) { + db_render_override |= S_028D10_FORCE_SHADER_Z_ORDER(1); + } } else { db_render_override |= S_028D10_FORCE_HIZ_ENABLE(V_028D10_FORCE_DISABLE); } @@ -2774,7 +2781,7 @@ void r600_pipe_shader_ps(struct pipe_context *ctx, struct r600_pipe_shader *shad tmp); } - db_shader_control = S_02880C_Z_ORDER(V_02880C_EARLY_Z_THEN_LATE_Z); + db_shader_control = 0; for (i = 0; i < rshader->noutput; i++) { if (rshader->output[i].name == TGSI_SEMANTIC_POSITION) z_export = 1; @@ -2969,6 +2976,19 @@ void r600_update_db_shader_control(struct r600_context * rctx) unsigned db_shader_control = rctx->ps_shader->current->db_shader_control | S_02880C_DUAL_EXPORT_ENABLE(dual_export); + /* When alpha test is enabled we can't trust the hw to make the proper + * decision on the order in which ztest should be run related to fragment + * shader execution. + * + * If alpha test is enabled perform z test after fragment. RE_Z (early + * z test but no write to the zbuffer) seems to cause lockup on r6xx/r7xx + */ + if (rctx->alphatest_state.sx_alpha_test_control) { + db_shader_control |= S_02880C_Z_ORDER(V_02880C_LATE_Z); + } else { + db_shader_control |= S_02880C_Z_ORDER(V_02880C_EARLY_Z_THEN_LATE_Z); + } + if (db_shader_control != rctx->db_misc_state.db_shader_control) { rctx->db_misc_state.db_shader_control = db_shader_control; rctx->db_misc_state.atom.dirty = true; diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c index 33200a6d178..c03ce3d86ee 100644 --- a/src/gallium/drivers/r600/r600_state_common.c +++ b/src/gallium/drivers/r600/r600_state_common.c @@ -293,6 +293,11 @@ static void r600_bind_dsa_state(struct pipe_context *ctx, void *state) rctx->alphatest_state.sx_alpha_test_control = dsa->sx_alpha_test_control; rctx->alphatest_state.sx_alpha_ref = dsa->alpha_ref; rctx->alphatest_state.atom.dirty = true; + if (rctx->chip_class >= EVERGREEN) { + evergreen_update_db_shader_control(rctx); + } else { + r600_update_db_shader_control(rctx); + } } } |