mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-12 04:14:35 +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;
|
||||
|
||||
// Unknown error code returned by sys_rsx_context_attribute
|
||||
constexpr unsigned SYS_RSX_CONTEXT_ATTRIBUTE_ERROR = -17u;
|
||||
|
||||
u64 rsxTimeStamp()
|
||||
{
|
||||
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>();
|
||||
|
||||
if (!rsx_cfg->state)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
*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)
|
||||
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].pad = 0x1337BABE;
|
||||
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;
|
||||
|
||||
// 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)
|
||||
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
|
||||
{
|
||||
@ -327,23 +333,33 @@ error_code sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64
|
||||
break;
|
||||
|
||||
case 0x103: // Display Queue
|
||||
{
|
||||
driverInfo.head[a3].lastQueuedBufferId = a4;
|
||||
driverInfo.head[a3].flipFlags |= 0x40000000 | (1 << a4);
|
||||
if (a3 == 0)
|
||||
sys_event_port_send(rsx_cfg->rsx_event_port, 0, (1 << 5), 0);
|
||||
if (a3 == 1)
|
||||
sys_event_port_send(rsx_cfg->rsx_event_port, 0, (1 << 6), 0);
|
||||
break;
|
||||
|
||||
// NOTE: There currently seem to only be 2 active heads on PS3
|
||||
verify(HERE), a3 < 2;
|
||||
|
||||
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
|
||||
{
|
||||
u8 id = a3 & 0xFF;
|
||||
u32 width = (a4 >> 32) & 0xFFFFFFFF;
|
||||
u32 height = a4 & 0xFFFFFFFF;
|
||||
u32 pitch = (a5 >> 32) & 0xFFFFFFFF;
|
||||
u32 offset = a5 & 0xFFFFFFFF;
|
||||
const u8 id = a3 & 0xFF;
|
||||
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].height = height;
|
||||
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
|
||||
{
|
||||
if (a3 > 7)
|
||||
return -17;
|
||||
{
|
||||
return SYS_RSX_CONTEXT_ATTRIBUTE_ERROR;
|
||||
}
|
||||
|
||||
u32 flipStatus = driverInfo.head[a3].flipFlags;
|
||||
flipStatus = (flipStatus & a4) | a5;
|
||||
|
@ -2235,45 +2235,9 @@ namespace rsx
|
||||
|
||||
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
|
||||
// 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();
|
||||
}
|
||||
|
||||
// Deferred flip
|
||||
if (emu_flip)
|
||||
{
|
||||
async_flip_requested.clear(flip_request::emu_requested);
|
||||
@ -2284,13 +2248,16 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
if (!skip_frame)
|
||||
if (emu_flip)
|
||||
{
|
||||
// Reset counter
|
||||
m_draw_calls = 0;
|
||||
}
|
||||
if (g_cfg.video.frame_skip_enabled)
|
||||
{
|
||||
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)
|
||||
@ -2528,31 +2495,9 @@ namespace rsx
|
||||
return performance_counters.approximate_load;
|
||||
}
|
||||
|
||||
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)
|
||||
void thread::on_frame_end(u32 buffer, bool forced)
|
||||
{
|
||||
// Marks the end of a frame scope GPU-side
|
||||
if (user_asked_for_frame_capture && !capture_current_frame)
|
||||
{
|
||||
capture_current_frame = true;
|
||||
@ -2588,6 +2533,81 @@ namespace rsx
|
||||
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.;
|
||||
switch (g_cfg.video.frame_limit)
|
||||
{
|
||||
@ -2634,6 +2654,7 @@ namespace rsx
|
||||
|
||||
last_flip_time = get_system_time() - 1000000;
|
||||
flip_status = CELL_GCM_DISPLAY_FLIP_STATUS_DONE;
|
||||
queued_flip_index = -1;
|
||||
|
||||
if (flip_handler)
|
||||
{
|
||||
|
@ -558,6 +558,7 @@ namespace rsx
|
||||
u64 start_rsx_time = 0;
|
||||
u64 int_flip_index = 0;
|
||||
u64 last_flip_time;
|
||||
int queued_flip_index = -1;
|
||||
vm::ptr<void(u32)> flip_handler = vm::null;
|
||||
vm::ptr<void(u32)> user_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_thread() = 0;
|
||||
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 u64 timestamp();
|
||||
virtual bool on_access_violation(u32 /*address*/, bool /*is_writing*/) { return false; }
|
||||
|
Loading…
x
Reference in New Issue
Block a user