Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ImGui: Make input recording frame count thread-safe #12175

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading