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:
kd-11 2018-05-06 13:37:28 +03:00 committed by kd-11
parent 1aa44ede31
commit bff6060bd6
2 changed files with 48 additions and 28 deletions

View File

@ -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();

View File

@ -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;
}