v3d: disable early-Z on odd frame dimensions
authorJuan A. Suarez Romero <jasuarez@igalia.com>
Tue, 19 Apr 2022 14:53:20 +0000 (16:53 +0200)
committerMarge Bot <emma+marge@anholt.net>
Wed, 4 May 2022 07:44:46 +0000 (07:44 +0000)
The early-Z buffer may load incorrect depth values if the frame has an
od width or height. In this case we need to disable early-Z.

v3:
 - Set job->early_zs_clear only for V3D_VERSION >= 40 (Iago)
 - Check early-Z is disabled if no zsbuf (Iago)

v4:
 - Borrow comments from v3dv around v3d_update_job_ez() (Iago)

Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/3557
Signed-off-by: Juan A. Suarez Romero <jasuarez@igalia.com>
Reviewed-by: Iago Toral Quiroga <itoral@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16166>

src/gallium/drivers/v3d/v3d_context.h
src/gallium/drivers/v3d/v3dx_draw.c
src/gallium/drivers/v3d/v3dx_rcl.c

index 5bfe53e..5ba8727 100644 (file)
@@ -471,6 +471,12 @@ struct v3d_job {
         enum v3d_ez_state first_ez_state;
 
         /**
+         * If we have already decided if we need to disable early Z/S
+         * completely for this job.
+         */
+        bool decided_global_ez_enable;
+
+        /**
          * If this job has been configured to use early Z/S clear.
          */
         bool early_zs_clear;
index 80842b4..a3bc119 100644 (file)
@@ -852,6 +852,49 @@ v3d_update_primitives_generated_counter(struct v3d_context *v3d,
 static void
 v3d_update_job_ez(struct v3d_context *v3d, struct v3d_job *job)
 {
+        /* If first_ez_state is V3D_EZ_DISABLED it means that we have already
+         * determined that we should disable EZ completely for all draw calls
+         * in this job. This will cause us to disable EZ for the entire job in
+         * the Tile Rendering Mode RCL packet and when we do that we need to
+         * make sure we never emit a draw call in the job with EZ enabled in
+         * the CFG_BITS packet, so ez_state must also be V3D_EZ_DISABLED.
+         */
+        if (job->first_ez_state == V3D_EZ_DISABLED) {
+                assert(job->ez_state == V3D_EZ_DISABLED);
+                return;
+        }
+
+        /* If this is the first time we update EZ state for this job we first
+         * check if there is anything that requires disabling it completely
+         * for the entire job (based on state that is not related to the
+         * current draw call and pipeline state).
+         */
+        if (!job->decided_global_ez_enable) {
+                job->decided_global_ez_enable = true;
+
+                if (!job->zsbuf) {
+                        job->first_ez_state = V3D_EZ_DISABLED;
+                        job->ez_state = V3D_EZ_DISABLED;
+                        return;
+                }
+
+                /* GFXH-1918: the early-Z buffer may load incorrect depth
+                 * values if the frame has odd width or height. Disable early-Z
+                 * in this case.
+                 */
+                bool needs_depth_load = v3d->zsa && job->zsbuf &&
+                        v3d->zsa->base.depth_enabled &&
+                        (PIPE_CLEAR_DEPTH & ~job->clear);
+                if (needs_depth_load &&
+                     ((job->draw_width % 2 != 0) || (job->draw_height % 2 != 0))) {
+                        perf_debug("Loading depth buffer for framebuffer with odd width "
+                                   "or height disables early-Z tests\n");
+                        job->first_ez_state = V3D_EZ_DISABLED;
+                        job->ez_state = V3D_EZ_DISABLED;
+                        return;
+                }
+        }
+
         switch (v3d->zsa->ez_state) {
         case V3D_EZ_UNDECIDED:
                 /* If the Z/S state didn't pick a direction but didn't
index 7c85525..6147d6a 100644 (file)
@@ -726,6 +726,31 @@ v3dX(emit_rcl)(struct v3d_job *job)
                         struct v3d_surface *surf = v3d_surface(job->zsbuf);
                         config.internal_depth_type = surf->internal_type;
                 }
+#endif /* V3D_VERSION >= 40 */
+
+                if (job->decided_global_ez_enable) {
+                        switch (job->first_ez_state) {
+                        case V3D_EZ_UNDECIDED:
+                        case V3D_EZ_LT_LE:
+                                config.early_z_disable = false;
+                                config.early_z_test_and_update_direction =
+                                        EARLY_Z_DIRECTION_LT_LE;
+                                break;
+                        case V3D_EZ_GT_GE:
+                                config.early_z_disable = false;
+                                config.early_z_test_and_update_direction =
+                                        EARLY_Z_DIRECTION_GT_GE;
+                                break;
+                        case V3D_EZ_DISABLED:
+                                config.early_z_disable = true;
+                        }
+                } else {
+                        assert(job->draw_calls_queued == 0);
+                        config.early_z_disable = true;
+                }
+
+#if V3D_VERSION >= 40
+                assert(job->zsbuf || config.early_z_disable);
 
                 job->early_zs_clear = (job->clear & PIPE_CLEAR_DEPTHSTENCIL) &&
                         !(job->load & PIPE_CLEAR_DEPTHSTENCIL) &&
@@ -734,22 +759,6 @@ v3dX(emit_rcl)(struct v3d_job *job)
                 config.early_depth_stencil_clear = job->early_zs_clear;
 #endif /* V3D_VERSION >= 40 */
 
-                switch (job->first_ez_state) {
-                case V3D_EZ_UNDECIDED:
-                case V3D_EZ_LT_LE:
-                        config.early_z_disable = false;
-                        config.early_z_test_and_update_direction =
-                                EARLY_Z_DIRECTION_LT_LE;
-                        break;
-                case V3D_EZ_GT_GE:
-                        config.early_z_disable = false;
-                        config.early_z_test_and_update_direction =
-                                EARLY_Z_DIRECTION_GT_GE;
-                        break;
-                case V3D_EZ_DISABLED:
-                        config.early_z_disable = true;
-                }
-
                 config.image_width_pixels = job->draw_width;
                 config.image_height_pixels = job->draw_height;