From 3f0655c8210eb32630d37ea3cb947e6afb0be605 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Sun, 3 Jul 2016 10:54:12 +0200 Subject: [PATCH] MTVU: port write pointer to atomic and optimize atomic access Write pointer can be relaxed-read from the EE thread Read pointer can be relaxed-read from the VU thread Warning: AtomicExchange calls were replaced by release-store However AtomicExchange generates a memory barrier (at least on linux) So either it is useless and it will be faster, or it will explode ;) --- pcsx2/MTVU.cpp | 34 +++++++++++++++++----------------- pcsx2/MTVU.h | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/pcsx2/MTVU.cpp b/pcsx2/MTVU.cpp index 7a2fd4a7be..875e38a672 100644 --- a/pcsx2/MTVU.cpp +++ b/pcsx2/MTVU.cpp @@ -75,11 +75,11 @@ void VU_Thread::Reset() { ScopedLock lock(mtxBusy); - write_pos = 0; write_offset = 0; vuCycleIdx = 0; read_pos = 0; isBusy = false; + write_pos = 0; memzero(vif); memzero(vifRegs); memzero(vuCycles); @@ -97,7 +97,7 @@ void VU_Thread::ExecuteRingBuffer() for(;;) { semaEvent.WaitWithoutYield(); ScopedLockBool lock(mtxBusy, isBusy); - while (read_pos != GetWritePos()) { + while (read_pos.load(std::memory_order_relaxed) != GetWritePos()) { u32 tag = Read(); switch (tag) { case MTVU_VU_EXECUTE: { @@ -137,12 +137,12 @@ void VU_Thread::ExecuteRingBuffer() Read(&vif.tag, vif_copy_size); ReadRegs(&vifRegs); u32 size = Read(); - MTVU_Unpack(&buffer[read_pos], vifRegs); + MTVU_Unpack(&buffer[read_pos.load(std::memory_order_relaxed)], vifRegs); incReadPos(size_u32(size)); break; } case MTVU_NULL_PACKET: - read_pos = 0; + read_pos.store(0, std::memory_order_release); break; jNO_DEFAULT; } @@ -156,8 +156,8 @@ __ri void VU_Thread::WaitOnSize(s32 size) { for(;;) { s32 readPos = GetReadPos(); - if (readPos <= write_pos) break; // MTVU is reading in back of write_pos - if (readPos > write_pos + size) break; // Enough free front space + if (readPos <= write_pos.load(std::memory_order_relaxed)) break; // MTVU is reading in back of write_pos + if (readPos > write_pos.load(std::memory_order_relaxed) + size) break; // Enough free front space if (1) { // Let MTVU run to free up buffer space KickStart(); if (IsDevBuild) DevCon.WriteLn("WaitOnSize()"); @@ -174,12 +174,12 @@ void VU_Thread::ReserveSpace(s32 size) pxAssert(size < buffer_size); pxAssert(size > 0); pxAssert(write_offset == 0); - if (write_pos + size > buffer_size) { + if (write_pos.load(std::memory_order_relaxed) + size > buffer_size) { pxAssert(write_pos > 0); WaitOnSize(1); // Size of MTVU_NULL_PACKET Write(MTVU_NULL_PACKET); write_offset = 0; - AtomicExchange(volatize(write_pos), 0); + write_pos.store(0, std::memory_order_release); } WaitOnSize(size); } @@ -187,17 +187,17 @@ void VU_Thread::ReserveSpace(s32 size) // Use this when reading read_pos from ee thread __fi s32 VU_Thread::GetReadPos() { - return read_pos.load(); + return read_pos.load(std::memory_order_acquire); } // Use this when reading write_pos from vu thread __fi s32 VU_Thread::GetWritePos() { - return AtomicRead(volatize(write_pos)); + return write_pos.load(std::memory_order_acquire); } // Gets the effective write pointer after adding write_offset __fi u32* VU_Thread::GetWritePtr() { - return &buffer[(write_pos + write_offset) & buffer_mask]; + return &buffer[(write_pos.load(std::memory_order_relaxed) + write_offset) & buffer_mask]; } __fi void VU_Thread::incReadPos(s32 offset) @@ -206,29 +206,29 @@ __fi void VU_Thread::incReadPos(s32 offset) } __fi void VU_Thread::incWritePos() { // Adds write_offset - s32 temp = (write_pos + write_offset) & buffer_mask; + s32 temp = (write_pos.load(std::memory_order_relaxed) + write_offset) & buffer_mask; write_offset = 0; - AtomicExchange(volatize(write_pos), temp); + write_pos.store(temp, std::memory_order_release); if (MTVU_ALWAYS_KICK) KickStart(); if (MTVU_SYNC_MODE) WaitVU(); } __fi u32 VU_Thread::Read() { - u32 ret = buffer[read_pos]; + u32 ret = buffer[read_pos.load(std::memory_order_relaxed)]; incReadPos(1); return ret; } __fi void VU_Thread::Read(void* dest, u32 size) { - memcpy(dest, &buffer[read_pos], size); + memcpy(dest, &buffer[read_pos.load(std::memory_order_relaxed)], size); incReadPos(size_u32(size)); } __fi void VU_Thread::ReadRegs(VIFregisters* dest) { - VIFregistersMTVU* src = (VIFregistersMTVU*)&buffer[read_pos]; + VIFregistersMTVU* src = (VIFregistersMTVU*)&buffer[read_pos.load(std::memory_order_relaxed)]; dest->cycle = src->cycle; dest->mode = src->mode; dest->num = src->num; @@ -272,7 +272,7 @@ u32 VU_Thread::Get_vuCycles() void VU_Thread::KickStart(bool forceKick) { if ((forceKick && !semaEvent.Count()) - || (!isBusy.load(std::memory_order_relaxed) && GetReadPos() != write_pos)) semaEvent.Post(); + || (!isBusy.load(std::memory_order_relaxed) && GetReadPos() != write_pos.load(std::memory_order_relaxed))) semaEvent.Post(); } bool VU_Thread::IsDone() diff --git a/pcsx2/MTVU.h b/pcsx2/MTVU.h index 8db6cde720..e6e045c04b 100644 --- a/pcsx2/MTVU.h +++ b/pcsx2/MTVU.h @@ -32,7 +32,7 @@ class VU_Thread : public pxThread { __aligned(4) u32 buffer[buffer_size]; std::atomic read_pos; // Only modified by VU thread std::atomic isBusy; // Is thread processing data? - __aligned(4) s32 write_pos; // Only modified by EE thread + std::atomic write_pos; // Only modified by EE thread __aligned(4) s32 write_offset; // Only modified by EE thread __aligned(4) Mutex mtxBusy; __aligned(4) Semaphore semaEvent;