From: kub Date: Wed, 13 Oct 2021 19:30:54 +0000 (+0200) Subject: sms, basic gamegear support X-Git-Tag: v2.00~472 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=466fa079531d0605c73a65c4f499ef01aa9fdc7a;p=picodrive.git sms, basic gamegear support --- diff --git a/pico/draw.c b/pico/draw.c index 3ae05c54..2b349228 100644 --- a/pico/draw.c +++ b/pico/draw.c @@ -135,7 +135,7 @@ void blockcpy_or(void *dst, void *src, size_t n, int pat) for (; n; n--) *pd++ = (unsigned char) (*ps++ | pat); } -#define blockcpy memcpy +#define blockcpy memmove #endif #define TileNormMaker_(pix_func,ret) \ @@ -1642,21 +1642,28 @@ void FinalizeLine555(int sh, int line, struct PicoEState *est) PicoDrawUpdateHighPal(); - if (Pico.video.reg[12]&1) { - len = 320; - } else { - len = 256; - } - - if ((*est->PicoOpt & POPT_EN_SOFTSCALE) && len == 256) { - switch (PicoIn.filter) { - case 3: h_upscale_bl4_4_5(pd, 320, ps, 256, 256, f_pal); break; - case 2: h_upscale_bl2_4_5(pd, 320, ps, 256, 256, f_pal); break; - case 1: h_upscale_snn_4_5(pd, 320, ps, 256, 256, f_pal); break; - default: h_upscale_nn_4_5(pd, 320, ps, 256, 256, f_pal); break; - } + if ((PicoIn.AHW & PAHW_SMS) && (Pico.m.hardware & 0x3) == 0x3) + len = 160; + else if (Pico.video.reg[12]&1) len = 320; + else len = 256; + + if ((*est->PicoOpt & POPT_EN_SOFTSCALE) && len < 320) { + if (len == 256) + switch (PicoIn.filter) { + case 3: h_upscale_bl4_4_5(pd, 320, ps, 256, len, f_pal); break; + case 2: h_upscale_bl2_4_5(pd, 320, ps, 256, len, f_pal); break; + case 1: h_upscale_snn_4_5(pd, 320, ps, 256, len, f_pal); break; + default: h_upscale_nn_4_5(pd, 320, ps, 256, len, f_pal); break; + } + else if (len == 160) + switch (PicoIn.filter) { + case 3: + case 2: h_upscale_bl2_1_2(pd, 320, ps, 160, len, f_pal); break; + default: h_upscale_nn_1_2(pd, 320, ps, 160, len, f_pal); break; + } } else { - if (!(*est->PicoOpt & POPT_DIS_32C_BORDER) && len == 256) pd += 32; + if (!(*est->PicoOpt & POPT_DIS_32C_BORDER) && len < 320) + pd += (320-len) / 2; #if 1 h_copy(pd, 320, ps, 320, len, f_pal); #else @@ -1670,9 +1677,10 @@ void FinalizeLine555(int sh, int line, struct PicoEState *est) } #endif -static void FinalizeLine8bit(int sh, int line, struct PicoEState *est) +void FinalizeLine8bit(int sh, int line, struct PicoEState *est) { unsigned char *pd = est->DrawLineDest; + unsigned char *ps = est->HighCol+8; int len; static int dirty_line; @@ -1680,8 +1688,8 @@ static void FinalizeLine8bit(int sh, int line, struct PicoEState *est) { // a hack for mid-frame palette changes if (!(est->rendstatus & PDRAW_SONIC_MODE) | (line - dirty_line > 4)) { - // store a maximum of 2 additional palettes in SonicPal - if (est->SonicPalCount < 2) + // store a maximum of 3 additional palettes in SonicPal + if (est->SonicPalCount < 3) est->SonicPalCount ++; dirty_line = line; est->rendstatus |= PDRAW_SONIC_MODE; @@ -1690,35 +1698,33 @@ static void FinalizeLine8bit(int sh, int line, struct PicoEState *est) Pico.m.dirtyPal = 2; } - if (Pico.video.reg[12]&1) { - len = 320; - } else { - len = 256; - } + if ((PicoIn.AHW & PAHW_SMS) && (Pico.m.hardware & 0x3) == 0x3) + len = 160; + else if (Pico.video.reg[12]&1) len = 320; + else len = 256; + + if (DrawLineDestIncrement == 0) + pd = est->HighCol+8; - if ((PicoIn.opt & POPT_EN_SOFTSCALE) && len == 256) { - unsigned char *ps = est->HighCol+8; + if ((PicoIn.opt & POPT_EN_SOFTSCALE) && len < 320) { unsigned char pal = 0; if (!sh && (est->rendstatus & PDRAW_SONIC_MODE)) pal = est->SonicPalCount*0x40; - if (DrawLineDestIncrement == 0) - pd = est->HighCol+8; // Smoothing can't be used with CLUT, hence it's always Nearest Neighbour. - // use reverse version since src and dest ptr may be the same. - rh_upscale_nn_4_5(pd, 320, ps, 256, len, f_or); - } else if (DrawLineDestIncrement == 0) { - if (!sh && (est->rendstatus & PDRAW_SONIC_MODE)) - blockcpy_or(est->HighCol+8, est->HighCol+8, len, est->SonicPalCount*0x40); + if (len == 256) + // use reverse version since src and dest ptr may be the same. + rh_upscale_nn_4_5(pd, 320, ps, 256, len, f_or); + else + rh_upscale_nn_1_2(pd, 320, ps, 256, len, f_or); } else { - if (!(PicoIn.opt & POPT_DIS_32C_BORDER)) - pd += 32; - if (!sh && (est->rendstatus & PDRAW_SONIC_MODE)) { + if (!(*est->PicoOpt & POPT_DIS_32C_BORDER) && len < 320) + pd += (320-len) / 2; + if (!sh && (est->rendstatus & PDRAW_SONIC_MODE)) // select active backup palette - blockcpy_or(pd, est->HighCol+8, len, est->SonicPalCount*0x40); - } else { - blockcpy(pd, est->HighCol+8, len); - } + blockcpy_or(pd, ps, len, est->SonicPalCount*0x40); + else if (pd != ps) + blockcpy(pd, ps, len); } } @@ -1893,8 +1899,15 @@ PICO_INTERNAL void PicoFrameStart(void) static void DrawBlankedLine(int line, int offs, int sh, int bgc) { - if (PicoScanBegin != NULL) - PicoScanBegin(line + offs); + int skip = skip_next_line; + + if (PicoScanBegin != NULL && skip == 0) + skip = PicoScanBegin(line + offs); + + if (skip) { + skip_next_line = skip - 1; + return; + } BackFill(bgc, sh, &Pico.est); @@ -1902,7 +1915,7 @@ static void DrawBlankedLine(int line, int offs, int sh, int bgc) FinalizeLine(sh, line, &Pico.est); if (PicoScanEnd != NULL) - PicoScanEnd(line + offs); + skip_next_line = PicoScanEnd(line + offs); Pico.est.HighCol += HighColIncrement; Pico.est.DrawLineDest = (char *)Pico.est.DrawLineDest + DrawLineDestIncrement; @@ -1910,15 +1923,10 @@ static void DrawBlankedLine(int line, int offs, int sh, int bgc) static void PicoLine(int line, int offs, int sh, int bgc) { - int skip = 0; - - if (skip_next_line > 0) { - skip_next_line--; - return; - } + int skip = skip_next_line; Pico.est.DrawScanline = line; - if (PicoScanBegin != NULL) + if (PicoScanBegin != NULL && skip == 0) skip = PicoScanBegin(line + offs); if (skip) { diff --git a/pico/draw_arm.S b/pico/draw_arm.S index 38d831f6..6a3641bd 100644 --- a/pico/draw_arm.S +++ b/pico/draw_arm.S @@ -1642,27 +1642,42 @@ FinalizeLine555: add r3, r10, #OFS_EST_HighPal mov lr, #0xff + mov lr, lr, lsl #1 + ldr r5, [r10, #OFS_EST_PicoOpt] ldr r1, [r10, #OFS_EST_HighCol] ldr r0, [r10, #OFS_EST_DrawLineDest] + ldr r4, [r5] + ldr r7, [r5, #OFS_PicoIn_AHW-OFS_PicoIn_opt] + ldrb r12,[r8, #OFS_Pico_video_reg+12] + ldr r2, [r8, #OFS_Pico_m_hardware] add r1, r1, #8 - ldrb r12, [r8, #OFS_Pico_video_reg+12] - mov lr, lr, lsl #1 + tst r7, #0x10 + beq .fl_no20colRGB555 + and r7, r2, #0x3 + cmp r7, #0x3 @ Game Gear, LCD? + bne .fl_no20colRGB555 - tst r12, #1 - movne r2, #320/8 @ len + mov r2, #160/8 @ len = 160 + tst r4, #0x4000 @ EN_SOFTSCALE? + bne .fl_20scale_RGB555 @ scale 160->320 + beq .fl_checkborder + +.fl_no20colRGB555: + tst r12, #1 @ h32? + movne r2, #320/8 @ len = 320 bne .fl_no32colRGB555 - ldr r5, [r10, #OFS_EST_PicoOpt] - mov r2, #256/8 - ldr r4, [r5] - tst r4, #0x4000 - bne .fl_32scale_RGB555 - tst r4, #0x0100 - addeq r0, r0, #32*2 + moveq r2, #256/8 @ len = 256 + tst r4, #0x4000 @ EN_SOFTSCALE? + bne .fl_32scale_RGB555 @ scale 256->320 -.fl_no32colRGB555: +.fl_checkborder: + tst r4, #0x0100 @ DIS_32C_BORDER? + rsbeq r4, r2, #320/8 @ pd += (320-len)/2 + addeq r0, r0, r4, lsl #3 +.fl_no32colRGB555: #ifdef UNALIGNED_DRAWLINEDEST @ this is basically for Gizmondo, which has unaligned odd lines in the framebuffer tst r0, #2 @@ -1715,9 +1730,9 @@ FinalizeLine555: bne .fl_32scale_RGB555u #endif - ands r5, r5, #0x3 - addne pc, pc, r5, lsl #2 - b .fl_32scale_nn + and r5, r5, #0x3 + add pc, pc, r5, lsl #2 + nop b .fl_32scale_nn b .fl_32scale_snn b .fl_32scale_bl2 @@ -1866,6 +1881,9 @@ FinalizeLine555: ldmfd sp!, {r4-r10,pc} .fl_32scale_bl4: + // TODO this should reflect the bl4 C algorithm, but it doesn't, it's bln. + and r9, r9, r9, lsl #1 @ nuke 2 LSBs to avoid spilling for n/4 +.fl_32loop_bl4: ldr r12, [r1], #4 ldr r7, [r1], #4 @@ -1926,10 +1944,147 @@ FinalizeLine555: subs r2, r2, #1 stmia r0!, {r4,r5,r6,r8,r10} - bne .fl_32scale_bl4 + bne .fl_32loop_bl4 + + ldmfd sp!, {r4-r10,pc} + +.fl_20scale_RGB555: + ldr r5, [r5, #OFS_PicoIn_filter-OFS_PicoIn_opt] + + mov r9, #0xf700 @ f800 07e0 001f | e000 0780 001c | 3800 01e0 0007 + orr r9, r9, #0x00de + +#ifdef UNALIGNED_DRAWLINEDEST + tst r0, #2 + bne .fl_20scale_RGB555u +#endif + + and r5, r5, #0x2 + add pc, pc, r5, lsl #1 + nop + b .fl_20scale_nn + b .fl_20scale_bl2 + +.fl_20scale_nn: + ldr r12, [r1], #4 + ldr r7, [r1], #4 + + and r4, lr, r12, lsl #1 + ldrh r4, [r3, r4] + and r5, lr, r12, lsr #7 + ldrh r5, [r3, r5] + and r6, lr, r12, lsr #15 + ldrh r6, [r3, r6] + and r8 ,lr, r12, lsr #23 + ldrh r8 ,[r3, r8 ] + + orr r4, r4, r4, lsl #16 + orr r5, r5, r5, lsl #16 + orr r6, r6, r6, lsl #16 + orr r8, r8, r8, lsl #16 + stmia r0!, {r4,r5,r6,r8} + + and r4, lr, r7, lsl #1 + ldrh r4, [r3, r4] + and r5, lr, r7, lsr #7 + ldrh r5, [r3, r5] + and r6 ,lr, r7, lsr #15 + ldrh r6 ,[r3, r6] + and r8, lr, r7, lsr #23 + ldrh r8, [r3, r8] + + orr r4, r4, r4, lsl #16 + orr r5, r5, r5, lsl #16 + orr r6, r6, r6, lsl #16 + orr r8, r8, r8, lsl #16 + stmia r0!, {r4,r5,r6,r8} + + subs r2, r2, #1 + bne .fl_20scale_nn + + ldmfd sp!, {r4-r10,pc} + + +.fl_20scale_bl2: + ldr r8, [r1] + and r8, lr, r8, lsl #1 + ldrh r8, [r3, r8] + and r8, r8, r9 + lsl r8, r8, #16 + +.fl_20loop_bl2: + ldr r12, [r1], #4 + ldr r7, [r1], #4 + + and r4, lr, r12, lsl #1 + ldrh r4, [r3, r4] + and r5, lr, r12, lsr #7 + ldrh r5, [r3, r5] + and r6, lr, r12, lsr #15 + ldrh r6, [r3, r6] + + and r4, r4, r9 + add r10,r4, r8, lsr #16 + mov r10,r10,lsr #1 + orr r4, r10,r4, lsl #16 @ (px-1+px0)/2 | px0 + + and r8 ,lr, r12, lsr #23 + ldrh r8 ,[r3, r8] + + and r5, r5, r9 + add r10,r5, r4, lsr #16 + mov r10,r10,lsr #1 + orr r5, r10,r5, lsl #16 @ (px0 +px1)/2 | px1 + + and r6, r6, r9 + add r10,r6, r5, lsr #16 + mov r10,r10,lsr #1 + orr r6, r10,r6, lsl #16 @ (px1 +px2)/2 | px2 + + and r8, r8, r9 + add r10,r8, r6, lsr #16 + mov r10,r10,lsr #1 + orr r8, r10,r8, lsl #16 @ (px2 +px3)/2 | px3 + + stmia r0!, {r4,r5,r6,r8} + + and r4, lr, r7, lsl #1 + ldrh r4, [r3, r4] + and r5, lr, r7, lsr #7 + ldrh r5, [r3, r5] + and r6, lr, r7, lsr #15 + ldrh r6, [r3, r6] + + and r4, r4, r9 + add r10,r4, r8, lsr #16 + mov r10,r10,lsr #1 + orr r4, r10,r4, lsl #16 @ (px-1+px0)/2 | px0 + + and r8 ,lr, r7, lsr #23 + ldrh r8 ,[r3, r8] + + and r5, r5, r9 + add r10,r5, r4, lsr #16 + mov r10,r10,lsr #1 + orr r5, r10,r5, lsl #16 @ (px0 +px1)/2 | px1 + + and r6, r6, r9 + add r10,r6, r5, lsr #16 + mov r10,r10,lsr #1 + orr r6, r10,r6, lsl #16 @ (px1 +px2)/2 | px2 + + and r8, r8, r9 + add r10,r8, r6, lsr #16 + mov r10,r10,lsr #1 + orr r8, r10,r8, lsl #16 @ (px2 +px3)/2 | px3 + + subs r2, r2, #1 + stmia r0!, {r4,r5,r6,r8} + bne .fl_20loop_bl2 ldmfd sp!, {r4-r10,pc} + #ifdef UNALIGNED_DRAWLINEDEST @ unaligned versions of loops @ warning: starts drawing 2bytes before dst diff --git a/pico/media.c b/pico/media.c index f4ad8cde..d7e91a0f 100644 --- a/pico/media.c +++ b/pico/media.c @@ -248,7 +248,6 @@ enum media_type_e PicoLoadMedia(const char *filename, } } else if (media_type == PM_MARK3) { - lprintf("detected SMS ROM\n"); PicoIn.AHW = PAHW_SMS; } @@ -297,9 +296,18 @@ enum media_type_e PicoLoadMedia(const char *filename, goto out; } rom_data = NULL; // now belongs to PicoCart - Pico.m.ncart_in = 0; + + // simple test for GG. Do this here since m.hardware is nulled in Insert + if (PicoIn.AHW & PAHW_SMS) { + if (strstr(filename,".gg")) { + Pico.m.hardware |= 0x1; + lprintf("detected GG ROM\n"); + } else + lprintf("detected SMS ROM\n"); + } // insert CD if it was detected + Pico.m.ncart_in = 0; if (cd_img_type != CT_UNKNOWN) { ret = cdd_load(filename, cd_img_type); if (ret != 0) { diff --git a/pico/mode4.c b/pico/mode4.c index 889a43e0..2406dd4a 100644 --- a/pico/mode4.c +++ b/pico/mode4.c @@ -141,6 +141,8 @@ static void DrawSpritesM4(int scanline) if (pv->reg[0] & 8) xoff = 0; xoff += line_offset; + if ((Pico.m.hardware & 0x3) == 0x3) + xoff -= 48; // GG LCD, adjust to center 160 px sat = (u8 *)PicoMem.vram + ((pv->reg[5] & 0x7e) << 7); if (pv->reg[1] & 2) { @@ -164,10 +166,12 @@ static void DrawSpritesM4(int scanline) break; } - sprites_x[s] = xoff + sat[MEM_LE2(0x80 + i*2)]; - sprites_addr[s] = sprite_base + ((sat[MEM_LE2(0x80 + i*2 + 1)] & addr_mask) << (5-1)) + - ((scanline - y) >> zoomed << (2-1)); - s++; + if (xoff + sat[MEM_LE2(0x80 + i*2)] >= 0) { + sprites_x[s] = xoff + sat[MEM_LE2(0x80 + i*2)]; + sprites_addr[s] = sprite_base + ((sat[MEM_LE2(0x80 + i*2 + 1)] & addr_mask) << (5-1)) + + ((scanline - y) >> zoomed << (2-1)); + s++; + } } // really half-assed but better than nothing @@ -296,9 +300,12 @@ static void DrawDisplayM4(int scanline) // low priority tiles if (!(pv->debug_p & PVD_KILL_B)) { - if (pv->reg[0] & 0x80) { + if ((Pico.m.hardware & 0x3) == 0x3) { + // on GG render only the center 160 px + DrawStripLowM4(nametab , dx | ((cells-12)<< 16),(tilex+6) | (ty << 16)); + } else if (pv->reg[0] & 0x80) { // vscroll disabled for rightmost 8 columns (e.g. Gauntlet) - int dx2 = dx + (cells-8)*8, tilex2 = tilex + (cells-8), ty2 = scanline & 7; + int dx2 = dx + (cells-8)*8, tilex2 = tilex + (cells-8), ty2 = scanline&7; DrawStripLowM4(nametab, dx | ((cells-8) << 16), tilex | (ty << 16)); DrawStripLowM4(nametab2, dx2 | (8 << 16), tilex2 | (ty2 << 17)); } else @@ -311,8 +318,10 @@ static void DrawDisplayM4(int scanline) // high priority tiles (use virtual layer switch just for fun) if (!(pv->debug_p & PVD_KILL_A)) { - if (pv->reg[0] & 0x80) { - int dx2 = dx + (cells-8)*8, tilex2 = tilex + (cells-8), ty2 = scanline & 7; + if ((Pico.m.hardware & 0x3) == 0x3) { + DrawStripHighM4(nametab , dx | ((cells-12)<< 16),(tilex+6) | (ty << 16)); + } else if (pv->reg[0] & 0x80) { + int dx2 = dx + (cells-8)*8, tilex2 = tilex + (cells-8), ty2 = scanline&7; DrawStripHighM4(nametab, dx | ((cells-8) << 16), tilex | (ty << 16)); DrawStripHighM4(nametab2, dx2 | (8 << 16), tilex2 | (ty2 << 17)); } else @@ -451,20 +460,21 @@ static void DrawSpritesM2(int scanline) // now draw all sprites backwards for (--s; s >= 0; s--) { - int x, w = (zoomed ? 16: 8); + int x, c, w = (zoomed ? 16: 8); i = sprites_x[s]; x = sat[MEM_LE2(i+1)] + xoff; if (sat[MEM_LE2(i+3)] & 0x80) x -= 32; + c = sat[MEM_LE2(i+3)] & 0x0f; if (x > 0) { pack = PicoMem.vramb[MEM_LE2(sprites_addr[s])]; - if (zoomed) TileDoubleSprM2(x, pack, sat[MEM_LE2(i+3)] & 0xf); - else TileNormSprM2(x, pack, sat[MEM_LE2(i+3)] & 0xf); + if (zoomed) TileDoubleSprM2(x, pack, c); + else TileNormSprM2(x, pack, c); } if((pv->reg[1] & 0x2) && (x+=w) > 0) { pack = PicoMem.vramb[MEM_LE2(sprites_addr[s]+0x10)]; - if (zoomed) TileDoubleSprM2(x, pack, sat[MEM_LE2(i+3)] & 0xf); - else TileNormSprM2(x, pack, sat[MEM_LE2(i+3)] & 0xf); + if (zoomed) TileDoubleSprM2(x, pack, c); + else TileNormSprM2(x, pack, c); } } } @@ -524,34 +534,45 @@ static void FinalizeLineRGB555SMS(int line); void PicoFrameStartSMS(void) { - int lines = 192, columns = 256, coffs; + int lines = 192, columns = 256, loffs, coffs; skip_next_line = 0; - screen_offset = 24; + loffs = screen_offset = 24; // 192 lines is really 224 with top/bottom bars Pico.est.rendstatus = PDRAW_32_COLS; - switch ((Pico.video.reg[0]&0x06) | (Pico.video.reg[1]&0x18)) { + // Copy LCD enable flag for easier handling + Pico.m.hardware &= ~0x2; + if (PicoIn.opt & POPT_EN_GG_LCD) + Pico.m.hardware |= 0x2; + + if ((Pico.m.hardware & 0x3) == 0x3) { + // GG LCD always has 160x144 regardless of settings + screen_offset = 24; // nonetheless the vdp timing has 224 lines + loffs = 48; + lines = 144; + columns = 160; + } else switch ((Pico.video.reg[0]&0x06) | (Pico.video.reg[1]&0x18)) { // SMS2 only 224/240 line modes, e.g. Micro Machines case 0x06|0x08: - screen_offset = 0; + loffs = screen_offset = 0; lines = 240; break; case 0x06|0x10: - screen_offset = 8; + loffs = screen_offset = 8; lines = 224; break; } if (PicoIn.opt & POPT_EN_SOFTSCALE) { - line_offset = 0; + coffs = 0; columns = 320; } else - line_offset = PicoIn.opt & POPT_DIS_32C_BORDER ? 0 : 32; + coffs = PicoIn.opt & POPT_DIS_32C_BORDER ? 0:(320-columns)/2; + line_offset = (PicoIn.opt & POPT_ALT_RENDERER ? coffs : 0); - coffs = line_offset; if (FinalizeLineSMS == FinalizeLineRGB555SMS) line_offset = 0 /* done in FinalizeLine */; if (Pico.est.rendstatus != rendstatus_old || lines != rendlines) { - emu_video_mode_change(screen_offset, lines, coffs, columns); + emu_video_mode_change(loffs, lines, coffs, columns); rendstatus_old = Pico.est.rendstatus; rendlines = lines; } @@ -562,14 +583,20 @@ void PicoFrameStartSMS(void) void PicoLineSMS(int line) { - if (skip_next_line > 0) { - skip_next_line--; + int skip = skip_next_line; + + // GG LCD, render only visible part of screen + if ((Pico.m.hardware & 0x3) == 0x3 && (line < 24 || line >= 24+144)) + goto norender; + + if (PicoScanBegin != NULL && skip == 0) + skip = PicoScanBegin(line + screen_offset); + + if (skip) { + skip_next_line = skip - 1; return; } - if (PicoScanBegin != NULL) - skip_next_line = PicoScanBegin(line + screen_offset); - // Draw screen: BackFill(Pico.video.reg[7] & 0x0f, 0, &Pico.est); if (Pico.video.reg[1] & 0x40) { @@ -583,19 +610,21 @@ void PicoLineSMS(int line) if (PicoScanEnd != NULL) skip_next_line = PicoScanEnd(line + screen_offset); +norender: Pico.est.HighCol += HighColIncrement; Pico.est.DrawLineDest = (char *)Pico.est.DrawLineDest + DrawLineDestIncrement; } /* Fixed palette for TMS9918 modes */ static u16 tmspal[32] = { - 0x00,0x00,0x08,0x0c,0x10,0x30,0x01,0x3c,0x02,0x03,0x05,0x0f,0x04,0x33,0x15,0x3f + 0x0000, 0x0000, 0x00a0, 0x00f0, 0x0500, 0x0f00, 0x0005, 0x0ff0, + 0x000a, 0x000f, 0x0055, 0x00ff, 0x0050, 0x0f0f, 0x0555, 0x0fff, }; void PicoDoHighPal555SMS(void) { - unsigned int *spal=(void *)PicoMem.cram; - unsigned int *dpal=(void *)Pico.est.HighPal; + u32 *spal=(void *)PicoMem.cram; + u32 *dpal=(void *)Pico.est.HighPal; unsigned int t; int i; @@ -603,21 +632,9 @@ void PicoDoHighPal555SMS(void) if (!(Pico.video.reg[0] & 0x4)) spal = (u32 *)tmspal; - /* cram is always stored as shorts, even though real hardware probably uses bytes */ - if (PicoIn.AHW & PAHW_SMS) for (i = 0x20/2; i > 0; i--, spal++, dpal++) { - t = *spal; -#if defined(USE_BGR555) - t = ((t & 0x00030003)<< 3) | ((t & 0x000c000c)<<6) | ((t & 0x00300030)<<9); - t |= (t >> 2) | ((t >> 4) & 0x04210421); -#elif defined(USE_BGR565) - t = ((t & 0x00030003)<< 3) | ((t & 0x000c000c)<<7) | ((t & 0x00300030)<<10); - t |= (t >> 2) | ((t >> 4) & 0x08610861); -#else - t = ((t & 0x00030003)<<14) | ((t & 0x000c000c)<<7) | ((t & 0x00300030)>>1); - t |= (t >> 2) | ((t >> 4) & 0x08610861); -#endif - *dpal = t; - } else for (i = 0x20/2; i > 0; i--, spal++, dpal++) { // GG palette 4 bit/col + /* SMS 6 bit cram data was already converted to MD/GG format by vdp write, + * hence GG/SMS/TMS can all be handled the same here */ + for (i = 0x20/2; i > 0; i--, spal++, dpal++) { t = *spal; #if defined(USE_BGR555) t = ((t & 0x000f000f)<< 1) | ((t & 0x00f000f0)<<2) | ((t & 0x0f000f00)<<3); @@ -646,15 +663,7 @@ static void FinalizeLineRGB555SMS(int line) static void FinalizeLine8bitSMS(int line) { - u8 *pd = Pico.est.DrawLineDest + line_offset; - u8 *ps = Pico.est.HighCol + line_offset + 8; - - if (DrawLineDestIncrement) { - if (PicoIn.opt & POPT_EN_SOFTSCALE) - rh_upscale_nn_4_5(pd, 320, ps, 256, 256, f_nop); - else if (pd != ps) - memcpy(pd, ps, 256); - } + FinalizeLine8bit(0, line, &Pico.est); } void PicoDrawSetOutputSMS(pdso_t which) diff --git a/pico/pico.h b/pico/pico.h index 76786d61..dc615d1e 100644 --- a/pico/pico.h +++ b/pico/pico.h @@ -64,7 +64,7 @@ extern void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s; #define POPT_EN_MCD_PCM (1<<10) #define POPT_EN_MCD_CDDA (1<<11) #define POPT_EN_MCD_GFX (1<<12) // 00 x000 -// unused (1<<13) +#define POPT_EN_GG_LCD (1<<13) #define POPT_EN_SOFTSCALE (1<<14) #define POPT_EN_MCD_RAMCART (1<<15) #define POPT_DIS_VDP_FIFO (1<<16) // 0x 0000 diff --git a/pico/pico_int.h b/pico/pico_int.h index 9a66344c..e6019296 100644 --- a/pico/pico_int.h +++ b/pico/pico_int.h @@ -670,6 +670,7 @@ PICO_INTERNAL void PicoFrameStart(void); void PicoDrawSync(int to, int blank_last_line); void BackFill(int reg7, int sh, struct PicoEState *est); void FinalizeLine555(int sh, int line, struct PicoEState *est); +void FinalizeLine8bit(int sh, int line, struct PicoEState *est); void PicoDrawSetOutBufMD(void *dest, int increment); extern int (*PicoScanBegin)(unsigned int num); extern int (*PicoScanEnd)(unsigned int num); diff --git a/pico/sms.c b/pico/sms.c index 5f175ca6..6c8ce358 100644 --- a/pico/sms.c +++ b/pico/sms.c @@ -52,8 +52,17 @@ static void vdp_data_write(unsigned char d) struct PicoVideo *pv = &Pico.video; if (pv->type == 3) { - if (PicoMem.cram[pv->addr & 0x1f] != d) Pico.m.dirtyPal = 1; - PicoMem.cram[pv->addr & 0x1f] = d; + if (Pico.m.hardware & 0x1) { // GG, same layout as MD + unsigned a = pv->addr & 0x3f; + if (a & 0x1) d &= 0x0f; + if (((u8 *)PicoMem.cram)[MEM_LE2(a)] != d) Pico.m.dirtyPal = 1; + ((u8 *)PicoMem.cram)[MEM_LE2(a)] = d; + } else { // SMS, convert to MD layout (00BbGgRr to 0000BbBbGgGgRrRr) + unsigned a = pv->addr & 0x1f; + u16 c = (d&0x30)*0x40 + (d&0x0c)*0x10 + (d&0x03)*0x04; + if (PicoMem.cram[a] != (c | (c>>2))) Pico.m.dirtyPal = 1; + PicoMem.cram[a] = c | (c>>2); + } } else { PicoMem.vramb[MEM_LE2(pv->addr)] = d; } @@ -130,7 +139,7 @@ static unsigned char z80_sms_in(unsigned short a) { case 0x00: case 0x01: - d = 0xff; + d = 0xff & ~(PicoIn.pad[0] & 0x80); break; case 0x40: /* V counter */ diff --git a/platform/common/arm_utils.s b/platform/common/arm_utils.s index 6696e5af..5f0c46c3 100644 --- a/platform/common/arm_utils.s +++ b/platform/common/arm_utils.s @@ -58,9 +58,6 @@ .endif orr r2, r2, r2, lsr #3 -.if \sh == 1 - str r2, [r0, #0x40*2*4] -.endif str r2, [r0], #4 .endm @@ -101,10 +98,10 @@ bgr444_to_rgb32_sh: subs r12, r12, #1 ldmia r1!, {r4-r7} - convRGB32_2 r4, 1 - convRGB32_2 r5, 1 - convRGB32_2 r6, 1 - convRGB32_2 r7, 1 + convRGB32_2 r4, 2 + convRGB32_2 r5, 2 + convRGB32_2 r6, 2 + convRGB32_2 r7, 2 bgt .loopRGB32sh mov r12, #0x40>>3 @ repeats @@ -112,10 +109,10 @@ bgr444_to_rgb32_sh: .loopRGB32hi: ldmia r1!, {r4-r7} - convRGB32_2 r4, 2 - convRGB32_2 r5, 2 - convRGB32_2 r6, 2 - convRGB32_2 r7, 2 + convRGB32_2 r4, 1 + convRGB32_2 r5, 1 + convRGB32_2 r6, 1 + convRGB32_2 r7, 1 subs r12, r12, #1 bgt .loopRGB32hi diff --git a/platform/common/emu.c b/platform/common/emu.c index fd4a2519..1ae8cdb5 100644 --- a/platform/common/emu.c +++ b/platform/common/emu.c @@ -326,6 +326,8 @@ static void system_announce(void) if (PicoIn.AHW & PAHW_SMS) { sys_name = "Master System"; + if (Pico.m.hardware & 0x1) + sys_name = "Game Gear"; #ifdef NO_SMS extra = " [no support]"; #endif @@ -587,7 +589,7 @@ void emu_prep_defconfig(void) memset(&defaultConfig, 0, sizeof(defaultConfig)); defaultConfig.EmuOpt = EOPT_EN_SRAM | EOPT_EN_SOUND | EOPT_16BPP | EOPT_EN_CD_LEDS | EOPT_GZIP_SAVES | 0x10/*?*/; - defaultConfig.s_PicoOpt = POPT_EN_SNDFILTER|POPT_EN_YM2413| + defaultConfig.s_PicoOpt = POPT_EN_SNDFILTER|POPT_EN_YM2413|POPT_EN_GG_LCD | POPT_EN_STEREO|POPT_EN_FM|POPT_EN_PSG|POPT_EN_Z80 | POPT_EN_MCD_PCM|POPT_EN_MCD_CDDA|POPT_EN_MCD_GFX | POPT_EN_DRC|POPT_ACC_SPRITES | diff --git a/platform/common/menu_pico.c b/platform/common/menu_pico.c index 6a6da396..c6162987 100644 --- a/platform/common/menu_pico.c +++ b/platform/common/menu_pico.c @@ -42,7 +42,7 @@ static const char *rom_exts[] = { "bin", "smd", "gen", "md", "iso", "cso", "cue", "chd", "32x", - "sms", + "sms", "gg", NULL }; @@ -536,6 +536,7 @@ static menu_entry e_menu_adv_options[] = mee_onoff ("Disable YM2612 SSG-EG", MA_OPT2_DISABLE_YM_SSG,PicoIn.opt, POPT_DIS_FM_SSGEG), mee_onoff ("Emulate SN76496 (PSG)", MA_OPT2_ENABLE_SN76496,PicoIn.opt, POPT_EN_PSG), mee_onoff ("Emulate YM2413 (FM)", MA_OPT2_ENABLE_YM2413 ,PicoIn.opt, POPT_EN_YM2413), + mee_onoff ("Emulate Game Gear LCD", MA_OPT2_ENABLE_GGLCD ,PicoIn.opt, POPT_EN_GG_LCD), mee_onoff ("Disable idle loop patching",MA_OPT2_NO_IDLE_LOOPS,PicoIn.opt, POPT_DIS_IDLE_DET), mee_onoff ("Disable frame limiter", MA_OPT2_NO_FRAME_LIMIT,currentConfig.EmuOpt, EOPT_NO_FRMLIMIT), mee_onoff ("Enable dynarecs", MA_OPT2_DYNARECS, PicoIn.opt, POPT_EN_DRC), diff --git a/platform/common/menu_pico.h b/platform/common/menu_pico.h index 2b699ef2..af365dbb 100644 --- a/platform/common/menu_pico.h +++ b/platform/common/menu_pico.h @@ -52,6 +52,7 @@ typedef enum MA_OPT2_DISABLE_YM_SSG, MA_OPT2_ENABLE_SN76496, MA_OPT2_ENABLE_YM2413, + MA_OPT2_ENABLE_GGLCD, MA_OPT2_NO_LAST_ROM, MA_OPT2_RAMTIMINGS, /* gp2x */ MA_OPT2_NO_FRAME_LIMIT, /* psp */ diff --git a/platform/common/upscale.h b/platform/common/upscale.h index 9719981e..1cf0fd9c 100644 --- a/platform/common/upscale.h +++ b/platform/common/upscale.h @@ -35,12 +35,20 @@ */ #include + +/* LSB of all colors in a pixel */ +#if defined(USE_BGR555) +#define PXLSB 0x0421 +#else +#define PXLSB 0x0821 +#endif + /* RGB565 pixel mixing, see https://www.compuphase.com/graphic/scale3.htm and http://blargg.8bitalley.com/info/rgb_mixing.html */ /* 2-level mixing */ -//#define p_05(d,p1,p2) d=(((p1)+(p2) + ( ((p1)^(p2))&0x0821))>>1) // round up -//#define p_05(d,p1,p2) d=(((p1)+(p2) - ( ((p1)^(p2))&0x0821))>>1) // round down -#define p_05(d,p1,p2) d=(((p1)&(p2)) + ((((p1)^(p2))&~0x0821)>>1)) +//#define p_05(d,p1,p2) d=(((p1)+(p2) + ( ((p1)^(p2))&PXLSB))>>1) // round up +//#define p_05(d,p1,p2) d=(((p1)+(p2) - ( ((p1)^(p2))&PXLSB))>>1) // round down +#define p_05(d,p1,p2) d=(((p1)&(p2)) + ((((p1)^(p2))&~PXLSB)>>1)) /* 4-level mixing, 2 times slower */ // 1/4*p1 + 3/4*p2 = 1/2*(1/2*(p1+p2) + p2) #define p_025(d,p1,p2) p_05(t, p1, p2); p_05( d, t, p2) @@ -322,6 +330,21 @@ scalers h: si += ss - w; \ } while (0) +// reverse version for overlapping buffers +#define rh_upscale_nn_1_2(di,ds,si,ss,w,f) do { \ + int i; \ + di += w*2; \ + si += w; \ + for (i = w/2; i > 0; i--, si -= 2, di -= 4) { \ + di[-1] = f(si[-1]); \ + di[-2] = f(si[-1]); \ + di[-3] = f(si[-2]); \ + di[-4] = f(si[-2]); \ + } \ + di += ds; \ + si += ss; \ +} while (0) + #define h_upscale_bl2_1_2(di,ds,si,ss,w,f) do { \ int i; uint p = f(si[0]); \ for (i = w/2; i > 0; i--, si += 2, di += 4) { \ @@ -514,11 +537,12 @@ scalers v: } else { \ int j; \ l = 0; \ - di -= 4*ds; \ + di -= 3*ds; \ for (j = 0; j < 2; j++) { \ v_copy(&di[0], &di[-ds], w, f_nop); \ di += 2*ds; \ } \ + di -= ds; \ } \ } while (0) @@ -528,11 +552,12 @@ scalers v: } else { \ int j; \ l = 0; \ - di -= 4*ds; \ + di -= 3*ds; \ for (j = 0; j < 2; j++) { \ v_mix(&di[0], &di[-ds], &di[ds], w, p_05, f_nop); \ di += 2*ds; \ } \ + di -= ds; \ } \ } while (0) diff --git a/platform/gp2x/emu.c b/platform/gp2x/emu.c index 0622691b..deb86581 100644 --- a/platform/gp2x/emu.c +++ b/platform/gp2x/emu.c @@ -105,7 +105,7 @@ static void change_renderer(int diff) } #define is_16bit_mode() \ - (currentConfig.renderer == RT_16BIT || (PicoIn.AHW & PAHW_32X)) + (currentConfig.renderer == RT_16BIT || (PicoIn.AHW & PAHW_32X) || doing_bg_frame) static void (*osd_text)(int x, int y, const char *text); @@ -248,7 +248,7 @@ static int EmuScanEnd8_rot(unsigned int num) /* line doublers */ static unsigned int ld_counter; -static int ld_left, ld_lines; +static int ld_left, ld_lines; // numbers in Q1 format static int EmuScanBegin16_ld(unsigned int num) { @@ -271,9 +271,9 @@ static int EmuScanEnd16_ld(unsigned int num) emu_scan_end(ld_counter); ld_counter++; - ld_left--; + ld_left -= 2; if (ld_left <= 0) { - ld_left = ld_lines; + ld_left += ld_lines; EmuScanBegin16_ld(num); memcpy(Pico.est.DrawLineDest, oldline, 320 * gp2x_current_bpp / 8); @@ -313,6 +313,7 @@ static int make_local_pal_md(int fast_mode) else if (Pico.video.reg[0xC] & 8) { // shadow/hilight mode bgr444_to_rgb32(localPal, Pico.est.SonicPal); bgr444_to_rgb32_sh(localPal, Pico.est.SonicPal); + memcpy(localPal+0xc0, localPal, 0x40*4); // for spr prio mess } else { bgr444_to_rgb32(localPal, Pico.est.SonicPal); @@ -331,18 +332,7 @@ static int make_local_pal_md(int fast_mode) static int make_local_pal_sms(int fast_mode) { - unsigned short *spal = PicoMem.cram; - unsigned int *dpal = (void *)localPal; - unsigned int i, t; - - for (i = 0x40; i > 0; i--) { - t = *spal++; - t = ((t & 0x0003) << 22) | ((t & 0x000c) << 12) | ((t & 0x0030) << 2); - t |= t >> 2; - t |= t >> 4; - *dpal++ = t; - } - + bgr444_to_rgb32(localPal, PicoMem.cram); Pico.m.dirtyPal = 0; return 0x40; } @@ -486,6 +476,9 @@ static void vid_reset_mode(void) int gp2x_mode = 16; int renderer = get_renderer(); + if (doing_bg_frame) + renderer = RT_16BIT; + PicoIn.opt &= ~POPT_ALT_RENDERER; emu_scan_begin = NULL; emu_scan_end = NULL; @@ -557,11 +550,13 @@ static void vid_reset_mode(void) Pico.m.dirtyPal = 1; - PicoIn.opt &= ~POPT_EN_SOFTSCALE; + PicoIn.opt &= ~(POPT_DIS_32C_BORDER|POPT_EN_SOFTSCALE); if (currentConfig.scaling == EOPT_SCALE_SW) { PicoIn.opt |= POPT_EN_SOFTSCALE; PicoIn.filter = EOPT_FILTER_BILINEAR2; - } + } else if (currentConfig.scaling == EOPT_SCALE_HW && is_16bit_mode()) + // hw scaling, render without any padding + PicoIn.opt |= POPT_DIS_32C_BORDER; // palette converters for 8bit modes make_local_pal = (PicoIn.AHW & PAHW_SMS) ? make_local_pal_sms : make_local_pal_md; @@ -572,6 +567,12 @@ void emu_video_mode_change(int start_line, int line_count, int start_col, int co int scalex = 320, scaley = 240; int ln_offs = 0; + /* line doubling for swscaling, also needed for bg frames */ + if (currentConfig.vscaling == EOPT_SCALE_SW && line_count < 240) { + ld_lines = ld_left = 2*line_count / (240 - line_count); + PicoDrawSetCallbacks(EmuScanBegin16_ld, EmuScanEnd16_ld); + } + if (doing_bg_frame) return; @@ -579,10 +580,8 @@ void emu_video_mode_change(int start_line, int line_count, int start_col, int co osd_y = 232; /* set up hwscaling here */ - PicoIn.opt &= ~POPT_DIS_32C_BORDER; if (col_count < 320 && currentConfig.scaling == EOPT_SCALE_HW) { scalex = col_count; - PicoIn.opt |= POPT_DIS_32C_BORDER; osd_fps_x = col_count - (320-OSD_FPS_X); } @@ -594,11 +593,6 @@ void emu_video_mode_change(int start_line, int line_count, int start_col, int co gp2x_video_RGB_setscaling(ln_offs, scalex, scaley); - /* line doubling */ - if (currentConfig.vscaling == EOPT_SCALE_SW && line_count < 240) { - ld_lines = ld_left = line_count / (240 - line_count); - PicoDrawSetCallbacks(EmuScanBegin16_ld, EmuScanEnd16_ld); - } // clear whole screen in all buffers if (!is_16bit_mode()) @@ -731,6 +725,8 @@ void pemu_forced_frame(int no_scale, int do_emu) doing_bg_frame = 1; PicoDrawSetCallbacks(NULL, NULL); Pico.m.dirtyPal = 1; + PicoIn.opt &= ~POPT_DIS_32C_BORDER; + gp2x_current_bpp = 16; if (!no_scale) no_scale = currentConfig.scaling == EOPT_SCALE_NONE; @@ -749,6 +745,7 @@ void plat_video_loop_prepare(void) // make sure we are in correct mode change_renderer(0); vid_reset_mode(); + rendstatus_old = -1; } void pemu_loop_prep(void) diff --git a/platform/libretro/libretro.c b/platform/libretro/libretro.c index 7c63c97b..4a9abea8 100644 --- a/platform/libretro/libretro.c +++ b/platform/libretro/libretro.c @@ -89,8 +89,8 @@ static retro_audio_sample_batch_t audio_batch_cb; #define INITIAL_SND_RATE 44100 static const float VOUT_PAR = 0.0; -static const float VOUT_4_3 = (224.0f * (4.0f / 3.0f)); -static const float VOUT_CRT = (224.0f * 1.29911f); +static const float VOUT_4_3 = (4.0f / 3.0f); +static const float VOUT_CRT = (1.29911f); static bool show_overscan = false; static bool old_show_overscan = false; @@ -746,7 +746,7 @@ void retro_get_system_info(struct retro_system_info *info) #define _GIT_VERSION "-" GIT_VERSION #endif info->library_version = VERSION _GIT_VERSION; - info->valid_extensions = "bin|gen|smd|md|32x|cue|iso|chd|sms"; + info->valid_extensions = "bin|gen|smd|md|32x|cue|iso|chd|sms|gg"; info->need_fullpath = true; } @@ -899,7 +899,7 @@ typedef struct patch } patch; extern void decode(char *buff, patch *dest); -extern uint16_t m68k_read16(uint32_t a); +extern uint32_t m68k_read16(uint32_t a); extern void m68k_write16(uint32_t a, uint16_t d); void retro_cheat_reset(void) @@ -1494,12 +1494,13 @@ static void update_variables(bool first_run) var.value = NULL; var.key = "picodrive_aspect"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + int height = vout_height >= 192 && vout_height <= 224 ? 224 : vout_height; if (strcmp(var.value, "4/3") == 0) - user_vout_width = VOUT_4_3; + user_vout_width = VOUT_4_3 * height; else if (strcmp(var.value, "CRT") == 0) - user_vout_width = VOUT_CRT; + user_vout_width = VOUT_CRT * height; else - user_vout_width = VOUT_PAR; + user_vout_width = VOUT_PAR * height; } if (user_vout_width != old_user_vout_width) @@ -1801,7 +1802,8 @@ void retro_init(void) sceBlock = getVMBlock(); #endif - PicoIn.opt = POPT_EN_STEREO|POPT_EN_FM|POPT_EN_PSG|POPT_EN_Z80|POPT_EN_YM2413 + PicoIn.opt = POPT_EN_STEREO|POPT_EN_FM + | POPT_EN_PSG|POPT_EN_Z80|POPT_EN_YM2413|POPT_EN_GG_LCD | POPT_EN_MCD_PCM|POPT_EN_MCD_CDDA|POPT_EN_MCD_GFX | POPT_EN_32X|POPT_EN_PWM | POPT_ACC_SPRITES|POPT_DIS_32C_BORDER; diff --git a/platform/linux/emu.c b/platform/linux/emu.c index 36898e61..1b228e91 100644 --- a/platform/linux/emu.c +++ b/platform/linux/emu.c @@ -95,7 +95,7 @@ static void draw_cd_leds(void) * for display isn't always possible. */ -static u16 *screen_buffer(u16 *buf) +static inline u16 *screen_buffer(u16 *buf) { return buf + screen_y * g_screen_ppitch + screen_x - (out_y * g_screen_ppitch + out_x); @@ -105,34 +105,46 @@ void screen_blit(u16 *pd, int pp, u8* ps, int ss, u16 *pal) { typedef void (*upscale_t) (u16 *di,int ds, u8 *si,int ss, int w,int h, u16 *pal); - upscale_t upscale_hv[] = { + static const upscale_t upscale_256_224_hv[] = { upscale_rgb_nn_x_4_5_y_16_17, upscale_rgb_snn_x_4_5_y_16_17, upscale_rgb_bl2_x_4_5_y_16_17, upscale_rgb_bl4_x_4_5_y_16_17, }; - upscale_t upscale_h[] = { + static const upscale_t upscale_256_224_h[] = { upscale_rgb_nn_x_4_5, upscale_rgb_snn_x_4_5, upscale_rgb_bl2_x_4_5, upscale_rgb_bl4_x_4_5, }; - upscale_t upscale_v[] = { + static const upscale_t upscale_256_224_v[] = { upscale_rgb_nn_y_16_17, upscale_rgb_snn_y_16_17, upscale_rgb_bl2_y_16_17, upscale_rgb_bl4_y_16_17, }; - upscale_t *upscale; + static const upscale_t upscale_160_144_hv[] = { + upscale_rgb_nn_x_1_2_y_3_5, upscale_rgb_nn_x_1_2_y_3_5, + upscale_rgb_bl2_x_1_2_y_3_5, upscale_rgb_bl4_x_1_2_y_3_5, + }; + static const upscale_t upscale_160_144_h[] = { + upscale_rgb_nn_x_1_2, upscale_rgb_nn_x_1_2, + upscale_rgb_bl2_x_1_2, upscale_rgb_bl2_x_1_2, + }; + static const upscale_t upscale_160_144_v[] = { + upscale_rgb_nn_y_3_5, upscale_rgb_nn_y_3_5, + upscale_rgb_bl2_y_3_5, upscale_rgb_bl4_y_3_5, + }; + const upscale_t *upscale; int y; // handle software upscaling upscale = NULL; - if (currentConfig.scaling == EOPT_SCALE_SW && out_w == 256) { - if (currentConfig.vscaling == EOPT_SCALE_SW && out_h <= 224) - // h+v scaling - upscale = upscale_hv; - else - // h scaling - upscale = upscale_h; - } else if (currentConfig.vscaling == EOPT_SCALE_SW && out_h <= 224) { - // v scaling - upscale = upscale_v; - } else { + if (currentConfig.scaling == EOPT_SCALE_SW) { + if (currentConfig.vscaling == EOPT_SCALE_SW && out_h <= 224) + // h+v scaling + upscale = out_w == 256 ? upscale_256_224_hv: upscale_160_144_hv; + else + // h scaling + upscale = out_w == 256 ? upscale_256_224_h : upscale_160_144_h; + } else if (currentConfig.vscaling == EOPT_SCALE_SW && out_h <= 224) + // v scaling + upscale = out_w == 256 ? upscale_256_224_v : upscale_160_144_v; + if (!upscale) { // no scaling for (y = 0; y < out_h; y++) h_copy(pd, pp, ps, 328, out_w, f_pal); @@ -280,16 +292,16 @@ static int vscale_state; static int cb_vscaling_begin(unsigned int line) { - static int prevline = 999; - // at start of new frame? - if (line < prevline) { - // set y frame offset (see emu_change_video_mode) + if (line <= out_y) { + // set y frame offset (see emu_video_mode_change) Pico.est.DrawLineDest = screen_buffer(g_screen_ptr) + - (out_y * g_screen_ppitch + out_x); + (out_y * g_screen_ppitch /*+ out_x*/); vscale_state = 0; - } - prevline = line; + return out_y - line; + } else if (line > out_y + out_h) + return 1; + return 0; } @@ -301,16 +313,25 @@ static int cb_vscaling_nop(unsigned int line) static int cb_vscaling_end(unsigned int line) { u16 *dest = Pico.est.DrawLineDest; - switch (currentConfig.filter) { - case 3: v_upscale_bl4_16_17(dest, g_screen_ppitch, 320, vscale_state); - break; - case 2: v_upscale_bl2_16_17(dest, g_screen_ppitch, 320, vscale_state); - break; - case 1: v_upscale_snn_16_17(dest, g_screen_ppitch, 320, vscale_state); - break; - default: v_upscale_nn_16_17(dest, g_screen_ppitch, 320, vscale_state); - break; - } + + if (out_h == 144) + switch (currentConfig.filter) { + case 0: v_upscale_nn_3_5(dest, g_screen_ppitch, 320, vscale_state); + break; + default: v_upscale_snn_3_5(dest, g_screen_ppitch, 320, vscale_state); + break; + } + else + switch (currentConfig.filter) { + case 3: v_upscale_bl4_16_17(dest, g_screen_ppitch, 320, vscale_state); + break; + case 2: v_upscale_bl2_16_17(dest, g_screen_ppitch, 320, vscale_state); + break; + case 1: v_upscale_snn_16_17(dest, g_screen_ppitch, 320, vscale_state); + break; + default: v_upscale_nn_16_17(dest, g_screen_ppitch, 320, vscale_state); + break; + } Pico.est.DrawLineDest = dest; return 0; } @@ -337,10 +358,10 @@ void emu_video_mode_change(int start_line, int line_count, int start_col, int co } switch (currentConfig.vscaling) { case EOPT_SCALE_HW: - screen_h = (out_h < 224 ? 224 : out_h); + screen_h = (out_h < 224 && out_h > 144 ? 224 : out_h); screen_y = 0; // NTSC always has 224 visible lines, anything smaller has bars - if (out_h < 224) + if (out_h < 224 && out_h > 144) screen_y += (224 - out_h)/2; // handle vertical centering for 16 bit mode if (is_16bit_mode()) @@ -349,7 +370,7 @@ void emu_video_mode_change(int start_line, int line_count, int start_col, int co case EOPT_SCALE_SW: screen_y = (screen_h - 240)/2; // NTSC always has 224 visible lines, anything smaller has bars - if (out_h < 224) + if (out_h < 224 && out_h > 144) screen_y += (224 - out_h)/2; // in 16 bit mode sw scaling is divided between core and platform if (is_16bit_mode() && out_h < 240) diff --git a/tools/mkoffsets.sh b/tools/mkoffsets.sh index 615e347f..d9a8db5c 100755 --- a/tools/mkoffsets.sh +++ b/tools/mkoffsets.sh @@ -136,6 +136,7 @@ get_define OFS_Pico_ Pico est ; echo "$line" >>$fn get_define OFS_PicoIn_ PicoInterface opt ; echo "$line" >>$fn get_define OFS_PicoIn_ PicoInterface filter ; echo "$line" >>$fn +get_define OFS_PicoIn_ PicoInterface AHW ; echo "$line" >>$fn get_define OFS_EST_ PicoEState DrawScanline ; echo "$line" >>$fn get_define OFS_EST_ PicoEState rendstatus ; echo "$line" >>$fn