diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 5b6294d2c7..cce3576100 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -48,6 +48,7 @@ #include "Core/HW/VideoInterface.h" #include "Core/HW/Wiimote.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" +#include "Core/IPC_HLE/WII_Socket.h" #include "Core/PowerPC/PowerPC.h" #ifdef USE_GDBSTUB @@ -65,6 +66,8 @@ bool g_aspect_wide; namespace Core { +bool g_want_determinism; + // Declarations and definitions static Common::Timer s_timer; static volatile u32 s_drawn_frame = 0; @@ -177,6 +180,8 @@ bool Init() s_emu_thread.join(); } + Core::UpdateWantDeterminism(/*initial*/ true); + INFO_LOG(OSREPORT, "Starting core = %s mode", _CoreParameter.bWii ? "Wii" : "GameCube"); INFO_LOG(OSREPORT, "CPU Thread separate = %s", @@ -564,6 +569,9 @@ void RequestRefreshInfo() bool PauseAndLock(bool doLock, bool unpauseOnUnlock) { + if (!IsRunning()) + return true; + // let's support recursive locking to simplify things on the caller's side, // and let's do it at this outer level in case the individual systems don't support it. if (doLock ? s_pause_and_lock_depth++ : --s_pause_and_lock_depth) @@ -702,4 +710,27 @@ void SetOnStoppedCallback(StoppedCallbackFunc callback) s_on_stopped_callback = callback; } +void UpdateWantDeterminism(bool initial) +{ + // For now, this value is not itself configurable. Instead, individual + // settings that depend on it, such as GPU determinism mode. should have + // override options for testing, + bool new_want_determinism = + Movie::IsPlayingInput() || + Movie::IsRecordingInput() || + NetPlay::IsNetPlayRunning(); + if (new_want_determinism != g_want_determinism || initial) + { + WARN_LOG(COMMON, "Want determinism <- %s", new_want_determinism ? "true" : "false"); + + bool was_unpaused = Core::PauseAndLock(true); + + g_want_determinism = new_want_determinism; + WiiSockMan::GetInstance().UpdateWantDeterminism(new_want_determinism); + g_video_backend->UpdateWantDeterminism(new_want_determinism); + + Core::PauseAndLock(false, was_unpaused); + } +} + } // Core diff --git a/Source/Core/Core/Core.h b/Source/Core/Core/Core.h index 2e9ccddfca..08ed7f1081 100644 --- a/Source/Core/Core/Core.h +++ b/Source/Core/Core/Core.h @@ -23,6 +23,8 @@ extern bool g_aspect_wide; namespace Core { +extern bool g_want_determinism; + bool GetIsFramelimiterTempDisabled(); void SetIsFramelimiterTempDisabled(bool disable); @@ -79,4 +81,7 @@ bool PauseAndLock(bool doLock, bool unpauseOnUnlock=true); typedef void(*StoppedCallbackFunc)(void); void SetOnStoppedCallback(StoppedCallbackFunc callback); +// Run on the GUI thread when the factors change. +void UpdateWantDeterminism(bool initial = false); + } // namespace diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index cc3e5cdcf0..da24bbb280 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -331,7 +331,7 @@ bool Wiimote::Step() m_rumble->controls[0]->control_ref->State(m_rumble_on); // when a movie is active, this button status update is disabled (moved), because movies only record data reports. - if (!(Movie::IsMovieActive()) || NetPlay::IsNetPlayRunning()) + if (!Core::g_want_determinism) { UpdateButtonsStatus(); } @@ -385,7 +385,7 @@ void Wiimote::UpdateButtonsStatus() void Wiimote::GetCoreData(u8* const data) { // when a movie is active, the button update happens here instead of Wiimote::Step, to avoid potential desync issues. - if (Movie::IsMovieActive() || NetPlay::IsNetPlayRunning()) + if (Core::g_want_determinism) { UpdateButtonsStatus(); } diff --git a/Source/Core/Core/IPC_HLE/WII_Socket.cpp b/Source/Core/Core/IPC_HLE/WII_Socket.cpp index ce46a0fb3a..b5a130c2c6 100644 --- a/Source/Core/Core/IPC_HLE/WII_Socket.cpp +++ b/Source/Core/Core/IPC_HLE/WII_Socket.cpp @@ -4,8 +4,7 @@ #include -#include "Core/Movie.h" -#include "Core/NetPlayProto.h" +#include "Core/Core.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device.h" #include "Core/IPC_HLE/WII_Socket.h" // No Wii socket support while using NetPlay or TAS @@ -559,9 +558,7 @@ void WiiSockMan::AddSocket(s32 fd) s32 WiiSockMan::NewSocket(s32 af, s32 type, s32 protocol) { - if (NetPlay::IsNetPlayRunning() || - Movie::IsRecordingInput() || - Movie::IsPlayingInput()) + if (Core::g_want_determinism) { return SO_ENOMEM; } @@ -664,5 +661,12 @@ void WiiSockMan::Convert(sockaddr_in const & from, WiiSockAddrIn& to, s32 addrle to.len = addrlen; } +void WiiSockMan::UpdateWantDeterminism(bool want) +{ + // If we switched into movie recording, kill existing sockets. + if (want) + Clean(); +} + #undef ERRORCODE #undef EITHER diff --git a/Source/Core/Core/IPC_HLE/WII_Socket.h b/Source/Core/Core/IPC_HLE/WII_Socket.h index f9b72f5425..abed7d9f29 100644 --- a/Source/Core/Core/IPC_HLE/WII_Socket.h +++ b/Source/Core/Core/IPC_HLE/WII_Socket.h @@ -242,6 +242,8 @@ public: } } + void UpdateWantDeterminism(bool want); + private: WiiSockMan() = default; diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index 5cba50a883..a06a7ca25b 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -437,6 +437,8 @@ bool BeginRecordingInput(int controllers) if (s_playMode != MODE_NONE || controllers == 0) return false; + bool was_unpaused = Core::PauseAndLock(true); + s_numPads = controllers; g_currentFrame = g_totalFrames = 0; g_currentLagCount = s_totalLagCount = 0; @@ -487,6 +489,10 @@ bool BeginRecordingInput(int controllers) s_currentByte = s_totalBytes = 0; + Core::UpdateWantDeterminism(); + + Core::PauseAndLock(false, was_unpaused); + Core::DisplayMessage("Starting movie recording", 2000); return true; } @@ -764,6 +770,8 @@ bool PlayInput(const std::string& filename) s_playMode = MODE_PLAYING; + Core::UpdateWantDeterminism(); + s_totalBytes = g_recordfd.GetSize() - 256; EnsureTmpInputSize((size_t)s_totalBytes); g_recordfd.ReadArray(tmpInput, (size_t)s_totalBytes); @@ -1097,6 +1105,7 @@ void EndPlayInput(bool cont) s_rerecords = 0; s_currentByte = 0; s_playMode = MODE_NONE; + Core::UpdateWantDeterminism(); Core::DisplayMessage("Movie End.", 2000); s_bRecordingFromSaveState = false; // we don't clear these things because otherwise we can't resume playback if we load a movie state later diff --git a/Source/Core/VideoCommon/Fifo.cpp b/Source/Core/VideoCommon/Fifo.cpp index 87764ec85c..a47438c41e 100644 --- a/Source/Core/VideoCommon/Fifo.cpp +++ b/Source/Core/VideoCommon/Fifo.cpp @@ -11,13 +11,16 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" +#include "Core/NetPlayProto.h" #include "Core/HW/Memmap.h" #include "VideoCommon/CommandProcessor.h" +#include "VideoCommon/CPMemory.h" #include "VideoCommon/DataReader.h" #include "VideoCommon/Fifo.h" #include "VideoCommon/OpcodeDecoding.h" #include "VideoCommon/PixelEngine.h" +#include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VideoConfig.h" bool g_bSkipCurrentFrame = false; @@ -31,7 +34,7 @@ static u8 s_fifo_aux_data[FIFO_SIZE]; static u8* s_fifo_aux_write_ptr; static u8* s_fifo_aux_read_ptr; -bool g_use_deterministic_gpu_thread = true; // XXX +bool g_use_deterministic_gpu_thread; // STATE_TO_SAVE static std::mutex s_video_buffer_lock; @@ -413,3 +416,26 @@ void RunGpu() } CommandProcessor::SetCPStatusFromGPU(); } + +void Fifo_UpdateWantDeterminism(bool want) +{ + // We are paused (or not running at all yet) and have m_csHWVidOccupied, so + // it should be safe to change this. + g_use_deterministic_gpu_thread = want && SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread; + + // Hack: For now movies are an exception to this being on (but not + // to wanting determinism in general). Once vertex arrays are + // fixed, there should be no reason to want this off for movies by + // default, so this can be removed. + if (NetPlay::IsNetPlayRunning()) + g_use_deterministic_gpu_thread = false; + + if (g_use_deterministic_gpu_thread) + { + // These haven't been updated in non-deterministic mode. + s_video_buffer_seen_ptr = g_video_buffer_pp_read_ptr = g_video_buffer_read_ptr; + CopyPreprocessCPStateFromMain(); + VertexLoaderManager::MarkAllDirty(); + } + +} diff --git a/Source/Core/VideoCommon/Fifo.h b/Source/Core/VideoCommon/Fifo.h index 175d6b6e4a..40a5ad84b7 100644 --- a/Source/Core/VideoCommon/Fifo.h +++ b/Source/Core/VideoCommon/Fifo.h @@ -27,6 +27,7 @@ u8* GetVideoBufferEndPtr(); void Fifo_DoState(PointerWrap &f); void Fifo_PauseAndLock(bool doLock, bool unpauseOnUnlock); +void Fifo_UpdateWantDeterminism(bool want); // Used for diagnostics. enum SyncGPUReason { diff --git a/Source/Core/VideoCommon/MainBase.cpp b/Source/Core/VideoCommon/MainBase.cpp index 082c81c2ea..d775cfe64c 100644 --- a/Source/Core/VideoCommon/MainBase.cpp +++ b/Source/Core/VideoCommon/MainBase.cpp @@ -309,3 +309,8 @@ void VideoBackendHardware::RegisterCPMMIO(MMIO::Mapping* mmio, u32 base) CommandProcessor::RegisterMMIO(mmio, base); } +void VideoBackendHardware::UpdateWantDeterminism(bool want) +{ + Fifo_UpdateWantDeterminism(want); +} + diff --git a/Source/Core/VideoCommon/VideoBackendBase.h b/Source/Core/VideoCommon/VideoBackendBase.h index 6ab9fce8f2..7d62dda37b 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.h +++ b/Source/Core/VideoCommon/VideoBackendBase.h @@ -116,6 +116,8 @@ public: virtual void DoState(PointerWrap &p) = 0; virtual void CheckInvalidState() = 0; + + virtual void UpdateWantDeterminism(bool want) {} }; extern std::vector g_available_video_backends; @@ -151,6 +153,8 @@ class VideoBackendHardware : public VideoBackend void PauseAndLock(bool doLock, bool unpauseOnUnlock=true) override; void DoState(PointerWrap &p) override; + void UpdateWantDeterminism(bool want) override; + bool m_invalid; public: