Browse Source

anti-tear modes for Wiz

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@717 be3aeb3a-fb24-0410-a615-afba39da0efa
notaz 15 years ago
parent
commit
cc41eb4fa3

+ 5 - 4
platform/common/arm_utils.h

@@ -1,4 +1,4 @@
-// (c) Copyright 2006 notaz, All rights reserved.
+// (c) Copyright 2006-2009 notaz, All rights reserved.
 // Free for non-commercial use.
 
 // For commercial use, separate licencing terms must be obtained.
@@ -6,8 +6,9 @@
 void vidConvCpyRGB32  (void *to, void *from, int pixels);
 void vidConvCpyRGB32sh(void *to, void *from, int pixels);
 void vidConvCpyRGB32hi(void *to, void *from, int pixels);
-void vidCpyM2_40col(void *dest, void *src);
-void vidCpyM2_32col(void *dest, void *src);
-void vidCpyM2_32col_nobord(void *dest, void *src);
+void vidcpy_m2(void *dest, void *src, int m32col, int with_32c_border);
+void vidcpy_m2_rot(void *dest, void *src, int m32col, int with_32c_border);
 void spend_cycles(int c); // utility
 
+void rotated_blit8 (void *dst, void *linesx4, int y, int is_32col);
+void rotated_blit16(void *dst, void *linesx4, int y, int is_32col);

+ 179 - 48
platform/common/arm_utils.s

@@ -137,69 +137,201 @@ vidConvCpyRGB32hi:
 @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
 
-@ mode2 blitter for 40 cols
-.global vidCpyM2_40col @ void *dest, void *src
-
-vidCpyM2_40col:
+@ mode2 blitter
+.global vidcpy_m2 @ void *dest, void *src, int m32col, int with_32c_border
+vidcpy_m2:
     stmfd   sp!, {r4-r6,lr}
 
     mov     r12, #224       @ lines
+    add     r0, r0, #320*8
     add     r1, r1, #8
+    mov     lr, #0
+
+    tst     r2, r2
+    movne   lr, #64
+    tstne   r3, r3
+    addne   r0, r0, #32
 
-vidCpyM2_40_loop_out:
+vidCpyM2_loop_out:
     mov     r6, #10
-vidCpyM2_40_loop:
+    sub     r6, r6, lr, lsr #5	@ -= 2 in 32col mode
+vidCpyM2_loop:
     subs    r6, r6, #1
-     ldmia    r1!, {r2-r5}
-     stmia    r0!, {r2-r5}
-     ldmia    r1!, {r2-r5}
-     stmia    r0!, {r2-r5}
-    bne     vidCpyM2_40_loop
+    ldmia   r1!, {r2-r5}
+    stmia   r0!, {r2-r5}
+    ldmia   r1!, {r2-r5}
+    stmia   r0!, {r2-r5}
+    bne     vidCpyM2_loop
+
     subs    r12,r12,#1
+    add     r0, r0, lr
     add     r1, r1, #8
-    bne     vidCpyM2_40_loop_out
-
-    ldmfd   sp!, {r4-r6,lr}
-    bx      lr
+    add     r1, r1, lr
+    bne     vidCpyM2_loop_out
 
+    ldmfd   sp!, {r4-r6,pc}
 
-@ mode2 blitter for 32 cols
-.global vidCpyM2_32col @ void *dest, void *src
 
-vidCpyM2_32col:
-    stmfd   sp!, {r4-r6,lr}
-
-    mov     r12, #224       @ lines
+.global vidcpy_m2_rot @ void *dest, void *src, int m32col, int with_32c_border
+vidcpy_m2_rot:
+    stmfd   sp!,{r4-r8,lr}
     add     r1, r1, #8
