pandora: tripplebuffer fbdev out, refactoring
authornotaz <notasas@gmail.com>
Sun, 20 Dec 2009 19:47:55 +0000 (19:47 +0000)
committernotaz <notasas@gmail.com>
Sun, 20 Dec 2009 19:47:55 +0000 (19:47 +0000)
git-svn-id: file:///home/notaz/opt/svn/PicoDrive/platform@845 be3aeb3a-fb24-0410-a615-afba39da0efa

17 files changed:
common/emu.c
common/menu.c
common/plat.h
gp2x/emu.c
gp2x/menu.c
linux/Makefile
linux/emu.c
linux/fbdev.c [new file with mode: 0644]
linux/fbdev.h [new file with mode: 0644]
linux/io.c
linux/sndout_oss.c
linux/sndout_oss.h
pandora/Makefile
pandora/emu.c
pandora/pandora.c
pandora/port_config.h
win32/plat.c

index 23e90eb..bde10e4 100644 (file)
@@ -1535,6 +1535,9 @@ void emu_loop(void)
 \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
@@ -1552,7 +1555,9 @@ void emu_loop(void)
                        }\r
                }\r
 \r
-               pemu_update_display(fpsbuff, notice_msg);\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
index 73b41da..ded7bbc 100644 (file)
@@ -590,7 +590,16 @@ static void me_loop(menu_entry *menu, int *menu_sel, void (*draw_more)(void))
 /* ***************************************** */\r
 \r
 /* platform specific options and handlers */\r
+#if   defined(__GP2X__)\r
 #include "../gp2x/menu.c"\r
+#elif defined(PANDORA)\r
+#include "../pandora/menu.c"\r
+#else\r
+#define MENU_OPTIONS_GFX\r
+#define MENU_OPTIONS_ADV\r
+#define mgn_opt_renderer NULL /* TODO */\r
+#define menu_main_plat_draw NULL\r
+#endif\r
 \r
 static void draw_menu_credits(void)\r
 {\r
@@ -668,20 +677,18 @@ static void cdload_progress_cb(const char *fname, int percent)
 void menu_romload_prepare(const char *rom_name)\r
 {\r
        const char *p = rom_name + strlen(rom_name);\r
+       int i;\r
 \r
        while (p > rom_name && *p != '/')\r
                p--;\r
 \r
-       /* fill both buffers, callbacks won't update in full */\r
-       plat_video_menu_begin();\r
-       smalltext_out16(1, 1, "Loading", 0xffff);\r
-       smalltext_out16(1, me_sfont_h, p, 0xffff);\r
-       plat_video_menu_end();\r
-\r
-       plat_video_menu_begin();\r
-       smalltext_out16(1, 1, "Loading", 0xffff);\r
-       smalltext_out16(1, me_sfont_h, p, 0xffff);\r
-       plat_video_menu_end();\r
+       /* fill all buffers, callbacks won't update in full */\r
+       for (i = 0; i < 3; i++) {\r
+               plat_video_menu_begin();\r
+               smalltext_out16(1, 1, "Loading", 0xffff);\r
+               smalltext_out16(1, me_sfont_h, p, 0xffff);\r
+               plat_video_menu_end();\r
+       }\r
 \r
        PicoCartLoadProgressCB = load_progress_cb;\r
        PicoCDLoadProgressCB = cdload_progress_cb;\r
@@ -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),\r
        mee_onoff     ("Disable idle loop patching",MA_OPT2_NO_IDLE_LOOPS,PicoOpt, POPT_DIS_IDLE_DET),\r
        mee_onoff     ("Disable frame limiter",    MA_OPT2_NO_FRAME_LIMIT,currentConfig.EmuOpt, EOPT_NO_FRMLIMIT),\r
-       MENU_GP2X_OPTIONS_ADV\r
+       MENU_OPTIONS_ADV\r
        mee_end,\r
 };\r
 \r
