MTVU/MTGS: use a mutex free ring buffer

Most of the time the mutex was likely optimized. Now we have the guarantee that
thread won't block.
This commit is contained in:
Gregory Hainaut 2017-01-05 08:45:32 +01:00
parent e4f4350bb4
commit 7b3984059a
1 changed files with 21 additions and 19 deletions

View File

@ -17,6 +17,11 @@
#include <deque> #include <deque>
#include "System/SysThreads.h" #include "System/SysThreads.h"
#include "Gif.h" #include "Gif.h"
#include "GS.h"
// FIXME common path ?
#include "../plugins/GSdx/boost_spsc_queue.hpp"
struct GS_Packet; struct GS_Packet;
extern void Gif_MTGS_Wait(bool isMTVU); extern void Gif_MTGS_Wait(bool isMTVU);
extern void Gif_FinishIRQ(); extern void Gif_FinishIRQ();
@ -147,10 +152,13 @@ static __fi void incTag(u32& offset, u32& size, u32 incAmount) {
struct Gif_Path_MTVU { struct Gif_Path_MTVU {
u32 fakePackets; // Fake packets pending to be sent to MTGS u32 fakePackets; // Fake packets pending to be sent to MTGS
GS_Packet fakePacket; GS_Packet fakePacket;
Mutex gsPackMutex; // Used for atomic access to gsPackQueue // Set a size based on MTGS but keep a factor 2 to avoid too waste to much
std::deque<GS_Packet> gsPackQueue; // VU1 programs' XGkick(s) // memory overhead. Note the struct is instantied 3 times (for each gif
// path)
ringbuffer_base<GS_Packet, RingBufferSize / 2> gsPackQueue;
Gif_Path_MTVU() { Reset(); } Gif_Path_MTVU() { Reset(); }
void Reset() { fakePackets = 0; gsPackQueue.clear(); void Reset() { fakePackets = 0;
gsPackQueue.reset();
fakePacket.Reset(); fakePacket.Reset();
fakePacket.done = 1; // Fake packets don't get processed by pcsx2 fakePacket.done = 1; // Fake packets don't get processed by pcsx2
fakePacket.size =~0u; // Used to indicate that its a fake packet fakePacket.size =~0u; // Used to indicate that its a fake packet
@ -380,22 +388,21 @@ struct Gif_Path {
// MTVU: Gets called after VU1 execution on MTVU thread // MTVU: Gets called after VU1 execution on MTVU thread
void FinishGSPacketMTVU() { void FinishGSPacketMTVU() {
if (1) {
ScopedLock lock(mtvu.gsPackMutex);
readAmount.fetch_add(gsPack.size + gsPack.readAmount); readAmount.fetch_add(gsPack.size + gsPack.readAmount);
mtvu.gsPackQueue.push_back(gsPack); while (!mtvu.gsPackQueue.push(gsPack))
} ;
gsPack.Reset(); gsPack.Reset();
gsPack.offset = curOffset; gsPack.offset = curOffset;
} }
// MTVU: Gets called by MTGS thread // MTVU: Gets called by MTGS thread
GS_Packet GetGSPacketMTVU() { GS_Packet GetGSPacketMTVU() {
ScopedLock lock(mtvu.gsPackMutex); // FIXME is the error path useful ?
if (mtvu.gsPackQueue.size()) { if (!mtvu.gsPackQueue.empty()) {
GS_Packet t = mtvu.gsPackQueue[0]; return mtvu.gsPackQueue.front();
return t; // XGkick GS packet(s)
} }
Console.Error("MTVU: Expected gsPackQueue to have elements!"); Console.Error("MTVU: Expected gsPackQueue to have elements!");
pxAssert(0); pxAssert(0);
return GS_Packet(); // gsPack.size will be 0 return GS_Packet(); // gsPack.size will be 0
@ -403,18 +410,13 @@ struct Gif_Path {
// MTVU: Gets called by MTGS thread // MTVU: Gets called by MTGS thread
void PopGSPacketMTVU() { void PopGSPacketMTVU() {
ScopedLock lock(mtvu.gsPackMutex); mtvu.gsPackQueue.pop();
if (mtvu.gsPackQueue.size()) {
mtvu.gsPackQueue.pop_front();
}
} }
// MTVU: Returns the amount of pending // MTVU: Returns the amount of pending
// GS Packets that MTGS hasn't yet processed // GS Packets that MTGS hasn't yet processed
u32 GetPendingGSPackets() { u32 GetPendingGSPackets() {
ScopedLock lock(mtvu.gsPackMutex); return mtvu.gsPackQueue.size();
u32 t = mtvu.gsPackQueue.size();
return t;
} }
}; };