mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-27 08:10:27 -06:00
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:
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user