@@ -1530,7 +1537,7 @@ static int mh_opt_render(menu_id id, int keys)
 static menu_entry e_menu_gfx_options[] =\r
 {\r
        mee_cust      ("Renderer",                 MA_OPT_RENDERER,       mh_opt_render, mgn_opt_renderer),\r
-       MENU_GP2X_OPTIONS_GFX\r
+       MENU_OPTIONS_GFX\r
        mee_end,\r
 };\r
 \r
index 40478b6..46725bf 100644 (file)
@@ -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);
index b1b314e..2994fdb 100644 (file)
@@ -302,7 +302,7 @@ static int make_local_pal_sms(int fast_mode)
        return 0x40;\r
 }\r
 \r
-void pemu_update_display(const char *fps, const char *notice)\r
+void pemu_finalize_frame(const char *fps, const char *notice)\r
 {\r
        int emu_opt = currentConfig.EmuOpt;\r
        int ret;\r
@@ -344,7 +344,10 @@ void pemu_update_display(const char *fps, const char *notice)
                draw_cd_leds();\r
        if (PicoAHW & PAHW_PICO)\r
                draw_pico_ptr();\r
+}\r
 \r
+void plat_video_flip(void)\r
+{\r
        gp2x_video_flip();\r
 }\r
 \r
@@ -411,7 +414,8 @@ void plat_status_msg_clear(void)
 void plat_status_msg_busy_next(const char *msg)\r
 {\r
        plat_status_msg_clear();\r
-       pemu_update_display("", msg);\r
+       pemu_finalize_frame("", msg);\r
+       plat_video_flip();\r
        emu_status_msg("");\r
 \r
        /* assumption: msg_busy_next gets called only when\r
index e8908d2..da94d05 100644 (file)
@@ -1,5 +1,3 @@
-#ifdef __GP2X__
-
 #include <time.h>
 #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
index d09e211..250f824 100644 (file)
@@ -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
index aa5185f..98e2b72 100644 (file)
 \r
 \r
 static short __attribute__((aligned(4))) sndBuffer[2*44100/50];\r
-unsigned char temp_frame[320 * 240 * 2];\r
-unsigned char *PicoDraw2FB = temp_frame;\r
-static int osd_fps_x;\r
 char cpu_clk_name[] = "unused";\r
 \r
-extern void update_screen(void);\r
-\r
 \r
 void pemu_prep_defconfig(void)\r
 {\r
-       // XXX: move elsewhere\r
-       g_menubg_ptr = temp_frame;\r
 }\r
 \r
 void pemu_validate_config(void)\r
@@ -41,6 +34,7 @@ void pemu_validate_config(void)
 // FIXME: dupes from GP2X, need cleanup\r
 static void (*osd_text)(int x, int y, const char *text);\r
 \r
+/*\r
 static void osd_text8(int x, int y, const char *text)\r
 {\r
        int len = strlen(text)*8;\r
@@ -55,6 +49,7 @@ static void osd_text8(int x, int y, const char *text)
        }\r
        emu_text_out8(x, y, text);\r
 }\r
+*/\r
 \r
 static void osd_text16(int x, int y, const char *text)\r
 {\r
@@ -108,18 +103,16 @@ static int EmuScanBegin16(unsigned int num)
        return 0;\r
 }\r
 \r
-void pemu_update_display(const char *fps, const char *notice)\r
+void pemu_finalize_frame(const char *fps, const char *notice)\r
 {\r
        if (notice || (currentConfig.EmuOpt & EOPT_SHOW_FPS)) {\r
                if (notice)\r
                        osd_text(4, g_screen_height - 8, notice);\r
                if (currentConfig.EmuOpt & EOPT_SHOW_FPS)\r
-                       osd_text(osd_fps_x, g_screen_height - 8, fps);\r
+                       osd_text(g_screen_width - 60, g_screen_height - 8, fps);\r
        }\r
        if ((PicoAHW & PAHW_MCD) && (currentConfig.EmuOpt & EOPT_EN_CD_LEDS))\r
                draw_cd_leds();\r
-\r
-       update_screen();\r
 }\r
 \r
 void plat_video_toggle_renderer(int is_next, int force_16bpp, int is_menu)\r
@@ -139,7 +132,7 @@ void plat_video_menu_begin(void)
 \r
 void plat_video_menu_end(void)\r
 {\r
-       update_screen();\r
+       plat_video_flip();\r
 }\r
 \r
 void plat_status_msg_clear(void)\r
@@ -152,7 +145,8 @@ void plat_status_msg_clear(void)
 void plat_status_msg_busy_next(const char *msg)\r
 {\r
        plat_status_msg_clear();\r
-       pemu_update_display("", msg);\r
+       pemu_finalize_frame("", msg);\r
+       plat_video_flip();\r
        emu_status_msg("");\r
        reset_timing = 1;\r
 }\r
@@ -202,29 +196,30 @@ static void updateSound(int len)
 \r
 void pemu_sound_start(void)\r
 {\r
-       static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0;\r
        int target_fps = Pico.m.pal ? 50 : 60;\r
 \r
        PsndOut = NULL;\r
 \r
        if (currentConfig.EmuOpt & EOPT_EN_SOUND)\r
        {\r
-               int snd_excess_add;\r
-               if (PsndRate != PsndRate_old || (PicoOpt&0x20b) != (PicoOpt_old&0x20b) || Pico.m.pal != pal_old)\r
-                       PsndRerate(Pico.m.frame_count ? 1 : 0);\r
+               int snd_excess_add, frame_samples;\r
+               int is_stereo = (PicoOpt & POPT_EN_STEREO) ? 1 : 0;\r
+\r
+               PsndRerate(Pico.m.frame_count ? 1 : 0);\r
+\r
+               frame_samples = PsndLen;\r
+               snd_excess_add = ((PsndRate - PsndLen * target_fps)<<16) / target_fps;\r
+               if (snd_excess_add != 0)\r
+                       frame_samples++;\r
 \r
-               snd_excess_add = ((PsndRate - PsndLen*target_fps)<<16) / target_fps;\r
                printf("starting audio: %i len: %i (ex: %04x) stereo: %i, pal: %i\n",\r
-                       PsndRate, PsndLen, snd_excess_add, (PicoOpt&8)>>3, Pico.m.pal);\r
-               sndout_oss_start(PsndRate, 16, (PicoOpt&8)>>3);\r
+                       PsndRate, PsndLen, snd_excess_add, is_stereo, Pico.m.pal);\r
+               sndout_oss_start(PsndRate, frame_samples, is_stereo);\r
                sndout_oss_setvol(currentConfig.volume, currentConfig.volume);\r
                PicoWriteSound = updateSound;\r
                plat_update_volume(0, 0);\r
                memset(sndBuffer, 0, sizeof(sndBuffer));\r
                PsndOut = sndBuffer;\r
-               PsndRate_old = PsndRate;\r
-               PicoOpt_old  = PicoOpt;\r
-               pal_old = Pico.m.pal;\r
        }\r
 }\r
 \r
