input-rec: fix running input recording functions from UI thread

This commit is contained in:
Tyler Wilding 2022-06-23 17:29:45 -04:00 committed by refractionpcsx2
parent 6ae9e7edb5
commit 844ff5bb04
6 changed files with 90 additions and 87 deletions

View File

@ -1638,7 +1638,7 @@ void MainWindow::onInputRecNewActionTriggered()
const bool wasRunning = s_vm_valid;
if (wasRunning && !wasPaused)
{
VMManager::SetPaused(true);
g_emu_thread->setVMPaused(true);
}
NewInputRecordingDlg dlg(this);
@ -1646,20 +1646,26 @@ void MainWindow::onInputRecNewActionTriggered()
if (result == QDialog::Accepted)
{
if (g_InputRecording.create(
dlg.getFilePath(),
dlg.getInputRecType() == InputRecording::Type::FROM_SAVESTATE,
dlg.getAuthorName()))
{
m_ui.actionInputRecNew->setEnabled(false);
m_ui.actionInputRecStop->setEnabled(true);
return;
}
Host::RunOnCPUThread([&, filePath = dlg.getFilePath(),
fromSavestate = dlg.getInputRecType() == InputRecording::Type::FROM_SAVESTATE,
authorName = dlg.getAuthorName()]() {
if (g_InputRecording.create(
filePath,
fromSavestate,
authorName))
{
QtHost::RunOnUIThread([&]() {
m_ui.actionInputRecNew->setEnabled(false);
m_ui.actionInputRecStop->setEnabled(true);
return;
});
}
});
}
if (wasRunning && !wasPaused)
{
VMManager::SetPaused(false);
g_emu_thread->setVMPaused(false);
}
}
@ -1669,7 +1675,7 @@ void MainWindow::onInputRecPlayActionTriggered()
if (!wasPaused)
{
VMManager::SetPaused(true);
g_emu_thread->setVMPaused(true);
}
QFileDialog dialog(this);
@ -1685,7 +1691,7 @@ void MainWindow::onInputRecPlayActionTriggered()
{
if (!wasPaused)
{
VMManager::SetPaused(false);
g_emu_thread->setVMPaused(false);
return;
}
}
@ -1694,14 +1700,22 @@ void MainWindow::onInputRecPlayActionTriggered()
{
if (g_InputRecording.isActive())
{
g_InputRecording.stop();
Host::RunOnCPUThread([]() {
g_InputRecording.stop();
});
m_ui.actionInputRecStop->setEnabled(false);
}
if (g_InputRecording.play(fileNames.first().toStdString()))
{
m_ui.actionInputRecStop->setEnabled(true);
return;
}
Host::RunOnCPUThread([&, filename = fileNames.first().toStdString()]() {
if (g_InputRecording.play(filename))
{
QtHost::RunOnUIThread([&]() {
m_ui.actionInputRecStop->setEnabled(true);
return;
});
m_ui.actionInputRecStop->setEnabled(true);
return;
}
});
}
}
@ -1709,9 +1723,13 @@ void MainWindow::onInputRecStopActionTriggered()
{
if (g_InputRecording.isActive())
{
g_InputRecording.stop();
m_ui.actionInputRecNew->setEnabled(true);
m_ui.actionInputRecStop->setEnabled(false);
Host::RunOnCPUThread([&]() {
g_InputRecording.stop();
QtHost::RunOnUIThread([&]() {
m_ui.actionInputRecNew->setEnabled(true);
m_ui.actionInputRecStop->setEnabled(false);
});
});
}
}

View File

@ -842,21 +842,11 @@ void cdvdReset()
// If we are recording, always use the same RTC setting
// for games that use the RTC to seed their RNG -- this is very important to be the same everytime!
#ifndef PCSX2_CORE
if (g_InputRecording.IsActive())
{
Console.WriteLn("Input Recording Active - Using Constant RTC of 04-03-2020 (DD-MM-YYYY)");
// Why not just 0 everything? Some games apparently require the date to be valid in terms of when
// the PS2 / Game actually came out. (MGS3). So set it to a value well beyond any PS2 game's release date.
cdvd.RTC.second = 0;
cdvd.RTC.minute = 0;
cdvd.RTC.hour = 0;
cdvd.RTC.day = 4;
cdvd.RTC.month = 3;
cdvd.RTC.year = 20;
}
else
const bool input_recording_active = g_InputRecording.IsActive();
#else
if (g_InputRecording.isActive())
const bool input_recording_active = g_InputRecording.isActive();
#endif
if (input_recording_active)
{
Console.WriteLn("Input Recording Active - Using Constant RTC of 04-03-2020 (DD-MM-YYYY)");
// Why not just 0 everything? Some games apparently require the date to be valid in terms of when
@ -869,7 +859,6 @@ void cdvdReset()
cdvd.RTC.year = 20;
}
else
#endif
{
// CDVD internally uses GMT+9. If you think the time's wrong, you're wrong.
// Set up your time zone and winter/summer in the BIOS. No PS2 BIOS I know of features automatic DST.

View File

@ -482,7 +482,6 @@ void ImGuiManager::DrawInputRecordingOverlay()
dl->AddText(font, font->FontSize, ImVec2(ImGui::GetIO().DisplaySize.x - margin - text_size.x, position_y), color, (text)); \
position_y += text_size.y + spacing; \
} while (0)
// TODO - is there a way to forcibly update the imgui frame without requiring to wait until the next vsync?
// TODO - icon list that would be nice to add
// - 'video' when screen capturing
if (g_InputRecording.isActive())
@ -490,7 +489,7 @@ void ImGuiManager::DrawInputRecordingOverlay()
// Status Indicators
if (g_InputRecording.getControls().isRecording())
{
DRAW_LINE(standard_font, fmt::format("{} Recording", ICON_FA_CIRCLE).c_str(), IM_COL32(255, 0, 0, 255));
DRAW_LINE(standard_font, fmt::format("{} Recording", ICON_FA_RECORD_VINYL).c_str(), IM_COL32(255, 0, 0, 255));
}
else
{

View File

@ -517,17 +517,17 @@ bool InputRecording::create(const std::string_view& fileName, const bool fromSav
{
FileSystem::CopyFilePath(savestatePath.c_str(), fmt::format("{}.bak", savestatePath).c_str(), true);
}
m_initialSavestateLoadComplete = false;
m_initial_savestate_load_complete = false;
m_type = Type::FROM_SAVESTATE;
m_isActive = true;
m_is_active = true;
// TODO - error handling
VMManager::SaveState(savestatePath.c_str());
}
else
{
m_startingFrame = 0;
m_starting_frame = 0;
m_type = Type::POWER_ON;
m_isActive = true;
m_is_active = true;
// TODO - should this be an explicit [full] boot instead of a reset?
VMManager::Reset();
}
@ -561,22 +561,22 @@ bool InputRecording::play(const std::string_view& filename)
return false;
}
m_type = Type::FROM_SAVESTATE;
m_initialSavestateLoadComplete = false;
m_isActive = true;
m_initial_savestate_load_complete = false;
m_is_active = true;
const auto loaded = VMManager::LoadState(savestatePath.c_str());
if (!loaded)
{
InputRec::log("Savestate load failed, unsupported version?");
m_file.Close();
m_isActive = false;
m_is_active = false;
return false;
}
}
else
{
m_startingFrame = 0;
m_starting_frame = 0;
m_type = Type::POWER_ON;
m_isActive = true;
m_is_active = true;
// TODO - should this be an explicit [full] boot instead of a reset?
VMManager::Reset();
}
@ -594,7 +594,7 @@ bool InputRecording::play(const std::string_view& filename)
void InputRecording::stop()
{
m_isActive = false;
m_is_active = false;
if (m_file.Close())
{
InputRec::log("Input recording stopped");
@ -614,15 +614,15 @@ void InputRecording::ControllerInterrupt(u8 port, size_t fifoSize, u8 dataIn, u8
}
// If there is data to read (previous two bytes looked correct)
if (bufCount >= 3 && m_padDataAvailable)
if (bufCount >= 3 && m_pad_data_available)
{
u8& bufVal = dataOut;
const u16 bufIndex = fifoSize - 3;
if (state == InputRecordingMode::Replaying)
{
if (!m_file.ReadKeyBuffer(bufVal, m_frameCounter, port, bufIndex))
if (!m_file.ReadKeyBuffer(bufVal, m_frame_counter, port, bufIndex))
{
InputRec::consoleLog(fmt::format("Failed to read input data at frame {}", m_frameCounter));
InputRec::consoleLog(fmt::format("Failed to read input data at frame {}", m_frame_counter));
}
// Update controller data state for future VirtualPad / logging usage.
//pads[port].padData->UpdateControllerData(bufIndex, bufVal);
@ -635,16 +635,16 @@ void InputRecording::ControllerInterrupt(u8 port, size_t fifoSize, u8 dataIn, u8
// Commit the byte to the movie file if we are recording
if (m_controls.isRecording())
{
if (!m_file.WriteKeyBuffer(m_frameCounter, port, bufIndex, bufVal))
if (!m_file.WriteKeyBuffer(m_frame_counter, port, bufIndex, bufVal))
{
InputRec::consoleLog(fmt::format("Failed to write input data at frame {}", m_frameCounter));
InputRec::consoleLog(fmt::format("Failed to write input data at frame {}", m_frame_counter));
}
}
}
}
if (bufCount > 20)
{
m_padDataAvailable = false;
m_pad_data_available = false;
}
}
@ -665,51 +665,51 @@ std::string InputRecording::resolveGameName()
void InputRecording::incFrameCounter()
{
if (m_frameCounter >= std::numeric_limits<u64>::max())
if (m_frame_counter >= std::numeric_limits<u64>::max())
{
// TODO - log the incredible achievment of playing for longer than 4 billion years, and end the recording
stop();
return;
}
m_frameCounter++;
m_frame_counter++;
if (m_controls.isReplaying())
{
// If we've reached the end of the recording while replaying, pause
if (m_frameCounter == m_file.getTotalFrames() - 1)
if (m_frame_counter == m_file.getTotalFrames() - 1)
{
VMManager::SetPaused(true);
// Can also stop watching for re-records, they've watched to the end of the recording
m_watchingForRerecords = false;
m_watching_for_rerecords = false;
}
}
if (m_controls.isRecording())
{
m_file.SetTotalFrames(m_frameCounter);
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
if (m_watchingForRerecords)
if (m_watching_for_rerecords)
{
m_file.IncrementUndoCount();
m_watchingForRerecords = false;
m_watching_for_rerecords = false;
}
}
}
u64 InputRecording::getFrameCounter() const
{
return m_frameCounter;
return m_frame_counter;
}
bool InputRecording::isActive() const
{
return m_isActive;
return m_is_active;
}
void InputRecording::handleExceededFrameCounter()
{
// if we go past the end, switch to recording mode so nothing is lost
if (m_frameCounter >= m_file.getTotalFrames() && m_controls.isReplaying())
if (m_frame_counter >= m_file.getTotalFrames() && m_controls.isReplaying())
{
m_controls.setRecordMode(false);
}
@ -724,15 +724,15 @@ void InputRecording::handleLoadingSavestate()
// Why?
// - When you re-record you load another save-state which has it's own frame counter
// stored within, we use this to adjust the frame we are replaying/recording to
if (isTypeSavestate() && !m_initialSavestateLoadComplete)
if (isTypeSavestate() && !m_initial_savestate_load_complete)
{
setStartingFrame(g_FrameCount);
m_initialSavestateLoadComplete = true;
m_initial_savestate_load_complete = true;
}
else
{
adjustFrameCounterOnReRecord(g_FrameCount);
m_watchingForRerecords = true;
m_watching_for_rerecords = true;
}
}
@ -748,27 +748,27 @@ void InputRecording::setStartingFrame(u64 startingFrame)
return;
}
InputRec::consoleLog(fmt::format("Internal Starting Frame: {}", startingFrame));
m_startingFrame = startingFrame;
m_starting_frame = startingFrame;
}
void InputRecording::adjustFrameCounterOnReRecord(u64 newFrameCounter)
{
if (newFrameCounter > m_startingFrame + (u64)m_file.getTotalFrames())
if (newFrameCounter > m_starting_frame + (u64)m_file.getTotalFrames())
{
InputRec::consoleLog("Warning, you've loaded PCSX2 emulation to a point after the end of the original recording. This should be avoided.");
InputRec::consoleLog("Savestate's framecount has been ignored, using the max length of the recording instead.");
m_frameCounter = m_file.getTotalFrames();
m_frame_counter = m_file.getTotalFrames();
if (getControls().isReplaying())
{
getControls().setRecordMode();
}
return;
}
if (newFrameCounter < m_startingFrame)
if (newFrameCounter < m_starting_frame)
{
InputRec::consoleLog("Warning, you've loaded PCSX2 emulation to a point before the start of the original recording. This should be avoided.");
InputRec::consoleLog("Savestate's framecount has been ignored, starting from the beginning in replay mode.");
m_frameCounter = 0;
m_frame_counter = 0;
if (getControls().isRecording())
{
getControls().setReplayMode();
@ -779,7 +779,7 @@ void InputRecording::adjustFrameCounterOnReRecord(u64 newFrameCounter)
{
getControls().setReplayMode();
}
m_frameCounter = newFrameCounter - m_startingFrame;
m_frame_counter = newFrameCounter - m_starting_frame;
}
InputRecordingControls& InputRecording::getControls()
@ -794,8 +794,8 @@ const InputRecordingFile& InputRecording::getData() const
void InputRecording::initializeState()
{
m_frameCounter = 0;
m_watchingForRerecords = false;
m_frame_counter = 0;
m_watching_for_rerecords = false;
}
#endif

View File

@ -194,14 +194,14 @@ private:
Type m_type;
bool m_initialSavestateLoadComplete = false;
bool m_isActive = false;
bool m_padDataAvailable = false;
bool m_watchingForRerecords = false;
bool m_initial_savestate_load_complete = false;
bool m_is_active = false;
bool m_pad_data_available = false;
bool m_watching_for_rerecords = false;
u64 m_frameCounter = 0;
u64 m_frame_counter = 0;
// Either 0 for a power-on movie, or the g_FrameCount that is stored on the starting frame
u64 m_startingFrame = 0;
u64 m_starting_frame = 0;
void initializeState();
void setStartingFrame(u64 startingFrame);

View File

@ -227,13 +227,10 @@ void InputRecordingControls::StopCapture() const
#include "VMManager.h"
// TODO - update ImGUI when controls are changed - `GetMTGS().PresentCurrentFrame()`, becareful about only running it on the emu/cpu thread
void InputRecordingControls::toggleRecordMode()
{
// TODO - this needs to be fixed
// NOTE - delete logic here that prevented switching to replay immediately until frame was complete
// Has to be a better new way to do such a thing
//
// Set a lambda (or list of lambdas) to be executed on the next vsync perhaps?
if (isReplaying())
{
setRecordMode();