PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
vblank.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9*/
10
11#include "vblank.h"
12#include "irx_imports.h"
13#include "kerr.h"
14
15extern struct irx_export_table _exp_vblank;
16
17#ifdef _IOP
18IRX_ID("Vblank_service", 1, 1);
19#endif
20// Based on the module from SCE SDK 1.3.4.
21
22static vblank_internals_t vblank_internals;
23
24static int irq_vblank_interrupt_handler(void *userdata);
25static int irq_evblank_interrupt_handler(void *userdata);
26static int vblank_handler_base_beginning(void *userdata);
27static int vblank_handler_base_end(void *userdata);
28static void linked_list_set_self(vblank_ll_t *ll);
29static int linked_list_next_is_self(const vblank_ll_t *ll);
30static void linked_list_remove(vblank_ll_t *ll);
31static void linked_list_add_after(vblank_ll_t *ll1, vblank_ll_t *ll2);
32
33int _start(int ac, char **av)
34{
35 unsigned int i;
36 iop_event_t evfp;
37 int state;
38
39 (void)ac;
40 (void)av;
41
42 CpuSuspendIntr(&state);
43 if ( RegisterLibraryEntries(&_exp_vblank) )
44 {
45 CpuResumeIntr(state);
46 return 1;
47 }
48
49 memset(&vblank_internals, 0, sizeof(vblank_internals));
50 linked_list_set_self(&vblank_internals.list_00);
51 linked_list_set_self(&vblank_internals.list_11);
52 linked_list_set_self(&vblank_internals.list_free);
53 for ( i = 0; i < (sizeof(vblank_internals.list_items) / sizeof(vblank_internals.list_items[0])); i += 1 )
54 {
55 linked_list_add_after(&vblank_internals.list_free, &(vblank_internals.list_items[i].ll));
56 }
57 evfp.bits = 0;
58 evfp.attr = EA_MULTI;
59 evfp.option = 0;
60 vblank_internals.ef = CreateEventFlag(&evfp);
61 RegisterVblankHandler(0, 128, vblank_handler_base_beginning, &vblank_internals);
62 RegisterVblankHandler(1, 128, vblank_handler_base_end, &vblank_internals);
63 RegisterIntrHandler(IOP_IRQ_VBLANK, 1, irq_vblank_interrupt_handler, &vblank_internals);
64 RegisterIntrHandler(IOP_IRQ_EVBLANK, 1, irq_evblank_interrupt_handler, &vblank_internals);
65 EnableIntr(IOP_IRQ_VBLANK);
66 EnableIntr(IOP_IRQ_EVBLANK);
67 CpuResumeIntr(state);
68 return 0;
69}
70
71vblank_internals_t *GetVblankInternalData(void)
72{
73 return &vblank_internals;
74}
75
76int RegisterVblankHandler(int startend, int priority, int (*handler)(void *userdata), void *arg)
77{
78 const vblank_ll_t *list;
79 vblank_ll_t *item;
80 vblank_item_t *item_new;
81 int state;
82
83 if ( QueryIntrContext() != 0 )
84 {
85 return KE_ILLEGAL_CONTEXT;
86 }
87 CpuSuspendIntr(&state);
88 if ( linked_list_next_is_self(&vblank_internals.list_free) )
89 {
90 CpuResumeIntr(state);
91 return KE_NO_MEMORY;
92 }
93 list = &vblank_internals.list_11;
94 if ( !startend )
95 list = &vblank_internals.list_00;
96 item = list->next;
97 if ( list->next != list )
98 {
99 do
100 {
101 const vblank_item_t *item_vblank;
102
103 item_vblank = (vblank_item_t *)item;
104 if ( item_vblank->callback == handler )
105 {
106 CpuResumeIntr(state);
107 return KE_FOUND_HANDLER;
108 }
109 item = item->next;
110 } while ( item != list );
111 item = list->next;
112 }
113 for ( ; item != list; item = item->next )
114 {
115 const vblank_item_t *item_vblank;
116
117 item_vblank = (vblank_item_t *)item;
118 if ( priority < item_vblank->priority )
119 break;
120 }
121 item_new = (vblank_item_t *)vblank_internals.list_free.next;
122 linked_list_remove(vblank_internals.list_free.next);
123 item_new->callback = handler;
124 item_new->userdata = arg;
125 item_new->priority = priority;
126 linked_list_add_after(item, &item_new->ll);
127 CpuResumeIntr(state);
128 return 0;
129}
130
131// cppcheck-suppress constParameterPointer
132int ReleaseVblankHandler(int startend, int (*handler)(void *userdata))
133{
134 const vblank_ll_t *list;
135 vblank_ll_t *item;
136 int state;
137
138 if ( QueryIntrContext() != 0 )
139 {
140 return KE_ILLEGAL_CONTEXT;
141 }
142 CpuSuspendIntr(&state);
143 list = &vblank_internals.list_11;
144 if ( !startend )
145 list = &vblank_internals.list_00;
146 item = list->next;
147 if ( list->next == list )
148 {
149 CpuResumeIntr(state);
150 return KE_NOTFOUND_HANDLER;
151 }
152 {
153 const vblank_item_t *item_vblank;
154
155 item_vblank = (vblank_item_t *)item;
156 while ( item_vblank->callback != handler )
157 {
158 item = item->next;
159 item_vblank = (vblank_item_t *)item;
160 if ( item == list )
161 {
162 CpuResumeIntr(state);
163 return KE_NOTFOUND_HANDLER;
164 }
165 }
166 }
167 linked_list_remove(item);
168 linked_list_add_after(&vblank_internals.list_free, item);
169 CpuResumeIntr(state);
170 return 0;
171}
172
173static int irq_vblank_interrupt_handler(void *userdata)
174{
175 int item_count;
176 vblank_ll_t *item;
177 vblank_ll_t *item_tmp;
179
180 vbi = (vblank_internals_t *)userdata;
181 item_count = vbi->item_count;
182 if ( !item_count )
183 {
184 iSetEventFlag(GetSystemStatusFlag(), 0x200);
185 item_count = vbi->item_count;
186 }
187 item = vbi->list_00.next;
188 vbi->item_count = item_count + 1;
189 if ( item != &vbi->list_00 )
190 {
191 do
192 {
193 vblank_item_t *item_vblank;
194
195 item_vblank = (vblank_item_t *)item;
196 item_tmp = item->next;
197 if ( item_vblank->callback(item_vblank->userdata) == 0 )
198 {
199 linked_list_remove(item);
200 linked_list_add_after(&vbi->list_free, item);
201 }
202 item = item_tmp;
203 } while ( item_tmp != &vbi->list_00 );
204 }
205 return 1;
206}
207
208static int irq_evblank_interrupt_handler(void *userdata)
209{
210 vblank_ll_t *item;
211 const vblank_ll_t *list_tail;
212 vblank_ll_t *item_tmp;
214
215 vbi = (vblank_internals_t *)userdata;
216 item = vbi->list_11.next;
217 list_tail = &vbi->list_11;
218 if ( item != list_tail )
219 {
220 do
221 {
222 vblank_item_t *item_vblank;
223
224 item_vblank = (vblank_item_t *)item;
225 item_tmp = item->next;
226 if ( item_vblank->callback(item_vblank->userdata) == 0 )
227 {
228 linked_list_remove(item);
229 linked_list_add_after(&vbi->list_free, item);
230 }
231 item = item_tmp;
232 } while ( item_tmp != list_tail );
233 }
234 return 1;
235}
236
237#define EF_VBLANK_START 1
238#define EF_VBLANK_END 4
239#define EF_VBLANK 2
240#define EF_NON_VBLANK 8
241
242static int vblank_handler_base_beginning(void *userdata)
243{
245
246 vbi = (vblank_internals_t *)userdata;
247 iSetEventFlag(vbi->ef, EF_VBLANK_START);
248 iSetEventFlag(vbi->ef, EF_VBLANK);
249 iClearEventFlag(vbi->ef, ~(9));
250 return 1;
251}
252
253static int vblank_handler_base_end(void *userdata)
254{
256
257 vbi = (vblank_internals_t *)userdata;
258 iSetEventFlag(vbi->ef, EF_VBLANK_END);
259 iSetEventFlag(vbi->ef, EF_NON_VBLANK);
260 iClearEventFlag(vbi->ef, ~(6));
261 return 1;
262}
263
264void WaitVblankStart()
265{
266 WaitEventFlag(vblank_internals.ef, EF_VBLANK_START, WEF_OR, NULL);
267}
268
269void WaitVblankEnd()
270{
271 WaitEventFlag(vblank_internals.ef, EF_VBLANK_END, WEF_OR, NULL);
272}
273
274void WaitVblank()
275{
276 WaitEventFlag(vblank_internals.ef, EF_VBLANK, WEF_OR, NULL);
277}
278
279void WaitNonVblank()
280{
281 WaitEventFlag(vblank_internals.ef, EF_NON_VBLANK, WEF_OR, NULL);
282}
283
284static void linked_list_set_self(vblank_ll_t *ll)
285{
286 ll->next = ll;
287 ll->prev = ll;
288}
289
290static int linked_list_next_is_self(const vblank_ll_t *ll)
291{
292 return ll->next == ll;
293}
294
295static void linked_list_remove(vblank_ll_t *ll)
296{
297 ll->next->prev = ll->prev;
298 ll->prev->next = ll->next;
299}
300
301#if 0
302// This function is unused
303static int linked_list_is_circular(vblank_ll_t *ll)
304{
305 return ll->prev == ll->next;
306}
307#endif
308
309static void linked_list_add_after(vblank_ll_t *ll1, vblank_ll_t *ll2)
310{
311 ll2->next = ll1;
312 ll2->prev = ll1->prev;
313 ll1->prev = ll2;
314 ll2->prev->next = ll2;
315}
int CpuResumeIntr(int state)
Definition intrman.c:227
int QueryIntrContext(void)
int CpuSuspendIntr(int *state)
Definition intrman.c:205
int RegisterIntrHandler(int irq, int mode, int(*handler)(void *arg), void *arg)
Definition intrman.c:125
int EnableIntr(int irq)
Definition intrman.c:346
#define EA_MULTI
Definition thevent.h:35