Skip to content

Commit

Permalink
ImGui: Avoid frame count display race condition for input recording a…
Browse files Browse the repository at this point in the history
…nd display correct value
  • Loading branch information
TheTechnician27 committed Jan 8, 2025
1 parent 4dafea6 commit d7898dc
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 9 deletions.
10 changes: 6 additions & 4 deletions pcsx2/ImGui/ImGuiOverlays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
#include <tuple>
#include <unordered_map>

InputRecordingUI::InputRecordingData g_InputRecordingData;

namespace ImGuiManager
{
static void FormatProcessorStat(SmallStringBase& text, double usage, double time);
Expand Down Expand Up @@ -680,7 +682,7 @@ __ri void ImGuiManager::DrawInputRecordingOverlay(float& position_y, float scale
} while (0)

// Status Indicators
if (g_InputRecording.getControls().isRecording())
if (g_InputRecordingData.is_recording)
{
DRAW_LINE(standard_font, TinyString::from_format(TRANSLATE_FS("ImGuiOverlays", "{} Recording Input"), ICON_PF_CIRCLE).c_str(), IM_COL32(255, 0, 0, 255));
}
Expand All @@ -690,9 +692,9 @@ __ri void ImGuiManager::DrawInputRecordingOverlay(float& position_y, float scale
}

// Input Recording Metadata
DRAW_LINE(fixed_font, TinyString::from_format(TRANSLATE_FS("ImGuiOverlays", "Input Recording Active: {}"), g_InputRecording.getData().getFilename()).c_str(), IM_COL32(117, 255, 241, 255));
DRAW_LINE(fixed_font, TinyString::from_format(TRANSLATE_FS("ImGuiOverlays", "Frame: {}/{} ({})"), g_InputRecording.getFrameCounter() + 1, g_InputRecording.getData().getTotalFrames(), g_FrameCount).c_str(), IM_COL32(117, 255, 241, 255));
DRAW_LINE(fixed_font, TinyString::from_format(TRANSLATE_FS("ImGuiOverlays", "Undo Count: {}"), g_InputRecording.getData().getUndoCount()).c_str(), IM_COL32(117, 255, 241, 255));
DRAW_LINE(fixed_font, g_InputRecordingData.recording_active_message.c_str(), IM_COL32(117, 255, 241, 255));
DRAW_LINE(fixed_font, g_InputRecordingData.frame_data_message.c_str(), IM_COL32(117, 255, 241, 255));
DRAW_LINE(fixed_font, g_InputRecordingData.undo_count_message.c_str(), IM_COL32(117, 255, 241, 255));

#undef DRAW_LINE
}
Expand Down
13 changes: 13 additions & 0 deletions pcsx2/ImGui/ImGuiOverlays.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,16 @@ namespace SaveStateSelectorUI
void LoadCurrentSlot();
void SaveCurrentSlot();
} // namespace SaveStateSelectorUI

namespace InputRecordingUI
{
struct InputRecordingData
{
bool is_recording = false;
TinyString recording_active_message = "";
TinyString frame_data_message = "";
TinyString undo_count_message = "";
};
}

extern InputRecordingUI::InputRecordingData g_InputRecordingData;
39 changes: 37 additions & 2 deletions pcsx2/Recording/InputRecording.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ bool SaveStateBase::InputRecordingFreeze()
#include "Counters.h"
#include "SaveState.h"
#include "VMManager.h"
#include "Host.h"
#include "ImGui/ImGuiOverlays.h"
#include "DebugTools/Debug.h"
#include "GameDatabase.h"
#include "fmt/format.h"
Expand Down Expand Up @@ -237,8 +239,9 @@ void InputRecording::incFrameCounter()

if (m_controls.isReplaying())
{
InformGSThread();
// If we've reached the end of the recording while replaying, pause
if (m_frame_counter == m_file.getTotalFrames() - 1)
if (m_frame_counter == m_file.getTotalFrames())
{
VMManager::SetPaused(true);
// Can also stop watching for re-records, they've watched to the end of the recording
Expand All @@ -247,6 +250,7 @@ void InputRecording::incFrameCounter()
}
if (m_controls.isRecording())
{
m_frame_counter_stateless++;
m_file.setTotalFrames(m_frame_counter);
// If we've been in record mode and moved to the next frame, we've overrote something
// if this was following a save-state loading, this is considered a re-record, a.k.a an undo
Expand All @@ -255,14 +259,20 @@ void InputRecording::incFrameCounter()
m_file.incrementUndoCount();
m_watching_for_rerecords = false;
}
InformGSThread();
}
}

u64 InputRecording::getFrameCounter() const
u32 InputRecording::getFrameCounter() const
{
return m_frame_counter;
}

u32 InputRecording::getFrameCounterStateless() const
{
return m_frame_counter_stateless;
}

