mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-10 00:41:26 +12: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
|
//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
|
//Update sub-units
|
||||||
zcull_ctrl->update(this);
|
zcull_ctrl->update(this);
|
||||||
|
@ -510,16 +510,23 @@ namespace rsx
|
||||||
|
|
||||||
sync_point_request = false;
|
sync_point_request = false;
|
||||||
}
|
}
|
||||||
else if (performance_counters.FIFO_is_idle)
|
else if (performance_counters.state != FIFO_state::running)
|
||||||
|
{
|
||||||
|
if (performance_counters.state != FIFO_state::nop)
|
||||||
{
|
{
|
||||||
//Registers not updated, do housekeeping since queue is idle
|
|
||||||
if (has_deferred_call)
|
if (has_deferred_call)
|
||||||
{
|
{
|
||||||
|
//Flush if spinning or queue is empty
|
||||||
flush_command_queue();
|
flush_command_queue();
|
||||||
}
|
}
|
||||||
|
else if (zcull_ctrl->has_pending())
|
||||||
|
{
|
||||||
|
zcull_ctrl->sync(this);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
do_internal_task();
|
//do_internal_task();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,10 +536,10 @@ namespace rsx
|
||||||
|
|
||||||
if (put == internal_get || !Emu.IsRunning())
|
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_idle_timestamp = get_system_time();
|
||||||
performance_counters.FIFO_is_idle = true;
|
performance_counters.state = FIFO_state::empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -569,12 +576,13 @@ namespace rsx
|
||||||
u32 offs = cmd & 0x1ffffffc;
|
u32 offs = cmd & 0x1ffffffc;
|
||||||
if (offs == internal_get.load())
|
if (offs == internal_get.load())
|
||||||
{
|
{
|
||||||
//Jump to self
|
//Jump to self. Often preceded by 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_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);
|
//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;
|
u32 offs = cmd & 0xfffffffc;
|
||||||
if (offs == internal_get.load())
|
if (offs == internal_get.load())
|
||||||
{
|
{
|
||||||
//Jump to self
|
//Jump to self. Often preceded by 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_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);
|
//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 (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_idle_timestamp = get_system_time();
|
||||||
performance_counters.FIFO_is_idle = true;
|
performance_counters.state = FIFO_state::nop;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal_get += 4;
|
internal_get += 4;
|
||||||
|
@ -675,11 +684,20 @@ namespace rsx
|
||||||
if (internal_get < put && ((internal_get + (count + 1) * 4) > put))
|
if (internal_get < put && ((internal_get + (count + 1) * 4) > put))
|
||||||
LOG_ERROR(RSX, "Get pointer jumping over put pointer! This is bad!");
|
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
|
//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);
|
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++)
|
for (u32 i = 0; i < count; i++)
|
||||||
|
@ -1230,12 +1248,6 @@ namespace rsx
|
||||||
|
|
||||||
void thread::do_internal_task()
|
void thread::do_internal_task()
|
||||||
{
|
{
|
||||||
if (zcull_ctrl->has_pending())
|
|
||||||
{
|
|
||||||
zcull_ctrl->sync(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_internal_tasks.empty())
|
if (m_internal_tasks.empty())
|
||||||
{
|
{
|
||||||
std::this_thread::yield();
|
std::this_thread::yield();
|
||||||
|
|
|
@ -81,6 +81,14 @@ namespace rsx
|
||||||
all_dirty = 255
|
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_vertex_type_size_on_host(vertex_base_type type, u32 size);
|
||||||
|
|
||||||
u32 get_address(u32 offset, u32 location);
|
u32 get_address(u32 offset, u32 location);
|
||||||
|
@ -302,7 +310,7 @@ namespace rsx
|
||||||
atomic_t<u64> idle_time{ 0 }; //Time spent idling in microseconds
|
atomic_t<u64> idle_time{ 0 }; //Time spent idling in microseconds
|
||||||
u64 last_update_timestamp = 0; //Timestamp of last load update
|
u64 last_update_timestamp = 0; //Timestamp of last load update
|
||||||
u64 FIFO_idle_timestamp = 0; //Timestamp of when FIFO queue becomes idle
|
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 approximate_load = 0;
|
||||||
u32 sampled_frames = 0;
|
u32 sampled_frames = 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue