diff --git a/src/gallium/drivers/panfrost/pan_cmdstream.c b/src/gallium/drivers/panfrost/pan_cmdstream.c index ce5d9ac93e1..7e4ec15fcbe 100644 --- a/src/gallium/drivers/panfrost/pan_cmdstream.c +++ b/src/gallium/drivers/panfrost/pan_cmdstream.c @@ -70,6 +70,9 @@ struct panfrost_zsa_state { */ bool zs_always_passes; + /* Are depth or stencil writes possible? */ + bool writes_zs; + #if PAN_ARCH <= 7 /* Prepacked words from the RSD */ struct mali_multisample_misc_packed rsd_depth; @@ -526,9 +529,21 @@ panfrost_prepare_fs_state(struct panfrost_context *ctx, for (unsigned c = 0; c < rt_count; ++c) has_blend_shader |= (blend_shaders[c] != 0); + bool has_oq = ctx->occlusion_query && ctx->active_queries; + pan_pack(rsd, RENDERER_STATE, cfg) { if (panfrost_fs_required(fs, so, &ctx->pipe_framebuffer, zsa)) { #if PAN_ARCH >= 6 + struct pan_earlyzs_state earlyzs = + pan_earlyzs_get(fs->earlyzs, + ctx->depth_stencil->writes_zs || + has_oq, + ctx->blend->base.alpha_to_coverage, + ctx->depth_stencil->zs_always_passes); + + cfg.properties.pixel_kill_operation = earlyzs.kill; + cfg.properties.zs_update_operation = earlyzs.update; + cfg.properties.allow_forward_pixel_to_kill = pan_allow_forward_pixel_to_kill(ctx, fs); #else @@ -544,7 +559,6 @@ panfrost_prepare_fs_state(struct panfrost_context *ctx, /* Hardware quirks around early-zs forcing without a * depth buffer. Note this breaks occlusion queries. */ - bool has_oq = ctx->occlusion_query && ctx->active_queries; bool force_ez_with_discard = !zsa->enabled && !has_oq; cfg.properties.shader_reads_tilebuffer = @@ -3326,9 +3340,16 @@ panfrost_emit_draw(void *out, cfg.depth_stencil = batch->depth_stencil; if (fs_required) { - struct pan_pixel_kill kill = pan_shader_classify_pixel_kill_coverage(&fs->info); - cfg.pixel_kill_operation = kill.pixel_kill; - cfg.zs_update_operation = kill.zs_update; + bool has_oq = ctx->occlusion_query && ctx->active_queries; + + struct pan_earlyzs_state earlyzs = + pan_earlyzs_get(fs->earlyzs, + ctx->depth_stencil->writes_zs || has_oq, + ctx->blend->base.alpha_to_coverage, + ctx->depth_stencil->zs_always_passes); + + cfg.pixel_kill_operation = earlyzs.kill; + cfg.zs_update_operation = earlyzs.update; cfg.allow_forward_pixel_to_kill = pan_allow_forward_pixel_to_kill(ctx, fs); cfg.allow_forward_pixel_to_be_killed = !fs->info.writes_global; @@ -4449,6 +4470,7 @@ panfrost_create_depth_stencil_state(struct pipe_context *pipe, (zsa->depth_enabled && zsa->depth_func != PIPE_FUNC_ALWAYS); so->zs_always_passes = pipe_zs_always_passes(zsa); + so->writes_zs = util_writes_depth_stencil(zsa); /* TODO: Bounds test should be easy */ assert(!zsa->depth_bounds_test); diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c index d17455aa908..25c053f57b2 100644 --- a/src/gallium/drivers/panfrost/pan_context.c +++ b/src/gallium/drivers/panfrost/pan_context.c @@ -510,6 +510,8 @@ panfrost_new_variant_locked( update_so_info(&shader_state->stream_output, shader_state->info.outputs_written); + shader_state->earlyzs = pan_earlyzs_analyze(&shader_state->info); + return variant; } diff --git a/src/gallium/drivers/panfrost/pan_context.h b/src/gallium/drivers/panfrost/pan_context.h index 77933d7a4a4..870258e3594 100644 --- a/src/gallium/drivers/panfrost/pan_context.h +++ b/src/gallium/drivers/panfrost/pan_context.h @@ -33,6 +33,7 @@ #include "pan_blend_cso.h" #include "pan_encoder.h" #include "pan_texture.h" +#include "pan_earlyzs.h" #include "pipe/p_compiler.h" #include "pipe/p_config.h" @@ -290,6 +291,8 @@ struct panfrost_shader_state { struct pan_shader_info info; + struct pan_earlyzs_lut earlyzs; + /* Attached transform feedback program, if one exists */ struct panfrost_shader_state *xfb; diff --git a/src/panfrost/lib/pan_blitter.c b/src/panfrost/lib/pan_blitter.c index 287969521f4..03b5cba95b1 100644 --- a/src/panfrost/lib/pan_blitter.c +++ b/src/panfrost/lib/pan_blitter.c @@ -259,8 +259,14 @@ pan_blitter_emit_rsd(const struct panfrost_device *dev, cfg.stencil_back = cfg.stencil_front; #if PAN_ARCH >= 6 - /* Skipping ATEST requires forcing Z/S */ - if (!zs) { + if (zs) { + /* Writing Z/S requires late updates */ + cfg.properties.zs_update_operation = + MALI_PIXEL_KILL_FORCE_LATE; + cfg.properties.pixel_kill_operation = + MALI_PIXEL_KILL_FORCE_LATE; + } else { + /* Skipping ATEST requires forcing Z/S */ cfg.properties.zs_update_operation = MALI_PIXEL_KILL_STRONG_EARLY; cfg.properties.pixel_kill_operation = diff --git a/src/panfrost/lib/pan_shader.h b/src/panfrost/lib/pan_shader.h index 11770e74cad..dce72e5cba0 100644 --- a/src/panfrost/lib/pan_shader.h +++ b/src/panfrost/lib/pan_shader.h @@ -68,54 +68,6 @@ pan_register_allocation(unsigned work_reg_count) } #endif -#if PAN_ARCH >= 6 -/* Classify a shader into the following pixel kill categories: - * - * (force early, strong early): no side effects/depth/stencil/coverage writes (force) - * (weak early, weak early): no side effects/depth/stencil/coverage writes - * (weak early, force late): no side effects/depth/stencil writes - * (force late, weak early): side effects but no depth/stencil/coverage writes - * (force late, force early): only run for side effects - * (force late, force late): depth/stencil writes - * - * Note that discard is considered a coverage write. TODO: what about - * alpha-to-coverage? - * */ - -struct pan_pixel_kill { - enum mali_pixel_kill pixel_kill; - enum mali_pixel_kill zs_update; -}; - -#define RETURN_PIXEL_KILL(kill, update) return (struct pan_pixel_kill) { \ - MALI_PIXEL_KILL_## kill, MALI_PIXEL_KILL_## update \ -} - -static inline struct pan_pixel_kill -pan_shader_classify_pixel_kill_coverage(const struct pan_shader_info *info) -{ - bool force_early = info->fs.early_fragment_tests; - bool sidefx = info->writes_global; - bool coverage = info->fs.writes_coverage || info->fs.can_discard; - bool depth = info->fs.writes_depth; - bool stencil = info->fs.writes_stencil; - - if (force_early) - RETURN_PIXEL_KILL(FORCE_EARLY, STRONG_EARLY); - else if (depth || stencil || (sidefx && coverage)) - RETURN_PIXEL_KILL(FORCE_LATE, FORCE_LATE); - else if (sidefx) - RETURN_PIXEL_KILL(FORCE_LATE, WEAK_EARLY); - else if (coverage) - RETURN_PIXEL_KILL(WEAK_EARLY, FORCE_LATE); - else - RETURN_PIXEL_KILL(WEAK_EARLY, WEAK_EARLY); -} - -#undef RETURN_PIXEL_KILL - -#endif - static inline enum mali_depth_source pan_depth_source(const struct pan_shader_info *info) { @@ -229,11 +181,6 @@ pan_shader_prepare_bifrost_rsd(const struct pan_shader_info *info, pan_make_preload(info->stage, info->preload, &rsd->preload); if (info->stage == MESA_SHADER_FRAGMENT) { - struct pan_pixel_kill kill = pan_shader_classify_pixel_kill_coverage(info); - - rsd->properties.pixel_kill_operation = kill.pixel_kill; - rsd->properties.zs_update_operation = kill.zs_update; - rsd->properties.shader_modifies_coverage = info->fs.writes_coverage || info->fs.can_discard; diff --git a/src/panfrost/vulkan/panvk_vX_cs.c b/src/panfrost/vulkan/panvk_vX_cs.c index 15068f68073..f10feaf2731 100644 --- a/src/panfrost/vulkan/panvk_vX_cs.c +++ b/src/panfrost/vulkan/panvk_vX_cs.c @@ -32,6 +32,7 @@ #include "pan_encoder.h" #include "pan_pool.h" #include "pan_shader.h" +#include "pan_earlyzs.h" #include "panvk_cs.h" #include "panvk_private.h" @@ -722,6 +723,17 @@ panvk_per_arch(emit_base_fs_rsd)(const struct panvk_device *dev, !(rt_mask & ~rt_written) && !pipeline->ms.alpha_to_coverage && !pipeline->blend.reads_dest; + + bool writes_zs = pipeline->zs.z_write || pipeline->zs.s_test; + bool zs_always_passes = !pipeline->zs.z_test && !pipeline->zs.s_test; + bool oq = false; /* TODO: Occlusion queries */ + + struct pan_earlyzs_state earlyzs = + pan_earlyzs_get(pan_earlyzs_analyze(info), writes_zs || oq, + pipeline->ms.alpha_to_coverage, zs_always_passes); + + cfg.properties.pixel_kill_operation = earlyzs.kill; + cfg.properties.zs_update_operation = earlyzs.update; } else { cfg.properties.depth_source = MALI_DEPTH_SOURCE_FIXED_FUNCTION; cfg.properties.allow_forward_pixel_to_kill = true;