Mesa (main): panfrost: Add decoupled early-ZS helpers

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Jul 13 21:19:30 UTC 2022


Module: Mesa
Branch: main
Commit: e96292bc072b61c4ab33e654437773909177ab6d
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=e96292bc072b61c4ab33e654437773909177ab6d

Author: Alyssa Rosenzweig <alyssa at collabora.com>
Date:   Fri Jun 10 15:28:35 2022 -0400

panfrost: Add decoupled early-ZS helpers

Bifrost (and Valhall) separate early-ZS configuration into two fields: when does
the depth/stencil buffer update happen? and when are pixels killed by the
depth/stencil tests? The driver separately configures these to occur early
(before the shader executes) or late (after the ATEST instruction executes at
the end of the shader). Early tests are generally more efficient, but various
combinations of API state and fragment shader properties can require late
updates and/or late kills for correctness. Determining how to configure these
fields is nontrivial.

Our current implementation (on Bifrost) configures these fields at fragment
shader compile time and bakes the settings into the RSD. This is both wrong
(using early testing when late testing is required) and suboptimal (using late
testing when early testing would suffice). We need to defer this configuration
until draw time, when we know rasterizer and Z/S state.

Reclassifying at draw time (as we currently do on Valhall) would be expensive,
especially with the extra terms added in here. To cope, decouple the shader
classification from the draw-time configuration. Since there are only a few bits
of draw state involved, this implementation just calculates all possible states.
Then the draw time classification is just indexing into a lookup table.

The actual algorithm used to classify is written with correctness and clarity in
mind. Unlike the current classification algorithm (which tries to match what the
DDK does, poorly), this algorithm embeds its proofs of correctness.

Signed-off-by: Alyssa Rosenzweig <alyssa at collabora.com>
Cc: mesa-stable
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17428>

---

 src/panfrost/lib/meson.build   |   1 +
 src/panfrost/lib/pan_earlyzs.c | 119 +++++++++++++++++++++++++++++++++++++++++
 src/panfrost/lib/pan_earlyzs.h |  80 +++++++++++++++++++++++++++
 3 files changed, 200 insertions(+)