@@ -243,8 +238,6 @@ void plat_debug_cat(char *str)
 \r
 void emu_video_mode_change(int start_line, int line_count, int is_32cols)\r
 {\r
-       osd_fps_x = 260;\r
-\r
        // clear whole screen in all buffers\r
        memset32(g_screen_ptr, 0, g_screen_width * g_screen_height * 2 / 4);\r
 }\r
@@ -292,10 +285,6 @@ void plat_wait_till_us(unsigned int us_to)
        }\r
 }\r
 \r
-void plat_video_wait_vsync(void)\r
-{\r
-}\r
-\r
 const char *plat_get_credits(void)\r
 {\r
        return "PicoDrive v" VERSION " (c) notaz, 2006-2009\n\n\n"\r
diff --git a/linux/fbdev.c b/linux/fbdev.c
new file mode 100644 (file)
index 0000000..6ad1d4e
--- /dev/null
@@ -0,0 +1,162 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <linux/fb.h>
+#include <linux/matroxfb.h>
+
+#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 (file)
index 0000000..1e5d28b
--- /dev/null
@@ -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;
index b16cf08..63e3da8 100644 (file)
@@ -2,13 +2,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
-#include <pthread.h>
-#include <semaphore.h>
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
 
 #include "../common/emu.h"
 #include "../common/menu.h"
 
 #include "log_io.h"
 
-unsigned long current_keys = 0;
+int current_keys;
+unsigned char *PicoDraw2FB;
+
+#ifdef FBDEV
+
+#include "fbdev.h"
+
+#else
+
+#include <pthread.h>
+#include <semaphore.h>
+
 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();
 }
 
