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 <mgba/core/sync.h>
7 
8 #include <mgba/core/blip_buf.h>
9 
_changeVideoSync(struct mCoreSync * sync,bool frameOn)10 static void _changeVideoSync(struct mCoreSync* sync, bool frameOn) {
11 	// Make sure the video thread can process events while the GBA thread is paused
12 	MutexLock(&sync->videoFrameMutex);
13 	if (frameOn != sync->videoFrameOn) {
14 		sync->videoFrameOn = frameOn;
15 		ConditionWake(&sync->videoFrameAvailableCond);
16 	}
17 	MutexUnlock(&sync->videoFrameMutex);
18 }
19 
mCoreSyncPostFrame(struct mCoreSync * sync)20 void mCoreSyncPostFrame(struct mCoreSync* sync) {
21 	if (!sync) {
22 		return;
23 	}
24 
25 	MutexLock(&sync->videoFrameMutex);
26 	++sync->videoFramePending;
27 	do {
28 		ConditionWake(&sync->videoFrameAvailableCond);
29 		if (sync->videoFrameWait) {
30 			ConditionWait(&sync->videoFrameRequiredCond, &sync->videoFrameMutex);
31 		}
32 	} while (sync->videoFrameWait && sync->videoFramePending);
33 	MutexUnlock(&sync->videoFrameMutex);
34 }
35 
mCoreSyncForceFrame(struct mCoreSync * sync)36 void mCoreSyncForceFrame(struct mCoreSync* sync) {
37 	if (!sync) {
38 		return;
39 	}
40 
41 	MutexLock(&sync->videoFrameMutex);
42 	ConditionWake(&sync->videoFrameAvailableCond);
43 	MutexUnlock(&sync->videoFrameMutex);
44 }
45 
mCoreSyncWaitFrameStart(struct mCoreSync * sync)46 bool mCoreSyncWaitFrameStart(struct mCoreSync* sync) {
47 	if (!sync) {
48 		return true;
49 	}
50 
51 	MutexLock(&sync->videoFrameMutex);
52 	ConditionWake(&sync->videoFrameRequiredCond);
53 	if (!sync->videoFrameOn && !sync->videoFramePending) {
54 		return false;
55 	}
56 	if (sync->videoFrameOn) {
57 		if (ConditionWaitTimed(&sync->videoFrameAvailableCond, &sync->videoFrameMutex, 50)) {
58 			return false;
59 		}
60 	}
61 	sync->videoFramePending = 0;
62 	return true;
63 }
64 
mCoreSyncWaitFrameEnd(struct mCoreSync * sync)65 void mCoreSyncWaitFrameEnd(struct mCoreSync* sync) {
66 	if (!sync) {
67 		return;
68 	}
69 
70 	MutexUnlock(&sync->videoFrameMutex);
71 }
72 
mCoreSyncSetVideoSync(struct mCoreSync * sync,bool wait)73 void mCoreSyncSetVideoSync(struct mCoreSync* sync, bool wait) {
74 	if (!sync) {
75 		return;
76 	}
77 
78 	_changeVideoSync(sync, wait);
79 }
80 
mCoreSyncProduceAudio(struct mCoreSync * sync,const struct blip_t * buf,size_t samples)81 bool mCoreSyncProduceAudio(struct mCoreSync* sync, const struct blip_t* buf, size_t samples) {
82 	if (!sync) {
83 		return true;
84 	}
85 
86 	size_t produced = blip_samples_avail(buf);
87 	size_t producedNew = produced;
88 	while (sync->audioWait && producedNew >= samples) {
89 		ConditionWait(&sync->audioRequiredCond, &sync->audioBufferMutex);
90 		produced = producedNew;
91 		producedNew = blip_samples_avail(buf);
92 	}
93 	MutexUnlock(&sync->audioBufferMutex);
94 	return producedNew != produced;
95 }
96 
mCoreSyncLockAudio(struct mCoreSync * sync)97 void mCoreSyncLockAudio(struct mCoreSync* sync) {
98 	if (!sync) {
99 		return;
100 	}
101 
102 	MutexLock(&sync->audioBufferMutex);
103 }
104 
mCoreSyncUnlockAudio(struct mCoreSync * sync)105 void mCoreSyncUnlockAudio(struct mCoreSync* sync) {
106 	if (!sync) {
107 		return;
108 	}
109 
110 	MutexUnlock(&sync->audioBufferMutex);
111 }
112 
mCoreSyncConsumeAudio(struct mCoreSync * sync)113 void mCoreSyncConsumeAudio(struct mCoreSync* sync) {
114 	if (!sync) {
115 		return;
116 	}
117 
118 	ConditionWake(&sync->audioRequiredCond);
119 	MutexUnlock(&sync->audioBufferMutex);
120 }
121