From 1be01aea52f93a37a4f8d1bca1670a158eef7351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 25 May 2025 22:10:17 +0200 Subject: [PATCH] rcheevos: Call rc_client_do_frame in the flip callback. Also some minor cleanup of the AVI recording. Should fix #20383 --- Common/UI/View.cpp | 2 +- Core/AVIDump.cpp | 22 +++++++++++++--------- Core/AVIDump.h | 5 +++-- UI/EmuScreen.cpp | 23 +++++++++++++++++------ UI/EmuScreen.h | 2 +- 5 files changed, 35 insertions(+), 19 deletions(-) diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index 9c3503bc3f..d621105dc3 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -538,7 +538,7 @@ void Choice::Draw(UIContext &dc) { uint32_t col = rightIconKeepColor_ ? 0xffffffff : style.fgColor; // Don't apply theme to gold icon if (shine_) { Bounds b = Bounds::FromCenter(bounds_.x2() - 32 - paddingX, bounds_.centerY(), bounds_.h * 0.4f); - DrawIconShine(dc, b, 0.8f, false); + DrawIconShine(dc, b.Inset(5.0f, 5.0f), 0.65f, false); } dc.Draw()->DrawImageRotated(rightIconImage_, bounds_.x2() - 32 - paddingX, bounds_.centerY(), rightIconScale_, rightIconRot_, col, rightIconFlipH_); } diff --git a/Core/AVIDump.cpp b/Core/AVIDump.cpp index ebc140c389..74292c598a 100644 --- a/Core/AVIDump.cpp +++ b/Core/AVIDump.cpp @@ -64,6 +64,7 @@ static int s_current_width; static int s_current_height; static int s_file_index = 0; static GPUDebugBuffer buf; +static Path g_filename; static void InitAVCodec() { static bool first_run = true; @@ -97,7 +98,7 @@ bool AVIDump::CreateAVI() { // Use gameID_EmulatedTimestamp for filename std::string discID = g_paramSFO.GetDiscID(); - Path video_file_name = GetSysDirectory(DIRECTORY_VIDEO) / StringFromFormat("%s_%s.avi", discID.c_str(), KernelTimeNowFormatted().c_str()); + g_filename = GetSysDirectory(DIRECTORY_VIDEO) / StringFromFormat("%s_%s.avi", discID.c_str(), KernelTimeNowFormatted().c_str()); s_format_context = avformat_alloc_context(); @@ -107,16 +108,16 @@ bool AVIDump::CreateAVI() { s_format_context->url = filename; #else const char *filename = s_format_context->filename; - snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s", video_file_name.c_str()); + snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s", g_filename.c_str()); #endif - INFO_LOG(Log::Common, "Recording Video to: %s", video_file_name.ToVisualString().c_str()); + INFO_LOG(Log::Common, "Recording Video to: %s", g_filename.ToVisualString().c_str()); // Make sure that the path exists if (!File::Exists(GetSysDirectory(DIRECTORY_VIDEO))) File::CreateDir(GetSysDirectory(DIRECTORY_VIDEO)); - if (File::Exists(video_file_name)) - File::Delete(video_file_name); + if (File::Exists(g_filename)) + File::Delete(g_filename); s_format_context->oformat = av_guess_format("avi", nullptr, nullptr); if (!s_format_context->oformat) @@ -168,9 +169,9 @@ bool AVIDump::CreateAVI() { return false; #endif - NOTICE_LOG(Log::G3D, "Opening file %s for dumping", filename); + NOTICE_LOG(Log::G3D, "Opening file '%s' for dumping", g_filename.ToVisualString().c_str()); if (avio_open(&s_format_context->pb, filename, AVIO_FLAG_WRITE) < 0 || avformat_write_header(s_format_context, nullptr)) { - WARN_LOG(Log::G3D, "Could not open %s", filename); + WARN_LOG(Log::G3D, "Could not open %s", g_filename.ToVisualString().c_str()); return false; } @@ -273,14 +274,17 @@ void AVIDump::AddFrame() { delete[] flipbuffer; } +Path AVIDump::LastFilename() { + return g_filename; +} + void AVIDump::Stop() { #ifdef USE_FFMPEG - av_write_trailer(s_format_context); CloseFile(); s_file_index = 0; #endif - NOTICE_LOG(Log::G3D, "Stopping frame dump"); + NOTICE_LOG(Log::G3D, "Stopping frame dump to '%s'", g_filename.ToVisualString().c_str()); } void AVIDump::CloseFile() { diff --git a/Core/AVIDump.h b/Core/AVIDump.h index 07147d5780..266904f7fb 100644 --- a/Core/AVIDump.h +++ b/Core/AVIDump.h @@ -6,9 +6,9 @@ #pragma once #include "Common/CommonTypes.h" +#include "Common/File/Path.h" -class AVIDump -{ +class AVIDump { private: static bool CreateAVI(); static void CloseFile(); @@ -18,5 +18,6 @@ public: static bool Start(int w, int h); static void AddFrame(); static void Stop(); + static Path LastFilename(); }; #endif diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 6090420133..dddd356631 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -343,7 +343,10 @@ void EmuScreen::ProcessGameBoot(const Path &filename) { // Only call this on successful boot. void EmuScreen::bootComplete() { - __DisplayListenVblank([this]() {HandleVBlank(); }); + __DisplayListenFlip([](void *userdata) { + EmuScreen *scr = (EmuScreen *)userdata; + scr->HandleFlip(); + }, (void *)this); // Initialize retroachievements, now that we're on the right thread. if (g_Config.bAchievementsEnable) { @@ -1513,8 +1516,15 @@ void EmuScreen::darken() { } } -// TODO: We probably shouldn't even handle frame dumping at vblank, we can just as well handle it directly in EmuScreen. -void EmuScreen::HandleVBlank() { +void EmuScreen::HandleFlip() { + static double lastFrame; + double now = time_now_d(); + INFO_LOG(Log::System, "HandleFlip: %0.2f ms", (now - lastFrame) * 1000.0f); + lastFrame = now; + + Achievements::FrameUpdate(); + + // This video dumping stuff is bad. Or at least completely broken with frameskip.. #ifndef MOBILE_DEVICE if (g_Config.bDumpFrames && !startDumping_) { auto sy = GetI18NCategory(I18NCat::SYSTEM); @@ -1527,7 +1537,10 @@ void EmuScreen::HandleVBlank() { } else if (!g_Config.bDumpFrames && startDumping_) { auto sy = GetI18NCategory(I18NCat::SYSTEM); avi.Stop(); - g_OSD.Show(OSDType::MESSAGE_INFO, sy->T("AVI Dump stopped."), 1.0f); + g_OSD.Show(OSDType::MESSAGE_INFO, sy->T("AVI Dump stopped."), 3.0f, "avi_dump"); + g_OSD.SetClickCallback("avi_dump", [](bool, void *) { + System_ShowFileInFolder(avi.LastFilename()); + }, nullptr); startDumping_ = false; } #endif @@ -1677,7 +1690,6 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) { // Reached the end of the frame while running at full blast, all good. Set back to running for the next frame coreState = frameStep_ ? CORE_STEPPING_CPU : CORE_RUNNING_CPU; flags |= ScreenRenderFlags::HANDLED_THROTTLING; - Achievements::FrameUpdate(); break; case CORE_STEPPING_CPU: case CORE_STEPPING_GE: @@ -1711,7 +1723,6 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) { // However, let's not cause a UI sleep in the mainloop. flags |= ScreenRenderFlags::HANDLED_THROTTLING; - Achievements::FrameUpdate(); break; } diff --git a/UI/EmuScreen.h b/UI/EmuScreen.h index 5baa7f85f8..81c6b98ff9 100644 --- a/UI/EmuScreen.h +++ b/UI/EmuScreen.h @@ -76,7 +76,7 @@ private: UI::EventReturn OnDevTools(UI::EventParams ¶ms); UI::EventReturn OnChat(UI::EventParams ¶ms); - void HandleVBlank(); + void HandleFlip(); void ProcessGameBoot(const Path &filename); bool bootAllowStorage(const Path &filename); void bootComplete();