diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp index e781ba48f9..ee5f3d1b82 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -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 context_id, vm::ptr lpar_d auto rsx_cfg = g_fxo->get(); if (!rsx_cfg->state) + { return CELL_EINVAL; + } *context_id = 0x55555555; @@ -96,7 +101,8 @@ error_code sys_rsx_context_allocate(vm::ptr context_id, vm::ptr 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; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index fa76ff2480..441d05c673 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -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) { diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index c630ea7a60..2db654a8c4 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -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 flip_handler = vm::null; vm::ptr user_handler = vm::null; vm::ptr 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; }