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.
This commit is contained in:
kd-11 2020-02-22 18:19:16 +03:00 committed by kd-11
parent df1813b4e2
commit 6e9392fb45
2 changed files with 108 additions and 46 deletions

View file

@ -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)
{

View file

@ -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<occlusion_query_info, 1024> m_occlusion_query_data = {};
std::stack<occlusion_query_info*> m_free_occlusion_pool;
@ -397,17 +402,11 @@ namespace rsx
std::vector<queued_report_write> m_pending_writes;
std::unordered_map<u32, u32> 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<occlusion_query_info*> eval_sources;
u32 eval_sync_tag = 0;
u64 eval_sync_tag = 0;
u32 eval_address = 0;
// Resets common data