+
+static __attribute__((noinline)) int get_cpu_ticks(void)
+{
+ static unsigned long last_utime;
+ static int fd;
+ unsigned long utime, ret;
+ char buf[128];
+
+ if (fd == 0)
+ fd = open("/proc/self/stat", O_RDONLY);
+ lseek(fd, 0, SEEK_SET);
+ buf[0] = 0;
+ read(fd, buf, sizeof(buf));
+ buf[sizeof(buf) - 1] = 0;
+
+ sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu", &utime);
+ ret = utime - last_utime;
+ last_utime = utime;
+ return ret;
+}
+
+static void print_msg(int h, int border)
+{
+ if (pl_vout_bpp == 16)
+ pl_text_out16(border + 2, h - 10, "%s", hud_msg);
+}
+
+static void print_fps(int h, int border)
+{
+ if (pl_vout_bpp == 16)
+ pl_text_out16(border + 2, h - 10, "%2d %4.1f",
+ pl_rearmed_cbs.flips_per_sec, pl_rearmed_cbs.vsps_cur);
+}
+
+static void print_cpu_usage(int w, int h, int border)
+{
+ if (pl_vout_bpp == 16)
+ pl_text_out16(w - border - 28, h - 10, "%3d", pl_rearmed_cbs.cpu_usage);
+}
+
+// draw 192x8 status of 24 sound channels
+static __attribute__((noinline)) void draw_active_chans(int vout_w, int vout_h)
+{
+ extern void spu_get_debug_info(int *chans_out, int *run_chans,
+ int *fmod_chans_out, int *noise_chans_out); // hack
+ int live_chans, run_chans, fmod_chans, noise_chans;
+
+ static const unsigned short colors[2] = { 0x1fe3, 0x0700 };
+ unsigned short *dest = (unsigned short *)pl_vout_buf +
+ vout_w * (vout_h - 10) + vout_w / 2 - 192/2;
+ unsigned short *d, p;
+ int c, x, y;
+
+ if (pl_vout_bpp != 16)
+ return;
+
+ spu_get_debug_info(&live_chans, &run_chans, &fmod_chans, &noise_chans);
+
+ for (c = 0; c < 24; c++) {
+ d = dest + c * 8;
+ p = !(live_chans & (1<<c)) ? (run_chans & (1<<c) ? 0x01c0 : 0) :
+ (fmod_chans & (1<<c)) ? 0xf000 :
+ (noise_chans & (1<<c)) ? 0x001f :
+ colors[c & 1];
+ for (y = 0; y < 8; y++, d += vout_w)
+ for (x = 0; x < 8; x++)
+ d[x] = p;
+ }
+}
+
+void pl_print_hud(int xborder)
+{
+ int w = pl_vout_w, h = pl_vout_h;
+
+ if (h < 16)
+ return;
+
+ if (g_opts & OPT_SHOWSPU)
+ draw_active_chans(w, h);
+
+ if (hud_msg[0] != 0)
+ print_msg(h, xborder);
+ else if (g_opts & OPT_SHOWFPS)
+ print_fps(h, xborder);
+
+ if (g_opts & OPT_SHOWCPU)
+ print_cpu_usage(w, h, xborder);
+}
+
+static void *pl_vout_set_mode(int w, int h, int bpp)
+{
+ // special h handling, Wipeout likes to change it by 1-6
+ static int vsync_cnt_ms_prev;
+ if ((unsigned int)(vsync_cnt - vsync_cnt_ms_prev) < 5*60)
+ h = (h + 7) & ~7;
+ vsync_cnt_ms_prev = vsync_cnt;
+
+ if (w == psx_w && h == psx_h && bpp == psx_bpp)
+ return pl_vout_buf;
+
+ pl_vout_w = psx_w = w;
+ pl_vout_h = psx_h = h;
+ pl_vout_bpp = psx_bpp = bpp;
+
+ pl_vout_buf = plat_gvideo_set_mode(&pl_vout_w, &pl_vout_h, &pl_vout_bpp);
+ if (pl_vout_buf == NULL && pl_rearmed_cbs.pl_vout_raw_flip == NULL)
+ fprintf(stderr, "failed to set mode %dx%d@%d\n",
+ psx_w, psx_h, psx_bpp);
+
+ menu_notify_mode_change(pl_vout_w, pl_vout_h, pl_vout_bpp);
+
+ return pl_vout_buf;
+}
+
+// only used if raw flip is not defined
+static void *pl_vout_flip(void)
+{
+ pl_rearmed_cbs.flip_cnt++;
+
+ if (pl_vout_buf != NULL)
+ pl_print_hud(0);
+
+ // let's flip now
+ pl_vout_buf = plat_gvideo_flip();
+ return pl_vout_buf;
+}
+
+static int pl_vout_open(void)