index 4d8e58b..f816c7d 100644 (file)
@@ -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));
index d5a2610..2c48860 100644 (file)
@@ -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);
index 4f132df..c70c835 100644 (file)
@@ -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 \\r
        platform/common/arm_utils.o platform/common/mp3_helix.o platform/common/arm_linux.o \\r
        platform/common/readpng.o platform/common/input.o platform/common/main.o \\r
-       platform/linux/in_evdev.o platform/linux/sndout_oss.o platform/linux/plat.o\r
+       platform/linux/fbdev.o platform/linux/in_evdev.o platform/linux/sndout_oss.o \\r
+       platform/linux/plat.o\r
 \r
 # ARM stuff\r
 OBJS += pico/carthw/svp/compiler.o pico/carthw/svp/stub_arm.o\r
index 4a628c7..f7c2a2e 100644 (file)
@@ -4,24 +4,25 @@
 // For commercial use, separate licencing terms must be obtained.\r
 \r
 #include <stdio.h>\r
+#include <unistd.h>\r
 \r
 #include "../common/emu.h"\r
 #include "../common/menu.h"\r
 #include "../common/plat.h"\r
 #include "../common/arm_utils.h"\r
 #include "../linux/sndout_oss.h"\r
+#include "../linux/fbdev.h"\r
 #include "asm_utils.h"\r
 #include "version.h"\r
 \r
 #include <pico/pico_int.h>\r
 \r
-#define USE_320_SCREEN 1\r
+//#define USE_320_SCREEN 1\r
 \r
 \r
 static short __attribute__((aligned(4))) sndBuffer[2*44100/50];\r
 static unsigned char temp_frame[g_screen_width * g_screen_height * 2];\r
 unsigned char *PicoDraw2FB = temp_frame;\r
-static int osd_fps_x;\r
 char cpu_clk_name[] = "unused";\r
 \r
 \r
@@ -29,6 +30,8 @@ void pemu_prep_defconfig(void)
 {\r
        // XXX: move elsewhere\r
        g_menubg_ptr = temp_frame;\r
+\r
+       defaultConfig.EmuOpt |= EOPT_VSYNC;\r
 }\r
 \r
 void pemu_validate_config(void)\r
@@ -141,15 +144,40 @@ static int EmuScanEnd16(unsigned int num)
        return 0;\r
 }\r
 \r
+static int EmuScanEnd16_32x(unsigned int num)\r
+{\r
+       unsigned int *ps;\r
+       unsigned int *pd;\r
+       int len;\r
+\r
+       ps = (unsigned int *)temp_frame;\r
+       pd = (unsigned int *)g_screen_ptr + (num*800*2 + 800/2 - 320*2/2) / 2;\r
+\r
+       for (len = 320/2; len > 0; len--, ps++) {\r
+               unsigned int p, p1;\r
+               p1 = *ps;\r
+               p = p1 << 16;\r
+               p |= p >> 16;\r
+               *pd = pd[800/2] = p;\r
+               pd++;\r
+\r
+               p = p1 >> 16;\r
+               p |= p << 16;\r
+               *pd = pd[800/2] = p;\r
+               pd++;\r
+       }\r
+\r
+       return 0;\r
+}\r
 #endif // USE_320_SCREEN\r
 \r