-    add     r0, r0, #32
-
-vidCpyM2_32_loop_out:
-    mov     r6, #8
-vidCpyM2_32_loop:
-    subs    r6, r6, #1
-     ldmia    r1!, {r2-r5}
-     stmia    r0!, {r2-r5}
-     ldmia    r1!, {r2-r5}
-     stmia    r0!, {r2-r5}
-    bne     vidCpyM2_32_loop
-    subs    r12,r12,#1
-    add     r0, r0, #64
-    add     r1, r1, #8+64
-    bne     vidCpyM2_32_loop_out
-
-    ldmfd   sp!, {r4-r6,lr}
-    bx      lr
-
-
-@ mode2 blitter for 32 cols with no borders
-.global vidCpyM2_32col_nobord @ void *dest, void *src
+    tst     r2, r2
+    subne   r1, r1, #32		@ adjust
+
+    mov     r4, r0
+    mov     r5, r1
+    mov     r6, r2
+    mov     r7, #8+4
+
+vidcpy_m2_rot_loop:
+    @ a bit lame but oh well..
+    mov     r0, r4
+    mov     r1, r5
+    mov     r2, r7
+    mov     r3, r6
+    mov     r8, #328
+    adr     lr, after_rot_blit8
+    stmfd   sp!,{r4-r8,lr}
+    b       rotated_blit8_2
+
+after_rot_blit8:
+    add     r5, r5, #328*4
+    add     r7, r7, #4
+    cmp     r7, #224+8+4
+    ldmgefd sp!,{r4-r8,pc}
+    b       vidcpy_m2_rot_loop
+
+
+.global rotated_blit8 @ void *dst, void *linesx4, u32 y, int is_32col
+rotated_blit8:
+    stmfd   sp!,{r4-r8,lr}
+    mov     r8, #320
+
+rotated_blit8_2:
+    add     r0, r0, #(240*320)
+    sub     r0, r0, #(240+4)	@ y starts from 4
+    add     r0, r0, r2
+
+    tst     r3, r3
+    subne   r0, r0, #(240*32)
+    addne   r1, r1, #32
+    movne   lr, #256/4
+    moveq   lr, #320/4
+
+rotated_blit_loop8:
+    mov     r6, r1
+    ldr     r2, [r6], r8
+    ldr     r3, [r6], r8
+    ldr     r4, [r6], r8
+    ldr     r5, [r6], r8
+
+    mov     r6, r2, lsl #24
+    mov     r6, r6, lsr #8
+    orr     r6, r6, r3, lsl #24
+    mov     r6, r6, lsr #8
+    orr     r6, r6, r4, lsl #24
+    mov     r6, r6, lsr #8
+    orr     r6, r6, r5, lsl #24
+    str     r6, [r0], #-240
+
+    and     r6, r3, #0xff00
+    and     r7, r2, #0xff00
+    orr     r6, r6, r7, lsr #8
+    and     r7, r4, #0xff00
+    orr     r6, r6, r7, lsl #8
+    and     r7, r5, #0xff00
+    orr     r6, r6, r7, lsl #16
+    str     r6, [r0], #-240
+
+    and     r6, r4, #0xff0000
+    and     r7, r2, #0xff0000
+    orr     r6, r6, r7, lsr #16
+    and     r7, r3, #0xff0000
+    orr     r6, r6, r7, lsr #8
+    and     r7, r5, #0xff0000
+    orr     r6, r6, r7, lsl #8
+    str     r6, [r0], #-240
+
+    mov     r6, r5, lsr #24
+    mov     r6, r6, lsl #8
+    orr     r6, r6, r4, lsr #24
+    mov     r6, r6, lsl #8
+    orr     r6, r6, r3, lsr #24
+    mov     r6, r6, lsl #8
+    orr     r6, r6, r2, lsr #24
+    str     r6, [r0], #-240
+
+    subs    lr, lr, #1
+    add     r1, r1, #4
+    bne     rotated_blit_loop8
+
+    ldmfd   sp!,{r4-r8,pc}
+
+
+@ input: r2-r5
+@ output: r7,r8
+@ trash: r6
+.macro rb_line_low
+    mov     r6, r2, lsl #16
+    mov     r7, r3, lsl #16
+    orr     r7, r7, r6, lsr #16
+    mov     r6, r4, lsl #16
+    mov     r8, r5, lsl #16
+    orr     r8, r8, r6, lsr #16
+.endm
 
-vidCpyM2_32col_nobord:
-    stmfd   sp!, {r4-r6,lr}
+.macro rb_line_hi
+    mov     r6, r2, lsr #16
+    mov     r7, r3, lsr #16
+    orr     r7, r6, r7, lsl #16
+    mov     r6, r4, lsr #16
+    mov     r8, r5, lsr #16
+    orr     r8, r6, r8, lsl #16
+.endm
 
