mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-12 13:13:43 +00:00
rsx: Restructure flip code and frame scoping
- Add an explicit frame scope marker tied in with the queue_prepare command Since queue_prepare is emitted at the end of a frame, it can be used as end-of-frame in games that emit this - If this command is not emitted, fifo flatenner and frameskip will not work
This commit is contained in:
parent
c50119aefa
commit
2c76f47eec
@ -15,6 +15,9 @@ extern u64 get_timebased_time();
|
|||||||
|
|
||||||
static shared_mutex s_rsxmem_mtx;
|
static shared_mutex s_rsxmem_mtx;
|
||||||
|
|
||||||
|
// Unknown error code returned by sys_rsx_context_attribute
|
||||||
|
constexpr unsigned SYS_RSX_CONTEXT_ATTRIBUTE_ERROR = -17u;
|
||||||
|
|
||||||
u64 rsxTimeStamp()
|
u64 rsxTimeStamp()
|
||||||
{
|
{
|
||||||
return get_timebased_time();
|
return get_timebased_time();
|
||||||
@ -82,7 +85,9 @@ error_code sys_rsx_context_allocate(vm::ptr<u32> context_id, vm::ptr<u64> lpar_d
|
|||||||
auto rsx_cfg = g_fxo->get<lv2_rsx_config>();
|
auto rsx_cfg = g_fxo->get<lv2_rsx_config>();
|
||||||
|
|
||||||
if (!rsx_cfg->state)
|
if (!rsx_cfg->state)
|
||||||
|
{
|
||||||
return CELL_EINVAL;
|
return CELL_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
*context_id = 0x55555555;
|
*context_id = 0x55555555;
|
||||||
|
|
||||||
@ -96,7 +101,8 @@ error_code sys_rsx_context_allocate(vm::ptr<u32> context_id, vm::ptr<u64> lpar_d
|
|||||||
for (int i = 0; i < 64; ++i)
|
for (int i = 0; i < 64; ++i)
|
||||||
reports.notify[i].timestamp = (u64)-1;
|
reports.notify[i].timestamp = (u64)-1;
|
||||||
|
|
||||||
for (int i = 0; i < 256; ++i) {
|
for (int i = 0; i < 256; ++i)
|
||||||
|
{
|
||||||
reports.semaphore[i].val = 0x1337C0D3;
|
reports.semaphore[i].val = 0x1337C0D3;
|
||||||
reports.semaphore[i].pad = 0x1337BABE;
|
reports.semaphore[i].pad = 0x1337BABE;
|
||||||
reports.semaphore[i].timestamp = (u64)-1; // technically different but should be fine
|
reports.semaphore[i].timestamp = (u64)-1; // technically different but should be fine
|
||||||
@ -301,9 +307,9 @@ error_code sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64
|
|||||||
// fyi -- u32 hardware_channel = (a4 >> 8) & 0xFF;
|
// fyi -- u32 hardware_channel = (a4 >> 8) & 0xFF;
|
||||||
|
|
||||||
// sanity check, the head should have a 'queued' buffer on it, and it should have been previously 'queued'
|
// sanity check, the head should have a 'queued' buffer on it, and it should have been previously 'queued'
|
||||||
u32 sanity_check = 0x40000000 & (1 << flip_idx);
|
const u32 sanity_check = 0x40000000 & (1 << flip_idx);
|
||||||
if ((driverInfo.head[a3].flipFlags & sanity_check) != sanity_check)
|
if ((driverInfo.head[a3].flipFlags & sanity_check) != sanity_check)
|
||||||
LOG_ERROR(RSX, "Display Flip Queued: Flipping non previously queued buffer 0x%x", a4);
|
LOG_ERROR(RSX, "Display Flip Queued: Flipping non previously queued buffer 0x%llx", a4);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -327,23 +333,33 @@ error_code sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x103: // Display Queue
|
case 0x103: // Display Queue
|
||||||
|
{
|
||||||
driverInfo.head[a3].lastQueuedBufferId = a4;
|
driverInfo.head[a3].lastQueuedBufferId = a4;
|
||||||
driverInfo.head[a3].flipFlags |= 0x40000000 | (1 << a4);
|
driverInfo.head[a3].flipFlags |= 0x40000000 | (1 << a4);
|
||||||
if (a3 == 0)
|
|
||||||
sys_event_port_send(rsx_cfg->rsx_event_port, 0, (1 << 5), 0);
|
// NOTE: There currently seem to only be 2 active heads on PS3
|
||||||
if (a3 == 1)
|
verify(HERE), a3 < 2;
|
||||||
sys_event_port_send(rsx_cfg->rsx_event_port, 0, (1 << 6), 0);
|
|
||||||
break;
|
const u64 shift_offset = (a3 + 5);
|
||||||
|
sys_event_port_send(rsx_cfg->rsx_event_port, 0, (1ull << shift_offset), 0);
|
||||||
|
|
||||||
|
render->on_frame_end(a4);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x104: // Display buffer
|
case 0x104: // Display buffer
|
||||||
{
|
{
|
||||||
u8 id = a3 & 0xFF;
|
const u8 id = a3 & 0xFF;
|
||||||
u32 width = (a4 >> 32) & 0xFFFFFFFF;
|
|
||||||
u32 height = a4 & 0xFFFFFFFF;
|
|
||||||
u32 pitch = (a5 >> 32) & 0xFFFFFFFF;
|
|
||||||
u32 offset = a5 & 0xFFFFFFFF;
|
|
||||||
if (id > 7)
|
if (id > 7)
|
||||||
return -17;
|
{
|
||||||
|
return SYS_RSX_CONTEXT_ATTRIBUTE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u32 width = (a4 >> 32) & 0xFFFFFFFF;
|
||||||
|
const u32 height = a4 & 0xFFFFFFFF;
|
||||||
|
const u32 pitch = (a5 >> 32) & 0xFFFFFFFF;
|
||||||
|
const u32 offset = a5 & 0xFFFFFFFF;
|
||||||
|
|
||||||
render->display_buffers[id].width = width;
|
render->display_buffers[id].width = width;
|
||||||
render->display_buffers[id].height = height;
|
render->display_buffers[id].height = height;
|
||||||
render->display_buffers[id].pitch = pitch;
|
render->display_buffers[id].pitch = pitch;
|
||||||
@ -370,7 +386,9 @@ error_code sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64
|
|||||||
case 0x10a: // ? Involved in managing flip status through cellGcmResetFlipStatus
|
case 0x10a: // ? Involved in managing flip status through cellGcmResetFlipStatus
|
||||||
{
|
{
|
||||||
if (a3 > 7)
|
if (a3 > 7)
|
||||||
return -17;
|
{
|
||||||
|
return SYS_RSX_CONTEXT_ATTRIBUTE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
u32 flipStatus = driverInfo.head[a3].flipFlags;
|
u32 flipStatus = driverInfo.head[a3].flipFlags;
|
||||||
flipStatus = (flipStatus & a4) | a5;
|
flipStatus = (flipStatus & a4) | a5;
|
||||||
|
@ -2235,45 +2235,9 @@ namespace rsx
|
|||||||
|
|
||||||
void thread::flip(int buffer, bool emu_flip)
|
void thread::flip(int buffer, bool emu_flip)
|
||||||
{
|
{
|
||||||
if (!(async_flip_requested & flip_request::any))
|
if (async_flip_requested & flip_request::any)
|
||||||
{
|
{
|
||||||
// Flip is processed through inline FLIP command in the commandstream
|
// Deferred flip
|
||||||
// This is critical as it is a reliable end-of-frame marker
|
|
||||||
|
|
||||||
if (!g_cfg.video.disable_FIFO_reordering)
|
|
||||||
{
|
|
||||||
// Try to enable FIFO optimizations
|
|
||||||
// Only rarely useful for some games like RE4
|
|
||||||
m_flattener.evaluate_performance(m_draw_calls);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset zcull ctrl
|
|
||||||
zcull_ctrl->set_active(this, false);
|
|
||||||
zcull_ctrl->clear(this);
|
|
||||||
|
|
||||||
if (zcull_ctrl->has_pending())
|
|
||||||
{
|
|
||||||
LOG_TRACE(RSX, "Dangling reports found, discarding...");
|
|
||||||
zcull_ctrl->sync(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_cfg.video.frame_skip_enabled)
|
|
||||||
{
|
|
||||||
m_skip_frame_ctr++;
|
|
||||||
|
|
||||||
if (m_skip_frame_ctr == g_cfg.video.consequtive_frames_to_draw)
|
|
||||||
m_skip_frame_ctr = -g_cfg.video.consequtive_frames_to_skip;
|
|
||||||
|
|
||||||
skip_frame = (m_skip_frame_ctr < 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (async_flip_requested & flip_request::emu_requested)
|
|
||||||
{
|
|
||||||
m_flattener.force_disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (emu_flip)
|
if (emu_flip)
|
||||||
{
|
{
|
||||||
async_flip_requested.clear(flip_request::emu_requested);
|
async_flip_requested.clear(flip_request::emu_requested);
|
||||||
@ -2284,13 +2248,16 @@ namespace rsx
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skip_frame)
|
if (emu_flip)
|
||||||
{
|
{
|
||||||
// Reset counter
|
if (g_cfg.video.frame_skip_enabled)
|
||||||
m_draw_calls = 0;
|
{
|
||||||
}
|
skip_frame = (m_skip_frame_ctr < 0);
|
||||||
|
}
|
||||||
|
|
||||||
performance_counters.sampled_frames++;
|
m_draw_calls = 0;
|
||||||
|
performance_counters.sampled_frames++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread::check_zcull_status(bool framebuffer_swap)
|
void thread::check_zcull_status(bool framebuffer_swap)
|
||||||
@ -2528,31 +2495,9 @@ namespace rsx
|
|||||||
return performance_counters.approximate_load;
|
return performance_counters.approximate_load;
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread::request_emu_flip(u32 buffer)
|
void thread::on_frame_end(u32 buffer, bool forced)
|
||||||
{
|
|
||||||
const bool is_rsxthr = std::this_thread::get_id() == m_rsx_thread;
|
|
||||||
|
|
||||||
// requested through command buffer
|
|
||||||
if (is_rsxthr)
|
|
||||||
{
|
|
||||||
// NOTE: The flip will clear any queued flip requests
|
|
||||||
handle_emu_flip(buffer);
|
|
||||||
}
|
|
||||||
else // requested 'manually' through ppu syscall
|
|
||||||
{
|
|
||||||
if (async_flip_requested & flip_request::emu_requested)
|
|
||||||
{
|
|
||||||
// ignore multiple requests until previous happens
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
async_flip_buffer = buffer;
|
|
||||||
async_flip_requested |= flip_request::emu_requested;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void thread::handle_emu_flip(u32 buffer)
|
|
||||||
{
|
{
|
||||||
|
// Marks the end of a frame scope GPU-side
|
||||||
if (user_asked_for_frame_capture && !capture_current_frame)
|
if (user_asked_for_frame_capture && !capture_current_frame)
|
||||||
{
|
{
|
||||||
capture_current_frame = true;
|
capture_current_frame = true;
|
||||||
@ -2588,6 +2533,81 @@ namespace rsx
|
|||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset zcull ctrl
|
||||||
|
zcull_ctrl->set_active(this, false);
|
||||||
|
zcull_ctrl->clear(this);
|
||||||
|
|
||||||
|
if (zcull_ctrl->has_pending())
|
||||||
|
{
|
||||||
|
LOG_TRACE(RSX, "Dangling reports found, discarding...");
|
||||||
|
zcull_ctrl->sync(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LIKELY(!forced))
|
||||||
|
{
|
||||||
|
if (!g_cfg.video.disable_FIFO_reordering)
|
||||||
|
{
|
||||||
|
// Try to enable FIFO optimizations
|
||||||
|
// Only rarely useful for some games like RE4
|
||||||
|
m_flattener.evaluate_performance(m_draw_calls);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_cfg.video.frame_skip_enabled)
|
||||||
|
{
|
||||||
|
m_skip_frame_ctr++;
|
||||||
|
|
||||||
|
if (m_skip_frame_ctr == g_cfg.video.consequtive_frames_to_draw)
|
||||||
|
m_skip_frame_ctr = -g_cfg.video.consequtive_frames_to_skip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!g_cfg.video.disable_FIFO_reordering)
|
||||||
|
{
|
||||||
|
// Flattener is unusable due to forced random flips
|
||||||
|
m_flattener.force_disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_cfg.video.frame_skip_enabled)
|
||||||
|
{
|
||||||
|
LOG_ERROR(RSX, "Frame skip is not compatible with this application");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queued_flip_index = int(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread::request_emu_flip(u32 buffer)
|
||||||
|
{
|
||||||
|
const bool is_rsxthr = std::this_thread::get_id() == m_rsx_thread;
|
||||||
|
|
||||||
|
// requested through command buffer
|
||||||
|
if (is_rsxthr)
|
||||||
|
{
|
||||||
|
// NOTE: The flip will clear any queued flip requests
|
||||||
|
handle_emu_flip(buffer);
|
||||||
|
}
|
||||||
|
else // requested 'manually' through ppu syscall
|
||||||
|
{
|
||||||
|
if (async_flip_requested & flip_request::emu_requested)
|
||||||
|
{
|
||||||
|
// ignore multiple requests until previous happens
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async_flip_buffer = buffer;
|
||||||
|
async_flip_requested |= flip_request::emu_requested;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread::handle_emu_flip(u32 buffer)
|
||||||
|
{
|
||||||
|
if (queued_flip_index < 0)
|
||||||
|
{
|
||||||
|
// Frame was not queued before flipping
|
||||||
|
on_frame_end(buffer, true);
|
||||||
|
}
|
||||||
|
|
||||||
double limit = 0.;
|
double limit = 0.;
|
||||||
switch (g_cfg.video.frame_limit)
|
switch (g_cfg.video.frame_limit)
|
||||||
{
|
{
|
||||||
@ -2634,6 +2654,7 @@ namespace rsx
|
|||||||
|
|
||||||
last_flip_time = get_system_time() - 1000000;
|
last_flip_time = get_system_time() - 1000000;
|
||||||
flip_status = CELL_GCM_DISPLAY_FLIP_STATUS_DONE;
|
flip_status = CELL_GCM_DISPLAY_FLIP_STATUS_DONE;
|
||||||
|
queued_flip_index = -1;
|
||||||
|
|
||||||
if (flip_handler)
|
if (flip_handler)
|
||||||
{
|
{
|
||||||
|
@ -558,6 +558,7 @@ namespace rsx
|
|||||||
u64 start_rsx_time = 0;
|
u64 start_rsx_time = 0;
|
||||||
u64 int_flip_index = 0;
|
u64 int_flip_index = 0;
|
||||||
u64 last_flip_time;
|
u64 last_flip_time;
|
||||||
|
int queued_flip_index = -1;
|
||||||
vm::ptr<void(u32)> flip_handler = vm::null;
|
vm::ptr<void(u32)> flip_handler = vm::null;
|
||||||
vm::ptr<void(u32)> user_handler = vm::null;
|
vm::ptr<void(u32)> user_handler = vm::null;
|
||||||
vm::ptr<void(u32)> vblank_handler = vm::null;
|
vm::ptr<void(u32)> vblank_handler = vm::null;
|
||||||
@ -607,6 +608,7 @@ namespace rsx
|
|||||||
virtual void on_init_rsx() = 0;
|
virtual void on_init_rsx() = 0;
|
||||||
virtual void on_init_thread() = 0;
|
virtual void on_init_thread() = 0;
|
||||||
virtual bool do_method(u32 /*cmd*/, u32 /*value*/) { return false; }
|
virtual bool do_method(u32 /*cmd*/, u32 /*value*/) { return false; }
|
||||||
|
virtual void on_frame_end(u32 buffer, bool forced = false);
|
||||||
virtual void flip(int buffer, bool emu_flip = false) = 0;
|
virtual void flip(int buffer, bool emu_flip = false) = 0;
|
||||||
virtual u64 timestamp();
|
virtual u64 timestamp();
|
||||||
virtual bool on_access_violation(u32 /*address*/, bool /*is_writing*/) { return false; }
|
virtual bool on_access_violation(u32 /*address*/, bool /*is_writing*/) { return false; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user