mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 11:36:13 +00:00
rsx: Improve puller state management
- Properly identify puller spin primitives - Add a small wake delay after exiting a spin delay. Fixes desynchronization It seems real hw has a small delay between cell edits to commandbuffer memory at the GET address and the changes becoming visible to the DMA puller Simulated with a short busy_wait, large values will improve sync but degrade performance
This commit is contained in:
parent
1aa44ede31
commit
bff6060bd6
2 changed files with 48 additions and 28 deletions
|
@ -490,7 +490,7 @@ namespace rsx
|
|||
}
|
||||
|
||||
//Execute backend-local tasks first
|
||||
do_local_task(performance_counters.FIFO_is_idle);
|
||||
do_local_task(performance_counters.state != FIFO_state::running);
|
||||
|
||||
//Update sub-units
|
||||
zcull_ctrl->update(this);
|
||||
|
@ -510,16 +510,23 @@ namespace rsx
|
|||
|
||||
sync_point_request = false;
|
||||
}
|
||||
else if (performance_counters.FIFO_is_idle)
|
||||
else if (performance_counters.state != FIFO_state::running)
|
||||
{
|
||||
//Registers not updated, do housekeeping since queue is idle
|
||||
if (has_deferred_call)
|
||||
if (performance_counters.state != FIFO_state::nop)
|
||||
{
|
||||
flush_command_queue();
|
||||
}
|
||||
else
|
||||
{
|
||||
do_internal_task();
|
||||
if (has_deferred_call)
|
||||
{
|
||||
//Flush if spinning or queue is empty
|
||||
flush_command_queue();
|
||||
}
|
||||
else if (zcull_ctrl->has_pending())
|
||||
{
|
||||
zcull_ctrl->sync(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
//do_internal_task();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -529,10 +536,10 @@ namespace rsx
|
|||
|
||||
if (put == internal_get || !Emu.IsRunning())
|
||||
{
|
||||
if (!performance_counters.FIFO_is_idle)
|
||||
if (performance_counters.state == FIFO_state::running)
|
||||
{
|
||||
performance_counters.FIFO_idle_timestamp = get_system_time();
|
||||
performance_counters.FIFO_is_idle = true;
|
||||
performance_counters.state = FIFO_state::empty;
|
||||
}
|
||||
|
||||
continue;
|
||||
|
@ -569,12 +576,13 @@ namespace rsx
|
|||
u32 offs = cmd & 0x1ffffffc;
|
||||
if (offs == internal_get.load())
|
||||
{
|
||||
//Jump to self
|
||||
if (!performance_counters.FIFO_is_idle)
|
||||
//Jump to self. Often preceded by NOP
|
||||
if (performance_counters.state == FIFO_state::running)
|
||||
{
|
||||
performance_counters.FIFO_idle_timestamp = get_system_time();
|
||||
performance_counters.FIFO_is_idle = true;
|
||||
}
|
||||
|
||||
performance_counters.state = FIFO_state::spinning;
|
||||
}
|
||||
|
||||
//LOG_WARNING(RSX, "rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", offs, m_ioAddress + get, cmd, get, put);
|
||||
|
@ -586,12 +594,13 @@ namespace rsx
|
|||
u32 offs = cmd & 0xfffffffc;
|
||||
if (offs == internal_get.load())
|
||||
{
|
||||
//Jump to self
|
||||
if (!performance_counters.FIFO_is_idle)
|
||||
//Jump to self. Often preceded by NOP
|
||||
if (performance_counters.state == FIFO_state::running)
|
||||
{
|
||||
performance_counters.FIFO_idle_timestamp = get_system_time();
|
||||
performance_counters.FIFO_is_idle = true;
|
||||
}
|
||||
|
||||
performance_counters.state = FIFO_state::spinning;
|
||||
}
|
||||
|
||||
//LOG_WARNING(RSX, "rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", offs, m_ioAddress + get, cmd, get, put);
|
||||
|
@ -623,10 +632,10 @@ namespace rsx
|
|||
}
|
||||
if (cmd == 0) //nop
|
||||
{
|
||||
if (!performance_counters.FIFO_is_idle)
|
||||
if (performance_counters.state == FIFO_state::running)
|
||||
{
|
||||
performance_counters.FIFO_idle_timestamp = get_system_time();
|
||||
performance_counters.FIFO_is_idle = true;
|
||||
performance_counters.state = FIFO_state::nop;
|
||||
}
|
||||
|
||||
internal_get += 4;
|
||||
|
@ -675,11 +684,20 @@ namespace rsx
|
|||
if (internal_get < put && ((internal_get + (count + 1) * 4) > put))
|
||||
LOG_ERROR(RSX, "Get pointer jumping over put pointer! This is bad!");
|
||||
|
||||
if (performance_counters.FIFO_is_idle)
|
||||
if (performance_counters.state != FIFO_state::running)
|
||||
{
|
||||
//Update performance counters with time spent in idle mode
|
||||
performance_counters.FIFO_is_idle = false;
|
||||
performance_counters.idle_time += (get_system_time() - performance_counters.FIFO_idle_timestamp);
|
||||
|
||||
if (performance_counters.state == FIFO_state::spinning)
|
||||
{
|
||||
//TODO: Properly simulate FIFO wake delay.
|
||||
//NOTE: The typical spin setup is a NOP followed by a jump-to-self
|
||||
//NOTE: There is a small delay when the jump address is dynamically edited by cell
|
||||
busy_wait(3000);
|
||||
}
|
||||
|
||||
performance_counters.state = FIFO_state::running;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < count; i++)
|
||||
|
@ -1230,12 +1248,6 @@ namespace rsx
|
|||
|
||||
void thread::do_internal_task()
|
||||
{
|
||||
if (zcull_ctrl->has_pending())
|
||||
{
|
||||
zcull_ctrl->sync(this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_internal_tasks.empty())
|
||||
{
|
||||
std::this_thread::yield();
|
||||
|
|
|
@ -81,6 +81,14 @@ namespace rsx
|
|||
all_dirty = 255
|
||||
};
|
||||
|
||||
enum FIFO_state : u8
|
||||
{
|
||||
running = 0,
|
||||
empty = 1, //PUT == GET
|
||||
spinning = 2, //Puller continously jumps to self addr (synchronization technique)
|
||||
nop = 3, //Puller is processing a NOP command
|
||||
};
|
||||
|
||||
u32 get_vertex_type_size_on_host(vertex_base_type type, u32 size);
|
||||
|
||||
u32 get_address(u32 offset, u32 location);
|
||||
|
@ -302,7 +310,7 @@ namespace rsx
|
|||
atomic_t<u64> idle_time{ 0 }; //Time spent idling in microseconds
|
||||
u64 last_update_timestamp = 0; //Timestamp of last load update
|
||||
u64 FIFO_idle_timestamp = 0; //Timestamp of when FIFO queue becomes idle
|
||||
bool FIFO_is_idle = false; //True if FIFO is in idle state
|
||||
FIFO_state state = FIFO_state::running;
|
||||
u32 approximate_load = 0;
|
||||
u32 sampled_frames = 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue