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