-void pemu_update_display(const char *fps, const char *notice)\r
+void pemu_finalize_frame(const char *fps, const char *notice)\r
 {\r
        if (notice || (currentConfig.EmuOpt & EOPT_SHOW_FPS)) {\r
                if (notice)\r
-                       osd_text(4, 460, notice);\r
+                       osd_text(4, 464, notice);\r
                if (currentConfig.EmuOpt & EOPT_SHOW_FPS)\r
-                       osd_text(osd_fps_x, 460, fps);\r
+                       osd_text(640, 464, fps);\r
        }\r
        if ((PicoAHW & PAHW_MCD) && (currentConfig.EmuOpt & EOPT_EN_CD_LEDS))\r
                draw_cd_leds();\r
@@ -172,19 +200,24 @@ void plat_video_menu_begin(void)
 \r
 void plat_video_menu_end(void)\r
 {\r
+       plat_video_flip();\r
 }\r
 \r
 void plat_status_msg_clear(void)\r
 {\r
-       unsigned short *d = (unsigned short *)g_screen_ptr + g_screen_width * g_screen_height;\r
-       int l = g_screen_width * 8;\r
-       memset32((int *)(d - l), 0, l * 2 / 4);\r
+       int s = g_screen_width * g_screen_height * 2;\r
+       int l = g_screen_width * 16 * 2;\r
+       int i;\r
+\r
+       for (i = 0; i < fbdev_buffer_count; i++)\r
+               memset32((int *)((char *)fbdev_buffers[i] + s - l), 0, l / 4);\r
 }\r
 \r
 void plat_status_msg_busy_next(const char *msg)\r
 {\r
        plat_status_msg_clear();\r
-       pemu_update_display("", msg);\r
+       pemu_finalize_frame("", msg);\r
+       plat_video_flip();\r
        emu_status_msg("");\r
        reset_timing = 1;\r
 }\r
@@ -224,13 +257,6 @@ void pemu_forced_frame(int opts)
        PicoOpt |= opts|POPT_ACC_SPRITES; // acc_sprites\r
        currentConfig.EmuOpt |= 0x80;\r
 \r
-#ifdef USE_320_SCREEN\r
-       PicoDrawSetColorFormat(1);\r
-       PicoScanBegin = EmuScanBegin16;\r
-#else\r
-       PicoDrawSetColorFormat(-1);\r
-       PicoScanEnd = EmuScanEnd16;\r
-#endif\r
        Pico.m.dirtyPal = 1;\r
        PicoFrameDrawOnly();\r
 \r
@@ -240,48 +266,59 @@ void pemu_forced_frame(int opts)
 \r
 static void updateSound(int len)\r
 {\r
+       unsigned int t;\r
+\r
        len <<= 1;\r
        if (PicoOpt & POPT_EN_STEREO)\r
                len <<= 1;\r
 \r
+       // sndout_oss_can_write() not reliable..\r
        if ((currentConfig.EmuOpt & EOPT_NO_FRMLIMIT) && !sndout_oss_can_write(len))\r
                return;\r
 \r
        /* avoid writing audio when lagging behind to prevent audio lag */\r
-       if (PicoSkipFrame != 2)\r
-               sndout_oss_write(PsndOut, len);\r
+       if (PicoSkipFrame == 2)\r
+               return;\r
+\r
+       t = plat_get_ticks_ms();\r
+       sndout_oss_write(PsndOut, len);\r
+       t = plat_get_ticks_ms() - t;\r
+       if (t > 1)\r
+               printf("audio lag %u\n", t);\r
 }\r
 \r
 void pemu_sound_start(void)\r
 {\r
-       static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0;\r
        int target_fps = Pico.m.pal ? 50 : 60;\r
 \r
        PsndOut = NULL;\r
 \r
-       if (currentConfig.EmuOpt & 4)\r
+       if (currentConfig.EmuOpt & EOPT_EN_SOUND)\r
        {\r
-               int snd_excess_add;\r
-               if (PsndRate != PsndRate_old || (PicoOpt&0x20b) != (PicoOpt_old&0x20b) || Pico.m.pal != pal_old)\r
-                       PsndRerate(Pico.m.frame_count ? 1 : 0);\r
+               int snd_excess_add, frame_samples;\r
+               int is_stereo = (PicoOpt & POPT_EN_STEREO) ? 1 : 0;\r
+\r
+               PsndRerate(Pico.m.frame_count ? 1 : 0);\r
+\r
+               frame_samples = PsndLen;\r
+               snd_excess_add = ((PsndRate - PsndLen * target_fps)<<16) / target_fps;\r
+               if (snd_excess_add != 0)\r
+                       frame_samples++;\r
 \r
-               snd_excess_add = ((PsndRate - PsndLen*target_fps)<<16) / target_fps;\r
                printf("starting audio: %i len: %i (ex: %04x) stereo: %i, pal: %i\n",\r
-                       PsndRate, PsndLen, snd_excess_add, (PicoOpt&8)>>3, Pico.m.pal);\r
-               sndout_oss_start(PsndRate, 16, (PicoOpt&8)>>3);\r
-               sndout_oss_setvol(currentConfig.volume, currentConfig.volume);\r
+                       PsndRate, PsndLen, snd_excess_add, is_stereo, Pico.m.pal);\r
+               sndout_oss_start(PsndRate, frame_samples * 2, is_stereo);\r
+               //sndout_oss_setvol(currentConfig.volume, currentConfig.volume);\r
                PicoWriteSound = updateSound;\r
                plat_update_volume(0, 0);\r
                memset(sndBuffer, 0, sizeof(sndBuffer));\r
                PsndOut = sndBuffer;\r
-               PsndRate_old = PsndRate;\r
-               PicoOpt_old  = PicoOpt;\r
-               pal_old = Pico.m.pal;\r
        }\r
 }\r
 \r
 void pemu_sound_stop(void)\r
 {\r
+       sndout_oss_stop();\r
 }\r
 \r
 void pemu_sound_wait(void)\r
@@ -295,22 +332,32 @@ void plat_debug_cat(char *str)
 \r
 void emu_video_mode_change(int start_line, int line_count, int is_32cols)\r
 {\r
-       osd_fps_x = 260;\r
+       int i;\r
 \r
        // clear whole screen in all buffers\r
-       memset32(g_screen_ptr, 0, g_screen_width * g_screen_height * 2 / 4);\r
-}\r
+       for (i = 0; i < fbdev_buffer_count; i++)\r
+               memset32(fbdev_buffers[i], 0, g_screen_width * g_screen_height * 2 / 4);\r
 \r
-void pemu_loop_prep(void)\r
-{\r
 #ifdef USE_320_SCREEN\r
        PicoDrawSetColorFormat(1);\r
        PicoScanBegin = EmuScanBegin16;\r
 #else\r
-       PicoDrawSetColorFormat(-1);\r
-       PicoScanEnd = EmuScanEnd16;\r
+       if (PicoAHW & PAHW_32X) {\r
+               DrawLineDest = (unsigned short *)temp_frame;\r
+               PicoDrawSetColorFormat(1);\r
+               PicoScanBegin = NULL;\r
+               PicoScanEnd = EmuScanEnd16_32x;\r
+       } else {\r
+               PicoDrawSetColorFormat(-1);\r
+               PicoScanBegin = NULL;\r
+               PicoScanEnd = EmuScanEnd16;\r
+       }\r
 #endif\r
+}\r
 \r
+void pemu_loop_prep(void)\r
+{\r
+       emu_video_mode_change(0, 0, 0);\r
        pemu_sound_start();\r
 }\r
 \r
@@ -335,23 +382,27 @@ void pemu_loop_end(void)
        currentConfig.EmuOpt = eo_old;\r
 }\r
 \r
