all repos — mgba @ a760c7bb4a85c8abea17ff9db466e96ebe20a8de

mGBA Game Boy Advance Emulator

src/platform/qt/MultiplayerController.cpp (view raw)

  1/* Copyright (c) 2013-2015 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "MultiplayerController.h"
  7
  8#include "CoreController.h"
  9
 10#ifdef M_CORE_GBA
 11#include <mgba/internal/gba/gba.h>
 12#endif
 13#ifdef M_CORE_GB
 14#include <mgba/internal/gb/gb.h>
 15#endif
 16
 17using namespace QGBA;
 18
 19#ifdef M_CORE_GB
 20MultiplayerController::Player::Player(CoreController* coreController, GBSIOLockstepNode* node)
 21	: controller(coreController)
 22	, gbNode(node)
 23{
 24}
 25#endif
 26
 27#ifdef M_CORE_GBA
 28MultiplayerController::Player::Player(CoreController* coreController, GBASIOLockstepNode* node)
 29	: controller(coreController)
 30	, gbaNode(node)
 31{
 32}
 33#endif
 34
 35MultiplayerController::MultiplayerController() {
 36	mLockstepInit(&m_lockstep);
 37	m_lockstep.context = this;
 38	m_lockstep.lock = [](mLockstep* lockstep) {
 39		MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
 40		controller->m_lock.lock();
 41	};
 42	m_lockstep.unlock = [](mLockstep* lockstep) {
 43		MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
 44		controller->m_lock.unlock();
 45	};
 46	m_lockstep.signal = [](mLockstep* lockstep, unsigned mask) {
 47		MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
 48		Player* player = &controller->m_players[0];
 49		bool woke = false;
 50		player->waitMask &= ~mask;
 51		if (!player->waitMask && player->awake < 1) {
 52			mCoreThreadStopWaiting(player->controller->thread());
 53			player->awake = 1;
 54			woke = true;
 55		}
 56		return woke;
 57	};
 58	m_lockstep.wait = [](mLockstep* lockstep, unsigned mask) {
 59		MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
 60		Player* player = &controller->m_players[0];
 61		bool slept = false;
 62		player->waitMask |= mask;
 63		if (player->awake > 0) {
 64			mCoreThreadWaitFromThread(player->controller->thread());
 65			player->awake = 0;
 66			slept = true;
 67		}
 68		return slept;
 69	};
 70	m_lockstep.addCycles = [](mLockstep* lockstep, int id, int32_t cycles) {
 71		if (cycles < 0) {
 72			abort();
 73		}
 74		MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
 75		if (!id) {
 76			for (int i = 1; i < controller->m_players.count(); ++i) {
 77				Player* player = &controller->m_players[i];
 78#ifdef M_CORE_GBA
 79				if (player->controller->platform() == mPLATFORM_GBA && player->gbaNode->d.p->mode != controller->m_players[0].gbaNode->d.p->mode) {
 80					player->controller->setSync(true);
 81					continue;
 82				}
 83#endif
 84				player->controller->setSync(false);
 85				player->cyclesPosted += cycles;
 86				if (player->awake < 1) {
 87					switch (player->controller->platform()) {
 88#ifdef M_CORE_GBA
 89					case mPLATFORM_GBA:
 90						player->gbaNode->nextEvent += player->cyclesPosted;
 91						break;
 92#endif
 93#ifdef M_CORE_GB
 94					case mPLATFORM_GB:
 95						player->gbNode->nextEvent += player->cyclesPosted;
 96						break;
 97#endif
 98					default:
 99						break;
100					}
101					mCoreThreadStopWaiting(player->controller->thread());
102					player->awake = 1;
103				}
104			}
105		} else {
106			controller->m_players[id].controller->setSync(true);
107			controller->m_players[id].cyclesPosted += cycles;
108		}
109	};
110	m_lockstep.useCycles = [](mLockstep* lockstep, int id, int32_t cycles) {
111		MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
112		Player* player = &controller->m_players[id];
113		player->cyclesPosted -= cycles;
114		if (player->cyclesPosted <= 0) {
115			mCoreThreadWaitFromThread(player->controller->thread());
116			player->awake = 0;
117		}
118		cycles = player->cyclesPosted;
119		return cycles;
120	};
121	m_lockstep.unusedCycles= [](mLockstep* lockstep, int id) {
122		MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
123		Player* player = &controller->m_players[id];
124		auto cycles = player->cyclesPosted;
125		return cycles;
126	};
127	m_lockstep.unload = [](mLockstep* lockstep, int id) {
128		MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
129		if (id) {
130			Player* player = &controller->m_players[id];
131			player->controller->setSync(true);
132			player->cyclesPosted = 0;
133
134			// release master GBA if it is waiting for this GBA
135			player = &controller->m_players[0];
136			player->waitMask &= ~(1 << id);
137			if (!player->waitMask && player->awake < 1) {
138				mCoreThreadStopWaiting(player->controller->thread());
139				player->awake = 1;
140			}
141		} else {
142			for (int i = 1; i < controller->m_players.count(); ++i) {
143				Player* player = &controller->m_players[i];
144				player->controller->setSync(true);
145				switch (player->controller->platform()) {
146#ifdef M_CORE_GBA
147				case mPLATFORM_GBA:
148					player->cyclesPosted += reinterpret_cast<GBASIOLockstep*>(lockstep)->players[0]->eventDiff;
149					break;
150#endif
151#ifdef M_CORE_GB
152				case mPLATFORM_GB:
153					player->cyclesPosted += reinterpret_cast<GBSIOLockstep*>(lockstep)->players[0]->eventDiff;
154					break;
155#endif
156				default:
157					break;
158				}
159				if (player->awake < 1) {
160					switch (player->controller->platform()) {
161#ifdef M_CORE_GBA
162					case mPLATFORM_GBA:
163						player->gbaNode->nextEvent += player->cyclesPosted;
164						break;
165#endif
166#ifdef M_CORE_GB
167					case mPLATFORM_GB:
168						player->gbNode->nextEvent += player->cyclesPosted;
169						break;
170#endif
171					default:
172						break;
173					}
174					mCoreThreadStopWaiting(player->controller->thread());
175					player->awake = 1;
176				}
177			}
178		}
179	};
180}
181
182MultiplayerController::~MultiplayerController() {
183	mLockstepDeinit(&m_lockstep);
184}
185
186bool MultiplayerController::attachGame(CoreController* controller) {
187	if (m_lockstep.attached == MAX_GBAS) {
188		return false;
189	}
190
191	if (m_lockstep.attached == 0) {
192		switch (controller->platform()) {
193#ifdef M_CORE_GBA
194		case mPLATFORM_GBA:
195			GBASIOLockstepInit(&m_gbaLockstep);
196			break;
197#endif
198#ifdef M_CORE_GB
199		case mPLATFORM_GB:
200			GBSIOLockstepInit(&m_gbLockstep);
201			break;
202#endif
203		default:
204			return false;
205		}
206	}
207
208	mCoreThread* thread = controller->thread();
209	if (!thread) {
210		return false;
211	}
212
213	switch (controller->platform()) {
214#ifdef M_CORE_GBA
215	case mPLATFORM_GBA: {
216		GBA* gba = static_cast<GBA*>(thread->core->board);
217
218		GBASIOLockstepNode* node = new GBASIOLockstepNode;
219		GBASIOLockstepNodeCreate(node);
220		GBASIOLockstepAttachNode(&m_gbaLockstep, node);
221		m_players.append({controller, node});
222
223		GBASIOSetDriver(&gba->sio, &node->d, SIO_MULTI);
224		GBASIOSetDriver(&gba->sio, &node->d, SIO_NORMAL_32);
225
226		emit gameAttached();
227		return true;
228	}
229#endif
230#ifdef M_CORE_GB
231	case mPLATFORM_GB: {
232		GB* gb = static_cast<GB*>(thread->core->board);
233
234		GBSIOLockstepNode* node = new GBSIOLockstepNode;
235		GBSIOLockstepNodeCreate(node);
236		GBSIOLockstepAttachNode(&m_gbLockstep, node);
237		m_players.append({controller, node});
238
239		GBSIOSetDriver(&gb->sio, &node->d);
240
241		emit gameAttached();
242		return true;
243	}
244#endif
245	default:
246		break;
247	}
248
249	return false;
250}
251
252void MultiplayerController::detachGame(CoreController* controller) {
253	if (m_players.empty()) {
254		return;
255	}
256	mCoreThread* thread = controller->thread();
257	if (!thread) {
258		return;
259	}
260	QList<CoreController::Interrupter> interrupters;
261
262	for (int i = 0; i < m_players.count(); ++i) {
263		interrupters.append(m_players[i].controller);
264	}
265	switch (controller->platform()) {
266#ifdef M_CORE_GBA
267	case mPLATFORM_GBA: {
268		GBA* gba = static_cast<GBA*>(thread->core->board);
269		GBASIOLockstepNode* node = reinterpret_cast<GBASIOLockstepNode*>(gba->sio.drivers.multiplayer);
270		GBASIOSetDriver(&gba->sio, nullptr, SIO_MULTI);
271		GBASIOSetDriver(&gba->sio, nullptr, SIO_NORMAL_32);
272		if (node) {
273			GBASIOLockstepDetachNode(&m_gbaLockstep, node);
274			delete node;
275		}
276		break;
277	}
278#endif
279#ifdef M_CORE_GB
280	case mPLATFORM_GB: {
281		GB* gb = static_cast<GB*>(thread->core->board);
282		GBSIOLockstepNode* node = reinterpret_cast<GBSIOLockstepNode*>(gb->sio.driver);
283		GBSIOSetDriver(&gb->sio, nullptr);
284		if (node) {
285			GBSIOLockstepDetachNode(&m_gbLockstep, node);
286			delete node;
287		}
288		break;
289	}
290#endif
291	default:
292		break;
293	}
294
295	for (int i = 0; i < m_players.count(); ++i) {
296		if (m_players[i].controller == controller) {
297			m_players.removeAt(i);
298			break;
299		}
300	}
301	emit gameDetached();
302}
303
304int MultiplayerController::playerId(CoreController* controller) {
305	for (int i = 0; i < m_players.count(); ++i) {
306		if (m_players[i].controller == controller) {
307			return i;
308		}
309	}
310	return -1;
311}
312
313int MultiplayerController::attached() {
314	int num;
315	num = m_lockstep.attached;
316	return num;
317}