panfrost: Document MALI_WRITES_GLOBAL bit
[mesa.git] / src / gallium / drivers / freedreno / a6xx / fd6_zsa.c
index b7ce799eb4018d3ff089448fb28b497c1ea9977c..6aa63b2e89f3468ae802d6ecc5191e849db9387a 100644 (file)
 #include "fd6_context.h"
 #include "fd6_format.h"
 
+/* update lza state based on stencil/alpha-test func: */
+static void
+update_lrz_sa(struct fd6_zsa_stateobj *so, enum pipe_compare_func func)
+{
+       switch (func) {
+       case PIPE_FUNC_ALWAYS:
+               /* nothing to do for LRZ: */
+               break;
+       case PIPE_FUNC_NEVER:
+               /* fragment never passes, disable lrz_write for this draw: */
+               so->lrz_write = false;
+               break;
+       default:
+               /* whether the fragment passes or not depends on result
+                * of stencil test, which we cannot know when doing binning
+                * pass:
+                *
+                * TODO we maybe don't have to invalidate_lrz, depending on
+                * the depth/stencil func?  Ie. if there is an opaque surface
+                * behind what is currently being drawn, we could just disable
+                * lrz_write for a conservative but correct result?
+                */
+               so->invalidate_lrz = true;
+               so->lrz_write = false;
+               break;
+       }
+}
+
 void *
 fd6_zsa_state_create(struct pipe_context *pctx,
                const struct pipe_depth_stencil_alpha_state *cso)
 {
+       struct fd_context *ctx = fd_context(pctx);
        struct fd6_zsa_stateobj *so;
 
        so = CALLOC_STRUCT(fd6_zsa_stateobj);
@@ -46,40 +75,60 @@ fd6_zsa_state_create(struct pipe_context *pctx,
 
        so->base = *cso;
 
-       switch (cso->depth.func) {
-       case PIPE_FUNC_LESS:
-       case PIPE_FUNC_LEQUAL:
-               so->gras_lrz_cntl = A6XX_GRAS_LRZ_CNTL_ENABLE;
-               break;
-
-       case PIPE_FUNC_GREATER:
-       case PIPE_FUNC_GEQUAL:
-               so->gras_lrz_cntl = A6XX_GRAS_LRZ_CNTL_ENABLE | A6XX_GRAS_LRZ_CNTL_GREATER;
-               break;
-
-       default:
-               /* LRZ not enabled */
-               so->gras_lrz_cntl = 0;
-               break;
-       }
-
-       if (!(cso->stencil->enabled || cso->alpha.enabled || !cso->depth.writemask))
-               so->lrz_write = true;
-
        so->rb_depth_cntl |=
                A6XX_RB_DEPTH_CNTL_ZFUNC(cso->depth.func); /* maps 1:1 */
 
-       if (cso->depth.enabled)
+       if (cso->depth.enabled) {
                so->rb_depth_cntl |=
                        A6XX_RB_DEPTH_CNTL_Z_ENABLE |
                        A6XX_RB_DEPTH_CNTL_Z_TEST_ENABLE;
 
+               so->gras_lrz_cntl |= A6XX_GRAS_LRZ_CNTL_Z_TEST_ENABLE;
+
+               if (cso->depth.writemask) {
+                       so->lrz_write = true;
+               }
+
+               switch (cso->depth.func) {
+               case PIPE_FUNC_LESS:
+               case PIPE_FUNC_LEQUAL:
+                       so->gras_lrz_cntl |= A6XX_GRAS_LRZ_CNTL_ENABLE;
+                       so->rb_lrz_cntl |= A6XX_RB_LRZ_CNTL_ENABLE;
+                       break;
+
+               case PIPE_FUNC_GREATER:
+               case PIPE_FUNC_GEQUAL:
+                       so->gras_lrz_cntl |= A6XX_GRAS_LRZ_CNTL_ENABLE | A6XX_GRAS_LRZ_CNTL_GREATER;
+                       so->rb_lrz_cntl |= A6XX_RB_LRZ_CNTL_ENABLE;
+                       break;
+
+               case PIPE_FUNC_NEVER:
+                       so->gras_lrz_cntl |= A6XX_GRAS_LRZ_CNTL_ENABLE;
+                       so->rb_lrz_cntl |= A6XX_RB_LRZ_CNTL_ENABLE;
+                       so->lrz_write = false;
+                       break;
+
+               case PIPE_FUNC_EQUAL:
+               case PIPE_FUNC_NOTEQUAL:
+               case PIPE_FUNC_ALWAYS:
+                       so->lrz_write = false;
+                       so->invalidate_lrz = true;
+                       break;
+               }
+       }
+
        if (cso->depth.writemask)
                so->rb_depth_cntl |= A6XX_RB_DEPTH_CNTL_Z_WRITE_ENABLE;
 
        if (cso->stencil[0].enabled) {
                const struct pipe_stencil_state *s = &cso->stencil[0];
 
+               /* stencil test happens before depth test, so without performing
+                * stencil test we don't really know what the updates to the
+                * depth buffer will be.
+                */
+               update_lrz_sa(so, s->func);
+
                so->rb_stencil_control |=
                        A6XX_RB_STENCIL_CONTROL_STENCIL_READ |
                        A6XX_RB_STENCIL_CONTROL_STENCIL_ENABLE |
@@ -94,6 +143,8 @@ fd6_zsa_state_create(struct pipe_context *pctx,
                if (cso->stencil[1].enabled) {
                        const struct pipe_stencil_state *bs = &cso->stencil[1];
 
+                       update_lrz_sa(so, bs->func);
+
                        so->rb_stencil_control |=
                                A6XX_RB_STENCIL_CONTROL_STENCIL_ENABLE_BF |
                                A6XX_RB_STENCIL_CONTROL_FUNC_BF(bs->func) | /* maps 1:1 */
@@ -107,6 +158,12 @@ fd6_zsa_state_create(struct pipe_context *pctx,
        }
 
        if (cso->alpha.enabled) {
+               /* stencil test happens before depth test, so without performing
+                * stencil test we don't really know what the updates to the
+                * depth buffer will be.
+                */
+               update_lrz_sa(so, cso->alpha.func);
+
                uint32_t ref = cso->alpha.ref_value * 255.0;
                so->rb_alpha_control =
                        A6XX_RB_ALPHA_CONTROL_ALPHA_TEST |
@@ -116,5 +173,47 @@ fd6_zsa_state_create(struct pipe_context *pctx,
 //                     A6XX_RB_DEPTH_CONTROL_EARLY_Z_DISABLE;
        }
 
+       so->stateobj = fd_ringbuffer_new_object(ctx->pipe, 9 * 4);
+       struct fd_ringbuffer *ring = so->stateobj;
+
+       OUT_PKT4(ring, REG_A6XX_RB_ALPHA_CONTROL, 1);
+       OUT_RING(ring, so->rb_alpha_control);
+
+       OUT_PKT4(ring, REG_A6XX_RB_STENCIL_CONTROL, 1);
+       OUT_RING(ring, so->rb_stencil_control);
+
+       OUT_PKT4(ring, REG_A6XX_RB_DEPTH_CNTL, 1);
+       OUT_RING(ring, so->rb_depth_cntl);
+
+       OUT_PKT4(ring, REG_A6XX_RB_STENCILMASK, 2);
+       OUT_RING(ring, so->rb_stencilmask);
+       OUT_RING(ring, so->rb_stencilwrmask);
+
+       so->stateobj_no_alpha = fd_ringbuffer_new_object(ctx->pipe, 9 * 4);
+       ring = so->stateobj_no_alpha;
+
+       OUT_PKT4(ring, REG_A6XX_RB_ALPHA_CONTROL, 1);
+       OUT_RING(ring, so->rb_alpha_control & ~A6XX_RB_ALPHA_CONTROL_ALPHA_TEST);
+
+       OUT_PKT4(ring, REG_A6XX_RB_STENCIL_CONTROL, 1);
+       OUT_RING(ring, so->rb_stencil_control);
+
+       OUT_PKT4(ring, REG_A6XX_RB_DEPTH_CNTL, 1);
+       OUT_RING(ring, so->rb_depth_cntl);
+
+       OUT_PKT4(ring, REG_A6XX_RB_STENCILMASK, 2);
+       OUT_RING(ring, so->rb_stencilmask);
+       OUT_RING(ring, so->rb_stencilwrmask);
+
        return so;
 }
+
+void
+fd6_depth_stencil_alpha_state_delete(struct pipe_context *pctx, void *hwcso)
+{
+       struct fd6_zsa_stateobj *so = hwcso;
+
+       fd_ringbuffer_del(so->stateobj);
+       fd_ringbuffer_del(so->stateobj_no_alpha);
+       FREE(hwcso);
+}