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}