all repos — mgba @ ceea51b55ea2f112c49b4ad22e6d70b08ad430e7

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