frontend: add fast forward support
[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
cc56203b 20#include "libpicofe/fonts.h"
21#include "libpicofe/input.h"
22#include "libpicofe/plat.h"
23#include "libpicofe/arm/neon_scale2x.h"
24#include "libpicofe/arm/neon_eagle2x.h"
72228559 25#include "plugin_lib.h"
3c70c47b 26#include "menu.h"
8f892648 27#include "main.h"
47821672 28#include "plat.h"
72228559 29#include "pcnt.h"
4c08b9e7 30#include "pl_gun_ts.h"
69af03a2 31#include "../libpcsxcore/new_dynarec/new_dynarec.h"
799b0b87 32#include "../libpcsxcore/psemu_plugin_defs.h"
fa56d360 33#include "../plugins/gpulib/cspace.h"
b60f2812 34
4c08b9e7 35int in_type1, in_type2;
36int in_a1[2] = { 127, 127 }, in_a2[2] = { 127, 127 };
1b0c5139 37int in_adev[2] = { -1, -1 }, in_adev_axis[2][2] = {{ 0, 1 }, { 0, 1 }};
4c08b9e7 38int in_keystate, in_state_gun;
b944a30e 39int in_enable_vibration;
faf2b2aa 40void *tsdev;
76f7048e 41void *pl_vout_buf;
6469a8c4 42int g_layer_x, g_layer_y, g_layer_w, g_layer_h;
ddc0a02a 43static int pl_vout_w, pl_vout_h, pl_vout_bpp; /* output display/layer */
fa56d360 44static int pl_vout_scale;
ddc0a02a 45static int psx_w, psx_h, psx_bpp;
a92f6af1 46static int vsync_cnt;
ab423939 47static int is_pal, frame_interval, frame_interval1024;
48static int vsync_usec_time;
72228559 49
4c08b9e7 50
51static __attribute__((noinline)) int get_cpu_ticks(void)
72228559 52{
53 static unsigned long last_utime;
54 static int fd;
55 unsigned long utime, ret;
56 char buf[128];
57
58 if (fd == 0)
59 fd = open("/proc/self/stat", O_RDONLY);
60 lseek(fd, 0, SEEK_SET);
61 buf[0] = 0;
62 read(fd, buf, sizeof(buf));
63 buf[sizeof(buf) - 1] = 0;
64
65 sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu", &utime);
66 ret = utime - last_utime;
67 last_utime = utime;
68 return ret;
69}
70
41f55c9f 71static void print_msg(int h, int border)
8f892648 72{
76f7048e 73 if (pl_vout_bpp == 16)
41f55c9f 74 pl_text_out16(border + 2, h - 10, "%s", hud_msg);
8f892648 75}
76
41f55c9f 77static void print_fps(int h, int border)
72228559 78{
76f7048e 79 if (pl_vout_bpp == 16)
a92f6af1 80 pl_text_out16(border + 2, h - 10, "%2d %4.1f",
81 pl_rearmed_cbs.flips_per_sec, pl_rearmed_cbs.vsps_cur);
72228559 82}
83
41f55c9f 84static void print_cpu_usage(int w, int h, int border)
72228559 85{
76f7048e 86 if (pl_vout_bpp == 16)
a92f6af1 87 pl_text_out16(w - border - 28, h - 10, "%3d", pl_rearmed_cbs.cpu_usage);
72228559 88}
b60f2812 89
90f1d26c 90// draw 192x8 status of 24 sound channels
55b0eeea 91static __attribute__((noinline)) void draw_active_chans(int vout_w, int vout_h)
90f1d26c 92{
174c454a 93 extern void spu_get_debug_info(int *chans_out, int *run_chans,
94 int *fmod_chans_out, int *noise_chans_out); // hack
95 int live_chans, run_chans, fmod_chans, noise_chans;
90f1d26c 96
97 static const unsigned short colors[2] = { 0x1fe3, 0x0700 };
76f7048e 98 unsigned short *dest = (unsigned short *)pl_vout_buf +
55b0eeea 99 vout_w * (vout_h - 10) + vout_w / 2 - 192/2;
90f1d26c 100 unsigned short *d, p;
101 int c, x, y;
102
76f7048e 103 if (pl_vout_bpp != 16)
90f1d26c 104 return;
105
174c454a 106 spu_get_debug_info(&live_chans, &run_chans, &fmod_chans, &noise_chans);
90f1d26c 107
108 for (c = 0; c < 24; c++) {
109 d = dest + c * 8;
174c454a 110 p = !(live_chans & (1<<c)) ? (run_chans & (1<<c) ? 0x01c0 : 0) :
90f1d26c 111 (fmod_chans & (1<<c)) ? 0xf000 :
112 (noise_chans & (1<<c)) ? 0x001f :
113 colors[c & 1];
55b0eeea 114 for (y = 0; y < 8; y++, d += vout_w)
90f1d26c 115 for (x = 0; x < 8; x++)
116 d[x] = p;
117 }
118}
119
fa56d360 120void pl_print_hud(int w, int h, int xborder)
55b0eeea 121{
aafcb4dd 122 if (h < 16)
123 return;
124
55b0eeea 125 if (g_opts & OPT_SHOWSPU)
126 draw_active_chans(w, h);
127
128 if (hud_msg[0] != 0)
41f55c9f 129 print_msg(h, xborder);
55b0eeea 130 else if (g_opts & OPT_SHOWFPS)
41f55c9f 131 print_fps(h, xborder);
55b0eeea 132
133 if (g_opts & OPT_SHOWCPU)
41f55c9f 134 print_cpu_usage(w, h, xborder);
55b0eeea 135}
136
9e5ac38f 137/* update scaler target size according to user settings */
138static void update_layer_size(int w, int h)
139{
140 float mult;
141 int imult;
142
143 switch (g_scaler) {
144 case SCALE_1_1:
145 g_layer_w = w; g_layer_h = h;
146 break;
147
148 case SCALE_4_3v2:
149 if (h > g_menuscreen_h || (240 < h && h <= 360))
150 goto fractional_4_3;
151
152 // 4:3 that prefers integer scaling
153 imult = g_menuscreen_h / h;
154 g_layer_w = w * imult;
155 g_layer_h = h * imult;
156 mult = (float)g_layer_w / (float)g_layer_h;
157 if (mult < 1.25f || mult > 1.666f)
158 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
159 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
160 break;
161
162 fractional_4_3:
163 case SCALE_4_3:
164 mult = 240.0f / (float)h * 4.0f / 3.0f;
165 if (h > 256)
166 mult *= 2.0f;
167 g_layer_w = mult * (float)g_menuscreen_h;
168 g_layer_h = g_menuscreen_h;
169 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
170 break;
171
172 case SCALE_FULLSCREEN:
173 g_layer_w = g_menuscreen_w;
174 g_layer_h = g_menuscreen_h;
175 break;
176
177 default:
178 break;
179 }
180
181 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
182 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
183 if (g_layer_x < 0) g_layer_x = 0;
184 if (g_layer_y < 0) g_layer_y = 0;
185 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
186 if (g_layer_h > g_menuscreen_h) g_layer_h = g_menuscreen_h;
187}
188
fa56d360 189// XXX: this is platform specific really
190static int resolution_ok(int w, int h)
69af03a2 191{
fa56d360 192 return w <= 1024 && h <= 512;
193}
194
195static void pl_vout_set_mode(int w, int h, int bpp)
196{
197 int vout_w, vout_h, vout_bpp;
198
a185be70 199 // special h handling, Wipeout likes to change it by 1-6
321ca84d 200 static int vsync_cnt_ms_prev;
201 if ((unsigned int)(vsync_cnt - vsync_cnt_ms_prev) < 5*60)
202 h = (h + 7) & ~7;
203 vsync_cnt_ms_prev = vsync_cnt;
a185be70 204
fa56d360 205 vout_w = psx_w = w;
206 vout_h = psx_h = h;
207 vout_bpp = psx_bpp = bpp;
208
209 pl_vout_scale = 1;
210#ifdef __ARM_NEON__
211 if (soft_filter) {
212 if (resolution_ok(w * 2, h * 2) && bpp == 16) {
213 vout_w *= 2;
214 vout_h *= 2;
215 pl_vout_scale = 2;
216 }
217 else {
218 // filter unavailable
219 hud_msg[0] = 0;
220 }
221 }
222#endif
b60f2812 223
fa56d360 224 if (pl_vout_buf != NULL && vout_w == pl_vout_w && vout_h == pl_vout_h
225 && vout_bpp == pl_vout_bpp)
226 return;
d352cde2 227
fa56d360 228 update_layer_size(vout_w, vout_h);
9e5ac38f 229
fa56d360 230 pl_vout_buf = plat_gvideo_set_mode(&vout_w, &vout_h, &vout_bpp);
231 if (pl_vout_buf == NULL)
ddc0a02a 232 fprintf(stderr, "failed to set mode %dx%d@%d\n",
233 psx_w, psx_h, psx_bpp);
fa56d360 234 else {
235 pl_vout_w = vout_w;
236 pl_vout_h = vout_h;
237 pl_vout_bpp = vout_bpp;
238 }
a185be70 239
ddc0a02a 240 menu_notify_mode_change(pl_vout_w, pl_vout_h, pl_vout_bpp);
69af03a2 241}
242
fa56d360 243static void pl_vout_flip(const void *vram, int stride, int bgr24, int w, int h)
69af03a2 244{
fa56d360 245 static int doffs_old, clear_counter;
246 unsigned char *dest = pl_vout_buf;
247 const unsigned short *src = vram;
248 int dstride = pl_vout_w, h1 = h;
249 int doffs;
250
cc56203b 251 pcnt_start(PCNT_BLIT);
252
fa56d360 253 if (dest == NULL)
254 goto out;
255
256 if (vram == NULL) {
257 // blanking
258 memset(pl_vout_buf, 0, dstride * pl_vout_h * pl_vout_bpp / 8);
259 goto out;
260 }
261
262 // borders
263 doffs = (dstride - w * pl_vout_scale) / 2 & ~1;
264 dest += doffs * 2;
265
266 if (doffs > doffs_old)
267 clear_counter = 2;
268 doffs_old = doffs;
269
270 if (clear_counter > 0) {
271 memset(pl_vout_buf, 0, dstride * pl_vout_h * pl_vout_bpp / 8);
272 clear_counter--;
273 }
274
275 if (bgr24)
276 {
277 if (pl_rearmed_cbs.only_16bpp) {
278 for (; h1-- > 0; dest += dstride * 2, src += stride)
279 {
280 bgr888_to_rgb565(dest, src, w * 3);
281 }
282 }
283 else {
284 dest -= doffs * 2;
285 dest += (doffs / 8) * 24;
286
287 for (; h1-- > 0; dest += dstride * 3, src += stride)
288 {
289 bgr888_to_rgb888(dest, src, w * 3);
290 }
291 }
292 }
293#ifdef __ARM_NEON__
294 else if (soft_filter == SOFT_FILTER_SCALE2X && pl_vout_scale == 2)
295 {
296 neon_scale2x_16_16(src, (void *)dest, w,
297 stride * 2, dstride * 2, h1);
298 }
299 else if (soft_filter == SOFT_FILTER_EAGLE2X && pl_vout_scale == 2)
300 {
301 neon_eagle2x_16_16(src, (void *)dest, w,
302 stride * 2, dstride * 2, h1);
303 }
304#endif
305 else
306 {
307 for (; h1-- > 0; dest += dstride * 2, src += stride)
308 {
309 bgr555_to_rgb565(dest, src, w * 2);
310 }
311 }
8f892648 312
fa56d360 313 pl_print_hud(w * pl_vout_scale, h * pl_vout_scale, 0);
72228559 314
fa56d360 315out:
cc56203b 316 pcnt_end(PCNT_BLIT);
317
69af03a2 318 // let's flip now
6469a8c4 319 pl_vout_buf = plat_gvideo_flip();
fa56d360 320 pl_rearmed_cbs.flip_cnt++;
b60f2812 321}
322
76f7048e 323static int pl_vout_open(void)
6d1a1ac2 324{
cefe86b7 325 struct timeval now;
326
fa56d360 327 // force mode update on pl_vout_set_mode() call from gpulib/vout_pl
328 pl_vout_buf = NULL;
cefe86b7 329
ab423939 330 plat_gvideo_open(is_pal);
76f7048e 331
cefe86b7 332 gettimeofday(&now, 0);
333 vsync_usec_time = now.tv_usec;
76f7048e 334 while (vsync_usec_time >= frame_interval)
335 vsync_usec_time -= frame_interval;
cefe86b7 336
6d1a1ac2 337 return 0;
338}
339
76f7048e 340static void pl_vout_close(void)
b60f2812 341{
6469a8c4 342 plat_gvideo_close();
b60f2812 343}
344
fa56d360 345static void pl_set_gpu_caps(int caps)
346{
347 pl_rearmed_cbs.gpu_caps = caps;
348}
349
29a8c4f3 350void *pl_prepare_screenshot(int *w, int *h, int *bpp)
351{
6469a8c4 352 void *ret = plat_prepare_screenshot(w, h, bpp);
353 if (ret != NULL)
354 return ret;
355
76f7048e 356 *w = pl_vout_w;
357 *h = pl_vout_h;
358 *bpp = pl_vout_bpp;
29a8c4f3 359
76f7048e 360 return pl_vout_buf;
29a8c4f3 361}
362
fa56d360 363/* display/redering mode switcher */
364static int dispmode_default(void)
365{
366 pl_rearmed_cbs.gpu_neon.enhancement_enable = 0;
367 soft_filter = SOFT_FILTER_NONE;
368 snprintf(hud_msg, sizeof(hud_msg), "default mode");
369 return 1;
370}
371
372int dispmode_doubleres(void)
373{
374 if (!(pl_rearmed_cbs.gpu_caps & GPU_CAP_SUPPORTS_2X)
375 || !resolution_ok(psx_w * 2, psx_h * 2) || psx_bpp != 16)
376 return 0;
377
378 dispmode_default();
379 pl_rearmed_cbs.gpu_neon.enhancement_enable = 1;
380 snprintf(hud_msg, sizeof(hud_msg), "double resolution");
381 return 1;
382}
383
384int dispmode_scale2x(void)
385{
386 if (psx_bpp != 16)
387 return 0;
388
389 dispmode_default();
390 soft_filter = SOFT_FILTER_SCALE2X;
391 snprintf(hud_msg, sizeof(hud_msg), "scale2x");
392 return 1;
393}
394
395int dispmode_eagle2x(void)
396{
397 if (psx_bpp != 16)
398 return 0;
399
400 dispmode_default();
401 soft_filter = SOFT_FILTER_EAGLE2X;
402 snprintf(hud_msg, sizeof(hud_msg), "eagle2x");
403 return 1;
404}
405
406static int (*dispmode_switchers[])(void) = {
407 dispmode_default,
408#ifdef __ARM_NEON__
409 dispmode_doubleres,
410 dispmode_scale2x,
411 dispmode_eagle2x,
412#endif
413};
414
415static int dispmode_current;
416
417void pl_switch_dispmode(void)
418{
419 if (pl_rearmed_cbs.gpu_caps & GPU_CAP_OWNS_DISPLAY)
420 return;
421
422 while (1) {
423 dispmode_current++;
424 if (dispmode_current >=
425 sizeof(dispmode_switchers) / sizeof(dispmode_switchers[0]))
426 dispmode_current = 0;
427 if (dispmode_switchers[dispmode_current]())
428 break;
429 }
430}
431
1b0c5139 432#ifndef MAEMO
433static void update_analogs(void)
434{
435 int *nubp[2] = { in_a1, in_a2 };
436 int i, a, v, ret;
437
438 for (i = 0; i < 2; i++)
439 {
440 if (in_adev[i] < 0)
441 continue;
442
443 for (a = 0; a < 2; a++) {
444 nubp[i][a] = 127;
445
446 ret = in_update_analog(in_adev[i], in_adev_axis[i][a], &v);
447 if (ret == 0) {
448 v = v / (IN_ABS_RANGE / 128) + 127;
449 nubp[i][a] = v < 0 ? 0 : v;
450 }
451 }
452 }
453 //printf("%4d %4d %4d %4d\n", in_a1[0], in_a1[1], in_a2[0], in_a2[1]);
454}
455
15d46930 456static void update_input(void)
457{
458 int actions[IN_BINDTYPE_COUNT] = { 0, };
8f892648 459 unsigned int emu_act;
15d46930 460
461 in_update(actions);
4c08b9e7 462 if (in_type1 == PSE_PAD_TYPE_ANALOGPAD)
1b0c5139 463 update_analogs();
8f892648 464 emu_act = actions[IN_BINDTYPE_EMU];
4c08b9e7 465 in_state_gun = (emu_act & SACTION_GUN_MASK) >> SACTION_GUN_TRIGGER;
466
467 emu_act &= ~SACTION_GUN_MASK;
8f892648 468 if (emu_act) {
469 int which = 0;
470 for (; !(emu_act & 1); emu_act >>= 1, which++)
471 ;
472 emu_act = which;
473 }
474 emu_set_action(emu_act);
475
799b0b87 476 in_keystate = actions[IN_BINDTYPE_PLAYER12];
15d46930 477}
1b0c5139 478#else /* MAEMO */
479static void update_input(void)
480{
481}
482#endif
15d46930 483
4c08b9e7 484void pl_update_gun(int *xn, int *xres, int *y, int *in)
485{
faf2b2aa 486 if (tsdev)
487 pl_gun_ts_update(tsdev, xn, y, in);
4c08b9e7 488
76f7048e 489 *xres = pl_vout_w;
490 *y = *y * pl_vout_h >> 10;
4c08b9e7 491}
492
bce6b056 493#define MAX_LAG_FRAMES 3
494
495#define tvdiff(tv, tv_old) \
496 ((tv.tv_sec - tv_old.tv_sec) * 1000000 + tv.tv_usec - tv_old.tv_usec)
bce6b056 497
72228559 498/* called on every vsync */
499void pl_frame_limit(void)
500{
bce6b056 501 static struct timeval tv_old, tv_expect;
2f546f9a 502 static int vsync_cnt_prev, drc_active_vsyncs;
bce6b056 503 struct timeval now;
cefe86b7 504 int diff, usadj;
bce6b056 505
506 vsync_cnt++;
72228559 507
15d46930 508 /* doing input here because the pad is polled
509 * thousands of times per frame for some reason */
510 update_input();
511
72228559 512 pcnt_end(PCNT_ALL);
bce6b056 513 gettimeofday(&now, 0);
72228559 514
bce6b056 515 if (now.tv_sec != tv_old.tv_sec) {
516 diff = tvdiff(now, tv_old);
a92f6af1 517 pl_rearmed_cbs.vsps_cur = 0.0f;
bce6b056 518 if (0 < diff && diff < 2000000)
a92f6af1 519 pl_rearmed_cbs.vsps_cur = 1000000.0f * (vsync_cnt - vsync_cnt_prev) / diff;
7c0f51de 520 vsync_cnt_prev = vsync_cnt;
a92f6af1 521
522 if (g_opts & OPT_SHOWFPS)
523 pl_rearmed_cbs.flips_per_sec = pl_rearmed_cbs.flip_cnt;
524 pl_rearmed_cbs.flip_cnt = 0;
bd6267e6 525 if (g_opts & OPT_SHOWCPU)
a92f6af1 526 pl_rearmed_cbs.cpu_usage = get_cpu_ticks();
8f892648 527
528 if (hud_new_msg > 0) {
529 hud_new_msg--;
530 if (hud_new_msg == 0)
531 hud_msg[0] = 0;
532 }
a92f6af1 533 tv_old = now;
72228559 534 }
535#ifdef PCNT
536 static int ya_vsync_count;
537 if (++ya_vsync_count == PCNT_FRAMES) {
a92f6af1 538 pcnt_print(pl_rearmed_cbs.vsps_cur);
72228559 539 ya_vsync_count = 0;
540 }
541#endif
542
76f7048e 543 // tv_expect uses usec*1024 units instead of usecs for better accuracy
544 tv_expect.tv_usec += frame_interval1024;
545 if (tv_expect.tv_usec >= (1000000 << 10)) {
546 tv_expect.tv_usec -= (1000000 << 10);
547 tv_expect.tv_sec++;
548 }
549 diff = (tv_expect.tv_sec - now.tv_sec) * 1000000 + (tv_expect.tv_usec >> 10) - now.tv_usec;
550
551 if (diff > MAX_LAG_FRAMES * frame_interval || diff < -MAX_LAG_FRAMES * frame_interval) {
552 //printf("pl_frame_limit reset, diff=%d, iv %d\n", diff, frame_interval);
c89cd762 553 tv_expect = now;
554 diff = 0;
cefe86b7 555 // try to align with vsync
556 usadj = vsync_usec_time;
76f7048e 557 while (usadj < tv_expect.tv_usec - frame_interval)
558 usadj += frame_interval;
559 tv_expect.tv_usec = usadj << 10;
c89cd762 560 }
561
76f7048e 562 if (!(g_opts & OPT_NO_FRAMELIM) && diff > frame_interval) {
c89cd762 563 // yay for working usleep on pandora!
76f7048e 564 //printf("usleep %d\n", diff - frame_interval / 2);
47f37583 565 usleep(diff - frame_interval);
c89cd762 566 }
567
e64dc4c5 568 if (pl_rearmed_cbs.frameskip) {
76f7048e 569 if (diff < -frame_interval)
e64dc4c5 570 pl_rearmed_cbs.fskip_advice = 1;
571 else if (diff >= 0)
572 pl_rearmed_cbs.fskip_advice = 0;
2f546f9a 573
574 // recompilation is not that fast and may cause frame skip on
575 // loading screens and such, resulting in flicker or glitches
576 if (new_dynarec_did_compile) {
577 if (drc_active_vsyncs < 32)
578 pl_rearmed_cbs.fskip_advice = 0;
579 drc_active_vsyncs++;
580 }
581 else
582 drc_active_vsyncs = 0;
583 new_dynarec_did_compile = 0;
bce6b056 584 }
72228559 585
586 pcnt_start(PCNT_ALL);
587}
588
ab423939 589void pl_timing_prepare(int is_pal_)
76f7048e 590{
591 pl_rearmed_cbs.fskip_advice = 0;
a92f6af1 592 pl_rearmed_cbs.flips_per_sec = 0;
593 pl_rearmed_cbs.cpu_usage = 0;
76f7048e 594
ab423939 595 is_pal = is_pal_;
76f7048e 596 frame_interval = is_pal ? 20000 : 16667;
597 frame_interval1024 = is_pal ? 20000*1024 : 17066667;
598
599 // used by P.E.Op.S. frameskip code
600 pl_rearmed_cbs.gpu_peops.fFrameRateHz = is_pal ? 50.0f : 59.94f;
601 pl_rearmed_cbs.gpu_peops.dwFrameRateTicks =
602 (100000*100 / (unsigned long)(pl_rearmed_cbs.gpu_peops.fFrameRateHz*100));
603}
604
69af03a2 605static void pl_text_out16_(int x, int y, const char *text)
b60f2812 606{
bcb62992 607 int i, l, w = pl_vout_w;
608 unsigned short *screen;
69af03a2 609 unsigned short val = 0xffff;
610
bcb62992 611 x &= ~1;
612 screen = (unsigned short *)pl_vout_buf + x + y * w;
613 for (i = 0; ; i++, screen += 8)
69af03a2 614 {
bcb62992 615 char c = text[i];
616 if (c == 0)
617 break;
618 if (c == ' ')
619 continue;
620
69af03a2 621 for (l = 0; l < 8; l++)
622 {
bcb62992 623 unsigned char fd = fontdata8x8[c * 8 + l];
69af03a2 624 unsigned short *s = screen + l * w;
bcb62992 625 unsigned int *s32 = (void *)s;
626
627 s32[0] = (s32[0] >> 1) & 0x7bef7bef;
628 s32[1] = (s32[1] >> 1) & 0x7bef7bef;
629 s32[2] = (s32[2] >> 1) & 0x7bef7bef;
630 s32[3] = (s32[3] >> 1) & 0x7bef7bef;
631
69af03a2 632 if (fd&0x80) s[0] = val;
633 if (fd&0x40) s[1] = val;
634 if (fd&0x20) s[2] = val;
635 if (fd&0x10) s[3] = val;
636 if (fd&0x08) s[4] = val;
637 if (fd&0x04) s[5] = val;
638 if (fd&0x02) s[6] = val;
639 if (fd&0x01) s[7] = val;
640 }
641 }
b60f2812 642}
643
69af03a2 644void pl_text_out16(int x, int y, const char *texto, ...)
b60f2812 645{
69af03a2 646 va_list args;
647 char buffer[256];
648
649 va_start(args, texto);
650 vsnprintf(buffer, sizeof(buffer), texto, args);
651 va_end(args);
652
653 pl_text_out16_(x, y, buffer);
b60f2812 654}
655
201c21e2 656static void pl_get_layer_pos(int *x, int *y, int *w, int *h)
657{
658 *x = g_layer_x;
659 *y = g_layer_y;
660 *w = g_layer_w;
661 *h = g_layer_h;
662}
663
9ee0fd5b 664static void *pl_mmap(unsigned int size)
665{
a2ad8cc5 666 return plat_mmap(0, size, 0, 0);
9ee0fd5b 667}
668
669static void pl_munmap(void *ptr, unsigned int size)
670{
671 plat_munmap(ptr, size);
672}
673
e64dc4c5 674struct rearmed_cbs pl_rearmed_cbs = {
201c21e2 675 pl_get_layer_pos,
76f7048e 676 pl_vout_open,
677 pl_vout_set_mode,
678 pl_vout_flip,
679 pl_vout_close,
fa56d360 680
681 .mmap = pl_mmap,
682 .munmap = pl_munmap,
683 .pl_set_gpu_caps = pl_set_gpu_caps,
201c21e2 684};
685
7c0f51de 686/* watchdog */
687static void *watchdog_thread(void *unused)
688{
689 int vsync_cnt_old = 0;
690 int seen_dead = 0;
691 int sleep_time = 5;
692
d3f3bf09 693#if !defined(NDEBUG) || defined(DRC_DBG)
799b0b87 694 // don't interfere with debug
695 return NULL;
696#endif
7c0f51de 697 while (1)
698 {
699 sleep(sleep_time);
700
701 if (stop) {
702 seen_dead = 0;
703 sleep_time = 5;
704 continue;
705 }
706 if (vsync_cnt != vsync_cnt_old) {
707 vsync_cnt_old = vsync_cnt;
708 seen_dead = 0;
709 sleep_time = 2;
710 continue;
711 }
712
713 seen_dead++;
714 sleep_time = 1;
715 if (seen_dead > 1)
716 fprintf(stderr, "watchdog: seen_dead %d\n", seen_dead);
717 if (seen_dead > 4) {
718 fprintf(stderr, "watchdog: lockup detected, aborting\n");
719 // we can't do any cleanup here really, the main thread is
720 // likely touching resources and would crash anyway
721 abort();
722 }
723 }
724}
725
726void pl_start_watchdog(void)
727{
728 pthread_attr_t attr;
729 pthread_t tid;
730 int ret;
731
732 pthread_attr_init(&attr);
733 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
734
735 ret = pthread_create(&tid, &attr, watchdog_thread, NULL);
736 if (ret != 0)
737 fprintf(stderr, "could not start watchdog: %d\n", ret);
738}
739
4c08b9e7 740void pl_init(void)
741{
24de2dd4 742 extern unsigned int hSyncCount; // from psxcounters
3ece2f0c 743 extern unsigned int frame_counter;
24de2dd4 744
ddc0a02a 745 psx_w = psx_h = pl_vout_w = pl_vout_h = 256;
746 psx_bpp = pl_vout_bpp = 16;
321ca84d 747
faf2b2aa 748 tsdev = pl_gun_ts_init();
24de2dd4 749
750 pl_rearmed_cbs.gpu_hcnt = &hSyncCount;
3ece2f0c 751 pl_rearmed_cbs.gpu_frame_count = &frame_counter;
4c08b9e7 752}