diff --git a/src/panfrost/lib/meson.build b/src/panfrost/lib/meson.build
index d77573d8e3b..c21b2d5e8f8 100644
--- a/src/panfrost/lib/meson.build
+++ b/src/panfrost/lib/meson.build
@@ -78,6 +78,7 @@ libpanfrost_lib_files = files(
   'pan_bo.c',
   'pan_blend.c',
   'pan_clear.c',
+  'pan_earlyzs.c',
   'pan_samples.c',
   'pan_tiler.c',
   'pan_layout.c',
diff --git a/src/panfrost/lib/pan_earlyzs.c b/src/panfrost/lib/pan_earlyzs.c
new file mode 100644
index 00000000000..1f9abecfc24
--- /dev/null
+++ b/src/panfrost/lib/pan_earlyzs.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2022 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "pan_earlyzs.h"
+#include "panfrost/util/pan_ir.h"
+
+/*
+ * Return an "early" mode. If it is known that the depth/stencil tests always
+ * pass (so the shader is always executed), weak early is usually faster than
+ * force early.
+ */
+static enum pan_earlyzs
+best_early_mode(bool zs_always_passes)
+{
+        if (zs_always_passes)
+                return PAN_EARLYZS_WEAK_EARLY;
+        else
+                return PAN_EARLYZS_FORCE_EARLY;
+}
+
+/*
+ * Analyze a fragment shader and provided API state to determine the early-ZS
+ * configuration. The order of arguments must match the order of states in the
+ * lookup table, synchronized with pan_earlyzs_get.
+ */
+static struct pan_earlyzs_state
+analyze(const struct pan_shader_info *s,
+        bool writes_zs_or_oq,
+        bool alpha_to_coverage,
+        bool zs_always_passes)
+{
+        /* If the shader writes depth or stencil, all depth/stencil tests must
+         * be deferred until the value is known after the ZS_EMIT instruction,
+         * if present. ZS_EMIT must precede ATEST, so the value is known when
+         * ATEST executes, justifying the late test/update.
+         */
+        bool shader_writes_zs = (s->fs.writes_depth || s->fs.writes_stencil);
+        bool late_update = shader_writes_zs;
+        bool late_kill = shader_writes_zs;
+
+        /* Late coverage updates are required if the coverage mask depends on
+         * the results of the shader. Discards are implemented as coverage mask
+         * updates and must be considered. Strictly, depth/stencil writes may
+         * also update the coverage mask, but these already force late updates.
+         */
+        bool late_coverage = s->fs.writes_coverage ||
+                             s->fs.can_discard ||
+                             alpha_to_coverage;
+
+        /* Late coverage mask updates may affect the value written to the
+         * depth/stencil buffer (if a pixel is discarded entirely). However,
+         * they do not affect depth/stencil testing. So they may only matter if
+         * depth or stencil is written.
+         *
+         * That dependency does mean late coverage mask updates require late
+         * depth/stencil updates.
+         *
+         * Similarly, occlusion queries count samples that pass the
+         * depth/stencil tests, so occlusion queries with late coverage also
+         * require a late update.
+         */
+        late_update |= (late_coverage && writes_zs_or_oq);
+
+        /* Side effects require late depth/stencil tests to ensure the shader
+         * isn't killed before the side effects execute.
+         */
+        late_kill |= s->writes_global;
+
+        /* Finally, the shader may override and force early fragment tests */
+        late_update &= !s->fs.early_fragment_tests;
+        late_kill   &= !s->fs.early_fragment_tests;
+
+        /* Collect results */
+        enum pan_earlyzs early_mode = best_early_mode(zs_always_passes);
+
+        return (struct pan_earlyzs_state) {
+                .update = late_update ? PAN_EARLYZS_FORCE_LATE : early_mode,
+                .kill   = late_kill   ? PAN_EARLYZS_FORCE_LATE : early_mode
+        };
+}
+
+/*
+ * Analyze a fragment shader to determine all possible early-ZS configurations.
+ * Returns a lookup table of configurations indexed by the API state.
+ */
+struct pan_earlyzs_lut
+pan_earlyzs_analyze(const struct pan_shader_info *s)
+{
+        struct pan_earlyzs_lut lut;
+
+        for (unsigned v0 = 0; v0 < 2; ++v0) {
+                for (unsigned v1 = 0; v1 < 2; ++v1) {
+                        for (unsigned v2 = 0; v2 < 2; ++v2)
+                                lut.states[v0][v1][v2] = analyze(s, v0, v1, v2);
+                }
+        }
+
+        return lut;
+}
diff --git a/src/panfrost/lib/pan_earlyzs.h b/src/panfrost/lib/pan_earlyzs.h
new file mode 100644
index 00000000000..f0a0af496c9
--- /dev/null
+++ b/src/panfrost/lib/pan_earlyzs.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __PAN_EARLYZS_H__
+#define __PAN_EARLYZS_H__
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Matches hardware Pixel Kill enum on Bifrost and Valhall */
+enum pan_earlyzs {
+        PAN_EARLYZS_FORCE_EARLY = 0,
+        PAN_EARLYZS_WEAK_EARLY = 2,
+        PAN_EARLYZS_FORCE_LATE = 3
+};
+
+/* Early-ZS pair. */
+struct pan_earlyzs_state {
+        /* Z/S test and update */
+        enum pan_earlyzs update : 2;
+
+        /* Pixel kill */
+        enum pan_earlyzs kill : 2;
+
+        /* So it fits in a byte */
+        unsigned padding : 4;
+};
+
+/* Internal lookup table. Users should treat as an opaque structure and only
+ * access through pan_earlyzs_get and pan_earlyzs_analyze. See pan_earlyzs_get
+ * for definition of the arrays.
+ */
+struct pan_earlyzs_lut {
+        struct pan_earlyzs_state states[2][2][2];
+};
+
+/*
+ * Look up early-ZS state. This is in the draw hot path on Valhall, so this is
+ * defined inline in the header.
+ */
+static inline struct pan_earlyzs_state
+pan_earlyzs_get(struct pan_earlyzs_lut lut,
+                bool writes_zs_or_oq, bool alpha_to_coverage,
+                bool zs_always_passes)
+{
+        return lut.states[writes_zs_or_oq][alpha_to_coverage][zs_always_passes];
+}
+
+struct pan_shader_info;
+
+struct pan_earlyzs_lut pan_earlyzs_analyze(const struct pan_shader_info *s);
+
+#ifdef __cplusplus
+} /* extern C */
+#endif
+
+#endif



More information about the mesa-commit mailing list