From: Jerome Glisse <jgli...@redhat.com>

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 <jgli...@redhat.com>
---
 src/gallium/drivers/r600/evergreen_state.c   | 25 +++++++++++++++++++++++--
 src/gallium/drivers/r600/r600_state.c        | 22 +++++++++++++++++++++-
 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 211c218..29b22ab 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 5322850..3f359fb 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 33200a6..c03ce3d 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);
+               }
        }
 }
 
-- 
1.7.11.7

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to