From 599626b7097656569a1a2af03dfb21e394a5cd4c Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Thu, 5 May 2022 07:55:16 +1000 Subject: [PATCH] MTVU: Purge pxThread --- pcsx2/MTVU.cpp | 73 ++++++++++++++++++++-------------- pcsx2/MTVU.h | 31 ++++++++++----- pcsx2/PerformanceMetrics.cpp | 4 +- pcsx2/System/SysCoreThread.cpp | 3 +- pcsx2/x86/microVU.cpp | 2 +- 5 files changed, 68 insertions(+), 45 deletions(-) diff --git a/pcsx2/MTVU.cpp b/pcsx2/MTVU.cpp index 46750f2f3b..d8a13729a2 100644 --- a/pcsx2/MTVU.cpp +++ b/pcsx2/MTVU.cpp @@ -18,8 +18,9 @@ #include "MTVU.h" #include "newVif.h" #include "Gif_Unit.h" +#include -VU_Thread vu1Thread(CpuVU1, VU1); +VU_Thread vu1Thread; #define MTVU_ALWAYS_KICK 0 #define MTVU_SYNC_MODE 0 @@ -86,21 +87,35 @@ void SaveStateBase::mtvuFreeze() Freeze(vu1Thread.vuCycleIdx); } -VU_Thread::VU_Thread(BaseVUmicroCPU*& _vuCPU, VURegs& _vuRegs) - : vuCPU(_vuCPU) - , vuRegs(_vuRegs) +VU_Thread::VU_Thread() { - m_name = L"MTVU"; Reset(); } VU_Thread::~VU_Thread() { - try - { - pxThread::Cancel(); - } - DESTRUCTOR_CATCHALL + Close(); +} + +void VU_Thread::Open() +{ + if (m_thread.joinable()) + return; + + Reset(); + semaEvent.Reset(); + m_shutdown_flag.store(false, std::memory_order_release); + m_thread = std::thread(&VU_Thread::ExecuteRingBuffer, this); +} + +void VU_Thread::Close() +{ + if (!m_thread.joinable()) + return; + + m_shutdown_flag.store(true, std::memory_order_release); + semaEvent.NotifyOfWork(); + m_thread.join(); } void VU_Thread::Reset() @@ -117,20 +132,17 @@ void VU_Thread::Reset() vu1Thread.mtvuInterrupts = 0; } -void VU_Thread::ExecuteTaskInThread() -{ - PCSX2_PAGEFAULT_PROTECT - { - ExecuteRingBuffer(); - } - PCSX2_PAGEFAULT_EXCEPT; -} - void VU_Thread::ExecuteRingBuffer() { + m_thread_handle = Threading::ThreadHandle::GetForCallingThread(); + Threading::SetNameOfCurrentThread("MTVU"); + for (;;) { semaEvent.WaitForWork(); + if (m_shutdown_flag.load(std::memory_order_acquire)) + break; + while (m_ato_read_pos.load(std::memory_order_relaxed) != GetWritePos()) { u32 tag = Read(); @@ -138,18 +150,18 @@ void VU_Thread::ExecuteRingBuffer() { case MTVU_VU_EXECUTE: { - vuRegs.cycle = 0; + VU1.cycle = 0; s32 addr = Read(); vifRegs.top = Read(); vifRegs.itop = Read(); vuFBRST = Read(); if (addr != -1) - vuRegs.VI[REG_TPC].UL = addr & 0x7FF; - vuCPU->SetStartPC(vuRegs.VI[REG_TPC].UL << 3); - vuCPU->Execute(vu1RunCycles); + VU1.VI[REG_TPC].UL = addr & 0x7FF; + CpuVU1->SetStartPC(VU1.VI[REG_TPC].UL << 3); + CpuVU1->Execute(vu1RunCycles); gifUnit.gifPath[GIF_PATH_1].FinishGSPacketMTVU(); semaXGkick.Post(); // Tell MTGS a path1 packet is complete - vuCycles[vuCycleIdx].store(vuRegs.cycle, std::memory_order_release); + vuCycles[vuCycleIdx].store(VU1.cycle, std::memory_order_release); vuCycleIdx = (vuCycleIdx + 1) & 3; break; } @@ -157,22 +169,22 @@ void VU_Thread::ExecuteRingBuffer() { u32 vu_micro_addr = Read(); u32 size = Read(); - vuCPU->Clear(vu_micro_addr, size); - Read(&vuRegs.Micro[vu_micro_addr], size); + CpuVU1->Clear(vu_micro_addr, size); + Read(&VU1.Micro[vu_micro_addr], size); break; } case MTVU_VU_WRITE_DATA: { u32 vu_data_addr = Read(); u32 size = Read(); - Read(&vuRegs.Mem[vu_data_addr], size); + Read(&VU1.Mem[vu_data_addr], size); break; } case MTVU_VU_WRITE_VIREGS: - Read(&vuRegs.VI, size_u32(32)); + Read(&VU1.VI, size_u32(32)); break; case MTVU_VU_WRITE_VFREGS: - Read(&vuRegs.VF, size_u32(4*32)); + Read(&VU1.VF, size_u32(4*32)); break; case MTVU_VIF_WRITE_COL: Read(&vif.MaskCol, sizeof(vif.MaskCol)); @@ -199,6 +211,9 @@ void VU_Thread::ExecuteRingBuffer() CommitReadPos(); } } + + m_thread_handle = {}; + semaEvent.Kill(); } diff --git a/pcsx2/MTVU.h b/pcsx2/MTVU.h index d743224199..45f25961f5 100644 --- a/pcsx2/MTVU.h +++ b/pcsx2/MTVU.h @@ -14,11 +14,13 @@ */ #pragma once -#include "System/SysThreads.h" +#include "common/Threading.h" #include "Vif.h" #include "Vif_Dma.h" #include "VUmicro.h" +#include + #define MTVU_LOG(...) do{} while(0) //#define MTVU_LOG DevCon.WriteLn @@ -26,7 +28,7 @@ // - This class should only be accessed from the EE thread... // - buffer_size must be power of 2 // - ring-buffer has no complete pending packets when read_pos==write_pos -class VU_Thread : public pxThread { +class VU_Thread final { static const s32 buffer_size = (_1mb * 16) / sizeof(s32); u32 buffer[buffer_size]; @@ -35,14 +37,16 @@ class VU_Thread : public pxThread { alignas(64) std::atomic m_ato_write_pos; // Only modified by EE thread alignas(64) int m_read_pos; // temporary read pos (local to the VU thread) int m_write_pos; // temporary write pos (local to the EE thread) - WorkSema semaEvent; - BaseVUmicroCPU*& vuCPU; - VURegs& vuRegs; + Threading::WorkSema semaEvent; + std::atomic_bool m_shutdown_flag{false}; + + std::thread m_thread; + Threading::ThreadHandle m_thread_handle; public: alignas(16) vifStruct vif; alignas(16) VIFregisters vifRegs; - Semaphore semaXGkick; + Threading::Semaphore semaXGkick; std::atomic vuCycles[4]; // Used for VU cycle stealing hack u32 vuCycleIdx; // Used for VU cycle stealing hack u32 vuFBRST; @@ -59,8 +63,16 @@ public: std::atomic gsLabel; // Used for GS Label command std::atomic gsSignal; // Used for GS Signal command - VU_Thread(BaseVUmicroCPU*& _vuCPU, VURegs& _vuRegs); - virtual ~VU_Thread(); + VU_Thread(); + ~VU_Thread(); + + __fi const Threading::ThreadHandle& GetThreadHandle() const { return m_thread_handle; } + + /// Ensures the VU thread is started. + void Open(); + + /// Shuts down the VU thread if it is currently running. + void Close(); void Reset(); @@ -93,9 +105,6 @@ public: void WriteRow(vifStruct& _vif); -protected: - void ExecuteTaskInThread(); - private: void ExecuteRingBuffer(); diff --git a/pcsx2/PerformanceMetrics.cpp b/pcsx2/PerformanceMetrics.cpp index 1ff4eb7fb3..74983d712e 100644 --- a/pcsx2/PerformanceMetrics.cpp +++ b/pcsx2/PerformanceMetrics.cpp @@ -119,7 +119,7 @@ void PerformanceMetrics::Reset() s_last_cpu_time = s_cpu_thread_handle.GetCPUTime(); s_last_gs_time = GetMTGS().GetCpuTime(); - s_last_vu_time = THREAD_VU1 ? vu1Thread.GetCpuTime() : 0; + s_last_vu_time = THREAD_VU1 ? vu1Thread.GetThreadHandle().GetCPUTime() : 0; s_last_ticks = GetCPUTicks(); for (GSSWThreadStats& stat : s_gs_sw_threads) @@ -184,7 +184,7 @@ void PerformanceMetrics::Update(bool gs_register_write, bool fb_blit) const u64 cpu_time = s_cpu_thread_handle.GetCPUTime(); const u64 gs_time = GetMTGS().GetCpuTime(); - const u64 vu_time = THREAD_VU1 ? vu1Thread.GetCpuTime() : 0; + const u64 vu_time = THREAD_VU1 ? vu1Thread.GetThreadHandle().GetCPUTime() : 0; const u64 cpu_delta = cpu_time - s_last_cpu_time; const u64 gs_delta = gs_time - s_last_gs_time; diff --git a/pcsx2/System/SysCoreThread.cpp b/pcsx2/System/SysCoreThread.cpp index f2f0d7960b..07afae96a8 100644 --- a/pcsx2/System/SysCoreThread.cpp +++ b/pcsx2/System/SysCoreThread.cpp @@ -368,8 +368,7 @@ void SysCoreThread::OnCleanupInThread() m_resetVirtualMachine = true; R3000A::ioman::reset(); - // FIXME: temporary workaround for deadlock on exit, which actually should be a crash - vu1Thread.WaitVU(); + vu1Thread.Close(); USBclose(); SPU2close(); PADclose(); diff --git a/pcsx2/x86/microVU.cpp b/pcsx2/x86/microVU.cpp index 263b7ea05b..7fd46ea436 100644 --- a/pcsx2/x86/microVU.cpp +++ b/pcsx2/x86/microVU.cpp @@ -371,7 +371,7 @@ void recMicroVU1::Reserve() if (m_Reserved.exchange(1) == 0) { mVUinit(microVU1, 1); - vu1Thread.Start(); + vu1Thread.Open(); } }