+ PicoOpt |= POPT_ACC_SPRITES;\r
+ if (!no_scale)\r
+ PicoOpt |= POPT_EN_SOFTSCALE;\r
+\r
+ PicoDrawSetOutFormat(PDF_RGB555, 1);\r
+ Pico.m.dirtyPal = 1;\r
+ if (do_emu)\r
+ PicoFrame();\r
+ else\r
+ PicoFrameDrawOnly();\r
+\r
+ PicoOpt = po_old;\r
+}\r
+\r
+void emu_init(void)\r
+{\r
+ char path[512];\r
+ int pos;\r
+\r
+#if 0\r
+ // FIXME: handle through menu, etc\r
+ FILE *f;\r
+ f = fopen("32X_M_BIOS.BIN", "rb");\r
+ p32x_bios_m = malloc(2048);\r
+ fread(p32x_bios_m, 1, 2048, f);\r
+ fclose(f);\r
+ f = fopen("32X_S_BIOS.BIN", "rb");\r
+ p32x_bios_s = malloc(1024);\r
+ fread(p32x_bios_s, 1, 1024, f);\r
+ fclose(f);\r
+#endif\r
+\r
+ /* make dirs for saves */\r
+ pos = plat_get_root_dir(path, sizeof(path) - 4);\r
+ mkdir_path(path, pos, "mds");\r
+ mkdir_path(path, pos, "srm");\r
+ mkdir_path(path, pos, "brm");\r
+\r
+ pprof_init();\r
+\r
+ make_config_cfg(path);\r
+ config_readlrom(path);\r
+\r
+ PicoInit();\r
+ PicoMessage = plat_status_msg_busy_next;\r
+ PicoMCDopenTray = emu_tray_open;\r
+ PicoMCDcloseTray = emu_tray_close;\r
+}\r
+\r
+void emu_finish(void)\r
+{\r
+ // save SRAM\r
+ if ((currentConfig.EmuOpt & EOPT_EN_SRAM) && SRam.changed) {\r
+ emu_save_load_game(0, 1);\r
+ SRam.changed = 0;\r
+ }\r
+\r
+ if (!(currentConfig.EmuOpt & EOPT_NO_AUTOSVCFG)) {\r
+ char cfg[512];\r
+ make_config_cfg(cfg);\r
+ config_writelrom(cfg);\r
+#ifndef NO_SYNC\r
+ sync();\r
+#endif\r
+ }\r
+\r
+ pprof_finish();\r
+\r
+ PicoExit();\r
+}\r
+\r
+static void skip_frame(int do_audio)\r
+{\r
+ PicoSkipFrame = do_audio ? 1 : 2;\r
+ PicoFrame();\r
+ PicoSkipFrame = 0;\r
+}\r
+\r
+/* our tick here is 1 us right now */\r
+#define ms_to_ticks(x) (unsigned int)(x * 1000)\r
+#define get_ticks() plat_get_ticks_us()\r
+\r
+void emu_loop(void)\r
+{\r
+ int pframes_done; /* "period" frames, used for sync */\r
+ int frames_done, frames_shown; /* actual frames for fps counter */\r
+ int target_fps, target_frametime;\r
+ unsigned int timestamp_base = 0, timestamp_fps;\r
+ char *notice_msg = NULL;\r
+ char fpsbuff[24];\r
+ int i;\r
+\r
+ fpsbuff[0] = 0;\r
+\r
+ /* make sure we are in correct mode */\r
+ Pico.m.dirtyPal = 1;\r
+ rendstatus_old = -1;\r
+\r
+ PicoLoopPrepare();\r
+\r
+ // prepare CD buffer\r
+ if (PicoAHW & PAHW_MCD)\r
+ PicoCDBufferInit();\r
+\r
+ pemu_loop_prep();\r
+\r
+ /* number of ticks per frame */\r
+ if (Pico.m.pal) {\r
+ target_fps = 50;\r
+ target_frametime = ms_to_ticks(1000) / 50;\r
+ } else {\r
+ target_fps = 60;\r
+ target_frametime = ms_to_ticks(1000) / 60 + 1;\r
+ }\r
+\r
+ timestamp_fps = get_ticks();\r
+ reset_timing = 1;\r
+\r
+ frames_done = frames_shown = pframes_done = 0;\r
+\r
+ plat_video_wait_vsync();\r
+\r
+ /* loop with resync every 1 sec. */\r
+ while (engineState == PGS_Running)\r
+ {\r
+ unsigned int timestamp;\r
+ int diff, diff_lim;\r
+\r
+ pprof_start(main);\r
+\r
+ timestamp = get_ticks();\r
+ if (reset_timing) {\r
+ reset_timing = 0;\r
+ timestamp_base = timestamp;\r
+ pframes_done = 0;\r
+ }\r
+\r
+ // show notice_msg message?\r
+ if (notice_msg_time != 0)\r
+ {\r
+ static int noticeMsgSum;\r
+ if (timestamp - ms_to_ticks(notice_msg_time) > ms_to_ticks(STATUS_MSG_TIMEOUT)) {\r
+ notice_msg_time = 0;\r
+ plat_status_msg_clear();\r
+ notice_msg = NULL;\r
+ } else {\r
+ int sum = noticeMsg[0] + noticeMsg[1] + noticeMsg[2];\r
+ if (sum != noticeMsgSum) {\r
+ plat_status_msg_clear();\r
+ noticeMsgSum = sum;\r
+ }\r
+ notice_msg = noticeMsg;\r
+ }\r
+ }\r
+\r
+ // second changed?\r
+ if (timestamp - timestamp_fps >= ms_to_ticks(1000))\r
+ {\r
+#ifdef BENCHMARK\r
+ static int bench = 0, bench_fps = 0, bench_fps_s = 0, bfp = 0, bf[4];\r
+ if (++bench == 10) {\r
+ bench = 0;\r
+ bench_fps_s = bench_fps;\r
+ bf[bfp++ & 3] = bench_fps;\r
+ bench_fps = 0;\r
+ }\r
+ bench_fps += frames_shown;\r
+ sprintf(fpsbuff, "%02i/%02i/%02i", frames_shown, bench_fps_s, (bf[0]+bf[1]+bf[2]+bf[3])>>2);\r
+ printf("%s\n", fpsbuff);\r
+#else\r
+ if (currentConfig.EmuOpt & EOPT_SHOW_FPS) {\r
+ sprintf(fpsbuff, "%02i/%02i", frames_shown, frames_done);\r
+ if (fpsbuff[5] == 0) { fpsbuff[5] = fpsbuff[6] = ' '; fpsbuff[7] = 0; }\r
+ }\r
+#endif\r
+ frames_shown = frames_done = 0;\r
+ timestamp_fps += ms_to_ticks(1000);\r
+ }\r
+#ifdef PFRAMES\r
+ sprintf(fpsbuff, "%i", Pico.m.frame_count);\r
+#endif\r
+\r
+ if (timestamp - timestamp_base >= ms_to_ticks(1000))\r
+ {\r
+ if ((currentConfig.EmuOpt & EOPT_NO_FRMLIMIT) && currentConfig.Frameskip >= 0)\r
+ pframes_done = 0;\r
+ else\r
+ pframes_done -= target_fps;\r
+ if (pframes_done < -2) {\r
+ /* don't drag more than 2 frames behind */\r
+ pframes_done = -2;\r
+ timestamp_base = timestamp - 2 * target_frametime;\r
+ }\r
+ else\r
+ timestamp_base += ms_to_ticks(1000);\r
+ }\r
+\r
+ diff = timestamp - timestamp_base;\r
+ diff_lim = (pframes_done + 1) * target_frametime;\r
+\r
+ if (currentConfig.Frameskip >= 0) // frameskip enabled\r
+ {\r
+ for (i = 0; i < currentConfig.Frameskip; i++) {\r
+ emu_update_input();\r
+ skip_frame(1);\r
+ pframes_done++; frames_done++;\r
+ diff_lim += target_frametime;\r
+\r
+ if (!(currentConfig.EmuOpt & (EOPT_NO_FRMLIMIT|EOPT_EXT_FRMLIMIT))) {\r
+ timestamp = get_ticks();\r
+ diff = timestamp - timestamp_base;\r
+ if (!reset_timing && diff < diff_lim) // we are too fast\r
+ plat_wait_till_us(timestamp_base + diff_lim);\r
+ }\r
+ }\r
+ }\r
+ else if (diff > diff_lim)\r
+ {\r
+ /* no time left for this frame - skip */\r
+ /* limit auto frameskip to 8 */\r
+ if (frames_done / 8 <= frames_shown) {\r
+ emu_update_input();\r
+ skip_frame(diff < diff_lim + target_frametime * 16);\r
+ pframes_done++; frames_done++;\r
+ continue;\r
+ }\r
+ }\r
+\r
+ emu_update_input();\r
+ PicoFrame();\r
+ pemu_finalize_frame(fpsbuff, notice_msg);\r
+\r
+ // plat_video_flip();\r
+\r
+ /* frame limiter */\r
+ if (!reset_timing && !(currentConfig.EmuOpt & (EOPT_NO_FRMLIMIT|EOPT_EXT_FRMLIMIT)))\r
+ {\r
+ timestamp = get_ticks();\r
+ diff = timestamp - timestamp_base;\r
+\r
+ // sleep or vsync if we are still too fast\r
+ if (diff < diff_lim)\r
+ {\r
+ // we are too fast\r
+ plat_wait_till_us(timestamp_base + diff_lim - target_frametime / 4);\r
+ if (currentConfig.EmuOpt & EOPT_VSYNC)\r
+ plat_video_wait_vsync();\r
+ }\r
+ }\r
+\r
+ // XXX: for some plats it might be better to flip before vsync\r
+ // (due to shadow registers in display hw)\r
+ plat_video_flip();\r
+\r
+ pframes_done++; frames_done++; frames_shown++;\r
+\r
+ pprof_end(main);\r
+ }\r
+\r
+ emu_set_fastforward(0);\r
+\r
+ // save SRAM\r
+ if ((currentConfig.EmuOpt & EOPT_EN_SRAM) && SRam.changed) {\r
+ plat_status_msg_busy_first("Writing SRAM/BRAM...");\r
+ emu_save_load_game(0, 1);\r
+ SRam.changed = 0;\r
+ }\r
+\r
+ pemu_loop_end();\r
+\r
+ // pemu_loop_end() might want to do 1 frame for bg image,\r
+ // so free CD buffer here\r
+ if (PicoAHW & PAHW_MCD)\r
+ PicoCDBufferFree();\r
+}\r