From 9c00ce93661566c3ed25967fe0f0e9197e9d48d2 Mon Sep 17 00:00:00 2001 From: goldislead <69987043+goldislead@users.noreply.github.com> Date: Fri, 3 Apr 2026 22:17:43 -0700 Subject: [PATCH] [GPU] EVENT_WRITE_ZPD batched sample accumulation cvar --- src/xenia/gpu/gpu_flags.cc | 5 +++++ src/xenia/gpu/gpu_flags.h | 2 ++ src/xenia/gpu/pm4_command_processor_implement.h | 15 ++++++++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/xenia/gpu/gpu_flags.cc b/src/xenia/gpu/gpu_flags.cc index 8f99e4e06..9ed9335fa 100644 --- a/src/xenia/gpu/gpu_flags.cc +++ b/src/xenia/gpu/gpu_flags.cc @@ -59,6 +59,11 @@ DEFINE_bool( "when MSAA is used with fullscreen passes.", "GPU"); +DEFINE_bool(query_occlusion_batched, false, + "Increment the sample count total by a fixed amount on every " + "EVENT_WRITE_ZPD. This provides an approximate batched occlusion " + "query implementation for many titles.", + "GPU"); DEFINE_int32(query_occlusion_sample_lower_threshold, 80, "If set to -1 no sample counts are written, games may hang. Else, " "the sample count of every tile will be incremented on every " diff --git a/src/xenia/gpu/gpu_flags.h b/src/xenia/gpu/gpu_flags.h index 5dbc34f09..1778371eb 100644 --- a/src/xenia/gpu/gpu_flags.h +++ b/src/xenia/gpu/gpu_flags.h @@ -26,6 +26,8 @@ DECLARE_bool(non_seamless_cube_map); DECLARE_bool(half_pixel_offset); +DECLARE_bool(query_occlusion_batched); + DECLARE_int32(query_occlusion_sample_lower_threshold); DECLARE_int32(query_occlusion_sample_upper_threshold); diff --git a/src/xenia/gpu/pm4_command_processor_implement.h b/src/xenia/gpu/pm4_command_processor_implement.h index 0072ecc7e..1302e13ab 100644 --- a/src/xenia/gpu/pm4_command_processor_implement.h +++ b/src/xenia/gpu/pm4_command_processor_implement.h @@ -955,6 +955,7 @@ bool COMMAND_PROCESSOR::ExecutePacketType3_EVENT_WRITE_EXT( } static uint32_t samples = cvars::query_occlusion_sample_upper_threshold; +static uint32_t batched_samples = 0; XE_NOINLINE bool COMMAND_PROCESSOR::ExecutePacketType3_EVENT_WRITE_ZPD( @@ -982,7 +983,19 @@ bool COMMAND_PROCESSOR::ExecutePacketType3_EVENT_WRITE_ZPD( bool is_end_via_z_fail = pSampleCounts->ZFail_A == kQueryFinished && pSampleCounts->ZFail_B == kQueryFinished; std::memset(pSampleCounts, 0, sizeof(xe_gpu_depth_sample_counts)); - if (is_end_via_z_pass || is_end_via_z_fail) { + + // Titles that use QueryBatch (4D5309B1, 4E4D0801) don't use an END result for + // every query. Each ISSUE snapshots the sample count into a new slot and + // recovers the total by looking at differences between slots. + // END detection isn't sufficient here. + if (cvars::query_occlusion_batched) { + // Mimic batched behavior by reporting a running count and writing it on + // every event. + const uint32_t step = std::max(uint32_t(1), samples); + batched_samples = std::min(batched_samples, UINT32_MAX - step) + step; + pSampleCounts->ZPass_A = batched_samples; + pSampleCounts->Total_A = batched_samples; + } else if (is_end_via_z_pass || is_end_via_z_fail) { pSampleCounts->ZPass_A = samples; pSampleCounts->Total_A = samples; }