From d19fe700f5e249d8f4b277004edcafe54fcc4106 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Thu, 23 Nov 2023 09:58:00 +1300 Subject: [PATCH 1/3] Use 8bpp renderer when attrregs.0x10.6 is set instead of when gdcreg.0x05.6 is set This allows correct emulation of the 4bpp chunky mode which is supported by many but not all chipsets. See discussion #3840 on GitHub. --- src/video/vid_svga.c | 125 ++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 55 deletions(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index b2347f87c..1b9b3cf7c 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -639,67 +639,82 @@ svga_recalctimings(svga_t *svga) svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; svga->hdisp_old = svga->hdisp; - switch (svga->gdcreg[5] & 0x60) { - case 0x00: + if (svga->bpp <= 8) { + if (svga->attrregs[0x10] & 0x40) { /*8bpp mode*/ + svga->map8 = svga->pallook; + if (svga->lowres) /*Low res (320)*/ + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + } else { if (svga->seqregs[1] & 8) /*Low res (320)*/ svga->render = svga_render_4bpp_lowres; else svga->render = svga_render_4bpp_highres; - break; - case 0x20: /*4 colours*/ - if (svga->seqregs[1] & 8) /*Low res (320)*/ - svga->render = svga_render_2bpp_lowres; - else - svga->render = svga_render_2bpp_highres; - break; - case 0x40: - case 0x60: /*256+ colours*/ - switch (svga->bpp) { - case 8: - svga->map8 = svga->pallook; - if (svga->lowres) - svga->render = svga_render_8bpp_lowres; - else - svga->render = svga_render_8bpp_highres; - break; - case 15: - if (svga->lowres) - svga->render = svga_render_15bpp_lowres; - else - svga->render = svga_render_15bpp_highres; - break; - case 16: - if (svga->lowres) - svga->render = svga_render_16bpp_lowres; - else - svga->render = svga_render_16bpp_highres; - break; - case 17: - if (svga->lowres) - svga->render = svga_render_15bpp_mix_lowres; - else - svga->render = svga_render_15bpp_mix_highres; - break; - case 24: - if (svga->lowres) - svga->render = svga_render_24bpp_lowres; - else - svga->render = svga_render_24bpp_highres; - break; - case 32: - if (svga->lowres) - svga->render = svga_render_32bpp_lowres; - else - svga->render = svga_render_32bpp_highres; - break; + } + } else { + switch (svga->gdcreg[5] & 0x60) { + case 0x00: + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_4bpp_lowres; + else + svga->render = svga_render_4bpp_highres; + break; + case 0x20: /*4 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_2bpp_lowres; + else + svga->render = svga_render_2bpp_highres; + break; + case 0x40: + case 0x60: /*256+ colours*/ + switch (svga->bpp) { + case 8: + svga->map8 = svga->pallook; + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + break; + case 15: + if (svga->lowres) + svga->render = svga_render_15bpp_lowres; + else + svga->render = svga_render_15bpp_highres; + break; + case 16: + if (svga->lowres) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; + break; + case 17: + if (svga->lowres) + svga->render = svga_render_15bpp_mix_lowres; + else + svga->render = svga_render_15bpp_mix_highres; + break; + case 24: + if (svga->lowres) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; + break; + case 32: + if (svga->lowres) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; + break; - default: - break; - } - break; + default: + break; + } + break; - default: - break; + default: + break; + } } } } From 81d285b883651588bbe9e28a889687afff7284cd Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Thu, 23 Nov 2023 10:04:04 +1300 Subject: [PATCH 2/3] Force 8bpp highres SVGA modes to "bypass" the shifter entirely The current implementation still uses the shifter forced to Shift 256 mode to keep things generic, but we can always opt for a separate scanline renderer. --- src/video/vid_svga_render.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index fea4490d5..b1ce6a88d 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -462,20 +462,27 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) const bool attrblink = ((svga->attrregs[0x10] & 0x08) != 0); // The following is likely how it works on an IBM VGA - that is, it works with its BIOS. - // But on an S3 Trio, mode 13h is broken - seemingly accepting the address shift but ignoring the increment. - // Forcing it to use incbypow2=0, incevery=1, loadevery=1 makes it behave. + // But on some cards, certain modes are broken. + // - S3 Trio: mode 13h (320x200x8), incbypow2 given as 2 treated as 0 + // - ET4000/W32i: mode 2Eh (640x480x8), incevery given as 2 treated as 1 + const bool forcepacked = combine8bits && (svga->force_old_addr || svga->packed_chain4); + + // SVGA cards with a high-resolution 8bpp mode may actually bypass the VGA shifter logic. + // - HT-216 (+ other Video7 chipsets?) has 0x3C4.0xC8 bit 4 which, when set to 1, loads bytes directly, bypassing the shifters. + const bool highres8bpp = combine8bits && highres; + const bool dwordload = ((svga->seqregs[0x01] & 0x10) != 0); const bool wordload = ((svga->seqregs[0x01] & 0x04) != 0) && !dwordload; const bool wordincr = ((svga->crtc[0x17] & 0x08) != 0); const bool dwordincr = ((svga->crtc[0x14] & 0x20) != 0) && !wordincr; const bool dwordshift = ((svga->crtc[0x14] & 0x40) != 0); const bool wordshift = ((svga->crtc[0x17] & 0x40) == 0) && !dwordshift; - const uint32_t incbypow2 = (combine8bits && (svga->force_old_addr || svga->packed_chain4)) ? 0 : (dwordshift ? 2 : wordshift ? 1 : 0); - const uint32_t incevery = (combine8bits && (svga->force_old_addr || svga->packed_chain4)) ? 1 : (dwordincr ? 4 : wordincr ? 2 : 1); - const uint32_t loadevery = (combine8bits && (svga->force_old_addr || svga->packed_chain4)) ? 1 : (dwordload ? 4 : wordload ? 2 : 1); + const uint32_t incbypow2 = forcepacked ? 0 : (dwordshift ? 2 : wordshift ? 1 : 0); + const uint32_t incevery = forcepacked ? 1 : (dwordincr ? 4 : wordincr ? 2 : 1); + const uint32_t loadevery = forcepacked ? 1 : (dwordload ? 4 : wordload ? 2 : 1); - const bool shift2bit = ((svga->gdcreg[0x05] & 0x60) == 0x20 ); - const bool shift4bit = ((svga->gdcreg[0x05] & 0x40) == 0x40 ); + const bool shift4bit = ((svga->gdcreg[0x05] & 0x40) == 0x40 ) || highres8bpp; + const bool shift2bit = ((svga->gdcreg[0x05] & 0x60) == 0x20 ) && !shift4bit; const int dwshift = highres ? 0 : 1; const int dotwidth = 1 << dwshift; From 7de7ea3fe1ccce660ec9101aadbab4b5a8bfd476 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Thu, 23 Nov 2023 10:08:52 +1300 Subject: [PATCH 3/3] Clean up unused variable --- src/video/vid_svga_render.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index b1ce6a88d..9f3474418 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -455,7 +455,6 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) uint32_t addr; uint32_t *p; uint8_t edat[4]; - uint8_t dat; uint32_t changed_offset; const bool blinked = svga->blink & 0x10;