merge doublemelon (#2067)

non-exhaustive (but exhausting) list of changes:

* base laid for multiple window support, but will likely require more work to work correctly
* encapsulation of frontend state for proper multi-instance support
* (JIT still needs a fix for the NDS::Current workaround but we can get there later)
* new, more flexible configuration system
This commit is contained in:
Arisotura
2024-06-15 13:52:47 +02:00
committed by GitHub
parent 8e9b88d01d
commit 25a7b1ca1d
111 changed files with 16802 additions and 5042 deletions

View File

@ -29,17 +29,15 @@
#include <QThread>
#include <QSemaphore>
#include <QMutex>
#include <QOpenGLContext>
#include <QSharedMemory>
#include <QTemporaryFile>
#include <SDL_loadso.h>
#include "Platform.h"
#include "Config.h"
#include "ROMManager.h"
#include "main.h"
#include "CameraManager.h"
#include "LAN_Socket.h"
#include "LAN_PCap.h"
#include "Net.h"
#include "LocalMP.h"
#include "SPI_Firmware.h"
@ -48,173 +46,18 @@
#define ftell _ftelli64
#endif // __WIN32__
std::string EmuDirectory;
extern CameraManager* camManager[2];
void emuStop();
// TEMP
//#include "main.h"
//extern MainWindow* mainWindow;
namespace melonDS::Platform
{
void PathInit(int argc, char** argv)
void SignalStop(StopReason reason, void* userdata)
{
// First, check for the portable directory next to the executable.
QString appdirpath = QCoreApplication::applicationDirPath();
QString portablepath = appdirpath + QDir::separator() + "portable";
#if defined(__APPLE__)
// On Apple platforms we may need to navigate outside an app bundle.
// The executable directory would be "melonDS.app/Contents/MacOS", so we need to go a total of three steps up.
QDir bundledir(appdirpath);
if (bundledir.cd("..") && bundledir.cd("..") && bundledir.dirName().endsWith(".app") && bundledir.cd(".."))
{
portablepath = bundledir.absolutePath() + QDir::separator() + "portable";
}
#endif
QDir portabledir(portablepath);
if (portabledir.exists())
{
EmuDirectory = portabledir.absolutePath().toStdString();
}
else
{
// If no overrides are specified, use the default path.
#if defined(__WIN32__) && defined(WIN32_PORTABLE)
EmuDirectory = appdirpath.toStdString();
#else
QString confdir;
QDir config(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation));
config.mkdir("melonDS");
confdir = config.absolutePath() + QDir::separator() + "melonDS";
EmuDirectory = confdir.toStdString();
#endif
}
EmuInstance* inst = (EmuInstance*)userdata;
inst->emuStop(reason);
}
QSharedMemory* IPCBuffer = nullptr;
int IPCInstanceID;
void IPCInit()
{
IPCInstanceID = 0;
IPCBuffer = new QSharedMemory("melonIPC");
#if !defined(Q_OS_WINDOWS)
// QSharedMemory instances can be left over from crashed processes on UNIX platforms.
// To prevent melonDS thinking there's another instance, we attach and then immediately detach from the
// shared memory. If no other process was actually using it, it'll be destroyed and we'll have a clean
// shared memory buffer after creating it again below.
if (IPCBuffer->attach())
{
IPCBuffer->detach();
delete IPCBuffer;
IPCBuffer = new QSharedMemory("melonIPC");
}
#endif
if (!IPCBuffer->attach())
{
Log(LogLevel::Info, "IPC sharedmem doesn't exist. creating\n");
if (!IPCBuffer->create(1024))
{
Log(LogLevel::Error, "IPC sharedmem create failed: %s\n", IPCBuffer->errorString().toStdString().c_str());
delete IPCBuffer;
IPCBuffer = nullptr;
return;
}
IPCBuffer->lock();
memset(IPCBuffer->data(), 0, IPCBuffer->size());
IPCBuffer->unlock();
}
IPCBuffer->lock();
u8* data = (u8*)IPCBuffer->data();
u16 mask = *(u16*)&data[0];
for (int i = 0; i < 16; i++)
{
if (!(mask & (1<<i)))
{
IPCInstanceID = i;
*(u16*)&data[0] |= (1<<i);
break;
}
}
IPCBuffer->unlock();
Log(LogLevel::Info, "IPC: instance ID %d\n", IPCInstanceID);
}
void IPCDeInit()
{
if (IPCBuffer)
{
IPCBuffer->lock();
u8* data = (u8*)IPCBuffer->data();
*(u16*)&data[0] &= ~(1<<IPCInstanceID);
IPCBuffer->unlock();
IPCBuffer->detach();
delete IPCBuffer;
}
IPCBuffer = nullptr;
}
void Init(int argc, char** argv)
{
PathInit(argc, argv);
IPCInit();
}
void DeInit()
{
IPCDeInit();
}
void SignalStop(StopReason reason)
{
emuStop();
switch (reason)
{
case StopReason::GBAModeNotSupported:
Log(LogLevel::Error, "!! GBA MODE NOT SUPPORTED\n");
//mainWindow->osdAddMessage(0xFFA0A0, "GBA mode not supported.");
break;
case StopReason::BadExceptionRegion:
//mainWindow->osdAddMessage(0xFFA0A0, "Internal error.");
break;
case StopReason::PowerOff:
case StopReason::External:
//mainWindow->osdAddMessage(0xFFC040, "Shutdown");
default:
break;
}
}
int InstanceID()
{
return IPCInstanceID;
}
std::string InstanceFileSuffix()
{
int inst = IPCInstanceID;
if (inst == 0) return "";
char suffix[16] = {0};
snprintf(suffix, 15, ".%d", inst+1);
return suffix;
}
static QIODevice::OpenMode GetQMode(FileMode mode)
{
@ -308,9 +151,9 @@ FileHandle* OpenFile(const std::string& path, FileMode mode)
}
}
FileHandle* OpenLocalFile(const std::string& path, FileMode mode)
std::string GetLocalFilePath(const std::string& filename)
{
QString qpath = QString::fromStdString(path);
QString qpath = QString::fromStdString(filename);
QDir dir(qpath);
QString fullpath;
@ -321,10 +164,15 @@ FileHandle* OpenLocalFile(const std::string& path, FileMode mode)
}
else
{
fullpath = QString::fromStdString(EmuDirectory) + QDir::separator() + qpath;
fullpath = emuDirectory + QDir::separator() + qpath;
}
return OpenFile(fullpath.toStdString(), mode);
return fullpath.toStdString();
}
FileHandle* OpenLocalFile(const std::string& path, FileMode mode)
{
return OpenFile(GetLocalFilePath(path), mode);
}
bool CloseFile(FileHandle* file)
@ -539,27 +387,30 @@ void Sleep(u64 usecs)
}
void WriteNDSSave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen)
void WriteNDSSave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen, void* userdata)
{
if (ROMManager::NDSSave)
ROMManager::NDSSave->RequestFlush(savedata, savelen, writeoffset, writelen);
EmuInstance* inst = (EmuInstance*)userdata;
if (inst->ndsSave)
inst->ndsSave->RequestFlush(savedata, savelen, writeoffset, writelen);
}
void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen)
void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen, void* userdata)
{
if (ROMManager::GBASave)
ROMManager::GBASave->RequestFlush(savedata, savelen, writeoffset, writelen);
EmuInstance* inst = (EmuInstance*)userdata;
if (inst->gbaSave)
inst->gbaSave->RequestFlush(savedata, savelen, writeoffset, writelen);
}
void WriteFirmware(const Firmware& firmware, u32 writeoffset, u32 writelen)
void WriteFirmware(const Firmware& firmware, u32 writeoffset, u32 writelen, void* userdata)
{
if (!ROMManager::FirmwareSave)
EmuInstance* inst = (EmuInstance*)userdata;
if (!inst->firmwareSave)
return;
if (firmware.GetHeader().Identifier != GENERATED_FIRMWARE_IDENTIFIER)
{ // If this is not the default built-in firmware...
// ...then write the whole thing back.
ROMManager::FirmwareSave->RequestFlush(firmware.Buffer(), firmware.Length(), writeoffset, writelen);
inst->firmwareSave->RequestFlush(firmware.Buffer(), firmware.Length(), writeoffset, writelen);
}
else
{
@ -576,131 +427,104 @@ void WriteFirmware(const Firmware& firmware, u32 writeoffset, u32 writelen)
{ // If we're writing to the access points...
const u8* buffer = firmware.GetExtendedAccessPointPosition();
u32 length = sizeof(firmware.GetExtendedAccessPoints()) + sizeof(firmware.GetAccessPoints());
ROMManager::FirmwareSave->RequestFlush(buffer, length, writeoffset - eapstart, writelen);
inst->firmwareSave->RequestFlush(buffer, length, writeoffset - eapstart, writelen);
}
}
}
void WriteDateTime(int year, int month, int day, int hour, int minute, int second)
void WriteDateTime(int year, int month, int day, int hour, int minute, int second, void* userdata)
{
EmuInstance* inst = (EmuInstance*)userdata;
QDateTime hosttime = QDateTime::currentDateTime();
QDateTime time = QDateTime(QDate(year, month, day), QTime(hour, minute, second));
auto& cfg = inst->getLocalConfig();
Config::RTCOffset = hosttime.secsTo(time);
cfg.SetInt64("RTC.Offset", hosttime.secsTo(time));
Config::Save();
}
bool MP_Init()
void MP_Begin(void* userdata)
{
return LocalMP::Init();
int inst = ((EmuInstance*)userdata)->getInstanceID();
LocalMP::Begin(inst);
}
void MP_DeInit()
void MP_End(void* userdata)
{
return LocalMP::DeInit();
int inst = ((EmuInstance*)userdata)->getInstanceID();
LocalMP::End(inst);
}
void MP_Begin()
int MP_SendPacket(u8* data, int len, u64 timestamp, void* userdata)
{
return LocalMP::Begin();
int inst = ((EmuInstance*)userdata)->getInstanceID();
return LocalMP::SendPacket(inst, data, len, timestamp);
}
void MP_End()
int MP_RecvPacket(u8* data, u64* timestamp, void* userdata)
{
return LocalMP::End();
int inst = ((EmuInstance*)userdata)->getInstanceID();
return LocalMP::RecvPacket(inst, data, timestamp);
}
int MP_SendPacket(u8* data, int len, u64 timestamp)
int MP_SendCmd(u8* data, int len, u64 timestamp, void* userdata)
{
return LocalMP::SendPacket(data, len, timestamp);
int inst = ((EmuInstance*)userdata)->getInstanceID();
return LocalMP::SendCmd(inst, data, len, timestamp);
}
int MP_RecvPacket(u8* data, u64* timestamp)
int MP_SendReply(u8* data, int len, u64 timestamp, u16 aid, void* userdata)
{
return LocalMP::RecvPacket(data, timestamp);
int inst = ((EmuInstance*)userdata)->getInstanceID();
return LocalMP::SendReply(inst, data, len, timestamp, aid);
}
int MP_SendCmd(u8* data, int len, u64 timestamp)
int MP_SendAck(u8* data, int len, u64 timestamp, void* userdata)
{
return LocalMP::SendCmd(data, len, timestamp);
int inst = ((EmuInstance*)userdata)->getInstanceID();
return LocalMP::SendAck(inst, data, len, timestamp);
}
int MP_SendReply(u8* data, int len, u64 timestamp, u16 aid)
int MP_RecvHostPacket(u8* data, u64* timestamp, void* userdata)
{
return LocalMP::SendReply(data, len, timestamp, aid);
int inst = ((EmuInstance*)userdata)->getInstanceID();
return LocalMP::RecvHostPacket(inst, data, timestamp);
}
int MP_SendAck(u8* data, int len, u64 timestamp)
u16 MP_RecvReplies(u8* data, u64 timestamp, u16 aidmask, void* userdata)
{
return LocalMP::SendAck(data, len, timestamp);
}
int MP_RecvHostPacket(u8* data, u64* timestamp)
{
return LocalMP::RecvHostPacket(data, timestamp);
}
u16 MP_RecvReplies(u8* data, u64 timestamp, u16 aidmask)
{
return LocalMP::RecvReplies(data, timestamp, aidmask);
}
bool LAN_Init()
{
if (Config::DirectLAN)
{
if (!LAN_PCap::Init(true))
return false;
}
else
{
if (!LAN_Socket::Init())
return false;
}
return true;
}
void LAN_DeInit()
{
// checkme. blarg
//if (Config::DirectLAN)
// LAN_PCap::DeInit();
//else
// LAN_Socket::DeInit();
LAN_PCap::DeInit();
LAN_Socket::DeInit();
}
int LAN_SendPacket(u8* data, int len)
{
if (Config::DirectLAN)
return LAN_PCap::SendPacket(data, len);
else
return LAN_Socket::SendPacket(data, len);
}
int LAN_RecvPacket(u8* data)
{
if (Config::DirectLAN)
return LAN_PCap::RecvPacket(data);
else
return LAN_Socket::RecvPacket(data);
int inst = ((EmuInstance*)userdata)->getInstanceID();
return LocalMP::RecvReplies(inst, data, timestamp, aidmask);
}
void Camera_Start(int num)
int Net_SendPacket(u8* data, int len, void* userdata)
{
int inst = ((EmuInstance*)userdata)->getInstanceID();
Net::SendPacket(data, len, inst);
return 0;
}
int Net_RecvPacket(u8* data, void* userdata)
{
int inst = ((EmuInstance*)userdata)->getInstanceID();
return Net::RecvPacket(data, inst);
}
void Camera_Start(int num, void* userdata)
{
return camManager[num]->start();
}
void Camera_Stop(int num)
void Camera_Stop(int num, void* userdata)
{
return camManager[num]->stop();
}
void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv)
void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv, void* userdata)
{
return camManager[num]->captureFrame(frame, width, height, yuv);
}