rcheevos: Call rc_client_do_frame in the flip callback.

Also some minor cleanup of the AVI recording.

Should fix #20383
This commit is contained in:
Henrik Rydgård
2025-05-25 22:10:17 +02:00
parent f47c44f325
commit 1be01aea52
5 changed files with 35 additions and 19 deletions
+1 -1
View File
@@ -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_);
}
+13 -9
View File
@@ -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() {
+3 -2
View File
@@ -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
+17 -6
View File
@@ -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;
}
+1 -1
View File
@@ -76,7 +76,7 @@ private:
UI::EventReturn OnDevTools(UI::EventParams &params);
UI::EventReturn OnChat(UI::EventParams &params);
void HandleVBlank();
void HandleFlip();
void ProcessGameBoot(const Path &filename);
bool bootAllowStorage(const Path &filename);
void bootComplete();