gpu_neon: flush cmd buffer before blit too
[pcsx_rearmed.git] / frontend / plugin_lib.c
CommitLineData
b60f2812 1/*
8f892648 2 * (C) notaz, 2010-2011
b60f2812 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>
69af03a2 10#include <string.h>
11#include <stdarg.h>
799b0b87 12#include <stdint.h>
72228559 13#include <sys/time.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <fcntl.h>
17#include <unistd.h>
7c0f51de 18#include <pthread.h>
b60f2812 19
72228559 20#include "plugin_lib.h"
b60f2812 21#include "linux/fbdev.h"
69af03a2 22#include "common/fonts.h"
23#include "common/input.h"
24#include "omap.h"
3c70c47b 25#include "menu.h"
8f892648 26#include "main.h"
47821672 27#include "plat.h"
72228559 28#include "pcnt.h"
4c08b9e7 29#include "pl_gun_ts.h"
69af03a2 30#include "../libpcsxcore/new_dynarec/new_dynarec.h"
799b0b87 31#include "../libpcsxcore/psemu_plugin_defs.h"
b60f2812 32
4c08b9e7 33int in_type1, in_type2;
34int in_a1[2] = { 127, 127 }, in_a2[2] = { 127, 127 };
1b0c5139 35int in_adev[2] = { -1, -1 }, in_adev_axis[2][2] = {{ 0, 1 }, { 0, 1 }};
4c08b9e7 36int in_keystate, in_state_gun;
b944a30e 37int in_enable_vibration;
55b0eeea 38int pl_flip_cnt;
faf2b2aa 39void *tsdev;
76f7048e 40void *pl_vout_buf;
41static int pl_vout_w, pl_vout_h, pl_vout_bpp;
55b0eeea 42static int vsync_cnt, flips_per_sec, tick_per_sec;
bce6b056 43static float vsps_cur;
76f7048e 44static int frame_interval, frame_interval1024, vsync_usec_time;
72228559 45
4c08b9e7 46
47static __attribute__((noinline)) int get_cpu_ticks(void)
72228559 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
41f55c9f 67static void print_msg(int h, int border)
8f892648 68{
76f7048e 69 if (pl_vout_bpp == 16)
41f55c9f 70 pl_text_out16(border + 2, h - 10, "%s", hud_msg);
8f892648 71}
72
41f55c9f 73static void print_fps(int h, int border)
72228559 74{
76f7048e 75 if (pl_vout_bpp == 16)
41f55c9f 76 pl_text_out16(border + 2, h - 10, "%2d %4.1f", flips_per_sec, vsps_cur);
72228559 77}
78
41f55c9f 79static void print_cpu_usage(int w, int h, int border)
72228559 80{
76f7048e 81 if (pl_vout_bpp == 16)
41f55c9f 82 pl_text_out16(w - border - 28, h - 10, "%3d", tick_per_sec);
72228559 83}
b60f2812 84
90f1d26c 85// draw 192x8 status of 24 sound channels
55b0eeea 86static __attribute__((noinline)) void draw_active_chans(int vout_w, int vout_h)
90f1d26c 87{
174c454a 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;
90f1d26c 91
92 static const unsigned short colors[2] = { 0x1fe3, 0x0700 };
76f7048e 93 unsigned short *dest = (unsigned short *)pl_vout_buf +
55b0eeea 94 vout_w * (vout_h - 10) + vout_w / 2 - 192/2;
90f1d26c 95 unsigned short *d, p;
96 int c, x, y;
97
76f7048e 98 if (pl_vout_bpp != 16)
90f1d26c 99 return;
100
174c454a 101 spu_get_debug_info(&live_chans, &run_chans, &fmod_chans, &noise_chans);
90f1d26c 102
103 for (c = 0; c < 24; c++) {
104 d = dest + c * 8;
174c454a 105 p = !(live_chans & (1<<c)) ? (run_chans & (1<<c) ? 0x01c0 : 0) :
90f1d26c 106 (fmod_chans & (1<<c)) ? 0xf000 :
107 (noise_chans & (1<<c)) ? 0x001f :
108 colors[c & 1];
55b0eeea 109 for (y = 0; y < 8; y++, d += vout_w)
90f1d26c 110 for (x = 0; x < 8; x++)
111 d[x] = p;
112 }
113}
114
41f55c9f 115void pl_print_hud(int w, int h, int xborder)
55b0eeea 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)
41f55c9f 124 print_msg(h, xborder);
55b0eeea 125 else if (g_opts & OPT_SHOWFPS)
41f55c9f 126 print_fps(h, xborder);
55b0eeea 127
128 if (g_opts & OPT_SHOWCPU)
41f55c9f 129 print_cpu_usage(w, h, xborder);
55b0eeea 130}
131
76f7048e 132static void *pl_vout_set_mode(int w, int h, int bpp)
69af03a2 133{
a185be70 134 // special h handling, Wipeout likes to change it by 1-6
321ca84d 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;
a185be70 139
76f7048e 140 if (w == pl_vout_w && h == pl_vout_h && bpp == pl_vout_bpp)
141 return pl_vout_buf;
b60f2812 142
76f7048e 143 pl_vout_w = w;
144 pl_vout_h = h;
145 pl_vout_bpp = bpp;
d352cde2 146
76f7048e 147#if defined(VOUT_FBDEV)
d352cde2 148 vout_fbdev_clear(layer_fb);
76f7048e 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
d352cde2 154
76f7048e 155 if (pl_vout_buf == NULL)
156 fprintf(stderr, "failed to set mode\n");
a185be70 157
158 // menu decides on layer size, we commit it
bd6267e6 159 menu_notify_mode_change(w, h, bpp);
a185be70 160 omap_enable_layer(1);
3c70c47b 161
76f7048e 162 return pl_vout_buf;
69af03a2 163}
164
76f7048e 165static void *pl_vout_flip(void)
69af03a2 166{
55b0eeea 167 pl_flip_cnt++;
8f892648 168
55b0eeea 169 if (pl_vout_buf != NULL)
41f55c9f 170 pl_print_hud(pl_vout_w, pl_vout_h, 0);
72228559 171
69af03a2 172 // let's flip now
76f7048e 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;
b60f2812 180}
181
76f7048e 182static int pl_vout_open(void)
6d1a1ac2 183{
cefe86b7 184 struct timeval now;
185
6d1a1ac2 186 omap_enable_layer(1);
76f7048e 187#if defined(VOUT_FBDEV)
321ca84d 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);
cefe86b7 192
193 // try to align redraws to vsync
194 vout_fbdev_wait_vsync(layer_fb);
76f7048e 195#elif defined(MAEMO)
196 extern void *hildon_flip(void);
197 pl_vout_buf = hildon_flip();
198#endif
199
cefe86b7 200 gettimeofday(&now, 0);
201 vsync_usec_time = now.tv_usec;
76f7048e 202 while (vsync_usec_time >= frame_interval)
203 vsync_usec_time -= frame_interval;
cefe86b7 204
6d1a1ac2 205 return 0;
206}
207
76f7048e 208static void pl_vout_close(void)
b60f2812 209{
6d1a1ac2 210 omap_enable_layer(0);
b60f2812 211}
212
29a8c4f3 213void *pl_prepare_screenshot(int *w, int *h, int *bpp)
214{
47821672 215#if defined(VOUT_FBDEV)
76f7048e 216 *w = pl_vout_w;
217 *h = pl_vout_h;
218 *bpp = pl_vout_bpp;
29a8c4f3 219
76f7048e 220 return pl_vout_buf;
47821672 221#else
222 return plat_prepare_screenshot(w, h, bpp);
223#endif
29a8c4f3 224}
225
1b0c5139 226#ifndef MAEMO
227static 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
15d46930 250static void update_input(void)
251{
252 int actions[IN_BINDTYPE_COUNT] = { 0, };
8f892648 253 unsigned int emu_act;
15d46930 254
255 in_update(actions);
4c08b9e7 256 if (in_type1 == PSE_PAD_TYPE_ANALOGPAD)
1b0c5139 257 update_analogs();
8f892648 258 emu_act = actions[IN_BINDTYPE_EMU];
4c08b9e7 259 in_state_gun = (emu_act & SACTION_GUN_MASK) >> SACTION_GUN_TRIGGER;
260
261 emu_act &= ~SACTION_GUN_MASK;
8f892648 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
799b0b87 270 in_keystate = actions[IN_BINDTYPE_PLAYER12];
447783f8 271#ifdef X11
4218954f 272 extern int x11_update_keys(unsigned int *action);
273 in_keystate |= x11_update_keys(&emu_act);
274 emu_set_action(emu_act);
447783f8 275#endif
15d46930 276}
1b0c5139 277#else /* MAEMO */
278static void update_input(void)
279{
280}
281#endif
15d46930 282
4c08b9e7 283void pl_update_gun(int *xn, int *xres, int *y, int *in)
284{
faf2b2aa 285 if (tsdev)
286 pl_gun_ts_update(tsdev, xn, y, in);
4c08b9e7 287
76f7048e 288 *xres = pl_vout_w;
289 *y = *y * pl_vout_h >> 10;
4c08b9e7 290}
291
bce6b056 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)
bce6b056 296
72228559 297/* called on every vsync */
298void pl_frame_limit(void)
299{
bce6b056 300 static struct timeval tv_old, tv_expect;
2f546f9a 301 static int vsync_cnt_prev, drc_active_vsyncs;
bce6b056 302 struct timeval now;
cefe86b7 303 int diff, usadj;
bce6b056 304
305 vsync_cnt++;
72228559 306
15d46930 307 /* doing input here because the pad is polled
308 * thousands of times per frame for some reason */
309 update_input();
310
72228559 311 pcnt_end(PCNT_ALL);
bce6b056 312 gettimeofday(&now, 0);
72228559 313
bce6b056 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)
7c0f51de 318 vsps_cur = 1000000.0f * (vsync_cnt - vsync_cnt_prev) / diff;
319 vsync_cnt_prev = vsync_cnt;
55b0eeea 320 flips_per_sec = pl_flip_cnt;
321 pl_flip_cnt = 0;
bce6b056 322 tv_old = now;
bd6267e6 323 if (g_opts & OPT_SHOWCPU)
324 tick_per_sec = get_cpu_ticks();
8f892648 325
326 if (hud_new_msg > 0) {
327 hud_new_msg--;
328 if (hud_new_msg == 0)
329 hud_msg[0] = 0;
330 }
72228559 331 }
332#ifdef PCNT
333 static int ya_vsync_count;
334 if (++ya_vsync_count == PCNT_FRAMES) {
bce6b056 335 pcnt_print(vsps_cur);
72228559 336 ya_vsync_count = 0;
337 }
338#endif
339
76f7048e 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);
c89cd762 350 tv_expect = now;
351 diff = 0;
cefe86b7 352 // try to align with vsync
353 usadj = vsync_usec_time;
76f7048e 354 while (usadj < tv_expect.tv_usec - frame_interval)
355 usadj += frame_interval;
356 tv_expect.tv_usec = usadj << 10;
c89cd762 357 }
358
76f7048e 359 if (!(g_opts & OPT_NO_FRAMELIM) && diff > frame_interval) {
c89cd762 360 // yay for working usleep on pandora!
76f7048e 361 //printf("usleep %d\n", diff - frame_interval / 2);
47f37583 362 usleep(diff - frame_interval);
c89cd762 363 }
364
e64dc4c5 365 if (pl_rearmed_cbs.frameskip) {
76f7048e 366 if (diff < -frame_interval)
e64dc4c5 367 pl_rearmed_cbs.fskip_advice = 1;
368 else if (diff >= 0)
369 pl_rearmed_cbs.fskip_advice = 0;
2f546f9a 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;
bce6b056 381 }
72228559 382
383 pcnt_start(PCNT_ALL);
384}
385
76f7048e 386void 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
69af03a2 399static void pl_text_out16_(int x, int y, const char *text)
b60f2812 400{
76f7048e 401 int i, l, len = strlen(text), w = pl_vout_w;
402 unsigned short *screen = (unsigned short *)pl_vout_buf + x + y * w;
69af03a2 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 }
b60f2812 421}
422
69af03a2 423void pl_text_out16(int x, int y, const char *texto, ...)
b60f2812 424{
69af03a2 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);
b60f2812 433}
434
201c21e2 435static 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
e64dc4c5 443struct rearmed_cbs pl_rearmed_cbs = {
201c21e2 444 pl_get_layer_pos,
76f7048e 445 pl_vout_open,
446 pl_vout_set_mode,
447 pl_vout_flip,
448 pl_vout_close,
201c21e2 449};
450
7c0f51de 451/* watchdog */
452static void *watchdog_thread(void *unused)
453{
454 int vsync_cnt_old = 0;
455 int seen_dead = 0;
456 int sleep_time = 5;
457
d3f3bf09 458#if !defined(NDEBUG) || defined(DRC_DBG)
799b0b87 459 // don't interfere with debug
460 return NULL;
461#endif
7c0f51de 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
491void 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
4c08b9e7 505void pl_init(void)
506{
24de2dd4 507 extern unsigned int hSyncCount; // from psxcounters
3ece2f0c 508 extern unsigned int frame_counter;
24de2dd4 509
321ca84d 510 pl_vout_w = pl_vout_h = 256;
511 pl_vout_bpp = 16;
512
faf2b2aa 513 tsdev = pl_gun_ts_init();
24de2dd4 514
515 pl_rearmed_cbs.gpu_hcnt = &hSyncCount;
3ece2f0c 516 pl_rearmed_cbs.gpu_frame_count = &frame_counter;
4c08b9e7 517}