r300g: disable HiZ permanently if the the depth function is inverted
authorMarek Olšák <maraeo@gmail.com>
Mon, 28 Feb 2011 21:10:04 +0000 (22:10 +0100)
committerMarek Olšák <maraeo@gmail.com>
Mon, 28 Feb 2011 23:46:54 +0000 (00:46 +0100)
Instead of temporarily.

The HiZ function (something like a depth function) is a property
of a HiZ buffer and can only be changed during HiZ clears.

src/gallium/drivers/r300/r300_context.h
src/gallium/drivers/r300/r300_emit.c
src/gallium/drivers/r300/r300_hyperz.c

index e18f876fc2d54a40c0274a3db846c1b1c8a84a11..33d1390b070bca95607bf0b59a7822f1805b4844 100644 (file)
@@ -102,7 +102,6 @@ struct r300_dsa_state {
 };
 
 struct r300_hyperz_state {
-    int current_func; /* -1 after a clear before first op */
     int flush;
     /* This is actually a command buffer with named dwords. */
     uint32_t cb_flush_begin;
@@ -414,6 +413,21 @@ struct r300_vertex_element_state {
     struct r300_vertex_stream_state vertex_stream;
 };
 
+enum r300_hiz_func {
+    HIZ_FUNC_NONE,
+
+    /* The function, when determined, is set in stone
+     * until the next HiZ clear. */
+
+    /* MAX is written to the HiZ buffer.
+     * Used for LESS, LEQUAL. */
+    HIZ_FUNC_MAX,
+
+    /* MIN is written to the HiZ buffer.
+     * Used for GREATER, GEQUAL. */
+    HIZ_FUNC_MIN,
+};
+
 struct r300_context {
     /* Parent class */
     struct pipe_context context;
@@ -559,6 +573,8 @@ struct r300_context {
     struct pipe_surface *locked_zbuffer;
     /* Whether HIZ is enabled. */
     boolean hiz_in_use;
+    /* HiZ function. Can be either MIN or MAX. */
+    enum r300_hiz_func hiz_func;
 
     void *dsa_decompress_zmask;
 
index 1adac3454b4f8f021e5dd556df452b341d202956..6061c2a623cd28dee4248ae75dc79e3fb6ebe83d 100644 (file)
@@ -1028,8 +1028,6 @@ void r300_emit_hiz_clear(struct r300_context *r300, unsigned size, void *state)
 {
     struct pipe_framebuffer_state *fb =
         (struct pipe_framebuffer_state*)r300->fb_state.state;
-    struct r300_hyperz_state *z =
-        (struct r300_hyperz_state*)r300->hyperz_state.state;
     struct r300_resource* tex;
     CS_LOCALS(r300);
 
@@ -1042,10 +1040,9 @@ void r300_emit_hiz_clear(struct r300_context *r300, unsigned size, void *state)
     OUT_CS(0xffffffff);
     END_CS;
 
-    z->current_func = -1;
-
     /* Mark the current zbuffer's hiz ram as in use. */
     r300->hiz_in_use = TRUE;
+    r300->hiz_func = HIZ_FUNC_NONE;
     r300_mark_atom_dirty(r300, &r300->hyperz_state);
 }
 
index 7ff643f84dbcf7e2fa1ddf8ab8cd79183683ca44..8474839960f9089a34bb62fefdf3e41ee5c58766 100644 (file)
 /* The HyperZ setup                                                          */
 /*****************************************************************************/
 
-static bool r300_get_sc_hz_max(struct r300_context *r300)
+static enum r300_hiz_func r300_get_hiz_func(struct r300_context *r300)
 {
-    struct r300_dsa_state *dsa_state = r300->dsa_state.state;
-    int func = dsa_state->z_stencil_control & R300_ZS_MASK;
-    int ret = R300_SC_HYPERZ_MIN;
+    struct r300_dsa_state *dsa = r300->dsa_state.state;
 
-    if (func >= R300_ZS_GEQUAL && func <= R300_ZS_ALWAYS)
-       ret = R300_SC_HYPERZ_MAX;
-    return ret;
+    if (!dsa->dsa.depth.enabled || !dsa->dsa.depth.writemask)
+        return HIZ_FUNC_NONE;
+
+    switch (dsa->dsa.depth.func) {
+    case PIPE_FUNC_NEVER:
+    case PIPE_FUNC_EQUAL:
+    case PIPE_FUNC_NOTEQUAL:
+    case PIPE_FUNC_ALWAYS:
+        return HIZ_FUNC_NONE;
+
+    case PIPE_FUNC_LESS:
+    case PIPE_FUNC_LEQUAL:
+        return HIZ_FUNC_MAX;
+
+    case PIPE_FUNC_GREATER:
+    case PIPE_FUNC_GEQUAL:
+        return HIZ_FUNC_MIN;
+    }
 }
 
-static bool r300_zfunc_same_direction(int func1, int func2)
+/* Return what's used for the depth test (either minimum or maximum). */
+static unsigned r300_get_sc_hz_max(struct r300_context *r300)
 {
-    /* func1 is less/lessthan */
-    if ((func1 == R300_ZS_LESS || func1 == R300_ZS_LEQUAL) &&
-        (func2 == R300_ZS_EQUAL || func2 == R300_ZS_GEQUAL ||
-         func2 == R300_ZS_GREATER))
-            return FALSE;
+    struct r300_dsa_state *dsa = r300->dsa_state.state;
+    unsigned func = dsa->dsa.depth.func;
 
-    /* func1 is greater/greaterthan */
-    if ((func1 == R300_ZS_GEQUAL || func1 == R300_ZS_GREATER) &&
-        (func2 == R300_ZS_LESS || func2 == R300_ZS_LEQUAL))
-            return FALSE;
-
-    return TRUE;
+    return func >= PIPE_FUNC_GREATER ? R300_SC_HYPERZ_MAX : R300_SC_HYPERZ_MIN;
 }
 
-static int r300_get_hiz_min(struct r300_context *r300)
+static boolean r300_is_hiz_func_valid(struct r300_context *r300)
 {
-    struct r300_dsa_state *dsa_state = r300->dsa_state.state;
-    int func = dsa_state->z_stencil_control & R300_ZS_MASK;
-    int ret = R300_HIZ_MIN;
+    struct r300_dsa_state *dsa = r300->dsa_state.state;
+    unsigned func = dsa->dsa.depth.func;
+
+    if (r300->hiz_func == HIZ_FUNC_NONE)
+        return TRUE;
+
+    /* func1 is less/lessthan */
+    if (r300->hiz_func == HIZ_FUNC_MAX &&
+        (func == PIPE_FUNC_GEQUAL || func == PIPE_FUNC_GREATER))
+        return FALSE;
 
-    if (func == R300_ZS_LESS || func == R300_ZS_LEQUAL)
-       ret = R300_HIZ_MAX;
-    return ret;
+    /* func1 is greater/greaterthan */
+    if (r300->hiz_func == HIZ_FUNC_MIN &&
+        (func == PIPE_FUNC_LESS   || func == PIPE_FUNC_LEQUAL))
+        return FALSE;
+
+    return TRUE;
 }
 
 static boolean r300_dsa_stencil_op_not_keep(struct pipe_stencil_state *s)
 {
-    if (s->enabled && (s->fail_op != PIPE_STENCIL_OP_KEEP ||
-                       s->zfail_op != PIPE_STENCIL_OP_KEEP))
-        return TRUE;
-    return FALSE;
+    return s->enabled && (s->fail_op != PIPE_STENCIL_OP_KEEP ||
+                          s->zfail_op != PIPE_STENCIL_OP_KEEP);
 }
 
 static boolean r300_can_hiz(struct r300_context *r300)
 {
-    struct r300_dsa_state *dsa_state = r300->dsa_state.state;
-    struct pipe_depth_stencil_alpha_state *dsa = &dsa_state->dsa;
-    struct r300_screen* r300screen = r300->screen;
-    struct r300_hyperz_state *z = r300->hyperz_state.state;
+    struct r300_dsa_state *dsa = r300->dsa_state.state;
+    struct r300_screen *r300screen = r300->screen;
 
     /* shader writes depth - no HiZ */
     if (r300_fragment_shader_writes_depth(r300_fs(r300))) /* (5) */
@@ -101,33 +113,19 @@ static boolean r300_can_hiz(struct r300_context *r300)
         return FALSE;
 
     /* if stencil fail/zfail op is not KEEP */
-    if (r300_dsa_stencil_op_not_keep(&dsa->stencil[0]) ||
-        r300_dsa_stencil_op_not_keep(&dsa->stencil[1]))
+    if (r300_dsa_stencil_op_not_keep(&dsa->dsa.stencil[0]) ||
+        r300_dsa_stencil_op_not_keep(&dsa->dsa.stencil[1]))
         return FALSE;
 
-    if (dsa->depth.enabled) {
+    if (dsa->dsa.depth.enabled) {
         /* if depth func is EQUAL pre-r500 */
-        if (dsa->depth.func == PIPE_FUNC_EQUAL && !r300screen->caps.is_r500)
+        if (dsa->dsa.depth.func == PIPE_FUNC_EQUAL && !r300screen->caps.is_r500)
             return FALSE;
+
         /* if depth func is NOTEQUAL */
-        if (dsa->depth.func == PIPE_FUNC_NOTEQUAL)
+        if (dsa->dsa.depth.func == PIPE_FUNC_NOTEQUAL)
             return FALSE;
     }
-    /* depth comparison function - if just cleared save and return okay */
-    if (z->current_func == -1) {
-        int func = dsa_state->z_stencil_control & R300_ZS_MASK;
-        if (func != 0 && func != 7)
-            z->current_func = dsa_state->z_stencil_control & R300_ZS_MASK;
-    } else {
-        /* simple don't change */
-        if (!r300_zfunc_same_direction(z->current_func,
-                                       (dsa_state->z_stencil_control & R300_ZS_MASK))) {
-            DBG(r300, DBG_HYPERZ,
-                "z func changed direction - disabling hyper-z %d -> %d\n",
-                z->current_func, dsa_state->z_stencil_control);
-            return FALSE;
-        }
-    }
     return TRUE;
 }
 
@@ -150,10 +148,8 @@ static void r300_update_hyperz(struct r300_context* r300)
         return;
     }
 
-    if (!zstex)
-        return;
-
-    if (!r300->rws->get_value(r300->rws, R300_CAN_HYPERZ))
+    if (!zstex ||
+        !r300->rws->get_value(r300->rws, R300_CAN_HYPERZ))
         return;
 
     /* Zbuffer compression. */
@@ -171,17 +167,29 @@ static void r300_update_hyperz(struct r300_context* r300)
         z->gb_z_peq_config |= R300_GB_Z_PEQ_CONFIG_Z_PEQ_SIZE_8_8;
     }
 
-    /* XXX Use can_hiz to disable hyperz for good, instead of turning it off/on. */
-    if (r300->hiz_in_use && !r300->hyperz_locked && r300_can_hiz(r300)) {
-        z->zb_bw_cntl |= R300_HIZ_ENABLE |
-                         r300_get_hiz_min(r300);
-
-        z->sc_hyperz |= R300_SC_HYPERZ_ENABLE |
-                        r300_get_sc_hz_max(r300);
+    /* HiZ. */
+    if (r300->hiz_in_use && !r300->hyperz_locked) {
+        /* Set the HiZ function if needed. */
+        if (r300->hiz_func == HIZ_FUNC_NONE) {
+            r300->hiz_func = r300_get_hiz_func(r300);
+        }
 
-        if (r300->screen->caps.is_r500) {
-            z->zb_bw_cntl |= R500_HIZ_FP_EXP_BITS_3 |
-                             R500_HIZ_EQUAL_REJECT_ENABLE;
+        /* If the depth function is inverted, HiZ must be disabled. */
+        if (!r300_is_hiz_func_valid(r300)) {
+            r300->hiz_in_use = FALSE;
+        } else if (r300_can_hiz(r300)) {
+            /* Setup the HiZ bits. */
+            z->zb_bw_cntl |=
+                R300_HIZ_ENABLE |
+                (r300->hiz_func == HIZ_FUNC_MIN ? R300_HIZ_MIN : R300_HIZ_MAX);
+
+            z->sc_hyperz |= R300_SC_HYPERZ_ENABLE |
+                            r300_get_sc_hz_max(r300);
+
+            if (r300->screen->caps.is_r500) {
+                z->zb_bw_cntl |= R500_HIZ_FP_EXP_BITS_3 |
+                                 R500_HIZ_EQUAL_REJECT_ENABLE;
+            }
         }
     }