all repos — mgba @ 97447ffa40d6f90ae5f1daf84987e6ff7688d0b8

mGBA Game Boy Advance Emulator

src/gba/supervisor/sync.c (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 "thread.h"
  7
  8static void _changeVideoSync(struct GBASync* sync, bool frameOn) {
  9	// Make sure the video thread can process events while the GBA thread is paused
 10	MutexLock(&sync->videoFrameMutex);
 11	if (frameOn != sync->videoFrameOn) {
 12		sync->videoFrameOn = frameOn;
 13		ConditionWake(&sync->videoFrameAvailableCond);
 14	}
 15	MutexUnlock(&sync->videoFrameMutex);
 16}
 17
 18void GBASyncPostFrame(struct GBASync* sync) {
 19	if (!sync) {
 20		return;
 21	}
 22
 23	MutexLock(&sync->videoFrameMutex);
 24	++sync->videoFramePending;
 25	--sync->videoFrameSkip;
 26	if (sync->videoFrameSkip < 0) {
 27		do {
 28			ConditionWake(&sync->videoFrameAvailableCond);
 29			if (sync->videoFrameWait) {
 30				ConditionWait(&sync->videoFrameRequiredCond, &sync->videoFrameMutex);
 31			}
 32		} while (sync->videoFrameWait && sync->videoFramePending);
 33	}
 34	MutexUnlock(&sync->videoFrameMutex);
 35}
 36
 37void GBASyncForceFrame(struct GBASync* sync) {
 38	if (!sync) {
 39		return;
 40	}
 41
 42	MutexLock(&sync->videoFrameMutex);
 43	ConditionWake(&sync->videoFrameAvailableCond);
 44	MutexUnlock(&sync->videoFrameMutex);
 45}
 46
 47bool GBASyncWaitFrameStart(struct GBASync* sync, int frameskip) {
 48	if (!sync) {
 49		return true;
 50	}
 51
 52	MutexLock(&sync->videoFrameMutex);
 53	ConditionWake(&sync->videoFrameRequiredCond);
 54	if (!sync->videoFrameOn && !sync->videoFramePending) {
 55		return false;
 56	}
 57	if (sync->videoFrameOn) {
 58		if (ConditionWaitTimed(&sync->videoFrameAvailableCond, &sync->videoFrameMutex, 50)) {
 59			return false;
 60		}
 61	}
 62	sync->videoFramePending = 0;
 63	sync->videoFrameSkip = frameskip;
 64	return true;
 65}
 66
 67void GBASyncWaitFrameEnd(struct GBASync* sync) {
 68	if (!sync) {
 69		return;
 70	}
 71
 72	MutexUnlock(&sync->videoFrameMutex);
 73}
 74
 75bool GBASyncDrawingFrame(struct GBASync* sync) {
 76	if (!sync) {
 77		return true;
 78	}
 79
 80	return sync->videoFrameSkip <= 0;
 81}
 82
 83void GBASyncSetVideoSync(struct GBASync* sync, bool wait) {
 84	if (!sync) {
 85		return;
 86	}
 87
 88	_changeVideoSync(sync, wait);
 89}
 90
 91void GBASyncProduceAudio(struct GBASync* sync, bool wait) {
 92	if (!sync) {
 93		return;
 94	}
 95
 96	if (sync->audioWait && wait) {
 97		// TODO loop properly in event of spurious wakeups
 98		ConditionWait(&sync->audioRequiredCond, &sync->audioBufferMutex);
 99	}
100	MutexUnlock(&sync->audioBufferMutex);
101}
102
103void GBASyncLockAudio(struct GBASync* sync) {
104	if (!sync) {
105		return;
106	}
107
108	MutexLock(&sync->audioBufferMutex);
109}
110
111void GBASyncUnlockAudio(struct GBASync* sync) {
112	if (!sync) {
113		return;
114	}
115
116	MutexUnlock(&sync->audioBufferMutex);
117}
118
119void GBASyncConsumeAudio(struct GBASync* sync) {
120	if (!sync) {
121		return;
122	}
123
124	ConditionWake(&sync->audioRequiredCond);
125	MutexUnlock(&sync->audioBufferMutex);
126}