-    mov     r12, #224       @ lines
+.global rotated_blit16 @ void *dst, void *linesx4, u32 y, int is_32col
+rotated_blit16:
+    stmfd   sp!,{r4-r8,lr}
+
+    add     r0, r0, #(240*320)*2
+    sub     r0, r0, #(240+4)*2	@ y starts from 4
+    add     r0, r0, r2, lsl #1
+
+    tst     r3, r3
+    subne   r0, r0, #(240*32)*2
+    addne   r1, r1, #32*2
+    movne   lr, #256/4
+    moveq   lr, #320/4
+
+rotated_blit_loop16:
+    ldr     r2, [r1, #320*0*2]
+    ldr     r3, [r1, #320*1*2]
+    ldr     r4, [r1, #320*2*2]
+    ldr     r5, [r1, #320*3*2]
+    rb_line_low
+    stmia   r0, {r7,r8}
+    sub     r0, r0, #240*2
+    rb_line_hi
+    stmia   r0, {r7,r8}
+    sub     r0, r0, #240*2
+
+    ldr     r2, [r1, #320*0*2+4]
+    ldr     r3, [r1, #320*1*2+4]
+    ldr     r4, [r1, #320*2*2+4]
+    ldr     r5, [r1, #320*3*2+4]
+    rb_line_low
+    stmia   r0, {r7,r8}
+    sub     r0, r0, #240*2
+    rb_line_hi
+    stmia   r0, {r7,r8}
+    sub     r0, r0, #240*2
+
+    subs    lr, lr, #1
     add     r1, r1, #8
-    b       vidCpyM2_32_loop_out
+    bne     rotated_blit_loop16
+
+    ldmfd   sp!,{r4-r8,pc}
 
 
 .global spend_cycles @ c
@@ -213,4 +345,3 @@ spend_cycles:
 
     bx      lr
 
-

+ 18 - 14
platform/common/emu.c

@@ -662,32 +662,36 @@ int emu_write_config(int is_game)
 
 /* always using built-in font */
 
-#define mk_text_out(name, type, val) \
+#define mk_text_out(name, type, val, topleft, step_x, step_y) \
 void name(int x, int y, const char *text)				\
 {									\
 	int i, l, len = strlen(text);					\
-	type *screen = (type *)g_screen_ptr + x + y * g_screen_width;	\
+	type *screen = (type *)(topleft) + x * step_x + y * step_y;	\
 									\
-	for (i = 0; i < len; i++, screen += 8)				\
+	for (i = 0; i < len; i++, screen += 8 * step_x)			\
 	{								\
 		for (l = 0; l < 8; l++)					\
 		{							\
 			unsigned char fd = fontdata8x8[text[i] * 8 + l];\
-			type *s = screen + l * g_screen_width;		\
-			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;			\
+			type *s = screen + l * step_y;			\
+			if (fd&0x80) s[step_x * 0] = val;		\
+			if (fd&0x40) s[step_x * 1] = val;		\
+			if (fd&0x20) s[step_x * 2] = val;		\
+			if (fd&0x10) s[step_x * 3] = val;		\
+			if (fd&0x08) s[step_x * 4] = val;		\
+			if (fd&0x04) s[step_x * 5] = val;		\
+			if (fd&0x02) s[step_x * 6] = val;		\
+			if (fd&0x01) s[step_x * 7] = val;		\
 		}							\
 	}								\
 }
 
-mk_text_out(emu_textOut8, unsigned char, 0xf0)
-mk_text_out(emu_textOut16, unsigned short, 0xffff)
+mk_text_out(emu_text_out8,      unsigned char,    0xf0, g_screen_ptr, 1, g_screen_width)
+mk_text_out(emu_text_out16,     unsigned short, 0xffff, g_screen_ptr, 1, g_screen_width)
+mk_text_out(emu_text_out8_rot,  unsigned char,    0xf0,
+	(char *)g_screen_ptr  + (g_screen_width - 1) * g_screen_height, -g_screen_height, 1)
+mk_text_out(emu_text_out16_rot, unsigned short, 0xffff,
+	(short *)g_screen_ptr + (g_screen_width - 1) * g_screen_height, -g_screen_height, 1)
 
 #undef mk_text_out
 

+ 13 - 9
platform/common/emu.h

@@ -33,6 +33,12 @@ extern int g_screen_height;
 #define EOPT_CONFIRM_LOAD (1<<11)
 #define EOPT_A_SN_GAMMA   (1<<12)
 #define EOPT_PSYNC        (1<<13)
+#define EOPT_GIZ_SCANLN   (1<<14)
+#define EOPT_GIZ_DBLBUF   (1<<15)
+#define EOPT_VSYNC_MODE   (1<<16)
+#define EOPT_SHOW_RTC     (1<<17)
+#define EOPT_NO_FRMLIMIT  (1<<18)
+#define EOPT_WIZ_TEAR_FIX (1<<19)
 
 enum {
 	EOPT_SCALE_NONE = 0,
@@ -42,13 +48,8 @@ enum {
 };
 
 typedef struct _currentConfig_t {
-	// char lastRomFile[512];
-	int EmuOpt;		// LSb->MSb: use_sram, show_fps, enable_sound, gzip_saves,
-					// mmuhack, no_save_cfg_on_exit, <unused>, 16_bit_mode
-					// craigix_ram, confirm_save, show_cd_leds, confirm_load
-					// A_SNs_gamma, perfect_vsync, giz_scanlines, giz_dblbuff
-					// vsync_mode, show_clock, no_frame_limitter
-	int s_PicoOpt;		// for old cfg files only
+	int EmuOpt;
+	int s_PicoOpt;
 	int s_PsndRate;
 	int s_PicoRegion;
 	int s_PicoAutoRgnOrder;
@@ -111,10 +112,13 @@ char *emu_get_save_fname(int load, int is_sram, int slot);
 int   emu_check_save_file(int slot);
 void  emu_setSaveStateCbs(int gz);
 
+void  emu_text_out8 (int x, int y, const char *text);
+void  emu_text_out16(int x, int y, const char *text);
+void  emu_text_out8_rot (int x, int y, const char *text);
+void  emu_text_out16_rot(int x, int y, const char *text);
+
 void  emu_make_path(char *buff, const char *end, int size);
 void  emu_update_input(void);
-void  emu_textOut8 (int x, int y, const char *text);
-void  emu_textOut16(int x, int y, const char *text);
 void  emu_get_game_name(char *str150);
 void  emu_set_fastforward(int set_on);
 int   emu_cd_check(int *pregion, char *fname_in);

+ 1 - 0
platform/common/menu.c

@@ -1495,6 +1495,7 @@ static menu_entry e_menu_gfx_options[] =
 {
 	mee_cust      ("Renderer",                 MA_OPT_RENDERER,       mh_opt_render, mgn_opt_renderer),
 	mee_range_cust("Scaling",                  MA_OPT_SCALING,        currentConfig.scaling, 0, 3, mgn_opt_scaling),
+	mee_onoff     ("Tearing Fix",              MA_OPT_TEARING_FIX,    currentConfig.EmuOpt, EOPT_WIZ_TEAR_FIX),
 	mee_range_cust("Gamma correction",         MA_OPT2_GAMMA,         currentConfig.gamma, 1, 300, mgn_aopt_gamma),
 	mee_onoff     ("A_SN's gamma curve",       MA_OPT2_A_SN_GAMMA,    currentConfig.EmuOpt, EOPT_A_SN_GAMMA),
 	mee_onoff     ("Perfect vsync",            MA_OPT2_VSYNC,         currentConfig.EmuOpt, EOPT_PSYNC),

+ 1 - 0
platform/common/menu.h

@@ -46,6 +46,7 @@ typedef enum
 	MA_OPT_LOADCFG,
 	MA_OPT_INTERLACED,	/* giz */
 	MA_OPT_ROTATION,	/* uiq */
+	MA_OPT_TEARING_FIX,	/* wiz */
 	MA_OPT2_GAMMA,
 	MA_OPT2_A_SN_GAMMA,
 	MA_OPT2_DBLBUFF,	/* giz */

+ 2 - 2
platform/gizmondo/emu.c

@@ -55,7 +55,7 @@ static void emu_msg_cb(const char *msg)
 	giz_screen = fb_lock(1);
 
 	memset32((int *)((char *)giz_screen + 321*232*2), 0, 321*8*2/4);
-	emu_textOut16(4, 232, msg);
+	emu_text_out16(4, 232, msg);
 	noticeMsgTime = GetTickCount() - 2000;
 
 	/* assumption: emu_msg_cb gets called only when something slow is about to happen */
@@ -137,7 +137,7 @@ static void osd_text(int x, int y, const char *text)
 		p = (int *) ((int)p & ~3); // align
 		memset32(p, 0, len);
 	}
-	emu_textOut16(x, y, text);
+	emu_text_out16(x, y, text);
 }
 
 /*

+ 3 - 1
platform/gp2x/940ctl.c

@@ -17,6 +17,7 @@
 #include "../common/arm_utils.h"
 #include "../common/menu.h"
 #include "../common/emu.h"
+#include "../common/input.h"
 #include "../../pico/pico_int.h"
 #include "../../pico/sound/ym2612.h"
 #include "../../pico/sound/mix.h"
@@ -294,7 +295,7 @@ void YM2612Init_940(int baseclock, int rate)
 	if (crashed_940)
 	{
 		unsigned char ucData[1024];
-		int nRead, i, nLen = 0;
+		int nRead, nLen = 0;
 		char binpath[512];
 		FILE *fp;
 
@@ -306,6 +307,7 @@ void YM2612Init_940(int baseclock, int rate)
 			text_out16(10, 100, "failed to open required file:");
 			text_out16(10, 110, CODE940_FILE);
 			gp2x_video_flip2();
+			in_menu_wait(PBTN_MOK|PBTN_MBACK, 100);
 			printf("failed to open %s\n", binpath);
 			exit(1);
 		}

+ 209 - 95
platform/gp2x/emu.c

@@ -37,12 +37,12 @@ extern int crashed_940;
 
 static short __attribute__((aligned(4))) sndBuffer[2*44100/50];
 static struct timeval noticeMsgTime = { 0, 0 };	// when started showing
-static int osd_fps_x;
-static int gp2x_old_gamma = 100;
 static char noticeMsg[40];
 static unsigned char PicoDraw2FB_[(8+320) * (8+240+8)];
 unsigned char *PicoDraw2FB = PicoDraw2FB_;
+static int osd_fps_x;
 
+extern void *gp2x_screens[4];
 
 void plat_status_msg(const char *format, ...)
 {
@@ -92,7 +92,7 @@ void pemu_prep_defconfig(void)
 	gp2x_soc_t soc;
 
 	memset(&defaultConfig, 0, sizeof(defaultConfig));
-	defaultConfig.EmuOpt    = 0x9d | EOPT_RAM_TIMINGS | 0x600; // | <- confirm_save, cd_leds
+	defaultConfig.EmuOpt    = 0x9d | EOPT_RAM_TIMINGS|EOPT_CONFIRM_SAVE|EOPT_EN_CD_LEDS;
 	defaultConfig.s_PicoOpt = 0x0f | POPT_EN_MCD_PCM|POPT_EN_MCD_CDDA|POPT_EN_SVP_DRC|POPT_ACC_SPRITES;
 	defaultConfig.s_PsndRate = 44100;
 	defaultConfig.s_PicoRegion = 0; // auto
@@ -108,77 +108,129 @@ void pemu_prep_defconfig(void)
 	soc = soc_detect();
 	if (soc == SOCID_MMSP2)
 		defaultConfig.s_PicoOpt |= POPT_EXT_FM;
+	else if (soc == SOCID_POLLUX)
+		defaultConfig.EmuOpt |= EOPT_WIZ_TEAR_FIX;
 }
 
-static void osd_text(int x, int y, const char *text)
+static void (*osd_text)(int x, int y, const char *text);
+
+static void osd_text8(int x, int y, const char *text)
 {
 	int len = strlen(text)*8;
 	int *p, i, h, offs;
 
-	if ((PicoOpt&0x10)||!(currentConfig.EmuOpt&0x80)) {
-		len = (len+3) >> 2;
-		for (h = 0; h < 8; h++) {
-			offs = (x + g_screen_width * (y+h)) & ~3;
-			p = (int *) ((char *)g_screen_ptr + offs);
-			for (i = len; i; i--, p++)
-				*p = 0xe0e0e0e0;
-		}
-		emu_textOut8(x, y, text);
-	} else {
-		len = (len+1) >> 1;
-		for (h = 0; h < 8; h++) {
-			offs = (x + g_screen_width * (y+h)) & ~1;
-			p = (int *) ((short *)g_screen_ptr + offs);
-			for (i = len; i; i--, p++)
-				*p = (*p >> 2) & 0x39e7;
-		}
-		emu_textOut16(x, y, text);
+	len = (len+3) >> 2;
+	for (h = 0; h < 8; h++) {
+		offs = (x + g_screen_width * (y+h)) & ~3;
+		p = (int *) ((char *)g_screen_ptr + offs);
+		for (i = len; i; i--, p++)
+			*p = 0xe0e0e0e0;
+	}
+	emu_text_out8(x, y, text);
+}
+
+static void osd_text16(int x, int y, const char *text)
+{
+	int len = strlen(text)*8;
+	int *p, i, h, offs;
+
+	len = (len+1) >> 1;
+	for (h = 0; h < 8; h++) {
+		offs = (x + g_screen_width * (y+h)) & ~1;
+		p = (int *) ((short *)g_screen_ptr + offs);
+		for (i = len; i; i--, p++)
+			*p = (*p >> 2) & 0x39e7;
+	}
+	emu_text_out16(x, y, text);
+}
+
+static void osd_text8_rot(int x, int y, const char *text)
+{
+	int len = strlen(text) * 8;
+	char *p = (char *)g_screen_ptr + 240*(320-x) + y;
+
+	while (len--) {
+		memset(p, 0xe0, 8);
+		p -= 240;
 	}
+
+	emu_text_out8_rot(x, y, text);
+}
+
+static void osd_text16_rot(int x, int y, const char *text)
+{
+	int len = strlen(text) * 8;
+	short *p = (short *)g_screen_ptr + 240*(320-x) + y;
+
+	while (len--) {
+		memset(p, 0, 8*2);
+		p -= 240;
+	}
+
+	emu_text_out16_rot(x, y, text);
 }
 
 static void draw_cd_leds(void)
 {
-	int old_reg;
-	old_reg = Pico_mcd->s68k_regs[0];
+	int led_reg, pitch, scr_offs, led_offs;
+	led_reg = Pico_mcd->s68k_regs[0];
+
+	if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) {
+		pitch = 240;
+		led_offs = -pitch * 6;
+		scr_offs = pitch * (320 - 4);
+	} else {
+		pitch = 320;
+		led_offs = 4;
+		scr_offs = pitch * 2 + 4;
+	}
 
 	if ((PicoOpt & POPT_ALT_RENDERER) || !(currentConfig.EmuOpt & EOPT_16BPP)) {
+	#define p(x) px[(x) >> 2]
 		// 8-bit modes
-		unsigned int col_g = (old_reg & 2) ? 0xc0c0c0c0 : 0xe0e0e0e0;
-		unsigned int col_r = (old_reg & 1) ? 0xd0d0d0d0 : 0xe0e0e0e0;
-		*(unsigned int *)((char *)g_screen_ptr + 320*2+ 4) =
-		*(unsigned int *)((char *)g_screen_ptr + 320*3+ 4) =
-		*(unsigned int *)((char *)g_screen_ptr + 320*4+ 4) = col_g;
-		*(unsigned int *)((char *)g_screen_ptr + 320*2+12) =
-		*(unsigned int *)((char *)g_screen_ptr + 320*3+12) =
-		*(unsigned int *)((char *)g_screen_ptr + 320*4+12) = col_r;
+		unsigned int *px = (unsigned int *)((char *)g_screen_ptr + scr_offs);
+		unsigned int col_g = (led_reg & 2) ? 0xc0c0c0c0 : 0xe0e0e0e0;
+		unsigned int col_r = (led_reg & 1) ? 0xd0d0d0d0 : 0xe0e0e0e0;
+		p(pitch*0) = p(pitch*1) = p(pitch*2) = col_g;
+		p(pitch*0 + led_offs) = p(pitch*1 + led_offs) = p(pitch*2 + led_offs) = col_r;
+	#undef p
 	} else {
+	#define p(x) px[(x)*2 >> 2] = px[((x)*2 >> 2) + 1]
 		// 16-bit modes
-		unsigned int *p = (unsigned int *)((short *)g_screen_ptr + 320*2+4);
-		unsigned int col_g = (old_reg & 2) ? 0x06000600 : 0;
-		unsigned int col_r = (old_reg & 1) ? 0xc000c000 : 0;
-		*p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += 320/2 - 12/2;
-		*p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += 320/2 - 12/2;
-		*p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r;
+		unsigned int *px = (unsigned int *)((short *)g_screen_ptr + scr_offs);
+		unsigned int col_g = (led_reg & 2) ? 0x06000600 : 0;
+		unsigned int col_r = (led_reg & 1) ? 0xc000c000 : 0;
+		p(pitch*0) = p(pitch*1) = p(pitch*2) = col_g;
+		p(pitch*0 + led_offs) = p(pitch*1 + led_offs) = p(pitch*2 + led_offs) = col_r;
+	#undef p
 	}
 }
 
 static void draw_pico_ptr(void)
 {
 	unsigned short *p = (unsigned short *)g_screen_ptr;
+	int x, y, pitch = 320;
 
 	// only if pen enabled and for 16bit modes
-	if (pico_inp_mode == 0 || (PicoOpt&0x10) || !(currentConfig.EmuOpt&0x80)) return;
+	if (pico_inp_mode == 0 || (PicoOpt & POPT_ALT_RENDERER) || !(currentConfig.EmuOpt & EOPT_16BPP))
+		return;
 
-	if (!(Pico.video.reg[12]&1) && !(PicoOpt&POPT_DIS_32C_BORDER))
-		p += 32;
+	x = pico_pen_x + PICO_PEN_ADJUST_X;
+	y = pico_pen_y + PICO_PEN_ADJUST_Y;
+	if (!(Pico.video.reg[12]&1) && !(PicoOpt & POPT_DIS_32C_BORDER))
+		x += 32;
 
-	p += 320 * (pico_pen_y + PICO_PEN_ADJUST_Y);
-	p += pico_pen_x + PICO_PEN_ADJUST_X;
-	p[0]   ^= 0xffff;
-	p[319] ^= 0xffff;
-	p[320] ^= 0xffff;
-	p[321] ^= 0xffff;
-	p[640] ^= 0xffff;
+	if (EOPT_WIZ_TEAR_FIX) {
+		pitch = 240;
+		p += (319 - x) * pitch + y;
+	} else
+		p += x + y * pitch;
+
+	p[0]       ^= 0xffff;
+	p[pitch-1] ^= 0xffff;
+	p[pitch]   ^= 0xffff;
+	p[pitch+1] ^= 0xffff;
+	p[pitch*2] ^= 0xffff;
 }
 
 static int EmuScanBegin16(unsigned int num)
@@ -197,8 +249,45 @@ static int EmuScanBegin8(unsigned int num)
 	return 0;
 }
 
+/* rot thing for Wiz */
+static unsigned char __attribute__((aligned(4))) rot_buff[320*4*2];
+
+static int EmuScanBegin16_rot(unsigned int num)
+{
+	DrawLineDest = rot_buff + (num & 3) * 320 * 2;
+	return 0;
+}
+
+static int EmuScanEnd16_rot(unsigned int num)
+{
+	if ((num & 3) != 3)
+		return 0;
+	if (!(Pico.video.reg[1] & 8))
+		num += 8;
+	rotated_blit16(g_screen_ptr, rot_buff, num + 1,
+		!(Pico.video.reg[12] & 1) && !(PicoOpt & POPT_EN_SOFTSCALE));
+	return 0;
+}
+
+static int EmuScanBegin8_rot(unsigned int num)
+{
+	DrawLineDest = rot_buff + (num & 3) * 320;
+	return 0;
+}
+
+static int EmuScanEnd8_rot(unsigned int num)
+{
+	if ((num & 3) != 3)
+		return 0;
+	if (!(Pico.video.reg[1] & 8))
+		num += 8;
+	rotated_blit8(g_screen_ptr, rot_buff, num + 1,
+		!(Pico.video.reg[12] & 1));
+	return 0;
+}
+
 int localPal[0x100];
-static void (*vidCpyM2)(void *dest, void *src) = NULL;
+static void (*vidcpyM2)(void *dest, void *src, int m32col, int with_32c_border) = NULL;
 
 static void blit(const char *fps, const char *notice)
 {
@@ -217,7 +306,8 @@ static void blit(const char *fps, const char *notice)
 		if (PicoRead16Hook == PicoSVPRead16)
 			memset32((int *)(PicoDraw2FB+328*8+328*223), 0xe0e0e0e0, 328);
 		// do actual copy
-		vidCpyM2((unsigned char *)g_screen_ptr+320*8, PicoDraw2FB+328*8);
+		vidcpyM2(g_screen_ptr, PicoDraw2FB+328*8,
+			!(Pico.video.reg[12] & 1), !(PicoOpt & POPT_DIS_32C_BORDER));
 	}
 	else if (!(emu_opt & EOPT_16BPP))
 	{
@@ -268,23 +358,32 @@ static void blit(const char *fps, const char *notice)
 		draw_pico_ptr();
 
 	gp2x_video_flip();
-
-	if (!(PicoOpt & POPT_ALT_RENDERER)) {
-		if (!(Pico.video.reg[1]&8)) {
-			if (currentConfig.EmuOpt & EOPT_16BPP)
-				DrawLineDest = (unsigned short *) g_screen_ptr + 320*8;
-			else
-				DrawLineDest = (unsigned char  *) g_screen_ptr + 320*8;
-		} else {
-			DrawLineDest = g_screen_ptr;
-		}
-	}
 }
 
 // clears whole screen or just the notice area (in all buffers)
 static void clearArea(int full)
 {
-	if ((PicoOpt&0x10)||!(currentConfig.EmuOpt&0x80)) {
+	int is_8bit = (PicoOpt & POPT_ALT_RENDERER) || !(currentConfig.EmuOpt & EOPT_16BPP);
+	if (!full && (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX)) {
+		/* ugh.. */
+		int i, u, *p;
+		if (is_8bit) {
+			for (i = 0; i < 4; i++) {
+				p = (int *)gp2x_screens[i] + (240-8) / 4;
+				for (u = 320; u > 0; u--, p += 240/4)
+					p[0] = p[1] = 0xe0e0e0e0;
+			}
+		} else {
+			for (i = 0; i < 4; i++) {
+				p = (int *)gp2x_screens[i] + (240-8)*2 / 4;
+				for (u = 320; u > 0; u--, p += 240*2/4)
+					p[0] = p[1] = p[2] = p[3] = 0;
+			}
+		}
+		return;
+	}
+
+	if (is_8bit) {
 		// 8-bit renderers
 		if (full) gp2x_memset_all_buffers(0, 0xe0, 320*240);
 		else      gp2x_memset_all_buffers(320*232, 0xe0, 320*8);
@@ -313,17 +412,46 @@ void plat_status_msg_busy_first(const char *msg)
 
 static void vidResetMode(void)
 {
+	PicoScanEnd = NULL;
+
 	if (PicoOpt & POPT_ALT_RENDERER) {
-		gp2x_video_changemode(8);
-	} else if (currentConfig.EmuOpt & EOPT_16BPP) {
-		gp2x_video_changemode(16);
+		if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) {
+			gp2x_video_changemode(-8);
+			vidcpyM2 = vidcpy_m2_rot;
+			osd_text = osd_text8_rot;
+		} else {
+			gp2x_video_changemode(8);
+			vidcpyM2 = vidcpy_m2;
+			osd_text = osd_text8;
+		}
+	}
+	else if (currentConfig.EmuOpt & EOPT_16BPP) {
 		PicoDrawSetColorFormat(1);
-		PicoScanBegin = EmuScanBegin16;
-	} else {
-		gp2x_video_changemode(8);
+		if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) {
+			gp2x_video_changemode(-16);
+			PicoScanBegin = EmuScanBegin16_rot;
+			PicoScanEnd = EmuScanEnd16_rot;
+			osd_text = osd_text16_rot;
+		} else {
+			gp2x_video_changemode(16);
+			PicoScanBegin = EmuScanBegin16;
+			osd_text = osd_text16;
+		}
+	}
+	else {
 		PicoDrawSetColorFormat(2);
-		PicoScanBegin = EmuScanBegin8;
+		if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) {
+			gp2x_video_changemode(-8);
+			PicoScanBegin = EmuScanBegin8_rot;
+			PicoScanEnd = EmuScanEnd8_rot;
+			osd_text = osd_text8_rot;
+		} else {
+			gp2x_video_changemode(8);
+			PicoScanBegin = EmuScanBegin8;
+			osd_text = osd_text8;
+		}
 	}
+
 	if ((PicoOpt & POPT_ALT_RENDERER) || !(currentConfig.EmuOpt & EOPT_16BPP)) {
 		// setup pal for 8-bit modes
 		localPal[0xc0] = 0x0000c000; // MCD LEDs
@@ -335,6 +463,7 @@ static void vidResetMode(void)
 		gp2x_video_flip();
 	}
 	Pico.m.dirtyPal = 1;
+
 	// reset scaling
 	if (currentConfig.scaling == EOPT_SCALE_HW_HV && !(Pico.video.reg[1]&8))
 	     gp2x_video_RGB_setscaling(8, (PicoOpt&0x100)&&!(Pico.video.reg[12]&1) ? 256 : 320, 224);
@@ -516,19 +645,10 @@ void pemu_forced_frame(int opts)
 
 	PicoDrawSetColorFormat(1);
 	PicoScanBegin = EmuScanBegin16;
+	PicoScanEnd = NULL;
 	Pico.m.dirtyPal = 1;
 	PicoFrameDrawOnly();
 
-/*
-	if (!(Pico.video.reg[12]&1)) {
-		vidCpyM2 = vidCpyM2_32col;
-		clearArea(1);
-	} else	vidCpyM2 = vidCpyM2_40col;
-
-	vidCpyM2((unsigned char *)g_screen_ptr+320*8, PicoDraw2FB+328*8);
-	vidConvCpyRGB32(localPal, Pico.cram, 0x40);
-	gp2x_video_setpalette(localPal, 0x40);
-*/
 	PicoOpt = po_old;
 	currentConfig.EmuOpt = eo_old;
 }
@@ -605,7 +725,8 @@ static void tga_dump(void)
 
 void pemu_loop(void)
 {
-	static int gp2x_old_clock = -1, EmuOpt_old = 0;
+	static int gp2x_old_clock = -1, EmuOpt_old = 0, pal_old = 0;
+	static int gp2x_old_gamma = 100;
 	char fpsbuff[24]; // fps count c string
 	struct timeval tval; // timing
 	int pframes_done, pframes_shown, pthissec; // "period" frames, used for sync
@@ -637,7 +758,7 @@ void pemu_loop(void)
 		printf("updated gamma to %i, A_SN's curve: %i\n", currentConfig.gamma, !!(currentConfig.EmuOpt&0x1000));
 	}
 
-	if ((EmuOpt_old ^ currentConfig.EmuOpt) & EOPT_PSYNC) {
+	if (((EmuOpt_old ^ currentConfig.EmuOpt) & EOPT_PSYNC) || Pico.m.pal != pal_old) {
 		if (currentConfig.EmuOpt & EOPT_PSYNC)
 			set_lcd_custom_rate(Pico.m.pal);
 		else
@@ -648,6 +769,7 @@ void pemu_loop(void)
 		gp2x_make_fb_bufferable(currentConfig.EmuOpt & EOPT_MMUHACK);
 
 	EmuOpt_old = currentConfig.EmuOpt;
+	pal_old = Pico.m.pal;
 	fpsbuff[0] = 0;
 
 	// make sure we are in correct mode
@@ -667,7 +789,7 @@ void pemu_loop(void)
 	if (PicoAHW & PAHW_MCD) PicoCDBufferInit();
 
 	// calc vsync offset to sync timing code with vsync
-	if (currentConfig.EmuOpt&0x2000) {
+	if (currentConfig.EmuOpt & EOPT_PSYNC) {
 		gettimeofday(&tval, 0);
 		gp2x_video_wait_vsync();
 		gettimeofday(&tval, 0);
@@ -715,16 +837,9 @@ void pemu_loop(void)
 		{
 			int scalex = 320;
 			osd_fps_x = OSD_FPS_X;
-			if (modes & 4) {
-				vidCpyM2 = vidCpyM2_40col;
-			} else {
-				if (PicoOpt & 0x100) {
-					vidCpyM2 = vidCpyM2_32col_nobord;
-					scalex = 256;
-					osd_fps_x = OSD_FPS_X - 64;
-				} else {
-					vidCpyM2 = vidCpyM2_32col;
-				}
+			if (!(modes & 4) && (PicoOpt & POPT_DIS_32C_BORDER)) {
+				scalex = 256;
+				osd_fps_x = OSD_FPS_X - 64;
 			}
 			/* want vertical scaling and game is not in 240 line mode */
 			if (currentConfig.scaling == EOPT_SCALE_HW_HV && !(modes&8))
@@ -853,9 +968,8 @@ void pemu_loop(void)
 		SRam.changed = 0;
 	}
 
-	// if in 8bit mode, generate 16bit image for menu background
-	if ((PicoOpt & POPT_ALT_RENDERER) || !(currentConfig.EmuOpt & EOPT_16BPP))
-		pemu_forced_frame(POPT_EN_SOFTSCALE);
+	// do menu background to be sure it's right
+	pemu_forced_frame(POPT_EN_SOFTSCALE);
 }
 
 const char *plat_get_credits(void)

+ 1 - 1
platform/gp2x/in_gp2x.c

@@ -258,7 +258,7 @@ static const struct {
 	{ 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_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 },

+ 11 - 2
platform/gp2x/plat.c

@@ -86,13 +86,20 @@ void plat_video_menu_enter(int is_rom_loaded)
 			memset(g_screen_ptr, 0, 320*240*2);
 	}
 
-	// copy to buffer2
+	// copy to buffer2, switch to black
 	gp2x_memcpy_buffers((1<<2), g_screen_ptr, 0, 320*240*2);
 
+	/* try to switch nicely avoiding tearing on Wiz */
+	gp2x_video_wait_vsync();
+	memset(gp2x_screens[0], 0, 320*240*2);
+	memset(gp2x_screens[1], 0, 320*240*2);
+	gp2x_video_flip2();
+	gp2x_video_wait_vsync();
+	gp2x_video_wait_vsync();
+
 	// switch to 16bpp
 	gp2x_video_changemode_ll(16);
 	gp2x_video_RGB_setscaling(0, 320, 240);
-	gp2x_video_flip2();
 }
 
 void plat_video_menu_begin(void)
@@ -114,6 +121,8 @@ void plat_validate_config(void)
 	soc = soc_detect();
 	if (soc != SOCID_MMSP2)
 		PicoOpt &= ~POPT_EXT_FM;
+	if (soc != SOCID_POLLUX)
+		currentConfig.EmuOpt &= ~EOPT_WIZ_TEAR_FIX;
 
 	if (currentConfig.gamma < 10 || currentConfig.gamma > 300)
 		currentConfig.gamma = 100;

+ 1 - 0
platform/gp2x/soc.h

@@ -14,6 +14,7 @@ void pollux_finish(void);
 /* SoC specific functions */
 extern void (*gp2x_video_flip)(void);
 extern void (*gp2x_video_flip2)(void);
+/* negative bpp means rotated mode (for Wiz) */
 extern void (*gp2x_video_changemode_ll)(int bpp);
 extern void (*gp2x_video_setpalette)(int *pal, int len);
 extern void (*gp2x_video_RGB_setscaling)(int ln_offs, int W, int H);

+ 26 - 4
platform/gp2x/soc_pollux.c

@@ -30,6 +30,7 @@ static int fbdev = -1;
 static char cpuclk_was_changed = 0;
 static unsigned short memtimex_old[2];
 static unsigned int pllsetreg0;
+static int last_pal_setting = 0;
 
 
 /* video stuff */
@@ -56,9 +57,30 @@ static void gp2x_video_flip2_(void)
 
 static void gp2x_video_changemode_ll_(int bpp)
 {
+	static int prev_bpp = 0;
 	int code = 0, bytes = 2;
+	int rot_cmd[2] = { 0, 0 };
 	unsigned int r;
-	switch (bpp)
+	int ret;
+
+	if (bpp == prev_bpp)
+		return;
+	prev_bpp = bpp;
+
+	printf("changemode: %dbpp rot=%d\n", abs(bpp), bpp < 0);
+
+	/* negative bpp means rotated mode */
+	rot_cmd[0] = (bpp < 0) ? 6 : 5;
+	ret = ioctl(fbdev, _IOW('D', 90, int[2]), rot_cmd);
+	if (ret < 0)
+		perror("rot ioctl failed");
+	memregl[0x4004>>2] = (bpp < 0) ? 0x013f00ef : 0x00ef013f;
+	memregl[0x4000>>2] |= 1 << 3;
+
+	/* the above ioctl resets LCD timings, so set them here */
+	set_lcd_custom_rate(last_pal_setting);
+
+	switch (abs(bpp))
 	{
 		case 8:
 			code = 0x443a;
@@ -72,12 +94,12 @@ static void gp2x_video_changemode_ll_(int bpp)
 			break;
 
 		default:
-			printf("unhandled bpp request: %d\n", bpp);
+			printf("unhandled bpp request: %d\n", abs(bpp));
 			return;
 	}
 
 	memregl[0x405c>>2] = bytes;
-	memregl[0x4060>>2] = bytes * 320;
+	memregl[0x4060>>2] = bytes * (bpp < 0 ? 240 : 320);
 
 	r = memregl[0x4058>>2];
 	r = (r & 0xffff) | (code << 16) | 0x10;
@@ -156,6 +178,7 @@ static void set_lcd_custom_rate_(int is_pal)
 
 	snprintf(buff, sizeof(buff), "POLLUX_LCD_TIMINGS_%s", is_pal ? "PAL" : "NTSC");
 	pollux_set_fromenv(buff);
+	last_pal_setting = is_pal;
 }
 
 static void unset_lcd_custom_rate_(void)
@@ -245,7 +268,6 @@ void pollux_finish(void)
 	/* switch to default fb mem, turn portrait off */
 	memregl[0x406C>>2] = fb_paddr[0];
 	memregl[0x4058>>2] |= 0x10;
-//	wiz_lcd_set_portrait(0);
 	close(fbdev);
 
 	gp2x_video_changemode_ll_(16);

+ 1 - 1
platform/gp2x/version.h

@@ -1,2 +1,2 @@
-#define VERSION "1.52"
+#define VERSION "1.55"
 

+ 2 - 2
platform/pandora/emu.c

@@ -134,7 +134,7 @@ static void osd_text(int x, int y, const char *text)
 			p = (int *) ((unsigned char *) g_screen_ptr+x+g_screen_width*(y+h));
 			for (i = len; i; i--, p++) *p = 0xe0e0e0e0;
 		}
-		emu_textOut8(x, y, text);
+		emu_text_out8(x, y, text);
 	} else {
 		int *p, i, h;
 		x &= ~1; // align x
@@ -143,7 +143,7 @@ static void osd_text(int x, int y, const char *text)
 			p = (int *) ((unsigned short *) g_screen_ptr+x+g_screen_width*(y+h));
 			for (i = len; i; i--, p++) *p = 0;//(*p>>2)&0x39e7;
 		}
-		textOut16(x, y, text);
+		text_out16(x, y, text);
 	}
 }
 

+ 2 - 2
platform/psp/emu.c

@@ -76,7 +76,7 @@ static void osd_text(int x, const char *text, int is_active, int clear_all)
 		memset32_uncached(p, 0, len);
 	}
 	if (is_active) { tmp = psp_screen; psp_screen = screen; } // nasty pointer tricks
-	emu_textOut16(x, 264, text);
+	emu_text_out16(x, 264, text);
 	if (is_active) psp_screen = tmp;
 }
 
@@ -409,7 +409,7 @@ static void dbg_text(void)
 		p = (int *) ((int)p & ~3); // align
 		memset32_uncached(p, 0, len);
 	}
-	emu_textOut16(2, 256, text);
+	emu_text_out16(2, 256, text);
 }
 #endif