bool InputRecording::isActive() const
{
return m_is_active;
Expand Down Expand Up @@ -320,6 +330,12 @@ void InputRecording::setStartingFrame(u32 startingFrame)
}
InputRec::consoleLog(fmt::format("Internal Starting Frame: {}", startingFrame));
m_starting_frame = startingFrame;
InformGSThread();
}

u32 InputRecording::getStartingFrame()
{
return m_starting_frame;
}

void InputRecording::adjustFrameCounterOnReRecord(u32 newFrameCounter)
Expand Down Expand Up @@ -351,6 +367,9 @@ void InputRecording::adjustFrameCounterOnReRecord(u32 newFrameCounter)
getControls().setReplayMode();
}
m_frame_counter = newFrameCounter - m_starting_frame;
m_frame_counter_stateless--;
m_file.setTotalFrames(m_frame_counter);
InformGSThread();
}

InputRecordingControls& InputRecording::getControls()
Expand All @@ -367,4 +386,20 @@ void InputRecording::initializeState()
{
m_frame_counter = 0;
m_watching_for_rerecords = false;
InformGSThread();
}

void InputRecording::InformGSThread()
{
TinyString recording_active_message = TinyString::from_format(TRANSLATE_FS("InputRecording", "Input Recording Active: {}"), g_InputRecording.getData().getFilename());
TinyString frame_data_message = TinyString::from_format(TRANSLATE_FS("InputRecording", "Frame: {}/{} ({})"), g_InputRecording.getFrameCounter(), g_InputRecording.getData().getTotalFrames(), g_InputRecording.getFrameCounterStateless());
TinyString undo_count_message = TinyString::from_format(TRANSLATE_FS("InputRecording", "Undo Count: {}"), g_InputRecording.getData().getUndoCount());

MTGS::RunOnGSThread([recording_active_message, frame_data_message, undo_count_message](bool is_recording = g_InputRecording.getControls().isRecording())
{
g_InputRecordingData.is_recording = is_recording;
g_InputRecordingData.recording_active_message = recording_active_message;
g_InputRecordingData.frame_data_message = frame_data_message;
g_InputRecordingData.undo_count_message = undo_count_message;
});
}
9 changes: 7 additions & 2 deletions pcsx2/Recording/InputRecording.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,19 @@ class InputRecording
bool play(const std::string& path);
void stop();

static void InformGSThread();
void handleControllerDataUpdate();
void saveControllerData(const PadData& data, const int port, const int slot);
std::optional<PadData> updateControllerData(const int port, const int slot);
void incFrameCounter();
u64 getFrameCounter() const;
u32 getFrameCounter() const;
u32 getFrameCounterStateless() const;
bool isActive() const;
void processRecordQueue();

void setStartingFrame(u32 startingFrame);
u32 getStartingFrame();

void handleExceededFrameCounter();
void handleReset();
void handleLoadingSavestate();
Expand All @@ -53,11 +58,11 @@ class InputRecording
std::queue<std::function<void()>> m_recordingQueue;

u32 m_frame_counter = 0;
u32 m_frame_counter_stateless = 0;
// Either 0 for a power-on movie, or the g_FrameCount that is stored on the starting frame
u32 m_starting_frame = 0;

void initializeState();
void setStartingFrame(u32 startingFrame);
void closeActiveFile();
};

Expand Down
7 changes: 6 additions & 1 deletion pcsx2/Recording/InputRecordingFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0+

#include "InputRecordingFile.h"
#include "InputRecording.h"

#include "BuildVersion.h"
#include "Utilities/InputRecordingLogger.h"
Expand Down Expand Up @@ -89,6 +90,7 @@ void InputRecordingFile::incrementUndoCount()
}
fseek(m_recordingFile, s_seekpointUndoCount, SEEK_SET);
fwrite(&m_undoCount, 4, 1, m_recordingFile);
InputRecording::InformGSThread();
}

bool InputRecordingFile::openNew(const std::string& path, bool fromSavestate)
Expand All @@ -104,6 +106,7 @@ bool InputRecordingFile::openNew(const std::string& path, bool fromSavestate)
m_undoCount = 0;
m_header.init();
m_savestate = fromSavestate;
InputRecording::InformGSThread();
return true;
}

Expand All @@ -123,6 +126,7 @@ bool InputRecordingFile::openExisting(const std::string& path)
}

m_filename = path;
InputRecording::InformGSThread();
return true;
}

Expand All @@ -147,13 +151,14 @@ std::optional<PadData> InputRecordingFile::readPadData(const uint frame, const u

void InputRecordingFile::setTotalFrames(u32 frame)
{
if (m_recordingFile == nullptr || m_totalFrames >= frame)
if (m_recordingFile == nullptr)
{
return;
}
m_totalFrames = frame;
fseek(m_recordingFile, s_seekpointTotalFrames, SEEK_SET);
fwrite(&m_totalFrames, 4, 1, m_recordingFile);
InputRecording::InformGSThread();
}

bool InputRecordingFile::writeHeader() const
Expand Down

0 comments on commit d7898dc

Please sign in to comment.