gpu_neon: flush queues before reads too
[pcsx_rearmed.git] / frontend / plugin_lib.c
1 /*
2  * (C) notaz, 2010-2011
3  *
4  * This work is licensed under the terms of the GNU GPLv2 or later.
5  * See the COPYING file in the top-level directory.
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdarg.h>
12 #include <stdint.h>
13 #include <sys/time.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <unistd.h>
18 #include <pthread.h>
19
20 #include "plugin_lib.h"
21 #include "linux/fbdev.h"
22 #include "common/fonts.h"
23 #include "common/input.h"
24 #include "omap.h"
25 #include "menu.h"
26 #include "main.h"
27 #include "plat.h"
28 #include "pcnt.h"
29 #include "pl_gun_ts.h"
30 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
31 #include "../libpcsxcore/psemu_plugin_defs.h"
32
33 int in_type1, in_type2;
34 int in_a1[2] = { 127, 127 }, in_a2[2] = { 127, 127 };
35 int in_adev[2] = { -1, -1 }, in_adev_axis[2][2] = {{ 0, 1 }, { 0, 1 }};
36 int in_keystate, in_state_gun;
37 int in_enable_vibration;
38 int pl_flip_cnt;
39 void *tsdev;
40 void *pl_vout_buf;
41 static int pl_vout_w, pl_vout_h, pl_vout_bpp;
42 static int vsync_cnt, flips_per_sec, tick_per_sec;
43 static float vsps_cur;
44 static int frame_interval, frame_interval1024, vsync_usec_time;
45
46
47 static __attribute__((noinline)) int get_cpu_ticks(void)
48 {
49         static unsigned long last_utime;
50         static int fd;
51         unsigned long utime, ret;
52         char buf[128];
53
54         if (fd == 0)
55                 fd = open("/proc/self/stat", O_RDONLY);
56         lseek(fd, 0, SEEK_SET);
57         buf[0] = 0;
58         read(fd, buf, sizeof(buf));
59         buf[sizeof(buf) - 1] = 0;
60
61         sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu", &utime);
62         ret = utime - last_utime;
63         last_utime = utime;
64         return ret;
65 }
66
67 static void print_msg(int h, int border)
68 {
69         if (pl_vout_bpp == 16)
70                 pl_text_out16(border + 2, h - 10, "%s", hud_msg);
71 }
72
73 static void print_fps(int h, int border)
74 {
75         if (pl_vout_bpp == 16)
76                 pl_text_out16(border + 2, h - 10, "%2d %4.1f", flips_per_sec, vsps_cur);
77 }
78
79 static void print_cpu_usage(int w, int h, int border)
80 {
81         if (pl_vout_bpp == 16)
82                 pl_text_out16(w - border - 28, h - 10, "%3d", tick_per_sec);
83 }
84
85 // draw 192x8 status of 24 sound channels
86 static __attribute__((noinline)) void draw_active_chans(int vout_w, int vout_h)
87 {
88         extern void spu_get_debug_info(int *chans_out, int *run_chans,
89                 int *fmod_chans_out, int *noise_chans_out); // hack
90         int live_chans, run_chans, fmod_chans, noise_chans;
91
92         static const unsigned short colors[2] = { 0x1fe3, 0x0700 };
93         unsigned short *dest = (unsigned short *)pl_vout_buf +
94                 vout_w * (vout_h - 10) + vout_w / 2 - 192/2;
95         unsigned short *d, p;
96         int c, x, y;
97
98         if (pl_vout_bpp != 16)
99                 return;
100
101         spu_get_debug_info(&live_chans, &run_chans, &fmod_chans, &noise_chans);
102
103         for (c = 0; c < 24; c++) {
104                 d = dest + c * 8;
105                 p = !(live_chans & (1<<c)) ? (run_chans & (1<<c) ? 0x01c0 : 0) :
106                      (fmod_chans & (1<<c)) ? 0xf000 :
107                      (noise_chans & (1<<c)) ? 0x001f :
108                      colors[c & 1];
109                 for (y = 0; y < 8; y++, d += vout_w)
110                         for (x = 0; x < 8; x++)
111                                 d[x] = p;
112         }
113 }
114
115 void pl_print_hud(int w, int h, int xborder)
116 {
117         pl_vout_w = w; // used by pollux
118         pl_vout_h = h;
119
120         if (g_opts & OPT_SHOWSPU)
121                 draw_active_chans(w, h);
122
123         if (hud_msg[0] != 0)
124                 print_msg(h, xborder);
125         else if (g_opts & OPT_SHOWFPS)
126                 print_fps(h, xborder);
127
128         if (g_opts & OPT_SHOWCPU)
129                 print_cpu_usage(w, h, xborder);
130 }
131
132 static void *pl_vout_set_mode(int w, int h, int bpp)
133 {
134         // special h handling, Wipeout likes to change it by 1-6
135         static int vsync_cnt_ms_prev;
136         if ((unsigned int)(vsync_cnt - vsync_cnt_ms_prev) < 5*60)
137                 h = (h + 7) & ~7;
138         vsync_cnt_ms_prev = vsync_cnt;
139
140         if (w == pl_vout_w && h == pl_vout_h && bpp == pl_vout_bpp)
141                 return pl_vout_buf;
142
143         pl_vout_w = w;
144         pl_vout_h = h;
145         pl_vout_bpp = bpp;
146
147 #if defined(VOUT_FBDEV)
148         vout_fbdev_clear(layer_fb);
149         pl_vout_buf = vout_fbdev_resize(layer_fb, w, h, bpp, 0, 0, 0, 0, 3);
150 #elif defined(MAEMO)
151         extern void *hildon_set_mode(int w, int h);
152         pl_vout_buf = hildon_set_mode(w, h);
153 #endif
154
155         if (pl_vout_buf == NULL)
156                 fprintf(stderr, "failed to set mode\n");
157
158         // menu decides on layer size, we commit it
159         menu_notify_mode_change(w, h, bpp);
160         omap_enable_layer(1);
161
162         return pl_vout_buf;
163 }
164
165 static void *pl_vout_flip(void)
166 {
167         pl_flip_cnt++;
168
169         if (pl_vout_buf != NULL)
170                 pl_print_hud(pl_vout_w, pl_vout_h, 0);
171
172         // let's flip now
173 #if defined(VOUT_FBDEV)
174         pl_vout_buf = vout_fbdev_flip(layer_fb);
175 #elif defined(MAEMO)
176         extern void *hildon_flip(void);
177         pl_vout_buf = hildon_flip();
178 #endif
179         return pl_vout_buf;
180 }
181
182 static int pl_vout_open(void)
183 {
184         struct timeval now;
185
186         omap_enable_layer(1);
187 #if defined(VOUT_FBDEV)
188         // force mode update
189         int h = pl_vout_h;
190         pl_vout_h--;
191         pl_vout_buf = pl_vout_set_mode(pl_vout_w, h, pl_vout_bpp);
192
193         // try to align redraws to vsync
194         vout_fbdev_wait_vsync(layer_fb);
195 #elif defined(MAEMO)
196         extern void *hildon_flip(void);
197         pl_vout_buf = hildon_flip();
198 #endif
199
200         gettimeofday(&now, 0);
201         vsync_usec_time = now.tv_usec;
202         while (vsync_usec_time >= frame_interval)
203                 vsync_usec_time -= frame_interval;
204
205         return 0;
206 }
207
208 static void pl_vout_close(void)
209 {
210         omap_enable_layer(0);
211 }
212
213 void *pl_prepare_screenshot(int *w, int *h, int *bpp)
214 {
215 #if defined(VOUT_FBDEV)
216         *w = pl_vout_w;
217         *h = pl_vout_h;
218         *bpp = pl_vout_bpp;
219
220         return pl_vout_buf;
221 #else
222         return plat_prepare_screenshot(w, h, bpp);
223 #endif
224 }
225
226 #ifndef MAEMO
227 static void update_analogs(void)
228 {
229         int *nubp[2] = { in_a1, in_a2 };
230         int i, a, v, ret;
231
232         for (i = 0; i < 2; i++)
233         {
234                 if (in_adev[i] < 0)
235                         continue;
236
237                 for (a = 0; a < 2; a++) {
238                         nubp[i][a] = 127;
239
240                         ret = in_update_analog(in_adev[i], in_adev_axis[i][a], &v);
241                         if (ret == 0) {
242                                 v = v / (IN_ABS_RANGE / 128) + 127;
243                                 nubp[i][a] = v < 0 ? 0 : v;
244                         }
245                 }
246         }
247         //printf("%4d %4d %4d %4d\n", in_a1[0], in_a1[1], in_a2[0], in_a2[1]);
248 }
249
250 static void update_input(void)
251 {
252         int actions[IN_BINDTYPE_COUNT] = { 0, };
253         unsigned int emu_act;
254
255         in_update(actions);
256         if (in_type1 == PSE_PAD_TYPE_ANALOGPAD)
257                 update_analogs();
258         emu_act = actions[IN_BINDTYPE_EMU];
259         in_state_gun = (emu_act & SACTION_GUN_MASK) >> SACTION_GUN_TRIGGER;
260
261         emu_act &= ~SACTION_GUN_MASK;
262         if (emu_act) {
263                 int which = 0;
264                 for (; !(emu_act & 1); emu_act >>= 1, which++)
265                         ;
266                 emu_act = which;
267         }
268         emu_set_action(emu_act);
269
270         in_keystate = actions[IN_BINDTYPE_PLAYER12];
271 #ifdef X11
272         extern int x11_update_keys(unsigned int *action);
273         in_keystate |= x11_update_keys(&emu_act);
274         emu_set_action(emu_act);
275 #endif
276 }
277 #else /* MAEMO */
278 static void update_input(void)
279 {
280 }
281 #endif
282
283 void pl_update_gun(int *xn, int *xres, int *y, int *in)
284 {
285         if (tsdev)
286                 pl_gun_ts_update(tsdev, xn, y, in);
287
288         *xres = pl_vout_w;
289         *y = *y * pl_vout_h >> 10;
290 }
291
292 #define MAX_LAG_FRAMES 3
293
294 #define tvdiff(tv, tv_old) \
295         ((tv.tv_sec - tv_old.tv_sec) * 1000000 + tv.tv_usec - tv_old.tv_usec)
296
297 /* called on every vsync */
298 void pl_frame_limit(void)
299 {
300         static struct timeval tv_old, tv_expect;
301         static int vsync_cnt_prev, drc_active_vsyncs;
302         struct timeval now;
303         int diff, usadj;
304
305         vsync_cnt++;
306
307         /* doing input here because the pad is polled
308          * thousands of times per frame for some reason */
309         update_input();
310
311         pcnt_end(PCNT_ALL);
312         gettimeofday(&now, 0);
313
314         if (now.tv_sec != tv_old.tv_sec) {
315                 diff = tvdiff(now, tv_old);
316                 vsps_cur = 0.0f;
317                 if (0 < diff && diff < 2000000)
318                         vsps_cur = 1000000.0f * (vsync_cnt - vsync_cnt_prev) / diff;
319                 vsync_cnt_prev = vsync_cnt;
320                 flips_per_sec = pl_flip_cnt;
321                 pl_flip_cnt = 0;
322                 tv_old = now;
323                 if (g_opts & OPT_SHOWCPU)
324                         tick_per_sec = get_cpu_ticks();
325
326                 if (hud_new_msg > 0) {
327                         hud_new_msg--;
328                         if (hud_new_msg == 0)
329                                 hud_msg[0] = 0;
330                 }
331         }
332 #ifdef PCNT
333         static int ya_vsync_count;
334         if (++ya_vsync_count == PCNT_FRAMES) {
335                 pcnt_print(vsps_cur);
336                 ya_vsync_count = 0;
337         }
338 #endif
339
340         // tv_expect uses usec*1024 units instead of usecs for better accuracy
341         tv_expect.tv_usec += frame_interval1024;
342         if (tv_expect.tv_usec >= (1000000 << 10)) {
343                 tv_expect.tv_usec -= (1000000 << 10);
344                 tv_expect.tv_sec++;
345         }
346         diff = (tv_expect.tv_sec - now.tv_sec) * 1000000 + (tv_expect.tv_usec >> 10) - now.tv_usec;
347
348         if (diff > MAX_LAG_FRAMES * frame_interval || diff < -MAX_LAG_FRAMES * frame_interval) {
349                 //printf("pl_frame_limit reset, diff=%d, iv %d\n", diff, frame_interval);
350                 tv_expect = now;
351                 diff = 0;
352                 // try to align with vsync
353                 usadj = vsync_usec_time;
354                 while (usadj < tv_expect.tv_usec - frame_interval)
355                         usadj += frame_interval;
356                 tv_expect.tv_usec = usadj << 10;
357         }
358
359         if (!(g_opts & OPT_NO_FRAMELIM) && diff > frame_interval) {
360                 // yay for working usleep on pandora!
361                 //printf("usleep %d\n", diff - frame_interval / 2);
362                 usleep(diff - frame_interval);
363         }
364
365         if (pl_rearmed_cbs.frameskip) {
366                 if (diff < -frame_interval)
367                         pl_rearmed_cbs.fskip_advice = 1;
368                 else if (diff >= 0)
369                         pl_rearmed_cbs.fskip_advice = 0;
370
371                 // recompilation is not that fast and may cause frame skip on
372                 // loading screens and such, resulting in flicker or glitches
373                 if (new_dynarec_did_compile) {
374                         if (drc_active_vsyncs < 32)
375                                 pl_rearmed_cbs.fskip_advice = 0;
376                         drc_active_vsyncs++;
377                 }
378                 else
379                         drc_active_vsyncs = 0;
380                 new_dynarec_did_compile = 0;
381         }
382
383         pcnt_start(PCNT_ALL);
384 }
385
386 void pl_timing_prepare(int is_pal)
387 {
388         pl_rearmed_cbs.fskip_advice = 0;
389
390         frame_interval = is_pal ? 20000 : 16667;
391         frame_interval1024 = is_pal ? 20000*1024 : 17066667;
392
393         // used by P.E.Op.S. frameskip code
394         pl_rearmed_cbs.gpu_peops.fFrameRateHz = is_pal ? 50.0f : 59.94f;
395         pl_rearmed_cbs.gpu_peops.dwFrameRateTicks =
396                 (100000*100 / (unsigned long)(pl_rearmed_cbs.gpu_peops.fFrameRateHz*100));
397 }
398
399 static void pl_text_out16_(int x, int y, const char *text)
400 {
401         int i, l, len = strlen(text), w = pl_vout_w;
402         unsigned short *screen = (unsigned short *)pl_vout_buf + x + y * w;
403         unsigned short val = 0xffff;
404
405         for (i = 0; i < len; i++, screen += 8)
406         {
407                 for (l = 0; l < 8; l++)
408                 {
409                         unsigned char fd = fontdata8x8[text[i] * 8 + l];
410                         unsigned short *s = screen + l * w;
411                         if (fd&0x80) s[0] = val;
412                         if (fd&0x40) s[1] = val;
413                         if (fd&0x20) s[2] = val;
414                         if (fd&0x10) s[3] = val;
415                         if (fd&0x08) s[4] = val;
416                         if (fd&0x04) s[5] = val;
417                         if (fd&0x02) s[6] = val;
418                         if (fd&0x01) s[7] = val;
419                 }
420         }
421 }
422
423 void pl_text_out16(int x, int y, const char *texto, ...)
424 {
425         va_list args;
426         char    buffer[256];
427
428         va_start(args, texto);
429         vsnprintf(buffer, sizeof(buffer), texto, args);
430         va_end(args);
431
432         pl_text_out16_(x, y, buffer);
433 }
434
435 static void pl_get_layer_pos(int *x, int *y, int *w, int *h)
436 {
437         *x = g_layer_x;
438         *y = g_layer_y;
439         *w = g_layer_w;
440         *h = g_layer_h;
441 }
442
443 struct rearmed_cbs pl_rearmed_cbs = {
444         pl_get_layer_pos,
445         pl_vout_open,
446         pl_vout_set_mode,
447         pl_vout_flip,
448         pl_vout_close,
449 };
450
451 /* watchdog */
452 static void *watchdog_thread(void *unused)
453 {
454         int vsync_cnt_old = 0;
455         int seen_dead = 0;
456         int sleep_time = 5;
457
458 #if !defined(NDEBUG) || defined(DRC_DBG)
459         // don't interfere with debug
460         return NULL;
461 #endif
462         while (1)
463         {
464                 sleep(sleep_time);
465
466                 if (stop) {
467                         seen_dead = 0;
468                         sleep_time = 5;
469                         continue;
470                 }
471                 if (vsync_cnt != vsync_cnt_old) {
472                         vsync_cnt_old = vsync_cnt;
473                         seen_dead = 0;
474                         sleep_time = 2;
475                         continue;
476                 }
477
478                 seen_dead++;
479                 sleep_time = 1;
480                 if (seen_dead > 1)
481                         fprintf(stderr, "watchdog: seen_dead %d\n", seen_dead);
482                 if (seen_dead > 4) {
483                         fprintf(stderr, "watchdog: lockup detected, aborting\n");
484                         // we can't do any cleanup here really, the main thread is
485                         // likely touching resources and would crash anyway
486                         abort();
487                 }
488         }
489 }
490
491 void pl_start_watchdog(void)
492 {
493         pthread_attr_t attr;
494         pthread_t tid;
495         int ret;
496         
497         pthread_attr_init(&attr);
498         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
499
500         ret = pthread_create(&tid, &attr, watchdog_thread, NULL);
501         if (ret != 0)
502                 fprintf(stderr, "could not start watchdog: %d\n", ret);
503 }
504
505 void pl_init(void)
506 {
507         extern unsigned int hSyncCount; // from psxcounters
508         extern unsigned int frame_counter;
509
510         pl_vout_w = pl_vout_h = 256;
511         pl_vout_bpp = 16;
512
513         tsdev = pl_gun_ts_init();
514
515         pl_rearmed_cbs.gpu_hcnt = &hSyncCount;
516         pl_rearmed_cbs.gpu_frame_count = &frame_counter;
517 }