mirror of https://github.com/mgba-emu/mgba.git
Qt: Switch to new GBA lockstep driver
This commit is contained in:
parent
0955b94466
commit
cd8933415c
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "CoreController.h"
|
#include "CoreController.h"
|
||||||
#include "LogController.h"
|
#include "LogController.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#ifdef M_CORE_GBA
|
#ifdef M_CORE_GBA
|
||||||
#include <mgba/internal/gba/gba.h>
|
#include <mgba/internal/gba/gba.h>
|
||||||
|
@ -27,8 +28,14 @@ MultiplayerController::Player::Player(CoreController* coreController)
|
||||||
int MultiplayerController::Player::id() const {
|
int MultiplayerController::Player::id() const {
|
||||||
switch (controller->platform()) {
|
switch (controller->platform()) {
|
||||||
#ifdef M_CORE_GBA
|
#ifdef M_CORE_GBA
|
||||||
case mPLATFORM_GBA:
|
case mPLATFORM_GBA: {
|
||||||
return node.gba->id;
|
int id = node.gba->d.deviceId(&node.gba->d);
|
||||||
|
if (id >= 0) {
|
||||||
|
return id;
|
||||||
|
} else {
|
||||||
|
return preferredId;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef M_CORE_GB
|
#ifdef M_CORE_GB
|
||||||
case mPLATFORM_GB:
|
case mPLATFORM_GB:
|
||||||
|
@ -89,25 +96,7 @@ MultiplayerController::MultiplayerController() {
|
||||||
switch (player->controller->platform()) {
|
switch (player->controller->platform()) {
|
||||||
#ifdef M_CORE_GBA
|
#ifdef M_CORE_GBA
|
||||||
case mPLATFORM_GBA:
|
case mPLATFORM_GBA:
|
||||||
if (!id) {
|
abort();
|
||||||
for (int i = 1; i < controller->m_players.count(); ++i) {
|
|
||||||
player = controller->player(i);
|
|
||||||
if (player->node.gba->d.p->mode > GBA_SIO_MULTI) {
|
|
||||||
player->controller->setSync(true);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
player->controller->setSync(false);
|
|
||||||
player->cyclesPosted += cycles;
|
|
||||||
if (player->awake < 1) {
|
|
||||||
player->node.gba->nextEvent += player->cyclesPosted;
|
|
||||||
}
|
|
||||||
mCoreThreadStopWaiting(player->controller->thread());
|
|
||||||
player->awake = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
player->controller->setSync(true);
|
|
||||||
player->cyclesPosted += cycles;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef M_CORE_GB
|
#ifdef M_CORE_GB
|
||||||
|
@ -169,7 +158,6 @@ MultiplayerController::MultiplayerController() {
|
||||||
switch (player->controller->platform()) {
|
switch (player->controller->platform()) {
|
||||||
#ifdef M_CORE_GBA
|
#ifdef M_CORE_GBA
|
||||||
case mPLATFORM_GBA:
|
case mPLATFORM_GBA:
|
||||||
player->cyclesPosted += reinterpret_cast<GBASIOLockstep*>(lockstep)->players[0]->eventDiff;
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef M_CORE_GB
|
#ifdef M_CORE_GB
|
||||||
|
@ -184,7 +172,6 @@ MultiplayerController::MultiplayerController() {
|
||||||
switch (player->controller->platform()) {
|
switch (player->controller->platform()) {
|
||||||
#ifdef M_CORE_GBA
|
#ifdef M_CORE_GBA
|
||||||
case mPLATFORM_GBA:
|
case mPLATFORM_GBA:
|
||||||
player->node.gba->nextEvent += player->cyclesPosted;
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef M_CORE_GB
|
#ifdef M_CORE_GB
|
||||||
|
@ -214,11 +201,11 @@ bool MultiplayerController::attachGame(CoreController* controller) {
|
||||||
interrupters.append(p.controller);
|
interrupters.append(p.controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_lockstep.attached == 0) {
|
if (attached() == 0) {
|
||||||
switch (controller->platform()) {
|
switch (controller->platform()) {
|
||||||
#ifdef M_CORE_GBA
|
#ifdef M_CORE_GBA
|
||||||
case mPLATFORM_GBA:
|
case mPLATFORM_GBA:
|
||||||
GBASIOLockstepInit(&m_gbaLockstep);
|
GBASIOLockstepCoordinatorInit(&m_gbaCoordinator);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef M_CORE_GB
|
#ifdef M_CORE_GB
|
||||||
|
@ -240,28 +227,53 @@ bool MultiplayerController::attachGame(CoreController* controller) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Player player{controller};
|
Player player{controller};
|
||||||
|
for (int i = 0; i < MAX_GBAS; ++i) {
|
||||||
|
if (m_claimedIds & (1 << i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
player.preferredId = i;
|
||||||
|
m_claimedIds |= 1 << i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
switch (controller->platform()) {
|
switch (controller->platform()) {
|
||||||
#ifdef M_CORE_GBA
|
#ifdef M_CORE_GBA
|
||||||
case mPLATFORM_GBA: {
|
case mPLATFORM_GBA: {
|
||||||
if (m_lockstep.attached >= MAX_GBAS) {
|
if (attached() >= MAX_GBAS) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
GBA* gba = static_cast<GBA*>(thread->core->board);
|
GBA* gba = static_cast<GBA*>(thread->core->board);
|
||||||
|
|
||||||
GBASIOLockstepNode* node = new GBASIOLockstepNode;
|
GBASIOLockstepDriver* node = new GBASIOLockstepDriver;
|
||||||
GBASIOLockstepNodeCreate(node);
|
LockstepUser* user = new LockstepUser;
|
||||||
GBASIOLockstepAttachNode(&m_gbaLockstep, node);
|
mLockstepThreadUserInit(user, thread);
|
||||||
|
user->controller = this;
|
||||||
|
user->pid = m_nextPid;
|
||||||
|
user->d.requestedId = [](mLockstepUser* ctx) {
|
||||||
|
mLockstepThreadUser* tctx = reinterpret_cast<mLockstepThreadUser*>(ctx);
|
||||||
|
LockstepUser* user = static_cast<LockstepUser*>(tctx);
|
||||||
|
MultiplayerController* controller = user->controller;
|
||||||
|
const auto iter = controller->m_pids.find(user->pid);
|
||||||
|
if (iter == controller->m_pids.end()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
const Player& p = iter.value();
|
||||||
|
return p.preferredId;
|
||||||
|
};
|
||||||
|
|
||||||
|
GBASIOLockstepDriverCreate(node, &user->d);
|
||||||
|
GBASIOLockstepCoordinatorAttach(&m_gbaCoordinator, node);
|
||||||
player.node.gba = node;
|
player.node.gba = node;
|
||||||
|
|
||||||
GBASIOSetDriver(&gba->sio, &node->d, GBA_SIO_MULTI);
|
GBASIOSetDriver(&gba->sio, &node->d, GBA_SIO_MULTI);
|
||||||
|
GBASIOSetDriver(&gba->sio, &node->d, GBA_SIO_NORMAL_8);
|
||||||
GBASIOSetDriver(&gba->sio, &node->d, GBA_SIO_NORMAL_32);
|
GBASIOSetDriver(&gba->sio, &node->d, GBA_SIO_NORMAL_32);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef M_CORE_GB
|
#ifdef M_CORE_GB
|
||||||
case mPLATFORM_GB: {
|
case mPLATFORM_GB: {
|
||||||
if (m_lockstep.attached >= 2) {
|
if (attached() >= 2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,7 +293,7 @@ bool MultiplayerController::attachGame(CoreController* controller) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<QString, QString> path(controller->path(), controller->baseDirectory());
|
QPair<QString, QString> path(controller->path(), controller->baseDirectory());
|
||||||
int claimed = m_claimed[path];
|
int claimed = m_claimedSaves[path];
|
||||||
|
|
||||||
int saveId = 0;
|
int saveId = 0;
|
||||||
mCoreConfigGetIntValue(&controller->thread()->core->config, "savePlayerId", &saveId);
|
mCoreConfigGetIntValue(&controller->thread()->core->config, "savePlayerId", &saveId);
|
||||||
|
@ -304,7 +316,7 @@ bool MultiplayerController::attachGame(CoreController* controller) {
|
||||||
} else {
|
} else {
|
||||||
player.saveId = 1;
|
player.saveId = 1;
|
||||||
}
|
}
|
||||||
m_claimed[path] |= 1 << (player.saveId - 1);
|
m_claimedSaves[path] |= 1 << (player.saveId - 1);
|
||||||
|
|
||||||
m_pids.insert(m_nextPid, player);
|
m_pids.insert(m_nextPid, player);
|
||||||
++m_nextPid;
|
++m_nextPid;
|
||||||
|
@ -328,8 +340,7 @@ void MultiplayerController::detachGame(CoreController* controller) {
|
||||||
for (int i = 0; i < m_players.count(); ++i) {
|
for (int i = 0; i < m_players.count(); ++i) {
|
||||||
Player* p = player(i);
|
Player* p = player(i);
|
||||||
if (!p) {
|
if (!p) {
|
||||||
LOG(QT, ERROR) << tr("Trying to detach a multiplayer player that's not attached");
|
continue;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
CoreController* playerController = p->controller;
|
CoreController* playerController = p->controller;
|
||||||
if (playerController == controller) {
|
if (playerController == controller) {
|
||||||
|
@ -337,15 +348,21 @@ void MultiplayerController::detachGame(CoreController* controller) {
|
||||||
}
|
}
|
||||||
interrupters.append(playerController);
|
interrupters.append(playerController);
|
||||||
}
|
}
|
||||||
|
if (pid < 0) {
|
||||||
|
LOG(QT, WARN) << tr("Trying to detach a multiplayer player that's not attached");
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch (controller->platform()) {
|
switch (controller->platform()) {
|
||||||
#ifdef M_CORE_GBA
|
#ifdef M_CORE_GBA
|
||||||
case mPLATFORM_GBA: {
|
case mPLATFORM_GBA: {
|
||||||
GBA* gba = static_cast<GBA*>(thread->core->board);
|
GBA* gba = static_cast<GBA*>(thread->core->board);
|
||||||
GBASIOLockstepNode* node = reinterpret_cast<GBASIOLockstepNode*>(gba->sio.drivers.multiplayer);
|
GBASIOLockstepDriver* node = reinterpret_cast<GBASIOLockstepDriver*>(gba->sio.drivers.multiplayer);
|
||||||
GBASIOSetDriver(&gba->sio, nullptr, GBA_SIO_MULTI);
|
GBASIOSetDriver(&gba->sio, nullptr, GBA_SIO_MULTI);
|
||||||
|
GBASIOSetDriver(&gba->sio, nullptr, GBA_SIO_NORMAL_8);
|
||||||
GBASIOSetDriver(&gba->sio, nullptr, GBA_SIO_NORMAL_32);
|
GBASIOSetDriver(&gba->sio, nullptr, GBA_SIO_NORMAL_32);
|
||||||
if (node) {
|
if (node) {
|
||||||
GBASIOLockstepDetachNode(&m_gbaLockstep, node);
|
GBASIOLockstepCoordinatorDetach(&m_gbaCoordinator, node);
|
||||||
|
delete node->user;
|
||||||
delete node;
|
delete node;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -371,14 +388,20 @@ void MultiplayerController::detachGame(CoreController* controller) {
|
||||||
QPair<QString, QString> path(controller->path(), controller->baseDirectory());
|
QPair<QString, QString> path(controller->path(), controller->baseDirectory());
|
||||||
Player& p = m_pids.find(pid).value();
|
Player& p = m_pids.find(pid).value();
|
||||||
if (!p.saveId) {
|
if (!p.saveId) {
|
||||||
LOG(QT, ERROR) << "Clearing invalid save ID";
|
LOG(QT, WARN) << "Clearing invalid save ID";
|
||||||
} else {
|
} else {
|
||||||
m_claimed[path] &= ~(1 << (p.saveId - 1));
|
m_claimedSaves[path] &= ~(1 << (p.saveId - 1));
|
||||||
if (!m_claimed[path]) {
|
if (!m_claimedSaves[path]) {
|
||||||
m_claimed.remove(path);
|
m_claimedSaves.remove(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p.preferredId < 0) {
|
||||||
|
LOG(QT, WARN) << "Clearing invalid preferred ID";
|
||||||
|
} else {
|
||||||
|
m_claimedIds &= ~(1 << p.preferredId);
|
||||||
|
}
|
||||||
|
|
||||||
m_pids.remove(pid);
|
m_pids.remove(pid);
|
||||||
if (m_pids.size() == 0) {
|
if (m_pids.size() == 0) {
|
||||||
m_platform = mPLATFORM_NONE;
|
m_platform = mPLATFORM_NONE;
|
||||||
|
@ -417,8 +440,17 @@ int MultiplayerController::saveId(CoreController* controller) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int MultiplayerController::attached() {
|
int MultiplayerController::attached() {
|
||||||
int num;
|
int num = 0;
|
||||||
num = m_lockstep.attached;
|
switch (m_platform) {
|
||||||
|
case mPLATFORM_GB:
|
||||||
|
num = m_lockstep.attached;
|
||||||
|
break;
|
||||||
|
case mPLATFORM_GBA:
|
||||||
|
num = saturateCast<int>(GBASIOLockstepCoordinatorAttached(&m_gbaCoordinator));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,8 +488,8 @@ void MultiplayerController::fixOrder() {
|
||||||
for (int pid : m_pids.keys()) {
|
for (int pid : m_pids.keys()) {
|
||||||
Player& p = m_pids.find(pid).value();
|
Player& p = m_pids.find(pid).value();
|
||||||
GBA* gba = static_cast<GBA*>(p.controller->thread()->core->board);
|
GBA* gba = static_cast<GBA*>(p.controller->thread()->core->board);
|
||||||
GBASIOLockstepNode* node = reinterpret_cast<GBASIOLockstepNode*>(gba->sio.drivers.multiplayer);
|
GBASIOLockstepDriver* node = reinterpret_cast<GBASIOLockstepDriver*>(gba->sio.drivers.multiplayer);
|
||||||
m_players[node->id] = pid;
|
m_players[node->d.deviceId(&node->d)] = pid;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -49,7 +49,7 @@ signals:
|
||||||
private:
|
private:
|
||||||
union Node {
|
union Node {
|
||||||
GBSIOLockstepNode* gb;
|
GBSIOLockstepNode* gb;
|
||||||
GBASIOLockstepNode* gba;
|
GBASIOLockstepDriver* gba;
|
||||||
};
|
};
|
||||||
struct Player {
|
struct Player {
|
||||||
Player(CoreController* controller);
|
Player(CoreController* controller);
|
||||||
|
@ -63,6 +63,11 @@ private:
|
||||||
int32_t cyclesPosted = 0;
|
int32_t cyclesPosted = 0;
|
||||||
unsigned waitMask = 0;
|
unsigned waitMask = 0;
|
||||||
int saveId = 1;
|
int saveId = 1;
|
||||||
|
int preferredId = 0;
|
||||||
|
};
|
||||||
|
struct LockstepUser : mLockstepThreadUser {
|
||||||
|
MultiplayerController* controller;
|
||||||
|
int pid;
|
||||||
};
|
};
|
||||||
|
|
||||||
Player* player(int id);
|
Player* player(int id);
|
||||||
|
@ -73,18 +78,20 @@ private:
|
||||||
mLockstep m_lockstep;
|
mLockstep m_lockstep;
|
||||||
#ifdef M_CORE_GB
|
#ifdef M_CORE_GB
|
||||||
GBSIOLockstep m_gbLockstep;
|
GBSIOLockstep m_gbLockstep;
|
||||||
#endif
|
|
||||||
#ifdef M_CORE_GBA
|
|
||||||
GBASIOLockstep m_gbaLockstep;
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef M_CORE_GBA
|
||||||
|
GBASIOLockstepCoordinator m_gbaCoordinator;
|
||||||
|
#endif
|
||||||
|
|
||||||
mPlatform m_platform = mPLATFORM_NONE;
|
mPlatform m_platform = mPLATFORM_NONE;
|
||||||
int m_nextPid = 0;
|
int m_nextPid = 0;
|
||||||
|
int m_claimedIds = 0;
|
||||||
QHash<int, Player> m_pids;
|
QHash<int, Player> m_pids;
|
||||||
QList<int> m_players;
|
QList<int> m_players;
|
||||||
QMutex m_lock;
|
QMutex m_lock;
|
||||||
QHash<QPair<QString, QString>, int> m_claimed;
|
QHash<QPair<QString, QString>, int> m_claimedSaves;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue