Merge git://github.com/notaz/pcsx_rearmed
authortwinaphex <autechre1024@hotmail.com>
Wed, 28 Nov 2012 05:35:30 +0000 (06:35 +0100)
committertwinaphex <autechre1024@hotmail.com>
Wed, 28 Nov 2012 05:35:30 +0000 (06:35 +0100)
100 files changed:
.gitignore
.gitmodules
Makefile
configure
frontend/320240/ui_gp2x.h [new file with mode: 0644]
frontend/common/fonts.c [deleted file]
frontend/common/fonts.h [deleted file]
frontend/common/in_sdl.c [deleted file]
frontend/common/in_sdl.h [deleted file]
frontend/common/input.c [deleted file]
frontend/common/input.h [deleted file]
frontend/common/lprintf.h [deleted file]
frontend/common/menu.c [deleted file]
frontend/common/menu.h [deleted file]
frontend/common/plat.h [deleted file]
frontend/common/posix.h [deleted file]
frontend/common/readpng.c [deleted file]
frontend/common/readpng.h [deleted file]
frontend/gp2x/in_gp2x.c [deleted file]
frontend/gp2x/in_gp2x.h [deleted file]
frontend/in_tsbutton.c
frontend/libpicofe [new submodule]
frontend/libretro.c
frontend/linux/fbdev.c [deleted file]
frontend/linux/fbdev.h [deleted file]
frontend/linux/in_evdev.c [deleted file]
frontend/linux/in_evdev.h [deleted file]
frontend/linux/plat.c [deleted file]
frontend/linux/plat_mmap.c [new file with mode: 0644]
frontend/linux/plat_mmap.h [new file with mode: 0644]
frontend/linux/xenv.c [deleted file]
frontend/linux/xenv.h [deleted file]
frontend/main.c
frontend/main.h
frontend/menu.c
frontend/menu.h
frontend/pandora/pcsx.sh
frontend/pandora/ui_feat.h [new file with mode: 0644]
frontend/pcnt.h
frontend/pl_gun_ts.c
frontend/plat.h
frontend/plat_dummy.c
frontend/plat_omap.c
frontend/plat_pandora.c
frontend/plat_pollux.c
frontend/plat_sdl.c
frontend/plugin_lib.c
frontend/plugin_lib.h
frontend/xkb.c [deleted file]
libpcsxcore/cdriso.c
libpcsxcore/cdrom.c
libpcsxcore/cdrom.h
libpcsxcore/coff.h
libpcsxcore/gte.c
libpcsxcore/mdec.c
libpcsxcore/misc.c
libpcsxcore/new_dynarec/emu_if.c
libpcsxcore/psxcounters.c
libpcsxcore/psxmem.c
libpcsxcore/r3000a.h
maemo/hildon.c
maemo/main.c
plugins/cdrcimg/cdrcimg.c
plugins/dfinput/externals.h [new file with mode: 0644]
plugins/dfinput/guncon.c
plugins/dfinput/main.h
plugins/dfsound/adsr.c
plugins/dfsound/alsa.c
plugins/dfsound/externals.h
plugins/dfsound/freeze.c
plugins/dfsound/psemuxa.h
plugins/dfsound/stdafx.h
plugins/dfxvideo/Makefile
plugins/dfxvideo/draw_pl.c
plugins/dfxvideo/gpu.c
plugins/dfxvideo/gpulib_if.c
plugins/gpu-gles/gpulib_if.c
plugins/gpu_neon/Makefile
plugins/gpu_neon/psx_gpu/common.h
plugins/gpu_neon/psx_gpu/psx_gpu.c
plugins/gpu_neon/psx_gpu/psx_gpu.h
plugins/gpu_neon/psx_gpu/psx_gpu_4x.c [new file with mode: 0644]
plugins/gpu_neon/psx_gpu/psx_gpu_arm_neon.S
plugins/gpu_neon/psx_gpu/psx_gpu_offsets.h [new file with mode: 0644]
plugins/gpu_neon/psx_gpu/psx_gpu_offsets_update.c [new file with mode: 0644]
plugins/gpu_neon/psx_gpu/psx_gpu_parse.c
plugins/gpu_neon/psx_gpu/tests/Makefile
plugins/gpu_neon/psx_gpu/vector_ops.h
plugins/gpu_neon/psx_gpu_if.c
plugins/gpu_unai/gpu.cpp
plugins/gpu_unai/gpulib_if.cpp
plugins/gpulib/cspace.c
plugins/gpulib/cspace.h
plugins/gpulib/gpu.c
plugins/gpulib/gpu.h
plugins/gpulib/gpulib.mak
plugins/gpulib/vout_pl.c
plugins/spunull/Makefile
plugins/spunull/xa.h
readme.txt

index b59cf68..e6fc06b 100644 (file)
@@ -1,13 +1,12 @@
 *.o
-frontend/revision.h
-frontend/linux
-frontend/common
-frontend/X11
-frontend/gp2x
+*.a
+*.so
 tags
 cscope.out
 pandora
 pcsx.map
+config.mak
+config.log
+frontend/revision.h
 tools
-gpu_dumps*
 .pcsx/
index 650250d..f93599e 100644 (file)
@@ -1,3 +1,6 @@
-[submodule "frontend/warm"]
+[submodule "libpicofe"]
+       path = frontend/libpicofe
+       url = git://notaz.gp2x.de/~notaz/libpicofe.git
+[submodule "warm"]
        path = frontend/warm
        url = git://notaz.gp2x.de/~notaz/warm.git
index c10f739..548d8a0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -26,7 +26,11 @@ endif
 -include Makefile.local
 
 CC_LINK = $(CC)
+LDFLAGS += $(MAIN_LDFLAGS)
 LDLIBS += $(MAIN_LDLIBS)
+ifdef PCNT
+CFLAGS += -DPCNT
+endif
 
 # core
 OBJS += libpcsxcore/cdriso.o libpcsxcore/cdrom.o libpcsxcore/cheat.o libpcsxcore/debug.o \
@@ -42,14 +46,14 @@ endif
 ifeq "$(HAVE_NEON)" "1"
 OBJS += libpcsxcore/gte_neon.o
 endif
-libpcsxcore/gte.o libpcsxcore/gte_nf.o: CFLAGS += -fno-strict-aliasing
-libpcsxcore/cdrom.o libpcsxcore/misc.o: CFLAGS += -Wno-pointer-sign
-libpcsxcore/misc.o libpcsxcore/psxbios.o: CFLAGS += -Wno-nonnull
+libpcsxcore/psxbios.o: CFLAGS += -Wno-nonnull
 
 # dynarec
 ifeq "$(USE_DYNAREC)" "1"
 OBJS += libpcsxcore/new_dynarec/new_dynarec.o libpcsxcore/new_dynarec/linkage_arm.o
 OBJS += libpcsxcore/new_dynarec/pcsxmem.o
+else
+libpcsxcore/new_dynarec/emu_if.o: CFLAGS += -DDRC_DISABLE
 endif
 OBJS += libpcsxcore/new_dynarec/emu_if.o
 libpcsxcore/new_dynarec/new_dynarec.o: libpcsxcore/new_dynarec/assem_arm.c \
@@ -95,10 +99,9 @@ endif
 
 # builtin gpu
 OBJS += plugins/gpulib/gpu.o plugins/gpulib/vout_pl.o
+OBJS += plugins/gpulib/cspace.o
 ifeq "$(HAVE_NEON)" "1"
 OBJS += plugins/gpulib/cspace_neon.o
-else
-OBJS += plugins/gpulib/cspace.o
 endif
 ifeq "$(BUILTIN_GPU)" "neon"
 OBJS += plugins/gpu_neon/psx_gpu_if.o plugins/gpu_neon/psx_gpu/psx_gpu_arm_neon.o
@@ -127,39 +130,58 @@ OBJS += plugins/cdrcimg/cdrcimg.o
 # dfinput
 OBJS += plugins/dfinput/main.o plugins/dfinput/pad.o plugins/dfinput/guncon.o
 
-# gui
-OBJS += frontend/main.o frontend/plugin.o
-OBJS += frontend/common/readpng.o frontend/common/fonts.o
-OBJS += frontend/linux/plat.o
-
+# frontend/gui
 ifeq "$(PLATFORM)" "generic"
-OBJS += frontend/plat_sdl.o frontend/common/in_sdl.o
+OBJS += frontend/libpicofe/in_sdl.o frontend/plat_sdl.o
+OBJS += frontend/libpicofe/plat_dummy.o
+OBJS += frontend/libpicofe/linux/in_evdev.o
+USE_PLUGIN_LIB = 1
 USE_FRONTEND = 1
 endif
 ifeq "$(PLATFORM)" "pandora"
-OBJS += frontend/linux/fbdev.o
-OBJS += frontend/plat_omap.o frontend/linux/xenv.o
-OBJS += frontend/plat_pandora.o
+OBJS += frontend/libpicofe/pandora/plat.o
+OBJS += frontend/libpicofe/linux/fbdev.o frontend/libpicofe/linux/xenv.o
+OBJS += frontend/libpicofe/linux/in_evdev.o
+OBJS += frontend/plat_pandora.o frontend/plat_omap.o
+frontend/main.o frontend/menu.o: CFLAGS += -include pandora/ui_feat.h
+USE_PLUGIN_LIB = 1
 USE_FRONTEND = 1
 endif
 ifeq "$(PLATFORM)" "caanoo"
+OBJS += frontend/libpicofe/gp2x/in_gp2x.o frontend/warm/warm.o
+OBJS += frontend/libpicofe/gp2x/soc_pollux.o
+OBJS += frontend/libpicofe/linux/in_evdev.o
 OBJS += frontend/plat_pollux.o frontend/in_tsbutton.o frontend/blit320.o
-OBJS += frontend/gp2x/in_gp2x.o frontend/warm/warm.o
 libpcsxcore/new_dynarec/pcsxmem.o: CFLAGS += -DCUSTOM_MEMMAPS
+frontend/main.o frontend/menu.o: CFLAGS += -include 320240/ui_gp2x.h
+USE_PLUGIN_LIB = 1
 USE_FRONTEND = 1
 endif
 ifeq "$(PLATFORM)" "maemo"
 OBJS += maemo/hildon.o maemo/main.o
 maemo/%.o: maemo/%.c
-OBJS += frontend/plugin_lib.o
+USE_PLUGIN_LIB = 1
 endif
 ifeq "$(PLATFORM)" "libretro"
 OBJS += frontend/libretro.o
+OBJS += frontend/linux/plat_mmap.o
 endif
-ifeq "$(USE_FRONTEND)" "1"
-OBJS += frontend/menu.o frontend/linux/in_evdev.o
-OBJS += frontend/common/input.o
+
+ifeq "$(USE_PLUGIN_LIB)" "1"
 OBJS += frontend/plugin_lib.o
+OBJS += frontend/libpicofe/linux/plat.o
+OBJS += frontend/libpicofe/readpng.o frontend/libpicofe/fonts.o
+ifeq "$(HAVE_NEON)" "1"
+OBJS += frontend/libpicofe/arm/neon_scale2x.o
+OBJS += frontend/libpicofe/arm/neon_eagle2x.o
+frontend/libpicofe/arm/neon_scale2x.o: CFLAGS += -DDO_BGR_TO_RGB
+frontend/libpicofe/arm/neon_eagle2x.o: CFLAGS += -DDO_BGR_TO_RGB
+endif
+endif
+ifeq "$(USE_FRONTEND)" "1"
+OBJS += frontend/menu.o
+OBJS += frontend/libpicofe/input.o
+frontend/menu.o: frontend/libpicofe/menu.c
 ifeq "$(HAVE_TSLIB)" "1"
 frontend/%.o: CFLAGS += -DHAVE_TSLIB
 OBJS += frontend/pl_gun_ts.o
@@ -168,16 +190,17 @@ else
 CFLAGS += -DNO_FRONTEND
 endif
 
-ifdef X11
-frontend/%.o: CFLAGS += -DX11
-OBJS += frontend/xkb.o
-endif
-ifdef PCNT
-CFLAGS += -DPCNT
-endif
-frontend/%.o: CFLAGS += -DIN_EVDEV
+# misc
+OBJS += frontend/main.o frontend/plugin.o
+
+
 frontend/menu.o frontend/main.o frontend/plat_sdl.o: frontend/revision.h
 
+frontend/libpicofe/%.c:
+       @echo "libpicofe module is missing, please run:"
+       @echo "git submodule init && git submodule update"
+       @exit 1
+
 libpcsxcore/gte_nf.o: libpcsxcore/gte.c
        $(CC) -c -o $@ $^ $(CFLAGS) -DFLAGLESS
 
@@ -185,11 +208,11 @@ frontend/revision.h: FORCE
        @(git describe || echo) | sed -e 's/.*/#define REV "\0"/' > $@_
        @diff -q $@_ $@ > /dev/null 2>&1 || cp $@_ $@
        @rm $@_
-.PHONY: FORCE
 
 %.o: %.S
        $(CC) $(CFLAGS) -c $^ -o $@
 
+
 target_: $(TARGET)
 
 $(TARGET): $(OBJS)
@@ -213,9 +236,11 @@ plugins_:
 clean_plugins:
 endif
 
+.PHONY: all clean target_ plugins_ clean_plugins FORCE
+
 # ----------- release -----------
 
-VER ?= $(shell git describe master)
+VER ?= $(shell git describe HEAD)
 
 ifeq "$(PLATFORM)" "generic"
 OUT = pcsx_rearmed_$(VER)
index da126e7..4cff898 100755 (executable)
--- a/configure
+++ b/configure
@@ -48,6 +48,8 @@ have_arm_neon=""
 have_tslib=""
 enable_dynarec="yes"
 need_sdl="no"
+need_libpicofe="yes"
+need_warm="no"
 # these are for known platforms
 optimize_cortexa8="no"
 optimize_arm926ej="no"
@@ -91,9 +93,11 @@ set_platform()
     ram_fixed="yes"
     drc_cache_base="yes"
     optimize_arm926ej="yes"
+    need_warm="yes"
     ;;
   libretro)
     sound_drivers="libretro"
+    need_libpicofe="no"
     ;;
   *)
     fail "unsupported platform: $platform"
@@ -156,6 +160,18 @@ if [ "x$sound_drivers" != "x" ]; then
   done
 fi
 
+if [ "$need_libpicofe" = "yes" ]; then
+  if ! test -f "frontend/libpicofe/README"; then
+    fail "libpicofe is missing, please run 'git submodule init && git submodule update'"
+  fi
+fi
+
+if [ "$need_warm" = "yes" ]; then
+  if ! test -f "frontend/warm/README"; then
+    fail "wARM is missing, please run 'git submodule init && git submodule update'"
+  fi
+fi
+
 if [ -z "$ARCH" ]; then
   ARCH=`$CC -v 2>&1 | grep -i 'target:' | awk '{print $2}' \
         | awk -F '-' '{print $1}'`
@@ -230,13 +246,6 @@ if [ "x$builtin_gpu" = "x" ]; then
   builtin_gpu="peops"
 fi
 
-#if [ "$ARCH" = "x86_64" ]; then
-  # currently we are full of 32bit assumptions,
-  # at least savestate compatibility will break without these
-#  CFLAGS="$CFLAGS -m32"
-#  LDFLAGS="$LDFLAGS -m32"
-#fi
-
 # supposedly we can avoid -fPIC on armv5 for slightly better performace?
 if [ "$ARCH" != "arm" -o "$have_armv6" = "yes" ]; then
   PLUGIN_CFLAGS="$PLUGIN_CFLAGS -fPIC"
@@ -258,7 +267,7 @@ maemo)
   ;;
 libretro)
   CFLAGS="$CFLAGS -fPIC"
-  LDFLAGS="$LDFLAGS -shared"
+  MAIN_LDFLAGS="$MAIN_LDFLAGS -shared -Wl,--no-undefined"
   ;;
 esac
 
@@ -272,15 +281,6 @@ EOF
   compile_binary
 }
 
-check_bzlib()
-{
-  cat > $TMPC <<EOF
-  #include <bzlib.h>
-  void main() { BZ2_bzBuffToBuffDecompress(0, 0, 0, 0, 0, 0); }
-EOF
-  compile_object
-}
-
 check_libpng()
 {
   cat > $TMPC <<EOF
@@ -321,8 +321,6 @@ EOF
 MAIN_LDLIBS="$MAIN_LDLIBS -lz"
 check_zlib || fail "please install zlib (libz-dev)"
 
-check_bzlib || fail "please install bz2lib (libbz2-dev)"
-
 MAIN_LDLIBS="-lpng $MAIN_LDLIBS"
 check_libpng || fail "please install libpng (libpng-dev)"
 
@@ -411,7 +409,7 @@ echo "plugins             $plugins_short"
 echo "C compiler          $CC"
 echo "C compiler flags    $CFLAGS"
 echo "libraries           $MAIN_LDLIBS"
-echo "linker flags        $LDFLAGS"
+echo "linker flags        $LDFLAGS$MAIN_LDFLAGS"
 echo "enable dynarec      $enable_dynarec"
 echo "ARMv7 optimizations $have_armv7"
 echo "enable ARM NEON     $have_arm_neon"
@@ -428,6 +426,7 @@ echo "AS = $AS" >> $config_mak
 echo "CFLAGS += $CFLAGS" >> $config_mak
 echo "ASFLAGS += $ASFLAGS" >> $config_mak
 echo "LDFLAGS += $LDFLAGS" >> $config_mak
+echo "MAIN_LDFLAGS += $MAIN_LDFLAGS" >> $config_mak
 echo "MAIN_LDLIBS += $MAIN_LDLIBS" >> $config_mak
 echo "PLUGIN_CFLAGS += $PLUGIN_CFLAGS" >> $config_mak
 echo >> $config_mak
@@ -439,15 +438,7 @@ echo "ARCH = $ARCH" >> $config_mak
 echo "PLATFORM = $platform" >> $config_mak
 echo "BUILTIN_GPU = $builtin_gpu" >> $config_mak
 echo "SOUND_DRIVERS = $sound_drivers" >> $config_mak
-if [ "$ARCH" = "arm" ]; then
-  echo "PLUGINS = $plugins" >> $config_mak
-else
-  echo -n "PLUGINS =" >> $config_mak
-  for p in $plugins; do
-    echo -n " ${p}.${ARCH}" >> $config_mak
-  done
-  echo >> $config_mak
-fi
+echo "PLUGINS = $plugins" >> $config_mak
 if [ "$have_armv6" = "yes" ]; then
   echo "HAVE_ARMV6 = 1" >> $config_mak
 fi
diff --git a/frontend/320240/ui_gp2x.h b/frontend/320240/ui_gp2x.h
new file mode 100644 (file)
index 0000000..0fef431
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef UI_FEATURES_H
+#define UI_FEATURES_H
+
+#define MENU_BIOS_PATH "pcsx_rearmed/bios/"
+#define MENU_SHOW_VARSCALER 0
+#define MENU_SHOW_VIDOVERLAY 0
+#define MENU_SHOW_SCALER2 1
+#define MENU_SHOW_NUBS_BTNS 0
+#define MENU_SHOW_VIBRATION 1
+#define MENU_SHOW_DEADZONE 1
+#define MENU_SHOW_MINIMIZE 0
+#define MENU_SHOW_FULLSCREEN 0
+#define MENU_SHOW_VOLUME 1
+
+#endif // UI_FEATURES_H
diff --git a/frontend/common/fonts.c b/frontend/common/fonts.c
deleted file mode 100644 (file)
index ea65481..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-unsigned char fontdata8x8[64*16] =
-{
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-       0x3C,0x42,0x99,0xBD,0xBD,0x99,0x42,0x3C,0x3C,0x42,0x81,0x81,0x81,0x81,0x42,0x3C,
-       0xFE,0x82,0x8A,0xD2,0xA2,0x82,0xFE,0x00,0xFE,0x82,0x82,0x82,0x82,0x82,0xFE,0x00,
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00,
-       0x80,0xC0,0xF0,0xFC,0xF0,0xC0,0x80,0x00,0x01,0x03,0x0F,0x3F,0x0F,0x03,0x01,0x00,
-       0x18,0x3C,0x7E,0x18,0x7E,0x3C,0x18,0x00,0xEE,0xEE,0xEE,0xCC,0x00,0xCC,0xCC,0x00,
-       0x00,0x00,0x30,0x68,0x78,0x30,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00,
-       0x3C,0x66,0x7A,0x7A,0x7E,0x7E,0x3C,0x00,0x0E,0x3E,0x3A,0x22,0x26,0x6E,0xE4,0x40,
-       0x18,0x3C,0x7E,0x3C,0x3C,0x3C,0x3C,0x00,0x3C,0x3C,0x3C,0x3C,0x7E,0x3C,0x18,0x00,
-       0x08,0x7C,0x7E,0x7E,0x7C,0x08,0x00,0x00,0x10,0x3E,0x7E,0x7E,0x3E,0x10,0x00,0x00,
-       0x58,0x2A,0xDC,0xC8,0xDC,0x2A,0x58,0x00,0x24,0x66,0xFF,0xFF,0x66,0x24,0x00,0x00,
-       0x00,0x10,0x10,0x38,0x38,0x7C,0xFE,0x00,0xFE,0x7C,0x38,0x38,0x10,0x10,0x00,0x00,
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x1C,0x18,0x00,0x18,0x18,0x00,
-       0x6C,0x6C,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7C,0x28,0x7C,0x28,0x00,0x00,
-       0x10,0x38,0x60,0x38,0x0C,0x78,0x10,0x00,0x40,0xA4,0x48,0x10,0x24,0x4A,0x04,0x00,
-       0x18,0x34,0x18,0x3A,0x6C,0x66,0x3A,0x00,0x18,0x18,0x20,0x00,0x00,0x00,0x00,0x00,
-       0x30,0x60,0x60,0x60,0x60,0x60,0x30,0x00,0x0C,0x06,0x06,0x06,0x06,0x06,0x0C,0x00,
-       0x10,0x54,0x38,0x7C,0x38,0x54,0x10,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,
-       0x00,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,
-       0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x04,0x08,0x10,0x20,0x40,0x00,0x00,
-       0x38,0x4C,0xC6,0xC6,0xC6,0x64,0x38,0x00,0x18,0x38,0x18,0x18,0x18,0x18,0x7E,0x00,
-       0x7C,0xC6,0x0E,0x3C,0x78,0xE0,0xFE,0x00,0x7E,0x0C,0x18,0x3C,0x06,0xC6,0x7C,0x00,
-       0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x00,0xFC,0xC0,0xFC,0x06,0x06,0xC6,0x7C,0x00,
-       0x3C,0x60,0xC0,0xFC,0xC6,0xC6,0x7C,0x00,0xFE,0xC6,0x0C,0x18,0x30,0x30,0x30,0x00,
-       0x78,0xC4,0xE4,0x78,0x86,0x86,0x7C,0x00,0x7C,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00,
-       0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x30,
-       0x1C,0x38,0x70,0xE0,0x70,0x38,0x1C,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00,
-       0x70,0x38,0x1C,0x0E,0x1C,0x38,0x70,0x00,0x7C,0xC6,0xC6,0x1C,0x18,0x00,0x18,0x00,
-       0x3C,0x42,0x99,0xA1,0xA5,0x99,0x42,0x3C,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x00,
-       0xFC,0xC6,0xC6,0xFC,0xC6,0xC6,0xFC,0x00,0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00,
-       0xF8,0xCC,0xC6,0xC6,0xC6,0xCC,0xF8,0x00,0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xFE,0x00,
-       0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xC0,0x00,0x3E,0x60,0xC0,0xCE,0xC6,0x66,0x3E,0x00,
-       0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x7E,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,
-       0x06,0x06,0x06,0x06,0xC6,0xC6,0x7C,0x00,0xC6,0xCC,0xD8,0xF0,0xF8,0xDC,0xCE,0x00,
-       0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0x00,
-       0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,
-       0xFC,0xC6,0xC6,0xC6,0xFC,0xC0,0xC0,0x00,0x7C,0xC6,0xC6,0xC6,0xDE,0xCC,0x7A,0x00,
-       0xFC,0xC6,0xC6,0xCE,0xF8,0xDC,0xCE,0x00,0x78,0xCC,0xC0,0x7C,0x06,0xC6,0x7C,0x00,
-       0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,
-       0xC6,0xC6,0xC6,0xEE,0x7C,0x38,0x10,0x00,0xC6,0xC6,0xD6,0xFE,0xFE,0xEE,0xC6,0x00,
-       0xC6,0xEE,0x3C,0x38,0x7C,0xEE,0xC6,0x00,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00,
-       0xFE,0x0E,0x1C,0x38,0x70,0xE0,0xFE,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,
-       0x60,0x60,0x30,0x18,0x0C,0x06,0x06,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,
-       0x18,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
-       0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x06,0x3E,0x66,0x66,0x3C,0x00,
-       0x60,0x7C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x00,
-       0x06,0x3E,0x66,0x66,0x66,0x66,0x3E,0x00,0x00,0x3C,0x66,0x66,0x7E,0x60,0x3C,0x00,
-       0x1C,0x30,0x78,0x30,0x30,0x30,0x30,0x00,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x3C,
-       0x60,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x00,
-       0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x38,0x60,0x60,0x66,0x6C,0x78,0x6C,0x66,0x00,
-       0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0xEC,0xFE,0xFE,0xFE,0xD6,0xC6,0x00,
-       0x00,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x00,
-       0x00,0x7C,0x66,0x66,0x66,0x7C,0x60,0x60,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x06,
-       0x00,0x7E,0x70,0x60,0x60,0x60,0x60,0x00,0x00,0x3C,0x60,0x3C,0x06,0x66,0x3C,0x00,
-       0x30,0x78,0x30,0x30,0x30,0x30,0x1C,0x00,0x00,0x66,0x66,0x66,0x66,0x6E,0x3E,0x00,
-       0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0xC6,0xD6,0xFE,0xFE,0x7C,0x6C,0x00,
-       0x00,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00,0x00,0x66,0x66,0x66,0x66,0x3E,0x06,0x3C,
-       0x00,0x7E,0x0C,0x18,0x30,0x60,0x7E,0x00,0x0E,0x18,0x0C,0x38,0x0C,0x18,0x0E,0x00,
-       0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0x70,0x18,0x30,0x1C,0x30,0x18,0x70,0x00,
-       0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x10,0x28,0x10,0x54,0xAA,0x44,0x00,0x00,
-};
-
-
-/* The font is generated from Xorg clR5x8.bdf */
-/*
-COMMENT  Copyright 1989 Dale Schumacher, dal@syntel.mn.org
-COMMENT                 399 Beacon Ave.
-COMMENT                 St. Paul, MN  55104-3527
-COMMENT
-COMMENT  Permission to use, copy, modify, and distribute this software and
-COMMENT  its documentation for any purpose and without fee is hereby
-COMMENT  granted, provided that the above copyright notice appear in all
-COMMENT  copies and that both that copyright notice and this permission
-COMMENT  notice appear in supporting documentation, and that the name of
-COMMENT  Dale Schumacher not be used in advertising or publicity pertaining to
-COMMENT  distribution of the software without specific, written prior
-COMMENT  permission.  Dale Schumacher makes no representations about the
-COMMENT  suitability of this software for any purpose.  It is provided "as
-COMMENT  is" without express or implied warranty.
-COMMENT
-*/
-unsigned char fontdata6x8[256][8] = {
-{ 0x7c>>2, 0x44>>2, 0x7c>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0xff>>2, 0x7c>>2, },
-{ 0x00>>2, 0x00>>2, 0x10>>2, 0x28>>2, 0x44>>2, 0x7c>>2, 0x44>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x78>>2, 0x44>>2, 0x78>>2, 0x44>>2, 0x78>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x38>>2, 0x44>>2, 0x40>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x40>>2, 0x78>>2, 0x40>>2, 0x7c>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x40>>2, 0x78>>2, 0x40>>2, 0x40>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x40>>2, 0x4c>>2, 0x44>>2, 0x3c>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x44>>2, 0x44>>2, 0x7c>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x38>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x38>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x1c>>2, 0x04>>2, 0x04>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x48>>2, 0x50>>2, 0x60>>2, 0x50>>2, 0x48>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x7c>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x44>>2, 0x6c>>2, 0x54>>2, 0x54>>2, 0x44>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x44>>2, 0x64>>2, 0x54>>2, 0x4c>>2, 0x44>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x38>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x78>>2, 0x44>>2, 0x78>>2, 0x40>>2, 0x40>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x38>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x0c>>2, },
-{ 0x00>>2, 0x00>>2, 0x78>>2, 0x44>>2, 0x78>>2, 0x50>>2, 0x4c>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x40>>2, 0x38>>2, 0x04>>2, 0x78>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x44>>2, 0x44>>2, 0x28>>2, 0x28>>2, 0x10>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x44>>2, 0x54>>2, 0x54>>2, 0x6c>>2, 0x44>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x44>>2, 0x28>>2, 0x10>>2, 0x28>>2, 0x44>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x44>>2, 0x28>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x08>>2, 0x10>>2, 0x20>>2, 0x7c>>2, 0x00>>2, },
-{ 0xe0>>2, 0x80>>2, 0xe0>>2, 0x8c>>2, 0xf0>>2, 0x10>>2, 0x10>>2, 0x0c>>2, },
-{ 0x00>>2, 0x10>>2, 0x38>>2, 0x7c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
-{ 0x00>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x7c>>2, 0x38>>2, 0x10>>2, 0x00>>2, },
-{ 0x00>>2, 0x10>>2, 0x18>>2, 0xfc>>2, 0x18>>2, 0x10>>2, 0x00>>2, 0x00>>2, },
-{ 0x00>>2, 0x20>>2, 0x60>>2, 0xfc>>2, 0x60>>2, 0x20>>2, 0x00>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
-{ 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, 0x10>>2, 0x00>>2, },
-{ 0x28>>2, 0x28>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
-{ 0x00>>2, 0x28>>2, 0x7c>>2, 0x28>>2, 0x7c>>2, 0x28>>2, 0x00>>2, 0x00>>2, },
-{ 0x10>>2, 0x3c>>2, 0x50>>2, 0x38>>2, 0x14>>2, 0x78>>2, 0x10>>2, 0x00>>2, },
-{ 0x60>>2, 0x64>>2, 0x08>>2, 0x10>>2, 0x20>>2, 0x4c>>2, 0x0c>>2, 0x00>>2, },
-{ 0x38>>2, 0x40>>2, 0x40>>2, 0x20>>2, 0x54>>2, 0x48>>2, 0x34>>2, 0x00>>2, },
-{ 0x10>>2, 0x20>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
-{ 0x04>>2, 0x08>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x08>>2, 0x04>>2, 0x00>>2, },
-{ 0x40>>2, 0x20>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x20>>2, 0x40>>2, 0x00>>2, },
-{ 0x00>>2, 0x10>>2, 0x54>>2, 0x38>>2, 0x54>>2, 0x10>>2, 0x00>>2, 0x00>>2, },
-{ 0x00>>2, 0x10>>2, 0x10>>2, 0x7c>>2, 0x10>>2, 0x10>>2, 0x00>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x10>>2, 0x10>>2, 0x20>>2, },
-{ 0x00>>2, 0x00>>2, 0x00>>2, 0x7c>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
-{ 0x04>>2, 0x04>>2, 0x08>>2, 0x08>>2, 0x10>>2, 0x10>>2, 0x20>>2, 0x20>>2, },
-{ 0x38>>2, 0x44>>2, 0x4c>>2, 0x54>>2, 0x64>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
-{ 0x10>>2, 0x30>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
-{ 0x38>>2, 0x44>>2, 0x04>>2, 0x08>>2, 0x10>>2, 0x20>>2, 0x7c>>2, 0x00>>2, },
-{ 0x38>>2, 0x44>>2, 0x04>>2, 0x18>>2, 0x04>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
-{ 0x18>>2, 0x18>>2, 0x28>>2, 0x28>>2, 0x7c>>2, 0x08>>2, 0x1c>>2, 0x00>>2, },
-{ 0x7c>>2, 0x40>>2, 0x78>>2, 0x04>>2, 0x04>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
-{ 0x18>>2, 0x20>>2, 0x40>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
-{ 0x7c>>2, 0x44>>2, 0x04>>2, 0x08>>2, 0x08>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
-{ 0x38>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
-{ 0x38>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x04>>2, 0x08>>2, 0x30>>2, 0x00>>2, },
-{ 0x00>>2, 0x10>>2, 0x10>>2, 0x00>>2, 0x00>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
-{ 0x00>>2, 0x10>>2, 0x10>>2, 0x00>>2, 0x00>>2, 0x10>>2, 0x10>>2, 0x20>>2, },
-{ 0x00>>2, 0x0c>>2, 0x30>>2, 0xc0>>2, 0x30>>2, 0x0c>>2, 0x00>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x00>>2, 0x7c>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
-{ 0x00>>2, 0xc0>>2, 0x30>>2, 0x0c>>2, 0x30>>2, 0xc0>>2, 0x00>>2, 0x00>>2, },
-{ 0x38>>2, 0x44>>2, 0x04>>2, 0x08>>2, 0x10>>2, 0x00>>2, 0x10>>2, 0x00>>2, },
-{ 0x38>>2, 0x44>>2, 0x5c>>2, 0x5c>>2, 0x58>>2, 0x40>>2, 0x38>>2, 0x00>>2, },
-{ 0x10>>2, 0x28>>2, 0x44>>2, 0x44>>2, 0x7c>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
-{ 0x78>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x00>>2, },
-{ 0x38>>2, 0x44>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
-{ 0x70>>2, 0x48>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x48>>2, 0x70>>2, 0x00>>2, },
-{ 0x7c>>2, 0x40>>2, 0x40>>2, 0x78>>2, 0x40>>2, 0x40>>2, 0x7c>>2, 0x00>>2, },
-{ 0x7c>>2, 0x40>>2, 0x40>>2, 0x78>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x00>>2, },
-{ 0x38>>2, 0x44>>2, 0x40>>2, 0x4c>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x00>>2, },
-{ 0x44>>2, 0x44>>2, 0x44>>2, 0x7c>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
-{ 0x7c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x7c>>2, 0x00>>2, },
-{ 0x1c>>2, 0x04>>2, 0x04>>2, 0x04>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
-{ 0x44>>2, 0x48>>2, 0x50>>2, 0x60>>2, 0x50>>2, 0x48>>2, 0x44>>2, 0x00>>2, },
-{ 0x40>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x7c>>2, 0x00>>2, },
-{ 0x44>>2, 0x6c>>2, 0x54>>2, 0x54>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
-{ 0x44>>2, 0x64>>2, 0x64>>2, 0x54>>2, 0x4c>>2, 0x4c>>2, 0x44>>2, 0x00>>2, },
-{ 0x38>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
-{ 0x78>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x00>>2, },
-{ 0x38>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x0c>>2, },
-{ 0x78>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x50>>2, 0x48>>2, 0x44>>2, 0x00>>2, },
-{ 0x38>>2, 0x44>>2, 0x40>>2, 0x38>>2, 0x04>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
-{ 0x7c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
-{ 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
-{ 0x44>>2, 0x44>>2, 0x44>>2, 0x28>>2, 0x28>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
-{ 0x44>>2, 0x44>>2, 0x44>>2, 0x54>>2, 0x54>>2, 0x6c>>2, 0x44>>2, 0x00>>2, },
-{ 0x44>>2, 0x44>>2, 0x28>>2, 0x10>>2, 0x28>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
-{ 0x44>>2, 0x44>>2, 0x28>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
-{ 0x7c>>2, 0x04>>2, 0x08>>2, 0x10>>2, 0x20>>2, 0x40>>2, 0x7c>>2, 0x00>>2, },
-{ 0x1c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x1c>>2, 0x00>>2, },
-{ 0x20>>2, 0x20>>2, 0x10>>2, 0x10>>2, 0x08>>2, 0x08>>2, 0x04>>2, 0x04>>2, },
-{ 0x70>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x70>>2, 0x00>>2, },
-{ 0x10>>2, 0x28>>2, 0x44>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0xfc>>2, 0x00>>2, },
-{ 0x10>>2, 0x08>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x44>>2, 0x44>>2, 0x4c>>2, 0x34>>2, 0x00>>2, },
-{ 0x40>>2, 0x40>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x3c>>2, 0x00>>2, },
-{ 0x04>>2, 0x04>>2, 0x3c>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x38>>2, 0x44>>2, 0x7c>>2, 0x40>>2, 0x38>>2, 0x00>>2, },
-{ 0x1c>>2, 0x20>>2, 0x78>>2, 0x20>>2, 0x20>>2, 0x20>>2, 0x20>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x04>>2, 0x38>>2, },
-{ 0x40>>2, 0x40>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
-{ 0x10>>2, 0x00>>2, 0x30>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x38>>2, 0x00>>2, },
-{ 0x08>>2, 0x00>>2, 0x38>>2, 0x08>>2, 0x08>>2, 0x08>>2, 0x08>>2, 0x70>>2, },
-{ 0x40>>2, 0x40>>2, 0x48>>2, 0x50>>2, 0x60>>2, 0x50>>2, 0x48>>2, 0x00>>2, },
-{ 0x30>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x38>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x68>>2, 0x54>>2, 0x54>>2, 0x54>>2, 0x44>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x58>>2, 0x64>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x38>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x40>>2, },
-{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x04>>2, },
-{ 0x00>>2, 0x00>>2, 0x58>>2, 0x60>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x40>>2, 0x38>>2, 0x04>>2, 0x78>>2, 0x00>>2, },
-{ 0x10>>2, 0x10>>2, 0x7c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x0c>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x4c>>2, 0x34>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x6c>>2, 0x28>>2, 0x28>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x44>>2, 0x54>>2, 0x54>>2, 0x54>>2, 0x28>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x44>>2, 0x28>>2, 0x10>>2, 0x28>>2, 0x44>>2, 0x00>>2, },
-{ 0x00>>2, 0x00>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x04>>2, 0x38>>2, },
-{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x08>>2, 0x10>>2, 0x20>>2, 0x7c>>2, 0x00>>2, },
-{ 0x04>>2, 0x08>>2, 0x08>>2, 0x10>>2, 0x08>>2, 0x08>>2, 0x04>>2, 0x00>>2, },
-{ 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
-{ 0x40>>2, 0x20>>2, 0x20>>2, 0x10>>2, 0x20>>2, 0x20>>2, 0x40>>2, 0x00>>2, },
-{ 0x20>>2, 0x54>>2, 0x08>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
-{ 0x00>>2, 0x10>>2, 0x10>>2, 0x28>>2, 0x28>>2, 0x44>>2, 0x7c>>2, 0x00>>2, },
-};
-
diff --git a/frontend/common/fonts.h b/frontend/common/fonts.h
deleted file mode 100644 (file)
index dbbdd4c..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-
-extern unsigned char fontdata8x8[64*16];
-extern unsigned char fontdata6x8[256-32][8];
-
diff --git a/frontend/common/in_sdl.c b/frontend/common/in_sdl.c
deleted file mode 100644 (file)
index ce57536..0000000
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * (C) Gražvydas "notaz" Ignotas, 2012
- *
- * This work is licensed under the terms of any of these licenses
- * (at your option):
- *  - GNU GPL, version 2 or later.
- *  - GNU LGPL, version 2.1 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include <stdio.h>
-#include <SDL.h>
-#include "input.h"
-#include "in_sdl.h"
-
-#define IN_SDL_PREFIX "sdl:"
-/* should be machine word for best performace */
-typedef unsigned long keybits_t;
-#define KEYBITS_WORD_BITS (sizeof(keybits_t) * 8)
-
-struct in_sdl_state {
-       SDL_Joystick *joy;
-       int joy_id;
-       int axis_keydown[2];
-       keybits_t keystate[SDLK_LAST / KEYBITS_WORD_BITS + 1];
-};
-
-static const char * const in_sdl_keys[SDLK_LAST] = {
-       [SDLK_BACKSPACE] = "backspace",
-       [SDLK_TAB] = "tab",
-       [SDLK_CLEAR] = "clear",
-       [SDLK_RETURN] = "return",
-       [SDLK_PAUSE] = "pause",
-       [SDLK_ESCAPE] = "escape",
-       [SDLK_SPACE] = "space",
-       [SDLK_EXCLAIM]  = "!",
-       [SDLK_QUOTEDBL]  = "\"",
-       [SDLK_HASH]  = "#",
-       [SDLK_DOLLAR]  = "$",
-       [SDLK_AMPERSAND]  = "&",
-       [SDLK_QUOTE] = "'",
-       [SDLK_LEFTPAREN] = "(",
-       [SDLK_RIGHTPAREN] = ")",
-       [SDLK_ASTERISK] = "*",
-       [SDLK_PLUS] = "+",
-       [SDLK_COMMA] = ",",
-       [SDLK_MINUS] = "-",
-       [SDLK_PERIOD] = ".",
-       [SDLK_SLASH] = "/",
-       [SDLK_0] = "0",
-       [SDLK_1] = "1",
-       [SDLK_2] = "2",
-       [SDLK_3] = "3",
-       [SDLK_4] = "4",
-       [SDLK_5] = "5",
-       [SDLK_6] = "6",
-       [SDLK_7] = "7",
-       [SDLK_8] = "8",
-       [SDLK_9] = "9",
-       [SDLK_COLON] = ":",
-       [SDLK_SEMICOLON] = ",",
-       [SDLK_LESS] = "<",
-       [SDLK_EQUALS] = "=",
-       [SDLK_GREATER] = ">",
-       [SDLK_QUESTION] = "?",
-       [SDLK_AT] = "@",
-       [SDLK_LEFTBRACKET] = "[",
-       [SDLK_BACKSLASH] = "\\",
-       [SDLK_RIGHTBRACKET] = "]",
-       [SDLK_CARET] = "^",
-       [SDLK_UNDERSCORE] = "_",
-       [SDLK_BACKQUOTE] = "`",
-       [SDLK_a] = "a",
-       [SDLK_b] = "b",
-       [SDLK_c] = "c",
-       [SDLK_d] = "d",
-       [SDLK_e] = "e",
-       [SDLK_f] = "f",
-       [SDLK_g] = "g",
-       [SDLK_h] = "h",
-       [SDLK_i] = "i",
-       [SDLK_j] = "j",
-       [SDLK_k] = "k",
-       [SDLK_l] = "l",
-       [SDLK_m] = "m",
-       [SDLK_n] = "n",
-       [SDLK_o] = "o",
-       [SDLK_p] = "p",
-       [SDLK_q] = "q",
-       [SDLK_r] = "r",
-       [SDLK_s] = "s",
-       [SDLK_t] = "t",
-       [SDLK_u] = "u",
-       [SDLK_v] = "v",
-       [SDLK_w] = "w",
-       [SDLK_x] = "x",
-       [SDLK_y] = "y",
-       [SDLK_z] = "z",
-       [SDLK_DELETE] = "delete",
-
-       [SDLK_KP0] = "[0]",
-       [SDLK_KP1] = "[1]",
-       [SDLK_KP2] = "[2]",
-       [SDLK_KP3] = "[3]",
-       [SDLK_KP4] = "[4]",
-       [SDLK_KP5] = "[5]",
-       [SDLK_KP6] = "[6]",
-       [SDLK_KP7] = "[7]",
-       [SDLK_KP8] = "[8]",
-       [SDLK_KP9] = "[9]",
-       [SDLK_KP_PERIOD] = "[.]",
-       [SDLK_KP_DIVIDE] = "[/]",
-       [SDLK_KP_MULTIPLY] = "[*]",
-       [SDLK_KP_MINUS] = "[-]",
-       [SDLK_KP_PLUS] = "[+]",
-       [SDLK_KP_ENTER] = "enter",
-       [SDLK_KP_EQUALS] = "equals",
-
-       [SDLK_UP] = "up",
-       [SDLK_DOWN] = "down",
-       [SDLK_RIGHT] = "right",
-       [SDLK_LEFT] = "left",
-       [SDLK_DOWN] = "down",
-       [SDLK_INSERT] = "insert",
-       [SDLK_HOME] = "home",
-       [SDLK_END] = "end",
-       [SDLK_PAGEUP] = "page up",
-       [SDLK_PAGEDOWN] = "page down",
-
-       [SDLK_F1] = "f1",
-       [SDLK_F2] = "f2",
-       [SDLK_F3] = "f3",
-       [SDLK_F4] = "f4",
-       [SDLK_F5] = "f5",
-       [SDLK_F6] = "f6",
-       [SDLK_F7] = "f7",
-       [SDLK_F8] = "f8",
-       [SDLK_F9] = "f9",
-       [SDLK_F10] = "f10",
-       [SDLK_F11] = "f11",
-       [SDLK_F12] = "f12",
-       [SDLK_F13] = "f13",
-       [SDLK_F14] = "f14",
-       [SDLK_F15] = "f15",
-
-       [SDLK_NUMLOCK] = "numlock",
-       [SDLK_CAPSLOCK] = "caps lock",
-       [SDLK_SCROLLOCK] = "scroll lock",
-       [SDLK_RSHIFT] = "right shift",
-       [SDLK_LSHIFT] = "left shift",
-       [SDLK_RCTRL] = "right ctrl",
-       [SDLK_LCTRL] = "left ctrl",
-       [SDLK_RALT] = "right alt",
-       [SDLK_LALT] = "left alt",
-       [SDLK_RMETA] = "right meta",
-       [SDLK_LMETA] = "left meta",
-       [SDLK_LSUPER] = "left super",   /* "Windows" keys */
-       [SDLK_RSUPER] = "right super",  
-       [SDLK_MODE] = "alt gr",
-       [SDLK_COMPOSE] = "compose",
-};
-
-static void in_sdl_probe(void)
-{
-       struct in_sdl_state *state;
-       SDL_Joystick *joy;
-       int i, joycount;
-       char name[256];
-
-       state = calloc(1, sizeof(*state));
-       if (state == NULL) {
-               fprintf(stderr, "in_sdl: OOM\n");
-               return;
-       }
-
-       in_register(IN_SDL_PREFIX "keys", -1, state, SDLK_LAST,
-               in_sdl_keys, 0);
-
-       /* joysticks go here too */
-       SDL_InitSubSystem(SDL_INIT_JOYSTICK);
-
-       joycount = SDL_NumJoysticks();
-       for (i = 0; i < joycount; i++) {
-               joy = SDL_JoystickOpen(i);
-               if (joy == NULL)
-                       continue;
-
-               state = calloc(1, sizeof(*state));
-               if (state == NULL) {
-                       fprintf(stderr, "in_sdl: OOM\n");
-                       break;
-               }
-               state->joy = joy;
-               state->joy_id = i;
-
-               snprintf(name, sizeof(name), IN_SDL_PREFIX "%s", SDL_JoystickName(i));
-               in_register(name, -1, state, SDLK_LAST, in_sdl_keys, 0);
-       }
-
-       if (joycount > 0)
-               SDL_JoystickEventState(SDL_ENABLE);
-}
-
-static void in_sdl_free(void *drv_data)
-{
-       struct in_sdl_state *state = drv_data;
-
-       if (state != NULL) {
-               if (state->joy != NULL)
-                       SDL_JoystickClose(state->joy);
-               free(state);
-       }
-}
-
-static const char * const *
-in_sdl_get_key_names(int *count)
-{
-       *count = SDLK_LAST;
-       return in_sdl_keys;
-}
-
-/* could use SDL_GetKeyState, but this gives better packing */
-static void update_keystate(keybits_t *keystate, int sym, int is_down)
-{
-       keybits_t *ks_word, mask;
-
-       mask = 1;
-       mask <<= sym & (KEYBITS_WORD_BITS - 1);
-       ks_word = keystate + sym / KEYBITS_WORD_BITS;
-       if (is_down)
-               *ks_word |= mask;
-       else
-               *ks_word &= ~mask;
-}
-
-static int handle_event(struct in_sdl_state *state, SDL_Event *event,
-       int *kc_out, int *down_out)
-{
-       if (event->type != SDL_KEYDOWN && event->type != SDL_KEYUP)
-               return 0;
-
-       update_keystate(state->keystate, event->key.keysym.sym,
-               event->type == SDL_KEYDOWN);
-       if (kc_out != NULL)
-               *kc_out = event->key.keysym.sym;
-       if (down_out != NULL)
-               *down_out = event->type == SDL_KEYDOWN;
-
-       return 1;
-}
-
-static int handle_joy_event(struct in_sdl_state *state, SDL_Event *event,
-       int *kc_out, int *down_out)
-{
-       int kc = -1, down = 0, ret = 0;
-
-       /* FIXME: should ckeck .which */
-       /* TODO: remaining axis */
-       switch (event->type) {
-       case SDL_JOYAXISMOTION:
-               if (event->jaxis.axis > 1)
-                       break;
-               if (-16384 <= event->jaxis.value && event->jaxis.value <= 16384) {
-                       kc = state->axis_keydown[event->jaxis.axis];
-                       state->axis_keydown[event->jaxis.axis] = 0;
-                       ret = 1;
-               }
-               else if (event->jaxis.value < -16384) {
-                       kc = state->axis_keydown[event->jaxis.axis];
-                       if (kc)
-                               update_keystate(state->keystate, kc, 0);
-                       kc = event->jaxis.axis ? SDLK_UP : SDLK_LEFT;
-                       state->axis_keydown[event->jaxis.axis] = kc;
-                       down = 1;
-                       ret = 1;
-               }
-               else if (event->jaxis.value > 16384) {
-                       kc = state->axis_keydown[event->jaxis.axis];
-                       if (kc)
-                               update_keystate(state->keystate, kc, 0);
-                       kc = event->jaxis.axis ? SDLK_DOWN : SDLK_RIGHT;
-                       state->axis_keydown[event->jaxis.axis] = kc;
-                       down = 1;
-                       ret = 1;
-               }
-               break;
-
-       case SDL_JOYBUTTONDOWN:
-       case SDL_JOYBUTTONUP:
-               kc = (int)event->jbutton.button + SDLK_WORLD_0;
-               down = event->jbutton.state == SDL_PRESSED;
-               ret = 1;
-               break;
-       }
-
-       if (ret)
-               update_keystate(state->keystate, kc, down);
-       if (kc_out != NULL)
-               *kc_out = kc;
-       if (down_out != NULL)
-               *down_out = down;
-
-       return ret;
-}
-
-#define JOY_EVENTS (SDL_JOYAXISMOTIONMASK | SDL_JOYBALLMOTIONMASK | SDL_JOYHATMOTIONMASK \
-                   | SDL_JOYBUTTONDOWNMASK | SDL_JOYBUTTONUPMASK)
-
-static int collect_events(struct in_sdl_state *state, int *one_kc, int *one_down)
-{
-       SDL_Event events[4];
-       Uint32 mask = state->joy ? JOY_EVENTS : (SDL_ALLEVENTS & ~JOY_EVENTS);
-       int count, maxcount;
-       int i, ret, retval = 0;
-
-       maxcount = (one_kc != NULL) ? 1 : sizeof(events) / sizeof(events[0]);
-
-       SDL_PumpEvents();
-       while (1) {
-               count = SDL_PeepEvents(events, maxcount, SDL_GETEVENT, mask);
-               if (count <= 0)
-                       break;
-               for (i = 0; i < count; i++) {
-                       if (state->joy)
-                               ret = handle_joy_event(state,
-                                       &events[i], one_kc, one_down);
-                       else
-                               ret = handle_event(state,
-                                       &events[i], one_kc, one_down);
-                       retval |= ret;
-                       if (one_kc != NULL && ret)
-                               goto out;
-               }
-       }
-
-out:
-       return retval;
-}
-
-static int in_sdl_update(void *drv_data, const int *binds, int *result)
-{
-       struct in_sdl_state *state = drv_data;
-       keybits_t mask;
-       int i, sym, bit, b;
-
-       collect_events(state, NULL, NULL);
-
-       for (i = 0; i < SDLK_LAST / KEYBITS_WORD_BITS + 1; i++) {
-               mask = state->keystate[i];
-               if (mask == 0)
-                       continue;
-               for (bit = 0; mask != 0; bit++, mask >>= 1) {
-                       if ((mask & 1) == 0)
-                               continue;
-                       sym = i * KEYBITS_WORD_BITS + bit;
-
-                       for (b = 0; b < IN_BINDTYPE_COUNT; b++)
-                               result[b] |= binds[IN_BIND_OFFS(sym, b)];
-               }
-       }
-
-       return 0;
-}
-
-static int in_sdl_update_keycode(void *drv_data, int *is_down)
-{
-       struct in_sdl_state *state = drv_data;
-       int ret_kc = -1, ret_down = 0;
-
-       collect_events(state, &ret_kc, &ret_down);
-
-       if (is_down != NULL)
-               *is_down = ret_down;
-
-       return ret_kc;
-}
-
-struct menu_keymap {
-       short key;
-       short pbtn;
-};
-
-static const struct menu_keymap key_pbtn_map[] =
-{
-       { SDLK_UP,      PBTN_UP },
-       { SDLK_DOWN,    PBTN_DOWN },
-       { SDLK_LEFT,    PBTN_LEFT },
-       { SDLK_RIGHT,   PBTN_RIGHT },
-       /* XXX: maybe better set this from it's plat code somehow */
-       { SDLK_RETURN,  PBTN_MOK },
-       { SDLK_ESCAPE,  PBTN_MBACK },
-       { SDLK_a,       PBTN_MA2 },
-       { SDLK_s,       PBTN_MA3 },
-       { SDLK_BACKSLASH,    PBTN_MENU },
-       { SDLK_LEFTBRACKET,  PBTN_L },
-       { SDLK_RIGHTBRACKET, PBTN_R },
-};
-#define KEY_PBTN_MAP_SIZE (sizeof(key_pbtn_map) / sizeof(key_pbtn_map[0]))
-
-static const struct menu_keymap joybtn_pbtn_map[] =
-{
-       { SDLK_UP,      PBTN_UP },
-       { SDLK_DOWN,    PBTN_DOWN },
-       { SDLK_LEFT,    PBTN_LEFT },
-       { SDLK_RIGHT,   PBTN_RIGHT },
-       /* joystick */
-       { SDLK_WORLD_0, PBTN_MOK },
-       { SDLK_WORLD_1, PBTN_MBACK },
-       { SDLK_WORLD_2, PBTN_MA2 },
-       { SDLK_WORLD_3, PBTN_MA3 },
-};
-#define JOYBTN_PBTN_MAP_SIZE (sizeof(joybtn_pbtn_map) / sizeof(joybtn_pbtn_map[0]))
-
-static int in_sdl_menu_translate(void *drv_data, int keycode, char *charcode)
-{
-       struct in_sdl_state *state = drv_data;
-       const struct menu_keymap *map;
-       int map_len;
-       int ret = 0;
-       int i;
-
-       map = state->joy ? joybtn_pbtn_map : key_pbtn_map;
-       map_len = state->joy ? JOYBTN_PBTN_MAP_SIZE : KEY_PBTN_MAP_SIZE;
-
-       if (keycode < 0)
-       {
-               /* menu -> kc */
-               keycode = -keycode;
-               for (i = 0; i < map_len; i++)
-                       if (map[i].pbtn == keycode)
-                               return map[i].key;
-       }
-       else
-       {
-               for (i = 0; i < map_len; i++) {
-                       if (map[i].key == keycode) {
-                               ret = map[i].pbtn;
-                               break;
-                       }
-               }
-
-               if (charcode != NULL && (unsigned int)keycode < SDLK_LAST &&
-                   in_sdl_keys[keycode] != NULL && in_sdl_keys[keycode][1] == 0)
-               {
-                       ret |= PBTN_CHAR;
-                       *charcode = in_sdl_keys[keycode][0];
-               }
-       }
-
-       return ret;
-}
-
-static const in_drv_t in_sdl_drv = {
-       .prefix         = IN_SDL_PREFIX,
-       .probe          = in_sdl_probe,
-       .free           = in_sdl_free,
-       .get_key_names  = in_sdl_get_key_names,
-       .update         = in_sdl_update,
-       .update_keycode = in_sdl_update_keycode,
-       .menu_translate = in_sdl_menu_translate,
-};
-
-void in_sdl_init(const struct in_default_bind *defbinds)
-{
-       in_register_driver(&in_sdl_drv, defbinds);
-}
-
diff --git a/frontend/common/in_sdl.h b/frontend/common/in_sdl.h
deleted file mode 100644 (file)
index 47f7a83..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-struct in_default_bind;
-
-void in_sdl_init(const struct in_default_bind *defbinds);
diff --git a/frontend/common/input.c b/frontend/common/input.c
deleted file mode 100644 (file)
index 39d6783..0000000
+++ /dev/null
@@ -1,991 +0,0 @@
-/*
- * (C) Gražvydas "notaz" Ignotas, 2008-2011
- *
- * This work is licensed under the terms of any of these licenses
- * (at your option):
- *  - GNU GPL, version 2 or later.
- *  - GNU LGPL, version 2.1 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "input.h"
-#include "plat.h"
-#include "lprintf.h"
-
-#ifdef IN_GP2X
-#error needs update: in_gp2x_init in_gp2x_update
-#include "../gp2x/in_gp2x.h"
-#endif
-#ifdef IN_VK
-#error needs update: in_vk_init in_vk_update
-#include "../win32/in_vk.h"
-#endif
-
-typedef struct
-{
-       int drv_id;
-       int drv_fd_hnd;
-       void *drv_data;
-       char *name;
-       int key_count;
-       int *binds;     /* total = key_count * bindtypes * 2 */
-       const char * const *key_names;
-       unsigned int probed:1;
-       unsigned int does_combos:1;
-} in_dev_t;
-
-static in_drv_t *in_drivers;
-static in_dev_t in_devices[IN_MAX_DEVS];
-static int in_driver_count = 0;
-static int in_dev_count = 0;           /* probed + bind devices */
-static int in_have_async_devs = 0;
-static int in_probe_dev_id;
-static int menu_key_state = 0;
-static int menu_last_used_dev = 0;
-
-#define DRV(id) in_drivers[id]
-
-
-static int *in_alloc_binds(int drv_id, int key_count)
-{
-       const struct in_default_bind *defbinds;
-       int *binds;
-       int i;
-
-       binds = calloc(key_count * IN_BINDTYPE_COUNT * 2, sizeof(binds[0]));
-       if (binds == NULL)
-               return NULL;
-
-       defbinds = DRV(drv_id).defbinds;
-       if (defbinds != NULL) {
-               for (i = 0; ; i++) {
-                       if (defbinds[i].bit == 0 && defbinds[i].code == 0)
-                               break;
-                       binds[IN_BIND_OFFS(defbinds[i].code, defbinds[i].btype)] =
-                               1 << defbinds[i].bit;
-               }
-
-               /* always have a copy of defbinds */
-               memcpy(binds + key_count * IN_BINDTYPE_COUNT, binds,
-                       sizeof(binds[0]) * key_count * IN_BINDTYPE_COUNT);
-       }
-
-       return binds;
-}
-
-static void in_unprobe(in_dev_t *dev)
-{
-       if (dev->probed)
-               DRV(dev->drv_id).free(dev->drv_data);
-       dev->probed = 0;
-       dev->drv_data = NULL;
-}
-
-static void in_free(in_dev_t *dev)
-{
-       in_unprobe(dev);
-       free(dev->name);
-       dev->name = NULL;
-       free(dev->binds);
-       dev->binds = NULL;
-}
-
-/* to be called by drivers
- * async devices must set drv_fd_hnd to -1 */
-void in_register(const char *nname, int drv_fd_hnd, void *drv_data,
-               int key_count, const char * const *key_names, int combos)
-{
-       int i, ret, dupe_count = 0, *binds;
-       char name[256], *name_end, *tmp;
-
-       strncpy(name, nname, sizeof(name));
-       name[sizeof(name)-12] = 0;
-       name_end = name + strlen(name);
-
-       for (i = 0; i < in_dev_count; i++)
-       {
-               if (in_devices[i].name == NULL)
-                       continue;
-               if (strcmp(in_devices[i].name, name) == 0)
-               {
-                       if (in_devices[i].probed) {
-                               dupe_count++;
-                               sprintf(name_end, " [%d]", dupe_count);
-                               continue;
-                       }
-                       goto update;
-               }
-       }
-
-       if (i >= IN_MAX_DEVS)
-       {
-               /* try to find unused device */
-               for (i = 0; i < IN_MAX_DEVS; i++)
-                       if (!in_devices[i].probed) break;
-               if (i >= IN_MAX_DEVS) {
-                       lprintf("input: too many devices, can't add %s\n", name);
-                       return;
-               }
-               in_free(&in_devices[i]);
-       }
-
-       tmp = strdup(name);
-       if (tmp == NULL)
-               return;
-
-       binds = in_alloc_binds(in_probe_dev_id, key_count);
-       if (binds == NULL) {
-               free(tmp);
-               return;
-       }
-
-       in_devices[i].name = tmp;
-       in_devices[i].binds = binds;
-       in_devices[i].key_count = key_count;
-       if (i + 1 > in_dev_count)
-               in_dev_count = i + 1;
-
-       lprintf("input: new device #%d \"%s\"\n", i, name);
-update:
-       in_devices[i].probed = 1;
-       in_devices[i].does_combos = combos;
-       in_devices[i].drv_id = in_probe_dev_id;
-       in_devices[i].drv_fd_hnd = drv_fd_hnd;
-       in_devices[i].key_names = key_names;
-       in_devices[i].drv_data = drv_data;
-
-       if (in_devices[i].binds != NULL) {
-               ret = DRV(in_probe_dev_id).clean_binds(drv_data, in_devices[i].binds,
-                       in_devices[i].binds + key_count * IN_BINDTYPE_COUNT);
-               if (ret == 0) {
-                       /* no useable binds */
-                       free(in_devices[i].binds);
-                       in_devices[i].binds = NULL;
-               }
-       }
-}
-
-/* key combo handling, to be called by drivers that support it.
- * Only care about IN_BINDTYPE_EMU */
-void in_combos_find(const int *binds, int last_key, int *combo_keys, int *combo_acts)
-{
-       int act, u;
-
-       *combo_keys = *combo_acts = 0;
-       for (act = 0; act < sizeof(binds[0]) * 8; act++)
-       {
-               int keyc = 0;
-               for (u = 0; u <= last_key; u++)
-                       if (binds[IN_BIND_OFFS(u, IN_BINDTYPE_EMU)] & (1 << act))
-                               keyc++;
-
-               if (keyc > 1)
-               {
-                       // loop again and mark those keys and actions as combo
-                       for (u = 0; u <= last_key; u++)
-                       {
-                               if (binds[IN_BIND_OFFS(u, IN_BINDTYPE_EMU)] & (1 << act)) {
-                                       *combo_keys |= 1 << u;
-                                       *combo_acts |= 1 << act;
-                               }
-                       }
-               }
-       }
-}
-
-int in_combos_do(int keys, const int *binds, int last_key, int combo_keys, int combo_acts)
-{
-       int i, ret = 0;
-
-       for (i = 0; i <= last_key; i++)
-       {
-               int acts, acts_c, u;
-
-               if (!(keys & (1 << i)))
-                       continue;
-
-               acts = binds[IN_BIND_OFFS(i, IN_BINDTYPE_EMU)];
-               if (!acts)
-                       continue;
-
-               if (!(combo_keys & (1 << i))) {
-                       ret |= acts;
-                       continue;
-               }
-
-               acts_c = acts & combo_acts;
-               u = last_key;
-               if (acts_c) {
-                       // let's try to find the other one
-                       for (u = i + 1; u <= last_key; u++)
-                               if ( (keys & (1 << u)) && (binds[IN_BIND_OFFS(u, IN_BINDTYPE_EMU)] & acts_c) ) {
-                                       ret |= acts_c & binds[IN_BIND_OFFS(u, IN_BINDTYPE_EMU)];
-                                       keys &= ~((1 << i) | (1 << u));
-                                       break;
-                               }
-               }
-               // add non-combo actions if combo ones were not found
-               if (u >= last_key)
-                       ret |= acts & ~combo_acts;
-       }
-
-       return ret;
-}
-
-void in_probe(void)
-{
-       int i;
-
-       in_have_async_devs = 0;
-       menu_key_state = 0;
-       menu_last_used_dev = 0;
-
-       for (i = 0; i < in_dev_count; i++)
-               in_unprobe(&in_devices[i]);
-
-       for (i = 0; i < in_driver_count; i++) {
-               in_probe_dev_id = i;
-               in_drivers[i].probe();
-       }
-
-       /* get rid of devs without binds and probes */
-       for (i = 0; i < in_dev_count; i++) {
-               if (!in_devices[i].probed && in_devices[i].binds == NULL) {
-                       in_dev_count--;
-                       if (i < in_dev_count) {
-                               free(in_devices[i].name);
-                               memmove(&in_devices[i], &in_devices[i+1],
-                                       (in_dev_count - i) * sizeof(in_devices[0]));
-                       }
-
-                       continue;
-               }
-
-               if (in_devices[i].probed && in_devices[i].drv_fd_hnd == -1)
-                       in_have_async_devs = 1;
-       }
-
-       if (in_have_async_devs)
-               lprintf("input: async-only devices detected..\n");
-
-       in_debug_dump();
-}
-
-/* async update */
-int in_update(int *result)
-{
-       int i, ret = 0;
-
-       for (i = 0; i < in_dev_count; i++) {
-               in_dev_t *dev = &in_devices[i];
-               if (dev->probed && dev->binds != NULL)
-                       ret |= DRV(dev->drv_id).update(dev->drv_data, dev->binds, result);
-       }
-
-       return ret;
-}
-
-static in_dev_t *get_dev(int dev_id)
-{
-       if (dev_id < 0 || dev_id >= IN_MAX_DEVS)
-               return NULL;
-
-       return &in_devices[dev_id];
-}
-
-int in_update_analog(int dev_id, int axis_id, int *result)
-{
-       in_dev_t *dev = get_dev(dev_id);
-
-       if (dev == NULL || !dev->probed)
-               return -1;
-
-       return DRV(dev->drv_id).update_analog(dev->drv_data, axis_id, result);
-}
-
-static int in_update_kc_async(int *dev_id_out, int *is_down_out, int timeout_ms)
-{
-       int i, is_down, result;
-       unsigned int ticks;
-
-       ticks = plat_get_ticks_ms();
-
-       while (1)
-       {
-               for (i = 0; i < in_dev_count; i++) {
-                       in_dev_t *d = &in_devices[i];
-                       if (!d->probed)
-                               continue;
-
-                       result = DRV(d->drv_id).update_keycode(d->drv_data, &is_down);
-                       if (result == -1)
-                               continue;
-
-                       if (dev_id_out)
-                               *dev_id_out = i;
-                       if (is_down_out)
-                               *is_down_out = is_down;
-                       return result;
-               }
-
-               if (timeout_ms >= 0 && (int)(plat_get_ticks_ms() - ticks) > timeout_ms)
-                       break;
-
-               plat_sleep_ms(10);
-       }
-
-       return -1;
-}
-
-/* 
- * wait for a press, always return some keycode or -1 on timeout or error
- */
-int in_update_keycode(int *dev_id_out, int *is_down_out, char *charcode, int timeout_ms)
-{
-       int result = -1, dev_id = 0, is_down, result_menu;
-       int fds_hnds[IN_MAX_DEVS];
-       int i, ret, count = 0;
-       in_drv_t *drv = NULL;
-       unsigned int ticks;
-
-       if (in_have_async_devs) {
-               result = in_update_kc_async(&dev_id, &is_down, timeout_ms);
-               if (result == -1)
-                       return -1;
-               drv = &DRV(in_devices[dev_id].drv_id);
-               goto finish;
-       }
-
-       ticks = plat_get_ticks_ms();
-
-       for (i = 0; i < in_dev_count; i++) {
-               if (in_devices[i].probed)
-                       fds_hnds[count++] = in_devices[i].drv_fd_hnd;
-       }
-
-       if (count == 0) {
-               /* don't deadlock, fail */
-               lprintf("input: failed to find devices to read\n");
-               exit(1);
-       }
-
-       while (1)
-       {
-               ret = plat_wait_event(fds_hnds, count, timeout_ms);
-               if (ret < 0)
-                       break;
-
-               for (i = 0; i < in_dev_count; i++) {
-                       if (in_devices[i].drv_fd_hnd == ret) {
-                               dev_id = i;
-                               break;
-                       }
-               }
-
-               drv = &DRV(in_devices[dev_id].drv_id);
-               result = drv->update_keycode(in_devices[dev_id].drv_data, &is_down);
-               if (result >= 0)
-                       break;
-
-               if (result == -2) {
-                       lprintf("input: \"%s\" errored out, removing.\n", in_devices[dev_id].name);
-                       in_unprobe(&in_devices[dev_id]);
-                       break;
-               }
-
-               if (timeout_ms >= 0) {
-                       unsigned int ticks2 = plat_get_ticks_ms();
-                       timeout_ms -= ticks2 - ticks;
-                       ticks = ticks2;
-                       if (timeout_ms <= 0)
-                               break;
-               }
-       }
-
-       if (result < 0)
-               return -1;
-finish:
-       /* keep track of menu key state, to allow mixing
-        * in_update_keycode() and in_menu_wait_any() calls */
-       result_menu = drv->menu_translate(in_devices[dev_id].drv_data, result, charcode);
-       if (result_menu != 0) {
-               if (is_down)
-                       menu_key_state |=  result_menu;
-               else
-                       menu_key_state &= ~result_menu;
-       }
-
-       if (dev_id_out != NULL)
-               *dev_id_out = dev_id;
-       if (is_down_out != NULL)
-               *is_down_out = is_down;
-       return result;
-}
-
-/* same as above, only return bitfield of PBTN_*  */
-int in_menu_wait_any(char *charcode, int timeout_ms)
-{
-       int keys_old = menu_key_state;
-
-       while (1)
-       {
-               int code, is_down = 0, dev_id = 0;
-
-               code = in_update_keycode(&dev_id, &is_down, charcode, timeout_ms);
-               if (code < 0)
-                       break;
-
-               if (keys_old != menu_key_state) {
-                       menu_last_used_dev = dev_id;
-                       break;
-               }
-       }
-
-       return menu_key_state;
-}
-
-/* wait for menu input, do autorepeat */
-int in_menu_wait(int interesting, char *charcode, int autorep_delay_ms)
-{
-       static int inp_prev = 0;
-       static int repeats = 0;
-       int ret, release = 0, wait = 450;
-
-       if (repeats)
-               wait = autorep_delay_ms;
-
-       ret = in_menu_wait_any(charcode, wait);
-       if (ret == inp_prev)
-               repeats++;
-
-       while (!(ret & interesting)) {
-               ret = in_menu_wait_any(charcode, -1);
-               release = 1;
-       }
-
-       if (release || ret != inp_prev)
-               repeats = 0;
-
-       inp_prev = ret;
-
-       /* we don't need diagonals in menus */
-       if ((ret & PBTN_UP)   && (ret & PBTN_LEFT))  ret &= ~PBTN_LEFT;
-       if ((ret & PBTN_UP)   && (ret & PBTN_RIGHT)) ret &= ~PBTN_RIGHT;
-       if ((ret & PBTN_DOWN) && (ret & PBTN_LEFT))  ret &= ~PBTN_LEFT;
-       if ((ret & PBTN_DOWN) && (ret & PBTN_RIGHT)) ret &= ~PBTN_RIGHT;
-
-       return ret;
-}
-
-const int *in_get_dev_binds(int dev_id)
-{
-       in_dev_t *dev = get_dev(dev_id);
-
-       return dev ? dev->binds : NULL;
-}
-
-const int *in_get_dev_def_binds(int dev_id)
-{
-       in_dev_t *dev = get_dev(dev_id);
-       if (dev == NULL)
-               return NULL;
-
-       return dev->binds + dev->key_count * IN_BINDTYPE_COUNT;
-}
-
-int in_get_config(int dev_id, int what, void *val)
-{
-       int *ival = val;
-       in_dev_t *dev;
-
-       dev = get_dev(dev_id);
-       if (dev == NULL || val == NULL)
-               return -1;
-
-       switch (what) {
-       case IN_CFG_BIND_COUNT:
-               *ival = dev->key_count;
-               break;
-       case IN_CFG_DOES_COMBOS:
-               *ival = dev->does_combos;
-               break;
-       case IN_CFG_BLOCKING:
-       case IN_CFG_KEY_NAMES:
-               return -1; /* not implemented */
-       default:
-               return DRV(dev->drv_id).get_config(dev->drv_data, what, ival);
-       }
-
-       return 0;
-}
-
-static int in_set_blocking(int is_blocking)
-{
-       int i, ret;
-
-       /* have_async_devs means we will have to do all reads async anyway.. */
-       if (!in_have_async_devs) {
-               for (i = 0; i < in_dev_count; i++) {
-                       if (in_devices[i].probed)
-                               DRV(in_devices[i].drv_id).set_config(in_devices[i].drv_data,
-                                                                    IN_CFG_BLOCKING, is_blocking);
-               }
-       }
-
-       menu_key_state = 0;
-
-       /* flush events */
-       do {
-               ret = in_update_keycode(NULL, NULL, NULL, 0);
-       } while (ret >= 0);
-
-       return 0;
-}
-
-int in_set_config(int dev_id, int what, const void *val, int size)
-{
-       const char * const *names;
-       const int *ival = val;
-       in_dev_t *dev;
-       int count;
-
-       if (what == IN_CFG_BLOCKING)
-               return in_set_blocking(*ival);
-
-       dev = get_dev(dev_id);
-       if (dev == NULL)
-               return -1;
-
-       switch (what) {
-       case IN_CFG_KEY_NAMES:
-               names = val;
-               count = size / sizeof(names[0]);
-
-               if (count < dev->key_count) {
-                       lprintf("input: set_key_names: not enough keys\n");
-                       return -1;
-               }
-
-               dev->key_names = names;
-               return 0;
-       case IN_CFG_DEFAULT_DEV:
-               /* just set last used dev, for now */
-               menu_last_used_dev = dev_id;
-               return 0;
-       default:
-               break;
-       }
-
-       if (dev->probed)
-               return DRV(dev->drv_id).set_config(dev->drv_data, what, *ival);
-
-       return -1;
-}
-
-const char *in_get_dev_name(int dev_id, int must_be_active, int skip_pfix)
-{
-       const char *name, *tmp;
-       in_dev_t *dev;
-
-       dev = get_dev(dev_id);
-       if (dev == NULL)
-               return NULL;
-
-       if (must_be_active && !dev->probed)
-               return NULL;
-
-       name = dev->name;
-       if (name == NULL || !skip_pfix)
-               return name;
-
-       /* skip prefix */
-       tmp = strchr(name, ':');
-       if (tmp != NULL)
-               name = tmp + 1;
-
-       return name;
-}
-
-int in_name_to_id(const char *dev_name)
-{
-       int i;
-
-       for (i = 0; i < in_dev_count; i++)
-               if (strcmp(dev_name, in_devices[i].name) == 0)
-                       break;
-
-       if (i >= in_dev_count) {
-               lprintf("input: in_name_to_id: no such device: %s\n", dev_name);
-               return -1;
-       }
-
-       return i;
-}
-
-/* never returns NULL */
-const char *in_get_key_name(int dev_id, int keycode)
-{
-       const char *name = NULL;
-       static char xname[16];
-       in_drv_t *drv;
-       in_dev_t *dev;
-
-       if (dev_id < 0)         /* want last used dev? */
-               dev_id = menu_last_used_dev;
-
-       dev = get_dev(dev_id);
-       if (dev == NULL)
-               return "Unkn0";
-
-       drv = &DRV(dev->drv_id);
-       if (keycode < 0)        /* want name for menu key? */
-               keycode = drv->menu_translate(dev->drv_data, keycode, NULL);
-
-       if (dev->key_names != NULL && 0 <= keycode && keycode < dev->key_count)
-               name = dev->key_names[keycode];
-       if (name != NULL)
-               return name;
-
-       if (drv->get_key_name != NULL)
-               name = drv->get_key_name(keycode);
-       if (name != NULL)
-               return name;
-
-       /* assume scancode */
-       if ((keycode >= '0' && keycode <= '9') || (keycode >= 'a' && keycode <= 'z')
-                       || (keycode >= 'A' && keycode <= 'Z'))
-               sprintf(xname, "%c", keycode);
-       else
-               sprintf(xname, "\\x%02X", keycode);
-       return xname;
-}
-
-int in_get_key_code(int dev_id, const char *key_name)
-{
-       in_dev_t *dev;
-       int i;
-
-       if (dev_id < 0)         /* want last used dev? */
-               dev_id = menu_last_used_dev;
-
-       dev = get_dev(dev_id);
-       if (dev == NULL)
-               return -1;
-
-       if (dev->key_names == NULL)
-               return -1;
-
-       for (i = 0; i < dev->key_count; i++)
-               if (dev->key_names[i] && strcasecmp(dev->key_names[i], key_name) == 0)
-                       return i;
-
-       return -1;
-}
-
-int in_bind_key(int dev_id, int keycode, int mask, int bind_type, int force_unbind)
-{
-       int ret, count;
-       in_dev_t *dev;
-
-       dev = get_dev(dev_id);
-       if (dev == NULL || bind_type >= IN_BINDTYPE_COUNT)
-               return -1;
-
-       count = dev->key_count;
-
-       if (dev->binds == NULL) {
-               if (force_unbind)
-                       return 0;
-               dev->binds = in_alloc_binds(dev->drv_id, count);
-               if (dev->binds == NULL)
-                       return -1;
-       }
-
-       if (keycode < 0 || keycode >= count)
-               return -1;
-       
-       if (force_unbind)
-               dev->binds[IN_BIND_OFFS(keycode, bind_type)] &= ~mask;
-       else
-               dev->binds[IN_BIND_OFFS(keycode, bind_type)] ^=  mask;
-       
-       ret = DRV(dev->drv_id).clean_binds(dev->drv_data, dev->binds,
-                               dev->binds + count * IN_BINDTYPE_COUNT);
-       if (ret == 0) {
-               free(dev->binds);
-               dev->binds = NULL;
-       }
-
-       return 0;
-}
-
-/*
- * Unbind act_mask on binds with type bind_type
- * - if dev_id_ < 0, affects all devices
- *   else only affects dev_id_
- * - if act_mask == -1, unbind all keys
- *   else only actions in mask
- */
-void in_unbind_all(int dev_id_, int act_mask, int bind_type)
-{
-       int dev_id = 0, dev_last = IN_MAX_DEVS - 1;
-       int i, count;
-       in_dev_t *dev;
-
-       if (dev_id_ >= 0)
-               dev_id = dev_last = dev_id_;
-
-       if (bind_type >= IN_BINDTYPE_COUNT)
-               return;
-
-       for (; dev_id <= dev_last; dev_id++) {
-               dev = &in_devices[dev_id];
-               count = dev->key_count;
-
-               if (dev->binds == NULL)
-                       continue;
-
-               if (act_mask != -1) {
-                       for (i = 0; i < count; i++)
-                               dev->binds[IN_BIND_OFFS(i, bind_type)] &= ~act_mask;
-               }
-               else
-                       memset(dev->binds, 0, sizeof(dev->binds[0]) * count * IN_BINDTYPE_COUNT);
-       }
-}
-
-/* returns device id, or -1 on error */
-int in_config_parse_dev(const char *name)
-{
-       int drv_id = -1, i;
-
-       for (i = 0; i < in_driver_count; i++) {
-               int len = strlen(in_drivers[i].prefix);
-               if (strncmp(name, in_drivers[i].prefix, len) == 0) {
-                       drv_id = i;
-                       break;
-               }
-       }
-
-       if (drv_id < 0) {
-               lprintf("input: missing driver for %s\n", name);
-               return -1;
-       }
-
-       for (i = 0; i < in_dev_count; i++)
-       {
-               if (in_devices[i].name == NULL)
-                       continue;
-               if (strcmp(in_devices[i].name, name) == 0)
-                       return i;
-       }
-
-       if (i >= IN_MAX_DEVS)
-       {
-               /* try to find unused device */
-               for (i = 0; i < IN_MAX_DEVS; i++)
-                       if (in_devices[i].name == NULL) break;
-               if (i >= IN_MAX_DEVS) {
-                       lprintf("input: too many devices, can't add %s\n", name);
-                       return -1;
-               }
-       }
-
-       memset(&in_devices[i], 0, sizeof(in_devices[i]));
-
-       in_devices[i].name = strdup(name);
-       if (in_devices[i].name == NULL)
-               return -1;
-
-       in_devices[i].key_names = DRV(drv_id).get_key_names(&in_devices[i].key_count);
-       in_devices[i].drv_id = drv_id;
-
-       if (i + 1 > in_dev_count)
-               in_dev_count = i + 1;
-
-       return i;
-}
-
-int in_config_bind_key(int dev_id, const char *key, int acts, int bind_type)
-{
-       in_dev_t *dev;
-       int i, offs, kc;
-
-       dev = get_dev(dev_id);
-       if (dev == NULL || bind_type >= IN_BINDTYPE_COUNT)
-               return -1;
-
-       /* maybe a raw code? */
-       if (key[0] == '\\' && key[1] == 'x') {
-               char *p = NULL;
-               kc = (int)strtoul(key + 2, &p, 16);
-               if (p == NULL || *p != 0)
-                       kc = -1;
-       }
-       else {
-               /* device specific key name */
-               if (dev->binds == NULL) {
-                       dev->binds = in_alloc_binds(dev->drv_id, dev->key_count);
-                       if (dev->binds == NULL)
-                               return -1;
-               }
-
-               kc = -1;
-               if (dev->key_names != NULL) {
-                       for (i = 0; i < dev->key_count; i++) {
-                               const char *k = dev->key_names[i];
-                               if (k != NULL && strcasecmp(k, key) == 0) {
-                                       kc = i;
-                                       break;
-                               }
-                       }
-               }
-
-               if (kc < 0)
-                       kc = DRV(dev->drv_id).get_key_code(key);
-               if (kc < 0 && strlen(key) == 1) {
-                       /* assume scancode */
-                       kc = key[0];
-               }
-       }
-
-       if (kc < 0 || kc >= dev->key_count) {
-               lprintf("input: bad key: %s\n", key);
-               return -1;
-       }
-
-       if (bind_type == IN_BINDTYPE_NONE) {
-               for (i = 0; i < IN_BINDTYPE_COUNT; i++)
-                       dev->binds[IN_BIND_OFFS(kc, i)] = 0;
-               return 0;
-       }
-
-       offs = IN_BIND_OFFS(kc, bind_type);
-       if (dev->binds[offs] == -1)
-               dev->binds[offs] = 0;
-       dev->binds[offs] |= acts;
-       return 0;
-}
-
-void in_clean_binds(void)
-{
-       int i;
-
-       for (i = 0; i < IN_MAX_DEVS; i++) {
-               int ret, count, *binds, *def_binds;
-               in_dev_t *dev = &in_devices[i];
-
-               if (dev->binds == NULL || dev->drv_data == NULL)
-                       continue;
-
-               count = dev->key_count;
-               binds = dev->binds;
-               def_binds = binds + count * IN_BINDTYPE_COUNT;
-
-               ret = DRV(dev->drv_id).clean_binds(dev->drv_data, binds, def_binds);
-               if (ret == 0) {
-                       /* no useable binds */
-                       free(dev->binds);
-                       dev->binds = NULL;
-               }
-       }
-}
-
-void in_debug_dump(void)
-{
-       int i;
-
-       lprintf("# drv probed binds name\n");
-       for (i = 0; i < IN_MAX_DEVS; i++) {
-               in_dev_t *d = &in_devices[i];
-               if (!d->probed && d->name == NULL && d->binds == NULL)
-                       continue;
-               lprintf("%d %3d %6c %5c %s\n", i, d->drv_id, d->probed ? 'y' : 'n',
-                       d->binds ? 'y' : 'n', d->name);
-       }
-}
-
-/* stubs for drivers that choose not to implement something */
-
-static void in_def_free(void *drv_data) {}
-static int  in_def_clean_binds(void *drv_data, int *b, int *db) { return 1; }
-static int  in_def_get_config(void *drv_data, int what, int *val) { return -1; }
-static int  in_def_set_config(void *drv_data, int what, int val) { return -1; }
-static int  in_def_update_analog(void *drv_data, int axis_id, int *result) { return -1; }
-static int  in_def_update_keycode(void *drv_data, int *is_down) { return 0; }
-static int  in_def_menu_translate(void *drv_data, int keycode, char *ccode) { return 0; }
-static int  in_def_get_key_code(const char *key_name) { return -1; }
-static const char *in_def_get_key_name(int keycode) { return NULL; }
-
-#define CHECK_ADD_STUB(d, f) \
-       if (d.f == NULL) d.f = in_def_##f
-
-/* to be called by drivers */
-int in_register_driver(const in_drv_t *drv, const struct in_default_bind *defbinds)
-{
-       int count_new = in_driver_count + 1;
-       in_drv_t *new_drivers;
-
-       new_drivers = realloc(in_drivers, count_new * sizeof(in_drivers[0]));
-       if (new_drivers == NULL) {
-               lprintf("input: in_register_driver OOM\n");
-               return -1;
-       }
-
-       memcpy(&new_drivers[in_driver_count], drv, sizeof(new_drivers[0]));
-
-       CHECK_ADD_STUB(new_drivers[in_driver_count], free);
-       CHECK_ADD_STUB(new_drivers[in_driver_count], clean_binds);
-       CHECK_ADD_STUB(new_drivers[in_driver_count], get_config);
-       CHECK_ADD_STUB(new_drivers[in_driver_count], set_config);
-       CHECK_ADD_STUB(new_drivers[in_driver_count], update_analog);
-       CHECK_ADD_STUB(new_drivers[in_driver_count], update_keycode);
-       CHECK_ADD_STUB(new_drivers[in_driver_count], menu_translate);
-       CHECK_ADD_STUB(new_drivers[in_driver_count], get_key_code);
-       CHECK_ADD_STUB(new_drivers[in_driver_count], get_key_name);
-       if (defbinds != NULL)
-               new_drivers[in_driver_count].defbinds = defbinds;
-       in_drivers = new_drivers;
-       in_driver_count = count_new;
-
-       return 0;
-}
-
-void in_init(void)
-{
-       in_drivers = NULL;
-       memset(in_devices, 0, sizeof(in_devices));
-       in_driver_count = 0;
-       in_dev_count = 0;
-}
-
-#if 0
-int main(void)
-{
-       int ret;
-
-       in_init();
-       in_probe();
-
-       in_set_blocking(1);
-
-#if 1
-       while (1) {
-               int dev = 0, down;
-               ret = in_update_keycode(&dev, &down);
-               lprintf("#%i: %i %i (%s)\n", dev, down, ret, in_get_key_name(dev, ret));
-       }
-#else
-       while (1) {
-               ret = in_menu_wait_any();
-               lprintf("%08x\n", ret);
-       }
-#endif
-
-       return 0;
-}
-#endif
diff --git a/frontend/common/input.h b/frontend/common/input.h
deleted file mode 100644 (file)
index e87e6ea..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-#ifndef INCLUDE_uXt8Z4R7EMpuEEtvSibXjNhKH3741VNc
-#define INCLUDE_uXt8Z4R7EMpuEEtvSibXjNhKH3741VNc 1
-
-#define IN_MAX_DEVS 10
-#define IN_ABS_RANGE 1024      /* abs must be centered at 0, move upto +- this */
-
-/* unified menu keys */
-#define PBTN_UP    (1 <<  0)
-#define PBTN_DOWN  (1 <<  1)
-#define PBTN_LEFT  (1 <<  2)
-#define PBTN_RIGHT (1 <<  3)
-
-#define PBTN_MOK   (1 <<  4)
-#define PBTN_MBACK (1 <<  5)
-#define PBTN_MA2   (1 <<  6)   /* menu action 2 */
-#define PBTN_MA3   (1 <<  7)
-
-#define PBTN_L     (1 <<  8)
-#define PBTN_R     (1 <<  9)
-
-#define PBTN_MENU  (1 << 10)
-
-#define PBTN_CHAR  (1 << 11)   /* character (text input) */
-
-// TODO: move to pico
-#if 0
-
-/* ui events */
-#define PEVB_VOL_DOWN   30
-#define PEVB_VOL_UP     29
-#define PEVB_STATE_LOAD 28
-#define PEVB_STATE_SAVE 27
-#define PEVB_SWITCH_RND 26
-#define PEVB_SSLOT_PREV 25
-#define PEVB_SSLOT_NEXT 24
-#define PEVB_MENU       23
-#define PEVB_FF         22
-#define PEVB_PICO_PNEXT 21
-#define PEVB_PICO_PPREV 20
-#define PEVB_PICO_SWINP 19
-
-#define PEV_VOL_DOWN    (1 << PEVB_VOL_DOWN)
-#define PEV_VOL_UP      (1 << PEVB_VOL_UP)
-#define PEV_STATE_LOAD  (1 << PEVB_STATE_LOAD)
-#define PEV_STATE_SAVE  (1 << PEVB_STATE_SAVE)
-#define PEV_SWITCH_RND  (1 << PEVB_SWITCH_RND)
-#define PEV_SSLOT_PREV  (1 << PEVB_SSLOT_PREV)
-#define PEV_SSLOT_NEXT  (1 << PEVB_SSLOT_NEXT)
-#define PEV_MENU        (1 << PEVB_MENU)
-#define PEV_FF          (1 << PEVB_FF)
-#define PEV_PICO_PNEXT  (1 << PEVB_PICO_PNEXT)
-#define PEV_PICO_PPREV  (1 << PEVB_PICO_PPREV)
-#define PEV_PICO_SWINP  (1 << PEVB_PICO_SWINP)
-
-#define PEV_MASK 0x7ff80000
-
-#endif
-
-enum {
-       IN_CFG_BIND_COUNT = 0,
-       IN_CFG_DOES_COMBOS,
-       IN_CFG_BLOCKING,
-       IN_CFG_KEY_NAMES,
-       IN_CFG_ABS_DEAD_ZONE,   /* dead zone for analog-digital mapping */
-       IN_CFG_ABS_AXIS_COUNT,  /* number of abs axes (ro) */
-       IN_CFG_DEFAULT_DEV,
-};
-
-enum {
-       IN_BINDTYPE_NONE = -1,
-       IN_BINDTYPE_EMU = 0,
-       IN_BINDTYPE_PLAYER12,
-       IN_BINDTYPE_COUNT
-};
-
-#define IN_BIND_OFFS(key, btype) \
-       ((key) * IN_BINDTYPE_COUNT + (btype))
-
-typedef struct {
-       const char *prefix;
-       void (*probe)(void);
-       void (*free)(void *drv_data);
-       const char * const *
-            (*get_key_names)(int *count);
-       int  (*clean_binds)(void *drv_data, int *binds, int *def_finds);
-       int  (*get_config)(void *drv_data, int what, int *val);
-       int  (*set_config)(void *drv_data, int what, int val);
-       int  (*update)(void *drv_data, const int *binds, int *result);
-       int  (*update_analog)(void *drv_data, int axis_id, int *result);
-       /* return -1 on no event, -2 on error */
-       int  (*update_keycode)(void *drv_data, int *is_down);
-       int  (*menu_translate)(void *drv_data, int keycode, char *charcode);
-       int  (*get_key_code)(const char *key_name);
-       const char * (*get_key_name)(int keycode);
-
-       const struct in_default_bind *defbinds;
-} in_drv_t;
-
-struct in_default_bind {
-       unsigned short code;
-       unsigned char btype;    /* IN_BINDTYPE_* */
-       unsigned char bit;
-};
-
-/* to be called by drivers */
-int  in_register_driver(const in_drv_t *drv, const struct in_default_bind *defbinds);
-void in_register(const char *nname, int drv_fd_hnd, void *drv_data,
-               int key_count, const char * const *key_names, int combos);
-void in_combos_find(const int *binds, int last_key, int *combo_keys, int *combo_acts);
-int  in_combos_do(int keys, const int *binds, int last_key, int combo_keys, int combo_acts);
-
-void in_init(void);
-void in_probe(void);
-int  in_update(int *result);
-int  in_update_analog(int dev_id, int axis_id, int *value);
-int  in_update_keycode(int *dev_id, int *is_down, char *charcode, int timeout_ms);
-int  in_menu_wait_any(char *charcode, int timeout_ms);
-int  in_menu_wait(int interesting, char *charcode, int autorep_delay_ms);
-int  in_config_parse_dev(const char *dev_name);
-int  in_config_bind_key(int dev_id, const char *key, int binds, int bind_type);
-int  in_get_config(int dev_id, int what, void *val);
-int  in_set_config(int dev_id, int what, const void *val, int size);
-int  in_get_key_code(int dev_id, const char *key_name);
-int  in_name_to_id(const char *dev_name);
-int  in_bind_key(int dev_id, int keycode, int mask, int bind_type, int force_unbind);
-void in_unbind_all(int dev_id, int act_mask, int bind_type);
-void in_clean_binds(void);
-void in_debug_dump(void);
-
-const int  *in_get_dev_binds(int dev_id);
-const int  *in_get_dev_def_binds(int dev_id);
-const char *in_get_dev_name(int dev_id, int must_be_active, int skip_pfix);
-const char *in_get_key_name(int dev_id, int keycode);
-
-#define in_set_config_int(dev_id, what, v) { \
-       int val_ = v; \
-       in_set_config(dev_id, what, &val_, sizeof(val_)); \
-}
-
-#endif /* INCLUDE_uXt8Z4R7EMpuEEtvSibXjNhKH3741VNc */
diff --git a/frontend/common/lprintf.h b/frontend/common/lprintf.h
deleted file mode 100644 (file)
index 48b8d57..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern void lprintf(const char *fmt, ...);
-
-#ifdef __cplusplus
-}
-#endif
-
diff --git a/frontend/common/menu.c b/frontend/common/menu.c
deleted file mode 100644 (file)
index 3acab62..0000000
+++ /dev/null
@@ -1,1327 +0,0 @@
-/*\r
- * (C) Gražvydas "notaz" Ignotas, 2006-2011\r
- *\r
- * This work is licensed under the terms of any of these licenses\r
- * (at your option):\r
- *  - GNU GPL, version 2 or later.\r
- *  - GNU LGPL, version 2.1 or later.\r
- * See the COPYING file in the top-level directory.\r
- */\r
-\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <stdlib.h>\r
-#include <stdarg.h>\r
-#include <time.h>\r
-#include <locale.h> // savestate date\r
-\r
-#include "menu.h"\r
-#include "fonts.h"\r
-#include "readpng.h"\r
-#include "lprintf.h"\r
-#include "input.h"\r
-#include "plat.h"\r
-#include "posix.h"\r
-\r
-static char static_buff[64];\r
-static int  menu_error_time = 0;\r
-char menu_error_msg[64] = { 0, };\r
-void *g_menuscreen_ptr;\r
-void *g_menubg_src_ptr;\r
-void *g_menubg_ptr;\r
-\r
-#if !MSCREEN_SIZE_FIXED\r
-int g_menuscreen_w;\r
-int g_menuscreen_h;\r
-#endif\r
-\r
-static unsigned char *menu_font_data = NULL;\r
-static int menu_text_color = 0xffff; // default to white\r
-static int menu_sel_color = -1; // disabled\r
-\r
-/* note: these might become non-constant in future */\r
-#if MENU_X2\r
-static const int me_mfont_w = 16, me_mfont_h = 20;\r
-static const int me_sfont_w = 12, me_sfont_h = 20;\r
-#else\r
-static const int me_mfont_w = 8, me_mfont_h = 10;\r
-static const int me_sfont_w = 6, me_sfont_h = 10;\r
-#endif\r
-\r
-// draws text to current bbp16 screen\r
-static void text_out16_(int x, int y, const char *text, int color)\r
-{\r
-       int i, lh, tr, tg, tb, len;\r
-       unsigned short *dest = (unsigned short *)g_menuscreen_ptr + x + y * g_menuscreen_w;\r
-       tr = (color & 0xf800) >> 8;\r
-       tg = (color & 0x07e0) >> 3;\r
-       tb = (color & 0x001f) << 3;\r
-\r
-       if (text == (void *)1)\r
-       {\r
-               // selector symbol\r
-               text = "";\r
-               len = 1;\r
-       }\r
-       else\r
-       {\r
-               const char *p;\r
-               for (p = text; *p != 0 && *p != '\n'; p++)\r
-                       ;\r
-               len = p - text;\r
-       }\r
-\r
-       lh = me_mfont_h;\r
-       if (y + lh > g_menuscreen_h)\r
-               lh = g_menuscreen_h - y;\r
-\r
-       for (i = 0; i < len; i++)\r
-       {\r
-               unsigned char  *src = menu_font_data + (unsigned int)text[i] * me_mfont_w * me_mfont_h / 2;\r
-               unsigned short *dst = dest;\r
-               int u, l;\r
-\r
-               for (l = 0; l < lh; l++, dst += g_menuscreen_w - me_mfont_w)\r
-               {\r
-                       for (u = me_mfont_w / 2; u > 0; u--, src++)\r
-                       {\r
-                               int c, r, g, b;\r
-                               c = *src >> 4;\r
-                               r = (*dst & 0xf800) >> 8;\r
-                               g = (*dst & 0x07e0) >> 3;\r
-                               b = (*dst & 0x001f) << 3;\r
-                               r = (c^0xf)*r/15 + c*tr/15;\r
-                               g = (c^0xf)*g/15 + c*tg/15;\r
-                               b = (c^0xf)*b/15 + c*tb/15;\r
-                               *dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);\r
-                               c = *src & 0xf;\r
-                               r = (*dst & 0xf800) >> 8;\r
-                               g = (*dst & 0x07e0) >> 3;\r
-                               b = (*dst & 0x001f) << 3;\r
-                               r = (c^0xf)*r/15 + c*tr/15;\r
-                               g = (c^0xf)*g/15 + c*tg/15;\r
-                               b = (c^0xf)*b/15 + c*tb/15;\r
-                               *dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);\r
-                       }\r
-               }\r
-               dest += me_mfont_w;\r
-       }\r
-}\r
-\r
-void text_out16(int x, int y, const char *texto, ...)\r
-{\r
-       va_list args;\r
-       char    buffer[256];\r
-       int     maxw = (g_menuscreen_w - x) / me_mfont_w;\r
-\r
-       if (maxw < 0)\r
-               return;\r
-\r
-       va_start(args, texto);\r
-       vsnprintf(buffer, sizeof(buffer), texto, args);\r
-       va_end(args);\r
-\r
-       if (maxw > sizeof(buffer) - 1)\r
-               maxw = sizeof(buffer) - 1;\r
-       buffer[maxw] = 0;\r
-\r
-       text_out16_(x,y,buffer,menu_text_color);\r
-}\r
-\r
-/* draws in 6x8 font, might multiply size by integer */\r
-static void smalltext_out16_(int x, int y, const char *texto, int color)\r
-{\r
-       unsigned char  *src;\r
-       unsigned short *dst;\r
-       int multiplier = me_sfont_w / 6;\r
-       int i;\r
-\r
-       for (i = 0;; i++, x += me_sfont_w)\r
-       {\r
-               unsigned char c = (unsigned char) texto[i];\r
-               int h = 8;\r
-\r
-               if (!c || c == '\n')\r
-                       break;\r
-\r
-               src = fontdata6x8[c];\r
-               dst = (unsigned short *)g_menuscreen_ptr + x + y * g_menuscreen_w;\r
-\r
-               while (h--)\r
-               {\r
-                       int m, w2, h2;\r
-                       for (h2 = multiplier; h2 > 0; h2--)\r
-                       {\r
-                               for (m = 0x20; m; m >>= 1) {\r
-                                       if (*src & m)\r
-                                               for (w2 = multiplier; w2 > 0; w2--)\r
-                                                       *dst++ = color;\r
-                                       else\r
-                                               dst += multiplier;\r
-                               }\r
-\r
-                               dst += g_menuscreen_w - me_sfont_w;\r
-                       }\r
-                       src++;\r
-               }\r
-       }\r
-}\r
-\r
-static void smalltext_out16(int x, int y, const char *texto, int color)\r
-{\r
-       char buffer[128];\r
-       int maxw = (g_menuscreen_w - x) / me_sfont_w;\r
-\r
-       if (maxw < 0)\r
-               return;\r
-\r
-       strncpy(buffer, texto, sizeof(buffer));\r
-       if (maxw > sizeof(buffer) - 1)\r
-               maxw = sizeof(buffer) - 1;\r
-       buffer[maxw] = 0;\r
-\r
-       smalltext_out16_(x, y, buffer, color);\r
-}\r
-\r
-static void menu_draw_selection(int x, int y, int w)\r
-{\r
-       int i, h;\r
-       unsigned short *dst, *dest;\r
-\r
-       text_out16_(x, y, (void *)1, (menu_sel_color < 0) ? menu_text_color : menu_sel_color);\r
-\r
-       if (menu_sel_color < 0) return; // no selection hilight\r
-\r
-       if (y > 0) y--;\r
-       dest = (unsigned short *)g_menuscreen_ptr + x + y * g_menuscreen_w + me_mfont_w * 2 - 2;\r
-       for (h = me_mfont_h + 1; h > 0; h--)\r
-       {\r
-               dst = dest;\r
-               for (i = w - (me_mfont_w * 2 - 2); i > 0; i--)\r
-                       *dst++ = menu_sel_color;\r
-               dest += g_menuscreen_w;\r
-       }\r
-}\r
-\r
-static int parse_hex_color(char *buff)\r
-{\r
-       char *endp = buff;\r
-       int t = (int) strtoul(buff, &endp, 16);\r
-       if (endp != buff)\r
-#ifdef PSP\r
-               return ((t<<8)&0xf800) | ((t>>5)&0x07e0) | ((t>>19)&0x1f);\r
-#else\r
-               return ((t>>8)&0xf800) | ((t>>5)&0x07e0) | ((t>>3)&0x1f);\r
-#endif\r
-       return -1;\r
-}\r
-\r
-static char tolower_simple(char c)\r
-{\r
-       if ('A' <= c && c <= 'Z')\r
-               c = c - 'A' + 'a';\r
-       return c;\r
-}\r
-\r
-void menu_init(void)\r
-{\r
-       int i, c, l;\r
-       unsigned char *fd, *fds;\r
-       char buff[256];\r
-       FILE *f;\r
-\r
-       if (menu_font_data != NULL)\r
-               free(menu_font_data);\r
-\r
-       menu_font_data = calloc((MENU_X2 ? 256 * 320 : 128 * 160) / 2, 1);\r
-       if (menu_font_data == NULL)\r
-               return;\r
-\r
-       // generate default 8x10 font from fontdata8x8\r
-       for (c = 0, fd = menu_font_data; c < 256; c++)\r
-       {\r
-               for (l = 0; l < 8; l++)\r
-               {\r
-                       unsigned char fd8x8 = fontdata8x8[c*8+l];\r
-                       if (fd8x8&0x80) *fd  = 0xf0;\r
-                       if (fd8x8&0x40) *fd |= 0x0f; fd++;\r
-                       if (fd8x8&0x20) *fd  = 0xf0;\r
-                       if (fd8x8&0x10) *fd |= 0x0f; fd++;\r
-                       if (fd8x8&0x08) *fd  = 0xf0;\r
-                       if (fd8x8&0x04) *fd |= 0x0f; fd++;\r
-                       if (fd8x8&0x02) *fd  = 0xf0;\r
-                       if (fd8x8&0x01) *fd |= 0x0f; fd++;\r
-               }\r
-               fd += 8*2/2; // 2 empty lines\r
-       }\r
-\r
-       if (MENU_X2) {\r
-               // expand default font\r
-               fds = menu_font_data + 128 * 160 / 2 - 4;\r
-               fd  = menu_font_data + 256 * 320 / 2 - 1;\r
-               for (c = 255; c >= 0; c--)\r
-               {\r
-                       for (l = 9; l >= 0; l--, fds -= 4)\r
-                       {\r
-                               for (i = 3; i >= 0; i--) {\r
-                                       int px = fds[i] & 0x0f;\r
-                                       *fd-- = px | (px << 4);\r
-                                       px = (fds[i] >> 4) & 0x0f;\r
-                                       *fd-- = px | (px << 4);\r
-                               }\r
-                               for (i = 3; i >= 0; i--) {\r
-                                       int px = fds[i] & 0x0f;\r
-                                       *fd-- = px | (px << 4);\r
-                                       px = (fds[i] >> 4) & 0x0f;\r
-                                       *fd-- = px | (px << 4);\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       // load custom font and selector (stored as 1st symbol in font table)\r
-       emu_make_path(buff, "skin/font.png", sizeof(buff));\r
-       readpng(menu_font_data, buff, READPNG_FONT,\r
-               MENU_X2 ? 256 : 128, MENU_X2 ? 320 : 160);\r
-       // default selector symbol is '>'\r
-       memcpy(menu_font_data, menu_font_data + ((int)'>') * me_mfont_w * me_mfont_h / 2,\r
-               me_mfont_w * me_mfont_h / 2);\r
-       emu_make_path(buff, "skin/selector.png", sizeof(buff));\r
-       readpng(menu_font_data, buff, READPNG_SELECTOR, me_mfont_w, me_mfont_h);\r
-\r
-       // load custom colors\r
-       emu_make_path(buff, "skin/skin.txt", sizeof(buff));\r
-       f = fopen(buff, "r");\r
-       if (f != NULL)\r
-       {\r
-               lprintf("found skin.txt\n");\r
-               while (!feof(f))\r
-               {\r
-                       if (fgets(buff, sizeof(buff), f) == NULL)\r
-                               break;\r
-                       if (buff[0] == '#'  || buff[0] == '/')  continue; // comment\r
-                       if (buff[0] == '\r' || buff[0] == '\n') continue; // empty line\r
-                       if (strncmp(buff, "text_color=", 11) == 0)\r
-                       {\r
-                               int tmp = parse_hex_color(buff+11);\r
-                               if (tmp >= 0) menu_text_color = tmp;\r
-                               else lprintf("skin.txt: parse error for text_color\n");\r
-                       }\r
-                       else if (strncmp(buff, "selection_color=", 16) == 0)\r
-                       {\r
-                               int tmp = parse_hex_color(buff+16);\r
-                               if (tmp >= 0) menu_sel_color = tmp;\r
-                               else lprintf("skin.txt: parse error for selection_color\n");\r
-                       }\r
-                       else\r
-                               lprintf("skin.txt: parse error: %s\n", buff);\r
-               }\r
-               fclose(f);\r
-       }\r
-\r
-       // use user's locale for savestate date display\r
-       setlocale(LC_TIME, "");\r
-}\r
-\r
-static void menu_draw_begin(int need_bg)\r
-{\r
-       plat_video_menu_begin();\r
-       if (need_bg)\r
-               memcpy(g_menuscreen_ptr, g_menubg_ptr, g_menuscreen_w * g_menuscreen_h * 2);\r
-}\r
-\r
-static void menu_draw_end(void)\r
-{\r
-       plat_video_menu_end();\r
-}\r
-\r
-static void menu_darken_bg(void *dst, void *src, int pixels, int darker)\r
-{\r
-       unsigned int *dest = dst;\r
-       unsigned int *sorc = src;\r
-       pixels /= 2;\r
-       if (darker)\r
-       {\r
-               while (pixels--)\r
-               {\r
-                       unsigned int p = *sorc++;\r
-                       *dest++ = ((p&0xf79ef79e)>>1) - ((p&0xc618c618)>>3);\r
-               }\r
-       }\r
-       else\r
-       {\r
-               while (pixels--)\r
-               {\r
-                       unsigned int p = *sorc++;\r
-                       *dest++ = (p&0xf79ef79e)>>1;\r
-               }\r
-       }\r
-}\r
-\r
-static int me_id2offset(const menu_entry *ent, menu_id id)\r
-{\r
-       int i;\r
-       for (i = 0; ent->name; ent++, i++)\r
-               if (ent->id == id) return i;\r
-\r
-       lprintf("%s: id %i not found\n", __FUNCTION__, id);\r
-       return 0;\r
-}\r
-\r
-static void me_enable(menu_entry *entries, menu_id id, int enable)\r
-{\r
-       int i = me_id2offset(entries, id);\r
-       entries[i].enabled = enable;\r
-}\r
-\r
-static int me_count(const menu_entry *ent)\r
-{\r
-       int ret;\r
-\r
-       for (ret = 0; ent->name; ent++, ret++)\r
-               ;\r
-\r
-       return ret;\r
-}\r
-\r
-static unsigned int me_read_onoff(const menu_entry *ent)\r
-{\r
-       // guess var size based on mask to avoid reading too much\r
-       if (ent->mask & 0xffff0000)\r
-               return *(unsigned int *)ent->var & ent->mask;\r
-       else if (ent->mask & 0xff00)\r
-               return *(unsigned short *)ent->var & ent->mask;\r
-       else\r
-               return *(unsigned char *)ent->var & ent->mask;\r
-}\r
-\r
-static void me_toggle_onoff(menu_entry *ent)\r
-{\r
-       // guess var size based on mask to avoid reading too much\r
-       if (ent->mask & 0xffff0000)\r
-               *(unsigned int *)ent->var ^= ent->mask;\r
-       else if (ent->mask & 0xff00)\r
-               *(unsigned short *)ent->var ^= ent->mask;\r
-       else\r
-               *(unsigned char *)ent->var ^= ent->mask;\r
-}\r
-\r
-static void me_draw(const menu_entry *entries, int sel, void (*draw_more)(void))\r
-{\r
-       const menu_entry *ent, *ent_sel = entries;\r
-       int x, y, w = 0, h = 0;\r
-       int offs, col2_offs = 27 * me_mfont_w;\r
-       int vi_sel_ln = 0;\r
-       const char *name;\r
-       int i, n;\r
-\r
-       /* calculate size of menu rect */\r
-       for (ent = entries, i = n = 0; ent->name; ent++, i++)\r
-       {\r
-               int wt;\r
-\r
-               if (!ent->enabled)\r
-                       continue;\r
-\r
-               if (i == sel) {\r
-                       ent_sel = ent;\r
-                       vi_sel_ln = n;\r
-               }\r
-\r
-               name = NULL;\r
-               wt = strlen(ent->name) * me_mfont_w;\r
-               if (wt == 0 && ent->generate_name)\r
-                       name = ent->generate_name(ent->id, &offs);\r
-               if (name != NULL)\r
-                       wt = strlen(name) * me_mfont_w;\r
-\r
-               if (ent->beh != MB_NONE)\r
-               {\r
-                       if (wt > col2_offs)\r
-                               col2_offs = wt + me_mfont_w;\r
-                       wt = col2_offs;\r
-\r
-                       switch (ent->beh) {\r
-                       case MB_NONE:\r
-                               break;\r
-                       case MB_OPT_ONOFF:\r
-                       case MB_OPT_RANGE:\r
-                               wt += me_mfont_w * 3;\r
-                               break;\r
-                       case MB_OPT_CUSTOM:\r
-                       case MB_OPT_CUSTONOFF:\r
-                       case MB_OPT_CUSTRANGE:\r
-                               name = NULL;\r
-                               offs = 0;\r
-                               if (ent->generate_name != NULL)\r
-                                       name = ent->generate_name(ent->id, &offs);\r
-                               if (name != NULL)\r
-                                       wt += (strlen(name) + offs) * me_mfont_w;\r
-                               break;\r
-                       case MB_OPT_ENUM:\r
-                               wt += 10 * me_mfont_w;\r
-                               break;\r
-                       }\r
-               }\r
-\r
-               if (wt > w)\r
-                       w = wt;\r
-               n++;\r
-       }\r
-       h = n * me_mfont_h;\r
-       w += me_mfont_w * 2; /* selector */\r
-\r
-       if (w > g_menuscreen_w) {\r
-               lprintf("width %d > %d\n", w, g_menuscreen_w);\r
-               w = g_menuscreen_w;\r
-       }\r
-       if (h > g_menuscreen_h) {\r
-               lprintf("height %d > %d\n", w, g_menuscreen_h);\r
-               h = g_menuscreen_h;\r
-       }\r
-\r
-       x = g_menuscreen_w / 2 - w / 2;\r
-       y = g_menuscreen_h / 2 - h / 2;\r
-#ifdef MENU_ALIGN_LEFT\r
-       if (x > 12) x = 12;\r
-#endif\r
-\r
-       /* draw */\r
-       menu_draw_begin(1);\r
-       menu_draw_selection(x, y + vi_sel_ln * me_mfont_h, w);\r
-       x += me_mfont_w * 2;\r
-\r
-       for (ent = entries; ent->name; ent++)\r
-       {\r
-               const char **names;\r
-               int len, leftname_end = 0;\r
-\r
-               if (!ent->enabled)\r
-                       continue;\r
-\r
-               name = ent->name;\r
-               if (strlen(name) == 0) {\r
-                       if (ent->generate_name)\r
-                               name = ent->generate_name(ent->id, &offs);\r
-               }\r
-               if (name != NULL) {\r
-                       text_out16(x, y, name);\r
-                       leftname_end = x + (strlen(name) + 1) * me_mfont_w;\r
-               }\r
-\r
-               switch (ent->beh) {\r
-               case MB_NONE:\r
-                       break;\r
-               case MB_OPT_ONOFF:\r
-                       text_out16(x + col2_offs, y, me_read_onoff(ent) ? "ON" : "OFF");\r
-                       break;\r
-               case MB_OPT_RANGE:\r
-                       text_out16(x + col2_offs, y, "%i", *(int *)ent->var);\r
-                       break;\r
-               case MB_OPT_CUSTOM:\r
-               case MB_OPT_CUSTONOFF:\r
-               case MB_OPT_CUSTRANGE:\r
-                       name = NULL;\r
-                       offs = 0;\r
-                       if (ent->generate_name)\r
-                               name = ent->generate_name(ent->id, &offs);\r
-                       if (name != NULL)\r
-                               text_out16(x + col2_offs + offs * me_mfont_w, y, "%s", name);\r
-                       break;\r
-               case MB_OPT_ENUM:\r
-                       names = (const char **)ent->data;\r
-                       for (i = 0; names[i] != NULL; i++) {\r
-                               offs = x + col2_offs;\r
-                               len = strlen(names[i]);\r
-                               if (len > 10)\r
-                                       offs += (10 - len - 2) * me_mfont_w;\r
-                               if (offs < leftname_end)\r
-                                       offs = leftname_end;\r
-                               if (i == *(unsigned char *)ent->var) {\r
-                                       text_out16(offs, y, "%s", names[i]);\r
-                                       break;\r
-                               }\r
-                       }\r
-                       break;\r
-               }\r
-\r
-               y += me_mfont_h;\r
-       }\r
-\r
-       /* display help or message if we have one */\r
-       h = (g_menuscreen_h - h) / 2; // bottom area height\r
-       if (menu_error_msg[0] != 0) {\r
-               if (h >= me_mfont_h + 4)\r
-                       text_out16(5, g_menuscreen_h - me_mfont_h - 4, menu_error_msg);\r
-               else\r
-                       lprintf("menu msg doesn't fit!\n");\r
-\r
-               if (plat_get_ticks_ms() - menu_error_time > 2048)\r
-                       menu_error_msg[0] = 0;\r
-       }\r
-       else if (ent_sel->help != NULL) {\r
-               const char *tmp = ent_sel->help;\r
-               int l;\r
-               for (l = 0; tmp != NULL && *tmp != 0; l++)\r
-                       tmp = strchr(tmp + 1, '\n');\r
-               if (h >= l * me_sfont_h + 4)\r
-                       for (tmp = ent_sel->help; l > 0; l--, tmp = strchr(tmp, '\n') + 1)\r
-                               smalltext_out16(5, g_menuscreen_h - (l * me_sfont_h + 4), tmp, 0xffff);\r
-       }\r
-\r
-       if (draw_more != NULL)\r
-               draw_more();\r
-\r
-       menu_draw_end();\r
-}\r
-\r
-static int me_process(menu_entry *entry, int is_next, int is_lr)\r
-{\r
-       const char **names;\r
-       int c;\r
-       switch (entry->beh)\r
-       {\r
-               case MB_OPT_ONOFF:\r
-               case MB_OPT_CUSTONOFF:\r
-                       me_toggle_onoff(entry);\r
-                       return 1;\r
-               case MB_OPT_RANGE:\r
-               case MB_OPT_CUSTRANGE:\r
-                       c = is_lr ? 10 : 1;\r
-                       *(int *)entry->var += is_next ? c : -c;\r
-                       if (*(int *)entry->var < (int)entry->min)\r
-                               *(int *)entry->var = (int)entry->max;\r
-                       if (*(int *)entry->var > (int)entry->max)\r
-                               *(int *)entry->var = (int)entry->min;\r
-                       return 1;\r
-               case MB_OPT_ENUM:\r
-                       names = (const char **)entry->data;\r
-                       for (c = 0; names[c] != NULL; c++)\r
-                               ;\r
-                       *(signed char *)entry->var += is_next ? 1 : -1;\r
-                       if (*(signed char *)entry->var < 0)\r
-                               *(signed char *)entry->var = 0;\r
-                       if (*(signed char *)entry->var >= c)\r
-                               *(signed char *)entry->var = c - 1;\r
-                       return 1;\r
-               default:\r
-                       return 0;\r
-       }\r
-}\r
-\r
-static void debug_menu_loop(void);\r
-\r
-static int me_loop_d(menu_entry *menu, int *menu_sel, void (*draw_prep)(void), void (*draw_more)(void))\r
-{\r
-       int ret = 0, inp, sel = *menu_sel, menu_sel_max;\r
-\r
-       menu_sel_max = me_count(menu) - 1;\r
-       if (menu_sel_max < 0) {\r
-               lprintf("no enabled menu entries\n");\r
-               return 0;\r
-       }\r
-\r
-       while ((!menu[sel].enabled || !menu[sel].selectable) && sel < menu_sel_max)\r
-               sel++;\r
-\r
-       /* make sure action buttons are not pressed on entering menu */\r
-       me_draw(menu, sel, NULL);\r
-       while (in_menu_wait_any(NULL, 50) & (PBTN_MOK|PBTN_MBACK|PBTN_MENU));\r
-\r
-       for (;;)\r
-       {\r
-               if (draw_prep != NULL)\r
-                       draw_prep();\r
-\r
-               me_draw(menu, sel, draw_more);\r
-               inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|\r
-                       PBTN_MOK|PBTN_MBACK|PBTN_MENU|PBTN_L|PBTN_R, NULL, 70);\r
-               if (inp & (PBTN_MENU|PBTN_MBACK))\r
-                       break;\r
-\r
-               if (inp & PBTN_UP  ) {\r
-                       do {\r
-                               sel--;\r
-                               if (sel < 0)\r
-                                       sel = menu_sel_max;\r
-                       }\r
-                       while (!menu[sel].enabled || !menu[sel].selectable);\r
-               }\r
-               if (inp & PBTN_DOWN) {\r
-                       do {\r
-                               sel++;\r
-                               if (sel > menu_sel_max)\r
-                                       sel = 0;\r
-                       }\r
-                       while (!menu[sel].enabled || !menu[sel].selectable);\r
-               }\r
-\r
-               /* a bit hacky but oh well */\r
-               if ((inp & (PBTN_L|PBTN_R)) == (PBTN_L|PBTN_R))\r
-                       debug_menu_loop();\r
-\r
-               if (inp & (PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R)) { /* multi choice */\r
-                       if (me_process(&menu[sel], (inp & (PBTN_RIGHT|PBTN_R)) ? 1 : 0,\r
-                                               inp & (PBTN_L|PBTN_R)))\r
-                               continue;\r
-               }\r
-\r
-               if (inp & (PBTN_MOK|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R))\r
-               {\r
-                       /* require PBTN_MOK for MB_NONE */\r
-                       if (menu[sel].handler != NULL && (menu[sel].beh != MB_NONE || (inp & PBTN_MOK))) {\r
-                               ret = menu[sel].handler(menu[sel].id, inp);\r
-                               if (ret) break;\r
-                               menu_sel_max = me_count(menu) - 1; /* might change, so update */\r
-                       }\r
-               }\r
-       }\r
-       *menu_sel = sel;\r
-\r
-       return ret;\r
-}\r
-\r
-static int me_loop(menu_entry *menu, int *menu_sel)\r
-{\r
-       return me_loop_d(menu, menu_sel, NULL, NULL);\r
-}\r
-\r
-/* ***************************************** */\r
-\r
-static void draw_menu_message(const char *msg, void (*draw_more)(void))\r
-{\r
-       int x, y, h, w, wt;\r
-       const char *p;\r
-\r
-       p = msg;\r
-       for (h = 1, w = 0; *p != 0; h++) {\r
-               for (wt = 0; *p != 0 && *p != '\n'; p++)\r
-                       wt++;\r
-\r
-               if (wt > w)\r
-                       w = wt;\r
-               if (*p == 0)\r
-                       break;\r
-               p++;\r
-       }\r
-\r
-       x = g_menuscreen_w / 2 - w * me_mfont_w / 2;\r
-       y = g_menuscreen_h / 2 - h * me_mfont_h / 2;\r
-       if (x < 0) x = 0;\r
-       if (y < 0) y = 0;\r
-\r
-       menu_draw_begin(1);\r
-\r
-       for (p = msg; *p != 0 && y <= g_menuscreen_h - me_mfont_h; y += me_mfont_h) {\r
-               text_out16(x, y, p);\r
-\r
-               for (; *p != 0 && *p != '\n'; p++)\r
-                       ;\r
-               if (*p != 0)\r
-                       p++;\r
-       }\r
-\r
-       if (draw_more != NULL)\r
-               draw_more();\r
-\r
-       menu_draw_end();\r
-}\r
-\r
-// -------------- del confirm ---------------\r
-\r
-static void do_delete(const char *fpath, const char *fname)\r
-{\r
-       int len, mid, inp;\r
-       const char *nm;\r
-       char tmp[64];\r
-\r
-       menu_draw_begin(1);\r
-\r
-       len = strlen(fname);\r
-       if (len > g_menuscreen_w / me_sfont_w)\r
-               len = g_menuscreen_w / me_sfont_w;\r
-\r
-       mid = g_menuscreen_w / 2;\r
-       text_out16(mid - me_mfont_w * 15 / 2,  8 * me_mfont_h, "About to delete");\r
-       smalltext_out16(mid - len * me_sfont_w / 2, 9 * me_mfont_h + 5, fname, 0xbdff);\r
-       text_out16(mid - me_mfont_w * 13 / 2, 11 * me_mfont_h, "Are you sure?");\r
-\r
-       nm = in_get_key_name(-1, -PBTN_MA3);\r
-       snprintf(tmp, sizeof(tmp), "(%s - confirm, ", nm);\r
-       len = strlen(tmp);\r
-       nm = in_get_key_name(-1, -PBTN_MBACK);\r
-       snprintf(tmp + len, sizeof(tmp) - len, "%s - cancel)", nm);\r
-       len = strlen(tmp);\r
-\r
-       text_out16(mid - me_mfont_w * len / 2, 12 * me_mfont_h, tmp);\r
-       menu_draw_end();\r
-\r
-       while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MA2));\r
-       inp = in_menu_wait(PBTN_MA3|PBTN_MBACK, NULL, 100);\r
-       if (inp & PBTN_MA3)\r
-               remove(fpath);\r
-}\r
-\r
-// -------------- ROM selector --------------\r
-\r
-static void draw_dirlist(char *curdir, struct dirent **namelist, int n, int sel)\r
-{\r
-       int max_cnt, start, i, x, pos;\r
-       void *darken_ptr;\r
-\r
-       max_cnt = g_menuscreen_h / me_sfont_h;\r
-       start = max_cnt / 2 - sel;\r
-       n--; // exclude current dir (".")\r
-\r
-       menu_draw_begin(1);\r
-\r
-//     if (!rom_loaded)\r
-//             menu_darken_bg(gp2x_screen, 320*240, 0);\r
-\r
-       darken_ptr = (short *)g_menuscreen_ptr + g_menuscreen_w * max_cnt/2 * me_sfont_h;\r
-       menu_darken_bg(darken_ptr, darken_ptr, g_menuscreen_w * me_sfont_h * 8 / 10, 0);\r
-\r
-       x = 5 + me_mfont_w + 1;\r
-       if (start - 2 >= 0)\r
-               smalltext_out16(14, (start - 2) * me_sfont_h, curdir, 0xffff);\r
-       for (i = 0; i < n; i++) {\r
-               pos = start + i;\r
-               if (pos < 0)  continue;\r
-               if (pos >= max_cnt) break;\r
-               if (namelist[i+1]->d_type == DT_DIR) {\r
-                       smalltext_out16(x, pos * me_sfont_h, "/", 0xfff6);\r
-                       smalltext_out16(x + me_sfont_w, pos * me_sfont_h, namelist[i+1]->d_name, 0xfff6);\r
-               } else {\r
-                       unsigned short color = fname2color(namelist[i+1]->d_name);\r
-                       smalltext_out16(x, pos * me_sfont_h, namelist[i+1]->d_name, color);\r
-               }\r
-       }\r
-       smalltext_out16(5, max_cnt/2 * me_sfont_h, ">", 0xffff);\r
-       menu_draw_end();\r
-}\r
-\r
-static int scandir_cmp(const void *p1, const void *p2)\r
-{\r
-       const struct dirent **d1 = (const struct dirent **)p1;\r
-       const struct dirent **d2 = (const struct dirent **)p2;\r
-       if ((*d1)->d_type == (*d2)->d_type)\r
-               return alphasort(d1, d2);\r
-       if ((*d1)->d_type == DT_DIR)\r
-               return -1; // put before\r
-       if ((*d2)->d_type == DT_DIR)\r
-               return  1;\r
-\r
-       return alphasort(d1, d2);\r
-}\r
-\r
-static int scandir_filter(const struct dirent *ent)\r
-{\r
-       const char *p;\r
-       int i;\r
-\r
-       if (ent == NULL || ent->d_name == NULL) return 0;\r
-       if (strlen(ent->d_name) < 5) return 1;\r
-\r
-       p = ent->d_name + strlen(ent->d_name) - 4;\r
-\r
-       for (i = 0; i < array_size(filter_exts); i++)\r
-               if (strcmp(p, filter_exts[i]) == 0)\r
-                       return 0;\r
-\r
-       return 1;\r
-}\r
-\r
-static int dirent_seek_char(struct dirent **namelist, int len, int sel, char c)\r
-{\r
-       int i;\r
-\r
-       sel++;\r
-       for (i = sel + 1; i != sel; i++) {\r
-               if (i >= len)\r
-                       i = 1;\r
-\r
-               if (tolower_simple(namelist[i]->d_name[0]) == c)\r
-                       break;\r
-       }\r
-\r
-       return i - 1;\r
-}\r
-\r
-static char *menu_loop_romsel(char *curr_path, int len)\r
-{\r
-       struct dirent **namelist;\r
-       int n, inp, sel = 0;\r
-       char *ret = NULL, *fname = NULL;\r
-       char cinp;\r
-\r
-rescan:\r
-       // is this a dir or a full path?\r
-       if (!plat_is_dir(curr_path)) {\r
-               char *p = curr_path + strlen(curr_path) - 1;\r
-               for (; p > curr_path && *p != '/'; p--)\r
-                       ;\r
-               *p = 0;\r
-               fname = p+1;\r
-       }\r
-\r
-       n = scandir(curr_path, &namelist, scandir_filter, (void *)scandir_cmp);\r
-       if (n < 0) {\r
-               char *t;\r
-               lprintf("menu_loop_romsel failed, dir: %s\n", curr_path);\r
-\r
-               // try root\r
-               t = getcwd(curr_path, len);\r
-               if (t == NULL)\r
-                       plat_get_root_dir(curr_path, len);\r
-               n = scandir(curr_path, &namelist, scandir_filter, (void *)scandir_cmp);\r
-               if (n < 0) {\r
-                       // oops, we failed\r
-                       lprintf("menu_loop_romsel failed, dir: %s\n", curr_path);\r
-                       return NULL;\r
-               }\r
-       }\r
-\r
-       // try to find sel\r
-       // note: we don't show '.' so sel is namelist index - 1\r
-       if (fname != NULL) {\r
-               int i;\r
-               for (i = 1; i < n; i++) {\r
-                       char *dname = namelist[i]->d_name;\r
-                       if (dname[0] == fname[0] && strcmp(dname, fname) == 0) {\r
-                               sel = i - 1;\r
-                               break;\r
-                       }\r
-               }\r
-       }\r
-\r
-       /* make sure action buttons are not pressed on entering menu */\r
-       draw_dirlist(curr_path, namelist, n, sel);\r
-       while (in_menu_wait_any(NULL, 50) & (PBTN_MOK|PBTN_MBACK|PBTN_MENU))\r
-               ;\r
-\r
-       for (;;)\r
-       {\r
-               draw_dirlist(curr_path, namelist, n, sel);\r
-               inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|\r
-                       PBTN_L|PBTN_R|PBTN_MA2|PBTN_MOK|PBTN_MBACK|PBTN_MENU|PBTN_CHAR, &cinp, 33);\r
-               if (inp & PBTN_UP  )  { sel--;   if (sel < 0)   sel = n-2; }\r
-               if (inp & PBTN_DOWN)  { sel++;   if (sel > n-2) sel = 0; }\r
-               if (inp & PBTN_LEFT)  { sel-=10; if (sel < 0)   sel = 0; }\r
-               if (inp & PBTN_L)     { sel-=24; if (sel < 0)   sel = 0; }\r
-               if (inp & PBTN_RIGHT) { sel+=10; if (sel > n-2) sel = n-2; }\r
-               if (inp & PBTN_R)     { sel+=24; if (sel > n-2) sel = n-2; }\r
-               if (inp & PBTN_CHAR)  sel = dirent_seek_char(namelist, n, sel, cinp);\r
-               if ((inp & PBTN_MOK) || (inp & (PBTN_MENU|PBTN_MA2)) == (PBTN_MENU|PBTN_MA2))\r
-               {\r
-                       again:\r
-                       if (namelist[sel+1]->d_type == DT_REG)\r
-                       {\r
-                               strcpy(rom_fname_reload, curr_path);\r
-                               strcat(rom_fname_reload, "/");\r
-                               strcat(rom_fname_reload, namelist[sel+1]->d_name);\r
-                               if (inp & PBTN_MOK) { // return sel\r
-                                       ret = rom_fname_reload;\r
-                                       break;\r
-                               }\r
-                               do_delete(rom_fname_reload, namelist[sel+1]->d_name);\r
-                               if (n > 0) {\r
-                                       while (n--) free(namelist[n]);\r
-                                       free(namelist);\r
-                               }\r
-                               goto rescan;\r
-                       }\r
-                       else if (namelist[sel+1]->d_type == DT_DIR)\r
-                       {\r
-                               int newlen;\r
-                               char *p, *newdir;\r
-                               if (!(inp & PBTN_MOK))\r
-                                       continue;\r
-                               newlen = strlen(curr_path) + strlen(namelist[sel+1]->d_name) + 2;\r
-                               newdir = malloc(newlen);\r
-                               if (newdir == NULL)\r
-                                       break;\r
-                               if (strcmp(namelist[sel+1]->d_name, "..") == 0) {\r
-                                       char *start = curr_path;\r
-                                       p = start + strlen(start) - 1;\r
-                                       while (*p == '/' && p > start) p--;\r
-                                       while (*p != '/' && p > start) p--;\r
-                                       if (p <= start) strcpy(newdir, "/");\r
-                                       else { strncpy(newdir, start, p-start); newdir[p-start] = 0; }\r
-                               } else {\r
-                                       strcpy(newdir, curr_path);\r
-                                       p = newdir + strlen(newdir) - 1;\r
-                                       while (*p == '/' && p >= newdir) *p-- = 0;\r
-                                       strcat(newdir, "/");\r
-                                       strcat(newdir, namelist[sel+1]->d_name);\r
-                               }\r
-                               ret = menu_loop_romsel(newdir, newlen);\r
-                               free(newdir);\r
-                               break;\r
-                       }\r
-                       else\r
-                       {\r
-                               // unknown file type, happens on NTFS mounts. Try to guess.\r
-                               FILE *tstf; int tmp;\r
-                               strcpy(rom_fname_reload, curr_path);\r
-                               strcat(rom_fname_reload, "/");\r
-                               strcat(rom_fname_reload, namelist[sel+1]->d_name);\r
-                               tstf = fopen(rom_fname_reload, "rb");\r
-                               if (tstf != NULL)\r
-                               {\r
-                                       if (fread(&tmp, 1, 1, tstf) > 0 || ferror(tstf) == 0)\r
-                                               namelist[sel+1]->d_type = DT_REG;\r
-                                       else    namelist[sel+1]->d_type = DT_DIR;\r
-                                       fclose(tstf);\r
-                                       goto again;\r
-                               }\r
-                       }\r
-               }\r
-               if (inp & PBTN_MBACK)\r
-                       break;\r
-       }\r
-\r
-       if (n > 0) {\r
-               while (n--) free(namelist[n]);\r
-               free(namelist);\r
-       }\r
-\r
-       // restore curr_path\r
-       if (fname != NULL) {\r
-               n = strlen(curr_path);\r
-               if (curr_path + n + 1 == fname)\r
-                       curr_path[n] = '/';\r
-       }\r
-\r
-       return ret;\r
-}\r
-\r
-// ------------ savestate loader ------------\r
-\r
-#define STATE_SLOT_COUNT 10\r
-\r
-static int state_slot_flags = 0;\r
-static int state_slot_times[STATE_SLOT_COUNT];\r
-\r
-static void state_check_slots(void)\r
-{\r
-       int slot;\r
-\r
-       state_slot_flags = 0;\r
-\r
-       for (slot = 0; slot < STATE_SLOT_COUNT; slot++) {\r
-               state_slot_times[slot] = 0;\r
-               if (emu_check_save_file(slot, &state_slot_times[slot]))\r
-                       state_slot_flags |= 1 << slot;\r
-       }\r
-}\r
-\r
-static void draw_savestate_bg(int slot);\r
-\r
-static void draw_savestate_menu(int menu_sel, int is_loading)\r
-{\r
-       int i, x, y, w, h;\r
-       char time_buf[32];\r
-\r
-       if (state_slot_flags & (1 << menu_sel))\r
-               draw_savestate_bg(menu_sel);\r
-\r
-       w = (13 + 2) * me_mfont_w;\r
-       h = (1+2+STATE_SLOT_COUNT+1) * me_mfont_h;\r
-       x = g_menuscreen_w / 2 - w / 2;\r
-       if (x < 0) x = 0;\r
-       y = g_menuscreen_h / 2 - h / 2;\r
-       if (y < 0) y = 0;\r
-#ifdef MENU_ALIGN_LEFT\r
-       if (x > 12 + me_mfont_w * 2)\r
-               x = 12 + me_mfont_w * 2;\r
-#endif\r
-\r
-       menu_draw_begin(1);\r
-\r
-       text_out16(x, y, is_loading ? "Load state" : "Save state");\r
-       y += 3 * me_mfont_h;\r
-\r
-       menu_draw_selection(x - me_mfont_w * 2, y + menu_sel * me_mfont_h, (23 + 2) * me_mfont_w + 4);\r
-\r
-       /* draw all slots */\r
-       for (i = 0; i < STATE_SLOT_COUNT; i++, y += me_mfont_h)\r
-       {\r
-               if (!(state_slot_flags & (1 << i)))\r
-                       strcpy(time_buf, "free");\r
-               else {\r
-                       strcpy(time_buf, "USED");\r
-                       if (state_slot_times[i] != 0) {\r
-                               time_t time = state_slot_times[i];\r
-                               struct tm *t = localtime(&time);\r
-                               strftime(time_buf, sizeof(time_buf), "%x %R", t);\r
-                       }\r
-               }\r
-\r
-               text_out16(x, y, "SLOT %i (%s)", i, time_buf);\r
-       }\r
-       text_out16(x, y, "back");\r
-\r
-       menu_draw_end();\r
-}\r
-\r
-static int menu_loop_savestate(int is_loading)\r
-{\r
-       static int menu_sel = STATE_SLOT_COUNT;\r
-       int menu_sel_max = STATE_SLOT_COUNT;\r
-       unsigned long inp = 0;\r
-       int ret = 0;\r
-\r
-       state_check_slots();\r
-\r
-       if (!(state_slot_flags & (1 << menu_sel)) && is_loading)\r
-               menu_sel = menu_sel_max;\r
-\r
-       for (;;)\r
-       {\r
-               draw_savestate_menu(menu_sel, is_loading);\r
-               inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_MOK|PBTN_MBACK, NULL, 100);\r
-               if (inp & PBTN_UP) {\r
-                       do {\r
-                               menu_sel--;\r
-                               if (menu_sel < 0)\r
-                                       menu_sel = menu_sel_max;\r
-                       } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading);\r
-               }\r
-               if (inp & PBTN_DOWN) {\r
-                       do {\r
-                               menu_sel++;\r
-                               if (menu_sel > menu_sel_max)\r
-                                       menu_sel = 0;\r
-                       } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading);\r
-               }\r
-               if (inp & PBTN_MOK) { // save/load\r
-                       if (menu_sel < STATE_SLOT_COUNT) {\r
-                               state_slot = menu_sel;\r
-                               if (emu_save_load_game(is_loading, 0)) {\r
-                                       me_update_msg(is_loading ? "Load failed" : "Save failed");\r
-                                       break;\r
-                               }\r
-                               ret = 1;\r
-                               break;\r
-                       }\r
-                       break;\r
-               }\r
-               if (inp & PBTN_MBACK)\r
-                       break;\r
-       }\r
-\r
-       return ret;\r
-}\r
-\r
-// -------------- key config --------------\r
-\r
-static char *action_binds(int player_idx, int action_mask, int dev_id)\r
-{\r
-       int dev = 0, dev_last = IN_MAX_DEVS - 1;\r
-       int can_combo = 1, type;\r
-\r
-       static_buff[0] = 0;\r
-\r
-       type = IN_BINDTYPE_EMU;\r
-       if (player_idx >= 0) {\r
-               can_combo = 0;\r
-               type = IN_BINDTYPE_PLAYER12;\r
-       }\r
-       if (player_idx == 1)\r
-               action_mask <<= 16;\r
-\r
-       if (dev_id >= 0)\r
-               dev = dev_last = dev_id;\r
-\r
-       for (; dev <= dev_last; dev++) {\r
-               int k, count = 0, combo = 0;\r
-               const int *binds;\r
-\r
-               binds = in_get_dev_binds(dev);\r
-               if (binds == NULL)\r
-                       continue;\r
-\r
-               in_get_config(dev, IN_CFG_BIND_COUNT, &count);\r
-               in_get_config(dev, IN_CFG_DOES_COMBOS, &combo);\r
-               combo = combo && can_combo;\r
-\r
-               for (k = 0; k < count; k++) {\r
-                       const char *xname;\r
-                       int len;\r
-\r
-                       if (!(binds[IN_BIND_OFFS(k, type)] & action_mask))\r
-                               continue;\r
-\r
-                       xname = in_get_key_name(dev, k);\r
-                       len = strlen(static_buff);\r
-                       if (len) {\r
-                               strncat(static_buff, combo ? " + " : ", ",\r
-                                       sizeof(static_buff) - len - 1);\r
-                               len += combo ? 3 : 2;\r
-                       }\r
-                       strncat(static_buff, xname, sizeof(static_buff) - len - 1);\r
-               }\r
-       }\r
-\r
-       return static_buff;\r
-}\r
-\r
-static int count_bound_keys(int dev_id, int action_mask, int bindtype)\r
-{\r
-       const int *binds;\r
-       int k, keys = 0;\r
-       int count = 0;\r
-\r
-       binds = in_get_dev_binds(dev_id);\r
-       if (binds == NULL)\r
-               return 0;\r
-\r
-       in_get_config(dev_id, IN_CFG_BIND_COUNT, &count);\r
-       for (k = 0; k < count; k++)\r
-       {\r
-               if (binds[IN_BIND_OFFS(k, bindtype)] & action_mask)\r
-                       keys++;\r
-       }\r
-\r
-       return keys;\r
-}\r
-\r
-static void draw_key_config(const me_bind_action *opts, int opt_cnt, int player_idx,\r
-               int sel, int dev_id, int dev_count, int is_bind)\r
-{\r
-       char buff[64], buff2[32];\r
-       const char *dev_name;\r
-       int x, y, w, i;\r
-\r
-       w = ((player_idx >= 0) ? 20 : 30) * me_mfont_w;\r
-       x = g_menuscreen_w / 2 - w / 2;\r
-       y = (g_menuscreen_h - 4 * me_mfont_h) / 2 - (2 + opt_cnt) * me_mfont_h / 2;\r
-       if (x < me_mfont_w * 2)\r
-               x = me_mfont_w * 2;\r
-\r
-       menu_draw_begin(1);\r
-       if (player_idx >= 0)\r
-               text_out16(x, y, "Player %i controls", player_idx + 1);\r
-       else\r
-               text_out16(x, y, "Emulator controls");\r
-\r
-       y += 2 * me_mfont_h;\r
-       menu_draw_selection(x - me_mfont_w * 2, y + sel * me_mfont_h, w + 2 * me_mfont_w);\r
-\r
-       for (i = 0; i < opt_cnt; i++, y += me_mfont_h)\r
-               text_out16(x, y, "%s : %s", opts[i].name,\r
-                       action_binds(player_idx, opts[i].mask, dev_id));\r
-\r
-       if (dev_id < 0)\r
-               dev_name = "(all devices)";\r
-       else\r
-               dev_name = in_get_dev_name(dev_id, 1, 1);\r
-       w = strlen(dev_name) * me_mfont_w;\r
-       if (w < 30 * me_mfont_w)\r
-               w = 30 * me_mfont_w;\r
-       if (w > g_menuscreen_w)\r
-               w = g_menuscreen_w;\r
-\r
-       x = g_menuscreen_w / 2 - w / 2;\r
-\r
-       if (!is_bind) {\r
-               snprintf(buff2, sizeof(buff2), "%s", in_get_key_name(-1, -PBTN_MOK));\r
-               snprintf(buff, sizeof(buff), "%s - bind, %s - clear", buff2,\r
-                               in_get_key_name(-1, -PBTN_MA2));\r
-               text_out16(x, g_menuscreen_h - 4 * me_mfont_h, buff);\r
-       }\r
-       else\r
-               text_out16(x, g_menuscreen_h - 4 * me_mfont_h, "Press a button to bind/unbind");\r
-\r
-       if (dev_count > 1) {\r
-               text_out16(x, g_menuscreen_h - 3 * me_mfont_h, dev_name);\r
-               text_out16(x, g_menuscreen_h - 2 * me_mfont_h, "Press left/right for other devs");\r
-       }\r
-\r
-       menu_draw_end();\r
-}\r
-\r
-static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_idx)\r
-{\r
-       int i, sel = 0, menu_sel_max = opt_cnt - 1, does_combos = 0;\r
-       int dev_id, bind_dev_id, dev_count, kc, is_down, mkey;\r
-       int unbind, bindtype, mask_shift;\r
-\r
-       for (i = 0, dev_id = -1, dev_count = 0; i < IN_MAX_DEVS; i++) {\r
-               if (in_get_dev_name(i, 1, 0) != NULL) {\r
-                       dev_count++;\r
-                       if (dev_id < 0)\r
-                               dev_id = i;\r
-               }\r
-       }\r
-\r
-       if (dev_id == -1) {\r
-               lprintf("no devs, can't do config\n");\r
-               return;\r
-       }\r
-\r
-       dev_id = -1; // show all\r
-       mask_shift = 0;\r
-       if (player_idx == 1)\r
-               mask_shift = 16;\r
-       bindtype = player_idx >= 0 ? IN_BINDTYPE_PLAYER12 : IN_BINDTYPE_EMU;\r
-\r
-       for (;;)\r
-       {\r
-               draw_key_config(opts, opt_cnt, player_idx, sel, dev_id, dev_count, 0);\r
-               mkey = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT\r
-                               |PBTN_MBACK|PBTN_MOK|PBTN_MA2, NULL, 100);\r
-               switch (mkey) {\r
-                       case PBTN_UP:   sel--; if (sel < 0) sel = menu_sel_max; continue;\r
-                       case PBTN_DOWN: sel++; if (sel > menu_sel_max) sel = 0; continue;\r
-                       case PBTN_LEFT:\r
-                               for (i = 0, dev_id--; i < IN_MAX_DEVS + 1; i++, dev_id--) {\r
-                                       if (dev_id < -1)\r
-                                               dev_id = IN_MAX_DEVS - 1;\r
-                                       if (dev_id == -1 || in_get_dev_name(dev_id, 1, 0) != NULL)\r
-                                               break;\r
-                               }\r
-                               continue;\r
-                       case PBTN_RIGHT:\r
-                               for (i = 0, dev_id++; i < IN_MAX_DEVS; i++, dev_id++) {\r
-                                       if (dev_id >= IN_MAX_DEVS)\r
-                                               dev_id = -1;\r
-                                       if (dev_id == -1 || in_get_dev_name(dev_id, 1, 0) != NULL)\r
-                                               break;\r
-                               }\r
-                               continue;\r
-                       case PBTN_MBACK:\r
-                               return;\r
-                       case PBTN_MOK:\r
-                               if (sel >= opt_cnt)\r
-                                       return;\r
-                               while (in_menu_wait_any(NULL, 30) & PBTN_MOK)\r
-                                       ;\r
-                               break;\r
-                       case PBTN_MA2:\r
-                               in_unbind_all(dev_id, opts[sel].mask << mask_shift, bindtype);\r
-                               continue;\r
-                       default:continue;\r
-               }\r
-\r
-               draw_key_config(opts, opt_cnt, player_idx, sel, dev_id, dev_count, 1);\r
-\r
-               /* wait for some up event */\r
-               for (is_down = 1; is_down; )\r
-                       kc = in_update_keycode(&bind_dev_id, &is_down, NULL, -1);\r
-\r
-               i = count_bound_keys(bind_dev_id, opts[sel].mask << mask_shift, bindtype);\r
-               unbind = (i > 0);\r
-\r
-               /* allow combos if device supports them */\r
-               in_get_config(bind_dev_id, IN_CFG_DOES_COMBOS, &does_combos);\r
-               if (i == 1 && bindtype == IN_BINDTYPE_EMU && does_combos)\r
-                       unbind = 0;\r
-\r
-               if (unbind)\r
-                       in_unbind_all(bind_dev_id, opts[sel].mask << mask_shift, bindtype);\r
-\r
-               in_bind_key(bind_dev_id, kc, opts[sel].mask << mask_shift, bindtype, 0);\r
-       }\r
-}\r
-\r
diff --git a/frontend/common/menu.h b/frontend/common/menu.h
deleted file mode 100644 (file)
index 79b8278..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * (C) Gražvydas "notaz" Ignotas, 2006-2010
- *
- * This work is licensed under the terms of any of these licenses
- * (at your option):
- *  - GNU GPL, version 2 or later.
- *  - GNU LGPL, version 2.1 or later.
- * See the COPYING file in the top-level directory.
- */
-
-typedef enum
-{
-       MB_NONE = 1,            /* no auto processing */
-       MB_OPT_ONOFF,           /* ON/OFF setting */
-       MB_OPT_RANGE,           /* [min-max] setting */
-       MB_OPT_CUSTOM,          /* custom value */
-       MB_OPT_CUSTONOFF,
-       MB_OPT_CUSTRANGE,
-       MB_OPT_ENUM,
-} menu_behavior;
-
-typedef struct
-{
-       const char *name;
-       menu_behavior beh;
-       int id;
-       void *var;              /* for on-off/range settings */
-       int mask;               /* bit to toggle for on/off */
-       signed short min;       /* for ranged integer settings, to be sign-extended */
-       signed short max;
-       unsigned int enabled:1;
-       unsigned int need_to_save:1;
-       unsigned int selectable:1;
-       int (*handler)(int id, int keys);
-       const char * (*generate_name)(int id, int *offs);
-       const void *data;
-       const char *help;
-} menu_entry;
-
-#define mee_handler_id_h(name, id, handler, help) \
-       { name, MB_NONE, id, NULL, 0, 0, 0, 1, 0, 1, handler, NULL, NULL, help }
-
-#define mee_handler_id(name, id, handler) \
-       mee_handler_id_h(name, id, handler, NULL)
-
-#define mee_handler(name, handler) \
-       mee_handler_id(name, MA_NONE, handler)
-
-#define mee_handler_h(name, handler, help) \
-       mee_handler_id_h(name, MA_NONE, handler, help)
-
-#define mee_label(name) \
-       { name, MB_NONE, MA_NONE, NULL, 0, 0, 0, 1, 0, 0, NULL, NULL, NULL, NULL }
-
-#define mee_label_mk(id, name_func) \
-       { "", MB_NONE, id, NULL, 0, 0, 0, 1, 0, 0, NULL, name_func, NULL, NULL }
-
-#define mee_onoff_h(name, id, var, mask, help) \
-       { name, MB_OPT_ONOFF, id, &(var), mask, 0, 0, 1, 1, 1, NULL, NULL, NULL, help }
-
-#define mee_onoff(name, id, var, mask) \
-       mee_onoff_h(name, id, var, mask, NULL)
-
-#define mee_range_h(name, id, var, min, max, help) \
-       { name, MB_OPT_RANGE, id, &(var), 0, min, max, 1, 1, 1, NULL, NULL, NULL, help }
-
-#define mee_range(name, id, var, min, max) \
-       mee_range_h(name, id, var, min, max, NULL)
-
-#define mee_range_hide(name, id, var, min, max) \
-       { name, MB_OPT_RANGE, id, &(var), 0, min, max, 0, 1, 0, NULL, NULL, NULL, NULL }
-
-#define mee_cust_s_h(name, id, need_save, handler, name_func, help) \
-       { name, MB_OPT_CUSTOM, id, NULL, 0, 0, 0, 1, need_save, 1, handler, name_func, NULL, help }
-
-#define mee_cust_h(name, id, handler, name_func, help) \
-       mee_cust_s_h(name, id, 1, handler, name_func, help)
-
-#define mee_cust(name, id, handler, name_func) \
-       mee_cust_h(name, id, handler, name_func, NULL)
-
-#define mee_cust_nosave(name, id, handler, name_func) \
-       mee_cust_s_h(name, id, 0, handler, name_func, NULL)
-
-#define mee_onoff_cust(name, id, var, mask, name_func) \
-       { name, MB_OPT_CUSTONOFF, id, &(var), mask, 0, 0, 1, 1, 1, NULL, name_func, NULL, NULL }
-
-#define mee_range_cust(name, id, var, min, max, name_func) \
-       { name, MB_OPT_CUSTRANGE, id, &(var), 0, min, max, 1, 1, 1, NULL, name_func, NULL, NULL }
-
-#define mee_enum_h(name, id, var, names_list, help) \
-       { name, MB_OPT_ENUM, id, &(var), 0, 0, 0, 1, 1, 1, NULL, NULL, names_list, help }
-
-#define mee_enum(name, id, var, names_list) \
-       mee_enum_h(name, id, var, names_list, NULL)
-
-#define mee_end \
-       { NULL, 0, 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
-
-typedef struct
-{
-       char *name;
-       int mask;
-} me_bind_action;
-
-extern me_bind_action me_ctrl_actions[];
-extern me_bind_action emuctrl_actions[];       // platform code
-
-extern void *g_menubg_src_ptr;
-extern void *g_menubg_ptr;
-extern void *g_menuscreen_ptr;
-#if MSCREEN_SIZE_FIXED
-#define g_menuscreen_w MSCREEN_WIDTH
-#define g_menuscreen_h MSCREEN_HEIGHT
-#else
-extern int g_menuscreen_w;
-extern int g_menuscreen_h;
-#endif
-
-void menu_init(void);
-void text_out16(int x, int y, const char *texto, ...);
-void me_update_msg(const char *msg);
-
-void menu_romload_prepare(const char *rom_name);
-void menu_romload_end(void);
-
-void menu_loop(void);
-int  menu_loop_tray(void);
-
-menu_entry *me_list_get_first(void);
-menu_entry *me_list_get_next(void);
-
diff --git a/frontend/common/plat.h b/frontend/common/plat.h
deleted file mode 100644 (file)
index 0a9fc0b..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* stuff to be implemented by platform code */
-extern const char *renderer_names[];
-extern const char *renderer_names32x[];
-
-void pemu_prep_defconfig(void);
-void pemu_validate_config(void);
-void pemu_loop_prep(void);
-void pemu_loop_end(void);
-void pemu_forced_frame(int no_scale, int do_emu); // ..to g_menubg_src_ptr
-void pemu_finalize_frame(const char *fps, const char *notice_msg);
-
-void pemu_sound_start(void);
-void pemu_sound_stop(void);
-void pemu_sound_wait(void);
-
-void plat_early_init(void);
-void plat_init(void);
-void plat_finish(void);
-
-/* return the dir/ where configs, saves, bios, etc. are found */
-int  plat_get_root_dir(char *dst, int len);
-
-/* used before things blocking for a while (these funcs redraw on return) */
-void plat_status_msg_busy_first(const char *msg);
-void plat_status_msg_busy_next(const char *msg);
-void plat_status_msg_clear(void);
-
-/* menu: enter (switch bpp, etc), begin/end drawing */
-void plat_video_menu_enter(int is_rom_loaded);
-void plat_video_menu_begin(void);
-void plat_video_menu_end(void);
-void plat_video_menu_leave(void);
-
-void plat_video_flip(void);
-void plat_video_wait_vsync(void);
-void plat_video_toggle_renderer(int change, int menu_call);
-
-void plat_update_volume(int has_changed, int is_up);
-
-int  plat_is_dir(const char *path);
-int  plat_wait_event(int *fds_hnds, int count, int timeout_ms);
-void plat_sleep_ms(int ms);
-
-/* timers, to be used for time diff and must refer to the same clock */
-unsigned int plat_get_ticks_ms(void);
-unsigned int plat_get_ticks_us(void);
-void plat_wait_till_us(unsigned int us);
-
-void plat_debug_cat(char *str);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
diff --git a/frontend/common/posix.h b/frontend/common/posix.h
deleted file mode 100644 (file)
index 33ca96c..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* define POSIX stuff: dirent, scandir, getcwd, mkdir */
-#if defined(__linux__) || defined(__MINGW32__)
-
-#include <dirent.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#ifdef __MINGW32__
-#warning hacks!
-#define mkdir(pathname,mode) mkdir(pathname)
-#define d_type d_ino
-#define DT_REG 0
-#define DT_DIR 0
-#endif
-
-#else
-
-#error "must provide posix"
-
-#endif
-
-
diff --git a/frontend/common/readpng.c b/frontend/common/readpng.c
deleted file mode 100644 (file)
index 722dc26..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * (C) Gražvydas "notaz" Ignotas, 2008-2011
- *
- * This work is licensed under the terms of any of these licenses
- * (at your option):
- *  - GNU GPL, version 2 or later.
- *  - GNU LGPL, version 2.1 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <png.h>
-#include "readpng.h"
-#include "lprintf.h"
-
-int readpng(void *dest, const char *fname, readpng_what what, int req_w, int req_h)
-{
-       FILE *fp;
-       png_structp png_ptr = NULL;
-       png_infop info_ptr = NULL;
-       png_bytepp row_ptr = NULL;
-       int ret = -1;
-
-       if (dest == NULL || fname == NULL)
-       {
-               return -1;
-       }
-
-       fp = fopen(fname, "rb");
-       if (fp == NULL)
-       {
-               lprintf(__FILE__ ": failed to open: %s\n", fname);
-               return -1;
-       }
-
-       png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-       if (!png_ptr)
-       {
-               lprintf(__FILE__ ": png_create_read_struct() failed\n");
-               fclose(fp);
-               return -1;
-       }
-
-       info_ptr = png_create_info_struct(png_ptr);
-       if (!info_ptr)
-       {
-               lprintf(__FILE__ ": png_create_info_struct() failed\n");
-               goto done;
-       }
-
-       // Start reading
-       png_init_io(png_ptr, fp);
-       png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_PACKING, NULL);
-       row_ptr = png_get_rows(png_ptr, info_ptr);
-       if (row_ptr == NULL)
-       {
-               lprintf(__FILE__ ": png_get_rows() failed\n");
-               goto done;
-       }
-
-       // lprintf("%s: %ix%i @ %ibpp\n", fname, (int)png_get_image_width(png_ptr, info_ptr), (int)png_get_image_height(png_ptr, info_ptr), png_get_bit_depth(png_ptr, info_ptr));
-
-       switch (what)
-       {
-               case READPNG_BG:
-               {
-                       int height, width, h;
-                       unsigned short *dst = dest;
-                       if (png_get_bit_depth(png_ptr, info_ptr) != 8)
-                       {
-                               lprintf(__FILE__ ": bg image uses %ibpc, needed 8bpc\n", png_get_bit_depth(png_ptr, info_ptr));
-                               break;
-                       }
-                       width = png_get_image_width(png_ptr, info_ptr);
-                       if (width > req_w)
-                               width = req_w;
-                       height = png_get_image_height(png_ptr, info_ptr);
-                       if (height > req_h)
-                               height = req_h;
-
-                       for (h = 0; h < height; h++)
-                       {
-                               unsigned char *src = row_ptr[h];
-                               int len = width;
-                               while (len--)
-                               {
-#ifdef PSP
-                                       *dst++ = ((src[2]&0xf8)<<8) | ((src[1]&0xf8)<<3) | (src[0] >> 3); // BGR
-#else
-                                       *dst++ = ((src[0]&0xf8)<<8) | ((src[1]&0xf8)<<3) | (src[2] >> 3); // RGB
-#endif
-                                       src += 3;
-                               }
-                               dst += req_w - width;
-                       }
-                       break;
-               }
-
-               case READPNG_FONT:
-               {
-                       int x, y, x1, y1;
-                       unsigned char *dst = dest;
-                       if (png_get_image_width(png_ptr, info_ptr) != req_w || png_get_image_height(png_ptr, info_ptr) != req_h)
-                       {
-                               lprintf(__FILE__ ": unexpected font image size %dx%d, needed %dx%d\n",
-                                       (int)png_get_image_width(png_ptr, info_ptr), (int)png_get_image_height(png_ptr, info_ptr), req_w, req_h);
-                               break;
-                       }
-                       if (png_get_bit_depth(png_ptr, info_ptr) != 8)
-                       {
-                               lprintf(__FILE__ ": font image uses %ibpp, needed 8bpp\n", png_get_bit_depth(png_ptr, info_ptr));
-                               break;
-                       }
-                       for (y = 0; y < 16; y++)
-                       {
-                               for (x = 0; x < 16; x++)
-                               {
-                                       /* 16x16 grid of syms */
-                                       int sym_w = req_w / 16;
-                                       int sym_h = req_h / 16;
-                                       for (y1 = 0; y1 < sym_h; y1++)
-                                       {
-                                               unsigned char *src = row_ptr[y*sym_h + y1] + x*sym_w;
-                                               for (x1 = sym_w/2; x1 > 0; x1--, src+=2)
-                                                       *dst++ = ((src[0]^0xff) & 0xf0) | ((src[1]^0xff) >> 4);
-                                       }
-                               }
-                       }
-                       break;
-               }
-
-               case READPNG_SELECTOR:
-               {
-                       int x1, y1;
-                       unsigned char *dst = dest;
-                       if (png_get_image_width(png_ptr, info_ptr) != req_w || png_get_image_height(png_ptr, info_ptr) != req_h)
-                       {
-                               lprintf(__FILE__ ": unexpected selector image size %ix%i, needed %dx%d\n",
-                                       (int)png_get_image_width(png_ptr, info_ptr), (int)png_get_image_height(png_ptr, info_ptr), req_w, req_h);
-                               break;
-                       }
-                       if (png_get_bit_depth(png_ptr, info_ptr) != 8)
-                       {
-                               lprintf(__FILE__ ": selector image uses %ibpp, needed 8bpp\n", png_get_bit_depth(png_ptr, info_ptr));
-                               break;
-                       }
-                       for (y1 = 0; y1 < req_h; y1++)
-                       {
-                               unsigned char *src = row_ptr[y1];
-                               for (x1 = req_w/2; x1 > 0; x1--, src+=2)
-                                       *dst++ = ((src[0]^0xff) & 0xf0) | ((src[1]^0xff) >> 4);
-                       }
-                       break;
-               }
-
-               case READPNG_24:
-               {
-                       int height, width, h;
-                       unsigned char *dst = dest;
-                       if (png_get_bit_depth(png_ptr, info_ptr) != 8)
-                       {
-                               lprintf(__FILE__ ": image uses %ibpc, needed 8bpc\n", png_get_bit_depth(png_ptr, info_ptr));
-                               break;
-                       }
-                       width = png_get_image_width(png_ptr, info_ptr);
-                       if (width > req_w)
-                               width = req_w;
-                       height = png_get_image_height(png_ptr, info_ptr);
-                       if (height > req_h)
-                               height = req_h;
-
-                       for (h = 0; h < height; h++)
-                       {
-                               int len = width;
-                               unsigned char *src = row_ptr[h];
-                               dst += (req_w - width) * 3;
-                               for (len = width; len > 0; len--, dst+=3, src+=3)
-                                       dst[0] = src[2], dst[1] = src[1], dst[2] = src[0];
-                       }
-                       break;
-               }
-       }
-
-
-       ret = 0;
-done:
-       png_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : NULL, (png_infopp)NULL);
-       fclose(fp);
-       return ret;
-}
-
-int writepng(const char *fname, unsigned short *src, int w, int h)
-{
-       png_structp png_ptr = NULL;
-       png_infop info_ptr = NULL;
-       png_bytepp row_pointers;
-       int i, j, ret = -1;
-       FILE *f;
-
-       f = fopen(fname, "wb");
-       if (f == NULL) {
-               lprintf(__FILE__ ": failed to open \"%s\"\n", fname);
-               return -1;
-       }
-
-       row_pointers = calloc(h, sizeof(row_pointers[0]));
-       if (row_pointers == NULL)
-               goto end1;
-
-       for (i = 0; i < h; i++) {
-               unsigned char *dst = malloc(w * 3);
-               if (dst == NULL)
-                       goto end2;
-               row_pointers[i] = dst;
-               for (j = 0; j < w; j++, src++, dst += 3) {
-                       dst[0] = (*src & 0xf800) >> 8;
-                       dst[1] = (*src & 0x07e0) >> 3;
-                       dst[2] = (*src & 0x001f) << 3;
-               }
-       }
-
-       /* initialize stuff */
-       png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-       if (png_ptr == NULL) {
-               fprintf(stderr, "png_create_write_struct() failed");
-               goto end2;
-       }
-
-       info_ptr = png_create_info_struct(png_ptr);
-       if (info_ptr == NULL) {
-               fprintf(stderr, "png_create_info_struct() failed");
-               goto end3;
-       }
-
-       if (setjmp(png_jmpbuf(png_ptr)) != 0) {
-               fprintf(stderr, "error in png code\n");
-               goto end4;
-       }
-
-       png_init_io(png_ptr, f);
-
-       png_set_IHDR(png_ptr, info_ptr, w, h,
-               8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
-               PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
-
-       png_write_info(png_ptr, info_ptr);
-       png_write_image(png_ptr, row_pointers);
-       png_write_end(png_ptr, NULL);
-
-       ret = 0;
-
-end4:
-//     png_destroy_info_struct(png_ptr, &info_ptr); // freed below
-end3:
-       png_destroy_write_struct(&png_ptr, &info_ptr);
-end2:
-       for (i = 0; i < h; i++)
-               free(row_pointers[i]);
-       free(row_pointers);
-end1:
-       fclose(f);
-       return ret;
-}
-
diff --git a/frontend/common/readpng.h b/frontend/common/readpng.h
deleted file mode 100644 (file)
index 924b341..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-typedef enum
-{
-       READPNG_BG = 1,
-       READPNG_FONT,
-       READPNG_SELECTOR,
-       READPNG_24,
-}
-readpng_what;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int readpng(void *dest, const char *fname, readpng_what what, int w, int h);
-int writepng(const char *fname, unsigned short *src, int w, int h);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/frontend/gp2x/in_gp2x.c b/frontend/gp2x/in_gp2x.c
deleted file mode 100644 (file)
index 6b274a0..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "../common/input.h"
-#include "in_gp2x.h"
-
-#define IN_GP2X_PREFIX "gp2x:"
-#define IN_GP2X_NBUTTONS 32
-
-/* note: in_gp2x hadles combos (if 2 btns have the same bind,
- * both must be pressed for action to happen) */
-static int in_gp2x_combo_keys = 0;
-static int in_gp2x_combo_acts = 0;
-static int gpiodev = -1;       /* Wiz only */
-
-static int (*in_gp2x_get_bits)(void);
-
-static const char *in_gp2x_keys[IN_GP2X_NBUTTONS] = {
-       [0 ... IN_GP2X_NBUTTONS-1] = NULL,
-       [GP2X_BTN_UP]    = "Up",    [GP2X_BTN_LEFT]   = "Left",
-       [GP2X_BTN_DOWN]  = "Down",  [GP2X_BTN_RIGHT]  = "Right",
-       [GP2X_BTN_START] = "Start", [GP2X_BTN_SELECT] = "Select",
-       [GP2X_BTN_L]     = "L",     [GP2X_BTN_R]      = "R",
-       [GP2X_BTN_A]     = "A",     [GP2X_BTN_B]      = "B",
-       [GP2X_BTN_X]     = "X",     [GP2X_BTN_Y]      = "Y",
-       [GP2X_BTN_VOL_DOWN] = "VOL DOWN",
-       [GP2X_BTN_VOL_UP]   = "VOL UP",
-       [GP2X_BTN_PUSH]     = "PUSH"
-};
-
-
-static int in_gp2x_get_mmsp2_bits(void)
-{
-       extern volatile unsigned short *gp2x_memregs;
-       int value;
-       value = gp2x_memregs[0x1198>>1] & 0xff; // GPIO M
-       if (value == 0xFD) value = 0xFA;
-       if (value == 0xF7) value = 0xEB;
-       if (value == 0xDF) value = 0xAF;
-       if (value == 0x7F) value = 0xBE;
-       value |= gp2x_memregs[0x1184>>1] & 0xFF00; // GPIO C
-       value |= gp2x_memregs[0x1186>>1] << 16; // GPIO D
-       value = ~value & 0x08c0ff55;
-
-       return value;
-}
-
-static int in_gp2x_get_wiz_bits(void)
-{
-       int r, value = 0;
-       r = read(gpiodev, &value, 4);
-       if (value & 0x02)
-               value |= 0x05;
-       if (value & 0x08)
-               value |= 0x14;
-       if (value & 0x20)
-               value |= 0x50;
-       if (value & 0x80)
-               value |= 0x41;
-
-       /* convert to GP2X style */
-       value &= 0x7ff55;
-       if (value & (1 << 16))
-               value |= 1 << GP2X_BTN_VOL_UP;
-       if (value & (1 << 17))
-               value |= 1 << GP2X_BTN_VOL_DOWN;
-       if (value & (1 << 18))
-               value |= 1 << GP2X_BTN_PUSH;
-       value &= ~0x70000;
-
-       return value;
-}
-
-#ifdef FAKE_IN_GP2X
-volatile unsigned short *gp2x_memregs;
-int gp2x_dev_id = -1;
-
-static int in_gp2x_get_fake_bits(void)
-{
-       extern int current_keys;
-       return current_keys;
-}
-#endif
-
-static void in_gp2x_probe(void)
-{
-       switch (gp2x_dev_id)
-       {
-       case GP2X_DEV_GP2X:
-               in_gp2x_get_bits = in_gp2x_get_mmsp2_bits;
-               break;
-       case GP2X_DEV_WIZ:
-               gpiodev = open("/dev/GPIO", O_RDONLY);
-               if (gpiodev < 0) {
-                       perror("in_gp2x: couldn't open /dev/GPIO");
-                       return;
-               }
-               in_gp2x_get_bits = in_gp2x_get_wiz_bits;
-               break;
-       // we'll use evdev for Caanoo
-       default:
-#ifdef FAKE_IN_GP2X
-               in_gp2x_get_bits = in_gp2x_get_fake_bits;
-               break;
-#endif
-               return;
-       }
-
-       in_register(IN_GP2X_PREFIX "GP2X pad", -1, NULL,
-               IN_GP2X_NBUTTONS, in_gp2x_keys, 1);
-}
-
-static void in_gp2x_free(void *drv_data)
-{
-       if (gpiodev >= 0) {
-               close(gpiodev);
-               gpiodev = -1;
-       }
-}
-
-static const char * const *
-in_gp2x_get_key_names(int *count)
-{
-       *count = IN_GP2X_NBUTTONS;
-       return in_gp2x_keys;
-}
-
-/* ORs result with pressed buttons */
-static int in_gp2x_update(void *drv_data, const int *binds, int *result)
-{
-       int type_start = 0;
-       int i, t, keys;
-
-       keys = in_gp2x_get_bits();
-
-       if (keys & in_gp2x_combo_keys) {
-               result[IN_BINDTYPE_EMU] = in_combos_do(keys, binds, GP2X_BTN_PUSH,
-                                               in_gp2x_combo_keys, in_gp2x_combo_acts);
-               type_start = IN_BINDTYPE_PLAYER12;
-       }
-
-       for (i = 0; keys; i++, keys >>= 1) {
-               if (!(keys & 1))
-                       continue;
-
-               for (t = type_start; t < IN_BINDTYPE_COUNT; t++)
-                       result[t] |= binds[IN_BIND_OFFS(i, t)];
-       }
-
-       return 0;
-}
-
-int in_gp2x_update_keycode(void *data, int *is_down)
-{
-       static int old_val = 0;
-       int val, diff, i;
-
-       val = in_gp2x_get_bits();
-       diff = val ^ old_val;
-       if (diff == 0)
-               return -1;
-
-       /* take one bit only */
-       for (i = 0; i < sizeof(diff)*8; i++)
-               if (diff & (1<<i))
-                       break;
-
-       old_val ^= 1 << i;
-
-       if (is_down)
-               *is_down = !!(val & (1<<i));
-       return i;
-}
-
-static const struct {
-       short key;
-       short pbtn;
-} key_pbtn_map[] =
-{
-       { GP2X_BTN_UP,          PBTN_UP },
-       { GP2X_BTN_DOWN,        PBTN_DOWN },
-       { GP2X_BTN_LEFT,        PBTN_LEFT },
-       { GP2X_BTN_RIGHT,       PBTN_RIGHT },
-       { GP2X_BTN_B,           PBTN_MOK },
-       { GP2X_BTN_X,           PBTN_MBACK },
-       { GP2X_BTN_A,           PBTN_MA2 },
-       { GP2X_BTN_Y,           PBTN_MA3 },
-       { GP2X_BTN_L,           PBTN_L },
-       { GP2X_BTN_R,           PBTN_R },
-       { GP2X_BTN_SELECT,      PBTN_MENU },
-};
-
-#define KEY_PBTN_MAP_SIZE (sizeof(key_pbtn_map) / sizeof(key_pbtn_map[0]))
-
-static int in_gp2x_menu_translate(void *drv_data, int keycode, char *charcode)
-{
-       int i;
-       if (keycode < 0)
-       {
-               /* menu -> kc */
-               keycode = -keycode;
-               for (i = 0; i < KEY_PBTN_MAP_SIZE; i++)
-                       if (key_pbtn_map[i].pbtn == keycode)
-                               return key_pbtn_map[i].key;
-       }
-       else
-       {
-               for (i = 0; i < KEY_PBTN_MAP_SIZE; i++)
-                       if (key_pbtn_map[i].key == keycode)
-                               return key_pbtn_map[i].pbtn;
-       }
-
-       return 0;
-}
-
-#if 0 // TODO: move to pico
-static const struct {
-       short code;
-       char btype;
-       char bit;
-} in_gp2x_defbinds[] =
-{
-       /* MXYZ SACB RLDU */
-       { BTN_UP,       IN_BINDTYPE_PLAYER12, 0 },
-       { BTN_DOWN,     IN_BINDTYPE_PLAYER12, 1 },
-       { BTN_LEFT,     IN_BINDTYPE_PLAYER12, 2 },
-       { BTN_RIGHT,    IN_BINDTYPE_PLAYER12, 3 },
-       { BTN_X,        IN_BINDTYPE_PLAYER12, 4 },      /* B */
-       { BTN_B,        IN_BINDTYPE_PLAYER12, 5 },      /* C */
-       { BTN_A,        IN_BINDTYPE_PLAYER12, 6 },      /* A */
-       { BTN_START,    IN_BINDTYPE_PLAYER12, 7 },
-       { BTN_SELECT,   IN_BINDTYPE_EMU, PEVB_MENU },
-//     { BTN_Y,        IN_BINDTYPE_EMU, PEVB_SWITCH_RND },
-       { BTN_L,        IN_BINDTYPE_EMU, PEVB_STATE_SAVE },
-       { BTN_R,        IN_BINDTYPE_EMU, PEVB_STATE_LOAD },
-       { BTN_VOL_UP,   IN_BINDTYPE_EMU, PEVB_VOL_UP },
-       { BTN_VOL_DOWN, IN_BINDTYPE_EMU, PEVB_VOL_DOWN },
-       { 0, 0, 0 },
-};
-#endif
-
-/* remove binds of missing keys, count remaining ones */
-static int in_gp2x_clean_binds(void *drv_data, int *binds, int *def_binds)
-{
-       int i, count = 0;
-//     int eb, have_vol = 0, have_menu = 0;
-
-       for (i = 0; i < IN_GP2X_NBUTTONS; i++) {
-               int t, offs;
-               for (t = 0; t < IN_BINDTYPE_COUNT; t++) {
-                       offs = IN_BIND_OFFS(i, t);
-                       if (in_gp2x_keys[i] == NULL)
-                               binds[offs] = def_binds[offs] = 0;
-                       if (binds[offs])
-                               count++;
-               }
-#if 0
-               eb = binds[IN_BIND_OFFS(i, IN_BINDTYPE_EMU)];
-               if (eb & (PEV_VOL_DOWN|PEV_VOL_UP))
-                       have_vol = 1;
-               if (eb & PEV_MENU)
-                       have_menu = 1;
-#endif
-       }
-
-       // TODO: move to pico
-#if 0
-       /* autobind some important keys, if they are unbound */
-       if (!have_vol && binds[GP2X_BTN_VOL_UP] == 0 && binds[GP2X_BTN_VOL_DOWN] == 0) {
-               binds[IN_BIND_OFFS(GP2X_BTN_VOL_UP, IN_BINDTYPE_EMU)]   = PEV_VOL_UP;
-               binds[IN_BIND_OFFS(GP2X_BTN_VOL_DOWN, IN_BINDTYPE_EMU)] = PEV_VOL_DOWN;
-               count += 2;
-       }
-
-       if (!have_menu) {
-               binds[IN_BIND_OFFS(GP2X_BTN_SELECT, IN_BINDTYPE_EMU)] = PEV_MENU;
-               count++;
-       }
-#endif
-
-       in_combos_find(binds, GP2X_BTN_PUSH, &in_gp2x_combo_keys, &in_gp2x_combo_acts);
-
-       return count;
-}
-
-static const in_drv_t in_gp2x_drv = {
-       .prefix         = IN_GP2X_PREFIX,
-       .probe          = in_gp2x_probe,
-       .free           = in_gp2x_free,
-       .get_key_names  = in_gp2x_get_key_names,
-       .clean_binds    = in_gp2x_clean_binds,
-       .update         = in_gp2x_update,
-       .update_keycode = in_gp2x_update_keycode,
-       .menu_translate = in_gp2x_menu_translate,
-};
-
-void in_gp2x_init(const struct in_default_bind *defbinds)
-{
-       if (gp2x_dev_id == GP2X_DEV_WIZ)
-               in_gp2x_keys[GP2X_BTN_START] = "MENU";
-       
-       in_gp2x_combo_keys = in_gp2x_combo_acts = 0;
-
-       in_register_driver(&in_gp2x_drv, defbinds);
-}
-
diff --git a/frontend/gp2x/in_gp2x.h b/frontend/gp2x/in_gp2x.h
deleted file mode 100644 (file)
index 035cded..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-
-struct in_default_bind;
-
-void in_gp2x_init(const struct in_default_bind *defbinds);
-
-enum  { GP2X_BTN_UP = 0,      GP2X_BTN_LEFT = 2,      GP2X_BTN_DOWN = 4,  GP2X_BTN_RIGHT = 6,
-        GP2X_BTN_START = 8,   GP2X_BTN_SELECT = 9,    GP2X_BTN_L = 10,    GP2X_BTN_R = 11,
-        GP2X_BTN_A = 12,      GP2X_BTN_B = 13,        GP2X_BTN_X = 14,    GP2X_BTN_Y = 15,
-        GP2X_BTN_VOL_UP = 23, GP2X_BTN_VOL_DOWN = 22, GP2X_BTN_PUSH = 27 };
-
-/* FIXME */
-#ifndef GP2X_DEV_GP2X
-extern int gp2x_dev_id;
-#define GP2X_DEV_GP2X 1
-#define GP2X_DEV_WIZ 2
-#define GP2X_DEV_CAANOO 3
-#endif
index 80c9c58..aee6852 100644 (file)
@@ -11,7 +11,7 @@
 #include <stdio.h>
 #include <tslib.h>
 
-#include "common/input.h"
+#include "libpicofe/input.h"
 #include "pl_gun_ts.h"
 #include "in_tsbutton.h"
 
diff --git a/frontend/libpicofe b/frontend/libpicofe
new file mode 160000 (submodule)
index 0000000..3e1124f
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 3e1124f989febba80ef582c1200153ed176226f0
index 4305aa7..b832a4e 100644 (file)
@@ -13,6 +13,8 @@
 #include "../libpcsxcore/psxcounters.h"
 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
 #include "../plugins/dfsound/out.h"
+#include "../plugins/gpulib/cspace.h"
+#include "linux/plat_mmap.h"
 #include "main.h"
 #include "plugin.h"
 #include "plugin_lib.h"
@@ -26,7 +28,6 @@ static retro_environment_t environ_cb;
 static retro_audio_sample_batch_t audio_batch_cb;
 
 static void *vout_buf;
-static int vout_width, vout_height;
 static int samples_sent, samples_to_send;
 static int plugins_opened;
 static int native_rgb565;
@@ -42,14 +43,10 @@ static int vout_open(void)
        return 0;
 }
 
-static void *vout_set_mode(int w, int h, int bpp)
+static void vout_set_mode(int w, int h, int raw_w, int raw_h, int bpp)
 {
-       vout_width = w;
-       vout_height = h;
-       return vout_buf;
 }
 
-/* FIXME: either teach PCSX to blit to RGB1555 or RetroArch to support RGB565 */
 static void convert(void *buf, size_t bytes)
 {
        unsigned int i, v, *p = buf;
@@ -60,25 +57,62 @@ static void convert(void *buf, size_t bytes)
        }
 }
 
-static void *vout_flip(void)
+static void vout_flip(const void *vram, int stride, int bgr24, int w, int h)
 {
-       pl_rearmed_cbs.flip_cnt++;
-       if (!native_rgb565)
-               convert(vout_buf,  vout_width * vout_height * 2);
-       video_cb(vout_buf, vout_width, vout_height, vout_width * 2);
+       unsigned short *dest = vout_buf;
+       const unsigned short *src = vram;
+       int dstride = w, h1 = h;
+
+       if (vram == NULL) {
+               // blanking
+               memset(vout_buf, 0, dstride * h * 2);
+               goto out;
+       }
 
-       return vout_buf;
+       if (bgr24)
+       {
+               // XXX: could we switch to RETRO_PIXEL_FORMAT_XRGB8888 here?
+               for (; h1-- > 0; dest += dstride, src += stride)
+               {
+                       bgr888_to_rgb565(dest, src, w * 3);
+               }
+       }
+       else
+       {
+               for (; h1-- > 0; dest += dstride, src += stride)
+               {
+                       bgr555_to_rgb565(dest, src, w * 2);
+               }
+       }
+
+out:
+       if (!native_rgb565)
+               convert(vout_buf, w * h * 2);
+       video_cb(vout_buf, w, h, w * 2);
+       pl_rearmed_cbs.flip_cnt++;
 }
 
 static void vout_close(void)
 {
 }
 
+static void *pl_mmap(unsigned int size)
+{
+       return plat_mmap(0, size, 0, 0);
+}
+
+static void pl_munmap(void *ptr, unsigned int size)
+{
+       plat_munmap(ptr, size);
+}
+
 struct rearmed_cbs pl_rearmed_cbs = {
        .pl_vout_open = vout_open,
        .pl_vout_set_mode = vout_set_mode,
        .pl_vout_flip = vout_flip,
        .pl_vout_close = vout_close,
+       .mmap = pl_mmap,
+       .munmap = pl_munmap,
        /* from psxcounters */
        .gpu_hcnt = &hSyncCount,
        .gpu_frame_count = &frame_counter,
@@ -98,7 +132,7 @@ void plat_trigger_vibrate(int is_strong)
 {
 }
 
-void pl_update_gun(int *xn, int *xres, int *y, int *in)
+void pl_update_gun(int *xn, int *yn, int *xres, int *yres, int *in)
 {
 }
 
@@ -240,7 +274,7 @@ bool retro_load_game(const struct retro_game_info *info)
                printf("could not load CD-ROM!\n");
                return false;
        }
-       emu_on_new_cd();
+       emu_on_new_cd(0);
 
        return true;
 }
diff --git a/frontend/linux/fbdev.c b/frontend/linux/fbdev.c
deleted file mode 100644 (file)
index ec3d5c7..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * (C) Gražvydas "notaz" Ignotas, 2009-2010
- *
- * This work is licensed under the terms of any of these licenses
- * (at your option):
- *  - GNU GPL, version 2 or later.
- *  - GNU LGPL, version 2.1 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include <stdio.h>
-#include <stdlib.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 "fbdev.h"
-
-#define PFX "fbdev: "
-
-struct vout_fbdev {
-       int     fd;
-       void    *mem;
-       size_t  mem_size;
-       struct  fb_var_screeninfo fbvar_old;
-       struct  fb_var_screeninfo fbvar_new;
-       int     buffer_write;
-       int     fb_size;
-       int     buffer_count;
-       int     top_border, bottom_border;
-       void    *mem_saved;
-       size_t  mem_saved_size;
-};
-
-void *vout_fbdev_flip(struct vout_fbdev *fbdev)
-{
-       int draw_buf;
-
-       if (fbdev->buffer_count < 2)
-               return fbdev->mem;
-
-       draw_buf = fbdev->buffer_write;
-       fbdev->buffer_write++;
-       if (fbdev->buffer_write >= fbdev->buffer_count)
-               fbdev->buffer_write = 0;
-
-       fbdev->fbvar_new.yoffset = 
-               (fbdev->top_border + fbdev->fbvar_new.yres + fbdev->bottom_border) * draw_buf +
-               fbdev->top_border;
-
-       ioctl(fbdev->fd, FBIOPAN_DISPLAY, &fbdev->fbvar_new);
-
-       return (char *)fbdev->mem + fbdev->fb_size * fbdev->buffer_write;
-}
-
-void vout_fbdev_wait_vsync(struct vout_fbdev *fbdev)
-{
-       int arg = 0;
-       ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &arg);
-}
-
-/* it is recommended to call vout_fbdev_clear() before this */
-void *vout_fbdev_resize(struct vout_fbdev *fbdev, int w, int h, int bpp,
-                     int left_border, int right_border, int top_border, int bottom_border, int buffer_cnt)
-{
-       int w_total = left_border + w + right_border;
-       int h_total = top_border + h + bottom_border;
-       size_t mem_size;
-       int ret;
-
-       // unblank to be sure the mode is really accepted
-       ioctl(fbdev->fd, FBIOBLANK, FB_BLANK_UNBLANK);
-
-       if (fbdev->fbvar_new.bits_per_pixel != bpp ||
-                       fbdev->fbvar_new.xres != w ||
-                       fbdev->fbvar_new.yres != h ||
-                       fbdev->fbvar_new.xres_virtual != w_total||
-                       fbdev->fbvar_new.yres_virtual < h_total ||
-                       fbdev->fbvar_new.xoffset != left_border ||
-                       fbdev->buffer_count != buffer_cnt)
-       {
-               if (fbdev->fbvar_new.bits_per_pixel != bpp ||
-                               w != fbdev->fbvar_new.xres || h != fbdev->fbvar_new.yres)
-                       printf(PFX "switching to %dx%d@%d\n", w, h, bpp);
-
-               fbdev->fbvar_new.xres = w;
-               fbdev->fbvar_new.yres = h;
-               fbdev->fbvar_new.xres_virtual = w_total;
-               fbdev->fbvar_new.yres_virtual = h_total * buffer_cnt;
-               fbdev->fbvar_new.xoffset = left_border;
-               fbdev->fbvar_new.yoffset = top_border;
-               fbdev->fbvar_new.bits_per_pixel = bpp;
-               fbdev->fbvar_new.nonstd = 0; // can set YUV here on omapfb
-               fbdev->buffer_count = buffer_cnt;
-               fbdev->buffer_write = buffer_cnt > 1 ? 1 : 0;
-
-               // seems to help a bit to avoid glitches
-               vout_fbdev_wait_vsync(fbdev);
-
-               ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new);
-               if (ret == -1) {
-                       // retry with no multibuffering
-                       fbdev->fbvar_new.yres_virtual = h_total;
-                       ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new);
-                       if (ret == -1) {
-                               perror(PFX "FBIOPUT_VSCREENINFO ioctl");
-                               return NULL;
-                       }
-                       fbdev->buffer_count = 1;
-                       fbdev->buffer_write = 0;
-                       fprintf(stderr, PFX "Warning: failed to increase virtual resolution, "
-                                       "multibuffering disabled\n");
-               }
-
-       }
-
-       fbdev->fb_size = w_total * h_total * bpp / 8;
-       fbdev->top_border = top_border;
-       fbdev->bottom_border = bottom_border;
-
-       mem_size = fbdev->fb_size * fbdev->buffer_count;
-       if (fbdev->mem_size >= mem_size)
-               goto out;
-
-       if (fbdev->mem != NULL)
-               munmap(fbdev->mem, fbdev->mem_size);
-
-       fbdev->mem = mmap(0, mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0);
-       if (fbdev->mem == MAP_FAILED && fbdev->buffer_count > 1) {
-               fprintf(stderr, PFX "Warning: can't map %zd bytes, doublebuffering disabled\n", mem_size);
-               fbdev->buffer_count = 1;
-               fbdev->buffer_write = 0;
-               mem_size = fbdev->fb_size;
-               fbdev->mem = mmap(0, mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0);
-       }
-       if (fbdev->mem == MAP_FAILED) {
-               fbdev->mem = NULL;
-               fbdev->mem_size = 0;
-               perror(PFX "mmap framebuffer");
-               return NULL;
-       }
-
-       fbdev->mem_size = mem_size;
-
-out:
-       return (char *)fbdev->mem + fbdev->fb_size * fbdev->buffer_write;
-}
-
-void vout_fbdev_clear(struct vout_fbdev *fbdev)
-{
-       memset(fbdev->mem, 0, fbdev->mem_size);
-}
-
-void vout_fbdev_clear_lines(struct vout_fbdev *fbdev, int y, int count)
-{
-       int stride = fbdev->fbvar_new.xres_virtual * fbdev->fbvar_new.bits_per_pixel / 8;
-       int i;
-
-       if (y + count > fbdev->top_border + fbdev->fbvar_new.yres)
-               count = fbdev->top_border + fbdev->fbvar_new.yres - y;
-
-       if (y >= 0 && count > 0)
-               for (i = 0; i < fbdev->buffer_count; i++)
-                       memset((char *)fbdev->mem + fbdev->fb_size * i + y * stride, 0, stride * count);
-}
-
-int vout_fbdev_get_fd(struct vout_fbdev *fbdev)
-{
-       return fbdev->fd;
-}
-
-struct vout_fbdev *vout_fbdev_init(const char *fbdev_name, int *w, int *h, int bpp, int buffer_cnt)
-{
-       struct vout_fbdev *fbdev;
-       int req_w, req_h;
-       void *pret;
-       int ret;
-
-       fbdev = calloc(1, sizeof(*fbdev));
-       if (fbdev == NULL)
-               return NULL;
-
-       fbdev->fd = open(fbdev_name, O_RDWR);
-       if (fbdev->fd == -1) {
-               fprintf(stderr, PFX "%s: ", fbdev_name);
-               perror("open");
-               goto fail_open;
-       }
-
-       ret = ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->fbvar_old);
-       if (ret == -1) {
-               perror(PFX "FBIOGET_VSCREENINFO ioctl");
-               goto fail;
-       }
-
-       fbdev->fbvar_new = fbdev->fbvar_old;
-
-       req_w = fbdev->fbvar_new.xres;
-       if (*w != 0)
-               req_w = *w;
-       req_h = fbdev->fbvar_new.yres;
-       if (*h != 0)
-               req_h = *h;
-
-       pret = vout_fbdev_resize(fbdev, req_w, req_h, bpp, 0, 0, 0, 0, buffer_cnt);
-       if (pret == NULL)
-               goto fail;
-
-       printf(PFX "%s: %ix%i@%d\n", fbdev_name, fbdev->fbvar_new.xres,
-               fbdev->fbvar_new.yres, fbdev->fbvar_new.bits_per_pixel);
-       *w = fbdev->fbvar_new.xres;
-       *h = fbdev->fbvar_new.yres;
-
-       memset(fbdev->mem, 0, fbdev->mem_size);
-
-       // some checks
-       ret = 0;
-       ret = ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &ret);
-       if (ret != 0)
-               fprintf(stderr, PFX "Warning: vsync doesn't seem to be supported\n");
-
-       if (fbdev->buffer_count > 1) {
-               fbdev->buffer_write = 0;
-               fbdev->fbvar_new.yoffset = fbdev->fbvar_new.yres * (fbdev->buffer_count - 1);
-               ret = ioctl(fbdev->fd, FBIOPAN_DISPLAY, &fbdev->fbvar_new);
-               if (ret != 0) {
-                       fbdev->buffer_count = 1;
-                       fprintf(stderr, PFX "Warning: can't pan display, doublebuffering disabled\n");
-               }
-       }
-
-       printf("fbdev initialized.\n");
-       return fbdev;
-
-fail:
-       close(fbdev->fd);
-fail_open:
-       free(fbdev);
-       return NULL;
-}
-
-static void vout_fbdev_release(struct vout_fbdev *fbdev)
-{
-       ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_old);
-       if (fbdev->mem != MAP_FAILED)
-               munmap(fbdev->mem, fbdev->mem_size);
-       fbdev->mem = NULL;
-}
-
-int vout_fbdev_save(struct vout_fbdev *fbdev)
-{
-       void *tmp;
-
-       if (fbdev == NULL || fbdev->mem == NULL || fbdev->mem == MAP_FAILED) {
-               fprintf(stderr, PFX "bad args for save\n");
-               return -1;
-       }
-
-       if (fbdev->mem_saved_size < fbdev->mem_size) {
-               tmp = realloc(fbdev->mem_saved, fbdev->mem_size);
-               if (tmp == NULL)
-                       return -1;
-               fbdev->mem_saved = tmp;
-       }
-       memcpy(fbdev->mem_saved, fbdev->mem, fbdev->mem_size);
-       fbdev->mem_saved_size = fbdev->mem_size;
-
-       vout_fbdev_release(fbdev);
-       return 0;
-}
-
-int vout_fbdev_restore(struct vout_fbdev *fbdev)
-{
-       int ret;
-
-       if (fbdev == NULL || fbdev->mem != NULL) {
-               fprintf(stderr, PFX "bad args/state for restore\n");
-               return -1;
-       }
-
-       fbdev->mem = mmap(0, fbdev->mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0);
-       if (fbdev->mem == MAP_FAILED) {
-               perror(PFX "restore: memory restore failed");
-               return -1;
-       }
-       memcpy(fbdev->mem, fbdev->mem_saved, fbdev->mem_size);
-
-       ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new);
-       if (ret == -1) {
-               perror(PFX "restore: FBIOPUT_VSCREENINFO");
-               return -1;
-       }
-
-       return 0;
-}
-
-void vout_fbdev_finish(struct vout_fbdev *fbdev)
-{
-       vout_fbdev_release(fbdev);
-       if (fbdev->fd >= 0)
-               close(fbdev->fd);
-       fbdev->fd = -1;
-       free(fbdev);
-}
-
diff --git a/frontend/linux/fbdev.h b/frontend/linux/fbdev.h
deleted file mode 100644 (file)
index 88cd519..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-struct vout_fbdev;
-
-struct vout_fbdev *vout_fbdev_init(const char *fbdev_name, int *w, int *h, int bpp, int buffer_count);
-void *vout_fbdev_flip(struct vout_fbdev *fbdev);
-void  vout_fbdev_wait_vsync(struct vout_fbdev *fbdev);
-void *vout_fbdev_resize(struct vout_fbdev *fbdev, int w, int h, int bpp,
-                       int left_border, int right_border, int top_border, int bottom_border,
-                       int buffer_count);
-void  vout_fbdev_clear(struct vout_fbdev *fbdev);
-void  vout_fbdev_clear_lines(struct vout_fbdev *fbdev, int y, int count);
-int   vout_fbdev_get_fd(struct vout_fbdev *fbdev);
-int   vout_fbdev_save(struct vout_fbdev *fbdev);
-int   vout_fbdev_restore(struct vout_fbdev *fbdev);
-void  vout_fbdev_finish(struct vout_fbdev *fbdev);
diff --git a/frontend/linux/in_evdev.c b/frontend/linux/in_evdev.c
deleted file mode 100644 (file)
index b447da1..0000000
+++ /dev/null
@@ -1,655 +0,0 @@
-/*
- * (C) Gražvydas "notaz" Ignotas, 2008-2010
- *
- * This work is licensed under the terms of any of these licenses
- * (at your option):
- *  - GNU GPL, version 2 or later.
- *  - GNU LGPL, version 2.1 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-#include <linux/input.h>
-#include <errno.h>
-
-#include "../common/input.h"
-#include "in_evdev.h"
-
-#define MAX_ABS_DEVS 8
-
-typedef struct {
-       int fd;
-       int *kbits;
-       int abs_min_x; /* abs->digital mapping */
-       int abs_max_x;
-       int abs_min_y;
-       int abs_max_y;
-       int abs_lzone;
-       int abs_lastx;
-       int abs_lasty;
-       int kc_first;
-       int kc_last;
-       unsigned int abs_count;
-       int abs_mult[MAX_ABS_DEVS]; /* 16.16 multiplier to IN_ABS_RANGE */
-       int abs_adj[MAX_ABS_DEVS];  /* adjust for centering */
-       unsigned int abs_to_digital:1;
-} in_evdev_t;
-
-#ifndef KEY_CNT
-#define KEY_CNT (KEY_MAX + 1)
-#endif
-
-#define KEYBITS_BIT(x) (keybits[(x)/sizeof(keybits[0])/8] & \
-       (1 << ((x) & (sizeof(keybits[0])*8-1))))
-
-#define KEYBITS_BIT_SET(x) (keybits[(x)/sizeof(keybits[0])/8] |= \
-       (1 << ((x) & (sizeof(keybits[0])*8-1))))
-
-#define KEYBITS_BIT_CLEAR(x) (keybits[(x)/sizeof(keybits[0])/8] &= \
-       ~(1 << ((x) & (sizeof(keybits[0])*8-1))))
-
-int in_evdev_allow_abs_only;
-
-#define IN_EVDEV_PREFIX "evdev:"
-
-static const char * const in_evdev_keys[KEY_CNT] = {
-       [0 ... KEY_MAX] = NULL,
-       [KEY_RESERVED] = "Reserved",            [KEY_ESC] = "Esc",
-       [KEY_1] = "1",                          [KEY_2] = "2",
-       [KEY_3] = "3",                          [KEY_4] = "4",
-       [KEY_5] = "5",                          [KEY_6] = "6",
-       [KEY_7] = "7",                          [KEY_8] = "8",
-       [KEY_9] = "9",                          [KEY_0] = "0",
-       [KEY_MINUS] = "Minus",                  [KEY_EQUAL] = "Equal",
-       [KEY_BACKSPACE] = "Backspace",          [KEY_TAB] = "Tab",
-       [KEY_Q] = "Q",                          [KEY_W] = "W",
-       [KEY_E] = "E",                          [KEY_R] = "R",
-       [KEY_T] = "T",                          [KEY_Y] = "Y",
-       [KEY_U] = "U",                          [KEY_I] = "I",
-       [KEY_O] = "O",                          [KEY_P] = "P",
-       [KEY_LEFTBRACE] = "LeftBrace",          [KEY_RIGHTBRACE] = "RightBrace",
-       [KEY_ENTER] = "Enter",                  [KEY_LEFTCTRL] = "LeftControl",
-       [KEY_A] = "A",                          [KEY_S] = "S",
-       [KEY_D] = "D",                          [KEY_F] = "F",
-       [KEY_G] = "G",                          [KEY_H] = "H",
-       [KEY_J] = "J",                          [KEY_K] = "K",
-       [KEY_L] = "L",                          [KEY_SEMICOLON] = "Semicolon",
-       [KEY_APOSTROPHE] = "Apostrophe",        [KEY_GRAVE] = "Grave",
-       [KEY_LEFTSHIFT] = "LeftShift",          [KEY_BACKSLASH] = "BackSlash",
-       [KEY_Z] = "Z",                          [KEY_X] = "X",
-       [KEY_C] = "C",                          [KEY_V] = "V",
-       [KEY_B] = "B",                          [KEY_N] = "N",
-       [KEY_M] = "M",                          [KEY_COMMA] = "Comma",
-       [KEY_DOT] = "Dot",                      [KEY_SLASH] = "Slash",
-       [KEY_RIGHTSHIFT] = "RightShift",        [KEY_KPASTERISK] = "KPAsterisk",
-       [KEY_LEFTALT] = "LeftAlt",              [KEY_SPACE] = "Space",
-       [KEY_CAPSLOCK] = "CapsLock",            [KEY_F1] = "F1",
-       [KEY_F2] = "F2",                        [KEY_F3] = "F3",
-       [KEY_F4] = "F4",                        [KEY_F5] = "F5",
-       [KEY_F6] = "F6",                        [KEY_F7] = "F7",
-       [KEY_F8] = "F8",                        [KEY_F9] = "F9",
-       [KEY_F10] = "F10",                      [KEY_NUMLOCK] = "NumLock",
-       [KEY_SCROLLLOCK] = "ScrollLock",        [KEY_KP7] = "KP7",
-       [KEY_KP8] = "KP8",                      [KEY_KP9] = "KP9",
-       [KEY_KPMINUS] = "KPMinus",              [KEY_KP4] = "KP4",
-       [KEY_KP5] = "KP5",                      [KEY_KP6] = "KP6",
-       [KEY_KPPLUS] = "KPPlus",                [KEY_KP1] = "KP1",
-       [KEY_KP2] = "KP2",                      [KEY_KP3] = "KP3",
-       [KEY_KP0] = "KP0",                      [KEY_KPDOT] = "KPDot",
-       [KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd",
-       [KEY_F11] = "F11",                      [KEY_F12] = "F12",
-       [KEY_KPJPCOMMA] = "KPJpComma",          [KEY_KPENTER] = "KPEnter",
-       [KEY_RIGHTCTRL] = "RightCtrl",          [KEY_KPSLASH] = "KPSlash",
-       [KEY_SYSRQ] = "SysRq",                  [KEY_RIGHTALT] = "RightAlt",
-       [KEY_LINEFEED] = "LineFeed",            [KEY_HOME] = "Home",
-       [KEY_UP] = "Up",                        [KEY_PAGEUP] = "PageUp",
-       [KEY_LEFT] = "Left",                    [KEY_RIGHT] = "Right",
-       [KEY_END] = "End",                      [KEY_DOWN] = "Down",
-       [KEY_PAGEDOWN] = "PageDown",            [KEY_INSERT] = "Insert",
-       [KEY_DELETE] = "Delete",                [KEY_MACRO] = "Macro",
-       [KEY_HELP] = "Help",                    [KEY_MENU] = "Menu",
-       [KEY_COFFEE] = "Coffee",                [KEY_DIRECTION] = "Direction",
-       [BTN_0] = "Btn0",                       [BTN_1] = "Btn1",
-       [BTN_2] = "Btn2",                       [BTN_3] = "Btn3",
-       [BTN_4] = "Btn4",                       [BTN_5] = "Btn5",
-       [BTN_6] = "Btn6",                       [BTN_7] = "Btn7",
-       [BTN_8] = "Btn8",                       [BTN_9] = "Btn9",
-       [BTN_LEFT] = "LeftBtn",                 [BTN_RIGHT] = "RightBtn",
-       [BTN_MIDDLE] = "MiddleBtn",             [BTN_SIDE] = "SideBtn",
-       [BTN_EXTRA] = "ExtraBtn",               [BTN_FORWARD] = "ForwardBtn",
-       [BTN_BACK] = "BackBtn",                 [BTN_TASK] = "TaskBtn",
-       [BTN_TRIGGER] = "Trigger",              [BTN_THUMB] = "ThumbBtn",
-       [BTN_THUMB2] = "ThumbBtn2",             [BTN_TOP] = "TopBtn",
-       [BTN_TOP2] = "TopBtn2",                 [BTN_PINKIE] = "PinkieBtn",
-       [BTN_BASE] = "BaseBtn",                 [BTN_BASE2] = "BaseBtn2",
-       [BTN_BASE3] = "BaseBtn3",               [BTN_BASE4] = "BaseBtn4",
-       [BTN_BASE5] = "BaseBtn5",               [BTN_BASE6] = "BaseBtn6",
-       [BTN_DEAD] = "BtnDead",                 [BTN_A] = "BtnA",
-       [BTN_B] = "BtnB",                       [BTN_C] = "BtnC",
-       [BTN_X] = "BtnX",                       [BTN_Y] = "BtnY",
-       [BTN_Z] = "BtnZ",                       [BTN_TL] = "BtnTL",
-       [BTN_TR] = "BtnTR",                     [BTN_TL2] = "BtnTL2",
-       [BTN_TR2] = "BtnTR2",                   [BTN_SELECT] = "BtnSelect",
-       [BTN_START] = "BtnStart",               [BTN_MODE] = "BtnMode",
-       [BTN_THUMBL] = "BtnThumbL",             [BTN_THUMBR] = "BtnThumbR",
-       [BTN_TOUCH] = "Touch",                  [BTN_STYLUS] = "Stylus",
-       [BTN_STYLUS2] = "Stylus2",              [BTN_TOOL_DOUBLETAP] = "Tool Doubletap",
-       [BTN_TOOL_TRIPLETAP] = "Tool Tripletap", [BTN_GEAR_DOWN] = "WheelBtn",
-       [BTN_GEAR_UP] = "Gear up",              [KEY_OK] = "Ok",
-};
-
-
-static void in_evdev_probe(void)
-{
-       long keybits[KEY_CNT / sizeof(long) / 8];
-       long absbits[(ABS_MAX+1) / sizeof(long) / 8];
-       int i;
-
-       // the kernel might support and return less keys then we know about,
-       // so make sure the buffers are clear.
-       memset(keybits, 0, sizeof(keybits));
-       memset(absbits, 0, sizeof(absbits));
-
-       for (i = 0;; i++)
-       {
-               int support = 0, count = 0;
-               int u, ret, fd, kc_first = KEY_MAX, kc_last = 0, have_abs = 0;
-               in_evdev_t *dev;
-               char name[64];
-
-               snprintf(name, sizeof(name), "/dev/input/event%d", i);
-               fd = open(name, O_RDONLY|O_NONBLOCK);
-               if (fd == -1) {
-                       if (errno == EACCES)
-                               continue;       /* maybe we can access next one */
-                       break;
-               }
-
-               /* check supported events */
-               ret = ioctl(fd, EVIOCGBIT(0, sizeof(support)), &support);
-               if (ret == -1) {
-                       printf("in_evdev: ioctl failed on %s\n", name);
-                       goto skip;
-               }
-
-               if (support & (1 << EV_KEY)) {
-                       ret = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits);
-                       if (ret == -1) {
-                               printf("in_evdev: ioctl failed on %s\n", name);
-                               goto skip;
-                       }
-
-                       /* check for interesting keys */
-                       for (u = 0; u < KEY_CNT; u++) {
-                               if (KEYBITS_BIT(u)) {
-                                       if (u < kc_first)
-                                               kc_first = u;
-                                       if (u > kc_last)
-                                               kc_last = u;
-                                       if (u != KEY_POWER && u != KEY_SLEEP && u != BTN_TOUCH)
-                                               count++;
-                                       if (u == BTN_TOUCH) /* we can't deal with ts currently */
-                                               goto skip;
-                               }
-                       }
-               }
-
-               dev = calloc(1, sizeof(*dev));
-               if (dev == NULL)
-                       goto skip;
-
-               ret = ioctl(fd, EVIOCGKEY(sizeof(keybits)), keybits);
-               if (ret == -1) {
-                       printf("Warning: EVIOCGKEY not supported, will have to track state\n");
-                       dev->kbits = calloc(KEY_CNT, sizeof(int));
-                       if (dev->kbits == NULL) {
-                               free(dev);
-                               goto skip;
-                       }
-               }
-
-               /* check for abs too */
-               if (support & (1 << EV_ABS)) {
-                       struct input_absinfo ainfo;
-                       int dist;
-                       ret = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits);
-                       if (ret == -1)
-                               goto no_abs;
-                       if (absbits[0] & (1 << ABS_X)) {
-                               ret = ioctl(fd, EVIOCGABS(ABS_X), &ainfo);
-                               if (ret == -1)
-                                       goto no_abs;
-                               dist = ainfo.maximum - ainfo.minimum;
-                               dev->abs_lzone = dist / 4;
-                               dev->abs_min_x = ainfo.minimum;
-                               dev->abs_max_x = ainfo.maximum;
-                       }
-                       if (absbits[0] & (1 << ABS_Y)) {
-                               ret = ioctl(fd, EVIOCGABS(ABS_Y), &ainfo);
-                               if (ret == -1)
-                                       goto no_abs;
-                               dist = ainfo.maximum - ainfo.minimum;
-                               dev->abs_min_y = ainfo.minimum;
-                               dev->abs_max_y = ainfo.maximum;
-                       }
-                       for (u = 0; u < MAX_ABS_DEVS; u++) {
-                               ret = ioctl(fd, EVIOCGABS(u), &ainfo);
-                               if (ret == -1)
-                                       break;
-                               dist = ainfo.maximum - ainfo.minimum;
-                               if (dist != 0)
-                                       dev->abs_mult[u] = IN_ABS_RANGE * 2 * 65536 / dist;
-                               dev->abs_adj[u] = -(ainfo.maximum + ainfo.minimum + 1) / 2;
-                               have_abs = 1;
-                       }
-                       dev->abs_count = u;
-               }
-
-no_abs:
-               if (count == 0 && !have_abs) {
-                       free(dev);
-                       goto skip;
-               }
-
-               dev->fd = fd;
-               dev->kc_first = kc_first;
-               dev->kc_last = kc_last;
-               if (count > 0 || in_evdev_allow_abs_only)
-                       dev->abs_to_digital = 1;
-               strcpy(name, IN_EVDEV_PREFIX);
-               ioctl(fd, EVIOCGNAME(sizeof(name)-6), name+6);
-               printf("in_evdev: found \"%s\" with %d events (type %08x)\n",
-                       name+6, count, support);
-               in_register(name, fd, dev, KEY_CNT, in_evdev_keys, 0);
-               continue;
-
-skip:
-               close(fd);
-       }
-}
-
-static void in_evdev_free(void *drv_data)
-{
-       in_evdev_t *dev = drv_data;
-       if (dev == NULL)
-               return;
-       close(dev->fd);
-       free(dev);
-}
-
-static const char * const *
-in_evdev_get_key_names(int *count)
-{
-       *count = KEY_CNT;
-       return in_evdev_keys;
-}
-
-static void or_binds(const int *binds, int key, int *result)
-{
-       int t;
-       for (t = 0; t < IN_BINDTYPE_COUNT; t++)
-               result[t] |= binds[IN_BIND_OFFS(key, t)];
-}
-
-/* ORs result with binds of pressed buttons
- * XXX: should measure performance hit of this func, might need to optimize */
-static int in_evdev_update(void *drv_data, const int *binds, int *result)
-{
-       struct input_event ev[16];
-       struct input_absinfo ainfo;
-       int keybits_[KEY_CNT / sizeof(int)];
-       int *keybits = keybits_;
-       in_evdev_t *dev = drv_data;
-       int rd, ret, u, lzone;
-
-       if (dev->kbits == NULL) {
-               ret = ioctl(dev->fd, EVIOCGKEY(sizeof(keybits_)), keybits_);
-               if (ret == -1) {
-                       perror("in_evdev: ioctl failed");
-                       return -1;
-               }
-       }
-       else {
-               keybits = dev->kbits;
-               while (1) {
-                       rd = read(dev->fd, ev, sizeof(ev));
-                       if (rd < (int)sizeof(ev[0])) {
-                               if (errno != EAGAIN)
-                                       perror("in_evdev: read failed");
-                               break;
-                       }
-                       for (u = 0; u < rd / sizeof(ev[0]); u++) {
-                               if (ev[u].type != EV_KEY)
-                                       continue;
-                               else if (ev[u].value == 1)
-                                       KEYBITS_BIT_SET(ev[u].code);
-                               else if (ev[u].value == 0)
-                                       KEYBITS_BIT_CLEAR(ev[u].code);
-                       }
-               }
-       }
-
-       for (u = dev->kc_first; u <= dev->kc_last; u++) {
-               if (KEYBITS_BIT(u))
-                       or_binds(binds, u, result);
-       }
-
-       /* map X and Y absolute to UDLR */
-       lzone = dev->abs_lzone;
-       if (dev->abs_to_digital && lzone != 0) {
-               ret = ioctl(dev->fd, EVIOCGABS(ABS_X), &ainfo);
-               if (ret != -1) {
-                       if (ainfo.value < dev->abs_min_x + lzone) or_binds(binds, KEY_LEFT, result);
-                       if (ainfo.value > dev->abs_max_x - lzone) or_binds(binds, KEY_RIGHT, result);
-               }
-               ret = ioctl(dev->fd, EVIOCGABS(ABS_Y), &ainfo);
-               if (ret != -1) {
-                       if (ainfo.value < dev->abs_min_y + lzone) or_binds(binds, KEY_UP, result);
-                       if (ainfo.value > dev->abs_max_y - lzone) or_binds(binds, KEY_DOWN, result);
-               }
-       }
-
-       return 0;
-}
-
-static int in_evdev_update_analog(void *drv_data, int axis_id, int *result)
-{
-       struct input_absinfo ainfo;
-       in_evdev_t *dev = drv_data;
-       int ret;
-
-       if ((unsigned int)axis_id >= MAX_ABS_DEVS)
-               return -1;
-
-       ret = ioctl(dev->fd, EVIOCGABS(axis_id), &ainfo);
-       if (ret != 0)
-               return ret;
-
-       *result = (ainfo.value + dev->abs_adj[axis_id]) * dev->abs_mult[axis_id];
-       *result >>= 16;
-       return 0;
-}
-
-static int in_evdev_set_blocking(in_evdev_t *dev, int y)
-{
-       long flags;
-       int ret;
-
-       flags = (long)fcntl(dev->fd, F_GETFL);
-       if ((int)flags == -1) {
-               perror("in_evdev: F_GETFL fcntl failed");
-               return -1;
-       }
-
-       if (flags & O_NONBLOCK) {
-               /* flush the event queue */
-               struct input_event ev;
-               do {
-                       ret = read(dev->fd, &ev, sizeof(ev));
-               }
-               while (ret == sizeof(ev));
-       }
-
-       if (y)
-               flags &= ~O_NONBLOCK;
-       else
-               flags |=  O_NONBLOCK;
-       ret = fcntl(dev->fd, F_SETFL, flags);
-       if (ret == -1) {
-               perror("in_evdev: F_SETFL fcntl failed");
-               return -1;
-       }
-
-       return 0;
-}
-
-static int in_evdev_get_config(void *drv_data, int what, int *val)
-{
-       in_evdev_t *dev = drv_data;
-
-       switch (what) {
-       case IN_CFG_ABS_AXIS_COUNT:
-               *val = dev->abs_count;
-               break;
-       default:
-               return -1;
-       }
-
-       return 0;
-}
-
-static int in_evdev_set_config(void *drv_data, int what, int val)
-{
-       in_evdev_t *dev = drv_data;
-       int tmp;
-
-       switch (what) {
-       case IN_CFG_BLOCKING:
-               return in_evdev_set_blocking(dev, val);
-       case IN_CFG_ABS_DEAD_ZONE:
-               if (val < 1 || val > 99 || dev->abs_lzone == 0)
-                       return -1;
-               /* XXX: based on X axis only, for now.. */
-               tmp = (dev->abs_max_x - dev->abs_min_x) / 2;
-               dev->abs_lzone = tmp - tmp * val / 100;
-               if (dev->abs_lzone < 1)
-                       dev->abs_lzone = 1;
-               else if (dev->abs_lzone >= tmp)
-                       dev->abs_lzone = tmp - 1;
-               break;
-       default:
-               return -1;
-       }
-
-       return 0;
-}
-
-static int in_evdev_update_keycode(void *data, int *is_down)
-{
-       int ret_kc = -1, ret_down = 0;
-       in_evdev_t *dev = data;
-       struct input_event ev;
-       int rd;
-
-       /* do single event, the caller sometimes wants
-        * to do select() in blocking mode */
-       rd = read(dev->fd, &ev, sizeof(ev));
-       if (rd < (int) sizeof(ev)) {
-               if (errno != EAGAIN) {
-                       perror("in_evdev: error reading");
-                       //sleep(1);
-                       ret_kc = -2;
-               }
-               goto out;
-       }
-
-       if (ev.type == EV_KEY) {
-               if (ev.value < 0 || ev.value > 1)
-                       goto out;
-               ret_kc = ev.code;
-               ret_down = ev.value;
-               goto out;
-       }
-       else if (ev.type == EV_ABS && dev->abs_to_digital)
-       {
-               int lzone = dev->abs_lzone, down = 0, *last;
-
-               // map absolute to up/down/left/right
-               if (lzone != 0 && ev.code == ABS_X) {
-                       if (ev.value < dev->abs_min_x + lzone)
-                               down = KEY_LEFT;
-                       else if (ev.value > dev->abs_max_x - lzone)
-                               down = KEY_RIGHT;
-                       last = &dev->abs_lastx;
-               }
-               else if (lzone != 0 && ev.code == ABS_Y) {
-                       if (ev.value < dev->abs_min_y + lzone)
-                               down = KEY_UP;
-                       else if (ev.value > dev->abs_max_y - lzone)
-                               down = KEY_DOWN;
-                       last = &dev->abs_lasty;
-               }
-               else
-                       goto out;
-
-               if (down == *last)
-                       goto out;
-
-               if (down == 0 || *last != 0) {
-                       /* key up or direction change, return up event for old key */
-                       ret_kc = *last;
-                       ret_down = 0;
-                       *last = 0;
-                       goto out;
-               }
-               ret_kc = *last = down;
-               ret_down = 1;
-               goto out;
-       }
-
-out:
-       if (is_down != NULL)
-               *is_down = ret_down;
-
-       return ret_kc;
-}
-
-static const struct {
-       short key;
-       short pbtn;
-} key_pbtn_map[] =
-{
-       { KEY_UP,       PBTN_UP },
-       { KEY_DOWN,     PBTN_DOWN },
-       { KEY_LEFT,     PBTN_LEFT },
-       { KEY_RIGHT,    PBTN_RIGHT },
-       /* XXX: maybe better set this from it's plat code somehow */
-       /* Pandora */
-       { KEY_END,      PBTN_MOK },
-       { KEY_PAGEDOWN, PBTN_MBACK },
-       { KEY_HOME,     PBTN_MA2 },
-       { KEY_PAGEUP,   PBTN_MA3 },
-       { KEY_LEFTCTRL,   PBTN_MENU },
-       { KEY_RIGHTSHIFT, PBTN_L },
-       { KEY_RIGHTCTRL,  PBTN_R },
-       /* Caanoo */
-       { BTN_THUMB2,   PBTN_MOK },
-       { BTN_THUMB,    PBTN_MBACK },
-       { BTN_TRIGGER,  PBTN_MA2 },
-       { BTN_TOP,      PBTN_MA3 },
-       { BTN_BASE,     PBTN_MENU },
-       { BTN_TOP2,     PBTN_L },
-       { BTN_PINKIE,   PBTN_R },
-       /* "normal" keyboards */
-       { KEY_ENTER,    PBTN_MOK },
-       { KEY_ESC,      PBTN_MBACK },
-       { KEY_A,        PBTN_MA2 },
-       { KEY_S,        PBTN_MA3 },
-       { KEY_BACKSLASH,  PBTN_MENU },
-       { KEY_LEFTBRACE,  PBTN_L },
-       { KEY_RIGHTBRACE, PBTN_R },
-};
-
-#define KEY_PBTN_MAP_SIZE (sizeof(key_pbtn_map) / sizeof(key_pbtn_map[0]))
-
-static int in_evdev_menu_translate(void *drv_data, int keycode, char *charcode)
-{
-       in_evdev_t *dev = drv_data;
-       int ret = 0;
-       int i;
-
-       if (keycode < 0)
-       {
-               /* menu -> kc */
-               keycode = -keycode;
-               for (i = 0; i < KEY_PBTN_MAP_SIZE; i++)
-                       if (key_pbtn_map[i].pbtn == keycode) {
-                               int k = key_pbtn_map[i].key;
-                               /* should really check EVIOCGBIT, but this is enough for now */
-                               if (dev->kc_first <= k && k <= dev->kc_last)
-                                       return k;
-                       }
-       }
-       else
-       {
-               for (i = 0; i < KEY_PBTN_MAP_SIZE; i++) {
-                       if (key_pbtn_map[i].key == keycode) {
-                               ret = key_pbtn_map[i].pbtn;
-                               break;
-                       }
-               }
-
-               if (charcode != NULL && (unsigned int)keycode < KEY_CNT &&
-                   in_evdev_keys[keycode] != NULL && in_evdev_keys[keycode][1] == 0)
-               {
-                       char c = in_evdev_keys[keycode][0];
-                       if ('A' <= c && c <= 'Z')
-                               c = 'a' + c - 'A';
-                       ret |= PBTN_CHAR;
-                       *charcode = c;
-               }
-       }
-
-       return ret;
-}
-
-/* remove binds of missing keys, count remaining ones */
-static int in_evdev_clean_binds(void *drv_data, int *binds, int *def_binds)
-{
-       int keybits[KEY_CNT / sizeof(int)];
-       in_evdev_t *dev = drv_data;
-       int i, t, ret, offs, count = 0;
-
-       memset(keybits, 0, sizeof(keybits));
-       ret = ioctl(dev->fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits);
-       if (ret == -1) {
-               perror("in_evdev: ioctl failed");
-               // memset(keybits, 0xff, sizeof(keybits)); /* mark all as good */
-       }
-
-       if (dev->abs_to_digital && dev->abs_lzone != 0) {
-               KEYBITS_BIT_SET(KEY_LEFT);
-               KEYBITS_BIT_SET(KEY_RIGHT);
-               KEYBITS_BIT_SET(KEY_UP);
-               KEYBITS_BIT_SET(KEY_DOWN);
-       }
-
-       for (i = 0; i < KEY_CNT; i++) {
-               for (t = 0; t < IN_BINDTYPE_COUNT; t++) {
-                       offs = IN_BIND_OFFS(i, t);
-                       if (!KEYBITS_BIT(i))
-                               binds[offs] = def_binds[offs] = 0;
-                       if (binds[offs])
-                               count++;
-               }
-       }
-
-       return count;
-}
-
-static const in_drv_t in_evdev_drv = {
-       .prefix         = IN_EVDEV_PREFIX,
-       .probe          = in_evdev_probe,
-       .free           = in_evdev_free,
-       .get_key_names  = in_evdev_get_key_names,
-       .clean_binds    = in_evdev_clean_binds,
-       .get_config     = in_evdev_get_config,
-       .set_config     = in_evdev_set_config,
-       .update         = in_evdev_update,
-       .update_analog  = in_evdev_update_analog,
-       .update_keycode = in_evdev_update_keycode,
-       .menu_translate = in_evdev_menu_translate,
-};
-
-void in_evdev_init(const struct in_default_bind *defbinds)
-{
-       in_register_driver(&in_evdev_drv, defbinds);
-}
-
diff --git a/frontend/linux/in_evdev.h b/frontend/linux/in_evdev.h
deleted file mode 100644 (file)
index c5aef9b..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-
-struct in_default_bind;
-extern int in_evdev_allow_abs_only;
-
-void in_evdev_init(const struct in_default_bind *defbinds);
diff --git a/frontend/linux/plat.c b/frontend/linux/plat.c
deleted file mode 100644 (file)
index b7152b5..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * (C) Gražvydas "notaz" Ignotas, 2008-2010
- *
- * This work is licensed under the terms of any of these licenses
- * (at your option):
- *  - GNU GPL, version 2 or later.
- *  - GNU LGPL, version 2.1 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#define _GNU_SOURCE 1
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <dirent.h>
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
-#include <sys/mman.h>
-
-#include "../common/plat.h"
-
-
-int plat_is_dir(const char *path)
-{
-       DIR *dir;
-       if ((dir = opendir(path))) {
-               closedir(dir);
-               return 1;
-       }
-       return 0;
-}
-
-int plat_get_root_dir(char *dst, int len)
-{
-       int j, ret;
-
-       ret = readlink("/proc/self/exe", dst, len - 1);
-       if (ret < 0) {
-               perror("readlink");
-               ret = 0;
-       }
-       dst[ret] = 0;
-
-       for (j = strlen(dst); j > 0; j--)
-               if (dst[j] == '/') {
-                       dst[++j] = 0;
-                       break;
-               }
-
-       return j;
-}
-
-#ifdef __GP2X__
-/* Wiz has a borked gettimeofday().. */
-#define plat_get_ticks_ms plat_get_ticks_ms_good
-#define plat_get_ticks_us plat_get_ticks_us_good
-#endif
-
-unsigned int plat_get_ticks_ms(void)
-{
-       struct timeval tv;
-       unsigned int ret;
-
-       gettimeofday(&tv, NULL);
-
-       ret = (unsigned)tv.tv_sec * 1000;
-       /* approximate /= 1000 */
-       ret += ((unsigned)tv.tv_usec * 4195) >> 22;
-
-       return ret;
-}
-
-unsigned int plat_get_ticks_us(void)
-{
-       struct timeval tv;
-       unsigned int ret;
-
-       gettimeofday(&tv, NULL);
-
-       ret = (unsigned)tv.tv_sec * 1000000;
-       ret += (unsigned)tv.tv_usec;
-
-       return ret;
-}
-
-void plat_sleep_ms(int ms)
-{
-       usleep(ms * 1000);
-}
-
-int plat_wait_event(int *fds_hnds, int count, int timeout_ms)
-{
-       struct timeval tv, *timeout = NULL;
-       int i, ret, fdmax = -1;
-       fd_set fdset;
-
-       if (timeout_ms >= 0) {
-               tv.tv_sec = timeout_ms / 1000;
-               tv.tv_usec = (timeout_ms % 1000) * 1000;
-               timeout = &tv;
-       }
-
-       FD_ZERO(&fdset);
-       for (i = 0; i < count; i++) {
-               if (fds_hnds[i] > fdmax) fdmax = fds_hnds[i];
-               FD_SET(fds_hnds[i], &fdset);
-       }
-
-       ret = select(fdmax + 1, &fdset, NULL, NULL, timeout);
-       if (ret == -1)
-       {
-               perror("plat_wait_event: select failed");
-               sleep(1);
-               return -1;
-       }
-
-       if (ret == 0)
-               return -1; /* timeout */
-
-       ret = -1;
-       for (i = 0; i < count; i++)
-               if (FD_ISSET(fds_hnds[i], &fdset))
-                       ret = fds_hnds[i];
-
-       return ret;
-}
-
-void *plat_mmap(unsigned long addr, size_t size)
-{
-       void *req, *ret;
-
-       req = (void *)addr;
-       ret = mmap(req, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
-       if (ret == MAP_FAILED)
-               return NULL;
-       if (ret != req)
-               printf("warning: mmaped to %p, requested %p\n", ret, req);
-
-       return ret;
-}
-
-void *plat_mremap(void *ptr, size_t oldsize, size_t newsize)
-{
-       void *ret;
-
-       ret = mremap(ptr, oldsize, newsize, MREMAP_MAYMOVE);
-       if (ret == MAP_FAILED)
-               return NULL;
-       if (ret != ptr)
-               printf("warning: mremap moved: %p -> %p\n", ptr, ret);
-
-       return ret;
-}
-
-void plat_munmap(void *ptr, size_t size)
-{
-       munmap(ptr, size);
-}
-
-/* lprintf */
-void lprintf(const char *fmt, ...)
-{
-       va_list vl;
-
-       va_start(vl, fmt);
-       vprintf(fmt, vl);
-       va_end(vl);
-}
-
diff --git a/frontend/linux/plat_mmap.c b/frontend/linux/plat_mmap.c
new file mode 100644 (file)
index 0000000..db661b6
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * (C) Gražvydas "notaz" Ignotas, 2008-2010
+ *
+ * This work is licensed under the terms of any of these licenses
+ * (at your option):
+ *  - GNU GPL, version 2 or later.
+ *  - GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#define _GNU_SOURCE 1
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+// this is some dupe code to avoid libpicofe dep
+
+//#include "../libpicofe/plat.h"
+
+/* XXX: maybe unhardcode pagesize? */
+#define HUGETLB_PAGESIZE (2 * 1024 * 1024)
+#define HUGETLB_THRESHOLD (HUGETLB_PAGESIZE / 2)
+#ifndef MAP_HUGETLB
+#define MAP_HUGETLB 0x40000 /* arch specific */
+#endif
+
+void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed)
+{
+       static int hugetlb_disabled;
+       int prot = PROT_READ | PROT_WRITE;
+       int flags = MAP_PRIVATE | MAP_ANONYMOUS;
+       void *req, *ret;
+
+       req = (void *)addr;
+       if (need_exec)
+               prot |= PROT_EXEC;
+       if (is_fixed)
+               flags |= MAP_FIXED;
+       if (size >= HUGETLB_THRESHOLD && !hugetlb_disabled)
+               flags |= MAP_HUGETLB;
+
+       ret = mmap(req, size, prot, flags, -1, 0);
+       if (ret == MAP_FAILED && (flags & MAP_HUGETLB)) {
+               fprintf(stderr,
+                       "warning: failed to do hugetlb mmap (%p, %zu): %d\n",
+                       req, size, errno);
+               hugetlb_disabled = 1;
+               flags &= ~MAP_HUGETLB;
+               ret = mmap(req, size, prot, flags, -1, 0);
+       }
+       if (ret == MAP_FAILED)
+               return NULL;
+
+       if (req != NULL && ret != req)
+               fprintf(stderr,
+                       "warning: mmaped to %p, requested %p\n", ret, req);
+
+       return ret;
+}
+
+void *plat_mremap(void *ptr, size_t oldsize, size_t newsize)
+{
+       void *ret;
+
+       ret = mremap(ptr, oldsize, newsize, MREMAP_MAYMOVE);
+       if (ret == MAP_FAILED)
+               return NULL;
+       if (ret != ptr)
+               printf("warning: mremap moved: %p -> %p\n", ptr, ret);
+
+       return ret;
+}
+
+void plat_munmap(void *ptr, size_t size)
+{
+       int ret;
+
+       ret = munmap(ptr, size);
+       if (ret != 0 && (size & (HUGETLB_PAGESIZE - 1))) {
+               // prehaps an autorounded hugetlb mapping?
+               size = (size + HUGETLB_PAGESIZE - 1) & ~(HUGETLB_PAGESIZE - 1);
+               ret = munmap(ptr, size);
+       }
+       if (ret != 0) {
+               fprintf(stderr,
+                       "munmap(%p, %zu) failed: %d\n", ptr, size, errno);
+       }
+}
diff --git a/frontend/linux/plat_mmap.h b/frontend/linux/plat_mmap.h
new file mode 100644 (file)
index 0000000..175246e
--- /dev/null
@@ -0,0 +1,5 @@
+#include <stdlib.h>
+
+void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed);
+void *plat_mremap(void *ptr, size_t oldsize, size_t newsize);
+void  plat_munmap(void *ptr, size_t size);
diff --git a/frontend/linux/xenv.c b/frontend/linux/xenv.c
deleted file mode 100644 (file)
index 40bf92c..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * (C) Gražvydas "notaz" Ignotas, 2009-2012
- *
- * This work is licensed under the terms of any of these licenses
- * (at your option):
- *  - GNU GPL, version 2 or later.
- *  - GNU LGPL, version 2.1 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <pthread.h>
-
-#include <dlfcn.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/XKBlib.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <termios.h>
-#include <linux/kd.h>
-
-#include "xenv.h"
-
-#define PFX "xenv: "
-
-#define FPTR(f) typeof(f) * p##f
-#define FPTR_LINK(xf, dl, f) { \
-       xf.p##f = dlsym(dl, #f); \
-       if (xf.p##f == NULL) { \
-               fprintf(stderr, "missing symbol: %s\n", #f); \
-               goto fail; \
-       } \
-}
-
-struct xstuff {
-       Display *display;
-       Window window;
-       FPTR(XCreateBitmapFromData);
-       FPTR(XCreatePixmapCursor);
-       FPTR(XFreePixmap);
-       FPTR(XOpenDisplay);
-       FPTR(XDisplayName);
-       FPTR(XCloseDisplay);
-       FPTR(XCreateSimpleWindow);
-       FPTR(XChangeWindowAttributes);
-       FPTR(XSelectInput);
-       FPTR(XMapWindow);
-       FPTR(XNextEvent);
-       FPTR(XCheckTypedEvent);
-       FPTR(XWithdrawWindow);
-       FPTR(XGrabKeyboard);
-       FPTR(XPending);
-       FPTR(XLookupKeysym);
-       FPTR(XkbSetDetectableAutoRepeat);
-       FPTR(XStoreName);
-       FPTR(XIconifyWindow);
-       FPTR(XMoveResizeWindow);
-       FPTR(XInternAtom);
-       FPTR(XSetWMHints);
-       FPTR(XSync);
-};
-
-static struct xstuff g_xstuff;
-
-static Cursor transparent_cursor(struct xstuff *xf, Display *display, Window win)
-{
-       Cursor cursor;
-       Pixmap pix;
-       XColor dummy;
-       char d = 0;
-
-       memset(&dummy, 0, sizeof(dummy));
-       pix = xf->pXCreateBitmapFromData(display, win, &d, 1, 1);
-       cursor = xf->pXCreatePixmapCursor(display, pix, pix,
-                       &dummy, &dummy, 0, 0);
-       xf->pXFreePixmap(display, pix);
-       return cursor;
-}
-
-static int x11h_init(int *xenv_flags, const char *window_title)
-{
-       unsigned int display_width, display_height;
-       Display *display;
-       XSetWindowAttributes attributes;
-       Window win;
-       Visual *visual;
-       long evt_mask;
-       void *x11lib;
-       int screen;
-
-       memset(&g_xstuff, 0, sizeof(g_xstuff));
-       x11lib = dlopen("libX11.so.6", RTLD_LAZY);
-       if (x11lib == NULL) {
-               fprintf(stderr, "libX11.so load failed:\n%s\n", dlerror());
-               goto fail;
-       }
-       FPTR_LINK(g_xstuff, x11lib, XCreateBitmapFromData);
-       FPTR_LINK(g_xstuff, x11lib, XCreatePixmapCursor);
-       FPTR_LINK(g_xstuff, x11lib, XFreePixmap);
-       FPTR_LINK(g_xstuff, x11lib, XOpenDisplay);
-       FPTR_LINK(g_xstuff, x11lib, XDisplayName);
-       FPTR_LINK(g_xstuff, x11lib, XCloseDisplay);
-       FPTR_LINK(g_xstuff, x11lib, XCreateSimpleWindow);
-       FPTR_LINK(g_xstuff, x11lib, XChangeWindowAttributes);
-       FPTR_LINK(g_xstuff, x11lib, XSelectInput);
-       FPTR_LINK(g_xstuff, x11lib, XMapWindow);
-       FPTR_LINK(g_xstuff, x11lib, XNextEvent);
-       FPTR_LINK(g_xstuff, x11lib, XCheckTypedEvent);
-       FPTR_LINK(g_xstuff, x11lib, XWithdrawWindow);
-       FPTR_LINK(g_xstuff, x11lib, XGrabKeyboard);
-       FPTR_LINK(g_xstuff, x11lib, XPending);
-       FPTR_LINK(g_xstuff, x11lib, XLookupKeysym);
-       FPTR_LINK(g_xstuff, x11lib, XkbSetDetectableAutoRepeat);
-       FPTR_LINK(g_xstuff, x11lib, XStoreName);
-       FPTR_LINK(g_xstuff, x11lib, XIconifyWindow);
-       FPTR_LINK(g_xstuff, x11lib, XMoveResizeWindow);
-       FPTR_LINK(g_xstuff, x11lib, XInternAtom);
-       FPTR_LINK(g_xstuff, x11lib, XSetWMHints);
-       FPTR_LINK(g_xstuff, x11lib, XSync);
-
-       //XInitThreads();
-
-       g_xstuff.display = display = g_xstuff.pXOpenDisplay(NULL);
-       if (display == NULL)
-       {
-               fprintf(stderr, "cannot connect to X server %s, X handling disabled.\n",
-                               g_xstuff.pXDisplayName(NULL));
-               goto fail2;
-       }
-
-       visual = DefaultVisual(display, 0);
-       if (visual->class != TrueColor)
-               fprintf(stderr, PFX "warning: non true color visual\n");
-
-       printf(PFX "X vendor: %s, rel: %d, display: %s, protocol ver: %d.%d\n", ServerVendor(display),
-               VendorRelease(display), DisplayString(display), ProtocolVersion(display),
-               ProtocolRevision(display));
-
-       screen = DefaultScreen(display);
-
-       display_width = DisplayWidth(display, screen);
-       display_height = DisplayHeight(display, screen);
-       printf(PFX "display is %dx%d\n", display_width, display_height);
-
-       g_xstuff.window = win = g_xstuff.pXCreateSimpleWindow(display,
-               RootWindow(display, screen), 0, 0, display_width, display_height,
-               0, BlackPixel(display, screen), BlackPixel(display, screen));
-
-       attributes.override_redirect = True;
-       attributes.cursor = transparent_cursor(&g_xstuff, display, win);
-       g_xstuff.pXChangeWindowAttributes(display, win, CWOverrideRedirect | CWCursor, &attributes);
-
-       if (window_title != NULL)
-               g_xstuff.pXStoreName(display, win, window_title);
-       evt_mask = ExposureMask | FocusChangeMask | PropertyChangeMask;
-       if (xenv_flags && (*xenv_flags & XENV_CAP_KEYS))
-               evt_mask |= KeyPressMask | KeyReleaseMask;
-       if (xenv_flags && (*xenv_flags & XENV_CAP_MOUSE))
-               evt_mask |= ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
-       g_xstuff.pXSelectInput(display, win, evt_mask);
-       g_xstuff.pXMapWindow(display, win);
-       g_xstuff.pXGrabKeyboard(display, win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
-       g_xstuff.pXkbSetDetectableAutoRepeat(display, 1, NULL);
-       // XSetIOErrorHandler
-
-       // we don't know when event dispatch will be called, so sync now
-       g_xstuff.pXSync(display, False);
-
-       return 0;
-fail2:
-       dlclose(x11lib);
-fail:
-       g_xstuff.display = NULL;
-       fprintf(stderr, "x11 handling disabled.\n");
-       return -1;
-}
-
-static void x11h_update(int (*key_cb)(void *cb_arg, int kc, int is_pressed),
-                       int (*mouseb_cb)(void *cb_arg, int x, int y, int button, int is_pressed),
-                       int (*mousem_cb)(void *cb_arg, int x, int y),
-                       void *cb_arg)
-{
-       XEvent evt;
-       int keysym;
-
-       while (g_xstuff.pXPending(g_xstuff.display))
-       {
-               g_xstuff.pXNextEvent(g_xstuff.display, &evt);
-               switch (evt.type)
-               {
-               case Expose:
-                       while (g_xstuff.pXCheckTypedEvent(g_xstuff.display, Expose, &evt))
-                               ;
-                       break;
-
-               case KeyPress:
-                       keysym = g_xstuff.pXLookupKeysym(&evt.xkey, 0);
-                       if (key_cb != NULL)
-                               key_cb(cb_arg, keysym, 1);
-                       break;
-
-               case KeyRelease:
-                       keysym = g_xstuff.pXLookupKeysym(&evt.xkey, 0);
-                       if (key_cb != NULL)
-                               key_cb(cb_arg, keysym, 0);
-                       break;
-
-               case ButtonPress:
-                       if (mouseb_cb != NULL)
-                               mouseb_cb(cb_arg, evt.xbutton.x, evt.xbutton.y,
-                                         evt.xbutton.button, 1);
-                       break;
-
-               case ButtonRelease:
-                       if (mouseb_cb != NULL)
-                               mouseb_cb(cb_arg, evt.xbutton.x, evt.xbutton.y,
-                                         evt.xbutton.button, 0);
-                       break;
-
-               case MotionNotify:
-                       if (mousem_cb != NULL)
-                               mousem_cb(cb_arg, evt.xmotion.x, evt.xmotion.y);
-                       break;
-               }
-       }
-}
-
-static void x11h_wait_vmstate(void)
-{
-       Atom wm_state = g_xstuff.pXInternAtom(g_xstuff.display, "WM_STATE", False);
-       XEvent evt;
-       int i;
-
-       usleep(20000);
-
-       for (i = 0; i < 20; i++) {
-               while (g_xstuff.pXPending(g_xstuff.display)) {
-                       g_xstuff.pXNextEvent(g_xstuff.display, &evt);
-                       // printf("w event %d\n", evt.type);
-                       if (evt.type == PropertyNotify && evt.xproperty.atom == wm_state)
-                               return;
-               }
-               usleep(200000);
-       }
-
-       fprintf(stderr, PFX "timeout waiting for wm_state change\n");
-}
-
-static int x11h_minimize(void)
-{
-       XSetWindowAttributes attributes;
-       Display *display = g_xstuff.display;
-       Window window = g_xstuff.window;
-       int screen = DefaultScreen(g_xstuff.display);
-       int display_width, display_height;
-       XWMHints wm_hints;
-       XEvent evt;
-
-       g_xstuff.pXWithdrawWindow(display, window, screen);
-
-       attributes.override_redirect = False;
-       g_xstuff.pXChangeWindowAttributes(display, window,
-               CWOverrideRedirect, &attributes);
-
-       wm_hints.flags = StateHint;
-       wm_hints.initial_state = IconicState;
-       g_xstuff.pXSetWMHints(display, window, &wm_hints);
-
-       g_xstuff.pXMapWindow(display, window);
-
-       while (g_xstuff.pXNextEvent(display, &evt) == 0)
-       {
-               // printf("m event %d\n", evt.type);
-               switch (evt.type)
-               {
-                       case FocusIn:
-                               goto out;
-                       default:
-                               break;
-               }
-       }
-
-out:
-       g_xstuff.pXWithdrawWindow(display, window, screen);
-
-       // must wait for some magic vmstate property change before setting override_redirect
-       x11h_wait_vmstate();
-
-       attributes.override_redirect = True;
-       g_xstuff.pXChangeWindowAttributes(display, window,
-               CWOverrideRedirect, &attributes);
-
-       // fixup window after resize on override_redirect loss
-       display_width = DisplayWidth(display, screen);
-       display_height = DisplayHeight(display, screen);
-       g_xstuff.pXMoveResizeWindow(display, window, 0, 0, display_width, display_height);
-
-       g_xstuff.pXMapWindow(display, window);
-       g_xstuff.pXGrabKeyboard(display, window, False, GrabModeAsync, GrabModeAsync, CurrentTime);
-       g_xstuff.pXkbSetDetectableAutoRepeat(display, 1, NULL);
-
-       // we don't know when event dispatch will be called, so sync now
-       g_xstuff.pXSync(display, False);
-
-       return 0;
-}
-
-static struct termios g_kbd_termios_saved;
-static int g_kbdfd = -1;
-
-static int tty_init(void)
-{
-       struct termios kbd_termios;
-       int mode;
-
-       g_kbdfd = open("/dev/tty", O_RDWR);
-       if (g_kbdfd == -1) {
-               perror(PFX "open /dev/tty");
-               return -1;
-       }
-
-       if (ioctl(g_kbdfd, KDGETMODE, &mode) == -1) {
-               perror(PFX "(not hiding FB): KDGETMODE");
-               goto fail;
-       }
-
-       if (tcgetattr(g_kbdfd, &kbd_termios) == -1) {
-               perror(PFX "tcgetattr");
-               goto fail;
-       }
-
-       g_kbd_termios_saved = kbd_termios;
-       kbd_termios.c_lflag &= ~(ICANON | ECHO); // | ISIG);
-       kbd_termios.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
-       kbd_termios.c_cc[VMIN] = 0;
-       kbd_termios.c_cc[VTIME] = 0;
-
-       if (tcsetattr(g_kbdfd, TCSAFLUSH, &kbd_termios) == -1) {
-               perror(PFX "tcsetattr");
-               goto fail;
-       }
-
-       if (ioctl(g_kbdfd, KDSETMODE, KD_GRAPHICS) == -1) {
-               perror(PFX "KDSETMODE KD_GRAPHICS");
-               tcsetattr(g_kbdfd, TCSAFLUSH, &g_kbd_termios_saved);
-               goto fail;
-       }
-
-       return 0;
-
-fail:
-       close(g_kbdfd);
-       g_kbdfd = -1;
-       return -1;
-}
-
-static void tty_end(void)
-{
-       if (g_kbdfd < 0)
-               return;
-
-       if (ioctl(g_kbdfd, KDSETMODE, KD_TEXT) == -1)
-               perror(PFX "KDSETMODE KD_TEXT");
-
-       if (tcsetattr(g_kbdfd, TCSAFLUSH, &g_kbd_termios_saved) == -1)
-               perror(PFX "tcsetattr");
-
-       close(g_kbdfd);
-       g_kbdfd = -1;
-}
-
-int xenv_init(int *xenv_flags, const char *window_title)
-{
-       int ret;
-
-       ret = x11h_init(xenv_flags, window_title);
-       if (ret == 0)
-               goto out;
-
-       if (xenv_flags != NULL)
-               *xenv_flags &= ~(XENV_CAP_KEYS | XENV_CAP_MOUSE); /* TODO? */
-       ret = tty_init();
-       if (ret == 0)
-               goto out;
-
-       fprintf(stderr, PFX "error: both x11h_init and tty_init failed\n");
-       ret = -1;
-out:
-       return ret;
-}
-
-int xenv_update(int (*key_cb)(void *cb_arg, int kc, int is_pressed),
-               int (*mouseb_cb)(void *cb_arg, int x, int y, int button, int is_pressed),
-               int (*mousem_cb)(void *cb_arg, int x, int y),
-               void *cb_arg)
-{
-       if (g_xstuff.display) {
-               x11h_update(key_cb, mouseb_cb, mousem_cb, cb_arg);
-               return 0;
-       }
-
-       // TODO: read tty?
-       return -1;
-}
-
-/* blocking minimize until user maximizes again */
-int xenv_minimize(void)
-{
-       int ret;
-
-       if (g_xstuff.display) {
-               xenv_update(NULL, NULL, NULL, NULL);
-               ret = x11h_minimize();
-               xenv_update(NULL, NULL, NULL, NULL);
-               return ret;
-       }
-
-       return -1;
-}
-
-void xenv_finish(void)
-{
-       // TODO: cleanup X?
-       tty_end();
-}
-
-#if 0
-int main()
-{
-       int i, r, d;
-
-       xenv_init("just a test");
-
-       for (i = 0; i < 5; i++) {
-               while ((r = xenv_update(&d)) > 0)
-                       printf("%d %x %d\n", d, r, r);
-               sleep(1);
-
-               if (i == 1)
-                       xenv_minimize();
-               printf("ll %d\n", i);
-       }
-
-       printf("xenv_finish..\n");
-       xenv_finish();
-
-       return 0;
-}
-#endif
diff --git a/frontend/linux/xenv.h b/frontend/linux/xenv.h
deleted file mode 100644 (file)
index 6abda19..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-
-#define XENV_CAP_KEYS  (1<<0)
-#define XENV_CAP_MOUSE (1<<1)
-
-/* xenv_flags specify if we need keys and mouse,
- * on return, flag is removed if input is not available */
-int  xenv_init(int *xenv_flags, const char *window_title);
-
-/* read events from X, calling key_cb for key, mouseb_cb for mouse button
- * and mousem_cb for mouse motion events */
-int  xenv_update(int (*key_cb)(void *cb_arg, int kc, int is_pressed),
-                int (*mouseb_cb)(void *cb_arg, int x, int y, int button, int is_pressed),
-                int (*mousem_cb)(void *cb_arg, int x, int y),
-                void *cb_arg);
-
-int  xenv_minimize(void);
-void xenv_finish(void);
-
index 19e8319..29d2c25 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * (C) notaz, 2010-2011
+ * (C) notaz, 2010-2012
  *
  * This work is licensed under the terms of the GNU GPLv2 or later.
  * See the COPYING file in the top-level directory.
 #include "../libpcsxcore/cheat.h"
 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
 #include "../plugins/cdrcimg/cdrcimg.h"
-#include "common/plat.h"
-#include "common/readpng.h"
-#include "common/input.h"
-#include "linux/in_evdev.h"
 #include "revision.h"
 
+#ifndef NO_FRONTEND
+#include "libpicofe/input.h"
+#include "libpicofe/plat.h"
+#include "libpicofe/readpng.h"
+#endif
+#ifndef BOOT_MSG
+#define BOOT_MSG "Booting up..."
+#endif
+
 // don't include debug.h - it breaks ARM build (R1 redefined)
 void StartDebugger();
 void StopDebugger();
@@ -49,6 +54,8 @@ enum sched_action emu_action, emu_action_old;
 char hud_msg[64];
 int hud_new_msg;
 
+static void toggle_fast_forward(int force_off);
+
 static void make_path(char *buf, size_t size, const char *dir, const char *fname)
 {
        if (fname)
@@ -143,6 +150,8 @@ void emu_set_default_config(void)
        Config.PsxAuto = 1;
 
        pl_rearmed_cbs.gpu_neon.allow_interlace = 2; // auto
+       pl_rearmed_cbs.gpu_neon.enhancement_enable =
+       pl_rearmed_cbs.gpu_neon.enhancement_no_main = 0;
        pl_rearmed_cbs.gpu_peops.iUseDither = 0;
        pl_rearmed_cbs.gpu_peops.dwActFixes = 1<<7;
        pl_rearmed_cbs.gpu_unai.abe_hack =
@@ -203,6 +212,7 @@ void do_emu_action(void)
                break;
 #ifndef NO_FRONTEND
        case SACTION_ENTER_MENU:
+               toggle_fast_forward(1);
                menu_loop();
                return;
        case SACTION_NEXT_SSLOT:
@@ -230,6 +240,34 @@ do_state_slot:
                        pl_rearmed_cbs.frameskip == 0 ? "OFF" : "1" );
                plugin_call_rearmed_cbs();
                break;
+       case SACTION_SWITCH_DISPMODE:
+               pl_switch_dispmode();
+               plugin_call_rearmed_cbs();
+               if (GPU_open != NULL && GPU_close != NULL) {
+                       GPU_close();
+                       GPU_open(&gpuDisp, "PCSX", NULL);
+               }
+               break;
+       case SACTION_FAST_FORWARD:
+               toggle_fast_forward(0);
+               plugin_call_rearmed_cbs();
+               break;
+       case SACTION_TOGGLE_FPS:
+               if ((g_opts & (OPT_SHOWFPS|OPT_SHOWCPU))
+                   == (OPT_SHOWFPS|OPT_SHOWCPU))
+                       g_opts &= ~(OPT_SHOWFPS|OPT_SHOWCPU);
+               else if (g_opts & OPT_SHOWFPS)
+                       g_opts |= OPT_SHOWCPU;
+               else
+                       g_opts |= OPT_SHOWFPS;
+               break;
+       case SACTION_TOGGLE_FULLSCREEN:
+               g_fullscreen = !g_fullscreen;
+               if (GPU_open != NULL && GPU_close != NULL) {
+                       GPU_close();
+                       GPU_open(&gpuDisp, "PCSX", NULL);
+               }
+               break;
        case SACTION_SCREENSHOT:
                {
                        char buf[MAXPATHLEN];
@@ -252,7 +290,7 @@ do_state_slot:
                }
        case SACTION_VOLUME_UP:
        case SACTION_VOLUME_DOWN:
-               plat_step_volume(emu_action == SACTION_VOLUME_UP);
+               plat_target_step_volume(emu_action == SACTION_VOLUME_UP);
                return;
        case SACTION_MINIMIZE:
                if (GPU_close != NULL)
@@ -374,7 +412,7 @@ out:
        fclose(f);
 }
 
-void emu_on_new_cd(void)
+void emu_on_new_cd(int show_hud_msg)
 {
        ClearAllCheats();
        parse_cwcheat();
@@ -384,8 +422,10 @@ void emu_on_new_cd(void)
                printf("----------------------------------------------------------\n");
        }
 
-       snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
-       hud_new_msg = 2;
+       if (show_hud_msg) {
+               snprintf(hud_msg, sizeof(hud_msg), BOOT_MSG);
+               hud_new_msg = 3;
+       }
 }
 
 int emu_core_preinit(void)
@@ -541,11 +581,17 @@ int main(int argc, char *argv[])
                                printf(_("Could not load CD-ROM!\n"));
                                return -1;
                        }
-                       emu_on_new_cd();
+                       emu_on_new_cd(!loadst);
                        ready_to_go = 1;
                }
        }
 
+       if (loadst_f) {
+               int ret = LoadState(loadst_f);
+               printf("%s state file: %s\n", ret ? "failed to load" : "loaded", loadst_f);
+               ready_to_go |= ret == 0;
+       }
+
        if (ready_to_go) {
                menu_prepare_emu();
 
@@ -554,10 +600,6 @@ int main(int argc, char *argv[])
                        int ret = emu_load_state(loadst - 1);
                        printf("%s state %d\n", ret ? "failed to load" : "loaded", loadst);
                }
-               if (loadst_f) {
-                       int ret = LoadState(loadst_f);
-                       printf("%s state file: %s\n", ret ? "failed to load" : "loaded", loadst_f);
-               }
        }
        else
                menu_loop();
@@ -576,6 +618,40 @@ int main(int argc, char *argv[])
 
        return 0;
 }
+
+static void toggle_fast_forward(int force_off)
+{
+       static int fast_forward;
+       static int normal_g_opts;
+       static int normal_frameskip;
+       static int normal_enhancement_enable;
+
+       if (force_off && !fast_forward)
+               return;
+
+       fast_forward = !fast_forward;
+       if (fast_forward) {
+               normal_g_opts = g_opts;
+               normal_frameskip = pl_rearmed_cbs.frameskip;
+               normal_enhancement_enable =
+                       pl_rearmed_cbs.gpu_neon.enhancement_enable;
+
+               g_opts |= OPT_NO_FRAMELIM;
+               pl_rearmed_cbs.frameskip = 3;
+               pl_rearmed_cbs.gpu_neon.enhancement_enable = 0;
+       } else {
+               g_opts = normal_g_opts;
+               pl_rearmed_cbs.frameskip = normal_frameskip;
+               pl_rearmed_cbs.gpu_neon.enhancement_enable =
+                       normal_enhancement_enable;
+
+               pl_timing_prepare(Config.PsxType);
+       }
+
+       if (!force_off)
+               snprintf(hud_msg, sizeof(hud_msg), "FAST FORWARD %s",
+                       fast_forward ? "ON" : "OFF");
+}
 #endif
 
 void SysRunGui() {
@@ -665,6 +741,8 @@ int emu_load_state(int slot)
        char fname[MAXPATHLEN];
        int ret;
 
+       hud_msg[0] = 0;
+
        ret = get_state_filename(fname, sizeof(fname), slot);
        if (ret != 0)
                return ret;
@@ -848,15 +926,6 @@ void *SysLoadLibrary(const char *lib) {
                                return (void *)(long)(PLUGIN_DL_BASE + builtin_plugin_ids[i]);
        }
 
-#if defined(__x86_64__) || defined(__i386__)
-       // convenience hack
-       if (strstr(lib, ".x86") == NULL) {
-               char name[MAXPATHLEN];
-               snprintf(name, sizeof(name), "%s.x86_64", lib);
-               lib = name;
-       }
-#endif
-
        ret = dlopen(lib, RTLD_NOW);
        if (ret == NULL)
                fprintf(stderr, "dlopen: %s\n", dlerror());
index bdb4870..45e0aeb 100644 (file)
@@ -42,7 +42,7 @@ int emu_core_preinit(void);
 int emu_core_init(void);
 
 void emu_set_default_config(void);
-void emu_on_new_cd(void);
+void emu_on_new_cd(int show_hud_msg);
 
 int get_state_filename(char *buf, int size, int i);
 int emu_check_state(int slot);
@@ -65,10 +65,14 @@ enum sched_action {
        SACTION_NEXT_SSLOT,
        SACTION_PREV_SSLOT,
        SACTION_TOGGLE_FSKIP,
+       SACTION_SWITCH_DISPMODE,
+       SACTION_FAST_FORWARD,
        SACTION_SCREENSHOT,
        SACTION_VOLUME_UP,
        SACTION_VOLUME_DOWN,
        SACTION_MINIMIZE,
+       SACTION_TOGGLE_FPS,
+       SACTION_TOGGLE_FULLSCREEN,
        SACTION_GUN_TRIGGER = 16,
        SACTION_GUN_A,
        SACTION_GUN_B,
index 42a53e1..57c8d17 100644 (file)
 #include "plugin_lib.h"
 #include "plat.h"
 #include "pcnt.h"
-#include "common/plat.h"
-#include "common/input.h"
-#include "linux/in_evdev.h"
+#include "libpicofe/plat.h"
+#include "libpicofe/input.h"
+#include "libpicofe/linux/in_evdev.h"
+#include "libpicofe/plat.h"
 #include "../libpcsxcore/misc.h"
 #include "../libpcsxcore/cdrom.h"
 #include "../libpcsxcore/cdriso.h"
 #include "../libpcsxcore/cheat.h"
 #include "../libpcsxcore/psemu_plugin_defs.h"
 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
-#include "../plugins/dfinput/main.h"
+#include "../plugins/dfinput/externals.h"
 #include "../plugins/gpulib/cspace.h"
 #include "revision.h"
 
@@ -72,22 +73,26 @@ typedef enum
        MA_OPT_SAVECFG_GAME,
        MA_OPT_CPU_CLOCKS,
        MA_OPT_DISP_OPTS,
-       MA_OPT_SCALER,
+       MA_OPT_VARSCALER,
+       MA_OPT_VARSCALER_C,
        MA_OPT_SCALER2,
-       MA_OPT_FILTERING,
-       MA_OPT_SCALER_C,
+       MA_OPT_HWFILTER,
+       MA_OPT_SWFILTER,
+       MA_OPT_GAMMA,
+       MA_OPT_VIDOVERLAY,
 } menu_id;
 
 static int last_vout_w, last_vout_h, last_vout_bpp;
 static int cpu_clock, cpu_clock_st, volume_boost, frameskip;
 static char rom_fname_reload[MAXPATHLEN];
 static char last_selected_fname[MAXPATHLEN];
-static int warned_about_bios, region, in_type_sel1, in_type_sel2;
+static int config_save_counter, region, in_type_sel1, in_type_sel2;
 static int psx_clock;
 static int memcard1_sel, memcard2_sel;
-int g_opts, g_scaler;
+int g_opts, g_scaler, g_gamma = 100;
 int soft_scaling, analog_deadzone; // for Caanoo
-int filter;
+int g_use_overlay, g_fullscreen;
+int filter, soft_filter;
 
 #ifdef __ARM_ARCH_7A__
 #define DEFAULT_PSX_CLOCK 57
@@ -109,6 +114,18 @@ static const char *spu_plugins[16];
 static const char *memcards[32];
 static int bios_sel, gpu_plugsel, spu_plugsel;
 
+#ifndef UI_FEATURES_H
+#define MENU_BIOS_PATH "bios/"
+#define MENU_SHOW_VARSCALER 0
+#define MENU_SHOW_VIDOVERLAY 1
+#define MENU_SHOW_SCALER2 0
+#define MENU_SHOW_NUBS_BTNS 0
+#define MENU_SHOW_VIBRATION 0
+#define MENU_SHOW_DEADZONE 0
+#define MENU_SHOW_MINIMIZE 0
+#define MENU_SHOW_FULLSCREEN 1
+#define MENU_SHOW_VOLUME 0
+#endif
 
 static int min(int x, int y) { return x < y ? x : y; }
 static int max(int x, int y) { return x > y ? x : y; }
@@ -213,6 +230,9 @@ static void menu_set_defconfig(void)
        frameskip = 0;
        analog_deadzone = 50;
        soft_scaling = 1;
+       soft_filter = 0;
+       g_use_overlay = 1;
+       g_fullscreen = 0;
        psx_clock = DEFAULT_PSX_CLOCK;
 
        region = 0;
@@ -234,6 +254,9 @@ static void menu_set_defconfig(void)
 #define CE_INTVAL(val) \
        { #val, sizeof(val), &val }
 
+#define CE_INTVAL_N(name, val) \
+       { name, sizeof(val), &val }
+
 #define CE_INTVAL_P(val) \
        { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
 
@@ -274,12 +297,17 @@ static const struct {
        CE_INTVAL(g_layer_w),
        CE_INTVAL(g_layer_h),
        CE_INTVAL(filter),
+       CE_INTVAL(soft_filter),
+       CE_INTVAL(g_use_overlay),
+       CE_INTVAL(g_fullscreen),
        CE_INTVAL(state_slot),
        CE_INTVAL(cpu_clock),
        CE_INTVAL(g_opts),
        CE_INTVAL(in_type_sel1),
        CE_INTVAL(in_type_sel2),
        CE_INTVAL(analog_deadzone),
+       CE_INTVAL_N("adev0_is_nublike", in_adev_is_nublike[0]),
+       CE_INTVAL_N("adev1_is_nublike", in_adev_is_nublike[1]),
        CE_INTVAL_V(frameskip, 3),
        CE_INTVAL_P(gpu_peops.iUseDither),
        CE_INTVAL_P(gpu_peops.dwActFixes),
@@ -288,6 +316,8 @@ static const struct {
        CE_INTVAL_P(gpu_unai.no_light),
        CE_INTVAL_P(gpu_unai.no_blend),
        CE_INTVAL_P(gpu_neon.allow_interlace),
+       CE_INTVAL_P(gpu_neon.enhancement_enable),
+       CE_INTVAL_P(gpu_neon.enhancement_no_main),
        CE_INTVAL_P(gpu_peopsgl.bDrawDither),
        CE_INTVAL_P(gpu_peopsgl.iFilterType),
        CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
@@ -301,7 +331,7 @@ static const struct {
        CE_INTVAL_V(iUseReverb, 3),
        CE_INTVAL_V(iXAPitch, 3),
        CE_INTVAL_V(iUseInterpolation, 3),
-       CE_INTVAL(warned_about_bios),
+       CE_INTVAL(config_save_counter),
        CE_INTVAL(in_evdev_allow_abs_only),
        CE_INTVAL(volume_boost),
        CE_INTVAL(psx_clock),
@@ -340,6 +370,8 @@ static int menu_write_config(int is_game)
        FILE *f;
        int i;
 
+       config_save_counter++;
+
        make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
        f = fopen(cfgfile, "w");
        if (f == NULL) {
@@ -552,9 +584,7 @@ static const char *filter_exts[] = {
 #define MENU_X2 0
 #endif
 
-#define menu_init menu_init_common
-#include "common/menu.c"
-#undef menu_init
+#include "libpicofe/menu.c"
 
 // a bit of black magic here
 static void draw_savestate_bg(int slot)
@@ -602,12 +632,18 @@ static void draw_savestate_bg(int slot)
 
        x = gpu->ulControl[5] & 0x3ff;
        y = (gpu->ulControl[5] >> 10) & 0x1ff;
-       s = (u16 *)gpu->psxVRam + y * 1024 + x;
        w = psx_widths[(gpu->ulStatus >> 16) & 7];
        tmp = gpu->ulControl[7];
        h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
        if (gpu->ulStatus & 0x80000) // doubleheight
                h *= 2;
+       if (h <= 0 || h > 512)
+               goto out;
+       if (y > 512 - 64)
+               y = 0;
+       if (y + h > 512)
+               h = 512 - y;
+       s = (u16 *)gpu->psxVRam + y * 1024 + x;
 
        x = max(0, g_menuscreen_w - w) & ~3;
        y = max(0, g_menuscreen_h / 2 - h / 2);
@@ -661,15 +697,23 @@ me_bind_action emuctrl_actions[] =
        { "Next Save Slot   ", 1 << SACTION_NEXT_SSLOT },
        { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
        { "Take Screenshot  ", 1 << SACTION_SCREENSHOT },
-       { "Enter Menu       ", 1 << SACTION_ENTER_MENU },
-#ifdef __ARM_ARCH_7A__ /* XXX */
+       { "Show/Hide FPS    ", 1 << SACTION_TOGGLE_FPS },
+#ifdef __ARM_ARCH_7A__
+       { "Switch Renderer  ", 1 << SACTION_SWITCH_DISPMODE },
+#endif
+       { "Fast Forward     ", 1 << SACTION_FAST_FORWARD },
+#if MENU_SHOW_MINIMIZE
        { "Minimize         ", 1 << SACTION_MINIMIZE },
 #endif
+#if MENU_SHOW_FULLSCREEN
+       { "Toggle fullscreen", 1 << SACTION_TOGGLE_FULLSCREEN },
+#endif
+       { "Enter Menu       ", 1 << SACTION_ENTER_MENU },
        { "Gun Trigger      ", 1 << SACTION_GUN_TRIGGER },
        { "Gun A button     ", 1 << SACTION_GUN_A },
        { "Gun B button     ", 1 << SACTION_GUN_B },
        { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
-#ifndef __ARM_ARCH_7A__ /* XXX */
+#if MENU_SHOW_VOLUME
        { "Volume Up        ", 1 << SACTION_VOLUME_UP },
        { "Volume Down      ", 1 << SACTION_VOLUME_DOWN },
 #endif
@@ -887,17 +931,21 @@ static int key_config_loop_wrap(int id, int keys)
        return 0;
 }
 
+static const char h_nubmode[] = "Maps nub-like analog controls to PSX ones better\n"
+                               "Might cause problems with real analog sticks";
 static const char *adevnames[IN_MAX_DEVS + 2];
 static int stick_sel[2];
 
 static menu_entry e_menu_keyconfig_analog[] =
 {
-       mee_enum ("Left stick (L3)",  0, stick_sel[0], adevnames),
-       mee_range("  X axis",    0, in_adev_axis[0][0], 0, 7),
-       mee_range("  Y axis",    0, in_adev_axis[0][1], 0, 7),
-       mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
-       mee_range("  X axis",    0, in_adev_axis[1][0], 0, 7),
-       mee_range("  Y axis",    0, in_adev_axis[1][1], 0, 7),
+       mee_enum   ("Left stick (L3)",  0, stick_sel[0], adevnames),
+       mee_range  ("  X axis",    0, in_adev_axis[0][0], 0, 7),
+       mee_range  ("  Y axis",    0, in_adev_axis[0][1], 0, 7),
+       mee_onoff_h("  nub mode",  0, in_adev_is_nublike[0], 1, h_nubmode),
+       mee_enum   ("Right stick (R3)", 0, stick_sel[1], adevnames),
+       mee_range  ("  X axis",    0, in_adev_axis[1][0], 0, 7),
+       mee_range  ("  Y axis",    0, in_adev_axis[1][1], 0, 7),
+       mee_onoff_h("  nub mode",  0, in_adev_is_nublike[1], 1, h_nubmode),
        mee_end,
 };
 
@@ -964,9 +1012,9 @@ static const char *mgn_saveloadcfg(int id, int *offs)
 static int mh_savecfg(int id, int keys)
 {
        if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
-               me_update_msg("config saved");
+               menu_update_msg("config saved");
        else
-               me_update_msg("failed to write config");
+               menu_update_msg("failed to write config");
 
        return 1;
 }
@@ -975,7 +1023,7 @@ static int mh_input_rescan(int id, int keys)
 {
        //menu_sync_config();
        in_probe();
-       me_update_msg("rescan complete.");
+       menu_update_msg("rescan complete.");
 
        return 0;
 }
@@ -1029,9 +1077,17 @@ static int menu_loop_keyconfig(int id, int keys)
 // ------------ gfx options menu ------------
 
 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
+static const char *men_soft_filter[] = { "None",
+#ifdef __ARM_NEON__
+       "scale2x", "eagle2x",
+#endif
+       NULL };
+static const char *men_dummy[] = { NULL };
 static const char h_cscaler[]   = "Displays the scaler layer, you can resize it\n"
                                  "using d-pad or move it using R+d-pad";
-static const char *men_dummy[] = { NULL };
+static const char h_overlay[]   = "Overlay provides hardware accelerated scaling";
+static const char h_soft_filter[] = "Works only if game uses low resolution modes";
+static const char h_gamma[]     = "Gamma/brightness adjustment (default 100)";
 
 static int menu_loop_cscaler(int id, int keys)
 {
@@ -1043,7 +1099,7 @@ static int menu_loop_cscaler(int id, int keys)
 
        for (;;)
        {
-               menu_draw_begin(0);
+               menu_draw_begin(0, 1);
                memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
                text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
                text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
@@ -1087,11 +1143,14 @@ static int menu_loop_cscaler(int id, int keys)
 
 static menu_entry e_menu_gfx_options[] =
 {
-       mee_enum      ("Scaler",                   MA_OPT_SCALER, g_scaler, men_scaler),
+       mee_enum      ("Scaler",                   MA_OPT_VARSCALER, g_scaler, men_scaler),
+       mee_onoff_h   ("Use video overlay",        MA_OPT_VIDOVERLAY, g_use_overlay, 1, h_overlay),
        mee_onoff     ("Software Scaling",         MA_OPT_SCALER2, soft_scaling, 1),
-       mee_enum      ("Filter",                   MA_OPT_FILTERING, filter, men_dummy),
+       mee_enum      ("Hardware Filter",          MA_OPT_HWFILTER, filter, men_dummy),
+       mee_enum_h    ("Software Filter",          MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter),
+       mee_range_h   ("Gamma adjustment",         MA_OPT_GAMMA, g_gamma, 1, 200, h_gamma),
 //     mee_onoff     ("Vsync",                    0, vsync, 1),
-       mee_cust_h    ("Setup custom scaler",      MA_OPT_SCALER_C, menu_loop_cscaler, NULL, h_cscaler),
+       mee_cust_h    ("Setup custom scaler",      MA_OPT_VARSCALER_C, menu_loop_cscaler, NULL, h_cscaler),
        mee_end,
 };
 
@@ -1104,32 +1163,30 @@ static int menu_loop_gfx_options(int id, int keys)
        return 0;
 }
 
-// XXX
-void menu_set_filter_list(void *filters)
-{
-       int i;
-
-       i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
-       e_menu_gfx_options[i].data = filters;
-       me_enable(e_menu_gfx_options, MA_OPT_FILTERING, filters != NULL);
-}
-
 // ------------ bios/plugins ------------
 
 #ifdef __ARM_NEON__
 
-static const char h_gpu_neon[] = "Configure built-in NEON GPU plugin";
+static const char h_gpu_neon[] =
+       "Configure built-in NEON GPU plugin";
+static const char h_gpu_neon_enhanced[] =
+       "Renders in double resolution at the cost of lower performance\n"
+       "(not available for high resolution games)";
+static const char h_gpu_neon_enhanced_hack[] =
+       "Speed hack for above option (glitches some games)";
 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
 
 static menu_entry e_menu_plugin_gpu_neon[] =
 {
        mee_enum      ("Enable interlace mode",      0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
+       mee_onoff_h   ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
+       mee_onoff_h   ("Enhanced res. speed hack",   0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
        mee_end,
 };
 
 static int menu_loop_plugin_gpu_neon(int id, int keys)
 {
-       int sel = 0;
+       static int sel = 0;
        me_loop(e_menu_plugin_gpu_neon, &sel);
        return 0;
 }
@@ -1363,7 +1420,7 @@ static int menu_loop_adv_options(int id, int keys)
 static int mh_restore_defaults(int id, int keys)
 {
        menu_set_defconfig();
-       me_update_msg("defaults restored");
+       menu_update_msg("defaults restored");
        return 1;
 }
 
@@ -1445,7 +1502,7 @@ static void debug_menu_loop(void)
 
        while (1)
        {
-               menu_draw_begin(0);
+               menu_draw_begin(0, 1);
                draw_frame_debug(gpuf, df_x, df_y);
                menu_draw_end();
 
@@ -1497,7 +1554,7 @@ static void draw_mc_bg(void)
                GetMcdBlockInfo(2, i + 1, &blocks2[i]);
        }
 
-       menu_draw_begin(1);
+       menu_draw_begin(1, 1);
 
        memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
 
@@ -1578,7 +1635,7 @@ static void draw_cheatlist(int sel)
        max_cnt = g_menuscreen_h / me_sfont_h;
        start = max_cnt / 2 - sel;
 
-       menu_draw_begin(1);
+       menu_draw_begin(1, 1);
 
        for (i = 0; i < NumCheats; i++) {
                pos = start + i;
@@ -1630,11 +1687,8 @@ static void menu_bios_warn(void)
        static const char msg[] =
                "You don't seem to have copied any BIOS\n"
                "files to\n"
-#ifdef __ARM_ARCH_7A__ // XXX
-               "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
-#else
-               "pcsx_rearmed/bios/\n\n"
-#endif
+               MENU_BIOS_PATH "\n\n"
+
                "While many games work fine with fake\n"
                "(HLE) BIOS, others (like MGS and FF8)\n"
                "require BIOS to work.\n"
@@ -1681,7 +1735,7 @@ static void draw_frame_main(void)
        }
 
        if (ready_to_go) {
-               capacity = plat_get_bat_capacity();
+               capacity = plat_target_bat_capacity_get();
                ltime = time(NULL);
                tmp = localtime(&ltime);
                strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
@@ -1742,7 +1796,7 @@ static int reload_plugins(const char *cdimg)
        pcnt_hook_plugins();
        NetOpened = 0;
        if (OpenPlugins() == -1) {
-               me_update_msg("failed to open plugins");
+               menu_update_msg("failed to open plugins");
                return -1;
        }
        plugin_call_rearmed_cbs();
@@ -1782,7 +1836,7 @@ static int run_exe(void)
 
        SysReset();
        if (Load(fname) != 0) {
-               me_update_msg("exe load failed, bad file?");
+               menu_update_msg("exe load failed, bad file?");
                printf("meh\n");
                return -1;
        }
@@ -1802,7 +1856,7 @@ static int run_cd_image(const char *fname)
        if (CheckCdrom() == -1) {
                // Only check the CD if we are starting the console with a CD
                ClosePlugins();
-               me_update_msg("unsupported/invalid CD image");
+               menu_update_msg("unsupported/invalid CD image");
                return -1;
        }
 
@@ -1811,11 +1865,11 @@ static int run_cd_image(const char *fname)
        // Read main executable directly from CDRom and start it
        if (LoadCdrom() == -1) {
                ClosePlugins();
-               me_update_msg("failed to load CD image");
+               menu_update_msg("failed to load CD image");
                return -1;
        }
 
-       emu_on_new_cd();
+       emu_on_new_cd(1);
        ready_to_go = 1;
 
        return 0;
@@ -1870,11 +1924,11 @@ static int swap_cd_image(void)
 
        set_cd_image(fname);
        if (ReloadCdromPlugin() < 0) {
-               me_update_msg("failed to load cdr plugin");
+               menu_update_msg("failed to load cdr plugin");
                return -1;
        }
        if (CDR_open() < 0) {
-               me_update_msg("failed to open cdr plugin");
+               menu_update_msg("failed to open cdr plugin");
                return -1;
        }
 
@@ -1893,7 +1947,7 @@ static int swap_cd_multidisk(void)
 
        CDR_close();
        if (CDR_open() < 0) {
-               me_update_msg("failed to open cdr plugin");
+               menu_update_msg("failed to open cdr plugin");
                return -1;
        }
 
@@ -1917,10 +1971,10 @@ static void load_pcsx_cht(void)
        LoadCheats(fname);
 
        if (NumCheats == 0 && NumCodes == 0)
-               me_update_msg("failed to load cheats");
+               menu_update_msg("failed to load cheats");
        else {
                snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
-               me_update_msg(path);
+               menu_update_msg(path);
        }
        me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
 }
@@ -2035,13 +2089,22 @@ static void menu_leave_emu(void);
 
 void menu_loop(void)
 {
+       static int warned_about_bios = 0;
        static int sel = 0;
 
        menu_leave_emu();
 
-       if (bioses[1] == NULL && !warned_about_bios) {
-               menu_bios_warn();
-               warned_about_bios = 1;
+       if (config_save_counter == 0) {
+               // assume first run
+               if (bioses[1] != NULL) {
+                       // autoselect BIOS to make user's life easier
+                       snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[1]);
+                       bios_sel = 1;
+               }
+               else if (!warned_about_bios) {
+                       menu_bios_warn();
+                       warned_about_bios = 1;
+               }
        }
 
        me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
@@ -2219,13 +2282,14 @@ do_memcards:
 void menu_init(void)
 {
        char buff[MAXPATHLEN];
+       int i;
 
        strcpy(last_selected_fname, "/media");
 
-       cpu_clock_st = cpu_clock = plat_cpu_clock_get();
+       cpu_clock_st = cpu_clock = plat_target_cpu_clock_get();
 
        scan_bios_plugins();
-       menu_init_common();
+       menu_init_base();
 
        menu_set_defconfig();
        menu_load_config(0);
@@ -2244,16 +2308,28 @@ void menu_init(void)
        emu_make_path(buff, "skin/background.png", sizeof(buff));
        readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
 
-#ifndef __ARM_ARCH_7A__ /* XXX */
-       me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
-       me_enable(e_menu_gfx_options, MA_OPT_FILTERING, 0);
-       me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
-       me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
-#else
-       me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
-       me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
-       me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
+       i = plat_target.cpu_clock_set != NULL
+               && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0;
+       me_enable(e_menu_gfx_options, MA_OPT_CPU_CLOCKS, i);
+
+       i = me_id2offset(e_menu_gfx_options, MA_OPT_HWFILTER);
+       e_menu_gfx_options[i].data = plat_target.hwfilters;
+       me_enable(e_menu_gfx_options, MA_OPT_HWFILTER,
+               plat_target.hwfilters != NULL);
+
+       me_enable(e_menu_gfx_options, MA_OPT_GAMMA,
+               plat_target.gamma_set != NULL);
+
+#ifndef __ARM_ARCH_7A__
+       me_enable(e_menu_gfx_options, MA_OPT_SWFILTER, 0);
 #endif
+       me_enable(e_menu_gfx_options, MA_OPT_VARSCALER, MENU_SHOW_VARSCALER);
+       me_enable(e_menu_gfx_options, MA_OPT_VIDOVERLAY, MENU_SHOW_VIDOVERLAY);
+       me_enable(e_menu_gfx_options, MA_OPT_VARSCALER_C, MENU_SHOW_VARSCALER);
+       me_enable(e_menu_gfx_options, MA_OPT_SCALER2, MENU_SHOW_SCALER2);
+       me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, MENU_SHOW_NUBS_BTNS);
+       me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, MENU_SHOW_VIBRATION);
+       me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, MENU_SHOW_DEADZONE);
 }
 
 void menu_notify_mode_change(int w, int h, int bpp)
@@ -2295,7 +2371,7 @@ static void menu_leave_emu(void)
        }
 
        if (ready_to_go)
-               cpu_clock = plat_cpu_clock_get();
+               cpu_clock = plat_target_cpu_clock_get();
 }
 
 void menu_prepare_emu(void)
@@ -2316,7 +2392,7 @@ void menu_prepare_emu(void)
 
        menu_sync_config();
        if (cpu_clock > 0)
-               plat_cpu_clock_apply(cpu_clock);
+               plat_target_cpu_clock_set(cpu_clock);
 
        // push config to GPU plugin
        plugin_call_rearmed_cbs();
@@ -2330,7 +2406,7 @@ void menu_prepare_emu(void)
        dfinput_activate();
 }
 
-void me_update_msg(const char *msg)
+void menu_update_msg(const char *msg)
 {
        strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
        menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
@@ -2341,5 +2417,6 @@ void me_update_msg(const char *msg)
 
 void menu_finish(void)
 {
-       plat_cpu_clock_apply(cpu_clock_st);
+       if (cpu_clock_st > 0)
+               plat_target_cpu_clock_set(cpu_clock_st);
 }
index 2062acd..c6c1ab1 100644 (file)
@@ -4,7 +4,6 @@ void menu_loop(void);
 void menu_finish(void);
 
 void menu_notify_mode_change(int w, int h, int bpp);
-void menu_set_filter_list(void *filters);
 
 enum g_opts_opts {
        OPT_SHOWFPS = 1 << 0,
@@ -22,9 +21,16 @@ enum g_scaler_opts {
        SCALE_CUSTOM,
 };
 
-extern int g_opts, g_scaler;
+enum g_soft_filter_opts {
+       SOFT_FILTER_NONE,
+       SOFT_FILTER_SCALE2X,
+       SOFT_FILTER_EAGLE2X,
+};
+
+extern int g_opts, g_scaler, g_gamma;
 extern int soft_scaling, analog_deadzone;
-extern int filter;
+extern int g_use_overlay, g_fullscreen;
+extern int filter, soft_filter;
 
 extern int g_menuscreen_w;
 extern int g_menuscreen_h;
index 0957b94..4258ac1 100755 (executable)
@@ -5,10 +5,16 @@ nub0mode=`cat /proc/pandora/nub0/mode`
 nub1mode=`cat /proc/pandora/nub1/mode`
 /usr/pandora/scripts/op_nubchange.sh absolute absolute
 
+# 4MB for RAM (2+align) + 2MB for vram (1+overdraw) + 10MB for gpu_neon (8+overdraw)
+# no big deal if this fails, only performance loss
+sudo -n /usr/pandora/scripts/op_hugetlb.sh 16
+
 ./pcsx "$@"
 
 # restore stuff if pcsx crashes
 ./picorestore
 sudo -n /usr/pandora/scripts/op_lcdrate.sh 60
+sudo -n /usr/pandora/scripts/op_gamma.sh 0
+sudo -n /usr/pandora/scripts/op_hugetlb.sh 0
 
 /usr/pandora/scripts/op_nubchange.sh $nub0mode $nub1mode
diff --git a/frontend/pandora/ui_feat.h b/frontend/pandora/ui_feat.h
new file mode 100644 (file)
index 0000000..7564e17
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef UI_FEATURES_H
+#define UI_FEATURES_H
+
+#define MENU_BIOS_PATH "<SD card>/pandora/appdata/pcsx_rearmed/bios/"
+#define BOOT_MSG "Booting up...  (press SPACE for menu)"
+#define MENU_SHOW_VARSCALER 1
+#define MENU_SHOW_VIDOVERLAY 0
+#define MENU_SHOW_SCALER2 0
+#define MENU_SHOW_NUBS_BTNS 1
+#define MENU_SHOW_VIBRATION 0
+#define MENU_SHOW_DEADZONE 0
+#define MENU_SHOW_MINIMIZE 1
+#define MENU_SHOW_FULLSCREEN 0
+#define MENU_SHOW_VOLUME 0
+
+#endif // UI_FEATURES_H
index 0213ca1..9ddd500 100644 (file)
@@ -11,6 +11,13 @@ enum pcounters {
 
 #ifdef PCNT
 
+#if defined(__ARM_ARCH_7A__) || defined(ARM1176)
+#define PCNT_DIV 1000
+#else
+#include <sys/time.h>
+#define PCNT_DIV 1
+#endif
+
 static const char *pcnt_names[PCNT_CNT] = { "", "gpu", "spu", "blit", "gte", "test" };
 
 #define PCNT_FRAMES 10
@@ -33,7 +40,7 @@ static inline void pcnt_print(float fps)
        int i;
 
        for (i = 0; i < PCNT_CNT; i++)
-               pcounters[i] /= 1000 * PCNT_FRAMES;
+               pcounters[i] /= PCNT_DIV * PCNT_FRAMES;
 
        rem = total = pcounters[PCNT_ALL];
        for (i = 1; i < PCNT_CNT; i++)
@@ -78,8 +85,17 @@ static inline unsigned int pcnt_get(void)
 #ifdef __ARM_ARCH_7A__
        __asm__ volatile("mrc p15, 0, %0, c9, c13, 0"
                         : "=r"(val));
+#elif defined(ARM1176)
+       __asm__ volatile("mrc p15, 0, %0, c15, c12, 1"
+                        : "=r"(val));
 #else
-       val = 0;
+       // all slow on ARM :(
+       //struct timespec tv;
+       //clock_gettime(CLOCK_MONOTONIC_RAW, &tv);
+       //val = tv.tv_sec * 1000000000 + tv.tv_nsec;
+       struct timeval tv;
+       gettimeofday(&tv, NULL);
+       val = tv.tv_sec * 1000000 + tv.tv_usec;
 #endif
        return val;
 }
@@ -94,6 +110,12 @@ static inline void pcnt_init(void)
        asm volatile("mcr p15, 0, %0, c9, c12, 0" :: "r"(v));
        // enable cycle counter
        asm volatile("mcr p15, 0, %0, c9, c12, 1" :: "r"(1<<31));
+#elif defined(ARM1176)
+       int v;
+       asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r"(v));
+       v |= 5; // master enable, ccnt reset
+       v &= ~8; // ccnt divider 0
+       asm volatile("mcr p15, 0, %0, c15, c12, 0" :: "r"(v));
 #endif
 }
 
index de7fe11..661792c 100644 (file)
@@ -15,7 +15,7 @@
 #include "plugin_lib.h"
 #include "pl_gun_ts.h"
 #include "menu.h"
-#include "../plugins/dfinput/main.h"
+#include "../plugins/dfinput/externals.h"
 
 static int gun_x, gun_y, gun_in;
 static int ts_multiplier_x, ts_multiplier_y, ts_offs_x, ts_offs_y;
@@ -61,6 +61,7 @@ int pl_gun_ts_update_raw(struct tsdev *ts, int *x, int *y, int *p)
        return 0;
 }
 
+/* returns x, y in range 0..1023 (normalized to visible layer) */
 void pl_gun_ts_update(struct tsdev *ts, int *x, int *y, int *in)
 {
        pl_gun_ts_update_raw(ts, NULL, NULL, NULL);
index db66c57..6b0cd65 100644 (file)
@@ -1,9 +1,7 @@
+void plat_init(void);
+void plat_finish(void);
 void plat_minimize(void);
 void *plat_prepare_screenshot(int *w, int *h, int *bpp);
-void plat_step_volume(int is_up);
-int  plat_cpu_clock_get(void);
-int  plat_cpu_clock_apply(int cpu_clock);
-int  plat_get_bat_capacity(void);
 
 // indirectly called from GPU plugin
 void  plat_gvideo_open(int is_pal);
index 5b0adf1..baed0d5 100644 (file)
@@ -54,25 +54,6 @@ void *plat_prepare_screenshot(int *w, int *h, int *bpp)
        return 0;
 }
 
-int plat_cpu_clock_get(void)
-{
-       return -1;
-}
-
-int plat_cpu_clock_apply(int cpu_clock)
-{
-       return -1;
-}
-
-int plat_get_bat_capacity(void)
-{
-       return -1;
-}
-
-void plat_step_volume(int is_up)
-{
-}
-
 void plat_trigger_vibrate(int is_strong)
 {
 }
index b01c634..6126140 100644 (file)
 #include <unistd.h>
 #include <linux/omapfb.h>
 
-#include "common/menu.h"
-#include "common/input.h"
-#include "linux/fbdev.h"
-#include "linux/xenv.h"
+#include "libpicofe/menu.h"
+#include "libpicofe/input.h"
+#include "libpicofe/linux/fbdev.h"
+#include "libpicofe/linux/xenv.h"
 #include "plugin_lib.h"
 #include "pl_gun_ts.h"
 #include "plat.h"
@@ -52,8 +52,9 @@ static int omap_setup_layer_(int fd, int enabled, int x, int y, int w, int h)
                        perror("SETUP_PLANE");
        }
 
-       if (mi.size < 640*512*3*3) {
-               mi.size = 640*512*3*3;
+       // upto 1024x512 (2x resolution enhancement)
+       if (mi.size < 1024*512*2 * 3) {
+               mi.size = 1024*512*2 * 3;
                ret = ioctl(fd, OMAPFB_SETUP_MEM, &mi);
                if (ret != 0) {
                        perror("SETUP_MEM");
index 9ec747d..cdd94c6 100644 (file)
@@ -6,42 +6,16 @@
  */
 
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
 #include <linux/input.h>
-#include <dirent.h>
-#include <errno.h>
 
-#include "common/input.h"
-#include "linux/in_evdev.h"
+#include "libpicofe/input.h"
+#include "libpicofe/linux/in_evdev.h"
+#include "libpicofe/plat.h"
 #include "plugin_lib.h"
-#include "plat.h"
 #include "plat_omap.h"
 #include "main.h"
 #include "menu.h"
 
-static const char * const pandora_gpio_keys[KEY_MAX + 1] = {
-       [0 ... KEY_MAX] = NULL,
-       [KEY_UP]        = "Up",
-       [KEY_LEFT]      = "Left",
-       [KEY_RIGHT]     = "Right",
-       [KEY_DOWN]      = "Down",
-       [KEY_HOME]      = "(A)",
-       [KEY_PAGEDOWN]  = "(X)",
-       [KEY_END]       = "(B)",
-       [KEY_PAGEUP]    = "(Y)",
-       [KEY_RIGHTSHIFT]= "(L)",
-       [KEY_RIGHTCTRL] = "(R)",
-       [KEY_LEFTALT]   = "Start",
-       [KEY_LEFTCTRL]  = "Select",
-       [KEY_MENU]      = "Pandora",
-};
-
 static const struct in_default_bind in_evdev_defbinds[] = {
        { KEY_UP,       IN_BINDTYPE_PLAYER12, DKEY_UP },
        { KEY_DOWN,     IN_BINDTYPE_PLAYER12, DKEY_DOWN },
@@ -65,98 +39,24 @@ static const struct in_default_bind in_evdev_defbinds[] = {
        { KEY_4,        IN_BINDTYPE_EMU, SACTION_NEXT_SSLOT },
        { KEY_5,        IN_BINDTYPE_EMU, SACTION_TOGGLE_FSKIP },
        { KEY_6,        IN_BINDTYPE_EMU, SACTION_SCREENSHOT },
+       { KEY_7,        IN_BINDTYPE_EMU, SACTION_TOGGLE_FPS },
+       { KEY_8,        IN_BINDTYPE_EMU, SACTION_SWITCH_DISPMODE },
+       { KEY_BACKSPACE,IN_BINDTYPE_EMU, SACTION_FAST_FORWARD },
        { 0, 0, 0 }
 };
 
-static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
-static char **pnd_filter_list;
-
-static void scan_for_filters(void)
-{
-       struct dirent *ent;
-       int i, count = 0;
-       char **mfilters;
-       char buff[64];
-       DIR *dir;
-
-       dir = opendir("/etc/pandora/conf/dss_fir");
-       if (dir == NULL) {
-               perror("filter opendir");
-               return;
-       }
-
-       while (1) {
-               errno = 0;
-               ent = readdir(dir);
-               if (ent == NULL) {
-                       if (errno != 0)
-                               perror("readdir");
-                       break;
-               }
-
-               if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
-                       continue;
-
-               count++;
-       }
-
-       if (count == 0)
-               return;
-
-       mfilters = calloc(count + 1, sizeof(mfilters[0]));
-       if (mfilters == NULL)
-               return;
-
-       rewinddir(dir);
-       for (i = 0; (ent = readdir(dir)); ) {
-               size_t len;
-
-               if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
-                       continue;
-
-               len = strlen(ent->d_name);
-
-               // skip pre-HF5 extra files
-               if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
-                       continue;
-               if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
-                       continue;
-
-               // have to cut "_up_h" for pre-HF5
-               if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
-                       len -= 5;
-
-               if (len > sizeof(buff) - 1)
-                       continue;
-
-               strncpy(buff, ent->d_name, len);
-               buff[len] = 0;
-               mfilters[i] = strdup(buff);
-               if (mfilters[i] != NULL)
-                       i++;
-       }
-       closedir(dir);
-
-       pnd_filter_list = mfilters;
-       menu_set_filter_list((void *)mfilters);
-}
-
 int plat_init(void)
 {
-       int gpiokeys_id;
-
        plat_omap_init();
+       plat_target_init();
 
        in_evdev_init(in_evdev_defbinds);
        in_probe();
-       gpiokeys_id = in_name_to_id("evdev:gpio-keys");
-       in_set_config(gpiokeys_id, IN_CFG_KEY_NAMES,
-                     pandora_gpio_keys, sizeof(pandora_gpio_keys));
-       in_set_config(gpiokeys_id, IN_CFG_DEFAULT_DEV, NULL, 0);
+       plat_target_setup_input();
+
        in_adev[0] = in_name_to_id("evdev:nub0");
        in_adev[1] = in_name_to_id("evdev:nub1");
-
-       scan_for_filters();
+       in_adev_is_nublike[0] = in_adev_is_nublike[1] = 1;
 
        return 0;
 }
@@ -164,94 +64,18 @@ int plat_init(void)
 void plat_finish(void)
 {
        plat_omap_finish();
-}
-
-static void apply_lcdrate(int pal)
-{
-       char buf[128];
-
-       snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
-                       pnd_script_base, pal ? 50 : 60);
-       system(buf);
-}
-
-static void apply_filter(int which)
-{
-       char buf[128];
-       int i;
-
-       if (pnd_filter_list == NULL)
-               return;
-
-       for (i = 0; i < which; i++)
-               if (pnd_filter_list[i] == NULL)
-                       return;
-
-       if (pnd_filter_list[i] == NULL)
-               return;
-
-       snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s",
-               pnd_script_base, pnd_filter_list[i]);
-       system(buf);
+       plat_target_finish();
 }
 
 void plat_gvideo_open(int is_pal)
 {
-       static int old_pal = -1, old_filter = -1;
-
-       if (is_pal != old_pal) {
-               apply_lcdrate(is_pal);
-               old_pal = is_pal;
-       }
-       if (filter != old_filter) {
-               apply_filter(filter);
-               old_filter = filter;
-       }
+       plat_target_lcdrate_set(is_pal);
+       plat_target_hwfilter_set(filter);
+       plat_target_gamma_set(g_gamma, 0);
 
        plat_omap_gvideo_open();
 }
 
-int plat_cpu_clock_get(void)
-{
-       FILE *f;
-       int ret = 0;
-       f = fopen("/proc/pandora/cpu_mhz_max", "r");
-       if (f) {
-               fscanf(f, "%d", &ret);
-               fclose(f);
-       }
-       return ret;
-}
-
-int plat_cpu_clock_apply(int cpu_clock)
-{
-       char buf[128];
-
-       if (cpu_clock != 0 && cpu_clock != plat_cpu_clock_get()) {
-               snprintf(buf, sizeof(buf), "unset DISPLAY; echo y | %s/op_cpuspeed.sh %d",
-                        pnd_script_base, cpu_clock);
-               system(buf);
-       }
-       return 0;
-}
-
-int plat_get_bat_capacity(void)
-{
-       FILE *f;
-       int ret = 0;
-       f = fopen("/sys/class/power_supply/bq27500-0/capacity", "r");
-       if (f) {
-               fscanf(f, "%d", &ret);
-               fclose(f);
-       }
-       return ret;
-}
-
-void plat_step_volume(int is_up)
-{
-}
-
 void plat_trigger_vibrate(int is_strong)
 {
 }
-
index 1dafb7c..32af9a6 100644 (file)
 #include <linux/soundcard.h>
 #include <linux/input.h>
 
-#include "common/input.h"
-#include "gp2x/in_gp2x.h"
-#include "linux/in_evdev.h"
-#include "common/menu.h"
+#include "libpicofe/plat.h"
+#include "libpicofe/input.h"
+#include "libpicofe/gp2x/in_gp2x.h"
+#include "libpicofe/gp2x/soc_pollux.h"
+#include "libpicofe/linux/in_evdev.h"
+#include "libpicofe/menu.h"
 #include "warm/warm.h"
 #include "plugin_lib.h"
 #include "pl_gun_ts.h"
 #include "pcnt.h"
 #include "../plugins/gpulib/cspace.h"
 
-int gp2x_dev_id;
 
-static int fbdev = -1, memdev = -1, battdev = -1, mixerdev = -1;
-static volatile unsigned short *memregs;
-static volatile unsigned int   *memregl;
+static int fbdev = -1;
 static void *fb_vaddrs[2];
 static unsigned int fb_paddrs[2];
 static int fb_work_buf;
-static int cpu_clock_allowed, have_warm;
-static unsigned int saved_video_regs[2][6];
+static int have_warm;
 #define FB_VRAM_SIZE (320*240*2*2*2) // 2 buffers with space for 24bpp mode
 
 static unsigned short *psx_vram;
@@ -123,88 +121,20 @@ static void pollux_changemode(int bpp, int is_bgr)
        memregl[0x4458>>2] = r;
 }
 
-/* note: both PLLs are programmed the same way,
- * the databook incorrectly states that PLL1 differs */
-static int decode_pll(unsigned int reg)
+static int cpu_clock_wrapper(int mhz)
 {
-       long long v;
-       int p, m, s;
-
-       p = (reg >> 18) & 0x3f;
-       m = (reg >> 8) & 0x3ff;
-       s = reg & 0xff;
-
-       if (p == 0)
-               p = 1;
-
-       v = 27000000; // master clock
-       v = v * m / (p << s);
-       return v;
-}
-
-int plat_cpu_clock_get(void)
-{
-       return decode_pll(memregl[0xf004>>2]) / 1000000;
-}
-
-int plat_cpu_clock_apply(int mhz)
-{
-       int adiv, mdiv, pdiv, sdiv = 0;
-       int i, vf000, vf004;
-
-       if (!cpu_clock_allowed)
-               return -1;
-       if (mhz == plat_cpu_clock_get())
-               return 0;
-
-       // m = MDIV, p = PDIV, s = SDIV
-       #define SYS_CLK_FREQ 27
-       pdiv = 9;
-       mdiv = (mhz * pdiv) / SYS_CLK_FREQ;
-       if (mdiv & ~0x3ff)
-               return -1;
-       vf004 = (pdiv<<18) | (mdiv<<8) | sdiv;
-
-       // attempt to keep the AHB divider close to 250, but not higher
-       for (adiv = 1; mhz / adiv > 250; adiv++)
-               ;
-
-       vf000 = memregl[0xf000>>2];
-       vf000 = (vf000 & ~0x3c0) | ((adiv - 1) << 6);
-       memregl[0xf000>>2] = vf000;
-       memregl[0xf004>>2] = vf004;
-       memregl[0xf07c>>2] |= 0x8000;
-       for (i = 0; (memregl[0xf07c>>2] & 0x8000) && i < 0x100000; i++)
-               ;
-
-       printf("clock set to %dMHz, AHB set to %dMHz\n", mhz, mhz / adiv);
-
        // stupid pll share hack - must restart audio
+       int pollux_cpu_clock_set(int cpu_clock);
        extern long SPUopen(void);
        extern long SPUclose(void);
+
+       pollux_cpu_clock_set(mhz);
        SPUclose();
        SPUopen();
 
        return 0;
 }
 
-int plat_get_bat_capacity(void)
-{
-       unsigned short magic_val = 0;
-
-       if (battdev < 0)
-               return -1;
-       if (read(battdev, &magic_val, sizeof(magic_val)) != sizeof(magic_val))
-               return -1;
-       switch (magic_val) {
-       default:
-       case 1: return 100;
-       case 2: return 66;
-       case 3: return 40;
-       case 4: return 0;
-       }
-}
-
 #define TIMER_BASE3 0x1980
 #define TIMER_REG(x) memregl[(TIMER_BASE3 + x) >> 2]
 
@@ -214,15 +144,6 @@ static __attribute__((unused)) unsigned int timer_get(void)
        return TIMER_REG(0);
 }
 
-static void timer_cleanup(void)
-{
-       TIMER_REG(0x40) = 0x0c; /* be sure clocks are on */
-       TIMER_REG(0x08) = 0x23; /* stop the timer, clear irq in case it's pending */
-       TIMER_REG(0x00) = 0;    /* clear counter */
-       TIMER_REG(0x40) = 0;    /* clocks off */
-       TIMER_REG(0x44) = 0;    /* dividers back to default */
-}
-
 void plat_video_menu_enter(int is_rom_loaded)
 {
        if (pl_vout_buf != NULL) {
@@ -305,12 +226,13 @@ static void spend_cycles(int loops)
 #define DMA_REG(x) memregl[(DMA_BASE6 + x) >> 2]
 
 /* this takes ~1.5ms, while ldm/stm ~1.95ms */
-static void raw_flip_dma(int x, int y)
+static void raw_flip_dma(const void *vram, int stride, int bgr24, int w, int h)
 {
+       unsigned int pixel_offset = psx_vram - (unsigned short *)vram;
        unsigned int dst = fb_paddrs[fb_work_buf] +
                        (fb_offset_y * 320 + fb_offset_x) * psx_bpp / 8;
-       int spsx_line = y + psx_offset_y;
-       int spsx_offset = (x + psx_offset_x) & 0x3f8;
+       int spsx_line = pixel_offset / 1024 + psx_offset_y;
+       int spsx_offset = (pixel_offset + psx_offset_x) & 0x3f8;
        int dst_stride = 320 * psx_bpp / 8;
        int len = psx_src_width * psx_bpp / 8;
        int i;
@@ -344,7 +266,7 @@ static void raw_flip_dma(int x, int y)
 
        if (psx_bpp == 16) {
                pl_vout_buf = g_menuscreen_ptr;
-               pl_print_hud(fb_offset_x);
+               pl_print_hud(w, h, fb_offset_x);
        }
 
        g_menuscreen_ptr = fb_flip();
@@ -354,26 +276,24 @@ static void raw_flip_dma(int x, int y)
 }
 
 #define make_flip_func(name, blitfunc)                                                  \
-static void name(int x, int y)                                                          \
+static void name(const void *vram_, int stride, int bgr24, int w, int h)                \
 {                                                                                       \
-        unsigned short *vram = psx_vram;                                                \
+        const unsigned short *vram = vram_;                                             \
         unsigned char *dst = (unsigned char *)g_menuscreen_ptr +                        \
                         (fb_offset_y * 320 + fb_offset_x) * psx_bpp / 8;                \
-        unsigned int src = (y + psx_offset_y) * 1024 + x + psx_offset_x;                \
         int dst_stride = 320 * psx_bpp / 8;                                             \
         int len = psx_src_width * psx_bpp / 8;                                          \
         int i;                                                                          \
                                                                                         \
         pcnt_start(PCNT_BLIT);                                                          \
                                                                                         \
-        for (i = psx_src_height; i > 0; i--, src += psx_step * 1024, dst += dst_stride) { \
-                src &= 1024*512-1;                                                      \
-                blitfunc(dst, vram + src, len);                                         \
-        }                                                                               \
+        vram += psx_offset_y * 1024 + psx_offset_x;                                     \
+        for (i = psx_src_height; i > 0; i--, vram += psx_step * 1024, dst += dst_stride)\
+                blitfunc(dst, vram, len);                                               \
                                                                                         \
         if (psx_bpp == 16) {                                                            \
                 pl_vout_buf = g_menuscreen_ptr;                                         \
-                pl_print_hud(fb_offset_x);                                              \
+                pl_print_hud(w, h, fb_offset_x);                                        \
         }                                                                               \
                                                                                         \
         g_menuscreen_ptr = fb_flip();                                                   \
@@ -402,20 +322,20 @@ void *plat_gvideo_set_mode(int *w_, int *h_, int *bpp_)
 
        switch (w + (bpp != 16) + !soft_scaling) {
        case 640:
-               pl_rearmed_cbs.pl_vout_raw_flip = raw_flip_soft_640;
+               pl_rearmed_cbs.pl_vout_flip = raw_flip_soft_640;
                w_max = 640;
                break;
        case 512:
-               pl_rearmed_cbs.pl_vout_raw_flip = raw_flip_soft_512;
+               pl_rearmed_cbs.pl_vout_flip = raw_flip_soft_512;
                w_max = 512;
                break;
        case 384:
        case 368:
-               pl_rearmed_cbs.pl_vout_raw_flip = raw_flip_soft_368;
+               pl_rearmed_cbs.pl_vout_flip = raw_flip_soft_368;
                w_max = 368;
                break;
        default:
-               pl_rearmed_cbs.pl_vout_raw_flip = have_warm ? raw_flip_dma : raw_flip_soft;
+               pl_rearmed_cbs.pl_vout_flip = have_warm ? raw_flip_dma : raw_flip_soft;
                w_max = 320;
                break;
        }
@@ -477,48 +397,13 @@ void plat_gvideo_close(void)
 {
 }
 
-static void save_multiple_regs(unsigned int *dest, int base, int count)
-{
-       const volatile unsigned int *regs = memregl + base / 4;
-       int i;
-
-       for (i = 0; i < count; i++)
-               dest[i] = regs[i];
-}
-
-static void restore_multiple_regs(int base, const unsigned int *src, int count)
-{
-       volatile unsigned int *regs = memregl + base / 4;
-       int i;
-
-       for (i = 0; i < count; i++)
-               regs[i] = src[i];
-}
-
 void plat_init(void)
 {
        const char *main_fb_name = "/dev/fb0";
        struct fb_fix_screeninfo fbfix;
-       int rate, timer_div, timer_div2;
-       int fbdev, ret, warm_ret;
-       FILE *f;
-
-       memdev = open("/dev/mem", O_RDWR);
-       if (memdev == -1) {
-               perror("open(/dev/mem) failed");
-               exit(1);
-       }
-
-       memregs = mmap(0, 0x20000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0xc0000000);
-       if (memregs == MAP_FAILED) {
-               perror("mmap(memregs) failed");
-               exit(1);
-       }
-       memregl = (volatile void *)memregs;
+       int ret;
 
-       // save video regs of both MLCs
-       save_multiple_regs(saved_video_regs[0], 0x4058, ARRAY_SIZE(saved_video_regs[0]));
-       save_multiple_regs(saved_video_regs[1], 0x4458, ARRAY_SIZE(saved_video_regs[1]));
+       plat_target_init();
 
        fbdev = open(main_fb_name, O_RDWR);
        if (fbdev == -1) {
@@ -545,71 +430,19 @@ void plat_init(void)
        fb_vaddrs[1] = (char *)fb_vaddrs[0] + 320*240*4;
 
        memset(fb_vaddrs[0], 0, FB_VRAM_SIZE);
+
        pollux_changemode(16, 0);
        g_menuscreen_w = 320;
        g_menuscreen_h = 240;
        g_menuscreen_ptr = fb_flip();
 
-       warm_ret = warm_init();
-       have_warm = warm_ret == 0;
+       ret = warm_init();
+       have_warm = (ret == 0);
        warm_change_cb_upper(WCB_B_BIT, 1);
 
-       /* some firmwares have sys clk on PLL0, we can't adjust CPU clock
-        * by reprogramming the PLL0 then, as it overclocks system bus */
-       if ((memregl[0xf000>>2] & 0x03000030) == 0x01000000)
-               cpu_clock_allowed = 1;
-       else {
-               cpu_clock_allowed = 0;
-               fprintf(stderr, "unexpected PLL config (%08x), overclocking disabled\n",
-                       memregl[0xf000>>2]);
-       }
-
-       /* find what PLL1 runs at, for the timer */
-       rate = decode_pll(memregl[0xf008>>2]);
-       printf("PLL1 @ %dHz\n", rate);
-
-       /* setup timer */
-       timer_div = (rate + 500000) / 1000000;
-       timer_div2 = 0;
-       while (timer_div > 256) {
-               timer_div /= 2;
-               timer_div2++;
-       }
-       if (1 <= timer_div && timer_div <= 256 && timer_div2 < 4) {
-               int timer_rate = (rate >> timer_div2) / timer_div;
-               if (TIMER_REG(0x08) & 8) {
-                       fprintf(stderr, "warning: timer in use, overriding!\n");
-                       timer_cleanup();
-               }
-               if (timer_rate != 1000000)
-                       fprintf(stderr, "warning: timer drift %d us\n", timer_rate - 1000000);
-
-               timer_div2 = (timer_div2 + 3) & 3;
-               TIMER_REG(0x44) = ((timer_div - 1) << 4) | 2;   /* using PLL1 */
-               TIMER_REG(0x40) = 0x0c;                         /* clocks on */
-               TIMER_REG(0x08) = 0x68 | timer_div2;            /* run timer, clear irq, latch value */
-       }
-       else
-               fprintf(stderr, "warning: could not make use of timer\n");
-
        /* setup DMA */
        DMA_REG(0x0c) = 0x20000; // pending IRQ clear
 
-       battdev = open("/dev/pollux_batt", O_RDONLY);
-       if (battdev < 0)
-               perror("Warning: could't open pollux_batt");
-
-       f = fopen("/dev/accel", "rb");
-       if (f) {
-               printf("detected Caanoo\n");
-               gp2x_dev_id = GP2X_DEV_CAANOO;
-               fclose(f);
-       }
-       else {
-               printf("detected Wiz\n");
-               gp2x_dev_id = GP2X_DEV_WIZ;
-       }
-
        in_tsbutton_init();
        in_evdev_init(in_evdev_defbinds);
        if (gp2x_dev_id == GP2X_DEV_CAANOO)
@@ -617,11 +450,7 @@ void plat_init(void)
        else
                wiz_init();
 
-       mixerdev = open("/dev/mixer", O_RDWR);
-       if (mixerdev == -1)
-               perror("open(/dev/mixer)");
-
-       pl_rearmed_cbs.pl_vout_raw_flip = have_warm ? raw_flip_dma : raw_flip_soft;
+       pl_rearmed_cbs.pl_vout_flip = have_warm ? raw_flip_dma : raw_flip_soft;
        pl_rearmed_cbs.pl_vout_set_raw_vram = pl_vout_set_raw_vram;
 
        psx_src_width = 320;
@@ -630,27 +459,19 @@ void plat_init(void)
 
        pl_rearmed_cbs.screen_w = 320;
        pl_rearmed_cbs.screen_h = 240;
+
+       plat_target_setup_input();
+
+       plat_target.cpu_clock_set = cpu_clock_wrapper;
 }
 
 void plat_finish(void)
 {
        warm_finish();
-       timer_cleanup();
-
        memset(fb_vaddrs[0], 0, FB_VRAM_SIZE);
-       restore_multiple_regs(0x4058, saved_video_regs[0], ARRAY_SIZE(saved_video_regs[0]));
-       restore_multiple_regs(0x4458, saved_video_regs[1], ARRAY_SIZE(saved_video_regs[1]));
-       memregl[0x4058>>2] |= 0x10;
-       memregl[0x4458>>2] |= 0x10;
        munmap(fb_vaddrs[0], FB_VRAM_SIZE);
        close(fbdev);
-
-       if (battdev >= 0)
-               close(battdev);
-       if (mixerdev >= 0)
-               close(mixerdev);
-       munmap((void *)memregs, 0x20000);
-       close(memdev);
+       plat_target_finish();
 }
 
 /* WIZ RAM lack workaround */
@@ -823,30 +644,6 @@ static const struct in_default_bind in_gp2x_defbinds[] =
        { 0, 0, 0 },
 };
 
-void plat_step_volume(int is_up)
-{
-       static int volume = 50;
-       int ret, val;
-
-       if (mixerdev < 0)
-               return;
-
-       if (is_up) {
-               volume += 5;
-               if (volume > 255) volume = 255;
-       }
-       else {
-               volume -= 5;
-               if (volume < 0) volume = 0;
-       }
-       val = volume;
-       val |= val << 8;
-
-       ret = ioctl(mixerdev, SOUND_MIXER_WRITE_PCM, &val);
-       if (ret == -1)
-               perror("WRITE_PCM");
-}
-
 // unused dummy for in_gp2x
 volatile unsigned short *gp2x_memregs;
 
index 08afd70..9862e2b 100644 (file)
 
 #include <stdio.h>
 #include <SDL.h>
-#include "common/input.h"
-#include "common/in_sdl.h"
-#include "common/menu.h"
+
+#include "libpicofe/input.h"
+#include "libpicofe/in_sdl.h"
+#include "libpicofe/menu.h"
+#include "libpicofe/fonts.h"
+#include "../plugins/gpulib/cspace.h"
 #include "plugin_lib.h"
 #include "main.h"
+#include "menu.h"
 #include "plat.h"
 #include "revision.h"
 
@@ -34,26 +38,118 @@ static const struct in_default_bind in_sdl_defbinds[] = {
   { SDLK_e,      IN_BINDTYPE_PLAYER12, DKEY_L2 },
   { SDLK_t,      IN_BINDTYPE_PLAYER12, DKEY_R2 },
   { SDLK_ESCAPE, IN_BINDTYPE_EMU, SACTION_ENTER_MENU },
+  { SDLK_F1,     IN_BINDTYPE_EMU, SACTION_SAVE_STATE },
+  { SDLK_F2,     IN_BINDTYPE_EMU, SACTION_LOAD_STATE },
+  { SDLK_F3,     IN_BINDTYPE_EMU, SACTION_PREV_SSLOT },
+  { SDLK_F4,     IN_BINDTYPE_EMU, SACTION_NEXT_SSLOT },
+  { SDLK_F5,     IN_BINDTYPE_EMU, SACTION_TOGGLE_FSKIP },
+  { SDLK_F6,     IN_BINDTYPE_EMU, SACTION_SCREENSHOT },
+  { SDLK_F7,     IN_BINDTYPE_EMU, SACTION_TOGGLE_FPS },
+  { SDLK_F8,     IN_BINDTYPE_EMU, SACTION_SWITCH_DISPMODE },
+  { SDLK_F11,    IN_BINDTYPE_EMU, SACTION_TOGGLE_FULLSCREEN },
+  { SDLK_BACKSPACE, IN_BINDTYPE_EMU, SACTION_FAST_FORWARD },
   { 0, 0, 0 }
 };
 
+// XXX: maybe determine this instead..
+#define WM_DECORATION_H 32
+
 static SDL_Surface *screen;
+static SDL_Overlay *overlay;
+static int window_w, window_h;
+static int fs_w, fs_h;
+static int psx_w, psx_h;
 static void *menubg_img;
+static int in_menu, old_fullscreen;
+
+static void overlay_clear(void);
 
 static int change_video_mode(int w, int h)
 {
-  screen = SDL_SetVideoMode(w, h, 16, 0);
-  if (screen == NULL) {
-    fprintf(stderr, "SDL_SetVideoMode failed: %s\n", SDL_GetError());
-    return -1;
+  psx_w = w;
+  psx_h = h;
+
+  if (overlay != NULL) {
+    SDL_FreeYUVOverlay(overlay);
+    overlay = NULL;
+  }
+
+  if (g_use_overlay && !in_menu) {
+    Uint32 flags = SDL_RESIZABLE;
+    int win_w = window_w;
+    int win_h = window_h;
+
+    if (g_fullscreen) {
+      flags |= SDL_FULLSCREEN;
+      win_w = fs_w;
+      win_h = fs_h;
+    }
+
+    screen = SDL_SetVideoMode(win_w, win_h, 0, flags);
+    if (screen == NULL) {
+      fprintf(stderr, "SDL_SetVideoMode failed: %s\n", SDL_GetError());
+      return -1;
+    }
+
+    overlay = SDL_CreateYUVOverlay(w, h, SDL_UYVY_OVERLAY, screen);
+    if (overlay != NULL) {
+      /*printf("overlay: fmt %x, planes: %d, pitch: %d, hw: %d\n",
+        overlay->format, overlay->planes, *overlay->pitches,
+        overlay->hw_overlay);*/
+
+      if ((long)overlay->pixels[0] & 3)
+        fprintf(stderr, "warning: overlay pointer is unaligned\n");
+
+      if (!overlay->hw_overlay) {
+        fprintf(stderr, "warning: video overlay is not hardware accelerated, "
+                        "disabling it.\n");
+        g_use_overlay = 0;
+        SDL_FreeYUVOverlay(overlay);
+        overlay = NULL;
+      }
+      else
+        overlay_clear();
+    }
+    else {
+      fprintf(stderr, "warning: could not create overlay.\n");
+    }
+  }
+
+  if (overlay == NULL) {
+    screen = SDL_SetVideoMode(w, h, 16, 0);
+    if (screen == NULL) {
+      fprintf(stderr, "SDL_SetVideoMode failed: %s\n", SDL_GetError());
+      return -1;
+    }
+
+    if (!in_menu) {
+      window_w = screen->w;
+      window_h = screen->h;
+    }
   }
 
+  old_fullscreen = g_fullscreen;
   return 0;
 }
 
+static void event_handler(void *event_)
+{
+  SDL_Event *event = event_;
+
+  if (event->type == SDL_VIDEORESIZE) {
+    //printf("%dx%d\n", event->resize.w, event->resize.h);
+    if (overlay != NULL && !g_fullscreen && !old_fullscreen) {
+      window_w = event->resize.w;
+      window_h = event->resize.h;
+      change_video_mode(psx_w, psx_h);
+    }
+  }
+}
+
 void plat_init(void)
 {
-  int ret;
+  const SDL_VideoInfo *info;
+  int ret, h;
 
   ret = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
   if (ret != 0) {
@@ -61,8 +157,25 @@ void plat_init(void)
     exit(1);
   }
 
+  info = SDL_GetVideoInfo();
+  if (info != NULL) {
+    fs_w = info->current_w;
+    fs_h = info->current_h;
+  }
+
+  in_menu = 1;
   g_menuscreen_w = 640;
+  if (fs_w != 0 && g_menuscreen_w > fs_w)
+    g_menuscreen_w = fs_w;
   g_menuscreen_h = 480;
+  if (fs_h != 0) {
+    h = fs_h;
+    if (info && info->wm_available && h > WM_DECORATION_H)
+      h -= WM_DECORATION_H;
+    if (g_menuscreen_h > h)
+      g_menuscreen_h = h;
+  }
+
   ret = change_video_mode(g_menuscreen_w, g_menuscreen_h);
   if (ret != 0) {
     ret = change_video_mode(0, 0);
@@ -74,18 +187,21 @@ void plat_init(void)
               screen->w, screen->h);
       goto fail;
     }
-    g_menuscreen_w = screen->w;
-    g_menuscreen_h = screen->h;
   }
+  g_menuscreen_w = window_w = screen->w;
+  g_menuscreen_h = window_h = screen->h;
+
   SDL_WM_SetCaption("PCSX-ReARMed " REV, NULL);
 
   menubg_img = malloc(640 * 512 * 2);
   if (menubg_img == NULL)
     goto fail;
 
-  in_sdl_init(in_sdl_defbinds);
+  in_sdl_init(in_sdl_defbinds, event_handler);
   in_probe();
   pl_rearmed_cbs.only_16bpp = 1;
+
+  bgr_to_uyvy_init();
   return;
 
 fail:
@@ -104,17 +220,96 @@ void plat_gvideo_open(int is_pal)
 {
 }
 
+static void uyvy_to_rgb565(void *d, const void *s, int pixels)
+{
+  unsigned short *dst = d;
+  const unsigned int *src = s;
+  int v;
+
+  // no colors, for now
+  for (; pixels > 0; src++, dst += 2, pixels -= 2) {
+    v = (*src >> 8) & 0xff;
+    v = (v - 16) * 255 / 219 / 8;
+    dst[0] = (v << 11) | (v << 6) | v;
+
+    v = (*src >> 24) & 0xff;
+    v = (v - 16) * 255 / 219 / 8;
+    dst[1] = (v << 11) | (v << 6) | v;
+  }
+}
+
+static void overlay_clear(void)
+{
+  int pixels = overlay->w * overlay->h;
+  int *dst = (int *)overlay->pixels[0];
+  int v = 0x10801080;
+
+  for (; pixels > 0; dst += 4, pixels -= 2 * 4)
+    dst[0] = dst[1] = dst[2] = dst[3] = v;
+
+  for (; pixels > 0; dst++, pixels -= 2)
+    *dst = v;
+}
+
+static void overlay_blit(int doffs, const void *src_, int w, int h,
+                         int sstride, int bgr24)
+{
+  const unsigned short *src = src_;
+  unsigned short *dst;
+  int dstride = overlay->w;
+
+  SDL_LockYUVOverlay(overlay);
+  dst = (void *)overlay->pixels[0];
+
+  dst += doffs;
+  if (bgr24) {
+    for (; h > 0; dst += dstride, src += sstride, h--)
+      bgr888_to_uyvy(dst, src, w);
+  }
+  else {
+    for (; h > 0; dst += dstride, src += sstride, h--)
+      bgr555_to_uyvy(dst, src, w);
+  }
+
+  SDL_UnlockYUVOverlay(overlay);
+}
+
+static void overlay_hud_print(int x, int y, const char *str, int bpp)
+{
+  SDL_LockYUVOverlay(overlay);
+  basic_text_out_uyvy_nf(overlay->pixels[0], overlay->w, x, y, str);
+  SDL_UnlockYUVOverlay(overlay);
+}
+
 void *plat_gvideo_set_mode(int *w, int *h, int *bpp)
 {
   change_video_mode(*w, *h);
-  return screen->pixels;
+  if (overlay != NULL) {
+    pl_plat_clear = overlay_clear;
+    pl_plat_blit = overlay_blit;
+    pl_plat_hud_print = overlay_hud_print;
+    return NULL;
+  }
+  else {
+    pl_plat_clear = NULL;
+    pl_plat_blit = NULL;
+    pl_plat_hud_print = NULL;
+    return screen->pixels;
+  }
 }
 
-/* XXX: missing SDL_LockSurface() */
 void *plat_gvideo_flip(void)
 {
-  SDL_Flip(screen);
-  return screen->pixels;
+  if (!in_menu && overlay != NULL) {
+    SDL_Rect dstrect = { 0, 0, screen->w, screen->h };
+    SDL_DisplayYUVOverlay(overlay, &dstrect);
+    return NULL;
+  }
+  else {
+    // XXX: missing SDL_LockSurface()
+    SDL_Flip(screen);
+    return screen->pixels;
+  }
 }
 
 void plat_gvideo_close(void)
@@ -123,8 +318,13 @@ void plat_gvideo_close(void)
 
 void plat_video_menu_enter(int is_rom_loaded)
 {
+  in_menu = 1;
+
   /* surface will be lost, must adjust pl_vout_buf for menu bg */
-  memcpy(menubg_img, screen->pixels, screen->w * screen->h * 2);
+  if (overlay != NULL)
+    uyvy_to_rgb565(menubg_img, overlay->pixels[0], psx_w * psx_h);
+  else
+    memcpy(menubg_img, screen->pixels, psx_w * psx_h * 2);
   pl_vout_buf = menubg_img;
 
   change_video_mode(g_menuscreen_w, g_menuscreen_h);
@@ -145,6 +345,7 @@ void plat_video_menu_end(void)
 
 void plat_video_menu_leave(void)
 {
+  in_menu = 0;
 }
 
 /* unused stuff */
@@ -153,25 +354,6 @@ void *plat_prepare_screenshot(int *w, int *h, int *bpp)
   return 0;
 }
 
-int plat_cpu_clock_get(void)
-{
-  return -1;
-}
-
-int plat_cpu_clock_apply(int cpu_clock)
-{
-  return -1;
-}
-
-int plat_get_bat_capacity(void)
-{
-  return -1;
-}
-
-void plat_step_volume(int is_up)
-{
-}
-
 void plat_trigger_vibrate(int is_strong)
 {
 }
index 4dbb9a7..a0f16e9 100644 (file)
 #include <unistd.h>
 #include <pthread.h>
 
+#include "libpicofe/fonts.h"
+#include "libpicofe/input.h"
+#include "libpicofe/plat.h"
+#include "libpicofe/arm/neon_scale2x.h"
+#include "libpicofe/arm/neon_eagle2x.h"
 #include "plugin_lib.h"
-#include "linux/fbdev.h"
-#include "common/fonts.h"
-#include "common/input.h"
 #include "menu.h"
 #include "main.h"
 #include "plat.h"
 #include "pl_gun_ts.h"
 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
 #include "../libpcsxcore/psemu_plugin_defs.h"
+#include "../plugins/gpulib/cspace.h"
+#include "../plugins/dfinput/externals.h"
 
 int in_type1, in_type2;
 int in_a1[2] = { 127, 127 }, in_a2[2] = { 127, 127 };
 int in_adev[2] = { -1, -1 }, in_adev_axis[2][2] = {{ 0, 1 }, { 0, 1 }};
+int in_adev_is_nublike[2];
 int in_keystate, in_state_gun;
 int in_enable_vibration;
 void *tsdev;
 void *pl_vout_buf;
 int g_layer_x, g_layer_y, g_layer_w, g_layer_h;
 static int pl_vout_w, pl_vout_h, pl_vout_bpp; /* output display/layer */
+static int pl_vout_scale;
 static int psx_w, psx_h, psx_bpp;
 static int vsync_cnt;
 static int is_pal, frame_interval, frame_interval1024;
 static int vsync_usec_time;
 
+// platform hooks
+void (*pl_plat_clear)(void);
+void (*pl_plat_blit)(int doffs, const void *src, int w, int h,
+                    int sstride, int bgr24);
+void (*pl_plat_hud_print)(int x, int y, const char *str, int bpp);
+
 
 static __attribute__((noinline)) int get_cpu_ticks(void)
 {
@@ -60,27 +72,48 @@ static __attribute__((noinline)) int get_cpu_ticks(void)
 
        sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu", &utime);
        ret = utime - last_utime;
+       if (ret > 200)
+               ret = 0;
        last_utime = utime;
        return ret;
 }
 
+static void hud_print(void *fb, int w, int x, int y, const char *text)
+{
+       if (pl_plat_hud_print)
+               pl_plat_hud_print(x, y, text, pl_vout_bpp);
+       else if (pl_vout_bpp == 16)
+               basic_text_out16_nf(fb, w, x, y, text);
+}
+
+static void hud_printf(void *fb, int w, int x, int y, const char *texto, ...)
+{
+       va_list args;
+       char    buffer[256];
+
+       va_start(args, texto);
+       vsnprintf(buffer, sizeof(buffer), texto, args);
+       va_end(args);
+
+       hud_print(fb, w, x, y, buffer);
+}
+
 static void print_msg(int h, int border)
 {
-       if (pl_vout_bpp == 16)
-               pl_text_out16(border + 2, h - 10, "%s", hud_msg);
+       hud_print(pl_vout_buf, pl_vout_w, border + 2, h - 10, 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);
+       hud_printf(pl_vout_buf, pl_vout_w, 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);
+       hud_printf(pl_vout_buf, pl_vout_w, pl_vout_w - border - 28, h - 10,
+               "%3d", pl_rearmed_cbs.cpu_usage);
 }
 
 // draw 192x8 status of 24 sound channels
@@ -96,7 +129,7 @@ static __attribute__((noinline)) void draw_active_chans(int vout_w, int vout_h)
        unsigned short *d, p;
        int c, x, y;
 
-       if (pl_vout_bpp != 16)
+       if (dest == NULL || pl_vout_bpp != 16)
                return;
 
        spu_get_debug_info(&live_chans, &run_chans, &fmod_chans, &noise_chans);
@@ -113,13 +146,13 @@ static __attribute__((noinline)) void draw_active_chans(int vout_w, int vout_h)
        }
 }
 
-void pl_print_hud(int xborder)
+void pl_print_hud(int w, int h, int xborder)
 {
-       int w = pl_vout_w, h = pl_vout_h;
-
        if (h < 16)
                return;
 
+       xborder += (pl_vout_w - w) / 2;
+
        if (g_opts & OPT_SHOWSPU)
                draw_active_chans(w, h);
 
@@ -184,55 +217,164 @@ static void update_layer_size(int w, int h)
        if (g_layer_h > g_menuscreen_h) g_layer_h = g_menuscreen_h;
 }
 
-static void *pl_vout_set_mode(int w, int h, int bpp)
+// XXX: this is platform specific really
+static int resolution_ok(int w, int h)
 {
+       return w <= 1024 && h <= 512;
+}
+
+static void pl_vout_set_mode(int w, int h, int raw_w, int raw_h, int bpp)
+{
+       int vout_w, vout_h, vout_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;
+       psx_w = raw_w;
+       psx_h = raw_h;
+       vout_w = w;
+       vout_h = h;
+       vout_bpp = psx_bpp = bpp;
+
+       pl_vout_scale = 1;
+#ifdef __ARM_NEON__
+       if (soft_filter) {
+               if (resolution_ok(w * 2, h * 2) && bpp == 16) {
+                       vout_w *= 2;
+                       vout_h *= 2;
+                       pl_vout_scale = 2;
+               }
+               else {
+                       // filter unavailable
+                       hud_msg[0] = 0;
+               }
+       }
+#endif
 
-       pl_vout_w = psx_w = w;
-       pl_vout_h = psx_h = h;
-       pl_vout_bpp = psx_bpp = bpp;
+       if (pl_vout_buf != NULL && vout_w == pl_vout_w && vout_h == pl_vout_h
+           && vout_bpp == pl_vout_bpp)
+               return;
 
-       update_layer_size(pl_vout_w, pl_vout_h);
+       update_layer_size(vout_w, vout_h);
 
-       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)
+       pl_vout_buf = plat_gvideo_set_mode(&vout_w, &vout_h, &vout_bpp);
+       if (pl_vout_buf == NULL && pl_plat_blit == NULL)
                fprintf(stderr, "failed to set mode %dx%d@%d\n",
-                       psx_w, psx_h, psx_bpp);
+                       vout_w, vout_h, psx_bpp);
+       else {
+               pl_vout_w = vout_w;
+               pl_vout_h = vout_h;
+               pl_vout_bpp = vout_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)
+static void pl_vout_flip(const void *vram, int stride, int bgr24, int w, int h)
 {
-       pl_rearmed_cbs.flip_cnt++;
+       static int doffs_old, clear_counter;
+       unsigned char *dest = pl_vout_buf;
+       const unsigned short *src = vram;
+       int dstride = pl_vout_w, h1 = h;
+       int doffs;
+
+       pcnt_start(PCNT_BLIT);
+
+       if (vram == NULL) {
+               // blanking
+               if (pl_plat_clear)
+                       pl_plat_clear();
+               else
+                       memset(pl_vout_buf, 0,
+                               dstride * pl_vout_h * pl_vout_bpp / 8);
+               goto out_hud;
+       }
+
+       // borders
+       doffs = (dstride - w * pl_vout_scale) / 2 & ~1;
 
-       if (pl_vout_buf != NULL)
-               pl_print_hud(0);
+       if (doffs > doffs_old)
+               clear_counter = 2;
+       doffs_old = doffs;
+
+       if (clear_counter > 0) {
+               if (pl_plat_clear)
+                       pl_plat_clear();
+               else
+                       memset(pl_vout_buf, 0,
+                               dstride * pl_vout_h * pl_vout_bpp / 8);
+               clear_counter--;
+       }
+
+       if (pl_plat_blit)
+       {
+               pl_plat_blit(doffs, src, w, h, stride, bgr24);
+               goto out_hud;
+       }
+
+       if (dest == NULL)
+               goto out;
+
+       dest += doffs * 2;
+
+       if (bgr24)
+       {
+               if (pl_rearmed_cbs.only_16bpp) {
+                       for (; h1-- > 0; dest += dstride * 2, src += stride)
+                       {
+                               bgr888_to_rgb565(dest, src, w * 3);
+                       }
+               }
+               else {
+                       dest -= doffs * 2;
+                       dest += (doffs / 8) * 24;
+
+                       for (; h1-- > 0; dest += dstride * 3, src += stride)
+                       {
+                               bgr888_to_rgb888(dest, src, w * 3);
+                       }
+               }
+       }
+#ifdef __ARM_NEON__
+       else if (soft_filter == SOFT_FILTER_SCALE2X && pl_vout_scale == 2)
+       {
+               neon_scale2x_16_16(src, (void *)dest, w,
+                       stride * 2, dstride * 2, h);
+       }
+       else if (soft_filter == SOFT_FILTER_EAGLE2X && pl_vout_scale == 2)
+       {
+               neon_eagle2x_16_16(src, (void *)dest, w,
+                       stride * 2, dstride * 2, h);
+       }
+#endif
+       else
+       {
+               for (; h1-- > 0; dest += dstride * 2, src += stride)
+               {
+                       bgr555_to_rgb565(dest, src, w * 2);
+               }
+       }
+
+out_hud:
+       pl_print_hud(w * pl_vout_scale, h * pl_vout_scale, 0);
+
+out:
+       pcnt_end(PCNT_BLIT);
 
        // let's flip now
        pl_vout_buf = plat_gvideo_flip();
-       return pl_vout_buf;
+       pl_rearmed_cbs.flip_cnt++;
 }
 
 static int pl_vout_open(void)
 {
        struct timeval now;
-       int h;
 
-       // force mode update
-       h = psx_h;
-       psx_h--;
-       pl_vout_buf = pl_vout_set_mode(psx_w, h, psx_bpp);
+       // force mode update on pl_vout_set_mode() call from gpulib/vout_pl
+       pl_vout_buf = NULL;
 
        plat_gvideo_open(is_pal);
 
@@ -249,6 +391,11 @@ static void pl_vout_close(void)
        plat_gvideo_close();
 }
 
+static void pl_set_gpu_caps(int caps)
+{
+       pl_rearmed_cbs.gpu_caps = caps;
+}
+
 void *pl_prepare_screenshot(int *w, int *h, int *bpp)
 {
        void *ret = plat_prepare_screenshot(w, h, bpp);
@@ -262,10 +409,109 @@ void *pl_prepare_screenshot(int *w, int *h, int *bpp)
        return pl_vout_buf;
 }
 
+/* display/redering mode switcher */
+static int dispmode_default(void)
+{
+       pl_rearmed_cbs.gpu_neon.enhancement_enable = 0;
+       soft_filter = SOFT_FILTER_NONE;
+       snprintf(hud_msg, sizeof(hud_msg), "default mode");
+       return 1;
+}
+
+int dispmode_doubleres(void)
+{
+       if (!(pl_rearmed_cbs.gpu_caps & GPU_CAP_SUPPORTS_2X)
+           || !resolution_ok(psx_w * 2, psx_h * 2) || psx_bpp != 16)
+               return 0;
+
+       dispmode_default();
+       pl_rearmed_cbs.gpu_neon.enhancement_enable = 1;
+       snprintf(hud_msg, sizeof(hud_msg), "double resolution");
+       return 1;
+}
+
+int dispmode_scale2x(void)
+{
+       if (!resolution_ok(psx_w * 2, psx_h * 2) || psx_bpp != 16)
+               return 0;
+
+       dispmode_default();
+       soft_filter = SOFT_FILTER_SCALE2X;
+       snprintf(hud_msg, sizeof(hud_msg), "scale2x");
+       return 1;
+}
+
+int dispmode_eagle2x(void)
+{
+       if (!resolution_ok(psx_w * 2, psx_h * 2) || psx_bpp != 16)
+               return 0;
+
+       dispmode_default();
+       soft_filter = SOFT_FILTER_EAGLE2X;
+       snprintf(hud_msg, sizeof(hud_msg), "eagle2x");
+       return 1;
+}
+
+static int (*dispmode_switchers[])(void) = {
+       dispmode_default,
+#ifdef __ARM_NEON__
+       dispmode_doubleres,
+       dispmode_scale2x,
+       dispmode_eagle2x,
+#endif
+};
+
+static int dispmode_current;
+
+void pl_switch_dispmode(void)
+{
+       if (pl_rearmed_cbs.gpu_caps & GPU_CAP_OWNS_DISPLAY)
+               return;
+
+       while (1) {
+               dispmode_current++;
+               if (dispmode_current >=
+                   sizeof(dispmode_switchers) / sizeof(dispmode_switchers[0]))
+                       dispmode_current = 0;
+               if (dispmode_switchers[dispmode_current]())
+                       break;
+       }
+}
+
 #ifndef MAEMO
+/* adjust circle-like analog inputs to better match
+ * more square-like analogs in PSX */
+static void update_analog_nub_adjust(int *x_, int *y_)
+{
+       #define d 16
+       static const int scale[] =
+               { 0 - d*2,  0 - d*2,  0 - d*2, 12 - d*2,
+                30 - d*2, 60 - d*2, 75 - d*2, 60 - d*2, 60 - d*2 };
+       int x = abs(*x_);
+       int y = abs(*y_);
+       int scale_x = scale[y / 16];
+       int scale_y = scale[x / 16];
+
+       if (x) {
+               x += d + (x * scale_x >> 8);
+               if (*x_ < 0)
+                       x = -x;
+       }
+       if (y) {
+               y += d + (y * scale_y >> 8);
+               if (*y_ < 0)
+                       y = -y;
+       }
+
+       *x_ = x;
+       *y_ = y;
+       #undef d
+}
+
 static void update_analogs(void)
 {
        int *nubp[2] = { in_a1, in_a2 };
+       int vals[2];
        int i, a, v, ret;
 
        for (i = 0; i < 2; i++)
@@ -274,14 +520,23 @@ static void update_analogs(void)
                        continue;
 
                for (a = 0; a < 2; a++) {
-                       nubp[i][a] = 127;
+                       vals[a] = 0;
 
                        ret = in_update_analog(in_adev[i], in_adev_axis[i][a], &v);
-                       if (ret == 0) {
-                               v = v / (IN_ABS_RANGE / 128) + 127;
-                               nubp[i][a] = v < 0 ? 0 : v;
-                       }
+                       if (ret == 0)
+                               vals[a] = 128 * v / IN_ABS_RANGE;
+               }
+
+               if (in_adev_is_nublike[i])
+                       update_analog_nub_adjust(&vals[0], &vals[1]);
+
+               for (a = 0; a < 2; a++) {
+                       v = vals[a] + 127;
+                       if (v < 0) v = 0;
+                       else if (v > 255) v = 255;
+                       nubp[i][a] = v;
                }
+
        }
        //printf("%4d %4d %4d %4d\n", in_a1[0], in_a1[1], in_a2[0], in_a2[1]);
 }
@@ -307,11 +562,6 @@ static void update_input(void)
        emu_set_action(emu_act);
 
        in_keystate = actions[IN_BINDTYPE_PLAYER12];
-#ifdef X11
-       extern int x11_update_keys(unsigned int *action);
-       in_keystate |= x11_update_keys(&emu_act);
-       emu_set_action(emu_act);
-#endif
 }
 #else /* MAEMO */
 static void update_input(void)
@@ -319,13 +569,13 @@ static void update_input(void)
 }
 #endif
 
-void pl_update_gun(int *xn, int *xres, int *y, int *in)
+void pl_update_gun(int *xn, int *yn, int *xres, int *yres, int *in)
 {
        if (tsdev)
-               pl_gun_ts_update(tsdev, xn, y, in);
+               pl_gun_ts_update(tsdev, xn, yn, in);
 
-       *xres = pl_vout_w;
-       *y = *y * pl_vout_h >> 10;
+       *xres = psx_w;
+       *yres = psx_h;
 }
 
 #define MAX_LAG_FRAMES 3
@@ -440,48 +690,22 @@ void pl_timing_prepare(int is_pal_)
                (100000*100 / (unsigned long)(pl_rearmed_cbs.gpu_peops.fFrameRateHz*100));
 }
 
-static void pl_text_out16_(int x, int y, const char *text)
+static void pl_get_layer_pos(int *x, int *y, int *w, int *h)
 {
-       int i, l, len = strlen(text), w = pl_vout_w;
-       unsigned short *screen = (unsigned short *)pl_vout_buf + x + y * w;
-       unsigned short val = 0xffff;
-
-       for (i = 0; i < len; i++, screen += 8)
-       {
-               for (l = 0; l < 8; l++)
-               {
-                       unsigned char fd = fontdata8x8[text[i] * 8 + l];
-                       unsigned short *s = screen + l * w;
-                       if (fd&0x80) s[0] = val;
-                       if (fd&0x40) s[1] = val;
-                       if (fd&0x20) s[2] = val;
-                       if (fd&0x10) s[3] = val;
-                       if (fd&0x08) s[4] = val;
-                       if (fd&0x04) s[5] = val;
-                       if (fd&0x02) s[6] = val;
-                       if (fd&0x01) s[7] = val;
-               }
-       }
+       *x = g_layer_x;
+       *y = g_layer_y;
+       *w = g_layer_w;
+       *h = g_layer_h;
 }
 
-void pl_text_out16(int x, int y, const char *texto, ...)
+static void *pl_mmap(unsigned int size)
 {
-       va_list args;
-       char    buffer[256];
-
-       va_start(args, texto);
-       vsnprintf(buffer, sizeof(buffer), texto, args);
-       va_end(args);
-
-       pl_text_out16_(x, y, buffer);
+       return plat_mmap(0, size, 0, 0);
 }
 
-static void pl_get_layer_pos(int *x, int *y, int *w, int *h)
+static void pl_munmap(void *ptr, unsigned int size)
 {
-       *x = g_layer_x;
-       *y = g_layer_y;
-       *w = g_layer_w;
-       *h = g_layer_h;
+       plat_munmap(ptr, size);
 }
 
 struct rearmed_cbs pl_rearmed_cbs = {
@@ -490,6 +714,10 @@ struct rearmed_cbs pl_rearmed_cbs = {
        pl_vout_set_mode,
        pl_vout_flip,
        pl_vout_close,
+
+       .mmap = pl_mmap,
+       .munmap = pl_munmap,
+       .pl_set_gpu_caps = pl_set_gpu_caps,
 };
 
 /* watchdog */
index bcf74ac..bec16b2 100644 (file)
@@ -20,6 +20,7 @@ enum {
 extern int in_type1, in_type2;
 extern int in_keystate, in_state_gun, in_a1[2], in_a2[2];
 extern int in_adev[2], in_adev_axis[2][2];
+extern int in_adev_is_nublike[2];
 extern int in_enable_vibration;
 
 extern void *pl_vout_buf;
@@ -27,26 +28,27 @@ extern void *pl_vout_buf;
 extern int g_layer_x, g_layer_y;
 extern int g_layer_w, g_layer_h;
 
-void  pl_text_out16(int x, int y, const char *texto, ...);
 void  pl_start_watchdog(void);
 void *pl_prepare_screenshot(int *w, int *h, int *bpp);
 void  pl_init(void);
-void  pl_print_hud(int xborder);
+void  pl_print_hud(int width, int height, int xborder);
+void  pl_switch_dispmode(void);
 
 void  pl_timing_prepare(int is_pal);
 void  pl_frame_limit(void);
 
-void  pl_update_gun(int *xn, int *xres, int *y, int *in);
-
 struct rearmed_cbs {
        void  (*pl_get_layer_pos)(int *x, int *y, int *w, int *h);
        int   (*pl_vout_open)(void);
-       void *(*pl_vout_set_mode)(int w, int h, int bpp);
-       void *(*pl_vout_flip)(void);
+       void  (*pl_vout_set_mode)(int w, int h, int raw_w, int raw_h, int bpp);
+       void  (*pl_vout_flip)(const void *vram, int stride, int bgr24,
+                             int w, int h);
        void  (*pl_vout_close)(void);
-       // these are only used by some frontends
-       void  (*pl_vout_raw_flip)(int x, int y);
+       void *(*mmap)(unsigned int size);
+       void  (*munmap)(void *ptr, unsigned int size);
+       // only used by some frontends
        void  (*pl_vout_set_raw_vram)(void *vram);
+       void  (*pl_set_gpu_caps)(int caps);
        // some stats, for display by some plugins
        int flips_per_sec, cpu_usage;
        float vsps_cur; // currect vsync/s
@@ -60,6 +62,8 @@ struct rearmed_cbs {
        unsigned int only_16bpp; // platform is 16bpp-only
        struct {
                int   allow_interlace; // 0 off, 1 on, 2 guess
+               int   enhancement_enable;
+               int   enhancement_no_main;
        } gpu_neon;
        struct {
                int   iUseDither;
@@ -78,10 +82,23 @@ struct rearmed_cbs {
                int   iUseMask, bOpaquePass, bAdvancedBlend, bUseFastMdec;
                int   iVRamSize, iTexGarbageCollection;
        } gpu_peopsgl;
+       // misc
+       int gpu_caps;
 };
 
 extern struct rearmed_cbs pl_rearmed_cbs;
 
+enum gpu_plugin_caps {
+       GPU_CAP_OWNS_DISPLAY = (1 << 0),
+       GPU_CAP_SUPPORTS_2X = (1 << 1),
+};
+
+// platform hooks
+extern void (*pl_plat_clear)(void);
+extern void (*pl_plat_blit)(int doffs, const void *src,
+                           int w, int h, int sstride, int bgr24);
+extern void (*pl_plat_hud_print)(int x, int y, const char *str, int bpp);
+
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
 #endif
diff --git a/frontend/xkb.c b/frontend/xkb.c
deleted file mode 100644 (file)
index f015dd0..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (c) 2009, Wei Mingzhi <whistler@openoffice.org>.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/keysym.h>
-#include <X11/XKBlib.h>
-
-#include "main.h"
-#include "plugin_lib.h"
-
-static const struct {
-       uint16_t xkey, psxkey;
-} keymap[] = {
-       { XK_Left,      DKEY_LEFT },
-       { XK_Right,     DKEY_RIGHT },
-       { XK_Up,        DKEY_UP },
-       { XK_Down,      DKEY_DOWN },
-       { XK_z,         DKEY_CROSS },
-       { XK_s,         DKEY_SQUARE },
-       { XK_x,         DKEY_CIRCLE },
-       { XK_d,         DKEY_TRIANGLE },
-       { XK_w,         DKEY_L1 },
-       { XK_r,         DKEY_R1 },
-       { XK_e,         DKEY_L2 },
-       { XK_t,         DKEY_R2 },
-       { XK_c,         DKEY_SELECT },
-       { XK_v,         DKEY_START },
-
-       { XK_F6,        32 + SACTION_SAVE_STATE },
-       { XK_F7,        32 + SACTION_PREV_SSLOT },
-       { XK_F8,        32 + SACTION_NEXT_SSLOT },
-       { XK_F9,        32 + SACTION_LOAD_STATE },
-};
-
-static Atom wmprotocols, wmdelwindow;
-static int initialized;
-
-static void InitKeyboard(void) {
-       Display *disp = (Display *)gpuDisp;
-       if (disp == NULL) {
-               fprintf(stderr, "xkb: null display\n");
-               exit(1);
-       }
-
-       wmprotocols = XInternAtom(disp, "WM_PROTOCOLS", 0);
-       wmdelwindow = XInternAtom(disp, "WM_DELETE_WINDOW", 0);
-
-       XkbSetDetectableAutoRepeat(disp, 1, NULL);
-}
-
-static void DestroyKeyboard(void) {
-       Display *disp = (Display *)gpuDisp;
-       if (disp)
-               XkbSetDetectableAutoRepeat(disp, 0, NULL);
-}
-
-int x11_update_keys(unsigned int *action) {
-       uint8_t                                 i;
-       XEvent                                  evt;
-       XClientMessageEvent             *xce;
-       uint16_t                                Key;
-       static int keystate_x11;
-       int psxkey, leave = 0;
-       Display *disp = (Display *)gpuDisp;
-
-       if (!disp)
-               return 0;
-
-       if (!initialized) {
-               initialized++;
-               InitKeyboard();
-       }
-
-       while (XPending(disp)) {
-               XNextEvent(disp, &evt);
-               switch (evt.type) {
-                       case KeyPress:
-                       case KeyRelease:
-                               Key = XLookupKeysym((XKeyEvent *)&evt, 0);
-                               //printf("%s %x\n", evt.type == KeyPress ? "press" : "rel  ", Key);
-                               psxkey = -1;
-                               for (i = 0; i < ARRAY_SIZE(keymap); i++) {
-                                       if (keymap[i].xkey == Key) {
-                                               psxkey = keymap[i].psxkey;
-                                               break;
-                                       }
-                               }
-
-                               if (0 <= psxkey && psxkey < 32) {
-                                       if (evt.type == KeyPress)
-                                               keystate_x11 |= 1 << psxkey;
-                                       else
-                                               keystate_x11 &= ~(1 << psxkey);
-                               }
-                               if (evt.type == KeyPress) {
-                                       if (psxkey > 32)
-                                               *action = psxkey - 32;
-                                       if (Key == XK_Escape)
-                                               leave = 1;
-                               }
-                               break;
-
-                       case ClientMessage:
-                               xce = (XClientMessageEvent *)&evt;
-                               if (xce->message_type == wmprotocols && (Atom)xce->data.l[0] == wmdelwindow)
-                                       leave = 1;
-                               break;
-               }
-       }
-
-       if (leave) {
-               extern void OnFile_Exit();
-               DestroyKeyboard();
-               OnFile_Exit();
-               exit(1);
-       }
-
-       return keystate_x11;
-}
index 0089cfe..c9d94f2 100644 (file)
@@ -59,8 +59,11 @@ static pthread_t threadid;
 static unsigned int initial_offset = 0;
 static boolean playing = FALSE;
 static boolean cddaBigEndian = FALSE;
+// offsets of cddaHandle file
 static unsigned int cdda_cur_sector;
-static unsigned int cdda_start_sector;
+static unsigned int cdda_first_sector;
+// toc_sector - file_sector
+static unsigned int cdda_toc_delta;
 /* Frame offset into CD image where pregap data would be found if it was there.
  * If a game seeks there we must *not* return subchannel data since it's
  * not in the CD image, so that cdrom code can fake subchannel data instead.
@@ -181,17 +184,13 @@ static void *playthread(void *param)
                        if (d < CD_FRAMESIZE_RAW)
                                break;
 
+                       if (cdda_cur_sector < cdda_first_sector)
+                               memset(sndbuffer + s, 0, CD_FRAMESIZE_RAW);
+
                        s += d;
                        cdda_cur_sector++;
                }
 
-               if (subHandle != NULL) {
-                       fseek(subHandle, cdda_cur_sector * SUB_FRAMESIZE, SEEK_SET);
-                       fread(subbuffer, 1, SUB_FRAMESIZE, subHandle);
-
-                       if (subChanRaw) DecodeRawSubData();
-               }
-
                if (s == 0) {
                        playing = FALSE;
                        initial_offset = 0;
@@ -1230,7 +1229,7 @@ static long CALLBACK ISOopen(void) {
        if (numtracks > 1 && ti[1].handle == NULL) {
                ti[1].handle = fopen(GetIsoFile(), "rb");
        }
-       cdda_cur_sector = cdda_start_sector = 0;
+       cdda_cur_sector = cdda_toc_delta = 0;
 
        return 0;
 }
@@ -1377,19 +1376,22 @@ static long CALLBACK ISOreadTrack(unsigned char *time) {
 // sector: byte 0 - minute; byte 1 - second; byte 2 - frame
 // does NOT uses bcd format
 static long CALLBACK ISOplay(unsigned char *time) {
-       unsigned int i, abs_sect;
-       int file_sect;
+       unsigned int i, abs_sect, start_sect = 0;
+       int track_offset, file_sect;
 
        if (numtracks <= 1)
                return 0;
 
        // find the track
        abs_sect = msf2sec((char *)time);
-       for (i = numtracks; i > 1; i--)
-               if (msf2sec(ti[i].start) <= abs_sect + 2 * 75)
+       for (i = numtracks; i > 1; i--) {
+               start_sect = msf2sec(ti[i].start);
+               if (start_sect <= abs_sect + 2 * 75)
                        break;
+       }
 
-       file_sect = ti[i].start_offset + (abs_sect - msf2sec(ti[i].start));
+       track_offset = abs_sect - start_sect;
+       file_sect = ti[i].start_offset + track_offset;
        if (file_sect < 0)
                file_sect = 0;
 
@@ -1398,13 +1400,12 @@ static long CALLBACK ISOplay(unsigned char *time) {
                if (ti[i].handle != NULL)
                        break;
 
-       cdda_start_sector = abs_sect - file_sect;
-       cddaHandle = ti[i].handle;
+       cdda_first_sector = 0;
+       if (i == 1)
+               cdda_first_sector = file_sect - track_offset;
 
-       if (pregapOffset && (unsigned int)(pregapOffset - file_sect) < 2 * 75) {
-               // get out of the missing pregap to avoid noise
-               file_sect = pregapOffset;
-       }
+       cdda_toc_delta = abs_sect - file_sect;
+       cddaHandle = ti[i].handle;
 
        if (SPU_playCDDAchannel != NULL) {
                startCDDA(file_sect);
@@ -1440,7 +1441,7 @@ static long CALLBACK ISOgetStatus(struct CdrStat *stat) {
                stat->Type = 0x01;
        }
 
-       sec = cdda_start_sector + cdda_cur_sector;
+       sec = cdda_cur_sector + cdda_toc_delta;
        sec2msf(sec, (char *)stat->Time);
 
        return 0;
index 297c8ae..60f03e7 100644 (file)
@@ -26,6 +26,7 @@
 #include "psxdma.h"
 
 cdrStruct cdr;
+static unsigned char *pTransfer;
 
 /* CD-ROM magic numbers */
 #define CdlSync        0
@@ -119,13 +120,20 @@ unsigned char Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 };
 // so (PSXCLK / 75) = cdr read time (linuzappz)
 #define cdReadTime (PSXCLK / 75)
 
+// for cdr.Seeked
+enum seeked_state {
+       SEEK_PENDING = 0,
+       SEEK_DONE = 1,
+       SEEK_DOING_CMD = 2,
+};
+
 static struct CdrStat stat;
 
-static unsigned int msf2sec(char *msf) {
+static unsigned int msf2sec(u8 *msf) {
        return ((msf[0] * 60 + msf[1]) * 75) + msf[2];
 }
 
-static void sec2msf(unsigned int s, char *msf) {
+static void sec2msf(unsigned int s, u8 *msf) {
        msf[0] = s / 75 / 60;
        s = s - msf[0] * 75 * 60;
        msf[1] = s / 75;
@@ -133,7 +141,7 @@ static void sec2msf(unsigned int s, char *msf) {
        msf[2] = s;
 }
 
-
+// cdrInterrupt
 #define CDR_INT(eCycle) { \
        psxRegs.interrupt |= (1 << PSXINT_CDR); \
        psxRegs.intCycle[PSXINT_CDR].cycle = eCycle; \
@@ -141,6 +149,7 @@ static void sec2msf(unsigned int s, char *msf) {
        new_dyna_set_event(PSXINT_CDR, eCycle); \
 }
 
+// cdrReadInterrupt
 #define CDREAD_INT(eCycle) { \
        psxRegs.interrupt |= (1 << PSXINT_CDREAD); \
        psxRegs.intCycle[PSXINT_CDREAD].cycle = eCycle; \
@@ -148,6 +157,7 @@ static void sec2msf(unsigned int s, char *msf) {
        new_dyna_set_event(PSXINT_CDREAD, eCycle); \
 }
 
+// cdrLidSeekInterrupt
 #define CDRLID_INT(eCycle) { \
        psxRegs.interrupt |= (1 << PSXINT_CDRLID); \
        psxRegs.intCycle[PSXINT_CDRLID].cycle = eCycle; \
@@ -155,7 +165,8 @@ static void sec2msf(unsigned int s, char *msf) {
        new_dyna_set_event(PSXINT_CDRLID, eCycle); \
 }
 
-#define CDRPLAY_INT(eCycle) { \
+// cdrPlayInterrupt
+#define CDRMISC_INT(eCycle) { \
        psxRegs.interrupt |= (1 << PSXINT_CDRPLAY); \
        psxRegs.intCycle[PSXINT_CDRPLAY].cycle = eCycle; \
        psxRegs.intCycle[PSXINT_CDRPLAY].sCycle = psxRegs.cycle; \
@@ -251,7 +262,6 @@ void cdrLidSeekInterrupt()
        }
 }
 
-
 static void Check_Shell( int Irq )
 {
        // check case open/close
@@ -410,12 +420,13 @@ static void ReadTrack( u8 *time ) {
 }
 
 
-void AddIrqQueue(unsigned char irq, unsigned long ecycle) {
+static void AddIrqQueue(unsigned char irq, unsigned long ecycle) {
+       //if (cdr.Irq != 0 && cdr.Irq != 0xff)
+       //      printf("cdr: override cmd %02x -> %02x\n", cdr.Irq, irq);
+
        cdr.Irq = irq;
        cdr.eCycle = ecycle;
 
-       // Doom: Force rescheduling
-       // - Fixes boot
        CDR_INT(ecycle);
 }
 
@@ -541,6 +552,9 @@ static void cdrPlayInterrupt_Autopause()
        struct SubQ *subq = (struct SubQ *)CDR_getBufferSub();
        int track_changed = 0;
        if (subq != NULL ) {
+               // update subq
+               ReadTrack( cdr.SetSectorPlay );
+
 #ifdef CDR_LOG
                CDR_LOG( "CDDA SUB - %X:%X:%X\n",
                        subq->AbsoluteAddress[0], subq->AbsoluteAddress[1], subq->AbsoluteAddress[2] );
@@ -553,7 +567,9 @@ static void cdrPlayInterrupt_Autopause()
                Tomb Raider 1 ($7)
                */
 
-               if( cdr.CurTrack < btoi( subq->TrackNumber ) )
+               // .. + 1 is probably wrong, but deals with corrupted subq + good checksum
+               // (how does real thing handle those?)
+               if( cdr.CurTrack + 1 == btoi( subq->TrackNumber ) )
                        track_changed = 1;
        } else {
                Create_Fake_Subq();
@@ -582,13 +598,14 @@ static void cdrPlayInterrupt_Autopause()
 
                StopCdda();
        }
-       if (cdr.Mode & MODE_REPORT) {
+       else if (cdr.Mode & MODE_REPORT) {
                if (subq != NULL) {
 #ifdef CDR_LOG
                        CDR_LOG( "REPPLAY SUB - %X:%X:%X\n",
                                subq->AbsoluteAddress[0], subq->AbsoluteAddress[1], subq->AbsoluteAddress[2] );
 #endif
-                       cdr.CurTrack = btoi( subq->TrackNumber );
+                       // breaks when .sub doesn't have index 0 for some reason (bad rip?)
+                       //cdr.CurTrack = btoi( subq->TrackNumber );
 
                        if (subq->AbsoluteAddress[2] & 0xf)
                                return;
@@ -629,15 +646,40 @@ static void cdrPlayInterrupt_Autopause()
        }
 }
 
+// also handles seek
 void cdrPlayInterrupt()
 {
-       if( !cdr.Play ) return;
+       if (cdr.Seeked == SEEK_DOING_CMD) {
+               SetResultSize(1);
+               cdr.StatP |= STATUS_ROTATING;
+               cdr.StatP &= ~STATUS_SEEK;
+               cdr.Result[0] = cdr.StatP;
+               if (cdr.Irq == 0 || cdr.Irq == 0xff) {
+                       cdr.Stat = Complete;
+                       if (cdr.Stat != NoIntr)
+                               psxHu32ref(0x1070) |= SWAP32(0x4);
+               }
+
+               cdr.Seeked = SEEK_PENDING;
+               CDRMISC_INT(cdReadTime * 20); // ???
+               return;
+       }
+       else if (cdr.Seeked == SEEK_PENDING) {
+               cdr.Seeked = SEEK_DONE;
+               if (!cdr.Play && !cdr.Reading) {
+                       memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
+                       Find_CurTrack();
+                       ReadTrack(cdr.SetSector);
+               }
+       }
+
+       if (!cdr.Play) return;
 
 #ifdef CDR_LOG
        CDR_LOG( "CDDA - %d:%d:%d\n",
                cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2] );
 #endif
-       CDRPLAY_INT( cdReadTime );
+       CDRMISC_INT( cdReadTime );
 
        if (!cdr.Irq && !cdr.Stat && (cdr.Mode & MODE_CDDA) && (cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT)))
                cdrPlayInterrupt_Autopause();
@@ -696,9 +738,10 @@ void cdrInterrupt() {
                case CdlPlay:
                        fake_subq_change = 0;
 
-                       if( cdr.Seeked == FALSE ) {
+                       if (cdr.Seeked == SEEK_PENDING) {
+                               // XXX: wrong, should seek instead..
                                memcpy( cdr.SetSectorPlay, cdr.SetSector, 4 );
-                               cdr.Seeked = TRUE;
+                               cdr.Seeked = SEEK_DONE;
                        }
 
                        /*
@@ -779,7 +822,7 @@ void cdrInterrupt() {
                                                                cdr.SetSectorPlay[2] = cdr.ResultTD[0];
 
                                                                // reset data
-                                                               Set_Track();
+                                                               //Set_Track();
                                                                Find_CurTrack();
                                                                ReadTrack( cdr.SetSectorPlay );
 
@@ -807,7 +850,7 @@ void cdrInterrupt() {
                        // BIOS player - set flag again
                        cdr.Play = TRUE;
 
-                       CDRPLAY_INT( cdReadTime );
+                       CDRMISC_INT( cdReadTime );
                        break;
 
                case CdlForward:
@@ -958,6 +1001,10 @@ void cdrInterrupt() {
                        subq = (struct SubQ *)CDR_getBufferSub();
 
                        if (subq != NULL) {
+                               if( cdr.Play && (cdr.Mode & MODE_CDDA) && !(cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT)) )
+                                       // update subq
+                                       ReadTrack( cdr.SetSectorPlay );
+
                                cdr.Result[0] = subq->TrackNumber;
                                cdr.Result[1] = subq->IndexNumber;
                                memcpy(cdr.Result + 2, subq->TrackRelativeAddress, 3);
@@ -1036,6 +1083,7 @@ void cdrInterrupt() {
                        break;
 
                case CdlSeekL:
+               case CdlSeekP:
                        SetResultSize(1);
                        cdr.StatP |= STATUS_ROTATING;
                        cdr.Result[0] = cdr.StatP;
@@ -1055,45 +1103,8 @@ void cdrInterrupt() {
                        Rockman X5 = 0.5-4x
                        - fix capcom logo
                        */
-                       AddIrqQueue(CdlSeekL + 0x20, cdReadTime * 4);
-                       break;
-
-               case CdlSeekL + 0x20:
-                       SetResultSize(1);
-                       cdr.StatP |= STATUS_ROTATING;
-                       cdr.StatP &= ~STATUS_SEEK;
-                       cdr.Result[0] = cdr.StatP;
-                       cdr.Seeked = TRUE;
-                       cdr.Stat = Complete;
-
-
-                       // Mega Man Legends 2: must update read cursor for getlocp
-                       ReadTrack( cdr.SetSector );
-                       break;
-
-               case CdlSeekP:
-                       SetResultSize(1);
-                       cdr.StatP |= STATUS_ROTATING;
-                       cdr.Result[0] = cdr.StatP;
-                       cdr.StatP |= STATUS_SEEK;
-                       cdr.Stat = Acknowledge;
-                       AddIrqQueue(CdlSeekP + 0x20, cdReadTime * 1);
-                       break;
-
-               case CdlSeekP + 0x20:
-                       SetResultSize(1);
-                       cdr.StatP |= STATUS_ROTATING;
-                       cdr.StatP &= ~STATUS_SEEK;
-                       cdr.Result[0] = cdr.StatP;
-                       cdr.Stat = Complete;
-                       cdr.Seeked = TRUE;
-
-                       // GameShark Music Player
-                       memcpy( cdr.SetSectorPlay, cdr.SetSector, 4 );
-
-                       // Tomb Raider 2: must update read cursor for getlocp
-                       Find_CurTrack();
-                       ReadTrack( cdr.SetSectorPlay );
+                       CDRMISC_INT(cdr.Seeked == SEEK_DONE ? 0x800 : cdReadTime * 4);
+                       cdr.Seeked = SEEK_DOING_CMD;
                        break;
 
                case CdlTest:
@@ -1222,17 +1233,14 @@ void cdrInterrupt() {
                                if (buf != NULL)
                                        memcpy(cdr.Transfer, buf, 8);
                        }
-                       
-                       
+
                        /*
                        Duke Nukem: Land of the Babes - seek then delay read for one frame
                        - fixes cutscenes
                        C-12 - Final Resistance - doesn't like seek
                        */
 
-                       if (!cdr.Seeked) {
-                               cdr.Seeked = TRUE;
-
+                       if (cdr.Seeked != SEEK_DONE) {
                                cdr.StatP |= STATUS_SEEK;
                                cdr.StatP &= ~STATUS_READ;
 
@@ -1272,7 +1280,10 @@ void cdrInterrupt() {
        }
 
 #ifdef CDR_LOG
-       CDR_LOG("cdrInterrupt() Log: CDR Interrupt IRQ %x\n", Irq);
+       printf("cdrInterrupt() Log: CDR Interrupt IRQ %x: ", Irq);
+       for (i = 0; i < cdr.ResultC; i++)
+               printf("%02x ", cdr.Result[i]);
+       printf("\n");
 #endif
 }
 
@@ -1296,6 +1307,7 @@ void cdrReadInterrupt() {
        cdr.StatP |= STATUS_READ|STATUS_ROTATING;
        cdr.StatP &= ~STATUS_SEEK;
        cdr.Result[0] = cdr.StatP;
+       cdr.Seeked = SEEK_DONE;
 
        ReadTrack( cdr.SetSector );
 
@@ -1473,7 +1485,7 @@ unsigned char cdrRead1(void) {
 }
 
 void cdrWrite1(unsigned char rt) {
-       char set_loc[3];
+       u8 set_loc[3];
        int i;
 
 #ifdef CDR_LOG
@@ -1526,17 +1538,14 @@ void cdrWrite1(unsigned char rt) {
                StopReading();
                for (i = 0; i < 3; i++)
                        set_loc[i] = btoi(cdr.Param[i]);
+
                i = abs(msf2sec(cdr.SetSector) - msf2sec(set_loc));
                if (i > 16)
-                       cdr.Seeked = FALSE;
+                      cdr.Seeked = SEEK_PENDING;
+
                memcpy(cdr.SetSector, set_loc, 3);
                cdr.SetSector[3] = 0;
 
-               /*
-                  if ((cdr.SetSector[0] | cdr.SetSector[1] | cdr.SetSector[2]) == 0) {
-                *(u32 *)cdr.SetSector = *(u32 *)cdr.SetSectorSeek;
-                }*/
-
                cdr.Ctrl |= 0x80;
                cdr.Stat = NoIntr;
                AddIrqQueue(cdr.Cmd, 0x800);
@@ -1652,6 +1661,7 @@ void cdrWrite1(unsigned char rt) {
 
        case CdlReset:
        case CdlInit:
+               cdr.Seeked = SEEK_DONE;
                StopCdda();
                StopReading();
                cdr.Ctrl |= 0x80;
@@ -1826,7 +1836,7 @@ unsigned char cdrRead2(void) {
        if (cdr.Readed == 0) {
                ret = 0;
        } else {
-               ret = *cdr.pTransfer++;
+               ret = *pTransfer++;
        }
 
 #ifdef CDR_LOG
@@ -1942,16 +1952,16 @@ void cdrWrite3(unsigned char rt) {
 
        if (rt == 0x80 && !(cdr.Ctrl & 0x3) && cdr.Readed == 0) {
                cdr.Readed = 1;
-               cdr.pTransfer = cdr.Transfer;
+               pTransfer = cdr.Transfer;
 
                switch (cdr.Mode & 0x30) {
                        case MODE_SIZE_2328:
                        case 0x00:
-                               cdr.pTransfer += 12;
+                               pTransfer += 12;
                                break;
 
                        case MODE_SIZE_2340:
-                               cdr.pTransfer += 0;
+                               pTransfer += 0;
                                break;
 
                        default:
@@ -2007,16 +2017,16 @@ void psxDma3(u32 madr, u32 bcr, u32 chcr) {
                        - CdlPlay
                        - Spams DMA3 and gets buffer overrun
                        */
-                       size = CD_FRAMESIZE_RAW - (cdr.pTransfer - cdr.Transfer);
+                       size = CD_FRAMESIZE_RAW - (pTransfer - cdr.Transfer);
                        if (size > cdsize)
                                size = cdsize;
                        if (size > 0)
                        {
-                               memcpy(ptr, cdr.pTransfer, size);
+                               memcpy(ptr, pTransfer, size);
                        }
 
                        psxCpu->Clear(madr, cdsize / 4);
-                       cdr.pTransfer += cdsize;
+                       pTransfer += cdsize;
 
 
                        // burst vs normal
@@ -2053,6 +2063,7 @@ void cdrReset() {
        cdr.CurTrack = 1;
        cdr.File = 1;
        cdr.Channel = 1;
+       pTransfer = cdr.Transfer;
 
        // BIOS player - default values
        cdr.AttenuatorLeft[0] = 0x80;
@@ -2062,8 +2073,7 @@ void cdrReset() {
 }
 
 int cdrFreeze(gzFile f, int Mode) {
-       uintptr_t tmp;
-
+       u32 tmp;
 
        if( Mode == 0 ) {
                StopCdda();
@@ -2072,12 +2082,12 @@ int cdrFreeze(gzFile f, int Mode) {
        gzfreeze(&cdr, sizeof(cdr));
        
        if (Mode == 1)
-               tmp = cdr.pTransfer - cdr.Transfer;
+               tmp = pTransfer - cdr.Transfer;
 
        gzfreeze(&tmp, sizeof(tmp));
 
        if (Mode == 0) {
-               cdr.pTransfer = cdr.Transfer + tmp;
+               pTransfer = cdr.Transfer + tmp;
 
                if (cdr.Play && !Config.Cdda)
                        CDR_play(cdr.SetSectorPlay);
index 772e3ca..ab22ccd 100644 (file)
@@ -52,7 +52,7 @@ typedef struct {
        unsigned char StatP;
 
        unsigned char Transfer[CD_FRAMESIZE_RAW];
-       unsigned char *pTransfer;
+       unsigned int  pad1;
 
        unsigned char Prev[4];
        unsigned char Param[8];
@@ -87,7 +87,7 @@ typedef struct {
        unsigned char Irq;
        u32 eCycle;
 
-       boolean Seeked;
+       u8 Seeked;
 
        u8 LidCheck;
        u8 FastForward;
index 1d084d2..b472e1d 100644 (file)
@@ -25,9 +25,9 @@
 struct external_filehdr {
        unsigned short f_magic;         /* magic number                 */
        unsigned short f_nscns;         /* number of sections           */
-       unsigned long f_timdat; /* time & date stamp            */
-       unsigned long f_symptr; /* file pointer to symtab       */
-       unsigned long f_nsyms;          /* number of symtab entries     */
+       unsigned int f_timdat;  /* time & date stamp            */
+       unsigned int f_symptr;  /* file pointer to symtab       */
+       unsigned int f_nsyms;           /* number of symtab entries     */
        unsigned short f_opthdr;        /* sizeof(optional hdr)         */
        unsigned short f_flags;         /* flags                        */
 };
index dc56b7f..62fc7f3 100644 (file)
 #include "gte.h"
 #include "psxmem.h"
 
-typedef struct psxCP2Regs {
-       psxCP2Data CP2D;        /* Cop2 data registers */
-       psxCP2Ctrl CP2C;        /* Cop2 control registers */
-} psxCP2Regs;
-
 #define VX(n) (n < 3 ? regs->CP2D.p[n << 1].sw.l : regs->CP2D.p[9].sw.l)
 #define VY(n) (n < 3 ? regs->CP2D.p[n << 1].sw.h : regs->CP2D.p[10].sw.l)
 #define VZ(n) (n < 3 ? regs->CP2D.p[(n << 1) + 1].sw.l : regs->CP2D.p[11].sw.l)
@@ -264,7 +259,7 @@ static inline u32 limE_(psxCP2Regs *regs, u32 result) {
 #ifndef FLAGLESS
 
 static inline u32 MFC2(int reg) {
-       psxCP2Regs *regs = (psxCP2Regs *)&psxRegs.CP2D;
+       psxCP2Regs *regs = &psxRegs.CP2;
        switch (reg) {
                case 1:
                case 3:
@@ -299,7 +294,7 @@ static inline u32 MFC2(int reg) {
 }
 
 static inline void MTC2(u32 value, int reg) {
-       psxCP2Regs *regs = (psxCP2Regs *)&psxRegs.CP2D;
+       psxCP2Regs *regs = &psxRegs.CP2;
        switch (reg) {
                case 15:
                        gteSXY0 = gteSXY1;
index 6cf2886..cd8d3bf 100644 (file)
@@ -672,7 +672,30 @@ void mdec1Interrupt() {
 }
 
 int mdecFreeze(gzFile f, int Mode) {
-       gzfreeze(&mdec, sizeof(mdec));
+       u8 *base = (u8 *)&psxM[0x100000];
+       u32 v;
+
+       gzfreeze(&mdec.reg0, sizeof(mdec.reg0));
+       gzfreeze(&mdec.reg1, sizeof(mdec.reg1));
+
+       // old code used to save raw pointers..
+       v = (u8 *)mdec.rl - base;
+       gzfreeze(&v, sizeof(v));
+       mdec.rl = (u16 *)(base + (v & 0xffffe));
+       v = (u8 *)mdec.rl_end - base;
+       gzfreeze(&v, sizeof(v));
+       mdec.rl_end = (u16 *)(base + (v & 0xffffe));
+
+       v = 0;
+       if (mdec.block_buffer_pos)
+               v = mdec.block_buffer_pos - base;
+       gzfreeze(&v, sizeof(v));
+       mdec.block_buffer_pos = 0;
+       if (v)
+               mdec.block_buffer_pos = base + (v & 0xfffff);
+
+       gzfreeze(&mdec.block_buffer, sizeof(mdec.block_buffer));
+       gzfreeze(&mdec.pending_dma1, sizeof(mdec.pending_dma1));
        gzfreeze(iq_y, sizeof(iq_y));
        gzfreeze(iq_uv, sizeof(iq_uv));
 
index 2fe5600..ad2e5d5 100644 (file)
@@ -93,8 +93,9 @@ void mmssdd( char *b, char *p )
 
 #define READTRACK() \
        if (CDR_readTrack(time) == -1) return -1; \
-       buf = CDR_getBuffer(); \
-       if (buf == NULL) return -1; else CheckPPFCache(buf, time[0], time[1], time[2]);
+       buf = (void *)CDR_getBuffer(); \
+       if (buf == NULL) return -1; \
+       else CheckPPFCache((u8 *)buf, time[0], time[1], time[2]);
 
 #define READDIR(_dir) \
        READTRACK(); \
@@ -104,9 +105,9 @@ void mmssdd( char *b, char *p )
        READTRACK(); \
        memcpy(_dir + 2048, buf + 12, 2048);
 
-int GetCdromFile(u8 *mdir, u8 *time, s8 *filename) {
+int GetCdromFile(u8 *mdir, u8 *time, char *filename) {
        struct iso_directory_record *dir;
-       char ddir[4096];
+       u8 ddir[4096];
        u8 *buf;
        int i;
 
@@ -169,7 +170,7 @@ int LoadCdrom() {
        struct iso_directory_record *dir;
        u8 time[4], *buf;
        u8 mdir[4096];
-       s8 exename[256];
+       char exename[256];
 
        // not the best place to do it, but since BIOS boot logo killer
        // is just below, do it here
@@ -207,7 +208,7 @@ int LoadCdrom() {
                if (GetCdromFile(mdir, time, exename) == -1) {
                        sscanf((char *)buf + 12, "BOOT = cdrom:%256s", exename);
                        if (GetCdromFile(mdir, time, exename) == -1) {
-                               char *ptr = strstr(buf + 12, "cdrom:");
+                               char *ptr = strstr((char *)buf + 12, "cdrom:");
                                if (ptr != NULL) {
                                        ptr += 6;
                                        while (*ptr == '\\' || *ptr == '/') ptr++;
@@ -258,8 +259,10 @@ int LoadCdrom() {
 int LoadCdromFile(const char *filename, EXE_HEADER *head) {
        struct iso_directory_record *dir;
        u8 time[4],*buf;
-       u8 mdir[4096], exename[256];
+       u8 mdir[4096];
+       char exename[256];
        u32 size, addr;
+       void *mem;
 
        sscanf(filename, "cdrom:\\%256s", exename);
 
@@ -288,7 +291,9 @@ int LoadCdromFile(const char *filename, EXE_HEADER *head) {
                incTime();
                READTRACK();
 
-               memcpy((void *)PSXM(addr), buf + 12, 2048);
+               mem = PSXM(addr);
+               if (mem)
+                       memcpy(mem, buf + 12, 2048);
 
                size -= 2048;
                addr += 2048;
@@ -299,7 +304,8 @@ int LoadCdromFile(const char *filename, EXE_HEADER *head) {
 
 int CheckCdrom() {
        struct iso_directory_record *dir;
-       unsigned char time[4], *buf;
+       unsigned char time[4];
+       char *buf;
        unsigned char mdir[4096];
        char exename[256];
        int i, c;
@@ -327,9 +333,9 @@ int CheckCdrom() {
        if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") != -1) {
                READTRACK();
 
-               sscanf((char *)buf + 12, "BOOT = cdrom:\\%256s", exename);
+               sscanf(buf + 12, "BOOT = cdrom:\\%256s", exename);
                if (GetCdromFile(mdir, time, exename) == -1) {
-                       sscanf((char *)buf + 12, "BOOT = cdrom:%256s", exename);
+                       sscanf(buf + 12, "BOOT = cdrom:%256s", exename);
                        if (GetCdromFile(mdir, time, exename) == -1) {
                                char *ptr = strstr(buf + 12, "cdrom:");                 // possibly the executable is in some subdir
                                if (ptr != NULL) {
@@ -364,6 +370,9 @@ int CheckCdrom() {
                }
        }
 
+       if (CdromId[0] == '\0')
+               strcpy(CdromId, "SLUS99999");
+
        if (Config.PsxAuto) { // autodetect system (pal or ntsc)
                if (CdromId[2] == 'e' || CdromId[2] == 'E')
                        Config.PsxType = PSX_TYPE_PAL; // pal
@@ -406,6 +415,22 @@ static int PSXGetFileType(FILE *f) {
        return INVALID_EXE;
 }
 
+// temporary pandora workaround..
+// FIXME: remove
+size_t fread_to_ram(void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+       void *tmp;
+       size_t ret = 0;
+       
+       tmp = malloc(size * nmemb);
+       if (tmp) {
+               ret = fread(tmp, size, nmemb, stream);
+               memcpy(ptr, tmp, size * nmemb);
+               free(tmp);
+       }
+       return ret;
+}
+
 int Load(const char *ExePath) {
        FILE *tmpFile;
        EXE_HEADER tmpHead;
@@ -432,7 +457,7 @@ int Load(const char *ExePath) {
                                mem = PSXM(section_address);
                                if (mem != NULL) {
                                        fseek(tmpFile, 0x800, SEEK_SET);                
-                                       fread(mem, section_size, 1, tmpFile);
+                                       fread_to_ram(mem, section_size, 1, tmpFile);
                                        psxCpu->Clear(section_address, section_size / 4);
                                }
                                fclose(tmpFile);
@@ -458,7 +483,7 @@ int Load(const char *ExePath) {
 #endif
                                                        mem = PSXM(section_address);
                                                        if (mem != NULL) {
-                                                               fread(mem, section_size, 1, tmpFile);
+                                                               fread_to_ram(mem, section_size, 1, tmpFile);
                                                                psxCpu->Clear(section_address, section_size / 4);
                                                        }
                                                        break;
index 85ec174..588bc63 100644 (file)
@@ -299,7 +299,6 @@ static void ari64_reset()
        pending_exception = 1;
 }
 
-#ifdef __arm__
 // execute until predefined leave points
 // (HLE softcall exit and BIOS fastboot end)
 static void ari64_execute_until()
@@ -322,7 +321,6 @@ static void ari64_execute()
                evprintf("drc left @%08x\n", psxRegs.pc);
        }
 }
-#endif
 
 static void ari64_clear(u32 addr, u32 size)
 {
@@ -360,7 +358,7 @@ extern void intExecuteBlockT();
 R3000Acpu psxRec = {
        ari64_init,
        ari64_reset,
-#if defined(__arm__)
+#ifndef DRC_DISABLE
        ari64_execute,
        ari64_execute_until,
 #else
@@ -377,7 +375,7 @@ void do_insn_trace() {}
 void do_insn_cmp() {}
 #endif
 
-#if defined(__x86_64__) || defined(__i386__)
+#ifdef DRC_DISABLE
 unsigned int address;
 int pending_exception, stop;
 unsigned int next_interupt;
@@ -387,7 +385,7 @@ int new_dynarec_hacks;
 void *psxH_ptr;
 void *zeromem_ptr;
 u8 zero_mem[0x1000];
-void new_dynarec_init() {}
+void new_dynarec_init() { (void)ari64_execute; }
 void new_dyna_start() {}
 void new_dynarec_cleanup() {}
 void new_dynarec_clear_full() {}
index 8fc33b4..3e6d417 100644 (file)
@@ -152,6 +152,52 @@ u32 _psxRcntRcount( u32 index )
     return count;
 }
 
+static
+void _psxRcntWmode( u32 index, u32 value )
+{
+    rcnts[index].mode = value;
+
+    switch( index )
+    {
+        case 0:
+            if( value & Rc0PixelClock )
+            {
+                rcnts[index].rate = 5;
+            }
+            else
+            {
+                rcnts[index].rate = 1;
+            }
+        break;
+        case 1:
+            if( value & Rc1HSyncClock )
+            {
+                rcnts[index].rate = (PSXCLK / (FrameRate[Config.PsxType] * HSyncTotal[Config.PsxType]));
+            }
+            else
+            {
+                rcnts[index].rate = 1;
+            }
+        break;
+        case 2:
+            if( value & Rc2OneEighthClock )
+            {
+                rcnts[index].rate = 8;
+            }
+            else
+            {
+                rcnts[index].rate = 1;
+            }
+
+            // TODO: wcount must work.
+            if( value & Rc2Disable )
+            {
+                rcnts[index].rate = 0xffffffff;
+            }
+        break;
+    }
+}
+
 /******************************************************************************/
 
 static
@@ -357,50 +403,10 @@ void psxRcntWmode( u32 index, u32 value )
 {
     verboseLog( 1, "[RCNT %i] wmode: %x\n", index, value );
 
-    rcnts[index].mode = value;
-    rcnts[index].irqState = 0;
-
-    switch( index )
-    {
-        case 0:
-            if( value & Rc0PixelClock )
-            {
-                rcnts[index].rate = 5;
-            }
-            else
-            {
-                rcnts[index].rate = 1;
-            }
-        break;
-        case 1:
-            if( value & Rc1HSyncClock )
-            {
-                rcnts[index].rate = (PSXCLK / (FrameRate[Config.PsxType] * HSyncTotal[Config.PsxType]));
-            }
-            else
-            {
-                rcnts[index].rate = 1;
-            }
-        break;
-        case 2:
-            if( value & Rc2OneEighthClock )
-            {
-                rcnts[index].rate = 8;
-            }
-            else
-            {
-                rcnts[index].rate = 1;
-            }
-
-            // TODO: wcount must work.
-            if( value & Rc2Disable )
-            {
-                rcnts[index].rate = 0xffffffff;
-            }
-        break;
-    }
-
+    _psxRcntWmode( index, value );
     _psxRcntWcount( index, 0 );
+
+    rcnts[index].irqState = 0;
     psxRcntSet();
 }
 
@@ -497,6 +503,9 @@ void psxRcntInit()
 
 s32 psxRcntFreeze( gzFile f, s32 Mode )
 {
+    u32 count;
+    s32 i;
+
     gzfreeze( &rcnts, sizeof(rcnts) );
     gzfreeze( &hSyncCount, sizeof(hSyncCount) );
     gzfreeze( &spuSyncCount, sizeof(spuSyncCount) );
@@ -504,9 +513,19 @@ s32 psxRcntFreeze( gzFile f, s32 Mode )
     gzfreeze( &psxNextsCounter, sizeof(psxNextsCounter) );
 
     if (Mode == 0)
+    {
+        // don't trust things from a savestate
+        for( i = 0; i < CounterQuantity; ++i )
+        {
+            _psxRcntWmode( i, rcnts[i].mode );
+            count = (psxRegs.cycle - rcnts[i].cycleStart) / rcnts[i].rate;
+            _psxRcntWcount( i, count );
+        }
         hsync_steps = (psxRegs.cycle - rcnts[3].cycleStart) / rcnts[3].target;
+        psxRcntSet();
 
-    base_cycle = 0;
+        base_cycle = 0;
+    }
 
     return 0;
 }
index 1cabd53..ddcd05b 100644 (file)
@@ -60,6 +60,16 @@ u8 **psxMemRLUT = NULL;
 0xbfc0_0000-0xbfc7_ffff                BIOS Mirror (512K) Uncached
 */
 
+#if 1
+void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed);
+void  plat_munmap(void *ptr, size_t size);
+#else
+#define plat_mmap(addr, size, need_exec, is_fixed) \
+       mmap((void *)addr, size, PROT_WRITE | PROT_READ, \
+       MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0)
+#define plat_munmap munmap
+#endif
+
 int psxMemInit() {
        int i;
 
@@ -68,8 +78,7 @@ int psxMemInit() {
        memset(psxMemRLUT, 0, 0x10000 * sizeof(void *));
        memset(psxMemWLUT, 0, 0x10000 * sizeof(void *));
 
-       psxM = mmap((void *)0x80000000, 0x00210000,
-               PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+       psxM = plat_mmap(0x80000000, 0x00210000, 0, 1);
 #ifndef RAM_FIXED
        if (psxM == MAP_FAILED)
                psxM = mmap((void *)0x70000000, 0x00210000,
@@ -144,7 +153,7 @@ void psxMemReset() {
 }
 
 void psxMemShutdown() {
-       munmap(psxM, 0x00210000);
+       plat_munmap(psxM, 0x00210000);
        munmap(psxH, 0x1f800000);
        munmap(psxR, 0x80000);
 
index 76f42bc..13aaa59 100644 (file)
@@ -163,11 +163,21 @@ enum {
        PSXINT_COUNT
 };
 
+typedef struct psxCP2Regs {
+       psxCP2Data CP2D;        /* Cop2 data registers */
+       psxCP2Ctrl CP2C;        /* Cop2 control registers */
+} psxCP2Regs;
+
 typedef struct {
        psxGPRRegs GPR;         /* General Purpose Registers */
        psxCP0Regs CP0;         /* Coprocessor0 Registers */
-       psxCP2Data CP2D;        /* Cop2 data registers */
-       psxCP2Ctrl CP2C;        /* Cop2 control registers */
+       union {
+               struct {
+                       psxCP2Data CP2D;        /* Cop2 data registers */
+                       psxCP2Ctrl CP2C;        /* Cop2 control registers */
+               };
+               psxCP2Regs CP2;
+       };
     u32 pc;                            /* Program counter */
     u32 code;                  /* The instruction */
        u32 cycle;
index 4458aa7..43e3e15 100644 (file)
@@ -4,12 +4,12 @@
 #include <stdint.h>
 #include <unistd.h>
 #include <hildon/hildon.h>
-#include "plugin_lib.h"
 
+#include "plugin_lib.h"
 #include "main.h"
 #include "plat.h"
 #include "../libpcsxcore/psemu_plugin_defs.h"
-#include "common/readpng.h"
+#include "libpicofe/readpng.h"
 #include "maemo_common.h"
 
 #define X_RES           800
index 2da693d..24db87a 100644 (file)
 #include "plugin_lib.h"
 #include "../libpcsxcore/misc.h"
 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
-#include "../plugins/dfinput/main.h"
+#include "../plugins/dfinput/externals.h"
 #include "maemo_common.h"
 
 int g_opts = OPT_SHOWFPS;
 int g_maemo_opts;
+int g_scaler, soft_filter;
+int g_menuscreen_w, g_menuscreen_h;
+
 char file_name[MAXPATHLEN];
 
 enum sched_action emu_action;
@@ -53,7 +56,10 @@ int main(int argc, char **argv)
        strcpy(Config.PluginsDir, "/opt/maemo/usr/games/plugins");
        snprintf(Config.PatchesDir, sizeof(Config.PatchesDir), "/opt/maemo/usr/games" PATCHES_DIR);
        Config.PsxAuto = 1;
-       
+
+       g_menuscreen_w = 800;
+       g_menuscreen_h = 480;
+
        pl_init();
 
        emu_core_init();
@@ -126,7 +132,7 @@ int main(int argc, char **argv)
                                printf(_("Could not load CD-ROM!\n"));
                                return -1;
                        }
-                       emu_on_new_cd();
+                       emu_on_new_cd(0);
                        ready_to_go = 1;
                }
        }
index cf55073..0ec14db 100644 (file)
@@ -48,8 +48,8 @@ extern long CDR__getStatus(struct CdrStat *stat);
 
 struct CdrStat
 {
-       unsigned long Type;
-       unsigned long Status;
+       unsigned int Type;
+       unsigned int Status;
        unsigned char Time[3]; // current playing time
 };
 
diff --git a/plugins/dfinput/externals.h b/plugins/dfinput/externals.h
new file mode 100644 (file)
index 0000000..5419977
--- /dev/null
@@ -0,0 +1,14 @@
+
+void dfinput_activate(void);
+
+/* get gunstate from emu frontend,
+ * xn, yn - layer position normalized to 0..1023 */
+#define GUNIN_TRIGGER  (1<<0)
+#define GUNIN_BTNA     (1<<1)
+#define GUNIN_BTNB     (1<<2)
+#define GUNIN_TRIGGER2 (1<<3)  /* offscreen trigger */
+extern void pl_update_gun(int *xn, int *yn, int *xres, int *yres, int *in);
+
+/* vibration trigger to frontend */
+extern int in_enable_vibration;
+extern void plat_trigger_vibrate(int is_strong);
index b4f103c..981a757 100644 (file)
@@ -29,17 +29,17 @@ unsigned char PADpoll_guncon(unsigned char value)
 
 unsigned char PADstartPoll_guncon(int pad)
 {
-       int x, xn = 0, y = 0, in = 0, xres = 256;
+       int x, y, xn = 0, yn = 0, in = 0, xres = 256, yres = 240;
        CurByte = 0;
 
        buf[2] = buf[3] = 0xff;
-       pl_update_gun(&xn, &xres, &y, &in);
+       pl_update_gun(&xn, &yn, &xres, &yres, &in);
 
        // while y = const + line counter, what is x?
        // for 256 mode, hw dumped offsets x, y: 0x5a, 0x20
        //x = 0x5a + (356 * xn >> 10);
        x = 0x5a - (xres - 256) / 3 + (((xres - 256) / 3 + 356) * xn >> 10);
-       y = 0x20 + y;
+       y = 0x20 + (yres * yn >> 10);
 
        if (in & GUNIN_TRIGGER)
                buf[3] &= ~0x20;
index 8e2d5ae..15d05e7 100644 (file)
@@ -1,4 +1,5 @@
 #include "../../libpcsxcore/psemu_plugin_defs.h"
+#include "externals.h"
 
 extern unsigned char CurPad, CurByte, CurCmd, CmdLen;
 
@@ -12,19 +13,6 @@ unsigned char PADpoll_guncon(unsigned char value);
 unsigned char PADstartPoll_guncon(int pad);
 void guncon_init(void);
 
-void dfinput_activate(void);
-
 /* get button state and pad type from main emu */
 extern long (*PAD1_readPort1)(PadDataS *pad);
 extern long (*PAD2_readPort2)(PadDataS *pad);
-
-/* get gunstate from emu frontend, x range 0-1023 */
-#define GUNIN_TRIGGER  (1<<0)
-#define GUNIN_BTNA     (1<<1)
-#define GUNIN_BTNB     (1<<2)
-#define GUNIN_TRIGGER2 (1<<3)  /* offscreen trigger */
-extern void pl_update_gun(int *xn, int *xres, int *y, int *in);
-
-/* vibration trigger to frontend */
-extern int in_enable_vibration;
-extern void plat_trigger_vibrate(int is_strong);
index e4873df..79f593c 100644 (file)
@@ -46,6 +46,10 @@ void InitADSR(void)                                    // INIT ADSR
 \r
   RateTableAdd[lcv] = ((7 - (lcv&3)) << 16) / denom;\r
   RateTableSub[lcv] = ((-8 + (lcv&3)) << 16) / denom;\r
+\r
+  // XXX: this is wrong, we need more bits..\r
+  if (RateTableAdd[lcv] == 0)\r
+    RateTableAdd[lcv] = 1;\r
  }\r
 }\r
 \r
@@ -67,12 +71,13 @@ static void MixADSR(int ch, int ns, int ns_to)         // MIX ADSR
  if (s_chan[ch].bStop)                                 // should be stopped:\r
  {                                                     // do release\r
    val = RateTableSub[s_chan[ch].ADSRX.ReleaseRate * 4];\r
+\r
    if (s_chan[ch].ADSRX.ReleaseModeExp)\r
    {\r
      for (; ns < ns_to; ns++)\r
      {\r
        EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
-       if (EnvelopeVol < 0)\r
+       if (EnvelopeVol <= 0)\r
          break;\r
 \r
        ChanBuf[ns] *= EnvelopeVol >> 21;\r
@@ -84,7 +89,7 @@ static void MixADSR(int ch, int ns, int ns_to)         // MIX ADSR
      for (; ns < ns_to; ns++)\r
      {\r
        EnvelopeVol += val;\r
-       if (EnvelopeVol < 0)\r
+       if (EnvelopeVol <= 0)\r
          break;\r
 \r
        ChanBuf[ns] *= EnvelopeVol >> 21;\r
@@ -92,7 +97,7 @@ static void MixADSR(int ch, int ns, int ns_to)         // MIX ADSR
      }\r
    }\r
 \r
-   if (EnvelopeVol < 0)\r
+   if (EnvelopeVol <= 0)\r
      goto stop;\r
 \r
    goto done;\r
index 58900cc..1c02d37 100644 (file)
 static snd_pcm_t *handle = NULL;
 static snd_pcm_uframes_t buffer_size;
 
+static void alsa_finish(void);
+
 // SETUP SOUND
 static int alsa_init(void)
 {
  snd_pcm_hw_params_t *hwparams;
  snd_pcm_status_t *status;
+ snd_ctl_t *ctl_handle = NULL;
+ snd_ctl_card_info_t *info;
  unsigned int pspeed;
  int pchannels;
  int format;
  unsigned int buffer_time = 100000;
  unsigned int period_time = buffer_time / 4;
+ const char *alsa_name = "default";
+ const char *name;
+ int retval = -1;
  int err;
 
+ name = getenv("ALSA_NAME");
+ if (name != NULL)
+  alsa_name = name;
+
+ snd_ctl_card_info_alloca(&info);
+ if ((err = snd_ctl_open(&ctl_handle, alsa_name, 0)) < 0) {
+  printf("control open: %s\n", snd_strerror(err));
+ }
+ else if ((err = snd_ctl_card_info(ctl_handle, info)) < 0) {
+  printf("control info: %s\n", snd_strerror(err));
+  snd_ctl_card_info_clear(info);
+ }
+ if (ctl_handle != NULL)
+  snd_ctl_close(ctl_handle);
+
+ name = snd_ctl_card_info_get_name(info);
+ if (name != NULL) {
+  if (strcasecmp(name, "PulseAudio") == 0) {
+    // PulseAudio's ALSA emulation is known to be broken..
+    printf("alsa: refusing to run under PulseAudio's emulation\n");
+    return -1;
+  }
+  else {
+    printf("alsa: using '%s', set ALSA_NAME to change\n", name);
+  }
+ }
+
  pchannels=2;
 
  pspeed = 44100;
  format = SND_PCM_FORMAT_S16;
 
- if ((err = snd_pcm_open(&handle, "default"
+ if ((err = snd_pcm_open(&handle, alsa_name
                       SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0)
   {
    printf("Audio open error: %s\n", snd_strerror(err));
@@ -51,7 +85,7 @@ static int alsa_init(void)
  if((err = snd_pcm_nonblock(handle, 0))<0)
   {
    printf("Can't set blocking moded: %s\n", snd_strerror(err));
-   return -1;
+   goto out;
   }
 
  snd_pcm_hw_params_alloca(&hwparams);
@@ -59,60 +93,65 @@ static int alsa_init(void)
  if((err=snd_pcm_hw_params_any(handle, hwparams))<0)
   {
    printf("Broken configuration for this PCM: %s\n", snd_strerror(err));
-   return -1;
+   goto out;
   }
 
  if((err=snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED))<0)
   {
    printf("Access type not available: %s\n", snd_strerror(err));
-   return -1;
+   goto out;
   }
 
  if((err=snd_pcm_hw_params_set_format(handle, hwparams, format))<0)
   {
    printf("Sample format not available: %s\n", snd_strerror(err));
-   return -1;
+   goto out;
   }
 
  if((err=snd_pcm_hw_params_set_channels(handle, hwparams, pchannels))<0)
   {
    printf("Channels count not available: %s\n", snd_strerror(err));
-   return -1;
+   goto out;
   }
 
  if((err=snd_pcm_hw_params_set_rate_near(handle, hwparams, &pspeed, 0))<0)
   {
    printf("Rate not available: %s\n", snd_strerror(err));
-   return -1;
+   goto out;
   }
 
  if((err=snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0))<0)
   {
    printf("Buffer time error: %s\n", snd_strerror(err));
-   return -1;
+   goto out;
   }
 
  if((err=snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0))<0)
   {
    printf("Period time error: %s\n", snd_strerror(err));
-   return -1;
+   goto out;
   }
 
  if((err=snd_pcm_hw_params(handle, hwparams))<0)
   {
    printf("Unable to install hw params: %s\n", snd_strerror(err));
-   return -1;
+   goto out;
   }
 
  snd_pcm_status_alloca(&status);
  if((err=snd_pcm_status(handle, status))<0)
   {
    printf("Unable to get status: %s\n", snd_strerror(err));
-   return -1;
+   goto out;
   }
 
  buffer_size = snd_pcm_status_get_avail(status);
- return 0;
+ retval = 0;
+
+out:
+ if (retval != 0)
+  alsa_finish();
+ return retval;
 }
 
 // REMOVE SOUND
index 28dab57..2f3028e 100644 (file)
 ///////////////////////////////////////////////////////////\r
 \r
 // ADSR INFOS PER CHANNEL\r
-typedef struct\r
-{\r
- int            AttackModeExp;\r
- long           AttackTime;\r
- long           DecayTime;\r
- long           SustainLevel;\r
- int            SustainModeExp;\r
- long           SustainModeDec;\r
- long           SustainTime;\r
- int            ReleaseModeExp;\r
- unsigned long  ReleaseVal;\r
- long           ReleaseTime;\r
- long           ReleaseStartTime; \r
- long           ReleaseVol; \r
- long           lTime;\r
- long           lVolume;\r
-} ADSRInfo;\r
-\r
 typedef struct\r
 {\r
  unsigned char  State:2;\r
@@ -215,11 +197,10 @@ extern int decode_pos;
 extern SPUCHAN s_chan[];\r
 extern REVERBInfo rvb;\r
 \r
-extern unsigned long dwNoiseVal;\r
 extern unsigned short spuCtrl;\r
 extern unsigned short spuStat;\r
 extern unsigned short spuIrq;\r
-extern unsigned long  spuAddr;\r
+extern unsigned int   spuAddr;\r
 extern int      bSpuInit;\r
 extern unsigned int dwNewChannel;\r
 extern unsigned int dwChannelOn;\r
index ec097c5..0601bf5 100644 (file)
 // freeze structs\r
 ////////////////////////////////////////////////////////////////////////\r
 \r
+typedef struct\r
+{\r
+ int            AttackModeExp;\r
+ int            AttackTime;\r
+ int            DecayTime;\r
+ int            SustainLevel;\r
+ int            SustainModeExp;\r
+ int            SustainModeDec;\r
+ int            SustainTime;\r
+ int            ReleaseModeExp;\r
+ unsigned int   ReleaseVal;\r
+ int            ReleaseTime;\r
+ int            ReleaseStartTime; \r
+ int            ReleaseVol; \r
+ int            lTime;\r
+ int            lVolume;\r
+} ADSRInfo;\r
+\r
 typedef struct\r
 {\r
  int            State;\r
@@ -40,9 +58,9 @@ typedef struct
  int            ReleaseModeExp;\r
  int            ReleaseRate;\r
  int            EnvelopeVol;\r
long           lVolume;\r
long           lDummy1;\r
long           lDummy2;\r
int            lVolume;\r
int            lDummy1;\r
int            lDummy2;\r
 } ADSRInfoEx_orig;\r
 \r
 typedef struct\r
@@ -58,9 +76,9 @@ typedef struct
  int               SB[32+32];                          // Pete added another 32 dwords in 1.6 ... prevents overflow issues with gaussian/cubic interpolation (thanx xodnizel!), and can be used for even better interpolations, eh? :)\r
  int               sval;\r
 \r
unsigned char *   pStart;                             // start ptr into sound mem\r
unsigned char *   pCurr;                              // current pos in sound mem\r
unsigned char *   pLoop;                              // loop ptr in sound mem\r
int               iStart;                             // start ptr into sound mem\r
int               iCurr;                              // current pos in sound mem\r
int               iLoop;                              // loop ptr in sound mem\r
 \r
  int               bOn;                                // is channel active (sample playing?)\r
  int               bStop;                              // is channel stopped (sample _can_ still be playing, ADSR Release phase)\r
@@ -128,9 +146,9 @@ static void save_channel(SPUCHAN_orig *d, const SPUCHAN *s, int ch)
  d->spos = s->spos;\r
  d->sinc = s->sinc;\r
  memcpy(d->SB, s->SB, sizeof(d->SB));\r
- d->pStart = (unsigned char *)((regAreaGet(ch,6)&~1)<<3);\r
- d->pCurr = s->pCurr;\r
- d->pLoop = s->pLoop;\r
+ d->iStart = (regAreaGet(ch,6)&~1)<<3;\r
+ d->iCurr = 0; // set by the caller\r
+ d->iLoop = 0; // set by the caller\r
  d->bOn = !!(dwChannelOn & (1<<ch));\r
  d->bStop = s->bStop;\r
  d->bReverb = s->bReverb;\r
@@ -168,9 +186,8 @@ static void load_channel(SPUCHAN *d, const SPUCHAN_orig *s, int ch)
  d->spos = s->spos;\r
  d->sinc = s->sinc;\r
  memcpy(d->SB, s->SB, sizeof(d->SB));\r
- d->pCurr = (void *)((long)s->pCurr & 0x7fff0);\r
- d->pLoop = (void *)((long)s->pLoop & 0x7fff0);\r
- if (s->bOn) dwChannelOn |= 1<<ch;\r
+ d->pCurr = (void *)((long)s->iCurr & 0x7fff0);\r
+ d->pLoop = (void *)((long)s->iLoop & 0x7fff0);\r
  d->bStop = s->bStop;\r
  d->bReverb = s->bReverb;\r
  d->iLeftVolume = s->iLeftVolume;\r
@@ -191,6 +208,8 @@ static void load_channel(SPUCHAN *d, const SPUCHAN_orig *s, int ch)
  d->ADSRX.ReleaseModeExp = s->ADSRX.ReleaseModeExp;\r
  d->ADSRX.ReleaseRate = s->ADSRX.ReleaseRate;\r
  d->ADSRX.EnvelopeVol = s->ADSRX.EnvelopeVol;\r
+ if (s->bOn) dwChannelOn |= 1<<ch;\r
+ else d->ADSRX.EnvelopeVol = 0;\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
@@ -234,14 +253,11 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode,SPUFreeze_t * pF)
 \r
    for(i=0;i<MAXCHAN;i++)\r
     {\r
-     if(!(s_chan[i].prevflags&2))\r
-      dwChannelOn&=~(1<<i);\r
-\r
      save_channel(&pFO->s_chan[i],&s_chan[i],i);\r
-     if(pFO->s_chan[i].pCurr)\r
-      pFO->s_chan[i].pCurr-=(unsigned long)spuMemC;\r
-     if(pFO->s_chan[i].pLoop)\r
-      pFO->s_chan[i].pLoop-=(unsigned long)spuMemC;\r
+     if(s_chan[i].pCurr)\r
+      pFO->s_chan[i].iCurr=s_chan[i].pCurr-spuMemC;\r
+     if(s_chan[i].pLoop)\r
+      pFO->s_chan[i].iLoop=s_chan[i].pLoop-spuMemC;\r
     }\r
 \r
    return 1;\r
index 84c6260..402d273 100644 (file)
@@ -8,7 +8,7 @@
 \r
 typedef struct\r
 {\r
-       long    y0, y1;\r
+       int     y0, y1;\r
 } ADPCM_Decode_t;\r
 \r
 typedef struct\r
@@ -21,7 +21,7 @@ typedef struct
        short                   pcm[16384];\r
 } xa_decode_t;\r
 \r
-long xa_decode_sector( xa_decode_t *xdp,\r
+int xa_decode_sector( xa_decode_t *xdp,\r
                                           unsigned char *sectorp,\r
                                           int is_first_sector );\r
 \r
index d40344f..8993bb3 100644 (file)
@@ -32,9 +32,9 @@
 
 #undef CALLBACK
 #define CALLBACK
-#define DWORD unsigned long
+#define DWORD unsigned int
 #define LOWORD(l)           ((unsigned short)(l)) 
-#define HIWORD(l)           ((unsigned short)(((unsigned long)(l) >> 16) & 0xFFFF)) 
+#define HIWORD(l)           ((unsigned short)(((unsigned int)(l) >> 16) & 0xFFFF)) 
 
 #ifndef INLINE
 #define INLINE static inline
index a5ca5f3..250cc49 100644 (file)
@@ -12,7 +12,7 @@ ifeq "$(ARCH)" "arm"
 SRC_STANDALONE += draw_pl.c
 else
 SRC_STANDALONE += draw.c
-LDLIBS_STANDALONE += -lX11 -lXv
+LDLIBS_STANDALONE += -lX11 -lXv -lXext
 endif
 
 BIN_STANDLALONE = gpuPEOPS.so
index dffd52b..ed07e75 100644 (file)
@@ -19,56 +19,26 @@ BOOL           bCheckMask = FALSE;
 unsigned short sSetMask;
 unsigned long  lSetMask;
 
-static void blit(void *vout_buf)
+static void blit(void)
 {
  int px = PSXDisplay.DisplayPosition.x & ~1; // XXX: align needed by bgr*_to_...
  int py = PSXDisplay.DisplayPosition.y;
  int w = PreviousPSXDisplay.Range.x1;
  int h = PreviousPSXDisplay.DisplayMode.y;
- int pitch = PreviousPSXDisplay.DisplayMode.x;
  unsigned short *srcs = psxVuw + py * 1024 + px;
- unsigned char *dest = vout_buf;
 
  if (w <= 0)
    return;
 
- pitch *= (PSXDisplay.RGB24 && !rcbs->only_16bpp) ? 3 : 2;
-
  // account for centering
  h -= PreviousPSXDisplay.Range.y0;
- dest += PreviousPSXDisplay.Range.y0 / 2 * pitch;
- dest += (PreviousPSXDisplay.Range.x0 & ~3) * 2; // must align here too..
-
- if (PSXDisplay.RGB24)
- {
-   if (!rcbs->only_16bpp)
-   {
-     for (; h-- > 0; dest += pitch, srcs += 1024)
-     {
-       bgr888_to_rgb888(dest, srcs, w * 3);
-     }
-   }
-   else
-   {
-     for (; h-- > 0; dest += pitch, srcs += 1024)
-     {
-       bgr888_to_rgb565(dest, srcs, w * 3);
-     }
-   }
- }
- else
- {
-   for (; h-- > 0; dest += pitch, srcs += 1024)
-   {
-     bgr555_to_rgb565(dest, srcs, w * 2);
-   }
- }
+
+ rcbs->pl_vout_flip(srcs, 1024, PSXDisplay.RGB24, w, h);
 }
 
 void DoBufferSwap(void)
 {
  static int fbw, fbh, fb24bpp;
- static void *vout_buf;
 
  if (PreviousPSXDisplay.DisplayMode.x == 0 || PreviousPSXDisplay.DisplayMode.y == 0)
   return;
@@ -80,17 +50,12 @@ void DoBufferSwap(void)
   fbw = PreviousPSXDisplay.DisplayMode.x;
   fbh = PreviousPSXDisplay.DisplayMode.y;
   fb24bpp = PSXDisplay.RGB24;
-  vout_buf = rcbs->pl_vout_set_mode(fbw, fbh, fb24bpp ? 24 : 16);
+  rcbs->pl_vout_set_mode(fbw, fbh, fbw, fbh, fb24bpp ? 24 : 16);
  }
 
  pcnt_start(PCNT_BLIT);
- if (rcbs->pl_vout_raw_flip != NULL)
-  rcbs->pl_vout_raw_flip(PSXDisplay.DisplayPosition.x, PSXDisplay.DisplayPosition.y);
- else
-  blit(vout_buf);
+ blit();
  pcnt_end(PCNT_BLIT);
-
- vout_buf = rcbs->pl_vout_flip();
 }
 
 void DoClearScreenBuffer(void)
index 9fa08fe..3d20dfa 100644 (file)
@@ -1143,6 +1143,8 @@ void GPUrearmedCallbacks(const struct rearmed_cbs *cbs)
  dwFrameRateTicks = cbs->gpu_peops.dwFrameRateTicks;
  if (cbs->pl_vout_set_raw_vram)
   cbs->pl_vout_set_raw_vram(psxVub);
+ if (cbs->pl_set_gpu_caps)
+  cbs->pl_set_gpu_caps(0);
 
  skip_advice = &cbs->fskip_advice;
  fps_skip = 100.0f;
index 12aa0a3..d98520c 100644 (file)
@@ -265,9 +265,9 @@ long           lLowerpart;
 
 /////////////////////////////////////////////////////////////////////////////
 
-int renderer_init(void)
+static void set_vram(void *vram)
 {
- psxVub=(void *)gpu.vram;
+ psxVub=vram;
 
  psxVsb=(signed char *)psxVub;                         // different ways of accessing PSX VRAM
  psxVsw=(signed short *)psxVub;
@@ -276,6 +276,11 @@ int renderer_init(void)
  psxVul=(uint32_t *)psxVub;
 
  psxVuw_eom=psxVuw+1024*512;                           // pre-calc of end of vram
+}
+
+int renderer_init(void)
+{
+ set_vram(gpu.vram);
 
  PSXDisplay.RGB24        = FALSE;                      // init some stuff
  PSXDisplay.Interlaced   = FALSE;
@@ -294,6 +299,14 @@ int renderer_init(void)
  return 0;
 }
 
+void renderer_finish(void)
+{
+}
+
+void renderer_notify_res_change(void)
+{
+}
+
 extern const unsigned char cmd_lengths[256];
 
 int do_cmd_list(unsigned int *list, int list_len, int *last_cmd)
@@ -408,4 +421,7 @@ void renderer_set_config(const struct rearmed_cbs *cbs)
 {
  iUseDither = cbs->gpu_peops.iUseDither;
  dwActFixes = cbs->gpu_peops.dwActFixes;
+ if (cbs->pl_set_gpu_caps)
+  cbs->pl_set_gpu_caps(0);
+ set_vram(gpu.vram);
 }
index c25ad8b..068dc41 100644 (file)
@@ -479,10 +479,15 @@ switch((gdata>>24)&0xff)
 
 static int is_opened;
 
-int renderer_init(void)
+static void set_vram(void *vram)
 {
- psxVub=(void *)gpu.vram;
+ psxVub=vram;
  psxVuw=(unsigned short *)psxVub;
+}
+
+int renderer_init(void)
+{
+ set_vram(gpu.vram);
 
  PSXDisplay.RGB24        = FALSE;                      // init some stuff
  PSXDisplay.Interlaced   = FALSE;
@@ -500,6 +505,14 @@ int renderer_init(void)
  return 0;
 }
 
+void renderer_finish(void)
+{
+}
+
+void renderer_notify_res_change(void)
+{
+}
+
 extern const unsigned char cmd_lengths[256];
 
 // XXX: mostly dupe code from soft peops
@@ -702,6 +715,10 @@ void renderer_set_config(const struct rearmed_cbs *cbs_)
  bUseFastMdec = cbs->gpu_peopsgl.bUseFastMdec;
  iTexGarbageCollection = cbs->gpu_peopsgl.iTexGarbageCollection;
  iVRamSize = cbs->gpu_peopsgl.iVRamSize;
+ if (cbs->pl_set_gpu_caps)
+  cbs->pl_set_gpu_caps(GPU_CAP_OWNS_DISPLAY);
+
+ set_vram(gpu.vram);
 }
 
 void SetAspectRatio(void)
index 8a7342b..08bf0ee 100644 (file)
@@ -1,4 +1,4 @@
-CFLAGS += -ggdb -Wall -O2
+CFLAGS += -ggdb -Wall -O2 -DNDEBUG
 
 include ../../config.mak
 
index f299f79..d5cf3e9 100644 (file)
@@ -18,5 +18,7 @@ typedef unsigned long long int u64;
 #include "vector_ops.h"
 #include "psx_gpu.h"
 
+#define unlikely(x) __builtin_expect((x), 0)
+
 #endif
 
index 68996c1..396d274 100644 (file)
@@ -47,7 +47,8 @@ u32 zero_block_spans = 0;
 u32 texture_cache_loads = 0;
 u32 false_modulated_blocks = 0;
 
-u32 reciprocal_table[512];
+/* double size for enhancement */
+u32 reciprocal_table[512 * 2];
 
 
 typedef s32 fixed_type;
@@ -453,7 +454,7 @@ void setup_blocks_shaded_untextured_undithered_unswizzled_indirect(
 
 void flush_render_block_buffer(psx_gpu_struct *psx_gpu)
 {
-  if((psx_gpu->interlace_mode & RENDER_INTERLACE_ENABLED) &&
+  if((psx_gpu->render_mode & RENDER_INTERLACE_ENABLED) &&
    (psx_gpu->primitive_type == PRIMITIVE_TYPE_SPRITE))
   {
     u32 num_blocks_dest = 0;
@@ -463,7 +464,7 @@ void flush_render_block_buffer(psx_gpu_struct *psx_gpu)
     u16 *vram_ptr = psx_gpu->vram_ptr;
     u32 i;
 
-    if(psx_gpu->interlace_mode & RENDER_INTERLACE_ODD)
+    if(psx_gpu->render_mode & RENDER_INTERLACE_ODD)
     {
       for(i = 0; i < psx_gpu->num_blocks; i++)
       {
@@ -566,7 +567,7 @@ void compute_all_gradients(psx_gpu_struct *psx_gpu, vertex_struct *a,
 
   vec_4x32u uvrg_base;
   vec_4x32u b_base;
-  vec_4x32u const_0x8000;
+  vec_4x32u uvrgb_phase;
 
   vec_4x16s d0_a_d3_c, d0_b, d0_c;
   vec_4x16s d1_a, d1_b, d1_c_d2_a;
@@ -595,12 +596,12 @@ void compute_all_gradients(psx_gpu_struct *psx_gpu, vertex_struct *a,
   setup_gradient_calculation_input(1, b);
   setup_gradient_calculation_input(2, c);
 
-  dup_4x32b(const_0x8000, 0x8000);
+  dup_4x32b(uvrgb_phase, psx_gpu->uvrgb_phase);
   shl_long_4x16b(uvrg_base, x0_a_y0_c, 16);
   shl_long_4x16b(b_base, x0_b, 16);
 
-  add_4x32b(uvrg_base, uvrg_base, const_0x8000);
-  add_4x32b(b_base, b_base, const_0x8000);
+  add_4x32b(uvrg_base, uvrg_base, uvrgb_phase);
+  add_4x32b(b_base, b_base, uvrgb_phase);
 
   // Can probably pair these, but it'll require careful register allocation
   sub_4x16b(d0_a_d3_c, x1_a_y1_c, x0_a_y0_c);
@@ -766,6 +767,26 @@ void compute_all_gradients(psx_gpu_struct *psx_gpu, vertex_struct *a,
     printf("mismatch on %s %s: %x vs %x\n", #_a, #_b, _a, _b)                  \
 
 
+#ifndef NDEBUG
+#define setup_spans_debug_check(span_edge_data_element)                        \
+{                                                                              \
+  u32 _num_spans = &span_edge_data_element - psx_gpu->span_edge_data;          \
+  if (_num_spans > MAX_SPANS)                                                  \
+    *(int *)0 = 1;                                                             \
+  if (_num_spans < psx_gpu->num_spans)                                         \
+  {                                                                            \
+    if(span_edge_data_element.num_blocks > MAX_BLOCKS_PER_ROW)                 \
+      *(int *)0 = 1;                                                           \
+    if(span_edge_data_element.y > 2048)                                        \
+      *(int *)0 = 1;                                                           \
+  }                                                                            \
+}                                                                              \
+
+#else
+#define setup_spans_debug_check(span_edge_data_element)                        \
+
+#endif
+
 #define setup_spans_prologue_alternate_yes()                                   \
   vec_2x64s alternate_x;                                                       \
   vec_2x64s alternate_dx_dy;                                                   \
@@ -854,7 +875,7 @@ void compute_all_gradients(psx_gpu_struct *psx_gpu, vertex_struct *a,
                                                                                \
   dup_2x32b(edge_shifts, edge_shift);                                          \
   sub_2x32b(heights_b, heights, c_0x01);                                       \
-  shr_2x32b(height_reciprocals, edge_shifts, 12);                              \
+  shr_2x32b(height_reciprocals, edge_shifts, 10);                              \
                                                                                \
   mla_2x32b(heights_b, x_starts, heights);                                     \
   bic_immediate_4x16b(vector_cast(vec_4x16u, edge_shifts), 0xE0);              \
@@ -883,8 +904,8 @@ void compute_all_gradients(psx_gpu_struct *psx_gpu, vertex_struct *a,
   sub_2x32b(widths, x_ends, x_starts);                                         \
   width_alt = x_c - start_c;                                                   \
                                                                                \
-  shr_2x32b(height_reciprocals, edge_shifts, 12);                              \
-  height_reciprocal_alt = edge_shift_alt >> 12;                                \
+  shr_2x32b(height_reciprocals, edge_shifts, 10);                              \
+  height_reciprocal_alt = edge_shift_alt >> 10;                                \
                                                                                \
   bic_immediate_4x16b(vector_cast(vec_4x16u, edge_shifts), 0xE0);              \
   edge_shift_alt &= 0x1F;                                                      \
@@ -1069,6 +1090,7 @@ void compute_all_gradients(psx_gpu_struct *psx_gpu, vertex_struct *a,
     span_edge_data[i].num_blocks = left_right_x_16.high.e[i];                  \
     span_edge_data[i].right_mask = span_shift.e[i];                            \
     span_edge_data[i].y = y_x4.e[i];                                           \
+    setup_spans_debug_check(span_edge_data[i]);                                \
   }                                                                            \
                                                                                \
   span_edge_data += 4;                                                         \
@@ -1406,12 +1428,16 @@ void setup_spans_up_down(psx_gpu_struct *psx_gpu, vertex_struct *v_a,
     y_x4.e[3] = y_a + 3;
     setup_spans_adjust_edges_alternate_no(index_left, index_right);
 
+    // FIXME: overflow corner case
+    if(psx_gpu->num_spans + height_minor_b == MAX_SPANS)
+      height_minor_b &= ~3;
+
     psx_gpu->num_spans += height_minor_b;
-    do
+    while(height_minor_b > 0)
     {
       setup_spans_set_x4(none, down, no);
       height_minor_b -= 4;
-    } while(height_minor_b > 0);
+    }
   }
 
   left_split_triangles++;
@@ -1872,7 +1898,7 @@ void setup_blocks_##shading##_##texturing##_##dithering##_##sw##_##target(     \
     if(span_num_blocks)                                                        \
     {                                                                          \
       y = span_edge_data->y;                                                   \
-      fb_ptr = psx_gpu->vram_ptr + span_edge_data->left_x + (y * 1024);        \
+      fb_ptr = psx_gpu->vram_out_ptr + span_edge_data->left_x + (y * 1024);    \
                                                                                \
       setup_blocks_span_initialize_##shading##_##texturing();                  \
       setup_blocks_span_initialize_##dithering(texturing);                     \
@@ -2905,8 +2931,8 @@ char *render_block_flag_strings[] =
    (triangle_y_direction_##direction_c << 4) |                                 \
    (triangle_winding_##winding << 6))                                          \
 
-void render_triangle(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
u32 flags)
+static int prepare_triangle(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
vertex_struct *vertexes_out[3])
 {
   s32 y_top, y_bottom;
   s32 triangle_area;
@@ -2927,7 +2953,7 @@ void render_triangle(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
 #ifdef PROFILE
     trivial_rejects++;
 #endif
-    return;
+    return 0;
   }
 
   if(b->y < a->y)
@@ -2949,7 +2975,7 @@ void render_triangle(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
 #ifdef PROFILE
     trivial_rejects++;
 #endif
-    return;
+    return 0;
   }
 
   if(triangle_area < 0)
@@ -2975,7 +3001,7 @@ void render_triangle(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
 #ifdef PROFILE
     trivial_rejects++;
 #endif
-    return;
+    return 0;
   }
 
   if(invalidate_texture_cache_region_viewport(psx_gpu, a->x, y_top, c->x,
@@ -2984,13 +3010,28 @@ void render_triangle(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
 #ifdef PROFILE
     trivial_rejects++;
 #endif
-    return;
+    return 0;
   }
 
-  psx_gpu->num_spans = 0;
   psx_gpu->triangle_area = triangle_area;
   psx_gpu->triangle_winding = triangle_winding;
 
+  vertexes_out[0] = a;
+  vertexes_out[1] = b;
+  vertexes_out[2] = c;
+
+  return 1;
+}
+
+static void render_triangle_p(psx_gpu_struct *psx_gpu,
+ vertex_struct *vertex_ptrs[3], u32 flags)
+{
+  psx_gpu->num_spans = 0;
+
+  vertex_struct *a = vertex_ptrs[0];
+  vertex_struct *b = vertex_ptrs[1];
+  vertex_struct *c = vertex_ptrs[2];
+
   s32 y_delta_a = b->y - a->y;
   s32 y_delta_b = c->y - b->y;
   s32 y_delta_c = c->y - a->y;
@@ -3002,7 +3043,7 @@ void render_triangle(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
   compute_all_gradients(psx_gpu, a, b, c);
 
   switch(y_direction_a | (y_direction_b << 2) | (y_direction_c << 4) |
-   (triangle_winding << 6))
+   (psx_gpu->triangle_winding << 6))
   {
     triangle_case(up, up, up, negative):
     triangle_case(up, up, flat, negative):
@@ -3081,11 +3122,11 @@ void render_triangle(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
   spans += psx_gpu->num_spans;
 #endif
 
-  if(psx_gpu->interlace_mode & RENDER_INTERLACE_ENABLED)
+  if(unlikely(psx_gpu->render_mode & RENDER_INTERLACE_ENABLED))
   {
     u32 i;
 
-    if(psx_gpu->interlace_mode & RENDER_INTERLACE_ODD)
+    if(psx_gpu->render_mode & RENDER_INTERLACE_ODD)
     {
       for(i = 0; i < psx_gpu->num_spans; i++)
       {
@@ -3126,6 +3167,14 @@ void render_triangle(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
    (psx_gpu);
 }
 
+void render_triangle(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
+ u32 flags)
+{
+  vertex_struct *vertex_ptrs[3];
+  if (prepare_triangle(psx_gpu, vertexes, vertex_ptrs))
+    render_triangle_p(psx_gpu, vertex_ptrs, flags);
+}
+
 
 void texture_sprite_blocks_8bpp(psx_gpu_struct *psx_gpu);
 
@@ -3161,14 +3210,17 @@ void texture_sprite_blocks_8bpp(psx_gpu_struct *psx_gpu)
 #endif
 
 
-#define setup_sprite_tiled_initialize_4bpp()                                   \
+#define setup_sprite_tiled_initialize_4bpp_clut()                              \
   u16 *clut_ptr = psx_gpu->clut_ptr;                                           \
   vec_8x16u clut_a, clut_b;                                                    \
   vec_16x8u clut_low, clut_high;                                               \
                                                                                \
   load_8x16b(clut_a, clut_ptr);                                                \
   load_8x16b(clut_b, clut_ptr + 8);                                            \
-  unzip_16x8b(clut_low, clut_high, clut_a, clut_b);                            \
+  unzip_16x8b(clut_low, clut_high, clut_a, clut_b)                             \
+
+#define setup_sprite_tiled_initialize_4bpp()                                   \
+  setup_sprite_tiled_initialize_4bpp_clut();                                   \
                                                                                \
   if(psx_gpu->current_texture_mask & psx_gpu->dirty_textures_4bpp_mask)        \
     update_texture_4bpp_cache(psx_gpu)                                         \
@@ -3185,10 +3237,6 @@ void texture_sprite_blocks_8bpp(psx_gpu_struct *psx_gpu)
   load_64b(texels, texture_block_ptr)                                          \
 
 
-#define setup_sprite_tile_setup_block_yes(side, offset, texture_mode)          \
-
-#define setup_sprite_tile_setup_block_no(side, offset, texture_mode)           \
-
 #define setup_sprite_tile_add_blocks(tile_num_blocks)                          \
   num_blocks += tile_num_blocks;                                               \
   sprite_blocks += tile_num_blocks;                                            \
@@ -3334,34 +3382,36 @@ void texture_sprite_blocks_8bpp(psx_gpu_struct *psx_gpu)
 #define setup_sprite_tile_column_edge_post_adjust_full(edge)                   \
 
 
-#define setup_sprite_tile_column_height_single(edge_mode, edge, texture_mode)  \
+#define setup_sprite_tile_column_height_single(edge_mode, edge, texture_mode,  \
+ x4mode)                                                                       \
 do                                                                             \
 {                                                                              \
   sub_tile_height = column_data;                                               \
-  setup_sprite_tile_column_edge_pre_adjust_##edge_mode(edge);                  \
-  setup_sprite_tile_##edge_mode##_##texture_mode(edge);                        \
-  setup_sprite_tile_column_edge_post_adjust_##edge_mode(edge);                 \
+  setup_sprite_tile_column_edge_pre_adjust_##edge_mode##x4mode(edge);          \
+  setup_sprite_tile_##edge_mode##_##texture_mode##x4mode(edge);                \
+  setup_sprite_tile_column_edge_post_adjust_##edge_mode##x4mode(edge);         \
 } while(0)                                                                     \
 
-#define setup_sprite_tile_column_height_multi(edge_mode, edge, texture_mode)   \
+#define setup_sprite_tile_column_height_multi(edge_mode, edge, texture_mode,   \
+ x4mode)                                                                       \
 do                                                                             \
 {                                                                              \
   u32 tiles_remaining = column_data >> 16;                                     \
   sub_tile_height = column_data & 0xFF;                                        \
-  setup_sprite_tile_column_edge_pre_adjust_##edge_mode(edge);                  \
-  setup_sprite_tile_##edge_mode##_##texture_mode(edge);                        \
+  setup_sprite_tile_column_edge_pre_adjust_##edge_mode##x4mode(edge);          \
+  setup_sprite_tile_##edge_mode##_##texture_mode##x4mode(edge);                \
   tiles_remaining -= 1;                                                        \
                                                                                \
   while(tiles_remaining)                                                       \
   {                                                                            \
     sub_tile_height = 16;                                                      \
-    setup_sprite_tile_##edge_mode##_##texture_mode(edge);                      \
+    setup_sprite_tile_##edge_mode##_##texture_mode##x4mode(edge);              \
     tiles_remaining--;                                                         \
   }                                                                            \
                                                                                \
   sub_tile_height = (column_data >> 8) & 0xFF;                                 \
-  setup_sprite_tile_##edge_mode##_##texture_mode(edge);                        \
-  setup_sprite_tile_column_edge_post_adjust_##edge_mode(edge);                 \
+  setup_sprite_tile_##edge_mode##_##texture_mode##x4mode(edge);                \
+  setup_sprite_tile_column_edge_post_adjust_##edge_mode##x4mode(edge);         \
 } while(0)                                                                     \
 
 
@@ -3374,15 +3424,18 @@ do                                                                             \
   column_data |= (tile_height - 1) << 16                                       \
 
 
+#define RIGHT_MASK_BIT_SHIFT 8
+#define RIGHT_MASK_BIT_SHIFT_4x 16
+
 #define setup_sprite_tile_column_width_single(texture_mode, multi_height,      \
- edge_mode, edge)                                                              \
+ edge_mode, edge, x4mode)                                                      \
 {                                                                              \
   setup_sprite_column_data_##multi_height();                                   \
   left_mask_bits = left_block_mask | right_block_mask;                         \
-  right_mask_bits = left_mask_bits >> 8;                                       \
+  right_mask_bits = left_mask_bits >> RIGHT_MASK_BIT_SHIFT##x4mode;            \
                                                                                \
   setup_sprite_tile_column_height_##multi_height(edge_mode, edge,              \
-   texture_mode);                                                              \
+   texture_mode, x4mode);                                                      \
 }                                                                              \
 
 #define setup_sprite_tiled_advance_column()                                    \
@@ -3390,18 +3443,22 @@ do                                                                             \
   if((texture_offset_base & 0xF00) == 0)                                       \
     texture_offset_base -= (0x100 + 0xF00)                                     \
 
+#define FB_PTR_MULTIPLIER 1
+#define FB_PTR_MULTIPLIER_4x 2
+
 #define setup_sprite_tile_column_width_multi(texture_mode, multi_height,       \
- left_mode, right_mode)                                                        \
+ left_mode, right_mode, x4mode)                                                \
 {                                                                              \
   setup_sprite_column_data_##multi_height();                                   \
-  s32 fb_ptr_advance_column = 16 - (1024 * height);                            \
+  s32 fb_ptr_advance_column = (16 - (1024 * height))                           \
+    * FB_PTR_MULTIPLIER##x4mode;                                               \
                                                                                \
   tile_width -= 2;                                                             \
   left_mask_bits = left_block_mask;                                            \
-  right_mask_bits = left_mask_bits >> 8;                                       \
+  right_mask_bits = left_mask_bits >> RIGHT_MASK_BIT_SHIFT##x4mode;            \
                                                                                \
   setup_sprite_tile_column_height_##multi_height(left_mode, right,             \
-   texture_mode);                                                              \
+   texture_mode, x4mode);                                                      \
   fb_ptr += fb_ptr_advance_column;                                             \
                                                                                \
   left_mask_bits = 0x00;                                                       \
@@ -3410,22 +3467,297 @@ do                                                                             \
   while(tile_width)                                                            \
   {                                                                            \
     setup_sprite_tiled_advance_column();                                       \
-    setup_sprite_tile_column_height_##multi_height(full, none, texture_mode);  \
+    setup_sprite_tile_column_height_##multi_height(full, none,                 \
+     texture_mode, x4mode);                                                    \
     fb_ptr += fb_ptr_advance_column;                                           \
     tile_width--;                                                              \
   }                                                                            \
                                                                                \
   left_mask_bits = right_block_mask;                                           \
-  right_mask_bits = left_mask_bits >> 8;                                       \
+  right_mask_bits = left_mask_bits >> RIGHT_MASK_BIT_SHIFT##x4mode;            \
                                                                                \
   setup_sprite_tiled_advance_column();                                         \
   setup_sprite_tile_column_height_##multi_height(right_mode, left,             \
-   texture_mode);                                                              \
+   texture_mode, x4mode);                                                      \
+}                                                                              \
+
+
+/* 4x stuff */
+#define setup_sprite_tiled_initialize_4bpp_4x()                                \
+  setup_sprite_tiled_initialize_4bpp_clut()                                    \
+
+#define setup_sprite_tiled_initialize_8bpp_4x()                                \
+
+
+#define setup_sprite_tile_full_4bpp_4x(edge)                                   \
+{                                                                              \
+  vec_8x8u texels_low, texels_high;                                            \
+  vec_8x16u pixels, pixels_wide;                                               \
+  setup_sprite_tile_add_blocks(sub_tile_height * 2 * 4);                       \
+  u32 left_mask_bits_a = left_mask_bits & 0xFF;                                \
+  u32 left_mask_bits_b = left_mask_bits >> 8;                                  \
+  u32 right_mask_bits_a = right_mask_bits & 0xFF;                              \
+  u32 right_mask_bits_b = right_mask_bits >> 8;                                \
+                                                                               \
+  while(sub_tile_height)                                                       \
+  {                                                                            \
+    setup_sprite_tile_fetch_texel_block_8bpp(0);                               \
+    tbl_16(texels_low, texels, clut_low);                                      \
+    tbl_16(texels_high, texels, clut_high);                                    \
+    zip_8x16b(pixels, texels_low, texels_high);                                \
+                                                                               \
+    zip_4x32b(vector_cast(vec_4x32u, pixels_wide), pixels.low, pixels.low);    \
+    block->texels = pixels_wide;                                               \
+    block->draw_mask_bits = left_mask_bits_a;                                  \
+    block->fb_ptr = fb_ptr;                                                    \
+    block++;                                                                   \
+                                                                               \
+    block->texels = pixels_wide;                                               \
+    block->draw_mask_bits = left_mask_bits_a;                                  \
+    block->fb_ptr = fb_ptr + 1024;                                             \
+    block++;                                                                   \
+                                                                               \
+    zip_4x32b(vector_cast(vec_4x32u, pixels_wide), pixels.high, pixels.high);  \
+    block->texels = pixels_wide;                                               \
+    block->draw_mask_bits = left_mask_bits_b;                                  \
+    block->fb_ptr = fb_ptr + 8;                                                \
+    block++;                                                                   \
+                                                                               \
+    block->texels = pixels_wide;                                               \
+    block->draw_mask_bits = left_mask_bits_b;                                  \
+    block->fb_ptr = fb_ptr + 1024 + 8;                                         \
+    block++;                                                                   \
+                                                                               \
+    setup_sprite_tile_fetch_texel_block_8bpp(8);                               \
+    tbl_16(texels_low, texels, clut_low);                                      \
+    tbl_16(texels_high, texels, clut_high);                                    \
+    zip_8x16b(pixels, texels_low, texels_high);                                \
+                                                                               \
+    zip_4x32b(vector_cast(vec_4x32u, pixels_wide), pixels.low, pixels.low);    \
+    block->texels = pixels_wide;                                               \
+    block->draw_mask_bits = right_mask_bits_a;                                 \
+    block->fb_ptr = fb_ptr + 16;                                               \
+    block++;                                                                   \
+                                                                               \
+    block->texels = pixels_wide;                                               \
+    block->draw_mask_bits = right_mask_bits_a;                                 \
+    block->fb_ptr = fb_ptr + 1024 + 16;                                        \
+    block++;                                                                   \
+                                                                               \
+    zip_4x32b(vector_cast(vec_4x32u, pixels_wide), pixels.high, pixels.high);  \
+    block->texels = pixels_wide;                                               \
+    block->draw_mask_bits = right_mask_bits_b;                                 \
+    block->fb_ptr = fb_ptr + 24;                                               \
+    block++;                                                                   \
+                                                                               \
+    block->texels = pixels_wide;                                               \
+    block->draw_mask_bits = right_mask_bits_b;                                 \
+    block->fb_ptr = fb_ptr + 1024 + 24;                                        \
+    block++;                                                                   \
+                                                                               \
+    fb_ptr += 2048;                                                            \
+    texture_offset += 0x10;                                                    \
+    sub_tile_height--;                                                         \
+  }                                                                            \
+  texture_offset += 0xF00;                                                     \
+  psx_gpu->num_blocks = num_blocks;                                            \
 }                                                                              \
 
+#define setup_sprite_tile_half_4bpp_4x(edge)                                   \
+{                                                                              \
+  vec_8x8u texels_low, texels_high;                                            \
+  vec_8x16u pixels, pixels_wide;                                               \
+  setup_sprite_tile_add_blocks(sub_tile_height * 4);                           \
+  u32 edge##_mask_bits_a = edge##_mask_bits & 0xFF;                            \
+  u32 edge##_mask_bits_b = edge##_mask_bits >> 8;                              \
+                                                                               \
+  while(sub_tile_height)                                                       \
+  {                                                                            \
+    setup_sprite_tile_fetch_texel_block_8bpp(0);                               \
+    tbl_16(texels_low, texels, clut_low);                                      \
+    tbl_16(texels_high, texels, clut_high);                                    \
+    zip_8x16b(pixels, texels_low, texels_high);                                \
+                                                                               \
+    zip_4x32b(vector_cast(vec_4x32u, pixels_wide), pixels.low, pixels.low);    \
+    block->texels = pixels_wide;                                               \
+    block->draw_mask_bits = edge##_mask_bits_a;                                \
+    block->fb_ptr = fb_ptr;                                                    \
+    block++;                                                                   \
+                                                                               \
+    block->texels = pixels_wide;                                               \
+    block->draw_mask_bits = edge##_mask_bits_a;                                \
+    block->fb_ptr = fb_ptr + 1024;                                             \
+    block++;                                                                   \
+                                                                               \
+    zip_4x32b(vector_cast(vec_4x32u, pixels_wide), pixels.high, pixels.high);  \
+    block->texels = pixels_wide;                                               \
+    block->draw_mask_bits = edge##_mask_bits_b;                                \
+    block->fb_ptr = fb_ptr + 8;                                                \
+    block++;                                                                   \
+                                                                               \
+    block->texels = pixels_wide;                                               \
+    block->draw_mask_bits = edge##_mask_bits_b;                                \
+    block->fb_ptr = fb_ptr + 1024 + 8;                                         \
+    block++;                                                                   \
+                                                                               \
+    fb_ptr += 2048;                                                            \
+    texture_offset += 0x10;                                                    \
+    sub_tile_height--;                                                         \
+  }                                                                            \
+  texture_offset += 0xF00;                                                     \
+  psx_gpu->num_blocks = num_blocks;                                            \
+}                                                                              \
 
-#define setup_sprite_tiled_builder(texture_mode)                               \
-void setup_sprite_##texture_mode(psx_gpu_struct *psx_gpu, s32 x, s32 y,        \
+  
+#define setup_sprite_tile_full_8bpp_4x(edge)                                   \
+{                                                                              \
+  setup_sprite_tile_add_blocks(sub_tile_height * 2 * 4);                       \
+  vec_16x8u texels_wide;                                                       \
+  u32 left_mask_bits_a = left_mask_bits & 0xFF;                                \
+  u32 left_mask_bits_b = left_mask_bits >> 8;                                  \
+  u32 right_mask_bits_a = right_mask_bits & 0xFF;                              \
+  u32 right_mask_bits_b = right_mask_bits >> 8;                                \
+                                                                               \
+  while(sub_tile_height)                                                       \
+  {                                                                            \
+    setup_sprite_tile_fetch_texel_block_8bpp(0);                               \
+    zip_8x16b(vector_cast(vec_8x16u, texels_wide), texels, texels);            \
+    block->r = texels_wide.low;                                                \
+    block->draw_mask_bits = left_mask_bits_a;                                  \
+    block->fb_ptr = fb_ptr;                                                    \
+    block++;                                                                   \
+                                                                               \
+    block->r = texels_wide.low;                                                \
+    block->draw_mask_bits = left_mask_bits_a;                                  \
+    block->fb_ptr = fb_ptr + 1024;                                             \
+    block++;                                                                   \
+                                                                               \
+    block->r = texels_wide.high;                                               \
+    block->draw_mask_bits = left_mask_bits_b;                                  \
+    block->fb_ptr = fb_ptr + 8;                                                \
+    block++;                                                                   \
+                                                                               \
+    block->r = texels_wide.high;                                               \
+    block->draw_mask_bits = left_mask_bits_b;                                  \
+    block->fb_ptr = fb_ptr + 1024 + 8;                                         \
+    block++;                                                                   \
+                                                                               \
+    setup_sprite_tile_fetch_texel_block_8bpp(8);                               \
+    zip_8x16b(vector_cast(vec_8x16u, texels_wide), texels, texels);            \
+    block->r = texels_wide.low;                                                \
+    block->draw_mask_bits = right_mask_bits_a;                                 \
+    block->fb_ptr = fb_ptr + 16;                                               \
+    block++;                                                                   \
+                                                                               \
+    block->r = texels_wide.low;                                                \
+    block->draw_mask_bits = right_mask_bits_a;                                 \
+    block->fb_ptr = fb_ptr + 1024 + 16;                                        \
+    block++;                                                                   \
+                                                                               \
+    block->r = texels_wide.high;                                               \
+    block->draw_mask_bits = right_mask_bits_b;                                 \
+    block->fb_ptr = fb_ptr + 24;                                               \
+    block++;                                                                   \
+                                                                               \
+    block->r = texels_wide.high;                                               \
+    block->draw_mask_bits = right_mask_bits_b;                                 \
+    block->fb_ptr = fb_ptr + 24 + 1024;                                        \
+    block++;                                                                   \
+                                                                               \
+    fb_ptr += 2048;                                                            \
+    texture_offset += 0x10;                                                    \
+    sub_tile_height--;                                                         \
+  }                                                                            \
+  texture_offset += 0xF00;                                                     \
+  psx_gpu->num_blocks = num_blocks;                                            \
+}                                                                              \
+
+#define setup_sprite_tile_half_8bpp_4x(edge)                                   \
+{                                                                              \
+  setup_sprite_tile_add_blocks(sub_tile_height * 4);                           \
+  vec_16x8u texels_wide;                                                       \
+  u32 edge##_mask_bits_a = edge##_mask_bits & 0xFF;                            \
+  u32 edge##_mask_bits_b = edge##_mask_bits >> 8;                              \
+                                                                               \
+  while(sub_tile_height)                                                       \
+  {                                                                            \
+    setup_sprite_tile_fetch_texel_block_8bpp(0);                               \
+    zip_8x16b(vector_cast(vec_8x16u, texels_wide), texels, texels);            \
+    block->r = texels_wide.low;                                                \
+    block->draw_mask_bits = edge##_mask_bits_a;                                \
+    block->fb_ptr = fb_ptr;                                                    \
+    block++;                                                                   \
+                                                                               \
+    block->r = texels_wide.low;                                                \
+    block->draw_mask_bits = edge##_mask_bits_a;                                \
+    block->fb_ptr = fb_ptr + 1024;                                             \
+    block++;                                                                   \
+                                                                               \
+    block->r = texels_wide.high;                                               \
+    block->draw_mask_bits = edge##_mask_bits_b;                                \
+    block->fb_ptr = fb_ptr + 8;                                                \
+    block++;                                                                   \
+                                                                               \
+    block->r = texels_wide.high;                                               \
+    block->draw_mask_bits = edge##_mask_bits_b;                                \
+    block->fb_ptr = fb_ptr + 8 + 1024;                                         \
+    block++;                                                                   \
+                                                                               \
+    fb_ptr += 2048;                                                            \
+    texture_offset += 0x10;                                                    \
+    sub_tile_height--;                                                         \
+  }                                                                            \
+  texture_offset += 0xF00;                                                     \
+  psx_gpu->num_blocks = num_blocks;                                            \
+}                                                                              \
+
+  
+#define setup_sprite_tile_column_edge_pre_adjust_half_right_4x()               \
+  texture_offset = texture_offset_base + 8;                                    \
+  fb_ptr += 16                                                                 \
+
+#define setup_sprite_tile_column_edge_pre_adjust_half_left_4x()                \
+  texture_offset = texture_offset_base                                         \
+
+#define setup_sprite_tile_column_edge_pre_adjust_half_4x(edge)                 \
+  setup_sprite_tile_column_edge_pre_adjust_half_##edge##_4x()                  \
+
+#define setup_sprite_tile_column_edge_pre_adjust_full_4x(edge)                 \
+  texture_offset = texture_offset_base                                         \
+
+#define setup_sprite_tile_column_edge_post_adjust_half_right_4x()              \
+  fb_ptr -= 16                                                                 \
+
+#define setup_sprite_tile_column_edge_post_adjust_half_left_4x()               \
+
+#define setup_sprite_tile_column_edge_post_adjust_half_4x(edge)                \
+  setup_sprite_tile_column_edge_post_adjust_half_##edge##_4x()                 \
+
+#define setup_sprite_tile_column_edge_post_adjust_full_4x(edge)                \
+
+
+#define setup_sprite_offset_u_adjust()                                         \
+
+#define setup_sprite_comapre_left_block_mask()                                 \
+  ((left_block_mask & 0xFF) == 0xFF)                                           \
+
+#define setup_sprite_comapre_right_block_mask()                                \
+  (((right_block_mask >> 8) & 0xFF) == 0xFF)                                   \
+
+
+#define setup_sprite_offset_u_adjust_4x()                                      \
+  offset_u *= 2;                                                               \
+  offset_u_right = offset_u_right * 2 + 1                                      \
+
+#define setup_sprite_comapre_left_block_mask_4x()                              \
+  ((left_block_mask & 0xFFFF) == 0xFFFF)                                       \
+
+#define setup_sprite_comapre_right_block_mask_4x()                             \
+  (((right_block_mask >> 16) & 0xFFFF) == 0xFFFF)                              \
+
+
+#define setup_sprite_tiled_builder(texture_mode, x4mode)                       \
+void setup_sprite_##texture_mode##x4mode(psx_gpu_struct *psx_gpu, s32 x, s32 y,\
  s32 u, s32 v, s32 width, s32 height, u32 color)                               \
 {                                                                              \
   s32 offset_u = u & 0xF;                                                      \
@@ -3437,8 +3769,10 @@ void setup_sprite_##texture_mode(psx_gpu_struct *psx_gpu, s32 x, s32 y,        \
   s32 tile_width = width_rounded / 16;                                         \
   u32 offset_u_right = width_rounded & 0xF;                                    \
                                                                                \
-  u32 left_block_mask = ~(0xFFFF << offset_u);                                 \
-  u32 right_block_mask = 0xFFFE << offset_u_right;                             \
+  setup_sprite_offset_u_adjust##x4mode();                                      \
+                                                                               \
+  u32 left_block_mask = ~(0xFFFFFFFF << offset_u);                             \
+  u32 right_block_mask = 0xFFFFFFFE << offset_u_right;                         \
                                                                                \
   u32 left_mask_bits;                                                          \
   u32 right_mask_bits;                                                         \
@@ -3455,19 +3789,19 @@ void setup_sprite_##texture_mode(psx_gpu_struct *psx_gpu, s32 x, s32 y,        \
   u32 texture_offset_base = texture_offset;                                    \
   u32 control_mask;                                                            \
                                                                                \
-  u16 *fb_ptr = psx_gpu->vram_ptr + (y * 1024) + (x - offset_u);               \
+  u16 *fb_ptr = psx_gpu->vram_out_ptr + (y * 1024) + (x - offset_u);           \
   u32 num_blocks = psx_gpu->num_blocks;                                        \
   block_struct *block = psx_gpu->blocks + num_blocks;                          \
                                                                                \
   u16 *texture_block_ptr;                                                      \
   vec_8x8u texels;                                                             \
                                                                                \
-  setup_sprite_tiled_initialize_##texture_mode();                              \
+  setup_sprite_tiled_initialize_##texture_mode##x4mode();                      \
                                                                                \
   control_mask = tile_width == 1;                                              \
   control_mask |= (tile_height == 1) << 1;                                     \
-  control_mask |= ((left_block_mask & 0xFF) == 0xFF) << 2;                     \
-  control_mask |= (((right_block_mask >> 8) & 0xFF) == 0xFF) << 3;             \
+  control_mask |= setup_sprite_comapre_left_block_mask##x4mode() << 2;         \
+  control_mask |= setup_sprite_comapre_right_block_mask##x4mode() << 3;        \
                                                                                \
   sprites_##texture_mode++;                                                    \
                                                                                \
@@ -3475,64 +3809,77 @@ void setup_sprite_##texture_mode(psx_gpu_struct *psx_gpu, s32 x, s32 y,        \
   {                                                                            \
     default:                                                                   \
     case 0x0:                                                                  \
-      setup_sprite_tile_column_width_multi(texture_mode, multi, full, full);   \
+      setup_sprite_tile_column_width_multi(texture_mode, multi, full, full,    \
+       x4mode);                                                                \
       break;                                                                   \
                                                                                \
     case 0x1:                                                                  \
-      setup_sprite_tile_column_width_single(texture_mode, multi, full, none);  \
+      setup_sprite_tile_column_width_single(texture_mode, multi, full, none,   \
+       x4mode);                                                                \
       break;                                                                   \
                                                                                \
     case 0x2:                                                                  \
-      setup_sprite_tile_column_width_multi(texture_mode, single, full, full);  \
+      setup_sprite_tile_column_width_multi(texture_mode, single, full, full,   \
+       x4mode);                                                                \
       break;                                                                   \
                                                                                \
     case 0x3:                                                                  \
-      setup_sprite_tile_column_width_single(texture_mode, single, full, none); \
+      setup_sprite_tile_column_width_single(texture_mode, single, full, none,  \
+       x4mode);                                                                \
       break;                                                                   \
                                                                                \
     case 0x4:                                                                  \
-      setup_sprite_tile_column_width_multi(texture_mode, multi, half, full);   \
+      setup_sprite_tile_column_width_multi(texture_mode, multi, half, full,    \
+       x4mode);                                                                \
       break;                                                                   \
                                                                                \
     case 0x5:                                                                  \
-      setup_sprite_tile_column_width_single(texture_mode, multi, half, right); \
+      setup_sprite_tile_column_width_single(texture_mode, multi, half, right,  \
+       x4mode);                                                                \
       break;                                                                   \
                                                                                \
     case 0x6:                                                                  \
-      setup_sprite_tile_column_width_multi(texture_mode, single, half, full);  \
+      setup_sprite_tile_column_width_multi(texture_mode, single, half, full,   \
+       x4mode);                                                                \
       break;                                                                   \
                                                                                \
     case 0x7:                                                                  \
-      setup_sprite_tile_column_width_single(texture_mode, single, half, right);\
+      setup_sprite_tile_column_width_single(texture_mode, single, half, right, \
+       x4mode);                                                                \
       break;                                                                   \
                                                                                \
     case 0x8:                                                                  \
-      setup_sprite_tile_column_width_multi(texture_mode, multi, full, half);   \
+      setup_sprite_tile_column_width_multi(texture_mode, multi, full, half,    \
+       x4mode);                                                                \
       break;                                                                   \
                                                                                \
     case 0x9:                                                                  \
-      setup_sprite_tile_column_width_single(texture_mode, multi, half, left);  \
+      setup_sprite_tile_column_width_single(texture_mode, multi, half, left,   \
+       x4mode);                                                                \
       break;                                                                   \
                                                                                \
     case 0xA:                                                                  \
-      setup_sprite_tile_column_width_multi(texture_mode, single, full, half);  \
+      setup_sprite_tile_column_width_multi(texture_mode, single, full, half,   \
+       x4mode);                                                                \
       break;                                                                   \
                                                                                \
     case 0xB:                                                                  \
-      setup_sprite_tile_column_width_single(texture_mode, single, half, left); \
+      setup_sprite_tile_column_width_single(texture_mode, single, half, left,  \
+       x4mode);                                                                \
       break;                                                                   \
                                                                                \
     case 0xC:                                                                  \
-      setup_sprite_tile_column_width_multi(texture_mode, multi, half, half);   \
+      setup_sprite_tile_column_width_multi(texture_mode, multi, half, half,    \
+       x4mode);                                                                \
       break;                                                                   \
                                                                                \
     case 0xE:                                                                  \
-      setup_sprite_tile_column_width_multi(texture_mode, single, half, half);  \
+      setup_sprite_tile_column_width_multi(texture_mode, single, half, half,   \
+       x4mode);                                                                \
       break;                                                                   \
   }                                                                            \
 }                                                                              \
 
-
 void setup_sprite_4bpp(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u, s32 v,
  s32 width, s32 height, u32 color);
 void setup_sprite_8bpp(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u, s32 v,
@@ -3540,9 +3887,24 @@ void setup_sprite_8bpp(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u, s32 v,
 void setup_sprite_16bpp(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u, s32 v,
  s32 width, s32 height, u32 color);
 
+void setup_sprite_4bpp_4x(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u, s32 v,
+ s32 width, s32 height, u32 color);
+void setup_sprite_8bpp_4x(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u, s32 v,
+ s32 width, s32 height, u32 color);
+void setup_sprite_16bpp_4x(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u, s32 v,
+ s32 width, s32 height, u32 color);
+
+void setup_sprite_untextured(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u,
+ s32 v, s32 width, s32 height, u32 color);
+void setup_sprite_untextured_simple(psx_gpu_struct *psx_gpu, s32 x, s32 y,
+ s32 u, s32 v, s32 width, s32 height, u32 color);
+
 #ifndef NEON_BUILD
-setup_sprite_tiled_builder(4bpp);
-setup_sprite_tiled_builder(8bpp);
+setup_sprite_tiled_builder(4bpp,);
+setup_sprite_tiled_builder(8bpp,);
+
+setup_sprite_tiled_builder(4bpp,_4x);
+setup_sprite_tiled_builder(8bpp,_4x);
 
 void setup_sprite_16bpp(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u,
  s32 v, s32 width, s32 height, u32 color)
@@ -3550,7 +3912,7 @@ void setup_sprite_16bpp(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u,
   u32 left_offset = u & 0x7;
   u32 width_rounded = width + left_offset + 7;
 
-  u16 *fb_ptr = psx_gpu->vram_ptr + (y * 1024) + (s32)(x - left_offset);
+  u16 *fb_ptr = psx_gpu->vram_out_ptr + (y * 1024) + (s32)(x - left_offset);
   u32 right_width = width_rounded & 0x7;
   u32 block_width = width_rounded / 8;
   u32 fb_ptr_pitch = (1024 + 8) - (block_width * 8);
@@ -3665,14 +4027,20 @@ void setup_sprite_16bpp(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u,
   }
 }
 
-#endif
-
 void setup_sprite_untextured(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u,
  s32 v, s32 width, s32 height, u32 color)
 {
+  if((psx_gpu->render_state & (RENDER_STATE_MASK_EVALUATE |
+   RENDER_FLAGS_MODULATE_TEXELS | RENDER_FLAGS_BLEND)) == 0 &&
+   (psx_gpu->render_mode & RENDER_INTERLACE_ENABLED) == 0)
+  {
+    setup_sprite_untextured_simple(psx_gpu, x, y, u, v, width, height, color);
+    return;
+  }
+
   u32 right_width = ((width - 1) & 0x7) + 1;
   u32 right_mask_bits = (0xFF << right_width);
-  u16 *fb_ptr = psx_gpu->vram_ptr + (y * 1024) + x;
+  u16 *fb_ptr = psx_gpu->vram_out_ptr + (y * 1024) + x;
   u32 block_width = (width + 7) / 8;
   u32 fb_ptr_pitch = 1024 - ((block_width - 1) * 8);
   u32 blocks_remaining;
@@ -3735,6 +4103,66 @@ void setup_sprite_untextured(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u,
   }
 }
 
+#endif
+
+void setup_sprite_untextured_simple(psx_gpu_struct *psx_gpu, s32 x, s32 y,
+ s32 u, s32 v, s32 width, s32 height, u32 color)
+{
+  u32 r = color & 0xFF;
+  u32 g = (color >> 8) & 0xFF;
+  u32 b = (color >> 16) & 0xFF;
+  u32 color_16bpp = (r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10) |
+   psx_gpu->mask_msb;
+  u32 color_32bpp = color_16bpp | (color_16bpp << 16);
+
+  u16 *vram_ptr16 = psx_gpu->vram_out_ptr + x + (y * 1024);
+  u32 *vram_ptr;
+
+  u32 num_width;
+
+  if(psx_gpu->num_blocks > MAX_BLOCKS)
+  {
+    flush_render_block_buffer(psx_gpu);
+  }
+
+  while(height)
+  {
+    num_width = width;
+
+    vram_ptr = (void *)vram_ptr16;
+    if((long)vram_ptr16 & 2)
+    {
+      *vram_ptr16 = color_32bpp;
+      vram_ptr = (void *)(vram_ptr16 + 1);
+      num_width--;
+    }
+
+    while(num_width >= 4 * 2)
+    {
+      vram_ptr[0] = color_32bpp;
+      vram_ptr[1] = color_32bpp;
+      vram_ptr[2] = color_32bpp;
+      vram_ptr[3] = color_32bpp;
+
+      vram_ptr += 4;
+      num_width -= 4 * 2;
+    }
+
+    while(num_width >= 2)
+    {
+      *vram_ptr++ = color_32bpp;
+      num_width -= 2;
+    }
+
+    if(num_width > 0)
+    {
+      *(u16 *)vram_ptr = color_32bpp;
+    }
+
+    vram_ptr16 += 1024;
+    height--;
+  }
+}
 
 
 #define setup_sprite_blocks_switch_textured(texture_mode)                      \
@@ -4155,9 +4583,6 @@ do                                                                             \
   {                                                                            \
     delta_y *= -1;                                                             \
                                                                                \
-    if(delta_y >= 512)                                                         \
-      return;                                                                  \
-                                                                               \
     if(delta_x > delta_y)                                                      \
     {                                                                          \
       draw_line_span_horizontal(decrement, shading, blending, dithering,       \
@@ -4171,9 +4596,6 @@ do                                                                             \
   }                                                                            \
   else                                                                         \
   {                                                                            \
-    if(delta_y >= 512)                                                         \
-      return;                                                                  \
-                                                                               \
     if(delta_x > delta_y)                                                      \
     {                                                                          \
       draw_line_span_horizontal(increment, shading, blending, dithering,       \
@@ -4188,7 +4610,7 @@ do                                                                             \
 
                                                                                 
 void render_line(psx_gpu_struct *psx_gpu, vertex_struct *vertexes, u32 flags,
- u32 color)
+ u32 color, int double_resolution)
 {
   s32 color_r, color_g, color_b;
   u32 triangle_winding = 0;
@@ -4240,12 +4662,22 @@ void render_line(psx_gpu_struct *psx_gpu, vertex_struct *vertexes, u32 flags,
   delta_x = x_b - x_a;
   delta_y = y_b - y_a;
 
-  if(delta_x >= 1024)
+  if(delta_x >= 1024 || delta_y >= 512 || delta_y <= -512)
     return;
 
+  if(double_resolution)
+  {
+    x_a *= 2;
+    x_b *= 2;
+    y_a *= 2;
+    y_b *= 2;
+    delta_x *= 2;
+    delta_y *= 2;
+  }
+
   flags &= ~RENDER_FLAGS_TEXTURE_MAP;
 
-  vram_ptr = psx_gpu->vram_ptr + (y_a * 1024) + x_a;
+  vram_ptr = psx_gpu->vram_out_ptr + (y_a * 1024) + x_a;
 
   control_mask = 0x0;
 
@@ -4435,7 +4867,6 @@ void render_block_fill(psx_gpu_struct *psx_gpu, u32 color, u32 x, u32 y,
   if((width == 0) || (height == 0))
     return;
 
-  flush_render_block_buffer(psx_gpu);
   invalidate_texture_cache_region(psx_gpu, x, y, x + width - 1, y + height - 1);
 
   u32 r = color & 0xFF;
@@ -4445,17 +4876,17 @@ void render_block_fill(psx_gpu_struct *psx_gpu, u32 color, u32 x, u32 y,
    psx_gpu->mask_msb;
   u32 color_32bpp = color_16bpp | (color_16bpp << 16);
 
-  u32 *vram_ptr = (u32 *)(psx_gpu->vram_ptr + x + (y * 1024));
+  u32 *vram_ptr = (u32 *)(psx_gpu->vram_out_ptr + x + (y * 1024));
 
   u32 pitch = 512 - (width / 2);
   u32 num_width;
 
-  if(psx_gpu->interlace_mode & RENDER_INTERLACE_ENABLED)
+  if(psx_gpu->render_mode & RENDER_INTERLACE_ENABLED)
   {
     pitch += 512;
     height /= 2;
 
-    if(psx_gpu->interlace_mode & RENDER_INTERLACE_ODD)
+    if(psx_gpu->render_mode & RENDER_INTERLACE_ODD)
       vram_ptr += 512; 
   }
 
@@ -4482,6 +4913,50 @@ void render_block_fill(psx_gpu_struct *psx_gpu, u32 color, u32 x, u32 y,
   }
 }
 
+void render_block_fill_enh(psx_gpu_struct *psx_gpu, u32 color, u32 x, u32 y,
+ u32 width, u32 height)
+{
+  if((width == 0) || (height == 0))
+    return;
+
+  if(width > 1024)
+    width = 1024;
+
+  u32 r = color & 0xFF;
+  u32 g = (color >> 8) & 0xFF;
+  u32 b = (color >> 16) & 0xFF;
+  u32 color_16bpp = (r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10) |
+   psx_gpu->mask_msb;
+  u32 color_32bpp = color_16bpp | (color_16bpp << 16);
+
+  u32 *vram_ptr = (u32 *)(psx_gpu->vram_out_ptr + x + (y * 1024));
+
+  u32 pitch = 1024 / 2 - (width / 2);
+  u32 num_width;
+
+  while(height)
+  {
+    num_width = width;
+    while(num_width)
+    {
+      vram_ptr[0] = color_32bpp;
+      vram_ptr[1] = color_32bpp;
+      vram_ptr[2] = color_32bpp;
+      vram_ptr[3] = color_32bpp;
+      vram_ptr[4] = color_32bpp;
+      vram_ptr[5] = color_32bpp;
+      vram_ptr[6] = color_32bpp;
+      vram_ptr[7] = color_32bpp;
+
+      vram_ptr += 8;
+      num_width -= 16;
+    }
+
+    vram_ptr += pitch;
+    height--;
+  }
+}
+
 void render_block_copy(psx_gpu_struct *psx_gpu, u16 *source, u32 x, u32 y,
  u32 width, u32 height, u32 pitch)
 {
@@ -4522,16 +4997,17 @@ void initialize_reciprocal_table(void)
   u32 height_reciprocal;
   s32 shift;
 
-  for(height = 1; height < 512; height++)
+  for(height = 1; height < sizeof(reciprocal_table)
+       / sizeof(reciprocal_table[0]); height++)
   {
     shift = __builtin_clz(height);
     height_normalized = height << shift;
-    height_reciprocal = ((1ULL << 50) + (height_normalized - 1)) /
+    height_reciprocal = ((1ULL << 51) + (height_normalized - 1)) /
      height_normalized;
 
-    shift = 32 - (50 - shift);
+    shift = 32 - (51 - shift);
 
-    reciprocal_table[height] = (height_reciprocal << 12) | shift;
+    reciprocal_table[height] = (height_reciprocal << 10) | shift;
   }
 }
 
@@ -4559,8 +5035,10 @@ void initialize_psx_gpu(psx_gpu_struct *psx_gpu, u16 *vram)
   psx_gpu->render_state = 0;
   psx_gpu->render_state_base = 0;
   psx_gpu->num_blocks = 0;
+  psx_gpu->uvrgb_phase = 0x8000;
 
   psx_gpu->vram_ptr = vram;
+  psx_gpu->vram_out_ptr = vram;
 
   psx_gpu->texture_page_base = psx_gpu->vram_ptr;
   psx_gpu->texture_page_ptr = psx_gpu->vram_ptr;
@@ -4573,7 +5051,7 @@ void initialize_psx_gpu(psx_gpu_struct *psx_gpu, u16 *vram)
   psx_gpu->texture_mask_width = 0xFF;
   psx_gpu->texture_mask_height = 0xFF;
 
-  psx_gpu->interlace_mode = 0;
+  psx_gpu->render_mode = 0;
 
   memset(psx_gpu->vram_ptr, 0, sizeof(u16) * 1024 * 512);
 
@@ -4596,6 +5074,8 @@ void initialize_psx_gpu(psx_gpu_struct *psx_gpu, u16 *vram)
   psx_gpu->dither_table[3] = dither_table_row(3, -1, 2, -2);
 
   psx_gpu->primitive_type = PRIMITIVE_TYPE_UNKNOWN;
+
+  psx_gpu->enhancement_x_threshold = 256;
 }
 
 u64 get_us(void)
@@ -4660,3 +5140,4 @@ void triangle_benchmark(psx_gpu_struct *psx_gpu)
 
 #endif
 
+#include "psx_gpu_4x.c"
index 53a8717..846658c 100644 (file)
@@ -56,8 +56,8 @@ typedef enum
 typedef enum
 {
   RENDER_INTERLACE_ENABLED     = 0x1,
-  RENDER_INTERLACE_ODD         = 0x2
-} render_interlace_enum;
+  RENDER_INTERLACE_ODD         = 0x2,
+} render_mode_enum;
 
 typedef struct
 {
@@ -122,7 +122,6 @@ typedef struct
   vec_4x32u g_block_span;
   vec_4x32u b_block_span;
 
-  // 72 bytes
   u32 b;
   u32 b_dy;
 
@@ -138,25 +137,21 @@ typedef struct
   u32 triangle_color;
   u32 dither_table[4];
 
+  u32 uvrgb_phase;
+
   struct render_block_handler_struct *render_block_handler;
   void *texture_page_ptr;
   void *texture_page_base;
   u16 *clut_ptr;
   u16 *vram_ptr;
+  u16 *vram_out_ptr;
 
-  // 26 bytes
   u16 render_state_base;
   u16 render_state;
 
   u16 num_spans;
   u16 num_blocks;
 
-  s16 offset_x;
-  s16 offset_y;
-
-  u16 clut_settings;
-  u16 texture_settings;
-
   s16 viewport_start_x;
   s16 viewport_start_y;
   s16 viewport_end_x;
@@ -164,7 +159,6 @@ typedef struct
 
   u16 mask_msb;
 
-  // 8 bytes
   u8 triangle_winding;
 
   u8 display_area_draw_enable;
@@ -178,11 +172,27 @@ typedef struct
   u8 texture_window_y;
 
   u8 primitive_type;
-  u8 interlace_mode;
+  u8 render_mode;
+
+  s16 offset_x;
+  s16 offset_y;
+
+  u16 clut_settings;
+  u16 texture_settings;
+
+  // enhancement stuff
+  u16 *enhancement_buf_ptr;
+  u16 *enhancement_current_buf_ptr;
+  u32 enhancement_x_threshold;
+  s16 saved_viewport_start_x;
+  s16 saved_viewport_start_y;
+  s16 saved_viewport_end_x;
+  s16 saved_viewport_end_y;
+  u8 enhancement_buf_by_x16[64];
 
   // Align up to 64 byte boundary to keep the upcoming buffers cache line
-  // aligned
-  //u8 reserved_a[0];
+  // aligned, also make reachable with single immediate addition
+  u8 reserved_a[164];
 
   // 8KB
   block_struct blocks[MAX_BLOCKS_PER_ROW];
@@ -224,7 +234,7 @@ void render_triangle(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
 void render_sprite(psx_gpu_struct *psx_gpu, s32 x, s32 y, u32 u, u32 v,
  s32 width, s32 height, u32 flags, u32 color);
 void render_line(psx_gpu_struct *gpu, vertex_struct *vertexes, u32 flags,
- u32 color);
+ u32 color, int double_resolution);
 
 u32 texture_region_mask(s32 x1, s32 y1, s32 x2, s32 y2);
 
diff --git a/plugins/gpu_neon/psx_gpu/psx_gpu_4x.c b/plugins/gpu_neon/psx_gpu/psx_gpu_4x.c
new file mode 100644 (file)
index 0000000..83c6680
--- /dev/null
@@ -0,0 +1,384 @@
+#define select_enhancement_buf_ptr(psx_gpu, x) \\r
+  ((psx_gpu)->enhancement_buf_ptr + \\r
+   ((psx_gpu)->enhancement_buf_by_x16[(x) / 16] << 20))\r
+\r
+#ifndef NEON_BUILD\r
+void setup_sprite_16bpp_4x(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u,\r
+ s32 v, s32 width, s32 height, u32 color)\r
+{\r
+  u32 left_offset = u & 0x7;\r
+  u32 width_rounded = width + left_offset + 7;\r
+\r
+  u16 *fb_ptr = psx_gpu->vram_out_ptr + (y * 1024) + (s32)(x - left_offset * 2);\r
+  u32 right_width = width_rounded & 0x7;\r
+  u32 block_width = width_rounded / 8;\r
+  u32 fb_ptr_pitch = (2048 + 16) - (block_width * 16);\r
+\r
+  u32 left_mask_bits = ~(0xFFFF << (left_offset * 2));\r
+  u32 right_mask_bits = 0xFFFC << (right_width * 2);\r
+\r
+  u32 texture_offset_base = u + (v * 1024);\r
+  u32 texture_mask =\r
+   psx_gpu->texture_mask_width | (psx_gpu->texture_mask_height * 1024);\r
+\r
+  u32 blocks_remaining;\r
+  u32 num_blocks = psx_gpu->num_blocks;\r
+  block_struct *block = psx_gpu->blocks + num_blocks;\r
+\r
+  u16 *texture_page_ptr = psx_gpu->texture_page_ptr;\r
+  u16 *texture_block_ptr;\r
+\r
+  texture_offset_base &= ~0x7;\r
+\r
+  sprites_16bpp++;\r
+\r
+  if(block_width == 1)\r
+  {\r
+    u32 mask_bits = left_mask_bits | right_mask_bits;\r
+    u32 mask_bits_a = mask_bits & 0xFF;\r
+    u32 mask_bits_b = mask_bits >> 8;\r
+    \r
+    vec_8x16u texels;\r
+    vec_8x16u texels_wide;\r
+\r
+    while(height)\r
+    {\r
+      num_blocks += 4;\r
+      sprite_blocks += 4;\r
+\r
+      if(num_blocks > MAX_BLOCKS)\r
+      {\r
+        flush_render_block_buffer(psx_gpu);\r
+        num_blocks = 4;\r
+        block = psx_gpu->blocks;\r
+      }\r
+      \r
+      texture_block_ptr =\r
+       texture_page_ptr + (texture_offset_base & texture_mask);\r
+\r
+      load_128b(texels, texture_block_ptr);\r
+      \r
+      zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.low, texels.low);\r
+      block->texels = texels_wide;\r
+      block->draw_mask_bits = mask_bits_a;\r
+      block->fb_ptr = fb_ptr;          \r
+      block++;\r
+      \r
+      block->texels = texels_wide;\r
+      block->draw_mask_bits = mask_bits_a;\r
+      block->fb_ptr = fb_ptr + 1024;          \r
+      block++;\r
+      \r
+      zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.high, texels.high);\r
+      block->texels = texels_wide;\r
+      block->draw_mask_bits = mask_bits_b;\r
+      block->fb_ptr = fb_ptr + 8;\r
+      block++;\r
+      \r
+      block->texels = texels_wide;\r
+      block->draw_mask_bits = mask_bits_b;\r
+      block->fb_ptr = fb_ptr + 8 + 1024;          \r
+      block++;      \r
+\r
+      texture_offset_base += 1024;\r
+      fb_ptr += 2048;\r
+\r
+      height--;\r
+      psx_gpu->num_blocks = num_blocks;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    u32 texture_offset;\r
+    \r
+    u32 left_mask_bits_a = left_mask_bits & 0xFF;\r
+    u32 left_mask_bits_b = left_mask_bits >> 8;\r
+    u32 right_mask_bits_a = right_mask_bits & 0xFF;\r
+    u32 right_mask_bits_b = right_mask_bits >> 8;\r
+    \r
+    vec_8x16u texels;\r
+    vec_8x16u texels_wide;    \r
+\r
+    while(height)\r
+    {\r
+      blocks_remaining = block_width - 2;\r
+      num_blocks += block_width * 4;\r
+      sprite_blocks += block_width * 4;\r
+\r
+      if(num_blocks > MAX_BLOCKS)\r
+      {\r
+        flush_render_block_buffer(psx_gpu);\r
+        num_blocks = block_width * 4;\r
+        block = psx_gpu->blocks;\r
+      }\r
+\r
+      texture_offset = texture_offset_base;\r
+      texture_offset_base += 1024;\r
+\r
+      texture_block_ptr = texture_page_ptr + (texture_offset & texture_mask);\r
+      \r
+      load_128b(texels, texture_block_ptr);\r
+\r
+      zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.low, texels.low);\r
+      block->texels = texels_wide;\r
+      block->draw_mask_bits = left_mask_bits_a;\r
+      block->fb_ptr = fb_ptr;\r
+      block++;\r
+      \r
+      block->texels = texels_wide;\r
+      block->draw_mask_bits = left_mask_bits_a;\r
+      block->fb_ptr = fb_ptr + 1024;\r
+      block++;      \r
+\r
+      zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.high, texels.high);\r
+      block->texels = texels_wide;\r
+      block->draw_mask_bits = left_mask_bits_b;\r
+      block->fb_ptr = fb_ptr + 8;\r
+      block++;  \r
+      \r
+      block->texels = texels_wide;\r
+      block->draw_mask_bits = left_mask_bits_b;\r
+      block->fb_ptr = fb_ptr + 8 + 1024;\r
+      block++;  \r
+      \r
+      texture_offset += 8;\r
+      fb_ptr += 16;\r
+\r
+      while(blocks_remaining)\r
+      {\r
+        texture_block_ptr = texture_page_ptr + (texture_offset & texture_mask);\r
+        load_128b(texels, texture_block_ptr);\r
+\r
+        zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.low, texels.low);\r
+        block->texels = texels_wide;\r
+        block->draw_mask_bits = 0;\r
+        block->fb_ptr = fb_ptr;\r
+        block++;\r
+        \r
+        block->texels = texels_wide;\r
+        block->draw_mask_bits = 0;\r
+        block->fb_ptr = fb_ptr + 1024;\r
+        block++;      \r
+\r
+        zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.high, texels.high);\r
+        block->texels = texels_wide;\r
+        block->draw_mask_bits = 0;\r
+        block->fb_ptr = fb_ptr + 8;\r
+        block++;\r
+        \r
+        block->texels = texels_wide;\r
+        block->draw_mask_bits = 0;\r
+        block->fb_ptr = fb_ptr + 8 + 1024;\r
+        block++;\r
+        \r
+        texture_offset += 8;\r
+        fb_ptr += 16;\r
+\r
+        blocks_remaining--;\r
+      }\r
+\r
+      texture_block_ptr = texture_page_ptr + (texture_offset & texture_mask);\r
+      load_128b(texels, texture_block_ptr);\r
+      \r
+      zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.low, texels.low);\r
+      block->texels = texels_wide;\r
+      block->draw_mask_bits = right_mask_bits_a;\r
+      block->fb_ptr = fb_ptr;\r
+      block++;\r
+      \r
+      block->texels = texels_wide;\r
+      block->draw_mask_bits = right_mask_bits_a;\r
+      block->fb_ptr = fb_ptr + 1024;\r
+      block++;      \r
+\r
+      zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.high, texels.high);\r
+      block->texels = texels_wide;\r
+      block->draw_mask_bits = right_mask_bits_b;\r
+      block->fb_ptr = fb_ptr + 8;\r
+      block++;\r
+\r
+      block->texels = texels_wide;\r
+      block->draw_mask_bits = right_mask_bits_b;\r
+      block->fb_ptr = fb_ptr + 8 + 1024;      \r
+      block++;\r
+\r
+      fb_ptr += fb_ptr_pitch;\r
+\r
+      height--;\r
+      psx_gpu->num_blocks = num_blocks;\r
+    }\r
+  }\r
+}\r
+\r
+#endif\r
+\r
+static void setup_sprite_untextured_4x(psx_gpu_struct *psx_gpu, s32 x, s32 y,\r
+ s32 u, s32 v, s32 width, s32 height, u32 color)\r
+{\r
+  setup_sprite_untextured(psx_gpu, x, y, u, v, width * 2, height * 2, color);\r
+}\r
+\r
+#define setup_sprite_blocks_switch_textured_4x(texture_mode)                   \\r
+  setup_sprite_##texture_mode##_4x                                             \\r
+\r
+#define setup_sprite_blocks_switch_untextured_4x(texture_mode)                 \\r
+  setup_sprite_untextured_4x                                                   \\r
+\r
+#define setup_sprite_blocks_switch_4x(texturing, texture_mode)                 \\r
+  setup_sprite_blocks_switch_##texturing##_4x(texture_mode)                    \\r
+\r
+  \r
+#define render_sprite_blocks_switch_block_modulation_4x(texture_mode,          \\r
+ blend_mode, mask_evaluate, shading, dithering, texturing, blending,           \\r
+ modulation)                                                                   \\r
+{                                                                              \\r
+  setup_sprite_blocks_switch_4x(texturing, texture_mode),                      \\r
+  texture_sprite_blocks_switch_##texturing(texture_mode),                      \\r
+  shade_blocks_switch(unshaded, texturing, modulation, undithered, blending,   \\r
+   mask_evaluate),                                                             \\r
+  blend_blocks_switch(texturing, blending, blend_mode, mask_evaluate)          \\r
+}                                                                              \\r
+\r
+#define render_sprite_blocks_switch_block_blending_4x(texture_mode,            \\r
+ blend_mode, mask_evaluate, shading, dithering, texturing, blending)           \\r
+  render_sprite_blocks_switch_block_modulation_4x(texture_mode, blend_mode,    \\r
+   mask_evaluate, shading, dithering, texturing, blending, modulated),         \\r
+  render_sprite_blocks_switch_block_modulation_4x(texture_mode, blend_mode,    \\r
+   mask_evaluate, shading, dithering, texturing, blending, unmodulated)        \\r
+\r
+#define render_sprite_blocks_switch_block_texturing_4x(texture_mode,           \\r
+ blend_mode, mask_evaluate, shading, dithering, texturing)                     \\r
+  render_sprite_blocks_switch_block_blending_4x(texture_mode, blend_mode,      \\r
+   mask_evaluate, shading, dithering, texturing, unblended),                   \\r
+  render_sprite_blocks_switch_block_blending_4x(texture_mode, blend_mode,      \\r
+   mask_evaluate, shading, dithering, texturing, blended)                      \\r
+\r
+#define render_sprite_blocks_switch_block_dithering_4x(texture_mode,           \\r
+ blend_mode, mask_evaluate, shading, dithering)                                \\r
+  render_sprite_blocks_switch_block_texturing_4x(texture_mode, blend_mode,     \\r
+   mask_evaluate, shading, dithering, untextured),                             \\r
+  render_sprite_blocks_switch_block_texturing_4x(texture_mode, blend_mode,     \\r
+   mask_evaluate, shading, dithering, textured)                                \\r
+\r
+#define render_sprite_blocks_switch_block_shading_4x(texture_mode, blend_mode, \\r
+ mask_evaluate, shading)                                                       \\r
+  render_sprite_blocks_switch_block_dithering_4x(texture_mode, blend_mode,     \\r
+   mask_evaluate, shading, undithered),                                        \\r
+  render_sprite_blocks_switch_block_dithering_4x(texture_mode, blend_mode,     \\r
+   mask_evaluate, shading, dithered)                                           \\r
+\r
+#define render_sprite_blocks_switch_block_mask_evaluate_4x(texture_mode,       \\r
+ blend_mode, mask_evaluate)                                                    \\r
+  render_sprite_blocks_switch_block_shading_4x(texture_mode, blend_mode,       \\r
+   mask_evaluate, unshaded),                                                   \\r
+  render_sprite_blocks_switch_block_shading_4x(texture_mode, blend_mode,       \\r
+   mask_evaluate, shaded)                                                      \\r
+\r
+#define render_sprite_blocks_switch_block_blend_mode_4x(texture_mode,          \\r
+ blend_mode)                                                                   \\r
+  render_sprite_blocks_switch_block_mask_evaluate_4x(texture_mode, blend_mode, \\r
+   off),                                                                       \\r
+  render_sprite_blocks_switch_block_mask_evaluate_4x(texture_mode, blend_mode, \\r
+   on)                                                                         \\r
+\r
+#define render_sprite_blocks_switch_block_texture_mode_4x(texture_mode)        \\r
+  render_sprite_blocks_switch_block_blend_mode_4x(texture_mode, average),      \\r
+  render_sprite_blocks_switch_block_blend_mode_4x(texture_mode, add),          \\r
+  render_sprite_blocks_switch_block_blend_mode_4x(texture_mode, subtract),     \\r
+  render_sprite_blocks_switch_block_blend_mode_4x(texture_mode, add_fourth)    \\r
+\r
+#define render_sprite_blocks_switch_block_4x()                                 \\r
+  render_sprite_blocks_switch_block_texture_mode_4x(4bpp),                     \\r
+  render_sprite_blocks_switch_block_texture_mode_4x(8bpp),                     \\r
+  render_sprite_blocks_switch_block_texture_mode_4x(16bpp),                    \\r
+  render_sprite_blocks_switch_block_texture_mode_4x(4bpp)                      \\r
+\r
+\r
+render_block_handler_struct render_sprite_block_handlers_4x[] =\r
+{\r
+  render_sprite_blocks_switch_block_4x()\r
+};\r
+\r
+\r
+void render_sprite_4x(psx_gpu_struct *psx_gpu, s32 x, s32 y, u32 u, u32 v,\r
+ s32 width, s32 height, u32 flags, u32 color)\r
+{\r
+  s32 x_right = x + width - 1;\r
+  s32 y_bottom = y + height - 1;\r
+\r
+#ifdef PROFILE\r
+  sprites++;\r
+#endif\r
+\r
+  if(x < psx_gpu->viewport_start_x)\r
+  {\r
+    u32 clip = psx_gpu->viewport_start_x - x;\r
+    x += clip;\r
+    u += clip;\r
+    width -= clip;\r
+  }\r
+\r
+  if(y < psx_gpu->viewport_start_y)\r
+  {\r
+    s32 clip = psx_gpu->viewport_start_y - y;\r
+    y += clip;\r
+    v += clip;\r
+    height -= clip;\r
+  }\r
+\r
+  if(x_right > psx_gpu->viewport_end_x)\r
+    width -= x_right - psx_gpu->viewport_end_x;\r
+\r
+  if(y_bottom > psx_gpu->viewport_end_y)\r
+    height -= y_bottom - psx_gpu->viewport_end_y;\r
+\r
+  if((width <= 0) || (height <= 0))\r
+    return;\r
+\r
+  psx_gpu->vram_out_ptr = select_enhancement_buf_ptr(psx_gpu, x);\r
+\r
+  x *= 2;\r
+  y *= 2;\r
+\r
+#ifdef PROFILE\r
+  span_pixels += width * height;\r
+  spans += height;\r
+#endif\r
+\r
+  u32 render_state = flags &\r
+   (RENDER_FLAGS_MODULATE_TEXELS | RENDER_FLAGS_BLEND |\r
+   RENDER_FLAGS_TEXTURE_MAP);\r
+  render_state |=\r
+   (psx_gpu->render_state_base & ~RENDER_STATE_DITHER);\r
+\r
+  if((psx_gpu->render_state != render_state) ||\r
+   (psx_gpu->primitive_type != PRIMITIVE_TYPE_SPRITE))\r
+  {\r
+    psx_gpu->render_state = render_state;\r
+    flush_render_block_buffer(psx_gpu);\r
+#ifdef PROFILE\r
+    state_changes++;\r
+#endif\r
+  }\r
+\r
+  psx_gpu->primitive_type = PRIMITIVE_TYPE_SPRITE;\r
+\r
+  color &= 0xFFFFFF;\r
+\r
+  if(psx_gpu->triangle_color != color)\r
+  {\r
+    flush_render_block_buffer(psx_gpu);\r
+    psx_gpu->triangle_color = color;\r
+  }\r
+\r
+  if(color == 0x808080)\r
+    render_state |= RENDER_FLAGS_MODULATE_TEXELS;\r
+\r
+  render_block_handler_struct *render_block_handler =\r
+   &(render_sprite_block_handlers_4x[render_state]);\r
+  psx_gpu->render_block_handler = render_block_handler;\r
+\r
+  ((setup_sprite_function_type *)render_block_handler->setup_blocks)\r
+   (psx_gpu, x, y, u, v, width, height, color);\r
+}\r
+\r
index 294685a..344331d 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2011 Gilead Kutnick "Exophase" <exophase@gmail.com>
+ * Copyright (C) 2012 Gražvydas Ignotas "notaz" <notasas@gmail.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
 #define MAX_BLOCKS                                        64
 #define MAX_BLOCKS_PER_ROW                                128
 
-#define psx_gpu_test_mask_offset                          0
-#define psx_gpu_uvrg_offset                               16
-#define psx_gpu_uvrg_dx_offset                            32
-#define psx_gpu_uvrg_dy_offset                            48
-#define psx_gpu_u_block_span_offset                       64
-#define psx_gpu_v_block_span_offset                       80
-#define psx_gpu_r_block_span_offset                       96
-#define psx_gpu_g_block_span_offset                       112
-#define psx_gpu_b_block_span_offset                       128
-
-#define psx_gpu_b_dx_offset                               132
-
-#define psx_gpu_b_offset                                  144
-#define psx_gpu_b_dy_offset                               148
-#define psx_gpu_triangle_area_offset                      152
-#define psx_gpu_texture_window_settings_offset            156
-#define psx_gpu_current_texture_mask_offset               160
-#define psx_gpu_viewport_mask_offset                      164
-#define psx_gpu_dirty_textures_4bpp_mask_offset           168
-#define psx_gpu_dirty_textures_8bpp_mask_offset           172
-#define psx_gpu_dirty_textures_8bpp_alternate_mask_offset 176
-#define psx_gpu_triangle_color_offset                     180
-#define psx_gpu_dither_table_offset                       184
-#define psx_gpu_render_block_handler_offset               200
-#define psx_gpu_texture_page_ptr_offset                   204
-#define psx_gpu_texture_page_base_offset                  208
-#define psx_gpu_clut_ptr_offset                           212
-#define psx_gpu_vram_ptr_offset                           216
-
-#define psx_gpu_render_state_base_offset                  220
-#define psx_gpu_render_state_offset                       222
-#define psx_gpu_num_spans_offset                          224
-#define psx_gpu_num_blocks_offset                         226
-#define psx_gpu_offset_x_offset                           228
-#define psx_gpu_offset_y_offset                           230
-#define psx_gpu_clut_settings_offset                      232
-#define psx_gpu_texture_settings_offset                   234
-#define psx_gpu_viewport_start_x_offset                   236
-#define psx_gpu_viewport_start_y_offset                   238
-#define psx_gpu_viewport_end_x_offset                     240
-#define psx_gpu_viewport_end_y_offset                     242
-#define psx_gpu_mask_msb_offset                           244
-                                                          
-#define psx_gpu_triangle_winding_offset                   246
-#define psx_gpu_display_area_draw_enable_offset           247
-#define psx_gpu_current_texture_page_offset               248
-#define psx_gpu_last_8bpp_texture_page_offset             249
-#define psx_gpu_texture_mask_width_offset                 250
-#define psx_gpu_texture_mask_height_offset                251
-#define psx_gpu_texture_window_x_offset                   252
-#define psx_gpu_texture_window_y_offset                   253
-#define psx_gpu_primitive_type_offset                     254
-
-#define psx_gpu_reserved_a_offset                         255
-
-#define psx_gpu_blocks_offset                             0x0100
-#define psx_gpu_span_uvrg_offset_offset                   0x2100
-#define psx_gpu_span_edge_data_offset                     0x4100
-#define psx_gpu_span_b_offset_offset                      0x5100
+#define RENDER_STATE_MASK_EVALUATE                        0x20
+#define RENDER_FLAGS_MODULATE_TEXELS                      0x1
+#define RENDER_FLAGS_BLEND                                0x2
+#define RENDER_INTERLACE_ENABLED                          0x1
+
+#include "psx_gpu_offsets.h"
+
+#define psx_gpu_b_dx_offset (psx_gpu_b_block_span_offset + 4)
 
 #define edge_data_left_x_offset                           0
 #define edge_data_num_blocks_offset                       2
 #define uvrg_dx3l                                         d6
 #define uvrg_dx3h                                         d7
 
+#define uvrgb_phase                                       q13
 
 .align 4
 
@@ -369,11 +320,16 @@ function(compute_all_gradients)
   vmull.s16 ga_uvrg_y, d0_b, d1_b
   rsbmi ga_bx, ga_bx, #0
 
+  @ r12 = psx_gpu->uvrgb_phase
+  ldr r12, [ psx_gpu, #psx_gpu_uvrgb_phase_offset ]
+
   vmlsl.s16 ga_uvrg_y, d2_b, d3_b
   movs gs_by, ga_by, asr #31
 
   vshr.u64 d0, d30, #22
-  mov b_base, b0, lsl #16
+  add b_base, r12, b0, lsl #16
+
+  vdup.u32 uvrgb_phase, r12
 
   rsbmi ga_by, ga_by, #0
   vclt.s32 gs_uvrg_x, ga_uvrg_x, #0  @ gs_uvrg_x = ga_uvrg_x < 0
@@ -382,7 +338,6 @@ function(compute_all_gradients)
   ldrb r12, [ psx_gpu, #psx_gpu_triangle_winding_offset ]
   vclt.s32 gs_uvrg_y, ga_uvrg_y, #0  @ gs_uvrg_y = ga_uvrg_y < 0
 
-  add b_base, b_base, #0x8000
   rsb r12, r12, #0                   @ r12 = -(triangle->winding)
 
   vdup.u32 w_mask, r12               @ w_mask = { -w, -w, -w, -w }
@@ -391,7 +346,7 @@ function(compute_all_gradients)
   vshll.u16 uvrg_base, uvrg0, #16    @ uvrg_base = uvrg0 << 16
   vdup.u32 r_shift, r14              @ r_shift = { shift, shift, shift, shift }
 
-  vorr.u32 uvrg_base, #0x8000
+  vadd.u32 uvrg_base, uvrgb_phase
   vabs.s32 ga_uvrg_x, ga_uvrg_x      @ ga_uvrg_x = abs(ga_uvrg_x)
 
   vmov area_r_s, s0                  @ area_r_s = triangle_reciprocal
@@ -657,7 +612,7 @@ function(compute_all_gradients)
                                                                                \
   vdup.u32 edge_shifts, temp;                                                  \
   vsub.u32 heights_b, heights, c_0x01;                                         \
-  vshr.u32 height_reciprocals, edge_shifts, #12;                               \
+  vshr.u32 height_reciprocals, edge_shifts, #10;                               \
                                                                                \
   vmla.s32 heights_b, x_starts, heights;                                       \
   vbic.u16 edge_shifts, #0xE0;                                                 \
@@ -682,8 +637,8 @@ function(compute_all_gradients)
   vsub.u32 heights_b, heights, c_0x01;                                         \
   sub height_b_alt, height_minor_b, #1;                                        \
                                                                                \
-  vshr.u32 height_reciprocals, edge_shifts, #12;                               \
-  lsr height_reciprocal_alt, edge_shift_alt, #12;                              \
+  vshr.u32 height_reciprocals, edge_shifts, #10;                               \
+  lsr height_reciprocal_alt, edge_shift_alt, #10;                              \
                                                                                \
   vmla.s32 heights_b, x_starts, heights;                                       \
   mla height_b_alt, height_minor_b, start_c, height_b_alt;                     \
@@ -1221,6 +1176,10 @@ function(setup_spans_up_down)
 
   ldrh temp, [ psx_gpu, #psx_gpu_num_spans_offset ]
   add temp, temp, height_minor_b
+
+  cmp temp, #MAX_SPANS
+  beq 5f
+
   strh temp, [ psx_gpu, #psx_gpu_num_spans_offset ]
 
  2:                                                     
@@ -1236,6 +1195,15 @@ function(setup_spans_up_down)
   setup_spans_prologue_b()
   bal 4b
 
+ 5:
+  // FIXME: overflow corner case
+  sub temp, temp, height_minor_b
+  bics height_minor_b, #3
+  add temp, temp, height_minor_b
+  strh temp, [ psx_gpu, #psx_gpu_num_spans_offset ]
+  bne 2b
+  bal 1b
+
 .pool
 
 #undef span_uvrg_offset
@@ -1393,7 +1361,7 @@ function(setup_blocks_shaded_textured_dithered_##swizzling##_indirect)         \
   add dither_offset_ptr, psx_gpu, #psx_gpu_dither_table_offset;                \
                                                                                \
   ldrh y, [ span_edge_data, #edge_data_y_offset ];                             \
-  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_ptr_offset ];                           \
+  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_out_ptr_offset ];                       \
                                                                                \
   cmp span_num_blocks, #0;                                                     \
   beq 1f;                                                                      \
@@ -1660,7 +1628,7 @@ function(setup_blocks_unshaded_textured_dithered_##swizzling##_indirect)       \
   add dither_offset_ptr, psx_gpu, #psx_gpu_dither_table_offset;                \
                                                                                \
   ldrh y, [ span_edge_data, #edge_data_y_offset ];                             \
-  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_ptr_offset ];                           \
+  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_out_ptr_offset ];                       \
                                                                                \
   cmp span_num_blocks, #0;                                                     \
   beq 1f;                                                                      \
@@ -1855,7 +1823,7 @@ function(setup_blocks_unshaded_untextured_undithered_unswizzled_indirect)
   ldrh span_num_blocks, [ span_edge_data, #edge_data_num_blocks_offset ]
   ldrh y, [ span_edge_data, #edge_data_y_offset ]
 
-  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_ptr_offset ]
+  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_out_ptr_offset ]
 
   cmp span_num_blocks, #0
   beq 1f
@@ -1975,7 +1943,7 @@ function(setup_blocks_unshaded_untextured_undithered_unswizzled_direct)
   ldrh span_num_blocks, [ span_edge_data, #edge_data_num_blocks_offset ]
   ldrh y, [ span_edge_data, #edge_data_y_offset ]
 
-  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_ptr_offset ]
+  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_out_ptr_offset ]
 
   cmp span_num_blocks, #0
   beq 1f
@@ -2162,7 +2130,7 @@ function(setup_blocks_shaded_untextured_##dithering##_unswizzled_indirect)     \
   add dither_offset_ptr, psx_gpu, #psx_gpu_dither_table_offset;                \
                                                                                \
   ldrh y, [ span_edge_data, #edge_data_y_offset ];                             \
-  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_ptr_offset ];                           \
+  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_out_ptr_offset ];                       \
                                                                                \
   cmp span_num_blocks, #0;                                                     \
   beq 1f;                                                                      \
@@ -2402,7 +2370,7 @@ function(setup_blocks_shaded_untextured_##dithering##_unswizzled_direct)       \
   add dither_offset_ptr, psx_gpu, #psx_gpu_dither_table_offset;                \
                                                                                \
   ldrh y, [ span_edge_data, #edge_data_y_offset ];                             \
-  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_ptr_offset ];                           \
+  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_out_ptr_offset ];                       \
                                                                                \
   cmp span_num_blocks, #0;                                                     \
   beq 1f;                                                                      \
@@ -3239,6 +3207,7 @@ function(shade_blocks_##shading##_textured_modulated_##dithering##_##target)   \
   shade_blocks_textured_modulated_load_bdm_##shading();                        \
   vshrn.u16 texels_b, texels, #7;                                              \
                                                                                \
+  pld [ block_ptr_load_a ];                                                    \
   vmovn.u16 texels_r, texels;                                                  \
   vmlal.u8 pixels, pixels_r_low, d64_1;                                        \
                                                                                \
@@ -3437,10 +3406,12 @@ function(shade_blocks_textured_unmodulated_direct)
    [ draw_mask_bits_ptr, :16 ], c_64
   vbif.u16 fb_pixels, pixels, draw_mask_combined
 
-  vld1.u32 { pixels }, [ block_ptr_load, :128 ], c_64
-
   sub fb_ptr_cmp, fb_ptr_next, fb_ptr
+  pld [ fb_ptr_next, #64 ]
+
   add fb_ptr_cmp, fb_ptr_cmp, #14
+  vld1.u32 { pixels }, [ block_ptr_load, :128 ], c_64
+
   cmp fb_ptr_cmp, #28
   bls 4f
 
@@ -3799,11 +3770,15 @@ function(blend_blocks_textured_add_##mask_evaluate)                            \
   vorr.u16 blend_pixels, fb_pixels_rb, fb_pixels_g;                            \
   vand.u16 pixels_mg, pixels, d128_0x83E0;                                     \
                                                                                \
-  vbit.u16 blend_pixels, fb_pixels, draw_mask;                                 \
-  vld1.u32 { draw_mask }, [ draw_mask_ptr, :128 ], c_64;                       \
+  sub fb_ptr_cmp, fb_ptr_next, fb_ptr;                                         \
+  pld [ fb_ptr_next, #64 ];                                                    \
                                                                                \
   sub fb_ptr_cmp, fb_ptr_next, fb_ptr;                                         \
+  vbit.u16 blend_pixels, fb_pixels, draw_mask;                                 \
+                                                                               \
   add fb_ptr_cmp, fb_ptr_cmp, #14;                                             \
+  vld1.u32 { draw_mask }, [ draw_mask_ptr, :128 ], c_64;                       \
+                                                                               \
   cmp fb_ptr_cmp, #28;                                                         \
   bls 2f;                                                                      \
                                                                                \
@@ -4456,6 +4431,12 @@ function(render_block_fill_body)
 #define draw_mask_fb_ptr_left                             d2
 #define draw_mask_fb_ptr_right                            d3
 
+#define draw_mask_fb_ptr_left_a                           d2
+#define draw_mask_fb_ptr_left_b                           d3
+#define draw_mask_fb_ptr_right_a                          d10
+#define draw_mask_fb_ptr_right_b                          d11
+#define draw_masks_fb_ptrs2                               q5
+
 #define clut_low_a                                        d4
 #define clut_low_b                                        d5
 #define clut_high_a                                       d6
@@ -4467,37 +4448,24 @@ function(render_block_fill_body)
 #define clut_a                                            q2
 #define clut_b                                            q3
 
-#define texels_low                                        d10
-#define texels_high                                       d11
-
+#define texels_low                                        d12
+#define texels_high                                       d13
 
-setup_sprite_flush_blocks_single:
-  vpush { q1 - q4 }
-
-  stmdb sp!, { r0 - r3, r12, r14 }
-  bl flush_render_block_buffer
-  ldmia sp!, { r0 - r3, r12, r14 }
-
-  vpop { q1 - q4 }
-
-  add block, psx_gpu, #psx_gpu_blocks_offset
-
-  mov num_blocks, sub_tile_height
-  bx lr
+#define texels_wide_low                                   d14
+#define texels_wide_high                                  d15
+#define texels_wide                                       q7
 
 
-setup_sprite_flush_blocks_double:
-  vpush { q1 - q4 }
+setup_sprite_flush_blocks:
+  vpush { q1 - q5 }
 
   stmdb sp!, { r0 - r3, r12, r14 }
   bl flush_render_block_buffer
   ldmia sp!, { r0 - r3, r12, r14 }
 
-  vpop { q1 - q4 }
+  vpop { q1 - q5 }
 
   add block, psx_gpu, #psx_gpu_blocks_offset
-
-  mov num_blocks, sub_tile_height, lsl #1
   bx lr
 
 
@@ -4535,8 +4503,6 @@ setup_sprite_update_texture_8bpp_cache:
   blne setup_sprite_update_texture_8bpp_cache                                  \
 
 
-#define setup_sprite_tile_setup_block_no(side, offset, texture_mode)           \
-
 #define setup_sprite_block_count_single()                                      \
   sub_tile_height                                                              \
 
@@ -4547,7 +4513,8 @@ setup_sprite_update_texture_8bpp_cache:
   add num_blocks, num_blocks, setup_sprite_block_count_##type();               \
   cmp num_blocks, #MAX_BLOCKS;                                                 \
                                                                                \
-  blgt setup_sprite_flush_blocks_##type                                        \
+  movgt num_blocks, setup_sprite_block_count_##type();                         \
+  blgt setup_sprite_flush_blocks                                               \
 
 
 #define setup_sprite_tile_full_4bpp(edge)                                      \
@@ -4729,31 +4696,33 @@ setup_sprite_update_texture_8bpp_cache:
 #define setup_sprite_tile_column_edge_post_adjust_full(edge)                   \
 
 
-#define setup_sprite_tile_column_height_single(edge_mode, edge, texture_mode)  \
+#define setup_sprite_tile_column_height_single(edge_mode, edge, texture_mode,  \
+ x4mode)                                                                       \
   mov sub_tile_height, column_data;                                            \
-  setup_sprite_tile_column_edge_pre_adjust_##edge_mode(edge);                  \
-  setup_sprite_tile_##edge_mode##_##texture_mode(edge);                        \
-  setup_sprite_tile_column_edge_post_adjust_##edge_mode(edge)                  \
+  setup_sprite_tile_column_edge_pre_adjust_##edge_mode##x4mode(edge);          \
+  setup_sprite_tile_##edge_mode##_##texture_mode##x4mode(edge);                \
+  setup_sprite_tile_column_edge_post_adjust_##edge_mode##x4mode(edge)          \
 
-#define setup_sprite_tile_column_height_multi(edge_mode, edge, texture_mode)   \
+#define setup_sprite_tile_column_height_multi(edge_mode, edge, texture_mode,   \
+ x4mode)                                                                       \
   and sub_tile_height, column_data, #0xFF;                                     \
   mov tiles_remaining, column_data, lsr #16;                                   \
-  setup_sprite_tile_column_edge_pre_adjust_##edge_mode(edge);                  \
-  setup_sprite_tile_##edge_mode##_##texture_mode(edge);                        \
+  setup_sprite_tile_column_edge_pre_adjust_##edge_mode##x4mode(edge);          \
+  setup_sprite_tile_##edge_mode##_##texture_mode##x4mode(edge);                \
                                                                                \
   subs tiles_remaining, tiles_remaining, #1;                                   \
   beq 2f;                                                                      \
                                                                                \
  3:                                                                            \
   mov sub_tile_height, #16;                                                    \
-  setup_sprite_tile_##edge_mode##_##texture_mode(edge);                        \
+  setup_sprite_tile_##edge_mode##_##texture_mode##x4mode(edge);                \
   subs tiles_remaining, tiles_remaining, #1;                                   \
   bne 3b;                                                                      \
                                                                                \
  2:                                                                            \
   uxtb sub_tile_height, column_data, ror #8;                                   \
-  setup_sprite_tile_##edge_mode##_##texture_mode(edge);                        \
-  setup_sprite_tile_column_edge_post_adjust_##edge_mode(edge)                  \
+  setup_sprite_tile_##edge_mode##_##texture_mode##x4mode(edge);                \
+  setup_sprite_tile_column_edge_post_adjust_##edge_mode##x4mode(edge)          \
 
 
 #define setup_sprite_column_data_single()                                      \
@@ -4772,17 +4741,30 @@ setup_sprite_update_texture_8bpp_cache:
                                                                                \
   orr column_data, column_data, height_rounded, lsl #8                         \
 
-#define setup_sprite_tile_column_width_single(texture_mode, multi_height,      \
- edge_mode, edge)                                                              \
- setup_sprite_##texture_mode##_single_##multi_height##_##edge_mode##_##edge:   \
+#define setup_sprite_setup_left_draw_mask_fb_ptr()                             \
+  vdup.u8 draw_mask_fb_ptr_left, block_masks[0];                               \
+  vdup.u8 draw_mask_fb_ptr_right, block_masks[1]                               \
+
+#define setup_sprite_setup_left_draw_mask_fb_ptr_advance_column()              \
+  mov fb_ptr_advance_column, #32;                                              \
+  vdup.u8 draw_mask_fb_ptr_left, block_masks[0];                               \
+                                                                               \
+  sub fb_ptr_advance_column, height, lsl #11;                                  \
+  vdup.u8 draw_mask_fb_ptr_right, block_masks[1]                               \
+
+#define setup_sprite_setup_right_draw_mask_fb_ptr()                            \
+  vdup.u8 draw_mask_fb_ptr_left, block_masks[4];                               \
+  vdup.u8 draw_mask_fb_ptr_right, block_masks[5]                               \
+
+#define setup_sprite_tile_column_width_single(tm, multi_height, edge_mode,     \
+ edge, x4mode)                                                                 \
+ setup_sprite_##tm##_single_##multi_height##_##edge_mode##_##edge##x4mode:     \
   setup_sprite_column_data_##multi_height();                                   \
   vext.32 block_masks_shifted, block_masks, block_masks, #1;                   \
   vorr.u32 block_masks, block_masks, block_masks_shifted;                      \
-  vdup.u8 draw_mask_fb_ptr_left, block_masks[0];                               \
-  vdup.u8 draw_mask_fb_ptr_right, block_masks[1];                              \
+  setup_sprite_setup_left_draw_mask_fb_ptr##x4mode();                          \
                                                                                \
-  setup_sprite_tile_column_height_##multi_height(edge_mode, edge,              \
-   texture_mode);                                                              \
+  setup_sprite_tile_column_height_##multi_height(edge_mode, edge, tm, x4mode); \
   ldmia sp!, { r4 - r11, pc }                                                  \
 
 #define setup_sprite_tiled_advance_column()                                    \
@@ -4791,39 +4773,337 @@ setup_sprite_update_texture_8bpp_cache:
   subeq texture_offset_base, texture_offset_base, #(0x100 + 0xF00)             \
 
 #define setup_sprite_tile_column_width_multi(tm, multi_height, left_mode,      \
- right_mode)                                                                   \
- setup_sprite_##tm##_multi_##multi_height##_##left_mode##_##right_mode:        \
+ right_mode, x4mode)                                                           \
+ setup_sprite_##tm##_multi_##multi_height##_##left_mode##_##right_mode##x4mode:\
   setup_sprite_column_data_##multi_height();                                   \
-  mov fb_ptr_advance_column, #32;                                              \
                                                                                \
-  sub fb_ptr_advance_column, height, lsl #11;                                  \
-  vdup.u8 draw_mask_fb_ptr_left, block_masks[0];                               \
+  setup_sprite_setup_left_draw_mask_fb_ptr_advance_column##x4mode();           \
                                                                                \
-  vdup.u8 draw_mask_fb_ptr_right, block_masks[1];                              \
-  setup_sprite_tile_column_height_##multi_height(left_mode, right, tm);        \
+  setup_sprite_tile_column_height_##multi_height(left_mode, right, tm, x4mode);\
                                                                                \
   subs tile_width, tile_width, #2;                                             \
   add fb_ptr, fb_ptr, fb_ptr_advance_column;                                   \
                                                                                \
-  vmov.u8 draw_masks_fb_ptrs, #0;                                              \
   beq 1f;                                                                      \
                                                                                \
+  vmov.u8 draw_masks_fb_ptrs, #0;                                              \
+  vmov.u8 draw_masks_fb_ptrs2, #0;                                             \
+                                                                               \
  0:                                                                            \
   setup_sprite_tiled_advance_column();                                         \
-  setup_sprite_tile_column_height_##multi_height(full, none, tm);              \
+  setup_sprite_tile_column_height_##multi_height(full, none, tm, x4mode);      \
   add fb_ptr, fb_ptr, fb_ptr_advance_column;                                   \
   subs tile_width, tile_width, #1;                                             \
   bne 0b;                                                                      \
                                                                                \
  1:                                                                            \
-  vdup.u8 draw_mask_fb_ptr_left, block_masks[4];                               \
-  vdup.u8 draw_mask_fb_ptr_right, block_masks[5];                              \
+  setup_sprite_setup_right_draw_mask_fb_ptr##x4mode();                         \
                                                                                \
   setup_sprite_tiled_advance_column();                                         \
-  setup_sprite_tile_column_height_##multi_height(right_mode, left, tm);        \
+  setup_sprite_tile_column_height_##multi_height(right_mode, left, tm, x4mode);\
   ldmia sp!, { r4 - r11, pc }                                                  \
 
 
+#define setup_sprite_offset_u_adjust()                                         \
+
+#define setup_sprite_get_left_block_mask()                                     \
+  and left_block_mask, left_block_mask, #0xFF                                  \
+
+#define setup_sprite_compare_left_block_mask()                                 \
+  cmp left_block_mask, #0xFF                                                   \
+
+#define setup_sprite_get_right_block_mask()                                    \
+  uxtb right_block_mask, right_block_mask, ror #8                              \
+
+#define setup_sprite_compare_right_block_mask()                                \
+  cmp right_block_mask, #0xFF                                                  \
+
+
+
+/* 4x stuff */
+#define fb_ptr2 column_data
+
+#define setup_sprite_offset_u_adjust_4x()                                      \
+  sub fb_ptr, fb_ptr, offset_u, lsl #1;                                        \
+  lsl offset_u_right, #1;                                                      \
+  lsl offset_u, #1;                                                            \
+  add offset_u_right, #1                                                       \
+
+#define setup_sprite_get_left_block_mask_4x()                                  \
+  sxth left_block_mask, left_block_mask                                        \
+
+#define setup_sprite_compare_left_block_mask_4x()                              \
+  cmp left_block_mask, #0xFFFFFFFF                                             \
+
+#define setup_sprite_get_right_block_mask_4x()                                 \
+  sxth right_block_mask, right_block_mask, ror #16                             \
+
+#define setup_sprite_compare_right_block_mask_4x()                             \
+  cmp right_block_mask, #0xFFFFFFFF                                            \
+
+
+#define widen_texels_16bpp(texels_)                                            \
+  vmov texels_wide_low, texels_;                                               \
+  vmov texels_wide_high, texels_;                                              \
+  vzip.16 texels_wide_low, texels_wide_high                                    \
+
+#define widen_texels_8bpp(texels_)                                             \
+  vmov texels_wide_low, texels_;                                               \
+  vmov texels_wide_high, texels_;                                              \
+  vzip.8 texels_wide_low, texels_wide_high                                     \
+
+#define write_block_16bpp(texels_, block_, draw_mask_fb_ptr_, fb_ptr_)         \
+  vst1.u32 { texels_ }, [ block_, :128 ];                                      \
+  add block_, block_, #40;                                                     \
+                                                                               \
+  vmov.u32 draw_mask_fb_ptr_[1], fb_ptr_;                                      \
+  vst1.u32 { draw_mask_fb_ptr_ }, [ block_, :64 ];                             \
+  add block_, block_, #24                                                      \
+
+/* assumes 16-byte offset already added to block_ */
+#define write_block_8bpp(texels_, block_, draw_mask_fb_ptr_, fb_ptr_)          \
+  vst1.u32 { texels_ }, [ block_, :64 ];                                       \
+  add block_, block_, #24;                                                     \
+                                                                               \
+  vmov.u32 draw_mask_fb_ptr_[1], fb_ptr_;                                      \
+  vst1.u32 { draw_mask_fb_ptr_ }, [ block_, :64 ];                             \
+  add block_, block_, #40                                                      \
+
+#define do_texture_block_16bpp_4x(fb_ptr_tmp, draw_mask_fb_ptr_a_,             \
+ draw_mask_fb_ptr_b_)                                                          \
+  widen_texels_16bpp(texels_low);                                              \
+  add fb_ptr_tmp, fb_ptr, #1024*2;                                             \
+                                                                               \
+  write_block_16bpp(texels_wide, block, draw_mask_fb_ptr_a_, fb_ptr);          \
+                                                                               \
+  write_block_16bpp(texels_wide, block, draw_mask_fb_ptr_a_, fb_ptr_tmp);      \
+  widen_texels_16bpp(texels_high);                                             \
+                                                                               \
+  add fb_ptr_tmp, fb_ptr, #8*2;                                                \
+  write_block_16bpp(texels_wide, block, draw_mask_fb_ptr_b_, fb_ptr_tmp);      \
+                                                                               \
+  add fb_ptr_tmp, fb_ptr_tmp, #1024*2;                                         \
+  write_block_16bpp(texels_wide, block, draw_mask_fb_ptr_b_, fb_ptr_tmp)       \
+
+#define do_texture_block_8bpp_4x(fb_ptr_tmp, draw_mask_fb_ptr_a_,              \
+ draw_mask_fb_ptr_b_)                                                          \
+  widen_texels_8bpp(texels);                                                   \
+  add fb_ptr_tmp, fb_ptr, #1024*2;                                             \
+                                                                               \
+  write_block_8bpp(texels_wide_low, block, draw_mask_fb_ptr_a_, fb_ptr);       \
+  write_block_8bpp(texels_wide_low, block, draw_mask_fb_ptr_a_, fb_ptr_tmp);   \
+                                                                               \
+  add fb_ptr_tmp, fb_ptr, #8*2;                                                \
+  write_block_8bpp(texels_wide_high, block, draw_mask_fb_ptr_b_, fb_ptr_tmp);  \
+                                                                               \
+  add fb_ptr_tmp, fb_ptr_tmp, #1024*2;                                         \
+  write_block_8bpp(texels_wide_high, block, draw_mask_fb_ptr_b_, fb_ptr_tmp)   \
+
+
+#define setup_sprite_tiled_initialize_4bpp_4x()                                \
+  ldr clut_ptr, [ psx_gpu, #psx_gpu_clut_ptr_offset ];                         \
+  vld1.u32 { clut_a, clut_b }, [ clut_ptr, :128 ];                             \
+                                                                               \
+  vuzp.u8 clut_a, clut_b                                                       \
+
+#define setup_sprite_tiled_initialize_8bpp_4x()                                \
+
+
+#define setup_sprite_block_count_single_4x()                                   \
+  sub_tile_height, lsl #2                                                      \
+
+#define setup_sprite_block_count_double_4x()                                   \
+  sub_tile_height, lsl #(1+2)                                                  \
+
+#define setup_sprite_tile_full_4bpp_4x(edge)                                   \
+  setup_sprite_tile_add_blocks(double_4x);                                     \
+  str column_data, [sp, #-8]!; /* fb_ptr2 */                                   \
+                                                                               \
+ 4:                                                                            \
+  and texture_block_ptr, texture_offset, texture_mask;                         \
+  pld [ fb_ptr ];                                                              \
+                                                                               \
+  add texture_block_ptr, texture_page_ptr, texture_block_ptr;                  \
+  vld1.u32 { texels }, [ texture_block_ptr, :64 ];                             \
+                                                                               \
+  add texture_block_ptr, texture_offset, #8;                                   \
+  vtbl.8 texels_low, { clut_low_a, clut_low_b }, texels;                       \
+                                                                               \
+  and texture_block_ptr, texture_block_ptr, texture_mask;                      \
+  vtbl.8 texels_high, { clut_high_a, clut_high_b }, texels;                    \
+                                                                               \
+  vzip.8 texels_low, texels_high;                                              \
+  do_texture_block_16bpp_4x(fb_ptr2, draw_mask_fb_ptr_left_a,                  \
+   draw_mask_fb_ptr_left_b);                                                   \
+                                                                               \
+  add texture_block_ptr, texture_page_ptr, texture_block_ptr;                  \
+  pld [ fb_ptr, #2048 ];                                                       \
+                                                                               \
+  vld1.u32 { texels }, [ texture_block_ptr, :64 ];                             \
+  add fb_ptr, fb_ptr, #16*2;                                                   \
+                                                                               \
+  vtbl.8 texels_low, { clut_low_a, clut_low_b }, texels;                       \
+  vtbl.8 texels_high, { clut_high_a, clut_high_b }, texels;                    \
+                                                                               \
+  vzip.8 texels_low, texels_high;                                              \
+  do_texture_block_16bpp_4x(fb_ptr2, draw_mask_fb_ptr_right_a,                 \
+   draw_mask_fb_ptr_right_b);                                                  \
+                                                                               \
+  add texture_offset, texture_offset, #0x10;                                   \
+  add fb_ptr, fb_ptr, #(2048 - 16) * 2;                                        \
+                                                                               \
+  subs sub_tile_height, sub_tile_height, #1;                                   \
+  bne 4b;                                                                      \
+                                                                               \
+  ldr column_data, [sp], #8; /* fb_ptr2 */                                     \
+  add texture_offset, texture_offset, #0xF00;                                  \
+  strh num_blocks, [ psx_gpu, #psx_gpu_num_blocks_offset ]                     \
+
+
+#define setup_sprite_tile_half_4bpp_4x(edge)                                   \
+  setup_sprite_tile_add_blocks(single_4x);                                     \
+  str column_data, [sp, #-8]!; /* fb_ptr2 */                                   \
+                                                                               \
+ 4:                                                                            \
+  and texture_block_ptr, texture_offset, texture_mask;                         \
+  pld [ fb_ptr ];                                                              \
+                                                                               \
+  add texture_block_ptr, texture_page_ptr, texture_block_ptr;                  \
+  vld1.u32 { texels }, [ texture_block_ptr, :64 ];                             \
+                                                                               \
+  add texture_block_ptr, texture_page_ptr, texture_block_ptr;                  \
+  vtbl.8 texels_low, { clut_low_a, clut_low_b }, texels;                       \
+                                                                               \
+  vtbl.8 texels_high, { clut_high_a, clut_high_b }, texels;                    \
+  add texture_offset, texture_offset, #0x10;                                   \
+                                                                               \
+  vzip.8 texels_low, texels_high;                                              \
+  do_texture_block_16bpp_4x(fb_ptr2, draw_mask_fb_ptr_##edge##_a,              \
+   draw_mask_fb_ptr_##edge##_b);                                               \
+                                                                               \
+  pld [ fb_ptr, #2048 ];                                                       \
+  add fb_ptr, fb_ptr, #2048 * 2;                                               \
+                                                                               \
+  subs sub_tile_height, sub_tile_height, #1;                                   \
+  bne 4b;                                                                      \
+                                                                               \
+  ldr column_data, [sp], #8; /* fb_ptr2 */                                     \
+  add texture_offset, texture_offset, #0xF00;                                  \
+  strh num_blocks, [ psx_gpu, #psx_gpu_num_blocks_offset ]                     \
+
+
+#define setup_sprite_tile_full_8bpp_4x(edge)                                   \
+  setup_sprite_tile_add_blocks(double_4x);                                     \
+  add block, block, #16;                                                       \
+  str column_data, [sp, #-8]!; /* fb_ptr2 */                                   \
+                                                                               \
+ 4:                                                                            \
+  and texture_block_ptr, texture_offset, texture_mask;                         \
+  pld [ fb_ptr ];                                                              \
+                                                                               \
+  add texture_block_ptr, texture_page_ptr, texture_block_ptr;                  \
+  vld1.u32 { texels }, [ texture_block_ptr, :64 ];                             \
+                                                                               \
+  add texture_block_ptr, texture_offset, #8;                                   \
+  do_texture_block_8bpp_4x(fb_ptr2, draw_mask_fb_ptr_left_a,                   \
+   draw_mask_fb_ptr_left_b);                                                   \
+                                                                               \
+  pld [ fb_ptr, #2048 ];                                                       \
+  and texture_block_ptr, texture_block_ptr, texture_mask;                      \
+                                                                               \
+  add fb_ptr, fb_ptr, #16*2;                                                   \
+  add texture_block_ptr, texture_page_ptr, texture_block_ptr;                  \
+                                                                               \
+  vld1.u32 { texels }, [ texture_block_ptr, :64 ];                             \
+                                                                               \
+  do_texture_block_8bpp_4x(fb_ptr2, draw_mask_fb_ptr_right_a,                  \
+   draw_mask_fb_ptr_right_b);                                                  \
+                                                                               \
+  add texture_offset, texture_offset, #0x10;                                   \
+  add fb_ptr, fb_ptr, #(2048 - 16) * 2;                                        \
+                                                                               \
+  subs sub_tile_height, sub_tile_height, #1;                                   \
+  bne 4b;                                                                      \
+                                                                               \
+  sub block, block, #16;                                                       \
+  ldr column_data, [sp], #8; /* fb_ptr2 */                                     \
+  add texture_offset, texture_offset, #0xF00;                                  \
+  strh num_blocks, [ psx_gpu, #psx_gpu_num_blocks_offset ]                     \
+
+  
+#define setup_sprite_tile_half_8bpp_4x(edge)                                   \
+  setup_sprite_tile_add_blocks(single_4x);                                     \
+  add block, block, #16;                                                       \
+  str column_data, [sp, #-8]!; /* fb_ptr2 */                                   \
+                                                                               \
+ 4:                                                                            \
+  and texture_block_ptr, texture_offset, texture_mask;                         \
+  pld [ fb_ptr ];                                                              \
+                                                                               \
+  add texture_block_ptr, texture_page_ptr, texture_block_ptr;                  \
+  vld1.u32 { texels }, [ texture_block_ptr, :64 ];                             \
+                                                                               \
+  pld [ fb_ptr, #2048 ];                                                       \
+  do_texture_block_8bpp_4x(fb_ptr2, draw_mask_fb_ptr_##edge##_a,               \
+   draw_mask_fb_ptr_##edge##_b);                                               \
+                                                                               \
+  add texture_offset, texture_offset, #0x10;                                   \
+  add fb_ptr, fb_ptr, #2048 * 2;                                               \
+                                                                               \
+  subs sub_tile_height, sub_tile_height, #1;                                   \
+  bne 4b;                                                                      \
+                                                                               \
+  sub block, block, #16;                                                       \
+  ldr column_data, [sp], #8; /* fb_ptr2 */                                     \
+  add texture_offset, texture_offset, #0xF00;                                  \
+  strh num_blocks, [ psx_gpu, #psx_gpu_num_blocks_offset ]                     \
+
+#define setup_sprite_tile_column_edge_pre_adjust_half_right_4x()               \
+  add texture_offset, texture_offset_base, #8;                                 \
+  add fb_ptr, fb_ptr, #16 * 2                                                  \
+
+#define setup_sprite_tile_column_edge_pre_adjust_half_left_4x()                \
+  mov texture_offset, texture_offset_base                                      \
+
+#define setup_sprite_tile_column_edge_pre_adjust_half_4x(edge)                 \
+  setup_sprite_tile_column_edge_pre_adjust_half_##edge##_4x()                  \
+
+#define setup_sprite_tile_column_edge_pre_adjust_full_4x(edge)                 \
+  mov texture_offset, texture_offset_base                                      \
+
+#define setup_sprite_tile_column_edge_post_adjust_half_right_4x()              \
+  sub fb_ptr, fb_ptr, #16 * 2                                                  \
+
+#define setup_sprite_tile_column_edge_post_adjust_half_left_4x()               \
+
+#define setup_sprite_tile_column_edge_post_adjust_half_4x(edge)                \
+  setup_sprite_tile_column_edge_post_adjust_half_##edge##_4x()                 \
+
+#define setup_sprite_tile_column_edge_post_adjust_full_4x(edge)                \
+
+
+#define setup_sprite_setup_left_draw_mask_fb_ptr_4x()                          \
+  vdup.u8 draw_mask_fb_ptr_left_a, block_masks[0];                             \
+  vdup.u8 draw_mask_fb_ptr_left_b, block_masks[1];                             \
+  vdup.u8 draw_mask_fb_ptr_right_a, block_masks[2];                            \
+  vdup.u8 draw_mask_fb_ptr_right_b, block_masks[3]                             \
+
+#define setup_sprite_setup_left_draw_mask_fb_ptr_advance_column_4x()           \
+  mov fb_ptr_advance_column, #32 * 2;                                          \
+  vdup.u8 draw_mask_fb_ptr_left_a, block_masks[0];                             \
+  vdup.u8 draw_mask_fb_ptr_left_b, block_masks[1];                             \
+  sub fb_ptr_advance_column, height, lsl #11 + 1;                              \
+  vdup.u8 draw_mask_fb_ptr_right_a, block_masks[2];                            \
+  vdup.u8 draw_mask_fb_ptr_right_b, block_masks[3]                             \
+
+#define setup_sprite_setup_right_draw_mask_fb_ptr_4x()                         \
+  vdup.u8 draw_mask_fb_ptr_left_a, block_masks[4];                             \
+  vdup.u8 draw_mask_fb_ptr_left_b, block_masks[5];                             \
+  vdup.u8 draw_mask_fb_ptr_right_a, block_masks[6];                            \
+  vdup.u8 draw_mask_fb_ptr_right_b, block_masks[7]                             \
+
+
 // r0: psx_gpu
 // r1: x
 // r2: y
@@ -4833,34 +5113,48 @@ setup_sprite_update_texture_8bpp_cache:
 // [ sp + 8 ]: height
 // [ sp + 12 ]: color (unused)
 
-#define setup_sprite_tiled_builder(texture_mode)                               \
-                                                                               \
-setup_sprite_tile_column_width_multi(texture_mode,  multi,  full, full);       \
-setup_sprite_tile_column_width_single(texture_mode, multi,  full, none);       \
-setup_sprite_tile_column_width_multi(texture_mode,  single, full, full);       \
-setup_sprite_tile_column_width_single(texture_mode, single, full, none);       \
-setup_sprite_tile_column_width_multi(texture_mode,  multi,  half, full);       \
-setup_sprite_tile_column_width_single(texture_mode, multi,  half, right);      \
-setup_sprite_tile_column_width_multi(texture_mode,  single, half, full);       \
-setup_sprite_tile_column_width_single(texture_mode, single, half, right);      \
-setup_sprite_tile_column_width_multi(texture_mode,  multi,  full, half);       \
-setup_sprite_tile_column_width_single(texture_mode, multi,  half, left);       \
-setup_sprite_tile_column_width_multi(texture_mode,  single, full, half);       \
-setup_sprite_tile_column_width_single(texture_mode, single, half, left);       \
-setup_sprite_tile_column_width_multi(texture_mode,  multi,  half, half);       \
-setup_sprite_tile_column_width_multi(texture_mode,  single, half, half);       \
+#define setup_sprite_tiled_builder(texture_mode, x4mode)                       \
+                                                                               \
+setup_sprite_tile_column_width_multi(texture_mode,  multi,  full, full,        \
+  x4mode);                                                                     \
+setup_sprite_tile_column_width_single(texture_mode, multi,  full, none,        \
+  x4mode);                                                                     \
+setup_sprite_tile_column_width_multi(texture_mode,  single, full, full,        \
+  x4mode);                                                                     \
+setup_sprite_tile_column_width_single(texture_mode, single, full, none,        \
+  x4mode);                                                                     \
+setup_sprite_tile_column_width_multi(texture_mode,  multi,  half, full,        \
+  x4mode);                                                                     \
+setup_sprite_tile_column_width_single(texture_mode, multi,  half, right,       \
+  x4mode);                                                                     \
+setup_sprite_tile_column_width_multi(texture_mode,  single, half, full,        \
+  x4mode);                                                                     \
+setup_sprite_tile_column_width_single(texture_mode, single, half, right,       \
+  x4mode);                                                                     \
+setup_sprite_tile_column_width_multi(texture_mode,  multi,  full, half,        \
+  x4mode);                                                                     \
+setup_sprite_tile_column_width_single(texture_mode, multi,  half, left,        \
+  x4mode);                                                                     \
+setup_sprite_tile_column_width_multi(texture_mode,  single, full, half,        \
+  x4mode);                                                                     \
+setup_sprite_tile_column_width_single(texture_mode, single, half, left,        \
+  x4mode);                                                                     \
+setup_sprite_tile_column_width_multi(texture_mode,  multi,  half, half,        \
+  x4mode);                                                                     \
+setup_sprite_tile_column_width_multi(texture_mode,  single, half, half,        \
+  x4mode);                                                                     \
                                                                                \
 .align 4;                                                                      \
                                                                                \
-function(setup_sprite_##texture_mode)                                          \
+function(setup_sprite_##texture_mode##x4mode)                                  \
   stmdb sp!, { r4 - r11, r14 };                                                \
-  setup_sprite_tiled_initialize_##texture_mode();                              \
+  setup_sprite_tiled_initialize_##texture_mode##x4mode();                      \
                                                                                \
   ldr v, [ sp, #36 ];                                                          \
   and offset_u, u, #0xF;                                                       \
                                                                                \
   ldr width, [ sp, #40 ];                                                      \
-  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_ptr_offset ];                           \
+  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_out_ptr_offset ];                       \
                                                                                \
   ldr height, [ sp, #44 ];                                                     \
   add fb_ptr, fb_ptr, y, lsl #11;                                              \
@@ -4883,11 +5177,13 @@ function(setup_sprite_##texture_mode)                                          \
                                                                                \
   /* texture_offset_base = VH-UH-UL-00                                       */\
   bfi texture_offset_base, u, #4, #8;                                          \
-  movw right_block_mask, #0xFFFE;                                              \
+  mov right_block_mask, #0xFFFFFFFE;                                           \
+                                                                               \
+  setup_sprite_offset_u_adjust##x4mode();                                      \
                                                                                \
   /* texture_offset_base = VH-UH-VL-00                                       */\
   bfi texture_offset_base, v, #4, #4;                                          \
-  movw left_block_mask, #0xFFFF;                                               \
+  mov left_block_mask, #0xFFFFFFFF;                                            \
                                                                                \
   mov tile_height, height_rounded, lsr #4;                                     \
   mvn left_block_mask, left_block_mask, lsl offset_u;                          \
@@ -4907,16 +5203,16 @@ function(setup_sprite_##texture_mode)                                          \
                                                                                \
   /* texture_mask = HH-WH-HL-WL                                              */\
   bfi texture_mask, texture_mask_rev, #8, #4;                                  \
-  and left_block_mask, left_block_mask, #0xFF;                                 \
+  setup_sprite_get_left_block_mask##x4mode();                                  \
                                                                                \
   mov control_mask, #0;                                                        \
-  cmp left_block_mask, #0xFF;                                                  \
+  setup_sprite_compare_left_block_mask##x4mode();                              \
                                                                                \
-  uxtb right_block_mask, right_block_mask, ror #8;                             \
+  setup_sprite_get_right_block_mask##x4mode();                                 \
   orreq control_mask, control_mask, #0x4;                                      \
                                                                                \
   ldrh num_blocks, [ psx_gpu, #psx_gpu_num_blocks_offset ];                    \
-  cmp right_block_mask, #0xFF;                                                 \
+  setup_sprite_compare_right_block_mask##x4mode();                             \
                                                                                \
   orreq control_mask, control_mask, #0x8;                                      \
   cmp tile_width, #1;                                                          \
@@ -4931,25 +5227,31 @@ function(setup_sprite_##texture_mode)                                          \
   ldr pc, [ pc, control_mask, lsl #2 ];                                        \
   nop;                                                                         \
                                                                                \
- .word setup_sprite_##texture_mode##_multi_multi_full_full;                    \
- .word setup_sprite_##texture_mode##_single_multi_full_none;                   \
- .word setup_sprite_##texture_mode##_multi_single_full_full;                   \
- .word setup_sprite_##texture_mode##_single_single_full_none;                  \
- .word setup_sprite_##texture_mode##_multi_multi_half_full;                    \
- .word setup_sprite_##texture_mode##_single_multi_half_right;                  \
- .word setup_sprite_##texture_mode##_multi_single_half_full;                   \
- .word setup_sprite_##texture_mode##_single_single_half_right;                 \
- .word setup_sprite_##texture_mode##_multi_multi_full_half;                    \
- .word setup_sprite_##texture_mode##_single_multi_half_left;                   \
- .word setup_sprite_##texture_mode##_multi_single_full_half;                   \
- .word setup_sprite_##texture_mode##_single_single_half_left;                  \
- .word setup_sprite_##texture_mode##_multi_multi_half_half;                    \
+ .word setup_sprite_##texture_mode##_multi_multi_full_full##x4mode;            \
+ .word setup_sprite_##texture_mode##_single_multi_full_none##x4mode;           \
+ .word setup_sprite_##texture_mode##_multi_single_full_full##x4mode;           \
+ .word setup_sprite_##texture_mode##_single_single_full_none##x4mode;          \
+ .word setup_sprite_##texture_mode##_multi_multi_half_full##x4mode;            \
+ .word setup_sprite_##texture_mode##_single_multi_half_right##x4mode;          \
+ .word setup_sprite_##texture_mode##_multi_single_half_full##x4mode;           \
+ .word setup_sprite_##texture_mode##_single_single_half_right##x4mode;         \
+ .word setup_sprite_##texture_mode##_multi_multi_full_half##x4mode;            \
+ .word setup_sprite_##texture_mode##_single_multi_half_left##x4mode;           \
+ .word setup_sprite_##texture_mode##_multi_single_full_half##x4mode;           \
+ .word setup_sprite_##texture_mode##_single_single_half_left##x4mode;          \
+ .word setup_sprite_##texture_mode##_multi_multi_half_half##x4mode;            \
  .word 0x00000000;                                                             \
- .word setup_sprite_##texture_mode##_multi_single_half_half                    \
+ .word setup_sprite_##texture_mode##_multi_single_half_half##x4mode;           \
 
 
-setup_sprite_tiled_builder(4bpp);
-setup_sprite_tiled_builder(8bpp);
+setup_sprite_tiled_builder(4bpp,);
+setup_sprite_tiled_builder(8bpp,);
+
+#undef draw_mask_fb_ptr_left
+#undef draw_mask_fb_ptr_right
+
+setup_sprite_tiled_builder(4bpp, _4x);
+setup_sprite_tiled_builder(8bpp, _4x);
 
 
 #undef block_ptr
@@ -5038,6 +5340,12 @@ function(texture_sprite_blocks_8bpp)
 #undef texture_mask
 #undef num_blocks
 #undef texture_offset
+#undef texels_low
+#undef texels_high
+#undef texels_wide_low
+#undef texels_wide_high
+#undef texels_wide
+#undef fb_ptr2
 
 #define psx_gpu                                           r0
 #define x                                                 r1
@@ -5049,6 +5357,7 @@ function(texture_sprite_blocks_8bpp)
 #define left_offset                                       r8
 #define width_rounded                                     r9
 #define right_width                                       r10
+
 #define block_width                                       r11
 
 #define texture_offset_base                               r1
@@ -5059,6 +5368,7 @@ function(texture_sprite_blocks_8bpp)
 #define fb_ptr                                            r7
 #define texture_offset                                    r8
 #define blocks_remaining                                  r9
+#define fb_ptr2                                           r10
 #define fb_ptr_pitch                                      r12
 #define texture_block_ptr                                 r14
 
@@ -5077,29 +5387,23 @@ function(texture_sprite_blocks_8bpp)
 #define draw_mask_fb_ptr                                  d2
 #define texels                                            q2
 
+#define draw_mask_fb_ptr_a                                d2
+#define draw_mask_fb_ptr_b                                d3
+#define texels_low                                        d4
+#define texels_high                                       d5
+#define texels_wide_low                                   d6
+#define texels_wide_high                                  d7
+#define texels_wide                                       q3
 
-setup_sprites_16bpp_flush_single:
-  vpush { d0 - d2 }
-
-  stmdb sp!, { r0 - r3, r12, r14 }
-  bl flush_render_block_buffer
-  ldmia sp!, { r0 - r3, r12, r14 }
-
-  vpop { d0 - d2 }
-
-  add block, psx_gpu, #psx_gpu_blocks_offset
-  mov num_blocks, #1
-
-  bx lr
 
-setup_sprites_16bpp_flush_row:
-  vpush { d0 - d2 }
+setup_sprites_16bpp_flush:
+  vpush { d0 - d3 }
 
   stmdb sp!, { r0 - r3, r12, r14 }
   bl flush_render_block_buffer
   ldmia sp!, { r0 - r3, r12, r14 }
 
-  vpop { d0 - d2 }
+  vpop { d0 - d3 }
 
   add block, psx_gpu, #psx_gpu_blocks_offset
   mov num_blocks, block_width
@@ -5108,7 +5412,7 @@ setup_sprites_16bpp_flush_row:
 
 function(setup_sprite_16bpp)
   stmdb sp!, { r4 - r11, r14 }
-  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_ptr_offset ]
+  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_out_ptr_offset ]
 
   ldr v, [ sp, #36 ]
   add fb_ptr, fb_ptr, y, lsl #11
@@ -5164,7 +5468,7 @@ function(setup_sprite_16bpp)
  1:
   add num_blocks, num_blocks, #1
   cmp num_blocks, #MAX_BLOCKS
-  blgt setup_sprites_16bpp_flush_single
+  blgt setup_sprites_16bpp_flush
 
   and texture_block_ptr, texture_offset_base, texture_mask
   subs height, height, #1
@@ -5193,7 +5497,7 @@ function(setup_sprite_16bpp)
   mov texture_offset, texture_offset_base
 
   cmp num_blocks, #MAX_BLOCKS
-  blgt setup_sprites_16bpp_flush_row
+  blgt setup_sprites_16bpp_flush
 
   add texture_offset_base, texture_offset_base, #2048
   and texture_block_ptr, texture_offset, texture_mask
@@ -5264,6 +5568,292 @@ function(setup_sprite_16bpp)
   ldmia sp!, { r4 - r11, pc }
 
 
+// 4x version
+// FIXME: duplicate code with normal version :(
+#undef draw_mask_fb_ptr
+
+function(setup_sprite_16bpp_4x)
+  stmdb sp!, { r4 - r11, r14 }
+  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_out_ptr_offset ]
+
+  ldr v, [ sp, #36 ]
+  add fb_ptr, fb_ptr, y, lsl #11
+
+  ldr width, [ sp, #40 ]
+  add fb_ptr, fb_ptr, x, lsl #1
+
+  ldr height, [ sp, #44 ]
+  and left_offset, u, #0x7
+
+  add texture_offset_base, u, u
+  add width_rounded, width, #7
+
+  add texture_offset_base, v, lsl #11
+  movw left_mask_bits, #0xFFFF
+  
+  ldrb texture_mask_width, [ psx_gpu, #psx_gpu_texture_mask_width_offset ]
+  add width_rounded, width_rounded, left_offset
+
+  lsl left_offset, #1
+
+  ldrb texture_mask_height, [ psx_gpu, #psx_gpu_texture_mask_height_offset ]
+  sub fb_ptr, fb_ptr, left_offset, lsl #1
+
+  add texture_mask, texture_mask_width, texture_mask_width
+  movw right_mask_bits, #0xFFFC
+
+  and right_width, width_rounded, #0x7
+  mvn left_mask_bits, left_mask_bits, lsl left_offset
+
+  lsl right_width, #1
+
+  add texture_mask, texture_mask_height, lsl #11
+  mov block_width, width_rounded, lsr #3
+
+  mov right_mask_bits, right_mask_bits, lsl right_width
+  movw fb_ptr_pitch, #(2048 + 16) * 2
+
+  sub fb_ptr_pitch, fb_ptr_pitch, block_width, lsl #4+1
+  vmov block_masks, left_mask_bits, right_mask_bits
+
+  ldrh num_blocks, [ psx_gpu, #psx_gpu_num_blocks_offset ]
+  add block, psx_gpu, #psx_gpu_blocks_offset
+
+  bic texture_offset_base, texture_offset_base, #0xF
+  cmp block_width, #1
+
+  ldr texture_page_ptr, [ psx_gpu, #psx_gpu_texture_page_ptr_offset ]
+  add block, block, num_blocks, lsl #6
+
+  lsl block_width, #2
+  bne 0f
+
+  vext.32 block_masks_shifted, block_masks, block_masks, #1
+  vorr.u32 block_masks, block_masks, block_masks_shifted
+  vdup.u8 draw_mask_fb_ptr_a, block_masks[0]
+  vdup.u8 draw_mask_fb_ptr_b, block_masks[1]
+
+ 1:
+  add num_blocks, num_blocks, block_width
+  cmp num_blocks, #MAX_BLOCKS
+  blgt setup_sprites_16bpp_flush
+
+  and texture_block_ptr, texture_offset_base, texture_mask
+  subs height, height, #1
+
+  add texture_block_ptr, texture_page_ptr, texture_block_ptr
+  vld1.u32 { texels }, [ texture_block_ptr, :128 ]
+
+  do_texture_block_16bpp_4x(fb_ptr2, draw_mask_fb_ptr_a, draw_mask_fb_ptr_b)
+
+  add texture_offset_base, texture_offset_base, #2048
+  add fb_ptr, fb_ptr, #2048*2
+  strh num_blocks, [ psx_gpu, #psx_gpu_num_blocks_offset ]
+  bne 1b
+
+  ldmia sp!, { r4 - r11, pc }
+
+ 0:
+  add num_blocks, num_blocks, block_width
+  mov texture_offset, texture_offset_base
+
+  vdup.u8 draw_mask_fb_ptr_a, block_masks[0] // left_mask_bits
+  vdup.u8 draw_mask_fb_ptr_b, block_masks[1]
+
+  cmp num_blocks, #MAX_BLOCKS
+  blgt setup_sprites_16bpp_flush
+
+  add texture_offset_base, texture_offset_base, #2048
+  and texture_block_ptr, texture_offset, texture_mask
+
+  add texture_block_ptr, texture_page_ptr, texture_block_ptr
+  vld1.u32 { texels }, [ texture_block_ptr, :128 ]
+
+  do_texture_block_16bpp_4x(fb_ptr2, draw_mask_fb_ptr_a, draw_mask_fb_ptr_b)
+
+  subs blocks_remaining, block_width, #2*4
+  add texture_offset, texture_offset, #16
+
+  vmov.u8 draw_mask_fb_ptr_a, #0
+  vmov.u8 draw_mask_fb_ptr_b, #0
+
+  add fb_ptr, fb_ptr, #16*2
+  beq 2f
+
+ 1:
+  and texture_block_ptr, texture_offset, texture_mask
+  subs blocks_remaining, blocks_remaining, #4
+
+  add texture_block_ptr, texture_page_ptr, texture_block_ptr
+  vld1.u32 { texels }, [ texture_block_ptr, :128 ]
+
+  do_texture_block_16bpp_4x(fb_ptr2, draw_mask_fb_ptr_a, draw_mask_fb_ptr_b)
+  add texture_offset, texture_offset, #16
+
+  add fb_ptr, fb_ptr, #16*2
+  bgt 1b
+
+ 2:
+  vdup.u8 draw_mask_fb_ptr_a, block_masks[4] // right_mask_bits
+  vdup.u8 draw_mask_fb_ptr_b, block_masks[5]
+
+  and texture_block_ptr, texture_offset, texture_mask
+  add texture_block_ptr, texture_page_ptr, texture_block_ptr
+
+  vld1.u32 { texels }, [ texture_block_ptr, :128 ]
+
+  do_texture_block_16bpp_4x(fb_ptr2, draw_mask_fb_ptr_a, draw_mask_fb_ptr_b)
+  subs height, height, #1
+
+  add fb_ptr, fb_ptr, fb_ptr_pitch
+  strh num_blocks, [ psx_gpu, #psx_gpu_num_blocks_offset ]
+
+  bne 0b
+
+  ldmia sp!, { r4 - r11, pc }
+
+
+#undef width
+#undef right_width
+#undef right_mask_bits
+#undef color
+#undef height
+#undef blocks_remaining
+#undef colors
+#undef right_mask
+#undef test_mask
+#undef draw_mask
+
+#define psx_gpu                                           r0
+#define x                                                 r1
+#define y                                                 r2
+#define width                                             r3
+#define right_width                                       r5
+#define right_mask_bits                                   r6
+#define fb_ptr                                            r7
+#define color                                             r8
+#define height                                            r9
+#define fb_ptr_pitch                                      r12
+
+// referenced by setup_sprites_16bpp_flush
+#define num_blocks                                        r4
+#define block                                             r5
+#define block_width                                       r11
+
+#define color_r                                           r1
+#define color_g                                           r2
+#define color_b                                           r8
+#define blocks_remaining                                  r6
+
+#define colors                                            q0
+#define right_mask                                        q1
+#define test_mask                                         q2
+#define draw_mask                                         q2
+#define draw_mask_bits_fb_ptr                             d6
+
+
+.align 3
+
+function(setup_sprite_untextured)
+  ldrh r12, [ psx_gpu, #psx_gpu_render_state_offset ]
+  tst r12, #(RENDER_STATE_MASK_EVALUATE | RENDER_FLAGS_MODULATE_TEXELS         \
+    | RENDER_FLAGS_BLEND)
+  ldreqb r12, [ psx_gpu, #psx_gpu_render_mode_offset ]
+  tsteq r12, #RENDER_INTERLACE_ENABLED
+  beq setup_sprite_untextured_simple
+
+  stmdb sp!, { r4 - r11, r14 }
+
+  ldr width, [ sp, #40 ]
+  ldr fb_ptr, [ psx_gpu, #psx_gpu_vram_out_ptr_offset ]
+
+  ldr height, [ sp, #44 ]
+  add fb_ptr, fb_ptr, y, lsl #11
+
+  add fb_ptr, fb_ptr, x, lsl #1
+  sub right_width, width, #1
+
+  ldr color, [ sp, #48 ]
+  and right_width, #7
+
+  add block_width, width, #7
+  add right_width, #1
+
+  lsr block_width, #3
+  mov right_mask_bits, #0xff
+
+  sub fb_ptr_pitch, block_width, #1
+  lsl right_mask_bits, right_width
+
+  lsl fb_ptr_pitch, #3+1
+  ubfx color_r, color, #3, #5
+
+  rsb fb_ptr_pitch, #1024*2
+  ubfx color_g, color, #11, #5
+
+  vld1.u32 { test_mask }, [ psx_gpu, :128 ]
+  ubfx color_b, color, #19, #5
+
+  vdup.u16 right_mask, right_mask_bits
+  orr color, color_r, color_b, lsl #10
+
+  ldrh num_blocks, [ psx_gpu, #psx_gpu_num_blocks_offset ]
+  orr color, color, color_g, lsl #5
+
+  vtst.u16 right_mask, right_mask, test_mask
+  add block, psx_gpu, #psx_gpu_blocks_offset
+
+  vdup.u16 colors, color
+  add block, block, num_blocks, lsl #6
+
+
+setup_sprite_untextured_height_loop:
+  add num_blocks, block_width
+  sub blocks_remaining, block_width, #1
+
+  cmp num_blocks, #MAX_BLOCKS
+  blgt setup_sprites_16bpp_flush
+
+  cmp blocks_remaining, #0
+  ble 1f
+
+  vmov.u8 draw_mask, #0 /* zero_mask */
+  vmov.u8 draw_mask_bits_fb_ptr, #0
+
+ 0:
+  vst1.u32 { draw_mask }, [ block, :128 ]!
+  subs blocks_remaining, #1
+
+  vst1.u32 { colors }, [ block, :128 ]
+  add block, block, #24
+
+  vmov.u32 draw_mask_bits_fb_ptr[1], fb_ptr
+  vst1.u32 { draw_mask_bits_fb_ptr }, [ block, :64 ]
+  
+  add block, block, #24
+  add fb_ptr, #8*2
+  bgt 0b
+
+ 1:
+  vst1.u32 { right_mask }, [ block, :128 ]!
+  subs height, #1
+
+  vst1.u32 { colors }, [ block, :128 ]
+  add block, block, #24
+
+  vmov.u32 draw_mask_bits_fb_ptr[1], fb_ptr
+  vst1.u32 { draw_mask_bits_fb_ptr }, [ block, :64 ]
+  
+  add block, block, #24
+  add fb_ptr, fb_ptr_pitch
+
+  strh num_blocks, [ psx_gpu, #psx_gpu_num_blocks_offset ]
+  bgt setup_sprite_untextured_height_loop
+
+  ldmia sp!, { r4 - r11, pc }
+
+
+
 #undef texture_page_ptr
 #undef vram_ptr
 #undef dirty_textures_mask
@@ -5461,3 +6051,40 @@ function(update_texture_8bpp_cache_slice)
   vpop { q0 - q3 }
   ldmia sp!, { r4 - r11, pc }
 
+
+/* void scale2x_tiles8(void *dst, const void *src, int w8, int h) */
+function(scale2x_tiles8)
+  push { r4, r14 }
+
+  mov r4, r1
+  add r12, r0, #1024*2
+  mov r14, r2
+
+0:
+  vld1.u16 { q0 }, [ r1, :128 ]!
+  vld1.u16 { q2 }, [ r1, :128 ]!
+  vmov q1, q0
+  vmov q3, q2
+  vzip.16 q0, q1
+  vzip.16 q2, q3
+  subs r14, #2
+  vst1.u16 { q0, q1 }, [ r0, :128 ]!
+  vst1.u16 { q0, q1 }, [ r12, :128 ]!
+  blt 1f
+  vst1.u16 { q2, q3 }, [ r0, :128 ]!
+  vst1.u16 { q2, q3 }, [ r12, :128 ]!
+  bgt 0b
+1:
+  subs r3, #1
+  mov r14, r2
+  add r0, #1024*2*2
+  add r4, #1024*2
+  sub r0, r2, lsl #4+1
+  mov r1, r4
+  add r12, r0, #1024*2
+  bgt 0b
+  nop
+
+  pop { r4, pc }
+
+// vim:filetype=armasm
diff --git a/plugins/gpu_neon/psx_gpu/psx_gpu_offsets.h b/plugins/gpu_neon/psx_gpu/psx_gpu_offsets.h
new file mode 100644 (file)
index 0000000..1307891
--- /dev/null
@@ -0,0 +1,57 @@
+#define psx_gpu_test_mask_offset                          0x0
+#define psx_gpu_uvrg_offset                               0x10
+#define psx_gpu_uvrg_dx_offset                            0x20
+#define psx_gpu_uvrg_dy_offset                            0x30
+#define psx_gpu_u_block_span_offset                       0x40
+#define psx_gpu_v_block_span_offset                       0x50
+#define psx_gpu_r_block_span_offset                       0x60
+#define psx_gpu_g_block_span_offset                       0x70
+#define psx_gpu_b_block_span_offset                       0x80
+#define psx_gpu_b_offset                                  0x90
+#define psx_gpu_b_dy_offset                               0x94
+#define psx_gpu_triangle_area_offset                      0x98
+#define psx_gpu_texture_window_settings_offset            0x9c
+#define psx_gpu_current_texture_mask_offset               0xa0
+#define psx_gpu_viewport_mask_offset                      0xa4
+#define psx_gpu_dirty_textures_4bpp_mask_offset           0xa8
+#define psx_gpu_dirty_textures_8bpp_mask_offset           0xac
+#define psx_gpu_dirty_textures_8bpp_alternate_mask_offset 0xb0
+#define psx_gpu_triangle_color_offset                     0xb4
+#define psx_gpu_dither_table_offset                       0xb8
+#define psx_gpu_uvrgb_phase_offset                        0xc8
+#define psx_gpu_render_block_handler_offset               0xcc
+#define psx_gpu_texture_page_ptr_offset                   0xd0
+#define psx_gpu_texture_page_base_offset                  0xd4
+#define psx_gpu_clut_ptr_offset                           0xd8
+#define psx_gpu_vram_ptr_offset                           0xdc
+#define psx_gpu_vram_out_ptr_offset                       0xe0
+#define psx_gpu_render_state_base_offset                  0xe4
+#define psx_gpu_render_state_offset                       0xe6
+#define psx_gpu_num_spans_offset                          0xe8
+#define psx_gpu_num_blocks_offset                         0xea
+#define psx_gpu_viewport_start_x_offset                   0xec
+#define psx_gpu_viewport_start_y_offset                   0xee
+#define psx_gpu_viewport_end_x_offset                     0xf0
+#define psx_gpu_viewport_end_y_offset                     0xf2
+#define psx_gpu_mask_msb_offset                           0xf4
+#define psx_gpu_triangle_winding_offset                   0xf6
+#define psx_gpu_display_area_draw_enable_offset           0xf7
+#define psx_gpu_current_texture_page_offset               0xf8
+#define psx_gpu_last_8bpp_texture_page_offset             0xf9
+#define psx_gpu_texture_mask_width_offset                 0xfa
+#define psx_gpu_texture_mask_height_offset                0xfb
+#define psx_gpu_texture_window_x_offset                   0xfc
+#define psx_gpu_texture_window_y_offset                   0xfd
+#define psx_gpu_primitive_type_offset                     0xfe
+#define psx_gpu_render_mode_offset                        0xff
+#define psx_gpu_offset_x_offset                           0x100
+#define psx_gpu_offset_y_offset                           0x102
+#define psx_gpu_clut_settings_offset                      0x104
+#define psx_gpu_texture_settings_offset                   0x106
+#define psx_gpu_blocks_offset                             0x200
+#define psx_gpu_span_uvrg_offset_offset                   0x2200
+#define psx_gpu_span_edge_data_offset                     0x4200
+#define psx_gpu_span_b_offset_offset                      0x5200
+#define psx_gpu_texture_4bpp_cache_offset                 0x5a00
+#define psx_gpu_texture_8bpp_even_cache_offset            0x205a00
+#define psx_gpu_texture_8bpp_odd_cache_offset             0x305a00
diff --git a/plugins/gpu_neon/psx_gpu/psx_gpu_offsets_update.c b/plugins/gpu_neon/psx_gpu/psx_gpu_offsets_update.c
new file mode 100644 (file)
index 0000000..5adfb75
--- /dev/null
@@ -0,0 +1,86 @@
+#include <stdio.h>
+#include <stddef.h>
+
+#include "common.h"
+
+#define WRITE_OFFSET(f, member) \
+       fprintf(f, "#define %-50s0x%x\n", \
+               "psx_gpu_" #member "_offset", \
+               offsetof(psx_gpu_struct, member));
+
+int main()
+{
+       FILE *f;
+
+       if (sizeof(f) != 4) {
+               fprintf(stderr, "bad pointer size\n");
+               return 1;
+       }
+
+       f = fopen("psx_gpu_offsets.h", "w");
+       if (f == NULL) {
+               perror("fopen");
+               return 1;
+       }
+
+       WRITE_OFFSET(f, test_mask);
+       WRITE_OFFSET(f, uvrg);
+       WRITE_OFFSET(f, uvrg_dx);
+       WRITE_OFFSET(f, uvrg_dy);
+       WRITE_OFFSET(f, u_block_span);
+       WRITE_OFFSET(f, v_block_span);
+       WRITE_OFFSET(f, r_block_span);
+       WRITE_OFFSET(f, g_block_span);
+       WRITE_OFFSET(f, b_block_span);
+       WRITE_OFFSET(f, b);
+       WRITE_OFFSET(f, b_dy);
+       WRITE_OFFSET(f, triangle_area);
+       WRITE_OFFSET(f, texture_window_settings);
+       WRITE_OFFSET(f, current_texture_mask);
+       WRITE_OFFSET(f, viewport_mask);
+       WRITE_OFFSET(f, dirty_textures_4bpp_mask);
+       WRITE_OFFSET(f, dirty_textures_8bpp_mask);
+       WRITE_OFFSET(f, dirty_textures_8bpp_alternate_mask);
+       WRITE_OFFSET(f, triangle_color);
+       WRITE_OFFSET(f, dither_table);
+       WRITE_OFFSET(f, uvrgb_phase);
+       WRITE_OFFSET(f, render_block_handler);
+       WRITE_OFFSET(f, texture_page_ptr);
+       WRITE_OFFSET(f, texture_page_base);
+       WRITE_OFFSET(f, clut_ptr);
+       WRITE_OFFSET(f, vram_ptr);
+       WRITE_OFFSET(f, vram_out_ptr);
+       WRITE_OFFSET(f, render_state_base);
+       WRITE_OFFSET(f, render_state);
+       WRITE_OFFSET(f, num_spans);
+       WRITE_OFFSET(f, num_blocks);
+       WRITE_OFFSET(f, viewport_start_x);
+       WRITE_OFFSET(f, viewport_start_y);
+       WRITE_OFFSET(f, viewport_end_x);
+       WRITE_OFFSET(f, viewport_end_y);
+       WRITE_OFFSET(f, mask_msb);
+       WRITE_OFFSET(f, triangle_winding);
+       WRITE_OFFSET(f, display_area_draw_enable);
+       WRITE_OFFSET(f, current_texture_page);
+       WRITE_OFFSET(f, last_8bpp_texture_page);
+       WRITE_OFFSET(f, texture_mask_width);
+       WRITE_OFFSET(f, texture_mask_height);
+       WRITE_OFFSET(f, texture_window_x);
+       WRITE_OFFSET(f, texture_window_y);
+       WRITE_OFFSET(f, primitive_type);
+       WRITE_OFFSET(f, render_mode);
+       WRITE_OFFSET(f, offset_x);
+       WRITE_OFFSET(f, offset_y);
+       WRITE_OFFSET(f, clut_settings);
+       WRITE_OFFSET(f, texture_settings);
+       WRITE_OFFSET(f, blocks);
+       WRITE_OFFSET(f, span_uvrg_offset);
+       WRITE_OFFSET(f, span_edge_data);
+       WRITE_OFFSET(f, span_b_offset);
+       WRITE_OFFSET(f, texture_4bpp_cache);
+       WRITE_OFFSET(f, texture_8bpp_even_cache);
+       WRITE_OFFSET(f, texture_8bpp_odd_cache);
+       fclose(f);
+
+       return 0;
+}
index 920c638..a364eef 100644 (file)
@@ -92,6 +92,7 @@ void update_texture_ptr(psx_gpu_struct *psx_gpu)
 
 void set_texture(psx_gpu_struct *psx_gpu, u32 texture_settings)
 {
+  texture_settings &= 0x1FF;
   if(psx_gpu->texture_settings != texture_settings)
   {
     u32 new_texture_page = texture_settings & 0x1F;
@@ -152,6 +153,52 @@ void set_triangle_color(psx_gpu_struct *psx_gpu, u32 triangle_color)
   }
 }
 
+static void do_fill(psx_gpu_struct *psx_gpu, u32 x, u32 y,
+ u32 width, u32 height, u32 color)
+{
+  x &= ~0xF;
+  width = ((width + 0xF) & ~0xF);
+
+  flush_render_block_buffer(psx_gpu);
+
+  if(unlikely((x + width) > 1024))
+  {
+    u32 width_a = 1024 - x;
+    u32 width_b = width - width_a;
+
+    if(unlikely((y + height) > 512))
+    {
+      u32 height_a = 512 - y;
+      u32 height_b = height - height_a;
+
+      render_block_fill(psx_gpu, color, x, y, width_a, height_a);
+      render_block_fill(psx_gpu, color, 0, y, width_b, height_a);
+      render_block_fill(psx_gpu, color, x, 0, width_a, height_b);
+      render_block_fill(psx_gpu, color, 0, 0, width_b, height_b);
+    }
+    else
+    {
+      render_block_fill(psx_gpu, color, x, y, width_a, height);
+      render_block_fill(psx_gpu, color, 0, y, width_b, height);
+    }
+  }
+  else
+  {
+    if(unlikely((y + height) > 512))
+    {
+      u32 height_a = 512 - y;
+      u32 height_b = height - height_a;
+
+      render_block_fill(psx_gpu, color, x, y, width, height_a);
+      render_block_fill(psx_gpu, color, x, 0, width, height_b);
+    }
+    else
+    {
+      render_block_fill(psx_gpu, color, x, y, width, height);
+    }
+  }
+}
+
 #define sign_extend_12bit(value)                                               \
   (((s32)((value) << 20)) >> 20)                                               \
 
@@ -235,45 +282,7 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
         u32 height = list_s16[5] & 0x1FF;
         u32 color = list[0] & 0xFFFFFF;
 
-        x &= ~0xF;
-        width = ((width + 0xF) & ~0xF);
-
-        if((x + width) > 1024)
-        {
-          u32 width_a = 1024 - x;
-          u32 width_b = width - width_a;
-
-          if((y + height) > 512)
-          {
-            u32 height_a = 512 - y;
-            u32 height_b = height - height_a;
-
-            render_block_fill(psx_gpu, color, x, y, width_a, height_a);
-            render_block_fill(psx_gpu, color, 0, y, width_b, height_a);
-            render_block_fill(psx_gpu, color, x, 0, width_a, height_b);
-            render_block_fill(psx_gpu, color, 0, 0, width_b, height_b);
-          }
-          else
-          {
-            render_block_fill(psx_gpu, color, x, y, width_a, height);
-            render_block_fill(psx_gpu, color, 0, y, width_b, height);
-          }
-        }
-        else
-        {
-          if((y + height) > 512)
-          {
-            u32 height_a = 512 - y;
-            u32 height_b = height - height_a;
-
-            render_block_fill(psx_gpu, color, x, y, width, height_a);
-            render_block_fill(psx_gpu, color, x, 0, width, height_b);
-          }
-          else
-          {
-            render_block_fill(psx_gpu, color, x, y, width, height);
-          }
-        }
+        do_fill(psx_gpu, x, y, width, height, color);
                        break;
       }
   
@@ -399,7 +408,7 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
         vertexes[1].x = list_s16[4] + psx_gpu->offset_x;
         vertexes[1].y = list_s16[5] + psx_gpu->offset_y;
 
-        render_line(psx_gpu, vertexes, current_command, list[0]);
+        render_line(psx_gpu, vertexes, current_command, list[0], 0);
                        break;
       }
   
@@ -420,7 +429,7 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
           vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
           vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
 
-          render_line(psx_gpu, vertexes, current_command, list[0]);
+          render_line(psx_gpu, vertexes, current_command, list[0], 0);
 
           list_position++;
           num_vertexes++;
@@ -451,7 +460,7 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
         vertexes[1].x = list_s16[6] + psx_gpu->offset_x;
         vertexes[1].y = list_s16[7] + psx_gpu->offset_y;
 
-        render_line(psx_gpu, vertexes, current_command, 0);
+        render_line(psx_gpu, vertexes, current_command, 0, 0);
                        break;
       }
  
@@ -481,7 +490,7 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
           vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
           vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
 
-          render_line(psx_gpu, vertexes, current_command, 0);
+          render_line(psx_gpu, vertexes, current_command, 0, 0);
 
           list_position += 2;
           num_vertexes++;
@@ -592,12 +601,22 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
                        break;
       }
   
-               case 0x80:          //  vid -> vid
-        render_block_move(psx_gpu, list_s16[2] & 0x3FF, list_s16[3] & 0x1FF,
-         list_s16[4] & 0x3FF, list_s16[5] & 0x1FF,
-         ((list_s16[6] - 1) & 0x3FF) + 1, ((list_s16[7] - 1) & 0x1FF) + 1);
-                       break;
+      case 0x80:          //  vid -> vid
+      {
+        u32 sx = list_s16[2] & 0x3FF;
+        u32 sy = list_s16[3] & 0x1FF;
+        u32 dx = list_s16[4] & 0x3FF;
+        u32 dy = list_s16[5] & 0x1FF;
+        u32 w = ((list_s16[6] - 1) & 0x3FF) + 1;
+        u32 h = ((list_s16[7] - 1) & 0x1FF) + 1;
+
+        if (sx == dx && sy == dy && psx_gpu->mask_msb == 0)
+          break;
+
+        render_block_move(psx_gpu, sx, sy, dx, dy, w, h);
+        break;
+      } 
+
 #ifdef PCSX
                case 0xA0:          //  sys -> vid
                case 0xC0:          //  vid -> sys
@@ -626,7 +645,7 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
 #endif
 
                case 0xE1:
-        set_texture(psx_gpu, list[0] & 0x1FF);
+        set_texture(psx_gpu, list[0]);
 
         if(list[0] & (1 << 9))
           psx_gpu->render_state_base |= RENDER_STATE_DITHER;
@@ -669,11 +688,21 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
         }
         SET_Ex(2, list[0]);
         break;
-               }
+      }
+
+      case 0xE3:
+      {
+        s16 viewport_start_x = list[0] & 0x3FF;
+        s16 viewport_start_y = (list[0] >> 10) & 0x1FF;
+
+        if(viewport_start_x == psx_gpu->viewport_start_x &&
+         viewport_start_y == psx_gpu->viewport_start_y)
+        {
+          break;
+        }
   
-               case 0xE3:
-        psx_gpu->viewport_start_x = list[0] & 0x3FF;
-        psx_gpu->viewport_start_y = (list[0] >> 10) & 0x1FF;
+        psx_gpu->viewport_start_x = viewport_start_x;
+        psx_gpu->viewport_start_y = viewport_start_y;
 
 #ifdef TEXTURE_CACHE_4BPP
         psx_gpu->viewport_mask =
@@ -681,12 +710,23 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
          psx_gpu->viewport_start_y, psx_gpu->viewport_end_x,
          psx_gpu->viewport_end_y);
 #endif
-                       SET_Ex(3, list[0]);
-                       break;
-  
-               case 0xE4:
-        psx_gpu->viewport_end_x = list[0] & 0x3FF;
-        psx_gpu->viewport_end_y = (list[0] >> 10) & 0x1FF;
+        SET_Ex(3, list[0]);
+        break;
+      }
+
+      case 0xE4:
+      {
+        s16 viewport_end_x = list[0] & 0x3FF;
+        s16 viewport_end_y = (list[0] >> 10) & 0x1FF;
+
+        if(viewport_end_x == psx_gpu->viewport_end_x &&
+         viewport_end_y == psx_gpu->viewport_end_y)
+        {
+          break;
+        }
+
+        psx_gpu->viewport_end_x = viewport_end_x;
+        psx_gpu->viewport_end_y = viewport_end_y;
 
 #ifdef TEXTURE_CACHE_4BPP
         psx_gpu->viewport_mask =
@@ -694,10 +734,11 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
          psx_gpu->viewport_start_y, psx_gpu->viewport_end_x,
          psx_gpu->viewport_end_y);
 #endif
-                       SET_Ex(4, list[0]);
-                       break;
+        SET_Ex(4, list[0]);
+        break;
+      }
   
-               case 0xE5:
+      case 0xE5:
       {
         s32 offset_x = list[0] << 21;
         s32 offset_y = list[0] << 10;
@@ -741,3 +782,790 @@ breakloop:
   return list - list_start;
 }
 
+#ifdef PCSX
+
+#define ENH_BUF_TABLE_STEP (1024 / sizeof(psx_gpu->enhancement_buf_by_x16))
+
+static void update_enhancement_buf_table_from_hres(psx_gpu_struct *psx_gpu)
+{
+  u32 b, x, s;
+
+  b = 0;
+  s = psx_gpu->enhancement_x_threshold;
+  for (x = 0; x < sizeof(psx_gpu->enhancement_buf_by_x16); x++)
+  {
+    if (b < 3 && x * ENH_BUF_TABLE_STEP >= s - ENH_BUF_TABLE_STEP - 1)
+    {
+      s += psx_gpu->enhancement_x_threshold;
+      b++;
+    }
+    psx_gpu->enhancement_buf_by_x16[x] = b;
+  }
+}
+
+static void update_enhancement_buf_table_from_x(psx_gpu_struct *psx_gpu,
+ u32 x0, u32 len)
+{
+  u32 x, b;
+
+  for (x = x0, b = 0; x >= len; b++)
+    x -= len;
+  if (b > 3)
+    b = 3;
+
+  memset(psx_gpu->enhancement_buf_by_x16 + x0 / ENH_BUF_TABLE_STEP,
+   b, (len + ENH_BUF_TABLE_STEP - 1) / ENH_BUF_TABLE_STEP);
+}
+
+#define select_enhancement_buf(psx_gpu) \
+  psx_gpu->enhancement_current_buf_ptr = \
+    select_enhancement_buf_ptr(psx_gpu, psx_gpu->saved_viewport_start_x)
+
+#define enhancement_disable() { \
+  psx_gpu->vram_out_ptr = psx_gpu->vram_ptr; \
+  psx_gpu->viewport_start_x = psx_gpu->saved_viewport_start_x; \
+  psx_gpu->viewport_start_y = psx_gpu->saved_viewport_start_y; \
+  psx_gpu->viewport_end_x = psx_gpu->saved_viewport_end_x; \
+  psx_gpu->viewport_end_y = psx_gpu->saved_viewport_end_y; \
+  psx_gpu->uvrgb_phase = 0x8000; \
+}
+
+#define enhancement_enable() { \
+  psx_gpu->vram_out_ptr = psx_gpu->enhancement_current_buf_ptr; \
+  psx_gpu->viewport_start_x = psx_gpu->saved_viewport_start_x * 2; \
+  psx_gpu->viewport_start_y = psx_gpu->saved_viewport_start_y * 2; \
+  psx_gpu->viewport_end_x = psx_gpu->saved_viewport_end_x * 2 + 1; \
+  psx_gpu->viewport_end_y = psx_gpu->saved_viewport_end_y * 2 + 1; \
+  psx_gpu->uvrgb_phase = 0x1000; \
+}
+
+#define shift_vertices3(v) { \
+  v[0]->x *= 2; \
+  v[0]->y *= 2; \
+  v[1]->x *= 2; \
+  v[1]->y *= 2; \
+  v[2]->x *= 2; \
+  v[2]->y *= 2; \
+}
+
+#define unshift_vertices3(v) { \
+  v[0]->x /= 2; \
+  v[0]->y /= 2; \
+  v[1]->x /= 2; \
+  v[1]->y /= 2; \
+  v[2]->x /= 2; \
+  v[2]->y /= 2; \
+}
+
+#define shift_triangle_area() \
+  psx_gpu->triangle_area *= 4
+
+extern void scale2x_tiles8(void *dst, const void *src, int w8, int h);
+
+#ifndef NEON_BUILD
+// TODO?
+void scale2x_tiles8(void *dst, const void *src, int w8, int h) {}
+#endif
+
+static int disable_main_render;
+
+static void do_triangle_enhanced(psx_gpu_struct *psx_gpu,
+ vertex_struct *vertexes, u32 current_command)
+{
+  vertex_struct *vertex_ptrs[3];
+
+  if (!prepare_triangle(psx_gpu, vertexes, vertex_ptrs))
+    return;
+
+  if (!disable_main_render)
+    render_triangle_p(psx_gpu, vertex_ptrs, current_command);
+
+  enhancement_enable();
+  shift_vertices3(vertex_ptrs);
+  shift_triangle_area();
+  render_triangle_p(psx_gpu, vertex_ptrs, current_command);
+}
+
+static void do_quad_enhanced(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
+ u32 current_command)
+{
+  vertex_struct *vertex_ptrs[3];
+
+  if (prepare_triangle(psx_gpu, vertexes, vertex_ptrs)) {
+    if (!disable_main_render)
+      render_triangle_p(psx_gpu, vertex_ptrs, current_command);
+
+    enhancement_enable();
+    shift_vertices3(vertex_ptrs);
+    shift_triangle_area();
+    render_triangle_p(psx_gpu, vertex_ptrs, current_command);
+    unshift_vertices3(vertex_ptrs);
+  }
+  enhancement_disable();
+  if (prepare_triangle(psx_gpu, &vertexes[1], vertex_ptrs)) {
+    if (!disable_main_render)
+      render_triangle_p(psx_gpu, vertex_ptrs, current_command);
+
+    enhancement_enable();
+    shift_vertices3(vertex_ptrs);
+    shift_triangle_area();
+    render_triangle_p(psx_gpu, vertex_ptrs, current_command);
+  }
+}
+
+#if 0
+
+#define fill_vertex(i, x_, y_, u_, v_, rgb_) \
+  vertexes[i].x = x_; \
+  vertexes[i].y = y_; \
+  vertexes[i].u = u_; \
+  vertexes[i].v = v_; \
+  vertexes[i].r = rgb_; \
+  vertexes[i].g = (rgb_) >> 8; \
+  vertexes[i].b = (rgb_) >> 16
+
+static void do_sprite_enhanced(psx_gpu_struct *psx_gpu, int x, int y,
+ u32 u, u32 v, u32 w, u32 h, u32 cmd_rgb)
+{
+  vertex_struct *vertex_ptrs[3];
+  u32 flags = (cmd_rgb >> 24);
+  u32 color = cmd_rgb & 0xffffff;
+  u32 render_state_base_saved = psx_gpu->render_state_base;
+  int x1, y1;
+  u8 u1, v1;
+
+  flags &=
+   (RENDER_FLAGS_MODULATE_TEXELS | RENDER_FLAGS_BLEND |
+   RENDER_FLAGS_TEXTURE_MAP);
+
+  set_triangle_color(psx_gpu, color);
+  if(color == 0x808080)
+    flags |= RENDER_FLAGS_MODULATE_TEXELS;
+
+  psx_gpu->render_state_base &= ~RENDER_STATE_DITHER;
+  enhancement_enable();
+
+  x1 = x + w;
+  y1 = y + h;
+  u1 = u + w;
+  v1 = v + h;
+  // FIXME..
+  if (u1 < u) u1 = 0xff;
+  if (v1 < v) v1 = 0xff;
+
+  // 0-2
+  // |/
+  // 1
+  fill_vertex(0, x,  y,  u,  v,  color);
+  fill_vertex(1, x,  y1, u,  v1, color);
+  fill_vertex(2, x1, y,  u1, v,  color);
+  if (prepare_triangle(psx_gpu, vertexes, vertex_ptrs)) {
+    shift_vertices3(vertex_ptrs);
+    shift_triangle_area();
+    render_triangle_p(psx_gpu, vertex_ptrs, flags);
+  }
+
+  //   0
+  //  /|
+  // 1-2
+  fill_vertex(0, x1, y,  u1, v,  color);
+  fill_vertex(1, x,  y1, u,  v1, color);
+  fill_vertex(2, x1, y1, u1, v1, color);
+  if (prepare_triangle(psx_gpu, vertexes, vertex_ptrs)) {
+    shift_vertices3(vertex_ptrs);
+    shift_triangle_area();
+    render_triangle_p(psx_gpu, vertex_ptrs, flags);
+  }
+
+  psx_gpu->render_state_base = render_state_base_saved;
+}
+#else
+static void do_sprite_enhanced(psx_gpu_struct *psx_gpu, int x, int y,
+ u32 u, u32 v, u32 w, u32 h, u32 cmd_rgb)
+{
+  u32 flags = (cmd_rgb >> 24);
+  u32 color = cmd_rgb & 0xffffff;
+
+  render_sprite_4x(psx_gpu, x, y, u, v, w, h, flags, color);
+}
+#endif
+
+u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size,
+ u32 *last_command)
+{
+  u32 current_command = 0, command_length;
+
+  u32 *list_start = list;
+  u32 *list_end = list + (size / 4);
+
+  psx_gpu->saved_viewport_start_x = psx_gpu->viewport_start_x;
+  psx_gpu->saved_viewport_start_y = psx_gpu->viewport_start_y;
+  psx_gpu->saved_viewport_end_x = psx_gpu->viewport_end_x;
+  psx_gpu->saved_viewport_end_y = psx_gpu->viewport_end_y;
+  select_enhancement_buf(psx_gpu);
+
+  for(; list < list_end; list += 1 + command_length)
+  {
+    s16 *list_s16 = (void *)list;
+    current_command = *list >> 24;
+    command_length = command_lengths[current_command];
+    if (list + 1 + command_length > list_end) {
+      current_command = (u32)-1;
+      break;
+    }
+
+    enhancement_disable();
+
+    switch(current_command)
+    {
+      case 0x00:
+        break;
+  
+      case 0x02:
+      {
+        u32 x = list_s16[2] & 0x3FF;
+        u32 y = list_s16[3] & 0x1FF;
+        u32 width = list_s16[4] & 0x3FF;
+        u32 height = list_s16[5] & 0x1FF;
+        u32 color = list[0] & 0xFFFFFF;
+
+        x &= ~0xF;
+        width = ((width + 0xF) & ~0xF);
+
+        do_fill(psx_gpu, x, y, width, height, color);
+
+        psx_gpu->vram_out_ptr = select_enhancement_buf_ptr(psx_gpu, x);
+        x *= 2;
+        y *= 2;
+        width *= 2;
+        height *= 2;
+        render_block_fill_enh(psx_gpu, color, x, y, width, height);
+        break;
+      }
+  
+      case 0x20 ... 0x23:
+      {
+        set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
+  
+        get_vertex_data_xy(0, 2);
+        get_vertex_data_xy(1, 4);
+        get_vertex_data_xy(2, 6);
+
+        do_triangle_enhanced(psx_gpu, vertexes, current_command);
+        break;
+      }
+  
+      case 0x24 ... 0x27:
+      {
+        set_clut(psx_gpu, list_s16[5]);
+        set_texture(psx_gpu, list_s16[9]);
+        set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
+  
+        get_vertex_data_xy_uv(0, 2);
+        get_vertex_data_xy_uv(1, 6);
+        get_vertex_data_xy_uv(2, 10);
+  
+        do_triangle_enhanced(psx_gpu, vertexes, current_command);
+        break;
+      }
+  
+      case 0x28 ... 0x2B:
+      {
+        set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
+  
+        get_vertex_data_xy(0, 2);
+        get_vertex_data_xy(1, 4);
+        get_vertex_data_xy(2, 6);
+        get_vertex_data_xy(3, 8);
+
+        do_quad_enhanced(psx_gpu, vertexes, current_command);
+        break;
+      }
+  
+      case 0x2C ... 0x2F:
+      {
+        set_clut(psx_gpu, list_s16[5]);
+        set_texture(psx_gpu, list_s16[9]);
+        set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
+  
+        get_vertex_data_xy_uv(0, 2);   
+        get_vertex_data_xy_uv(1, 6);   
+        get_vertex_data_xy_uv(2, 10);  
+        get_vertex_data_xy_uv(3, 14);
+  
+        do_quad_enhanced(psx_gpu, vertexes, current_command);
+        break;
+      }
+  
+      case 0x30 ... 0x33:
+      {
+        get_vertex_data_xy_rgb(0, 0);
+        get_vertex_data_xy_rgb(1, 4);
+        get_vertex_data_xy_rgb(2, 8);
+  
+        do_triangle_enhanced(psx_gpu, vertexes, current_command);
+        break;
+      }
+  
+      case 0x34:
+      case 0x35:
+      case 0x36:
+      case 0x37:
+      {
+        set_clut(psx_gpu, list_s16[5]);
+        set_texture(psx_gpu, list_s16[11]);
+  
+        get_vertex_data_xy_uv_rgb(0, 0);
+        get_vertex_data_xy_uv_rgb(1, 6);
+        get_vertex_data_xy_uv_rgb(2, 12);
+
+        do_triangle_enhanced(psx_gpu, vertexes, current_command);
+        break;
+      }
+  
+      case 0x38:
+      case 0x39:
+      case 0x3A:
+      case 0x3B:
+      {
+        get_vertex_data_xy_rgb(0, 0);
+        get_vertex_data_xy_rgb(1, 4);
+        get_vertex_data_xy_rgb(2, 8);
+        get_vertex_data_xy_rgb(3, 12);
+  
+        do_quad_enhanced(psx_gpu, vertexes, current_command);
+        break;
+      }
+  
+      case 0x3C:
+      case 0x3D:
+      case 0x3E:
+      case 0x3F:
+      {
+        set_clut(psx_gpu, list_s16[5]);
+        set_texture(psx_gpu, list_s16[11]);
+  
+        get_vertex_data_xy_uv_rgb(0, 0);
+        get_vertex_data_xy_uv_rgb(1, 6);
+        get_vertex_data_xy_uv_rgb(2, 12);
+        get_vertex_data_xy_uv_rgb(3, 18);
+
+        do_quad_enhanced(psx_gpu, vertexes, current_command);
+        break;
+      }
+  
+      case 0x40 ... 0x47:
+      {
+        vertexes[0].x = list_s16[2] + psx_gpu->offset_x;
+        vertexes[0].y = list_s16[3] + psx_gpu->offset_y;
+        vertexes[1].x = list_s16[4] + psx_gpu->offset_x;
+        vertexes[1].y = list_s16[5] + psx_gpu->offset_y;
+
+        render_line(psx_gpu, vertexes, current_command, list[0], 0);
+        enhancement_enable();
+        render_line(psx_gpu, vertexes, current_command, list[0], 1);
+        break;
+      }
+  
+      case 0x48 ... 0x4F:
+      {
+        u32 num_vertexes = 1;
+        u32 *list_position = &(list[2]);
+        u32 xy = list[1];
+
+        vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
+        vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
+      
+        xy = *list_position;
+        while(1)
+        {
+          vertexes[0] = vertexes[1];
+
+          vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
+          vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
+
+          enhancement_disable();
+          render_line(psx_gpu, vertexes, current_command, list[0], 0);
+          enhancement_enable();
+          render_line(psx_gpu, vertexes, current_command, list[0], 1);
+
+          list_position++;
+          num_vertexes++;
+
+          if(list_position >= list_end)
+            break;
+
+          xy = *list_position;
+          if((xy & 0xF000F000) == 0x50005000)
+            break;
+        }
+
+        command_length += (num_vertexes - 2);
+        break;
+      }
+  
+      case 0x50 ... 0x57:
+      {
+        vertexes[0].r = list[0] & 0xFF;
+        vertexes[0].g = (list[0] >> 8) & 0xFF;
+        vertexes[0].b = (list[0] >> 16) & 0xFF;
+        vertexes[0].x = list_s16[2] + psx_gpu->offset_x;
+        vertexes[0].y = list_s16[3] + psx_gpu->offset_y;
+
+        vertexes[1].r = list[2] & 0xFF;
+        vertexes[1].g = (list[2] >> 8) & 0xFF;
+        vertexes[1].b = (list[2] >> 16) & 0xFF;
+        vertexes[1].x = list_s16[6] + psx_gpu->offset_x;
+        vertexes[1].y = list_s16[7] + psx_gpu->offset_y;
+
+        render_line(psx_gpu, vertexes, current_command, 0, 0);
+        enhancement_enable();
+        render_line(psx_gpu, vertexes, current_command, 0, 1);
+        break;
+      }
+      case 0x58 ... 0x5F:
+      {
+        u32 num_vertexes = 1;
+        u32 *list_position = &(list[2]);
+        u32 color = list[0];
+        u32 xy = list[1];
+
+        vertexes[1].r = color & 0xFF;
+        vertexes[1].g = (color >> 8) & 0xFF;
+        vertexes[1].b = (color >> 16) & 0xFF;
+        vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
+        vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
+      
+        color = list_position[0];
+        while(1)
+        {
+          xy = list_position[1];
+
+          vertexes[0] = vertexes[1];
+
+          vertexes[1].r = color & 0xFF;
+          vertexes[1].g = (color >> 8) & 0xFF;
+          vertexes[1].b = (color >> 16) & 0xFF;
+          vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
+          vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
+
+          enhancement_disable();
+          render_line(psx_gpu, vertexes, current_command, 0, 0);
+          enhancement_enable();
+          render_line(psx_gpu, vertexes, current_command, 0, 1);
+
+          list_position += 2;
+          num_vertexes++;
+
+          if(list_position >= list_end)
+            break;
+
+          color = list_position[0];
+          if((color & 0xF000F000) == 0x50005000)
+            break;
+        }
+
+        command_length += ((num_vertexes - 2) * 2);
+        break;
+      }
+  
+      case 0x60 ... 0x63:
+      {        
+        u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
+        u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
+        u32 width = list_s16[4] & 0x3FF;
+        u32 height = list_s16[5] & 0x1FF;
+
+        render_sprite(psx_gpu, x, y, 0, 0, width, height, current_command, list[0]);
+        do_sprite_enhanced(psx_gpu, x, y, 0, 0, width, height, list[0]);
+        break;
+      }
+  
+      case 0x64 ... 0x67:
+      {        
+        u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
+        u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
+        u8 u = list_s16[4];
+        u8 v = list_s16[4] >> 8;
+        u32 width = list_s16[6] & 0x3FF;
+        u32 height = list_s16[7] & 0x1FF;
+
+        set_clut(psx_gpu, list_s16[5]);
+
+        render_sprite(psx_gpu, x, y, u, v, width, height,
+         current_command, list[0]);
+        do_sprite_enhanced(psx_gpu, x, y, u, v, width, height, list[0]);
+        break;
+      }
+  
+      case 0x68:
+      case 0x69:
+      case 0x6A:
+      case 0x6B:
+      {
+        s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
+        s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
+
+        render_sprite(psx_gpu, x, y, 0, 0, 1, 1, current_command, list[0]);
+        do_sprite_enhanced(psx_gpu, x, y, 0, 0, 1, 1, list[0]);
+        break;
+      }
+  
+      case 0x70:
+      case 0x71:
+      case 0x72:
+      case 0x73:
+      {        
+        s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
+        s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
+
+        render_sprite(psx_gpu, x, y, 0, 0, 8, 8, current_command, list[0]);
+        do_sprite_enhanced(psx_gpu, x, y, 0, 0, 8, 8, list[0]);
+        break;
+      }
+  
+      case 0x74:
+      case 0x75:
+      case 0x76:
+      case 0x77:
+      {        
+        s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
+        s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
+        u8 u = list_s16[4];
+        u8 v = list_s16[4] >> 8;
+
+        set_clut(psx_gpu, list_s16[5]);
+
+        render_sprite(psx_gpu, x, y, u, v, 8, 8,
+         current_command, list[0]);
+        do_sprite_enhanced(psx_gpu, x, y, u, v, 8, 8, list[0]);
+        break;
+      }
+  
+      case 0x78:
+      case 0x79:
+      case 0x7A:
+      case 0x7B:
+      {        
+        s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
+        s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
+
+        render_sprite(psx_gpu, x, y, 0, 0, 16, 16, current_command, list[0]);
+        do_sprite_enhanced(psx_gpu, x, y, 0, 0, 16, 16, list[0]);
+        break;
+      }
+  
+      case 0x7C:
+      case 0x7D:
+      case 0x7E:
+      case 0x7F:
+      {        
+        s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
+        s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
+        u8 u = list_s16[4];
+        u8 v = list_s16[4] >> 8;
+
+        set_clut(psx_gpu, list_s16[5]);
+
+        render_sprite(psx_gpu, x, y, u, v, 16, 16, current_command, list[0]);
+        do_sprite_enhanced(psx_gpu, x, y, u, v, 16, 16, list[0]);
+        break;
+      }
+  
+      case 0x80:          //  vid -> vid
+      {
+        u32 sx = list_s16[2] & 0x3FF;
+        u32 sy = list_s16[3] & 0x1FF;
+        u32 dx = list_s16[4] & 0x3FF;
+        u32 dy = list_s16[5] & 0x1FF;
+        u32 w = ((list_s16[6] - 1) & 0x3FF) + 1;
+        u32 h = ((list_s16[7] - 1) & 0x1FF) + 1;
+        u16 *buf;
+
+        if (sx == dx && sy == dy && psx_gpu->mask_msb == 0)
+          break;
+
+        render_block_move(psx_gpu, sx, sy, dx, dy, w, h);
+        if (dy + h > 512)
+          h = 512 - dy;
+        sx = sx & ~7; // FIXME?
+        dx = dx * 2 & ~7;
+        dy *= 2;
+        w = (w + 7) / 8;
+        buf = select_enhancement_buf_ptr(psx_gpu, dx / 2);
+        scale2x_tiles8(buf + dy * 1024 + dx,
+          psx_gpu->vram_ptr + sy * 1024 + sx, w, h);
+        break;
+      }
+      case 0xA0:          //  sys -> vid
+      case 0xC0:          //  vid -> sys
+        goto breakloop;
+
+      case 0xE1:
+        set_texture(psx_gpu, list[0]);
+
+        if(list[0] & (1 << 9))
+          psx_gpu->render_state_base |= RENDER_STATE_DITHER;
+        else
+          psx_gpu->render_state_base &= ~RENDER_STATE_DITHER;
+
+        psx_gpu->display_area_draw_enable = (list[0] >> 10) & 0x1;
+        SET_Ex(1, list[0]);
+        break;
+  
+      case 0xE2:
+      {
+        // TODO: Clean
+        u32 texture_window_settings = list[0];
+        u32 tmp, x, y, w, h;
+
+        if(texture_window_settings != psx_gpu->texture_window_settings)
+        {
+          tmp = (texture_window_settings & 0x1F) | 0x20;
+          for(w = 8; (tmp & 1) == 0; tmp >>= 1, w <<= 1);
+
+          tmp = ((texture_window_settings >> 5) & 0x1f) | 0x20;
+          for (h = 8; (tmp & 1) == 0; tmp >>= 1, h <<= 1);
+
+          tmp = 32 - (w >> 3);
+          x = ((texture_window_settings >> 10) & tmp) << 3;
+
+          tmp = 32 - (h >> 3);
+          y = ((texture_window_settings >> 15) & tmp) << 3;
+
+          flush_render_block_buffer(psx_gpu);
+          
+          psx_gpu->texture_window_settings = texture_window_settings;
+          psx_gpu->texture_window_x = x;
+          psx_gpu->texture_window_y = y;
+          psx_gpu->texture_mask_width = w - 1;
+          psx_gpu->texture_mask_height = h - 1;
+
+          update_texture_ptr(psx_gpu);
+        }
+        SET_Ex(2, list[0]);
+        break;
+      }
+  
+      case 0xE3:
+      {
+        s16 viewport_start_x = list[0] & 0x3FF;
+        s16 viewport_start_y = (list[0] >> 10) & 0x1FF;
+        u32 w;
+        s32 d;
+
+        if(viewport_start_x == psx_gpu->viewport_start_x &&
+         viewport_start_y == psx_gpu->viewport_start_y)
+        {
+          break;
+        }
+        psx_gpu->viewport_start_x = viewport_start_x;
+        psx_gpu->viewport_start_y = viewport_start_y;
+        psx_gpu->saved_viewport_start_x = viewport_start_x;
+        psx_gpu->saved_viewport_start_y = viewport_start_y;
+
+        w = (u32)psx_gpu->viewport_end_x - (u32)viewport_start_x + 1;
+        d = psx_gpu->enhancement_x_threshold - w;
+        if(-16 <= d && d <= 16)
+        {
+          update_enhancement_buf_table_from_x(psx_gpu,
+           viewport_start_x, w);
+        }
+        select_enhancement_buf(psx_gpu);
+
+#ifdef TEXTURE_CACHE_4BPP
+        psx_gpu->viewport_mask =
+         texture_region_mask(psx_gpu->viewport_start_x,
+         psx_gpu->viewport_start_y, psx_gpu->viewport_end_x,
+         psx_gpu->viewport_end_y);
+#endif
+        SET_Ex(3, list[0]);
+        break;
+      }
+
+      case 0xE4:
+      {
+        s16 viewport_end_x = list[0] & 0x3FF;
+        s16 viewport_end_y = (list[0] >> 10) & 0x1FF;
+        u32 w;
+        s32 d;
+
+        if(viewport_end_x == psx_gpu->viewport_end_x &&
+         viewport_end_y == psx_gpu->viewport_end_y)
+        {
+          break;
+        }
+
+        psx_gpu->viewport_end_x = viewport_end_x;
+        psx_gpu->viewport_end_y = viewport_end_y;
+        psx_gpu->saved_viewport_end_x = viewport_end_x;
+        psx_gpu->saved_viewport_end_y = viewport_end_y;
+
+        w = (u32)viewport_end_x - (u32)psx_gpu->viewport_start_x + 1;
+        d = psx_gpu->enhancement_x_threshold - w;
+        if(-16 <= d && d <= 16)
+        {
+          update_enhancement_buf_table_from_x(psx_gpu,
+           psx_gpu->viewport_start_x, w);
+        }
+        select_enhancement_buf(psx_gpu);
+
+#ifdef TEXTURE_CACHE_4BPP
+        psx_gpu->viewport_mask =
+         texture_region_mask(psx_gpu->viewport_start_x,
+         psx_gpu->viewport_start_y, psx_gpu->viewport_end_x,
+         psx_gpu->viewport_end_y);
+#endif
+        SET_Ex(4, list[0]);
+        break;
+      }
+  
+      case 0xE5:
+      {
+        s32 offset_x = list[0] << 21;
+        s32 offset_y = list[0] << 10;
+        psx_gpu->offset_x = offset_x >> 21;
+        psx_gpu->offset_y = offset_y >> 21; 
+  
+        SET_Ex(5, list[0]);
+        break;
+      }
+
+      case 0xE6:
+      {
+        u32 mask_settings = list[0];
+        u16 mask_msb = mask_settings << 15;
+
+        if(list[0] & 0x2)
+          psx_gpu->render_state_base |= RENDER_STATE_MASK_EVALUATE;
+        else
+          psx_gpu->render_state_base &= ~RENDER_STATE_MASK_EVALUATE;
+
+        if(mask_msb != psx_gpu->mask_msb)
+        {
+          flush_render_block_buffer(psx_gpu);
+          psx_gpu->mask_msb = mask_msb;
+        }
+
+        SET_Ex(6, list[0]);
+        break;
+      }
+  
+      default:
+        break;
+    }
+  }
+
+  enhancement_disable();
+
+breakloop:
+  if (last_command != NULL)
+    *last_command = current_command;
+  return list - list_start;
+}
+
+#endif /* PCSX */
+
+// vim:shiftwidth=2:expandtab
index 210f44d..58cca29 100644 (file)
@@ -13,7 +13,7 @@ ASFLAGS = $(CFLAGS)
 OBJ += psx_gpu_arm_neon.o
 endif
 ifndef DEBUG
-CFLAGS += -O2 -fno-strict-aliasing
+CFLAGS += -O2 -DNDEBUG -fno-strict-aliasing
 endif
 
 OBJ += psx_gpu.o psx_gpu_parse.o psx_gpu_main.o
index c11955d..c91e7d9 100644 (file)
@@ -394,6 +394,10 @@ build_vector_types(s);
   foreach_element(8, (dest).e[_i] =                                            \
    (u8)(source_a).e[_i] | ((u8)(source_b).e[_i] << 8))                         \
 
+#define zip_4x32b(dest, source_a, source_b)                                    \
+  foreach_element(4, (dest).e[_i] =                                            \
+   (u16)(source_a).e[_i] | ((u16)(source_b).e[_i] << 16))                      \
+
 #define zip_2x64b(dest, source_a, source_b)                                    \
   foreach_element(2, (dest).e[_i] =                                            \
    (u64)(source_a).e[_i] | ((u64)(source_b).e[_i] << 32))                      \
index ff31c27..ad01761 100644 (file)
@@ -9,11 +9,13 @@
  */
 
 #include <stdio.h>
+#include <sys/mman.h>
 
 extern const unsigned char cmd_lengths[256];
 #define command_lengths cmd_lengths
 
 static unsigned int *ex_regs;
+static int initialized;
 
 #define PCSX
 #define SET_Ex(r, v) \
@@ -27,20 +29,102 @@ static psx_gpu_struct egpu __attribute__((aligned(256)));
 
 int do_cmd_list(uint32_t *list, int count, int *last_cmd)
 {
-  int ret = gpu_parse(&egpu, list, count * 4, (u32 *)last_cmd);
+  int ret;
+
+  if (gpu.state.enhancement_active)
+    ret = gpu_parse_enhanced(&egpu, list, count * 4, (u32 *)last_cmd);
+  else
+    ret = gpu_parse(&egpu, list, count * 4, (u32 *)last_cmd);
 
   ex_regs[1] &= ~0x1ff;
   ex_regs[1] |= egpu.texture_settings & 0x1ff;
   return ret;
 }
 
+#define ENHANCEMENT_BUF_SIZE (1024 * 1024 * 2 * 4 + 4096 * 2)
+
+static uint16_t *get_enhancement_bufer(int *x, int *y, int *w, int *h,
+ int *vram_h)
+{
+  uint16_t *ret = select_enhancement_buf_ptr(&egpu, *x);
+
+  *x *= 2;
+  *y *= 2;
+  *w = *w * 2;
+  *h = *h * 2;
+  *vram_h = 1024;
+  return ret;
+}
+
+static void map_enhancement_buffer(void)
+{
+  // currently we use 4x 1024*1024 buffers instead of single 2048*1024
+  // to be able to reuse 1024-width code better (triangle setup,
+  // dithering phase, lines).
+  egpu.enhancement_buf_ptr = gpu.mmap(ENHANCEMENT_BUF_SIZE);
+  if (egpu.enhancement_buf_ptr == NULL) {
+    fprintf(stderr, "failed to map enhancement buffer\n");
+    gpu.get_enhancement_bufer = NULL;
+  }
+  else {
+    egpu.enhancement_buf_ptr += 4096 / 2;
+    gpu.get_enhancement_bufer = get_enhancement_bufer;
+  }
+}
+
 int renderer_init(void)
 {
-  initialize_psx_gpu(&egpu, gpu.vram);
+  if (gpu.vram != NULL) {
+    initialize_psx_gpu(&egpu, gpu.vram);
+    initialized = 1;
+  }
+
+  if (gpu.mmap != NULL && egpu.enhancement_buf_ptr == NULL)
+    map_enhancement_buffer();
+
   ex_regs = gpu.ex_regs;
   return 0;
 }
 
+void renderer_finish(void)
+{
+  if (egpu.enhancement_buf_ptr != NULL) {
+    egpu.enhancement_buf_ptr -= 4096 / 2;
+    gpu.munmap(egpu.enhancement_buf_ptr, ENHANCEMENT_BUF_SIZE);
+  }
+  egpu.enhancement_buf_ptr = NULL;
+  egpu.enhancement_current_buf_ptr = NULL;
+  initialized = 0;
+}
+
+static __attribute__((noinline)) void
+sync_enhancement_buffers(int x, int y, int w, int h)
+{
+  const int step_x = 1024 / sizeof(egpu.enhancement_buf_by_x16);
+  u16 *src, *dst;
+  int w1, fb_index;
+
+  w += x & (step_x - 1);
+  x &= ~(step_x - 1);
+  w = (w + step_x - 1) & ~(step_x - 1);
+  if (y + h > 512)
+    h = 512 - y;
+
+  while (w > 0) {
+    fb_index = egpu.enhancement_buf_by_x16[x / step_x];
+    for (w1 = 0; w > 0; w1++, w -= step_x)
+      if (fb_index != egpu.enhancement_buf_by_x16[x / step_x + w1])
+        break;
+
+    src = gpu.vram + y * 1024 + x;
+    dst = select_enhancement_buf_ptr(&egpu, x);
+    dst += (y * 1024 + x) * 2;
+    scale2x_tiles8(dst, src, w1 * step_x / 8, h);
+
+    x += w1 * step_x;
+  }
+}
+
 void renderer_sync_ecmds(uint32_t *ecmds)
 {
   gpu_parse(&egpu, ecmds + 1, 6 * 4, NULL);
@@ -49,6 +133,8 @@ void renderer_sync_ecmds(uint32_t *ecmds)
 void renderer_update_caches(int x, int y, int w, int h)
 {
   update_texture_cache_region(&egpu, x, y, x + w - 1, y + h - 1);
+  if (gpu.state.enhancement_active && !gpu.status.rgb24)
+    sync_enhancement_buffers(x, y, w, h);
 }
 
 void renderer_flush_queues(void)
@@ -58,13 +144,44 @@ void renderer_flush_queues(void)
 
 void renderer_set_interlace(int enable, int is_odd)
 {
-  egpu.interlace_mode &= ~(RENDER_INTERLACE_ENABLED|RENDER_INTERLACE_ODD);
+  egpu.render_mode &= ~(RENDER_INTERLACE_ENABLED|RENDER_INTERLACE_ODD);
   if (enable)
-    egpu.interlace_mode |= RENDER_INTERLACE_ENABLED;
+    egpu.render_mode |= RENDER_INTERLACE_ENABLED;
   if (is_odd)
-    egpu.interlace_mode |= RENDER_INTERLACE_ODD;
+    egpu.render_mode |= RENDER_INTERLACE_ODD;
 }
 
+void renderer_notify_res_change(void)
+{
+  // note: must keep it multiple of 8
+  if (egpu.enhancement_x_threshold != gpu.screen.hres)
+  {
+    egpu.enhancement_x_threshold = gpu.screen.hres;
+    update_enhancement_buf_table_from_hres(&egpu);
+  }
+}
+
+#include "../../frontend/plugin_lib.h"
+
 void renderer_set_config(const struct rearmed_cbs *cbs)
 {
+  static int enhancement_was_on;
+
+  disable_main_render = cbs->gpu_neon.enhancement_no_main;
+  if (egpu.enhancement_buf_ptr != NULL && cbs->gpu_neon.enhancement_enable
+      && !enhancement_was_on)
+  {
+    sync_enhancement_buffers(0, 0, 1024, 512);
+  }
+  enhancement_was_on = cbs->gpu_neon.enhancement_enable;
+
+  if (!initialized) {
+    initialize_psx_gpu(&egpu, gpu.vram);
+    initialized = 1;
+  }
+
+  if (gpu.mmap != NULL && egpu.enhancement_buf_ptr == NULL)
+    map_enhancement_buffer();
+  if (cbs->pl_set_gpu_caps)
+    cbs->pl_set_gpu_caps(GPU_CAP_SUPPORTS_2X);
 }
index 46552ac..df5e0cf 100644 (file)
@@ -824,7 +824,6 @@ void  GPU_updateLace(void)
 extern "C" {
 
 static const struct rearmed_cbs *cbs;
-static void *screen_buf;
 static s16 old_res_horz, old_res_vert, old_rgb24;
 
 static void blit(void)
@@ -832,12 +831,10 @@ static void blit(void)
        u16 *base = (u16 *)GPU_FrameBuffer;
        s16 isRGB24 = (GPU_GP1 & 0x00200000) ? 1 : 0;
        s16 h0, x0, y0, w0, h1;
-       u32 fb_offs;
-       u8  *dest;
 
        x0 = DisplayArea[0] & ~1; // alignment needed by blitter
        y0 = DisplayArea[1];
-       fb_offs = FRAME_OFFSET(x0, y0);
+       base += FRAME_OFFSET(x0, y0);
 
        w0 = DisplayArea[2];
        h0 = DisplayArea[3];  // video mode
@@ -853,62 +850,10 @@ static void blit(void)
                old_res_horz = w0;
                old_res_vert = h1;
                old_rgb24 = (s16)isRGB24;
-               screen_buf = cbs->pl_vout_set_mode(w0, h1, isRGB24 ? 24 : 16);
+               cbs->pl_vout_set_mode(w0, h1, w0, h1, isRGB24 ? 24 : 16);
        }
-       dest = (u8 *)screen_buf;
 
-       if (isRGB24)
-       {
-               if (!cbs->only_16bpp)
-               {
-                       for (; h1-- > 0; dest += w0 * 3, fb_offs += 1024)
-                       {
-                               fb_offs &= 1024*512-1;
-                               bgr888_to_rgb888(dest, base + fb_offs, w0 * 3);
-                       }
-               }
-               else
-               {
-                       for (; h1-- > 0; dest += w0 * 2, fb_offs += 1024)
-                       {
-                               fb_offs &= 1024*512-1;
-                               bgr888_to_rgb565(dest, base + fb_offs, w0 * 3);
-                       }
-               }
-       }
-       else
-       {
-               for (; h1-- > 0; dest += w0 * 2, fb_offs += 1024)
-               {
-                       fb_offs &= 1024*512-1;
-                       bgr555_to_rgb565(dest, base + fb_offs, w0 * 2);
-               }
-       }
-
-       screen_buf = cbs->pl_vout_flip();
-}
-
-static void blit_raw(void)
-{
-       s16 isRGB24 = (GPU_GP1 & 0x00200000) ? 1 : 0;
-       s16 h0, w0, h1;
-
-       w0 = DisplayArea[2];
-       h0 = DisplayArea[3];  // video mode
-       h1 = DisplayArea[5] - DisplayArea[4]; // display needed
-       if (h0 == 480) h1 = Min2(h1*2,480);
-
-       if (h1 <= 0)
-               return;
-
-       if (w0 != old_res_horz || h1 != old_res_vert || isRGB24 != old_rgb24)
-       {
-               old_res_horz = w0;
-               old_res_vert = h1;
-               old_rgb24 = (s16)isRGB24;
-               screen_buf = cbs->pl_vout_set_mode(w0, h1, isRGB24 ? 24 : 16);
-       }
-       cbs->pl_vout_raw_flip(DisplayArea[0], DisplayArea[1]);
+       cbs->pl_vout_flip(base, 1024, isRGB24, w0, h1);
 }
 
 void GPU_updateLace(void)
@@ -920,10 +865,7 @@ void GPU_updateLace(void)
                return;
 
        if (!wasSkip) {
-               if (cbs->pl_vout_raw_flip != NULL)
-                       blit_raw();
-               else
-                       blit();
+               blit();
                fb_dirty = false;
                skCount = 0;
        }
@@ -939,7 +881,6 @@ void GPU_updateLace(void)
 long GPUopen(unsigned long *, char *, char *)
 {
        cbs->pl_vout_open();
-       screen_buf = cbs->pl_vout_flip();
        return 0;
 }
 
@@ -966,6 +907,8 @@ void GPUrearmedCallbacks(const struct rearmed_cbs *cbs_)
                cbs_->pl_vout_set_raw_vram((void *)GPU_FrameBuffer);
 
        cbs = cbs_;
+       if (cbs->pl_set_gpu_caps)
+               cbs->pl_set_gpu_caps(0);
 }
 
 } /* extern "C" */
index 38e7ce1..de16721 100644 (file)
@@ -154,6 +154,14 @@ int renderer_init(void)
        return 0;
 }
 
+void renderer_finish(void)
+{
+}
+
+void renderer_notify_res_change(void)
+{
+}
+
 extern const unsigned char cmd_lengths[256];
 
 int do_cmd_list(unsigned int *list, int list_len, int *last_cmd)
@@ -525,6 +533,8 @@ void renderer_set_config(const struct rearmed_cbs *cbs)
   enableAbbeyHack = cbs->gpu_unai.abe_hack;
   light = !cbs->gpu_unai.no_light;
   blend = !cbs->gpu_unai.no_blend;
+
+  GPU_FrameBuffer = (u16 *)gpu.vram;
 }
 
 #endif
index 1d5718c..8e3bee9 100644 (file)
@@ -1,3 +1,13 @@
+/*
+ * (C) Gražvydas "notaz" Ignotas, 2011,2012
+ *
+ * This work is licensed under the terms of any of these licenses
+ * (at your option):
+ *  - GNU GPL, version 2 or later.
+ *  - GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
 #include "cspace.h"
 
 /*
@@ -5,6 +15,8 @@
  * in favor of NEON version or platform-specific conversion
  */
 
+#ifndef __ARM_NEON__
+
 void bgr555_to_rgb565(void *dst_, const void *src_, int bytes)
 {
        const unsigned int *src = src_;
@@ -42,3 +54,92 @@ void bgr888_to_rgb565(void *dst_, const void *src_, int bytes)
 void rgb888_to_rgb565(void *dst, const void *src, int bytes) {}
 void bgr888_to_rgb888(void *dst, const void *src, int bytes) {}
 
+#endif // __ARM_NEON__
+
+/* YUV stuff */
+static int yuv_ry[32], yuv_gy[32], yuv_by[32];
+static unsigned char yuv_u[32 * 2], yuv_v[32 * 2];
+
+void bgr_to_uyvy_init(void)
+{
+  int i, v;
+
+  /* init yuv converter:
+    y0 = (int)((0.299f * r0) + (0.587f * g0) + (0.114f * b0));
+    y1 = (int)((0.299f * r1) + (0.587f * g1) + (0.114f * b1));
+    u = (int)(8 * 0.565f * (b0 - y0)) + 128;
+    v = (int)(8 * 0.713f * (r0 - y0)) + 128;
+  */
+  for (i = 0; i < 32; i++) {
+    yuv_ry[i] = (int)(0.299f * i * 65536.0f + 0.5f);
+    yuv_gy[i] = (int)(0.587f * i * 65536.0f + 0.5f);
+    yuv_by[i] = (int)(0.114f * i * 65536.0f + 0.5f);
+  }
+  for (i = -32; i < 32; i++) {
+    v = (int)(8 * 0.565f * i) + 128;
+    if (v < 0)
+      v = 0;
+    if (v > 255)
+      v = 255;
+    yuv_u[i + 32] = v;
+    v = (int)(8 * 0.713f * i) + 128;
+    if (v < 0)
+      v = 0;
+    if (v > 255)
+      v = 255;
+    yuv_v[i + 32] = v;
+  }
+}
+
+void bgr555_to_uyvy(void *d, const void *s, int pixels)
+{
+  unsigned int *dst = d;
+  const unsigned short *src = s;
+  const unsigned char *yu = yuv_u + 32;
+  const unsigned char *yv = yuv_v + 32;
+  int r0, g0, b0, r1, g1, b1;
+  int y0, y1, u, v;
+
+  for (; pixels > 0; src += 2, dst++, pixels -= 2)
+  {
+    b0 = (src[0] >> 10) & 0x1f;
+    g0 = (src[0] >> 5) & 0x1f;
+    r0 =  src[0] & 0x1f;
+    b1 = (src[1] >> 10) & 0x1f;
+    g1 = (src[1] >> 5) & 0x1f;
+    r1 =  src[1] & 0x1f;
+    y0 = (yuv_ry[r0] + yuv_gy[g0] + yuv_by[b0]) >> 16;
+    y1 = (yuv_ry[r1] + yuv_gy[g1] + yuv_by[b1]) >> 16;
+    u = yu[b0 - y0];
+    v = yv[r0 - y0];
+    // valid Y range seems to be 16..235
+    y0 = 16 + 219 * y0 / 31;
+    y1 = 16 + 219 * y1 / 31;
+
+    *dst = (y1 << 24) | (v << 16) | (y0 << 8) | u;
+  }
+}
+
+void bgr888_to_uyvy(void *d, const void *s, int pixels)
+{
+  unsigned int *dst = d;
+  const unsigned char *src8 = s;
+  const unsigned char *yu = yuv_u + 32;
+  const unsigned char *yv = yuv_v + 32;
+  int r0, g0, b0, r1, g1, b1;
+  int y0, y1, u, v;
+
+  for (; pixels > 0; src8 += 3*2, dst++, pixels -= 2)
+  {
+    r0 = src8[0], g0 = src8[1], b0 = src8[2];
+    r1 = src8[3], g1 = src8[4], b1 = src8[5];
+    y0 = (r0 * 19595 + g0 * 38470 + b0 * 7471) >> 16;
+    y1 = (r1 * 19595 + g1 * 38470 + b1 * 7471) >> 16;
+    u = yu[(b0 - y0) / 8];
+    v = yv[(r0 - y0) / 8];
+    y0 = 16 + 219 * y0 / 255;
+    y1 = 16 + 219 * y1 / 255;
+
+    *dst = (y1 << 24) | (v << 16) | (y0 << 8) | u;
+  }
+}
index 8c9bcfa..95eae85 100644 (file)
@@ -8,6 +8,10 @@ void bgr888_to_rgb888(void *dst, const void *src, int bytes);
 void bgr888_to_rgb565(void *dst, const void *src, int bytes);
 void rgb888_to_rgb565(void *dst, const void *src, int bytes);
 
+void bgr_to_uyvy_init(void);
+void bgr555_to_uyvy(void *d, const void *s, int pixels);
+void bgr888_to_uyvy(void *d, const void *s, int pixels);
+
 #ifdef __cplusplus
 }
 #endif
index 46e92d1..b300c88 100644 (file)
@@ -24,7 +24,7 @@
 //#define log_anomaly gpu_log
 #define log_anomaly(...)
 
-struct psx_gpu gpu __attribute__((aligned(2048)));
+struct psx_gpu gpu;
 
 static noinline int do_cmd_buffer(uint32_t *data, int count);
 static void finish_vram_transfer(int is_read);
@@ -133,6 +133,22 @@ static noinline void get_gpu_info(uint32_t data)
   }
 }
 
+// double, for overdraw guard
+#define VRAM_SIZE (1024 * 512 * 2 * 2)
+
+static int map_vram(void)
+{
+  gpu.vram = gpu.mmap(VRAM_SIZE);
+  if (gpu.vram != NULL) {
+    gpu.vram += 4096 / 2;
+    return 0;
+  }
+  else {
+    fprintf(stderr, "could not map vram, expect crashes\n");
+    return -1;
+  }
+}
+
 long GPUinit(void)
 {
   int ret;
@@ -145,12 +161,26 @@ long GPUinit(void)
   gpu.cmd_len = 0;
   do_reset();
 
+  if (gpu.mmap != NULL) {
+    if (map_vram() != 0)
+      ret = -1;
+  }
   return ret;
 }
 
 long GPUshutdown(void)
 {
-  return vout_finish();
+  long ret;
+
+  renderer_finish();
+  ret = vout_finish();
+  if (gpu.vram != NULL) {
+    gpu.vram -= 4096 / 2;
+    gpu.munmap(gpu.vram, VRAM_SIZE);
+  }
+  gpu.vram = NULL;
+
+  return ret;
 }
 
 void GPUwriteStatus(uint32_t data)
@@ -182,7 +212,7 @@ void GPUwriteStatus(uint32_t data)
       break;
     case 0x05:
       gpu.screen.x = data & 0x3ff;
-      gpu.screen.y = (data >> 10) & 0x3ff;
+      gpu.screen.y = (data >> 10) & 0x1ff;
       if (gpu.frameskip.set) {
         decide_frameskip_allow(gpu.ex_regs[3]);
         if (gpu.frameskip.last_flip_frame != *gpu.state.frame_count) {
@@ -207,6 +237,7 @@ void GPUwriteStatus(uint32_t data)
       gpu.screen.vres = vres[(gpu.status.reg >> 19) & 3];
       update_width();
       update_height();
+      renderer_notify_res_change();
       break;
     default:
       if ((cmd & 0xf0) == 0x10)
@@ -582,13 +613,13 @@ long GPUfreeze(uint32_t type, struct GPUFreeze *freeze)
     case 1: // save
       if (gpu.cmd_len > 0)
         flush_cmd_buffer();
-      memcpy(freeze->psxVRam, gpu.vram, sizeof(gpu.vram));
+      memcpy(freeze->psxVRam, gpu.vram, 1024 * 512 * 2);
       memcpy(freeze->ulControl, gpu.regs, sizeof(gpu.regs));
       memcpy(freeze->ulControl + 0xe0, gpu.ex_regs, sizeof(gpu.ex_regs));
       freeze->ulStatus = gpu.status.reg;
       break;
     case 0: // load
-      memcpy(gpu.vram, freeze->psxVRam, sizeof(gpu.vram));
+      memcpy(gpu.vram, freeze->psxVRam, 1024 * 512 * 2);
       memcpy(gpu.regs, freeze->ulControl, sizeof(gpu.regs));
       memcpy(gpu.ex_regs, freeze->ulControl + 0xe0, sizeof(gpu.ex_regs));
       gpu.status.reg = freeze->ulStatus;
@@ -669,6 +700,14 @@ void GPUrearmedCallbacks(const struct rearmed_cbs *cbs)
   gpu.state.hcnt = cbs->gpu_hcnt;
   gpu.state.frame_count = cbs->gpu_frame_count;
   gpu.state.allow_interlace = cbs->gpu_neon.allow_interlace;
+  gpu.state.enhancement_enable = cbs->gpu_neon.enhancement_enable;
+
+  gpu.mmap = cbs->mmap;
+  gpu.munmap = cbs->munmap;
+
+  // delayed vram mmap
+  if (gpu.vram == NULL)
+    map_vram();
 
   if (cbs->pl_vout_set_raw_vram)
     cbs->pl_vout_set_raw_vram(gpu.vram);
index 1cbe38c..d11f991 100644 (file)
@@ -17,10 +17,9 @@ extern "C" {
 #define CMD_BUFFER_LEN          1024
 
 struct psx_gpu {
-  uint16_t vram[1024 * 512];
-  uint16_t guard[1024 * 512]; // overdraw guard
   uint32_t cmd_buffer[CMD_BUFFER_LEN];
   uint32_t regs[16];
+  uint16_t *vram;
   union {
     uint32_t reg;
     struct {
@@ -67,6 +66,8 @@ struct psx_gpu {
     uint32_t old_interlace:1;
     uint32_t allow_interlace:2;
     uint32_t blanked:1;
+    uint32_t enhancement_enable:1;
+    uint32_t enhancement_active:1;
     uint32_t *frame_count;
     uint32_t *hcnt; /* hsync count */
     struct {
@@ -87,6 +88,10 @@ struct psx_gpu {
     uint32_t last_flip_frame;
     uint32_t pending_fill[3];
   } frameskip;
+  uint16_t *(*get_enhancement_bufer)
+    (int *x, int *y, int *w, int *h, int *vram_h);
+  void *(*mmap)(unsigned int size);
+  void  (*munmap)(void *ptr, unsigned int size);
 };
 
 extern struct psx_gpu gpu;
@@ -98,11 +103,13 @@ int do_cmd_list(uint32_t *list, int count, int *last_cmd);
 struct rearmed_cbs;
 
 int  renderer_init(void);
+void renderer_finish(void);
 void renderer_sync_ecmds(uint32_t * ecmds);
 void renderer_update_caches(int x, int y, int w, int h);
 void renderer_flush_queues(void);
 void renderer_set_interlace(int enable, int is_odd);
 void renderer_set_config(const struct rearmed_cbs *config);
+void renderer_notify_res_change(void);
 
 int  vout_init(void);
 int  vout_finish(void);
index 349a0c8..ad6a8ad 100644 (file)
@@ -2,7 +2,7 @@
 # always adding gpulib to deps in case cspace is needed
 # users must include ../../config.mak
 
-LDFLAGS += -shared
+LDFLAGS += -shared -Wl,--no-undefined
 CFLAGS += $(PLUGIN_CFLAGS)
 ifeq "$(ARCH)" "arm"
  EXT =
@@ -17,10 +17,10 @@ endif
 GPULIB_A = ../gpulib/gpulib$(EXT).a
 
 ifdef BIN_STANDLALONE
-TARGETS += $(BIN_STANDLALONE)$(EXT)
+TARGETS += $(BIN_STANDLALONE)
 endif
 ifdef BIN_GPULIB
-TARGETS += $(BIN_GPULIB)$(EXT)
+TARGETS += $(BIN_GPULIB)
 endif
 CC_STANDLALONE = $(CC)
 CC_GPULIB = $(CC)
@@ -34,7 +34,7 @@ ifdef BIN_STANDLALONE
 ifneq ($(findstring .cpp,$(SRC_STANDALONE)),)
 CC_STANDLALONE = $(CXX)
 endif
-$(BIN_STANDLALONE)$(EXT): $(SRC) $(SRC_STANDALONE) $(GPULIB_A)
+$(BIN_STANDLALONE): $(SRC) $(SRC_STANDALONE) $(GPULIB_A)
        $(CC_STANDLALONE) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) $(LDLIBS_STANDALONE)
        ln -fs $(PLUGINDIR)/$@ ../
 endif
@@ -43,7 +43,7 @@ ifdef BIN_GPULIB
 ifneq ($(findstring .cpp,$(SRC_GPULIB)),)
 CC_GPULIB = $(CXX)
 endif
-$(BIN_GPULIB)$(EXT): $(SRC) $(SRC_GPULIB) $(GPULIB_A)
+$(BIN_GPULIB): $(SRC) $(SRC_GPULIB) $(GPULIB_A)
        $(CC_GPULIB) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) $(LDLIBS_GPULIB)
        ln -fs $(PLUGINDIR)/$@ ../
 endif
index 0bd1ecf..49f53d6 100644 (file)
@@ -15,7 +15,6 @@
 #include "../../frontend/plugin_lib.h"
 
 static const struct rearmed_cbs *cbs;
-static void *screen_buf;
 
 int vout_init(void)
 {
@@ -27,90 +26,77 @@ int vout_finish(void)
   return 0;
 }
 
-static void check_mode_change(void)
+static void check_mode_change(int force)
 {
   static uint32_t old_status;
   static int old_h;
+  int w = gpu.screen.hres;
+  int h = gpu.screen.h;
+  int w_out = w;
+  int h_out = h;
+
+  gpu.state.enhancement_active =
+    gpu.get_enhancement_bufer != NULL && gpu.state.enhancement_enable
+    && w <= 512 && h <= 256 && !gpu.status.rgb24;
+
+  if (gpu.state.enhancement_active) {
+    w_out *= 2;
+    h_out *= 2;
+  }
 
   // width|rgb24 change?
-  if ((gpu.status.reg ^ old_status) & ((7<<16)|(1<<21)) || gpu.screen.h != old_h)
+  if (force || (gpu.status.reg ^ old_status) & ((7<<16)|(1<<21)) || h != old_h)
   {
     old_status = gpu.status.reg;
-    old_h = gpu.screen.h;
-    screen_buf = cbs->pl_vout_set_mode(gpu.screen.hres, gpu.screen.h,
+    old_h = h;
+
+    cbs->pl_vout_set_mode(w_out, h_out, w, h,
       (gpu.status.rgb24 && !cbs->only_16bpp) ? 24 : 16);
   }
 }
 
-static void blit(void)
+void vout_update(void)
 {
   int x = gpu.screen.x & ~1; // alignment needed by blitter
   int y = gpu.screen.y;
   int w = gpu.screen.w;
   int h = gpu.screen.h;
   uint16_t *vram = gpu.vram;
-  int stride = gpu.screen.hres;
-  int fb_offs, doffs;
-  uint8_t *dest;
+  int vram_h = 512;
 
-  dest = (uint8_t *)screen_buf;
-  if (dest == NULL)
+  if (w == 0 || h == 0)
     return;
 
-  fb_offs = y * 1024 + x;
+  check_mode_change(0);
+  if (gpu.state.enhancement_active)
+    vram = gpu.get_enhancement_bufer(&x, &y, &w, &h, &vram_h);
 
-  // only do centering, at least for now
-  doffs = (stride - w) / 2 & ~1;
-
-  if (gpu.status.rgb24)
-  {
-    if (cbs->only_16bpp) {
-      dest += doffs * 2;
-      for (; h-- > 0; dest += stride * 2, fb_offs += 1024)
-      {
-        fb_offs &= 1024*512-1;
-        bgr888_to_rgb565(dest, vram + fb_offs, w * 3);
-      }
-    }
-    else {
-      dest += (doffs / 8) * 24;
-      for (; h-- > 0; dest += stride * 3, fb_offs += 1024)
-      {
-        fb_offs &= 1024*512-1;
-        bgr888_to_rgb888(dest, vram + fb_offs, w * 3);
-      }
-    }
-  }
-  else
-  {
-    dest += doffs * 2;
-    for (; h-- > 0; dest += stride * 2, fb_offs += 1024)
-    {
-      fb_offs &= 1024*512-1;
-      bgr555_to_rgb565(dest, vram + fb_offs, w * 2);
+  if (y + h > vram_h) {
+    if (y + h - vram_h > h / 2) {
+      // wrap
+      h -= vram_h - y;
+      y = 0;
     }
+    else
+      // clip
+      h = vram_h - y;
   }
 
-  screen_buf = cbs->pl_vout_flip();
-}
+  vram += y * 1024 + x;
 
-void vout_update(void)
-{
-  check_mode_change();
-  if (cbs->pl_vout_raw_flip)
-    cbs->pl_vout_raw_flip(gpu.screen.x, gpu.screen.y);
-  else
-    blit();
+  cbs->pl_vout_flip(vram, 1024, gpu.status.rgb24, w, h);
 }
 
 void vout_blank(void)
 {
-  check_mode_change();
-  if (cbs->pl_vout_raw_flip == NULL) {
-    int bytespp = gpu.status.rgb24 ? 3 : 2;
-    memset(screen_buf, 0, gpu.screen.hres * gpu.screen.h * bytespp);
-    screen_buf = cbs->pl_vout_flip();
+  int w = gpu.screen.hres;
+  int h = gpu.screen.h;
+  if (gpu.state.enhancement_active) {
+    w *= 2;
+    h *= 2;
   }
+  check_mode_change(0);
+  cbs->pl_vout_flip(NULL, 1024, gpu.status.rgb24, w, h);
 }
 
 long GPUopen(void **unused)
@@ -119,7 +105,7 @@ long GPUopen(void **unused)
   gpu.frameskip.frame_ready = 1;
 
   cbs->pl_vout_open();
-  screen_buf = cbs->pl_vout_flip();
+  check_mode_change(1);
   return 0;
 }
 
index dcd25ea..fcfec80 100644 (file)
@@ -1,9 +1,6 @@
 include ../../config.mak
 
-ifneq "$(ARCH)" "arm"
- EXT = .$(ARCH)
-endif
-TARGET = spunull.so$(EXT)
+TARGET = spunull.so
 WD = $(shell pwd)
 PLUGINDIR = $(shell basename $(WD))
 
index cd38f96..6fb7bfd 100644 (file)
@@ -5,7 +5,7 @@
 \r
 typedef struct\r
 {\r
-       long    y0, y1;\r
+       int     y0, y1;\r
 } ADPCM_Decode_t;\r
 \r
 typedef struct\r
index ad90b45..68d2882 100644 (file)
@@ -19,11 +19,28 @@ pixel perfect graphics at very high performance. There is also Una-i's GPU
 plugin from PCSX4ALL project, and traditional P.E.Op.S. one.
 
 
+Compiling
+---------
+
+'./configure && make' should work for the most part.
+
+When compiling for ARM, it's advisable to tell configure script the CPU, FPU
+and ABI that matches your target system to get best performance, like this:
+
+CFLAGS='-mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon -mfloat-abi=softfp' ./configure
+
+Cross compilation should also work if kernel-style CROSS_COMPILE variable
+is set:
+CROSS_COMPILE='arm-none-linux-gnueabi-' ./configure
+
+
 Usage
 -----
 
-This version features a framebuffer driven menu that can be used to run
-games and configure the emulator.
+There are several different frontends that can be built from source (one
+generic and several platform specific), so usage slightly differs depending
+on that. Most of them have a menu that can be used to run games and configure
+the emulator.
 
 Supported CD image formats:
 - .bin/.cue
@@ -43,9 +60,13 @@ extension). This is required for Libcrypt copy protected game support.
 
 The emulator can simulate BIOS, which means BIOS files are not required,
 however implementation is not complete and some games still need real BIOS
-to work. To use real BIOS, copy uncompressed BIOS files to
+to work. To use real BIOS, copy uncompressed BIOS files to bios/ directory
+which itself should be in main emulator directory.
+
+For pandora, it should be:
 [sd card]/pandora/appdata/pcsx_rearmed/bios/
-then select the BIOS you want to use in Options->BIOS/Plugins menu.
+
+When the file is copied, BIOS should be selected in Options->BIOS/Plugins menu.
 
 On pandora, analog controllers are supported using nubs, but this is
 disabled by default and needs to be enabled in 'Controls' menu.
@@ -60,7 +81,7 @@ GPU (graphics) and SPU (sound) plugins can be selected in
 [BIOS/Plugins] menu:
 
 builtin_gpu    - this is either Exophase's ARM NEON GPU (accurate and fast,
-                 available if platform supports NEON, like on pandoa),
+                 available if platform supports NEON, like on pandora),
                  gpu_peops or gpu_unai (depends on compile options).
 gpu_peops.so   - P.E.Op.S. soft GPU, reasonably accurate but slow
                  (also found with older emulators on PC)
@@ -88,6 +109,23 @@ the main menu where it is possible to enable/disable individual cheats.
 Changelog
 ---------
 
+r17
++ added overlay support for generic Linux build
+* attempted to fix sound breakage with PulseAudio
+* fixed some regressions caused by hires mode code
+* fixed some sound issues introduced in r9
+* various other tweaks
+
+r16 (2012-11-10)
++ gpu_neon now has new hires rendering mode
+  (sometimes slow and occasionally glitchy)
++ integrated M-HT's scale2x and eagle2x filters
+  (works for 512x256 or lower resolution games)
++ pandora: added gamma/brightness control (requires SZ 1.52)
+* pandora: some improvements for nub support
++ added fast forward support
+* fixed some glitches after loading savestates from r14 or earlier
+
 r15 (2012-08-02)
 * various compatibility fixes
 * attempts to fix various SPU issues