-/* XXX: avoid busy wait somehow? */\r
 void plat_wait_till_us(unsigned int us_to)\r
 {\r
        unsigned int now;\r
+       signed int diff;\r
 \r
-       spend_cycles(1024);\r
        now = plat_get_ticks_us();\r
 \r
-       while ((signed int)(us_to - now) > 512)\r
-       {\r
+       // XXX: need to check NOHZ and djw kernel\r
+       diff = (signed int)(us_to - now);\r
+       if (diff > 10000) {\r
+               //printf("sleep %d\n", us_to - now);\r
+               usleep(diff * 15 / 16);\r
+               now = plat_get_ticks_us();\r
+               //printf(" wake %d\n", (signed)(us_to - now));\r
+       }\r
+/*\r
+       while ((signed int)(us_to - now) > 512) {\r
                spend_cycles(1024);\r
                now = plat_get_ticks_us();\r
        }\r
-}\r
-\r
-void plat_video_wait_vsync(void)\r
-{\r
+*/\r
 }\r
 \r
 const char *plat_get_credits(void)\r
index 92047c2..4019994 100644 (file)
@@ -1,62 +1,39 @@
 #include <stdio.h>\r
 #include <stdlib.h>\r
 #include <stdarg.h>\r
-#include <string.h>\r
-#include <unistd.h>\r
-#include <sys/mman.h>\r
-#include <sys/types.h>\r
-#include <sys/stat.h>\r
-#include <linux/fb.h>\r
-#include <fcntl.h>\r
-#include <errno.h>\r
 \r
 #include "../linux/sndout_oss.h"\r
-#include "../common/arm_linux.h"\r
+#include "../linux/fbdev.h"\r
 #include "../common/emu.h"\r
 \r
-static int fbdev = -1;\r
-\r
-#define SCREEN_MAP_SIZE (800*480*2)\r
-static void *screen = MAP_FAILED;\r
-\r
 void plat_early_init(void)\r
 {\r
 }\r
 \r
 void plat_init(void)\r
 {\r
-       printf("entering init()\n"); fflush(stdout);\r
+       int ret, w, h;\r
 \r
-       fbdev = open("/dev/fb0", O_RDWR);\r
-       if (fbdev == -1)\r
-       {\r
-               perror("open(\"/dev/fb0\")");\r
+       ret = vout_fbdev_init(&w, &h);\r
+       if (ret != 0) {\r
+               fprintf(stderr, "couldn't init framebuffer\n");\r
                exit(1);\r
        }\r
 \r
-       screen = mmap(0, SCREEN_MAP_SIZE, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev, 0);\r
-       if (screen == MAP_FAILED)\r
-       {\r
-               perror("mmap(fbptr)");\r
+       if (w != g_screen_width || h != g_screen_height) {\r
+               fprintf(stderr, "%dx%d not supported\n", w, h);\r
+               vout_fbdev_finish();\r
                exit(1);\r
        }\r
-       printf("fbptr %p\n", screen);\r
-       g_screen_ptr = screen;\r
 \r
        // snd\r
        sndout_oss_init();\r
-\r
-       printf("exitting init()\n"); fflush(stdout);\r
 }\r
 \r
 void plat_finish(void)\r
 {\r
-       if (screen != MAP_FAILED)\r
-               munmap(screen, SCREEN_MAP_SIZE);\r
-       if (fbdev >= 0)\r
-               close(fbdev);\r
-\r
        sndout_oss_exit();\r
+       vout_fbdev_finish();\r
 \r
        printf("all done");\r
 }\r
index 506c52a..0c071bd 100644 (file)
@@ -6,7 +6,6 @@
 #define CASE_SENSITIVE_FS 1 // CS filesystem\r
 #define DONT_OPEN_MANY_FILES 0\r
 #define REDUCE_IO_CALLS 0\r
-#define SIMPLE_WRITE_SOUND 0\r
 \r
 #define SCREEN_SIZE_FIXED 1\r
 #define SCREEN_WIDTH  800\r
@@ -22,6 +21,8 @@
 // pico.c\r
 #define CAN_HANDLE_240_LINES   1\r
 \r
+#define SIMPLE_WRITE_SOUND     0\r
+\r
 // logging emu events\r
 #define EL_LOGMASK (EL_STATUS|EL_IDLE) // (EL_STATUS|EL_ANOMALY|EL_UIO|EL_SRAMIO|EL_INTS|EL_CDPOLL) // xffff\r
 \r
index 2770b94..e5e2f7e 100644 (file)
@@ -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();