make cross-instance pause work without breaking local wifi connections

This commit is contained in:
Arisotura
2023-03-11 23:07:29 +01:00
parent 4e6f054ffa
commit e0955cd1d4
4 changed files with 69 additions and 45 deletions

View File

@ -35,13 +35,10 @@
#include "IPC.h" #include "IPC.h"
#include "Config.h" #include "Config.h"
//#include "Input.h" #include "main.h"
namespace Input extern EmuThread* emuThread;
{
void ExtHotkeyPress(int id);
}
namespace IPC namespace IPC
@ -55,6 +52,7 @@ struct BufferHeader
u16 NumInstances; // total number of instances present u16 NumInstances; // total number of instances present
u16 InstanceBitmask; // bitmask of all instances present u16 InstanceBitmask; // bitmask of all instances present
u16 ConnectedBitmask; // bitmask of which instances are ready to send/receive MP packets u16 ConnectedBitmask; // bitmask of which instances are ready to send/receive MP packets
u16 ActiveBitmask; // bitmask of which instances are currently active (ie. not halted externally)
u32 CommandWriteOffset; u32 CommandWriteOffset;
u32 MPPacketWriteOffset; u32 MPPacketWriteOffset;
u32 MPReplyWriteOffset; u32 MPReplyWriteOffset;
@ -94,8 +92,6 @@ const u32 kMPPacketEnd = (2 * (kBufferSize / 3));
const u32 kMPReplyStart = kMPPacketEnd; const u32 kMPReplyStart = kMPPacketEnd;
const u32 kMPReplyEnd = kBufferSize; const u32 kMPReplyEnd = kBufferSize;
bool CmdRecvFlags[Cmd_MAX];
int MPRecvTimeout; int MPRecvTimeout;
int MPLastHostID; int MPLastHostID;
@ -294,8 +290,6 @@ bool Init()
} }
Buffer->unlock(); Buffer->unlock();
memset(CmdRecvFlags, 0, sizeof(CmdRecvFlags));
MPLastHostID = -1; MPLastHostID = -1;
MPRecvTimeout = 25; MPRecvTimeout = 25;
@ -312,6 +306,8 @@ bool InitSema()
SemPoolInit(); SemPoolInit();
if (!SemInit(InstanceID)) return false; if (!SemInit(InstanceID)) return false;
if (!SemInit(16+InstanceID)) return false; if (!SemInit(16+InstanceID)) return false;
return true;
} }
void DeInit() void DeInit()
@ -322,7 +318,8 @@ void DeInit()
u8* data = (u8*)Buffer->data(); u8* data = (u8*)Buffer->data();
BufferHeader* header = (BufferHeader*)&data[0]; BufferHeader* header = (BufferHeader*)&data[0];
header->ConnectedBitmask &= ~(1 << InstanceID); header->ConnectedBitmask &= ~(1 << InstanceID);
header->InstanceBitmask &= ~(1<<InstanceID); header->ActiveBitmask &= ~(1 << InstanceID);
header->InstanceBitmask &= ~(1 << InstanceID);
header->NumInstances--; header->NumInstances--;
Buffer->unlock(); Buffer->unlock();
@ -365,6 +362,15 @@ void MPEnd()
Buffer->unlock(); Buffer->unlock();
} }
void SetActive(bool active)
{
Buffer->lock();
BufferHeader* header = (BufferHeader*)Buffer->data();
if (active) header->ActiveBitmask |= (1 << InstanceID);
else header->ActiveBitmask &= ~(1 << InstanceID);
Buffer->unlock();
}
template<int fifo> void FIFORead(void* buf, int len) template<int fifo> void FIFORead(void* buf, int len)
{ {
@ -454,8 +460,6 @@ template<int fifo> void FIFOWrite(void* buf, int len)
void ProcessCommands() void ProcessCommands()
{ {
memset(CmdRecvFlags, 0, sizeof(CmdRecvFlags));
Buffer->lock(); Buffer->lock();
u8* data = (u8*)Buffer->data(); u8* data = (u8*)Buffer->data();
BufferHeader* header = (BufferHeader*)&data[0]; BufferHeader* header = (BufferHeader*)&data[0];
@ -468,7 +472,9 @@ void ProcessCommands()
FIFORead<0>(&cmdheader, sizeof(cmdheader)); FIFORead<0>(&cmdheader, sizeof(cmdheader));
if ((cmdheader.Magic != 0x4D434C4D) || (cmdheader.Length > kMaxCommandSize)) if ((cmdheader.Magic != 0x4D434C4D) ||
(cmdheader.Length > kMaxCommandSize) ||
(cmdheader.Command >= Cmd_MAX))
{ {
printf("IPC: !!! COMMAND BUFFER IS FUCKED. RESETTING\n"); printf("IPC: !!! COMMAND BUFFER IS FUCKED. RESETTING\n");
CommandReadOffset = header->CommandWriteOffset; CommandReadOffset = header->CommandWriteOffset;
@ -476,25 +482,27 @@ void ProcessCommands()
return; return;
} }
if (!(cmdheader.Recipients & (1<<InstanceID)))
{
// skip this command
CommandReadOffset += cmdheader.Length;
if (CommandReadOffset >= kCommandEnd)
CommandReadOffset += kCommandStart - kCommandEnd;
continue;
}
// handle this command
if (cmdheader.Length) if (cmdheader.Length)
FIFORead<0>(cmddata, cmdheader.Length); FIFORead<0>(cmddata, cmdheader.Length);
if (!(cmdheader.Recipients & (1<<InstanceID))) switch (cmdheader.Command)
continue;
if (cmdheader.Command >= Cmd_MAX)
continue;
// handle this command
/*switch (cmdheader.Command)
{ {
case Cmd_Pause: case Cmd_Pause:
Input::ExtHotkeyPress(HK_Pause); emuThread->IPCPause(cmddata[0] != 0);
break; break;
}*/ }
CmdRecvFlags[cmdheader.Command] = true;
// TODO: store the command data, for future commands that will need it
// TODO: also what if, say, we get multiple pause commands before CommandReceived() is called?
} }
Buffer->unlock(); Buffer->unlock();
@ -544,10 +552,10 @@ bool SendCommand(u16 recipients, u16 command, u16 len, void* cmddata)
return true; return true;
} }
bool CommandReceived(u16 command) bool SendCommandU8(u16 recipients, u16 command, u8 arg)
{ {
if (command >= Cmd_MAX) return false; u8 data = arg;
return CmdRecvFlags[command]; return SendCommand(recipients, command, 1, &data);
} }
@ -689,6 +697,8 @@ int SendMPAck(u8* packet, int len, u64 timestamp)
int RecvMPHostPacket(u8* packet, u64* timestamp) int RecvMPHostPacket(u8* packet, u64* timestamp)
{ {
bool block = true;
if (MPLastHostID != -1) if (MPLastHostID != -1)
{ {
// check if the host is still connected // check if the host is still connected
@ -697,26 +707,32 @@ int RecvMPHostPacket(u8* packet, u64* timestamp)
u8* data = (u8*)Buffer->data(); u8* data = (u8*)Buffer->data();
BufferHeader* header = (BufferHeader*)&data[0]; BufferHeader* header = (BufferHeader*)&data[0];
u16 curinstmask = header->ConnectedBitmask; u16 curinstmask = header->ConnectedBitmask;
u16 actinstmask = header->ActiveBitmask;
Buffer->unlock(); Buffer->unlock();
if (!(curinstmask & (1 << MPLastHostID))) if (!(curinstmask & (1 << MPLastHostID)))
return -1; return -1;
if (!(actinstmask & (1 << MPLastHostID)))
block = false;
} }
return RecvMPPacketGeneric(packet, true, timestamp); return RecvMPPacketGeneric(packet, block, timestamp);
} }
u16 RecvMPReplies(u8* packets, u64 timestamp, u16 aidmask) u16 RecvMPReplies(u8* packets, u64 timestamp, u16 aidmask)
{ {
u16 ret = 0; u16 ret = 0;
u16 myinstmask = (1 << InstanceID); u16 myinstmask = (1 << InstanceID);
u16 curinstmask; u16 curinstmask, actinstmask;
int timeout = MPRecvTimeout;
{ {
Buffer->lock(); Buffer->lock();
u8* data = (u8*)Buffer->data(); u8* data = (u8*)Buffer->data();
BufferHeader* header = (BufferHeader*)&data[0]; BufferHeader* header = (BufferHeader*)&data[0];
curinstmask = header->ConnectedBitmask; curinstmask = header->ConnectedBitmask;
actinstmask = header->ActiveBitmask;
Buffer->unlock(); Buffer->unlock();
} }
@ -724,9 +740,12 @@ u16 RecvMPReplies(u8* packets, u64 timestamp, u16 aidmask)
if ((myinstmask & curinstmask) == curinstmask) if ((myinstmask & curinstmask) == curinstmask)
return 0; return 0;
if ((myinstmask & actinstmask) == actinstmask)
timeout = 0;
for (;;) for (;;)
{ {
if (!SemWait(16+InstanceID, MPRecvTimeout)) if (!SemWait(16+InstanceID, timeout))
{ {
// no more replies available // no more replies available
return ret; return ret;

View File

@ -42,9 +42,11 @@ void SetMPRecvTimeout(int timeout);
void MPBegin(); void MPBegin();
void MPEnd(); void MPEnd();
void SetActive(bool active);
void ProcessCommands(); void ProcessCommands();
bool SendCommand(u16 recipients, u16 command, u16 len, void* data); bool SendCommand(u16 recipients, u16 command, u16 len, void* data);
bool CommandReceived(u16 command); bool SendCommandU8(u16 recipients, u16 command, u8 arg);
int SendMPPacket(u8* data, int len, u64 timestamp); int SendMPPacket(u8* data, int len, u64 timestamp);
int RecvMPPacket(u8* data, u64* timestamp); int RecvMPPacket(u8* data, u64* timestamp);

View File

@ -197,7 +197,7 @@ EmuThread::EmuThread(QObject* parent) : QThread(parent)
connect(this, SIGNAL(swapScreensToggle()), mainWindow->actScreenSwap, SLOT(trigger())); connect(this, SIGNAL(swapScreensToggle()), mainWindow->actScreenSwap, SLOT(trigger()));
connect(this, SIGNAL(screenEmphasisToggle()), mainWindow, SLOT(onScreenEmphasisToggled())); connect(this, SIGNAL(screenEmphasisToggle()), mainWindow, SLOT(onScreenEmphasisToggled()));
connect(this, SIGNAL(windowIPCPause()), mainWindow, SLOT(onIPCPause())); connect(this, SIGNAL(windowIPCPause(bool)), mainWindow, SLOT(onIPCPause(bool)));
static_cast<ScreenPanelGL*>(mainWindow->panel)->transferLayout(this); static_cast<ScreenPanelGL*>(mainWindow->panel)->transferLayout(this);
} }
@ -363,8 +363,6 @@ void EmuThread::run()
{ {
IPC::ProcessCommands(); IPC::ProcessCommands();
if (IPC::CommandReceived(IPC::Cmd_Pause)) emit windowIPCPause();
Input::Process(); Input::Process();
if (Input::HotkeyPressed(HK_FastForwardToggle)) emit windowLimitFPSChange(); if (Input::HotkeyPressed(HK_FastForwardToggle)) emit windowLimitFPSChange();
@ -678,6 +676,7 @@ void EmuThread::emuRun()
// checkme // checkme
emit windowEmuStart(); emit windowEmuStart();
AudioInOut::Enable(); AudioInOut::Enable();
IPC::SetActive(true);
} }
void EmuThread::initContext() void EmuThread::initContext()
@ -702,6 +701,7 @@ void EmuThread::emuPause()
while (EmuStatus != emuStatus_Paused); while (EmuStatus != emuStatus_Paused);
AudioInOut::Disable(); AudioInOut::Disable();
IPC::SetActive(false);
} }
void EmuThread::emuUnpause() void EmuThread::emuUnpause()
@ -714,6 +714,7 @@ void EmuThread::emuUnpause()
EmuRunning = PrevEmuStatus; EmuRunning = PrevEmuStatus;
AudioInOut::Enable(); AudioInOut::Enable();
IPC::SetActive(true);
} }
void EmuThread::emuStop() void EmuThread::emuStop()
@ -722,12 +723,13 @@ void EmuThread::emuStop()
EmuPauseStack = EmuPauseStackRunning; EmuPauseStack = EmuPauseStackRunning;
AudioInOut::Disable(); AudioInOut::Disable();
IPC::SetActive(false);
} }
void EmuThread::emuFrameStep() void EmuThread::emuFrameStep()
{ {
if (EmuPauseStack < EmuPauseStackPauseThreshold) emit windowEmuPause(); if (EmuRunning != 3) IPC::SetActive(false);
EmuRunning = emuStatus_FrameStep; EmuRunning = 3;
} }
bool EmuThread::emuIsRunning() bool EmuThread::emuIsRunning()
@ -2714,19 +2716,18 @@ void MainWindow::onPause(bool checked)
pausedManually = false; pausedManually = false;
} }
IPC::SendCommand(0xFFFF, IPC::Cmd_Pause, 0, nullptr); IPC::SendCommandU8(0xFFFF, IPC::Cmd_Pause, (u8)checked);
} }
void MainWindow::onIPCPause() void MainWindow::onIPCPause(bool pause)
{ {
// for IPC, using the normal way to trigger a pause (actPause->trigger()) // for IPC, using the normal way to trigger a pause (actPause->trigger())
// isn't viable, because it would lead to broadcasting more IPC 'pause' messages // isn't viable, because it would lead to broadcasting more IPC 'pause' messages
// so we have to replicate it this way // so we have to replicate it this way
actPause->toggle(); // changes visual state, without triggering onPause() actPause->setChecked(pause); // changes visual state, without triggering onPause()
bool checked = actPause->isChecked();
if (checked) if (pause)
{ {
emuThread->emuPause(); emuThread->emuPause();
OSD::AddMessage(0, "Paused"); OSD::AddMessage(0, "Paused");

View File

@ -68,6 +68,8 @@ public:
void updateScreenSettings(bool filter, const WindowInfo& windowInfo, int numScreens, int* screenKind, float* screenMatrix); void updateScreenSettings(bool filter, const WindowInfo& windowInfo, int numScreens, int* screenKind, float* screenMatrix);
void IPCPause(bool pause) { emit windowIPCPause(pause); }
signals: signals:
void windowUpdate(); void windowUpdate();
void windowTitleChange(QString title); void windowTitleChange(QString title);
@ -78,7 +80,7 @@ signals:
void windowEmuReset(); void windowEmuReset();
void windowEmuFrameStep(); void windowEmuFrameStep();
void windowIPCPause(); void windowIPCPause(bool pause);
void windowLimitFPSChange(); void windowLimitFPSChange();
@ -298,7 +300,7 @@ private slots:
void onQuit(); void onQuit();
void onPause(bool checked); void onPause(bool checked);
void onIPCPause(); void onIPCPause(bool pause);
void onReset(); void onReset();
void onStop(); void onStop();
void onFrameStep(); void onFrameStep();