mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-14 18:58:36 +12:00
rsx fifo: Stability improvements
* Restore stack in fifo error handling * Update get register after the cmd execution * Fix put pause in the middle of command * Add restore points when branching to self * Precise nopcmd detection * Test all invalid cmds for early treatment of queue corruption
This commit is contained in:
parent
835a552d8d
commit
87988e9da8
5 changed files with 61 additions and 38 deletions
|
@ -18,6 +18,23 @@ namespace rsx
|
||||||
m_ctrl = pctrl->ctrl;
|
m_ctrl = pctrl->ctrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FIFO_control::inc_get()
|
||||||
|
{
|
||||||
|
m_internal_get += 4;
|
||||||
|
|
||||||
|
// Check if put allows to procceed execution
|
||||||
|
while (m_ctrl->put == m_internal_get)
|
||||||
|
{
|
||||||
|
if (Emu.IsStopped())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sync_get();
|
||||||
|
std::this_thread::yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FIFO_control::set_put(u32 put)
|
void FIFO_control::set_put(u32 put)
|
||||||
{
|
{
|
||||||
if (m_ctrl->put == put)
|
if (m_ctrl->put == put)
|
||||||
|
@ -63,7 +80,15 @@ namespace rsx
|
||||||
{
|
{
|
||||||
m_command_reg += m_command_inc;
|
m_command_reg += m_command_inc;
|
||||||
m_args_ptr += 4;
|
m_args_ptr += 4;
|
||||||
m_remaining_commands--;
|
|
||||||
|
if (--m_remaining_commands)
|
||||||
|
{
|
||||||
|
inc_get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_internal_get += 4;
|
||||||
|
}
|
||||||
|
|
||||||
data.reg = m_command_reg;
|
data.reg = m_command_reg;
|
||||||
data.value = vm::read32(m_args_ptr);
|
data.value = vm::read32(m_args_ptr);
|
||||||
|
@ -129,16 +154,7 @@ namespace rsx
|
||||||
data = { cmd, 0, m_internal_get };
|
data = { cmd, 0, m_internal_get };
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (UNLIKELY((cmd & RSX_METHOD_NOP_MASK) == RSX_METHOD_NOP_CMD))
|
|
||||||
{
|
|
||||||
m_ctrl->get.store(m_internal_get + 4);
|
|
||||||
data = { RSX_METHOD_NOP_CMD, 0, m_internal_get };
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (UNLIKELY(cmd & 0x3))
|
|
||||||
{
|
|
||||||
// Malformed command, optional recovery
|
// Malformed command, optional recovery
|
||||||
data.reg = FIFO_ERROR;
|
data.reg = FIFO_ERROR;
|
||||||
return;
|
return;
|
||||||
|
@ -154,29 +170,27 @@ namespace rsx
|
||||||
}
|
}
|
||||||
|
|
||||||
verify(HERE), !m_remaining_commands;
|
verify(HERE), !m_remaining_commands;
|
||||||
u32 count = (cmd >> 18) & 0x7ff;
|
const u32 count = (cmd >> 18) & 0x7ff;
|
||||||
|
|
||||||
|
if (!count)
|
||||||
|
{
|
||||||
|
m_ctrl->get.store(m_internal_get + 4);
|
||||||
|
data.reg = FIFO_NOP;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (count > 1)
|
if (count > 1)
|
||||||
{
|
{
|
||||||
// Stop command execution if put will be equal to get ptr during the execution itself
|
|
||||||
if (UNLIKELY(count * 4 + 4 > put - m_internal_get))
|
|
||||||
{
|
|
||||||
count = (put - m_internal_get) / 4 - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up readback parameters
|
// Set up readback parameters
|
||||||
m_command_reg = cmd & 0xfffc;
|
m_command_reg = cmd & 0xfffc;
|
||||||
m_command_inc = ((cmd & RSX_METHOD_NON_INCREMENT_CMD_MASK) == RSX_METHOD_NON_INCREMENT_CMD) ? 0 : 4;
|
m_command_inc = ((cmd & RSX_METHOD_NON_INCREMENT_CMD_MASK) == RSX_METHOD_NON_INCREMENT_CMD) ? 0 : 4;
|
||||||
m_remaining_commands = count - 1;
|
m_remaining_commands = count - 1;
|
||||||
|
}
|
||||||
|
|
||||||
m_ctrl->get.store(m_internal_get + (count * 4 + 4));
|
inc_get();
|
||||||
data = { m_command_reg, vm::read32(m_args_ptr), m_internal_get };
|
m_internal_get += 4;
|
||||||
}
|
|
||||||
else
|
data = { cmd & 0xfffc, vm::read32(m_args_ptr), m_internal_get };
|
||||||
{
|
|
||||||
m_ctrl->get.store(m_internal_get + 8);
|
|
||||||
data = { cmd & 0xfffc, vm::read32(m_args_ptr), m_internal_get };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
flattening_helper::flattening_helper()
|
flattening_helper::flattening_helper()
|
||||||
|
@ -376,6 +390,16 @@ namespace rsx
|
||||||
// Check for special FIFO commands
|
// Check for special FIFO commands
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
|
case FIFO::FIFO_NOP:
|
||||||
|
{
|
||||||
|
if (performance_counters.state == FIFO_state::running)
|
||||||
|
{
|
||||||
|
performance_counters.FIFO_idle_timestamp = get_system_time();
|
||||||
|
performance_counters.state = FIFO_state::nop;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
case FIFO::FIFO_EMPTY:
|
case FIFO::FIFO_EMPTY:
|
||||||
{
|
{
|
||||||
if (performance_counters.state == FIFO_state::running)
|
if (performance_counters.state == FIFO_state::running)
|
||||||
|
@ -400,6 +424,7 @@ namespace rsx
|
||||||
// Error. Should reset the queue
|
// Error. Should reset the queue
|
||||||
LOG_ERROR(RSX, "FIFO error: possible desync event");
|
LOG_ERROR(RSX, "FIFO error: possible desync event");
|
||||||
fifo_ctrl->set_get(restore_point);
|
fifo_ctrl->set_get(restore_point);
|
||||||
|
m_return_addr = restore_ret;
|
||||||
std::this_thread::sleep_for(1ms);
|
std::this_thread::sleep_for(1ms);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -415,6 +440,7 @@ namespace rsx
|
||||||
if (performance_counters.state == FIFO_state::running)
|
if (performance_counters.state == FIFO_state::running)
|
||||||
{
|
{
|
||||||
performance_counters.FIFO_idle_timestamp = get_system_time();
|
performance_counters.FIFO_idle_timestamp = get_system_time();
|
||||||
|
sync_point_request = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
performance_counters.state = FIFO_state::spinning;
|
performance_counters.state = FIFO_state::spinning;
|
||||||
|
@ -433,6 +459,7 @@ namespace rsx
|
||||||
if (performance_counters.state == FIFO_state::running)
|
if (performance_counters.state == FIFO_state::running)
|
||||||
{
|
{
|
||||||
performance_counters.FIFO_idle_timestamp = get_system_time();
|
performance_counters.FIFO_idle_timestamp = get_system_time();
|
||||||
|
sync_point_request = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
performance_counters.state = FIFO_state::spinning;
|
performance_counters.state = FIFO_state::spinning;
|
||||||
|
@ -474,16 +501,6 @@ namespace rsx
|
||||||
// If we reached here, this is likely an error
|
// If we reached here, this is likely an error
|
||||||
fmt::throw_exception("Unexpected command 0x%x" HERE, cmd);
|
fmt::throw_exception("Unexpected command 0x%x" HERE, cmd);
|
||||||
}
|
}
|
||||||
else if (cmd == RSX_METHOD_NOP_CMD)
|
|
||||||
{
|
|
||||||
if (performance_counters.state == FIFO_state::running)
|
|
||||||
{
|
|
||||||
performance_counters.FIFO_idle_timestamp = get_system_time();
|
|
||||||
performance_counters.state = FIFO_state::nop;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (performance_counters.state != FIFO_state::running)
|
if (performance_counters.state != FIFO_state::running)
|
||||||
{
|
{
|
||||||
|
@ -580,5 +597,7 @@ namespace rsx
|
||||||
method(this, reg, value);
|
method(this, reg, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fifo_ctrl->sync_get();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
#include <Utilities/Thread.h>
|
#include <Utilities/Thread.h>
|
||||||
|
|
||||||
#include "rsx_utils.h"
|
#include "rsx_utils.h"
|
||||||
|
#include "Emu/Cell/lv2/sys_rsx.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -26,7 +27,7 @@ namespace rsx
|
||||||
{
|
{
|
||||||
enum internal_commands : u32
|
enum internal_commands : u32
|
||||||
{
|
{
|
||||||
NOP = 0,
|
FIFO_NOP = 0xBABEF1F4,
|
||||||
FIFO_EMPTY = 0xDEADF1F0,
|
FIFO_EMPTY = 0xDEADF1F0,
|
||||||
FIFO_BUSY = 0xBABEF1F0,
|
FIFO_BUSY = 0xBABEF1F0,
|
||||||
FIFO_ERROR = 0xDEADBEEF,
|
FIFO_ERROR = 0xDEADBEEF,
|
||||||
|
@ -108,6 +109,8 @@ namespace rsx
|
||||||
FIFO_control(rsx::thread* pctrl);
|
FIFO_control(rsx::thread* pctrl);
|
||||||
~FIFO_control() {}
|
~FIFO_control() {}
|
||||||
|
|
||||||
|
void sync_get() { m_ctrl->get.store(m_internal_get); }
|
||||||
|
void inc_get();
|
||||||
void set_get(u32 get, bool spinning = false);
|
void set_get(u32 get, bool spinning = false);
|
||||||
void set_put(u32 put);
|
void set_put(u32 put);
|
||||||
|
|
||||||
|
|
|
@ -676,6 +676,7 @@ namespace rsx
|
||||||
if (sync_point_request)
|
if (sync_point_request)
|
||||||
{
|
{
|
||||||
restore_point = ctrl->get;
|
restore_point = ctrl->get;
|
||||||
|
restore_ret = m_return_addr;
|
||||||
sync_point_request = false;
|
sync_point_request = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -369,7 +369,7 @@ namespace rsx
|
||||||
protected:
|
protected:
|
||||||
std::thread::id m_rsx_thread;
|
std::thread::id m_rsx_thread;
|
||||||
atomic_t<bool> m_rsx_thread_exiting{true};
|
atomic_t<bool> m_rsx_thread_exiting{true};
|
||||||
s32 m_return_addr{-1}, restore_ret_addr{-1};
|
s32 m_return_addr{-1}, restore_ret{-1};
|
||||||
std::array<push_buffer_vertex_info, 16> vertex_push_buffers;
|
std::array<push_buffer_vertex_info, 16> vertex_push_buffers;
|
||||||
std::vector<u32> element_push_buffer;
|
std::vector<u32> element_push_buffer;
|
||||||
|
|
||||||
|
|
|
@ -1060,7 +1060,7 @@ enum Method
|
||||||
RSX_METHOD_RETURN_MASK = 0xffff0003,
|
RSX_METHOD_RETURN_MASK = 0xffff0003,
|
||||||
|
|
||||||
RSX_METHOD_NOP_CMD = 0x00000000,
|
RSX_METHOD_NOP_CMD = 0x00000000,
|
||||||
RSX_METHOD_NOP_MASK = 0x1ffc0000,
|
RSX_METHOD_NOP_MASK = 0xbfff0003,
|
||||||
};
|
};
|
||||||
|
|
||||||
//Fog
|
//Fog
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue