mirror of https://github.com/PCSX2/pcsx2.git
input-rec: fix running input recording functions from UI thread
This commit is contained in:
parent
6ae9e7edb5
commit
844ff5bb04
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue