From 6e9392fb4519fbbaa9e41d90c451d976ab306f83 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sat, 22 Feb 2020 18:19:16 +0300 Subject: [PATCH] rsx: Restructure ZCULL query triggers - Both ZCULL stats and ZPASS stats require hardware queries, but ZCULL stats should not contribute to ZPASS stats and vice versa! - Disables hardware queries for ZCULL stats by themselves, we cannot generate them correctly anyway and no game so far has been found to actually use them. Should lessen the load on the backend for games that do not actually require it. --- rpcs3/Emu/RSX/RSXThread.cpp | 112 +++++++++++++++++++++++++----------- rpcs3/Emu/RSX/RSXThread.h | 42 +++++++++----- 2 files changed, 108 insertions(+), 46 deletions(-) diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 22c98823b5..741d760b8a 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -422,8 +422,7 @@ namespace rsx element_push_buffer.clear(); - if (zcull_ctrl->active) - zcull_ctrl->on_draw(); + zcull_ctrl->on_draw(); if (capture_current_frame) { @@ -2122,8 +2121,6 @@ namespace rsx if (g_cfg.video.disable_zcull_queries) return; - bool testing_enabled = zcull_pixel_cnt_enabled || zcull_stats_enabled; - if (framebuffer_swap) { zcull_surface_active = false; @@ -2148,7 +2145,7 @@ namespace rsx } zcull_ctrl->set_enabled(this, zcull_rendering_enabled); - zcull_ctrl->set_active(this, zcull_rendering_enabled && testing_enabled && zcull_surface_active); + zcull_ctrl->set_status(this, zcull_surface_active, zcull_pixel_cnt_enabled, zcull_stats_enabled); } void thread::clear_zcull_stats(u32 type) @@ -2564,12 +2561,6 @@ namespace rsx Emu.Pause(); } - // Reset ZCULL ctrl - // NOTE: A semaphore release is part of RSX flip control and will handle ZCULL sync - // TODO: These routines belong in the state reset routines controlled by sys_rsx and cellGcmSetFlip - zcull_ctrl->set_active(this, false, true); - zcull_ctrl->clear(this); - // Save current state m_queued_flip.stats = m_frame_stats; m_queued_flip.push(buffer); @@ -2728,26 +2719,15 @@ namespace rsx ZCULL_control::~ZCULL_control() {} - void ZCULL_control::set_enabled(class ::rsx::thread* ptimer, bool state, bool flush_queue) - { - if (state != enabled) - { - enabled = state; - - if (active && !enabled) - set_active(ptimer, false, flush_queue); - } - } - void ZCULL_control::set_active(class ::rsx::thread* ptimer, bool state, bool flush_queue) { - if (state != active) + if (state != host_queries_active) { - active = state; + host_queries_active = state; if (state) { - verify(HERE), enabled && m_current_task == nullptr; + verify(HERE), unit_enabled && m_current_task == nullptr; allocate_new_query(ptimer); begin_occlusion_query(m_current_task); } @@ -2779,6 +2759,58 @@ namespace rsx } } + void ZCULL_control::check_state(class ::rsx::thread* ptimer, bool flush_queue) + { + // NOTE: Only enable host queries if pixel count is active to save on resources + // Can optionally be enabled for either stats enabled or zpass enabled for accuracy + const bool data_stream_available = write_enabled && (zpass_count_enabled /*|| stats_enabled*/); + if (host_queries_active && !data_stream_available) + { + // Stop + set_active(ptimer, false, flush_queue); + } + else if (!host_queries_active && data_stream_available && unit_enabled) + { + // Start + set_active(ptimer, true, flush_queue); + } + } + + void ZCULL_control::set_enabled(class ::rsx::thread* ptimer, bool state, bool flush_queue) + { + if (state != unit_enabled) + { + unit_enabled = state; + check_state(ptimer, flush_queue); + } + } + + void ZCULL_control::set_status(class ::rsx::thread* ptimer, bool surface_active, bool zpass_active, bool zcull_stats_active, bool flush_queue) + { + write_enabled = surface_active; + zpass_count_enabled = zpass_active; + stats_enabled = zcull_stats_active; + + check_state(ptimer, flush_queue); + + if (m_current_task && m_current_task->active) + { + // Data check + u32 expected_type = 0; + if (zpass_active) expected_type |= CELL_GCM_ZPASS_PIXEL_CNT; + if (zcull_stats_active) expected_type |= CELL_GCM_ZCULL_STATS; + + if (m_current_task->data_type != expected_type) [[unlikely]] + { + rsx_log.error("ZCULL queue interrupted by data type change!"); + + // Stop+start the current setup + set_active(ptimer, false, false); + set_active(ptimer, true, false); + } + } + } + void ZCULL_control::read_report(::rsx::thread* ptimer, vm::addr_t sink, u32 type) { if (m_current_task && type == CELL_GCM_ZPASS_PIXEL_CNT) @@ -2855,12 +2887,18 @@ namespace rsx m_current_task = m_free_occlusion_pool.top(); m_free_occlusion_pool.pop(); + m_current_task->data_type = 0; m_current_task->num_draws = 0; m_current_task->result = 0; m_current_task->active = true; m_current_task->owned = false; m_current_task->sync_tag = 0; m_current_task->timestamp = 0; + + // Flags determine what kind of payload is carried by queries in the 'report' + if (zpass_count_enabled) m_current_task->data_type |= CELL_GCM_ZPASS_PIXEL_CNT; + if (stats_enabled) m_current_task->data_type |= CELL_GCM_ZCULL_STATS; + return; } @@ -2988,7 +3026,7 @@ namespace rsx u32 processed = 0; const bool has_unclaimed = (m_pending_writes.back().sink == 0); - //Write all claimed reports unconditionally + // Write all claimed reports unconditionally for (auto &writer : m_pending_writes) { if (!writer.sink) @@ -3009,7 +3047,10 @@ namespace rsx if (query->result) { result += query->result; - m_statistics_map[writer.counter_tag] = result; + if (query->data_type & CELL_GCM_ZPASS_PIXEL_CNT) + { + m_statistics_map[writer.counter_tag] += query->result; + } } } else @@ -3024,7 +3065,8 @@ namespace rsx if (!writer.forwarder) { // No other queries in the chain, write result - write(&writer, ptimer->timestamp(), result); + const auto value = (writer.type == CELL_GCM_ZPASS_PIXEL_CNT) ? m_statistics_map[writer.counter_tag] : result; + write(&writer, ptimer->timestamp(), value); if (query && query->sync_tag == ptimer->cond_render_ctrl.eval_sync_tag) { @@ -3171,7 +3213,10 @@ namespace rsx if (query->result) { result += query->result; - m_statistics_map[writer.counter_tag] = result; + if (query->data_type & CELL_GCM_ZPASS_PIXEL_CNT) + { + m_statistics_map[writer.counter_tag] += query->result; + } } } else @@ -3191,7 +3236,10 @@ namespace rsx if (query->result) { result += query->result; - m_statistics_map[writer.counter_tag] = result; + if (query->data_type & CELL_GCM_ZPASS_PIXEL_CNT) + { + m_statistics_map[writer.counter_tag] += query->result; + } } } else @@ -3212,11 +3260,11 @@ namespace rsx stat_tag_to_remove = writer.counter_tag; - // only zpass supported right now if (!writer.forwarder) { // No other queries in the chain, write result - write(&writer, ptimer->timestamp(), result); + const auto value = (writer.type == CELL_GCM_ZPASS_PIXEL_CNT) ? m_statistics_map[writer.counter_tag] : result; + write(&writer, ptimer->timestamp(), value); if (query && query->sync_tag == ptimer->cond_render_ctrl.eval_sync_tag) { diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 725a7cb9a2..2d65251c37 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -335,6 +335,7 @@ namespace rsx u32 driver_handle; u32 result; u32 num_draws; + u32 data_type; u64 sync_tag; u64 timestamp; bool pending; @@ -367,8 +368,9 @@ namespace rsx sync_no_notify = 2 // If set, backend hint notifications will not be made }; - struct ZCULL_control + class ZCULL_control { + protected: // Delay before a report update operation is forced to retire const u32 max_zcull_delay_us = 300; const u32 min_zcull_tick_us = 100; @@ -377,8 +379,11 @@ namespace rsx const u32 occlusion_query_count = 1024; const u32 max_safe_queue_depth = 892; - bool active = false; - bool enabled = false; + bool unit_enabled = false; // The ZCULL unit is on + bool write_enabled = false; // A surface in the ZCULL-monitored tile region has been loaded for rasterization + bool stats_enabled = false; // Collecting of ZCULL statistics is enabled (not same as pixels passing Z test!) + bool zpass_count_enabled = false; // Collecting of ZPASS statistics is enabled. If this is off, the counter does not increment + bool host_queries_active = false; // The backend/host is gathering Z data for the ZCULL unit std::array m_occlusion_query_data = {}; std::stack m_free_occlusion_pool; @@ -397,17 +402,11 @@ namespace rsx std::vector m_pending_writes; std::unordered_map m_statistics_map; - ZCULL_control(); - ~ZCULL_control(); + // Enables/disables the ZCULL unit + void set_active(class ::rsx::thread* ptimer, bool active, bool flush_queue); - void set_enabled(class ::rsx::thread* ptimer, bool state, bool flush_queue = false); - void set_active(class ::rsx::thread* ptimer, bool state, bool flush_queue = false); - - void write(vm::addr_t sink, u64 timestamp, u32 type, u32 value); - void write(queued_report_write* writer, u64 timestamp, u32 value); - - // Read current zcull statistics into the address provided - void read_report(class ::rsx::thread* ptimer, vm::addr_t sink, u32 type); + // Checks current state of the unit and applies changes + void check_state(class ::rsx::thread* ptimer, bool flush_queue); // Sets up a new query slot and sets it to the current task void allocate_new_query(class ::rsx::thread* ptimer); @@ -415,6 +414,21 @@ namespace rsx // Free a query slot in use void free_query(occlusion_query_info* query); + // Write report to memory + void write(vm::addr_t sink, u64 timestamp, u32 type, u32 value); + void write(queued_report_write* writer, u64 timestamp, u32 value); + + public: + + ZCULL_control(); + ~ZCULL_control(); + + void set_enabled(class ::rsx::thread* ptimer, bool state, bool flush_queue = false); + void set_status(class ::rsx::thread* ptimer, bool surface_active, bool zpass_active, bool zcull_stats_active, bool flush_queue = false); + + // Read current zcull statistics into the address provided + void read_report(class ::rsx::thread* ptimer, vm::addr_t sink, u32 type); + // Clears current stat block and increments stat_tag_id void clear(class ::rsx::thread* ptimer); @@ -459,7 +473,7 @@ namespace rsx bool reserved = false; std::vector eval_sources; - u32 eval_sync_tag = 0; + u64 eval_sync_tag = 0; u32 eval_address = 0; // Resets common data