From: notaz Date: Sun, 20 Dec 2009 19:47:55 +0000 (+0000) Subject: pandora: tripplebuffer fbdev out, refactoring X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=libpicofe.git;a=commitdiff_plain;h=b188c2b6d0448a9c328a9dcae5ba5c8c8b5273f3 pandora: tripplebuffer fbdev out, refactoring git-svn-id: file:///home/notaz/opt/svn/PicoDrive/platform@845 be3aeb3a-fb24-0410-a615-afba39da0efa --- diff --git a/common/emu.c b/common/emu.c index 23e90eb..bde10e4 100644 --- a/common/emu.c +++ b/common/emu.c @@ -1535,6 +1535,9 @@ void emu_loop(void) emu_update_input(); PicoFrame(); + pemu_finalize_frame(fpsbuff, notice_msg); + + //plat_video_flip(); /* frame limiter */ if (!reset_timing && !(currentConfig.EmuOpt & (EOPT_NO_FRMLIMIT|EOPT_EXT_FRMLIMIT))) @@ -1552,7 +1555,9 @@ void emu_loop(void) } } - pemu_update_display(fpsbuff, notice_msg); + // XXX: for some plats it might be better to flip before vsync + // (due to shadow registers in display hw) + plat_video_flip(); pframes_done++; frames_done++; frames_shown++; } diff --git a/common/menu.c b/common/menu.c index 73b41da..ded7bbc 100644 --- a/common/menu.c +++ b/common/menu.c @@ -590,7 +590,16 @@ static void me_loop(menu_entry *menu, int *menu_sel, void (*draw_more)(void)) /* ***************************************** */ /* platform specific options and handlers */ +#if defined(__GP2X__) #include "../gp2x/menu.c" +#elif defined(PANDORA) +#include "../pandora/menu.c" +#else +#define MENU_OPTIONS_GFX +#define MENU_OPTIONS_ADV +#define mgn_opt_renderer NULL /* TODO */ +#define menu_main_plat_draw NULL +#endif static void draw_menu_credits(void) { @@ -668,20 +677,18 @@ static void cdload_progress_cb(const char *fname, int percent) void menu_romload_prepare(const char *rom_name) { const char *p = rom_name + strlen(rom_name); + int i; while (p > rom_name && *p != '/') p--; - /* fill both buffers, callbacks won't update in full */ - plat_video_menu_begin(); - smalltext_out16(1, 1, "Loading", 0xffff); - smalltext_out16(1, me_sfont_h, p, 0xffff); - plat_video_menu_end(); - - plat_video_menu_begin(); - smalltext_out16(1, 1, "Loading", 0xffff); - smalltext_out16(1, me_sfont_h, p, 0xffff); - plat_video_menu_end(); + /* fill all buffers, callbacks won't update in full */ + for (i = 0; i < 3; i++) { + plat_video_menu_begin(); + smalltext_out16(1, 1, "Loading", 0xffff); + smalltext_out16(1, me_sfont_h, p, 0xffff); + plat_video_menu_end(); + } PicoCartLoadProgressCB = load_progress_cb; PicoCDLoadProgressCB = cdload_progress_cb; @@ -1508,7 +1515,7 @@ static menu_entry e_menu_adv_options[] = mee_onoff ("Don't save last used ROM", MA_OPT2_NO_LAST_ROM, currentConfig.EmuOpt, EOPT_NO_AUTOSVCFG), mee_onoff ("Disable idle loop patching",MA_OPT2_NO_IDLE_LOOPS,PicoOpt, POPT_DIS_IDLE_DET), mee_onoff ("Disable frame limiter", MA_OPT2_NO_FRAME_LIMIT,currentConfig.EmuOpt, EOPT_NO_FRMLIMIT), - MENU_GP2X_OPTIONS_ADV + MENU_OPTIONS_ADV mee_end, }; @@ -1530,7 +1537,7 @@ static int mh_opt_render(menu_id id, int keys) static menu_entry e_menu_gfx_options[] = { mee_cust ("Renderer", MA_OPT_RENDERER, mh_opt_render, mgn_opt_renderer), - MENU_GP2X_OPTIONS_GFX + MENU_OPTIONS_GFX mee_end, }; diff --git a/common/plat.h b/common/plat.h index 40478b6..46725bf 100644 --- a/common/plat.h +++ b/common/plat.h @@ -10,7 +10,7 @@ void pemu_validate_config(void); void pemu_loop_prep(void); void pemu_loop_end(void); void pemu_forced_frame(int opts); -void pemu_update_display(const char *fps, const char *notice_msg); +void pemu_finalize_frame(const char *fps, const char *notice_msg); void pemu_sound_start(void); void pemu_sound_stop(void); @@ -33,8 +33,10 @@ void plat_video_menu_enter(int is_rom_loaded); void plat_video_menu_begin(void); void plat_video_menu_end(void); +void plat_video_flip(void); void plat_video_wait_vsync(void); void plat_video_toggle_renderer(int is_next, int force_16bpp, int is_menu); + void plat_update_volume(int has_changed, int is_up); int plat_is_dir(const char *path); diff --git a/gp2x/emu.c b/gp2x/emu.c index b1b314e..2994fdb 100644 --- a/gp2x/emu.c +++ b/gp2x/emu.c @@ -302,7 +302,7 @@ static int make_local_pal_sms(int fast_mode) return 0x40; } -void pemu_update_display(const char *fps, const char *notice) +void pemu_finalize_frame(const char *fps, const char *notice) { int emu_opt = currentConfig.EmuOpt; int ret; @@ -344,7 +344,10 @@ void pemu_update_display(const char *fps, const char *notice) draw_cd_leds(); if (PicoAHW & PAHW_PICO) draw_pico_ptr(); +} +void plat_video_flip(void) +{ gp2x_video_flip(); } @@ -411,7 +414,8 @@ void plat_status_msg_clear(void) void plat_status_msg_busy_next(const char *msg) { plat_status_msg_clear(); - pemu_update_display("", msg); + pemu_finalize_frame("", msg); + plat_video_flip(); emu_status_msg(""); /* assumption: msg_busy_next gets called only when diff --git a/gp2x/menu.c b/gp2x/menu.c index e8908d2..da94d05 100644 --- a/gp2x/menu.c +++ b/gp2x/menu.c @@ -1,5 +1,3 @@ -#ifdef __GP2X__ - #include #include "soc.h" @@ -84,25 +82,17 @@ static const char *mgn_aopt_gamma(menu_id id, int *offs) } -#define MENU_GP2X_OPTIONS_GFX \ +#define MENU_OPTIONS_GFX \ mee_range_cust("Scaling", MA_OPT_SCALING, currentConfig.scaling, 0, 3, mgn_opt_scaling), \ mee_onoff ("Tearing Fix", MA_OPT_TEARING_FIX, currentConfig.EmuOpt, EOPT_WIZ_TEAR_FIX), \ mee_range_cust("Gamma correction", MA_OPT2_GAMMA, currentConfig.gamma, 1, 300, mgn_aopt_gamma), \ mee_onoff ("A_SN's gamma curve", MA_OPT2_A_SN_GAMMA, currentConfig.EmuOpt, EOPT_A_SN_GAMMA), \ mee_onoff ("Vsync", MA_OPT2_VSYNC, currentConfig.EmuOpt, EOPT_VSYNC), -#define MENU_GP2X_OPTIONS_ADV \ +#define MENU_OPTIONS_ADV \ mee_onoff ("Use second CPU for sound", MA_OPT_ARM940_SOUND, PicoOpt, POPT_EXT_FM), \ mee_onoff ("RAM overclock", MA_OPT2_RAMTIMINGS, currentConfig.EmuOpt, EOPT_RAM_TIMINGS), \ mee_onoff ("MMU hack", MA_OPT2_SQUIDGEHACK, currentConfig.EmuOpt, EOPT_MMUHACK), \ mee_onoff ("SVP dynarec", MA_OPT2_SVP_DYNAREC, PicoOpt, POPT_EN_SVP_DRC), \ - mee_onoff ("Status line in main menu", MA_OPT2_STATUS_LINE, currentConfig.EmuOpt, EOPT_SHOW_RTC ), - -#else - -#define MENU_GP2X_OPTIONS_GFX -#define MENU_GP2X_OPTIONS_ADV -#define mgn_opt_renderer NULL /* TODO */ -#define menu_main_plat_draw NULL + mee_onoff ("Status line in main menu", MA_OPT2_STATUS_LINE, currentConfig.EmuOpt, EOPT_SHOW_RTC), -#endif diff --git a/linux/Makefile b/linux/Makefile index d09e211..250f824 100644 --- a/linux/Makefile +++ b/linux/Makefile @@ -1,4 +1,7 @@ # settings +#use_fbdev = 1 +#fake_in_gp2x = 1 + use_musashi = 1 #use_fame = 1 use_cz80 = 1 @@ -8,7 +11,6 @@ use_sh2drc = 1 #drc_debug = 3 #drc_debug_interp = 1 #profile = 1 -#fake_in_gp2x = 1 -include Makefile.local @@ -24,8 +26,6 @@ ifeq "$(ARCH)" "arm" CFLAGS += -mcpu=arm920t DEFINES += ARM endif -LDFLAGS += -lpthread -LDFLAGS += -lX11 CC = $(CROSS)gcc @@ -37,6 +37,14 @@ OBJS += platform/common/main.o platform/common/emu.o platform/common/menu.o \ platform/common/config.o platform/common/fonts.o platform/common/readpng.o \ platform/common/input.o +ifeq "$(use_fbdev)" "1" +DEFINES += FBDEV +OBJS += fbdev.o +else +LDFLAGS += -lpthread +LDFLAGS += -lX11 +endif + ifeq "$(fake_in_gp2x)" "1" DEFINES += IN_GP2X FAKE_IN_GP2X OBJS += platform/gp2x/in_gp2x.o diff --git a/linux/emu.c b/linux/emu.c index aa5185f..98e2b72 100644 --- a/linux/emu.c +++ b/linux/emu.c @@ -17,18 +17,11 @@ static short __attribute__((aligned(4))) sndBuffer[2*44100/50]; -unsigned char temp_frame[320 * 240 * 2]; -unsigned char *PicoDraw2FB = temp_frame; -static int osd_fps_x; char cpu_clk_name[] = "unused"; -extern void update_screen(void); - void pemu_prep_defconfig(void) { - // XXX: move elsewhere - g_menubg_ptr = temp_frame; } void pemu_validate_config(void) @@ -41,6 +34,7 @@ void pemu_validate_config(void) // FIXME: dupes from GP2X, need cleanup static void (*osd_text)(int x, int y, const char *text); +/* static void osd_text8(int x, int y, const char *text) { int len = strlen(text)*8; @@ -55,6 +49,7 @@ static void osd_text8(int x, int y, const char *text) } emu_text_out8(x, y, text); } +*/ static void osd_text16(int x, int y, const char *text) { @@ -108,18 +103,16 @@ static int EmuScanBegin16(unsigned int num) return 0; } -void pemu_update_display(const char *fps, const char *notice) +void pemu_finalize_frame(const char *fps, const char *notice) { if (notice || (currentConfig.EmuOpt & EOPT_SHOW_FPS)) { if (notice) osd_text(4, g_screen_height - 8, notice); if (currentConfig.EmuOpt & EOPT_SHOW_FPS) - osd_text(osd_fps_x, g_screen_height - 8, fps); + osd_text(g_screen_width - 60, g_screen_height - 8, fps); } if ((PicoAHW & PAHW_MCD) && (currentConfig.EmuOpt & EOPT_EN_CD_LEDS)) draw_cd_leds(); - - update_screen(); } void plat_video_toggle_renderer(int is_next, int force_16bpp, int is_menu) @@ -139,7 +132,7 @@ void plat_video_menu_begin(void) void plat_video_menu_end(void) { - update_screen(); + plat_video_flip(); } void plat_status_msg_clear(void) @@ -152,7 +145,8 @@ void plat_status_msg_clear(void) void plat_status_msg_busy_next(const char *msg) { plat_status_msg_clear(); - pemu_update_display("", msg); + pemu_finalize_frame("", msg); + plat_video_flip(); emu_status_msg(""); reset_timing = 1; } @@ -202,29 +196,30 @@ static void updateSound(int len) void pemu_sound_start(void) { - static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0; int target_fps = Pico.m.pal ? 50 : 60; PsndOut = NULL; if (currentConfig.EmuOpt & EOPT_EN_SOUND) { - int snd_excess_add; - if (PsndRate != PsndRate_old || (PicoOpt&0x20b) != (PicoOpt_old&0x20b) || Pico.m.pal != pal_old) - PsndRerate(Pico.m.frame_count ? 1 : 0); + int snd_excess_add, frame_samples; + int is_stereo = (PicoOpt & POPT_EN_STEREO) ? 1 : 0; + + PsndRerate(Pico.m.frame_count ? 1 : 0); + + frame_samples = PsndLen; + snd_excess_add = ((PsndRate - PsndLen * target_fps)<<16) / target_fps; + if (snd_excess_add != 0) + frame_samples++; - snd_excess_add = ((PsndRate - PsndLen*target_fps)<<16) / target_fps; printf("starting audio: %i len: %i (ex: %04x) stereo: %i, pal: %i\n", - PsndRate, PsndLen, snd_excess_add, (PicoOpt&8)>>3, Pico.m.pal); - sndout_oss_start(PsndRate, 16, (PicoOpt&8)>>3); + PsndRate, PsndLen, snd_excess_add, is_stereo, Pico.m.pal); + sndout_oss_start(PsndRate, frame_samples, is_stereo); sndout_oss_setvol(currentConfig.volume, currentConfig.volume); PicoWriteSound = updateSound; plat_update_volume(0, 0); memset(sndBuffer, 0, sizeof(sndBuffer)); PsndOut = sndBuffer; - PsndRate_old = PsndRate; - PicoOpt_old = PicoOpt; - pal_old = Pico.m.pal; } } @@ -243,8 +238,6 @@ void plat_debug_cat(char *str) void emu_video_mode_change(int start_line, int line_count, int is_32cols) { - osd_fps_x = 260; - // clear whole screen in all buffers memset32(g_screen_ptr, 0, g_screen_width * g_screen_height * 2 / 4); } @@ -292,10 +285,6 @@ void plat_wait_till_us(unsigned int us_to) } } -void plat_video_wait_vsync(void) -{ -} - const char *plat_get_credits(void) { return "PicoDrive v" VERSION " (c) notaz, 2006-2009\n\n\n" diff --git a/linux/fbdev.c b/linux/fbdev.c new file mode 100644 index 0000000..6ad1d4e --- /dev/null +++ b/linux/fbdev.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/emu.h" +#include "fbdev.h" + +#define FBDEV_MAX_BUFFERS 3 + +static int fbdev = -1; +static void *fbdev_mem = MAP_FAILED; +static int fbdev_mem_size; +static struct fb_var_screeninfo fbvar_old; +static struct fb_var_screeninfo fbvar_new; +static int fbdev_buffer_write; + +void *fbdev_buffers[FBDEV_MAX_BUFFERS]; +int fbdev_buffer_count; + +void plat_video_flip(void) +{ + int draw_buf; + + if (fbdev_buffer_count < 2) + return; + + draw_buf = fbdev_buffer_write; + fbdev_buffer_write++; + if (fbdev_buffer_write >= fbdev_buffer_count) + fbdev_buffer_write = 0; + + fbvar_new.yoffset = fbvar_old.yres * draw_buf; + g_screen_ptr = fbdev_buffers[fbdev_buffer_write]; +} + +void plat_video_wait_vsync(void) +{ + int arg = 0; + ioctl(fbdev, FBIO_WAITFORVSYNC, &arg); +} + +int vout_fbdev_init(int *w, int *h) +{ + static const char *fbdev_name = "/dev/fb0"; + int i, ret; + + fbdev = open(fbdev_name, O_RDWR); + if (fbdev == -1) { + fprintf(stderr, "%s: ", fbdev_name); + perror("open"); + return -1; + } + + ret = ioctl(fbdev, FBIOGET_VSCREENINFO, &fbvar_old); + if (ret == -1) { + perror("FBIOGET_VSCREENINFO ioctl"); + goto fail; + } + + fbvar_new = fbvar_old; + printf("%s: %ix%i@%d\n", fbdev_name, fbvar_old.xres, fbvar_old.yres, fbvar_old.bits_per_pixel); + *w = fbvar_old.xres; + *h = fbvar_old.yres; + fbdev_buffer_count = FBDEV_MAX_BUFFERS; // be optimistic + + if (fbvar_new.bits_per_pixel != 16) { + printf(" switching to 16bpp\n"); + fbvar_new.bits_per_pixel = 16; + ret = ioctl(fbdev, FBIOPUT_VSCREENINFO, &fbvar_new); + if (ret == -1) { + perror("FBIOPUT_VSCREENINFO ioctl"); + goto fail; + } + } + + if (fbvar_new.yres_virtual < fbvar_old.yres * fbdev_buffer_count) { + fbvar_new.yres_virtual = fbvar_old.yres * fbdev_buffer_count; + ret = ioctl(fbdev, FBIOPUT_VSCREENINFO, &fbvar_new); + if (ret == -1) { + fbdev_buffer_count = 1; + fprintf(stderr, "Warning: failed to increase virtual resolution, " + "doublebuffering disabled\n"); + } + } + + fbdev_mem_size = *w * *h * 2 * fbdev_buffer_count; + fbdev_mem = mmap(0, fbdev_mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev, 0); + if (fbdev_mem == MAP_FAILED && fbdev_buffer_count > 1) { + fbdev_mem_size = *w * *h * 2; + fbdev_buffer_count = 1; + fprintf(stderr, "Warning: can't map %d bytes, doublebuffering disabled\n", fbdev_mem_size); + fbdev_mem = mmap(0, fbdev_mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev, 0); + } + if (fbdev_mem == MAP_FAILED) { + perror("mmap framebuffer"); + goto fail; + } + memset(fbdev_mem, 0, fbdev_mem_size); + for (i = 0; i < fbdev_buffer_count; i++) + fbdev_buffers[i] = (char *)fbdev_mem + i * *w * *h * 2; + g_screen_ptr = fbdev_buffers[0]; + + // some checks + ret = 0; + ret = ioctl(fbdev, FBIO_WAITFORVSYNC, &ret); + if (ret != 0) + fprintf(stderr, "Warning: vsync doesn't seem to be supported\n"); + + if (fbdev_buffer_count > 1) { + fbdev_buffer_write = 0; + fbvar_new.yoffset = fbvar_old.yres * (fbdev_buffer_count - 1); + ret = ioctl(fbdev, FBIOPAN_DISPLAY, &fbvar_new); + if (ret != 0) { + fbdev_buffer_count = 1; + fprintf(stderr, "Warning: can't pan display, doublebuffering disabled\n"); + } + } + + printf("fbdev initialized.\n"); + return 0; + +fail: + close(fbdev); + return -1; +} + +void vout_fbdev_finish(void) +{ + ioctl(fbdev, FBIOPUT_VSCREENINFO, &fbvar_old); + if (fbdev_mem != MAP_FAILED) + munmap(fbdev_mem, fbdev_mem_size); + if (fbdev >= 0) + close(fbdev); + fbdev_mem = NULL; + fbdev = -1; +} + +#if 0 +void *g_screen_ptr; +int main() +{ + int w, h; + vout_fbdev_init(&w, &h); + //while (1) + { + memset(g_screen_ptr, 0xff, fbdev_mem_size / 2); + plat_video_wait_vsync(); + plat_video_flip(); + memset(g_screen_ptr, 0x00, fbdev_mem_size / 2); + usleep(8000); +// plat_video_wait_vsync(); + plat_video_flip(); + } +} +#endif diff --git a/linux/fbdev.h b/linux/fbdev.h new file mode 100644 index 0000000..1e5d28b --- /dev/null +++ b/linux/fbdev.h @@ -0,0 +1,5 @@ +int vout_fbdev_init(int *w, int *h); +void vout_fbdev_finish(void); + +extern void *fbdev_buffers[]; +extern int fbdev_buffer_count; diff --git a/linux/io.c b/linux/io.c index b16cf08..63e3da8 100644 --- a/linux/io.c +++ b/linux/io.c @@ -2,13 +2,6 @@ #include #include #include -#include -#include - -#include -#include -#include -#include #include "../common/emu.h" #include "../common/menu.h" @@ -17,15 +10,23 @@ #include "log_io.h" -unsigned long current_keys = 0; +int current_keys; +unsigned char *PicoDraw2FB; + +#ifdef FBDEV + +#include "fbdev.h" + +#else + +#include +#include + static int current_bpp = 16; static int current_pal[256]; static const char *verstring = "PicoDrive " VERSION; static int scr_changed = 0, scr_w = SCREEN_WIDTH, scr_h = SCREEN_HEIGHT; -/* ifndef is for qemu build without video out */ -#ifndef ARM - /* faking GP2X pad */ enum { GP2X_UP=0x1, GP2X_LEFT=0x4, GP2X_DOWN=0x10, GP2X_RIGHT=0x40, GP2X_START=1<<8, GP2X_SELECT=1<<9, GP2X_L=1<<10, GP2X_R=1<<11, @@ -245,23 +246,24 @@ static void xlib_init(void) sem_wait(&xlib_sem); sem_destroy(&xlib_sem); } -#endif // !ARM /* --- */ static void realloc_screen(void) { - void *old = g_screen_ptr; + int size = scr_w * scr_h * 2; g_screen_width = scr_w; g_screen_height = scr_h; - g_screen_ptr = calloc(g_screen_width * g_screen_height * 2, 1); - free(old); + g_screen_ptr = realloc(g_screen_ptr, size); + g_menubg_ptr = realloc(g_menubg_ptr, size); + memset(g_screen_ptr, 0, size); + memset(g_menubg_ptr, 0, size); + PicoDraw2FB = g_menubg_ptr; scr_changed = 0; } -void update_screen(void) +void plat_video_flip(void) { -#ifndef ARM unsigned int *image; int pixel_count, i; @@ -301,29 +303,45 @@ void update_screen(void) realloc_screen(); ximage_realloc(xlib_display, DefaultVisual(xlib_display, 0)); } -#endif } +void plat_video_wait_vsync(void) +{ +} + +#endif // !FBDEV + void plat_early_init(void) { } void plat_init(void) { +#ifdef FBDEV + int ret, w, h; + ret = vout_fbdev_init(&w, &h); + if (ret != 0) + exit(1); + g_screen_width = w; + g_menubg_ptr = realloc(g_menubg_ptr, w * g_screen_height * 2); + PicoDraw2FB = g_menubg_ptr; +#else realloc_screen(); memset(g_screen_ptr, 0, g_screen_width * g_screen_height * 2); + xlib_init(); +#endif // snd sndout_oss_init(); - -#ifndef ARM - xlib_init(); -#endif } void plat_finish(void) { +#ifdef FBDEV + vout_fbdev_finish(); +#else free(g_screen_ptr); +#endif sndout_oss_exit(); } diff --git a/linux/sndout_oss.c b/linux/sndout_oss.c index 4d8e58b..f816c7d 100644 --- a/linux/sndout_oss.c +++ b/linux/sndout_oss.c @@ -25,21 +25,27 @@ int sndout_oss_init(void) return 0; } +void sndout_oss_stop(void) +{ + if (sounddev < 0) + return; + + ioctl(sounddev, SOUND_PCM_SYNC, 0); + close(sounddev); + sounddev = -1; +} + int sndout_oss_start(int rate, int frame_samples, int stereo) { static int s_oldrate = 0, s_old_fsamples = 0, s_oldstereo = 0; int frag, bsize, bits, ret; - // if no settings change, we don't need to do anything, - // since audio is never stopped - if (rate == s_oldrate && s_old_fsamples == frame_samples && s_oldstereo == stereo) + // GP2X: if no settings change, we don't need to do anything, + // since audio is never stopped there + if (sounddev >= 0 && rate == s_oldrate && s_old_fsamples == frame_samples && s_oldstereo == stereo) return 0; - if (sounddev >= 0) { - ioctl(sounddev, SOUND_PCM_SYNC, 0); - close(sounddev); - } - + sndout_oss_stop(); sounddev = open("/dev/dsp", O_WRONLY|O_ASYNC); if (sounddev == -1) { @@ -72,8 +78,10 @@ int sndout_oss_start(int rate, int frame_samples, int stereo) if (ret < 0) perror("failed to set audio format"); +#ifdef __GP2X__ // not sure if this is still needed (avoiding driver bugs?) usleep(192*1024); +#endif printf("sndout_oss_start: %d/%dbit/%s, %d buffers of %i bytes\n", rate, bits, stereo ? "stereo" : "mono", frag >> 16, 1 << (frag & 0xffff)); diff --git a/linux/sndout_oss.h b/linux/sndout_oss.h index d5a2610..2c48860 100644 --- a/linux/sndout_oss.h +++ b/linux/sndout_oss.h @@ -1,5 +1,6 @@ int sndout_oss_init(void); int sndout_oss_start(int rate, int frame_samples, int stereo); +void sndout_oss_stop(void); int sndout_oss_write(const void *buff, int len); int sndout_oss_can_write(int bytes); void sndout_oss_sync(void); diff --git a/pandora/Makefile b/pandora/Makefile index 4f132df..c70c835 100644 --- a/pandora/Makefile +++ b/pandora/Makefile @@ -48,7 +48,8 @@ OBJS += pandora.o emu.o asm_utils.o OBJS += platform/common/emu.o platform/common/menu.o platform/common/fonts.o platform/common/config.o \ platform/common/arm_utils.o platform/common/mp3_helix.o platform/common/arm_linux.o \ platform/common/readpng.o platform/common/input.o platform/common/main.o \ - platform/linux/in_evdev.o platform/linux/sndout_oss.o platform/linux/plat.o + platform/linux/fbdev.o platform/linux/in_evdev.o platform/linux/sndout_oss.o \ + platform/linux/plat.o # ARM stuff OBJS += pico/carthw/svp/compiler.o pico/carthw/svp/stub_arm.o diff --git a/pandora/emu.c b/pandora/emu.c index 4a628c7..f7c2a2e 100644 --- a/pandora/emu.c +++ b/pandora/emu.c @@ -4,24 +4,25 @@ // For commercial use, separate licencing terms must be obtained. #include +#include #include "../common/emu.h" #include "../common/menu.h" #include "../common/plat.h" #include "../common/arm_utils.h" #include "../linux/sndout_oss.h" +#include "../linux/fbdev.h" #include "asm_utils.h" #include "version.h" #include -#define USE_320_SCREEN 1 +//#define USE_320_SCREEN 1 static short __attribute__((aligned(4))) sndBuffer[2*44100/50]; static unsigned char temp_frame[g_screen_width * g_screen_height * 2]; unsigned char *PicoDraw2FB = temp_frame; -static int osd_fps_x; char cpu_clk_name[] = "unused"; @@ -29,6 +30,8 @@ void pemu_prep_defconfig(void) { // XXX: move elsewhere g_menubg_ptr = temp_frame; + + defaultConfig.EmuOpt |= EOPT_VSYNC; } void pemu_validate_config(void) @@ -141,15 +144,40 @@ static int EmuScanEnd16(unsigned int num) return 0; } +static int EmuScanEnd16_32x(unsigned int num) +{ + unsigned int *ps; + unsigned int *pd; + int len; + + ps = (unsigned int *)temp_frame; + pd = (unsigned int *)g_screen_ptr + (num*800*2 + 800/2 - 320*2/2) / 2; + + for (len = 320/2; len > 0; len--, ps++) { + unsigned int p, p1; + p1 = *ps; + p = p1 << 16; + p |= p >> 16; + *pd = pd[800/2] = p; + pd++; + + p = p1 >> 16; + p |= p << 16; + *pd = pd[800/2] = p; + pd++; + } + + return 0; +} #endif // USE_320_SCREEN -void pemu_update_display(const char *fps, const char *notice) +void pemu_finalize_frame(const char *fps, const char *notice) { if (notice || (currentConfig.EmuOpt & EOPT_SHOW_FPS)) { if (notice) - osd_text(4, 460, notice); + osd_text(4, 464, notice); if (currentConfig.EmuOpt & EOPT_SHOW_FPS) - osd_text(osd_fps_x, 460, fps); + osd_text(640, 464, fps); } if ((PicoAHW & PAHW_MCD) && (currentConfig.EmuOpt & EOPT_EN_CD_LEDS)) draw_cd_leds(); @@ -172,19 +200,24 @@ void plat_video_menu_begin(void) void plat_video_menu_end(void) { + plat_video_flip(); } void plat_status_msg_clear(void) { - unsigned short *d = (unsigned short *)g_screen_ptr + g_screen_width * g_screen_height; - int l = g_screen_width * 8; - memset32((int *)(d - l), 0, l * 2 / 4); + int s = g_screen_width * g_screen_height * 2; + int l = g_screen_width * 16 * 2; + int i; + + for (i = 0; i < fbdev_buffer_count; i++) + memset32((int *)((char *)fbdev_buffers[i] + s - l), 0, l / 4); } void plat_status_msg_busy_next(const char *msg) { plat_status_msg_clear(); - pemu_update_display("", msg); + pemu_finalize_frame("", msg); + plat_video_flip(); emu_status_msg(""); reset_timing = 1; } @@ -224,13 +257,6 @@ void pemu_forced_frame(int opts) PicoOpt |= opts|POPT_ACC_SPRITES; // acc_sprites currentConfig.EmuOpt |= 0x80; -#ifdef USE_320_SCREEN - PicoDrawSetColorFormat(1); - PicoScanBegin = EmuScanBegin16; -#else - PicoDrawSetColorFormat(-1); - PicoScanEnd = EmuScanEnd16; -#endif Pico.m.dirtyPal = 1; PicoFrameDrawOnly(); @@ -240,48 +266,59 @@ void pemu_forced_frame(int opts) static void updateSound(int len) { + unsigned int t; + len <<= 1; if (PicoOpt & POPT_EN_STEREO) len <<= 1; + // sndout_oss_can_write() not reliable.. if ((currentConfig.EmuOpt & EOPT_NO_FRMLIMIT) && !sndout_oss_can_write(len)) return; /* avoid writing audio when lagging behind to prevent audio lag */ - if (PicoSkipFrame != 2) - sndout_oss_write(PsndOut, len); + if (PicoSkipFrame == 2) + return; + + t = plat_get_ticks_ms(); + sndout_oss_write(PsndOut, len); + t = plat_get_ticks_ms() - t; + if (t > 1) + printf("audio lag %u\n", t); } void pemu_sound_start(void) { - static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0; int target_fps = Pico.m.pal ? 50 : 60; PsndOut = NULL; - if (currentConfig.EmuOpt & 4) + if (currentConfig.EmuOpt & EOPT_EN_SOUND) { - int snd_excess_add; - if (PsndRate != PsndRate_old || (PicoOpt&0x20b) != (PicoOpt_old&0x20b) || Pico.m.pal != pal_old) - PsndRerate(Pico.m.frame_count ? 1 : 0); + int snd_excess_add, frame_samples; + int is_stereo = (PicoOpt & POPT_EN_STEREO) ? 1 : 0; + + PsndRerate(Pico.m.frame_count ? 1 : 0); + + frame_samples = PsndLen; + snd_excess_add = ((PsndRate - PsndLen * target_fps)<<16) / target_fps; + if (snd_excess_add != 0) + frame_samples++; - snd_excess_add = ((PsndRate - PsndLen*target_fps)<<16) / target_fps; printf("starting audio: %i len: %i (ex: %04x) stereo: %i, pal: %i\n", - PsndRate, PsndLen, snd_excess_add, (PicoOpt&8)>>3, Pico.m.pal); - sndout_oss_start(PsndRate, 16, (PicoOpt&8)>>3); - sndout_oss_setvol(currentConfig.volume, currentConfig.volume); + PsndRate, PsndLen, snd_excess_add, is_stereo, Pico.m.pal); + sndout_oss_start(PsndRate, frame_samples * 2, is_stereo); + //sndout_oss_setvol(currentConfig.volume, currentConfig.volume); PicoWriteSound = updateSound; plat_update_volume(0, 0); memset(sndBuffer, 0, sizeof(sndBuffer)); PsndOut = sndBuffer; - PsndRate_old = PsndRate; - PicoOpt_old = PicoOpt; - pal_old = Pico.m.pal; } } void pemu_sound_stop(void) { + sndout_oss_stop(); } void pemu_sound_wait(void) @@ -295,22 +332,32 @@ void plat_debug_cat(char *str) void emu_video_mode_change(int start_line, int line_count, int is_32cols) { - osd_fps_x = 260; + int i; // clear whole screen in all buffers - memset32(g_screen_ptr, 0, g_screen_width * g_screen_height * 2 / 4); -} + for (i = 0; i < fbdev_buffer_count; i++) + memset32(fbdev_buffers[i], 0, g_screen_width * g_screen_height * 2 / 4); -void pemu_loop_prep(void) -{ #ifdef USE_320_SCREEN PicoDrawSetColorFormat(1); PicoScanBegin = EmuScanBegin16; #else - PicoDrawSetColorFormat(-1); - PicoScanEnd = EmuScanEnd16; + if (PicoAHW & PAHW_32X) { + DrawLineDest = (unsigned short *)temp_frame; + PicoDrawSetColorFormat(1); + PicoScanBegin = NULL; + PicoScanEnd = EmuScanEnd16_32x; + } else { + PicoDrawSetColorFormat(-1); + PicoScanBegin = NULL; + PicoScanEnd = EmuScanEnd16; + } #endif +} +void pemu_loop_prep(void) +{ + emu_video_mode_change(0, 0, 0); pemu_sound_start(); } @@ -335,23 +382,27 @@ void pemu_loop_end(void) currentConfig.EmuOpt = eo_old; } -/* XXX: avoid busy wait somehow? */ void plat_wait_till_us(unsigned int us_to) { unsigned int now; + signed int diff; - spend_cycles(1024); now = plat_get_ticks_us(); - while ((signed int)(us_to - now) > 512) - { + // XXX: need to check NOHZ and djw kernel + diff = (signed int)(us_to - now); + if (diff > 10000) { + //printf("sleep %d\n", us_to - now); + usleep(diff * 15 / 16); + now = plat_get_ticks_us(); + //printf(" wake %d\n", (signed)(us_to - now)); + } +/* + while ((signed int)(us_to - now) > 512) { spend_cycles(1024); now = plat_get_ticks_us(); } -} - -void plat_video_wait_vsync(void) -{ +*/ } const char *plat_get_credits(void) diff --git a/pandora/pandora.c b/pandora/pandora.c index 92047c2..4019994 100644 --- a/pandora/pandora.c +++ b/pandora/pandora.c @@ -1,62 +1,39 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include "../linux/sndout_oss.h" -#include "../common/arm_linux.h" +#include "../linux/fbdev.h" #include "../common/emu.h" -static int fbdev = -1; - -#define SCREEN_MAP_SIZE (800*480*2) -static void *screen = MAP_FAILED; - void plat_early_init(void) { } void plat_init(void) { - printf("entering init()\n"); fflush(stdout); + int ret, w, h; - fbdev = open("/dev/fb0", O_RDWR); - if (fbdev == -1) - { - perror("open(\"/dev/fb0\")"); + ret = vout_fbdev_init(&w, &h); + if (ret != 0) { + fprintf(stderr, "couldn't init framebuffer\n"); exit(1); } - screen = mmap(0, SCREEN_MAP_SIZE, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev, 0); - if (screen == MAP_FAILED) - { - perror("mmap(fbptr)"); + if (w != g_screen_width || h != g_screen_height) { + fprintf(stderr, "%dx%d not supported\n", w, h); + vout_fbdev_finish(); exit(1); } - printf("fbptr %p\n", screen); - g_screen_ptr = screen; // snd sndout_oss_init(); - - printf("exitting init()\n"); fflush(stdout); } void plat_finish(void) { - if (screen != MAP_FAILED) - munmap(screen, SCREEN_MAP_SIZE); - if (fbdev >= 0) - close(fbdev); - sndout_oss_exit(); + vout_fbdev_finish(); printf("all done"); } diff --git a/pandora/port_config.h b/pandora/port_config.h index 506c52a..0c071bd 100644 --- a/pandora/port_config.h +++ b/pandora/port_config.h @@ -6,7 +6,6 @@ #define CASE_SENSITIVE_FS 1 // CS filesystem #define DONT_OPEN_MANY_FILES 0 #define REDUCE_IO_CALLS 0 -#define SIMPLE_WRITE_SOUND 0 #define SCREEN_SIZE_FIXED 1 #define SCREEN_WIDTH 800 @@ -22,6 +21,8 @@ // pico.c #define CAN_HANDLE_240_LINES 1 +#define SIMPLE_WRITE_SOUND 0 + // logging emu events #define EL_LOGMASK (EL_STATUS|EL_IDLE) // (EL_STATUS|EL_ANOMALY|EL_UIO|EL_SRAMIO|EL_INTS|EL_CDPOLL) // xffff diff --git a/win32/plat.c b/win32/plat.c index 2770b94..e5e2f7e 100644 --- a/win32/plat.c +++ b/win32/plat.c @@ -91,7 +91,11 @@ void pemu_forced_frame(int opts) { } -void pemu_update_display(const char *fps, const char *notice_msg) +void pemu_finalize_frame(const char *fps, const char *notice_msg) +{ +} + +void plat_video_flip(void) { DirectScreen(g_screen_ptr); DirectPresent();