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 + +#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