From 1f5d00fe55aab2349733c726065082c41b80ee40 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 10:26:13 +1300 Subject: [PATCH 1/8] Generate CGA-to-EGA tables in video.c; Remove redundant table generation in vid_ega.c --- src/include/86box/vid_svga_render.h | 1 + src/video/vid_ega.c | 28 ---------------------------- src/video/video.c | 13 +++++++++++++ 3 files changed, 14 insertions(+), 28 deletions(-) diff --git a/src/include/86box/vid_svga_render.h b/src/include/86box/vid_svga_render.h index 0c48303c9..3ad9e401c 100644 --- a/src/include/86box/vid_svga_render.h +++ b/src/include/86box/vid_svga_render.h @@ -34,6 +34,7 @@ extern int cgablink; extern int scrollcache; extern uint8_t edatlookup[4][4]; +extern uint8_t egaremap2bpp[256]; void svga_recalc_remap_func(svga_t *svga); diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 957a81304..d4abebb39 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -61,8 +61,6 @@ static uint32_t pallook64[256]; static int ega_type = 0; static int old_overscan_color = 0; -uint8_t egaremap2bpp[256]; - /* 3C2 controls default mode on EGA. On VGA, it determines monitor type (mono or colour): 7=CGA mode (200 lines), 9=EGA mode (350 lines), 8=EGA mode (200 lines). */ int egaswitchread; @@ -1282,32 +1280,6 @@ ega_init(ega_t *ega, int monitor_type, int is_mono) } } - for (c = 0; c < 4; c++) { - for (d = 0; d < 4; d++) { - edatlookup[c][d] = 0; - if (c & 1) - edatlookup[c][d] |= 1; - if (d & 1) - edatlookup[c][d] |= 2; - if (c & 2) - edatlookup[c][d] |= 0x10; - if (d & 2) - edatlookup[c][d] |= 0x20; - } - } - - for (c = 0; c < 256; c++) { - egaremap2bpp[c] = 0; - if (c & 0x01) - egaremap2bpp[c] |= 0x01; - if (c & 0x04) - egaremap2bpp[c] |= 0x02; - if (c & 0x10) - egaremap2bpp[c] |= 0x04; - if (c & 0x40) - egaremap2bpp[c] |= 0x08; - } - if (is_mono) { for (c = 0; c < 256; c++) { if (((c >> 3) & 3) == 0) diff --git a/src/video/video.c b/src/video/video.c index 34e602e39..4c561e229 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -78,6 +78,7 @@ volatile int screenshots = 0; uint8_t edatlookup[4][4]; +uint8_t egaremap2bpp[256]; uint8_t fontdat[2048][8]; /* IBM CGA font */ uint8_t fontdatm[2048][16]; /* IBM MDA font */ uint8_t fontdat2[2048][8]; /* IBM CGA 2nd instance font */ @@ -915,6 +916,18 @@ video_init(void) } } + for (uint16_t c = 0; c < 256; c++) { + egaremap2bpp[c] = 0; + if (c & 0x01) + egaremap2bpp[c] |= 0x01; + if (c & 0x04) + egaremap2bpp[c] |= 0x02; + if (c & 0x10) + egaremap2bpp[c] |= 0x04; + if (c & 0x40) + egaremap2bpp[c] |= 0x08; + } + video_6to8 = malloc(4 * 256); for (uint16_t c = 0; c < 256; c++) video_6to8[c] = calc_6to8(c); From 9703ccec45d914f598c9f3d467bec20a38749367 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 11:31:47 +1300 Subject: [PATCH 2/8] Initial merge of VGA 2bpp/4bpp lo/hi res renderers About half of it was taken from the EGA renderer. Also, the "force_old_addr" hack is kept here for now. --- src/video/vid_svga_render.c | 493 +++++++----------------------------- 1 file changed, 88 insertions(+), 405 deletions(-) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index c9369f09c..cee321347 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -16,6 +16,7 @@ * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. */ +#include #include #include #include @@ -392,202 +393,6 @@ svga_render_text_80_ksc5601(svga_t *svga) } } -void -svga_render_2bpp_lowres(svga_t *svga) -{ - int changed_offset; - int x; - uint8_t dat[2]; - uint32_t addr; - uint32_t *p; - uint32_t changed_addr; - - if ((svga->displine + svga->y_add) < 0) - return; - - if (svga->force_old_addr) { - changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; - - if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { - addr = svga->ma; - - if (!(svga->crtc[0x17] & 0x40)) { - addr = (addr << 1) & svga->vram_mask; - addr &= ~7; - - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) - addr |= 4; - - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) - addr |= 4; - } - - if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); - - if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); - - dat[0] = svga->vram[addr]; - dat[1] = svga->vram[addr | 0x1]; - if (svga->seqregs[1] & 4) - svga->ma += 2; - else - svga->ma += 4; - svga->ma &= svga->vram_mask; - p[0] = p[1] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; - p[2] = p[3] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; - p[4] = p[5] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; - p[6] = p[7] = svga->pallook[svga->egapal[dat[0] & 3]]; - p[8] = p[9] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; - p[10] = p[11] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; - p[12] = p[13] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; - p[14] = p[15] = svga->pallook[svga->egapal[dat[1] & 3]]; - p += 16; - } - } - } else { - changed_addr = svga->remap_func(svga, svga->ma); - - if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { - addr = svga->remap_func(svga, svga->ma); - - dat[0] = svga->vram[addr]; - dat[1] = svga->vram[addr | 0x1]; - if (svga->seqregs[1] & 4) - svga->ma += 2; - else - svga->ma += 4; - - svga->ma &= svga->vram_mask; - - p[0] = p[1] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; - p[2] = p[3] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; - p[4] = p[5] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; - p[6] = p[7] = svga->pallook[svga->egapal[dat[0] & 3]]; - p[8] = p[9] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; - p[10] = p[11] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; - p[12] = p[13] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; - p[14] = p[15] = svga->pallook[svga->egapal[dat[1] & 3]]; - - p += 16; - } - } - } -} - -void -svga_render_2bpp_highres(svga_t *svga) -{ - int changed_offset; - int x; - uint8_t dat[2]; - uint32_t addr; - uint32_t *p; - uint32_t changed_addr; - - if ((svga->displine + svga->y_add) < 0) - return; - - if (svga->force_old_addr) { - changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; - - if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - addr = svga->ma; - - if (!(svga->crtc[0x17] & 0x40)) { - addr = (addr << 1) & svga->vram_mask; - addr &= ~7; - - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) - addr |= 4; - - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) - addr |= 4; - } - - if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); - - if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); - - dat[0] = svga->vram[addr]; - dat[1] = svga->vram[addr | 0x1]; - if (svga->seqregs[1] & 4) - svga->ma += 2; - else - svga->ma += 4; - svga->ma &= svga->vram_mask; - p[0] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; - p[1] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; - p[2] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; - p[3] = svga->pallook[svga->egapal[dat[0] & 3]]; - p[4] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; - p[5] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; - p[6] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; - p[7] = svga->pallook[svga->egapal[dat[1] & 3]]; - p += 8; - } - } - } else { - changed_addr = svga->remap_func(svga, svga->ma); - - if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - addr = svga->remap_func(svga, svga->ma); - - dat[0] = svga->vram[addr]; - dat[1] = svga->vram[addr | 0x1]; - if (svga->seqregs[1] & 4) - svga->ma += 2; - else - svga->ma += 4; - - svga->ma &= svga->vram_mask; - - p[0] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; - p[1] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; - p[2] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; - p[3] = svga->pallook[svga->egapal[dat[0] & 3]]; - p[4] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; - p[5] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; - p[6] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; - p[7] = svga->pallook[svga->egapal[dat[1] & 3]]; - - p += 8; - } - } - } -} - void svga_render_2bpp_headland_highres(svga_t *svga) { @@ -644,7 +449,7 @@ svga_render_2bpp_headland_highres(svga_t *svga) } void -svga_render_4bpp_lowres(svga_t *svga) +svga_render_4bpp(svga_t *svga, bool highres, bool cga2bpp) { int x; int oddeven; @@ -652,234 +457,112 @@ svga_render_4bpp_lowres(svga_t *svga) uint32_t *p; uint8_t edat[4]; uint8_t dat; - uint32_t changed_addr; + uint32_t changed_offset; - if ((svga->displine + svga->y_add) < 0) - return; - - if (svga->force_old_addr) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { - addr = svga->ma; - oddeven = 0; - - if (!(svga->crtc[0x17] & 0x40)) { - addr = (addr << 1) & svga->vram_mask; - - if (svga->seqregs[1] & 4) - oddeven = (addr & 4) ? 1 : 0; - - addr &= ~7; - - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) - addr |= 4; - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) - addr |= 4; - } - - if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); - if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); - - if (svga->seqregs[1] & 4) { - edat[0] = svga->vram[addr | oddeven]; - edat[2] = svga->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - svga->ma += 2; - } else { - *(uint32_t *) (&edat[0]) = *(uint32_t *) (&svga->vram[addr]); - svga->ma += 4; - } - svga->ma &= svga->vram_mask; - - dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - p[0] = p[1] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[2] = p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - p[4] = p[5] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[6] = p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - p[8] = p[9] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[10] = p[11] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - p[12] = p[13] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[14] = p[15] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - - p += 16; - } - } - } else { - changed_addr = svga->remap_func(svga, svga->ma); - - if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { - addr = svga->remap_func(svga, svga->ma); - oddeven = 0; - - if (svga->seqregs[1] & 4) { - oddeven = (addr & 4) ? 1 : 0; - edat[0] = svga->vram[addr | oddeven]; - edat[2] = svga->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - svga->ma += 2; - } else { - *(uint32_t *) (&edat[0]) = *(uint32_t *) (&svga->vram[addr]); - svga->ma += 4; - } - svga->ma &= svga->vram_mask; - - dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - p[0] = p[1] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[2] = p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - p[4] = p[5] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[6] = p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - p[8] = p[9] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[10] = p[11] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - p[12] = p[13] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[14] = p[15] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - - p += 16; - } - } - } -} - -void -svga_render_4bpp_highres(svga_t *svga) -{ - int changed_offset; - int x; - int oddeven; - uint32_t addr; - uint32_t *p; - uint8_t edat[4]; - uint8_t dat; - uint32_t changed_addr; + const bool blinked = svga->blink & 0x10; + const bool attrblink = ((svga->attrregs[0x10] & 0x08) != 0); + const bool wordmode = ((svga->crtc[0x17] & 0x40) == 0); + const int dwshift = highres ? 0 : 1; + const int dotwidth = 1 << dwshift; + const int charwidth = dotwidth * 8; + const uint8_t blinkmask = (attrblink && blinked ? 0x8 : 0x0); if ((svga->displine + svga->y_add) < 0) return; if (svga->force_old_addr) { changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; - - if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - addr = svga->ma; - oddeven = 0; - - if (!(svga->crtc[0x17] & 0x40)) { - addr = (addr << 1) & svga->vram_mask; - - if (svga->seqregs[1] & 4) - oddeven = (addr & 4) ? 1 : 0; - - addr &= ~7; - - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) - addr |= 4; - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) - addr |= 4; - } - - if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); - if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); - - if (svga->seqregs[1] & 4) { - edat[0] = svga->vram[addr | oddeven]; - edat[2] = svga->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - svga->ma += 2; - } else { - *(uint32_t *) (&edat[0]) = *(uint32_t *) (&svga->vram[addr]); - svga->ma += 4; - } - svga->ma &= svga->vram_mask; - - dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - p[0] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[1] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - p[2] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - p[4] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[5] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - p[6] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - - p += 8; - } - } } else { - changed_addr = svga->remap_func(svga, svga->ma); + changed_offset = svga->remap_func(svga, svga->ma) >> 12; + } - if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; + if (!(svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange)) { + return; + } + p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - addr = svga->remap_func(svga, svga->ma); - oddeven = 0; + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += charwidth) { + oddeven = 0; - if (svga->seqregs[1] & 4) { + if (svga->force_old_addr) { + addr = svga->ma; + + if (wordmode) { + addr = (addr << 1) & svga->vram_mask; + + if (svga->seqregs[1] & 4) oddeven = (addr & 4) ? 1 : 0; - edat[0] = svga->vram[addr | oddeven]; - edat[2] = svga->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - svga->ma += 2; - } else { - *(uint32_t *) (&edat[0]) = *(uint32_t *) (&svga->vram[addr]); - svga->ma += 4; - } - svga->ma &= svga->vram_mask; - dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - p[0] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[1] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - p[2] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - p[4] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[5] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - p[6] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + addr &= ~7; - p += 8; + if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) + addr |= 4; + if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) + addr |= 4; } + + if (!(svga->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + if (!(svga->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + } else { + addr = svga->remap_func(svga, svga->ma); } + + if (svga->seqregs[1] & 4) { + if (!svga->force_old_addr) { + oddeven = (addr & 4) ? 1 : 0; + } + edat[0] = svga->vram[addr | oddeven]; + edat[2] = svga->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + svga->ma += 2; + } else { + *(uint32_t *) (&edat[0]) = *(uint32_t *) (&svga->vram[addr]); + svga->ma += 4; + } + svga->ma &= svga->vram_mask; + + if (cga2bpp) { + // Remap CGA 2bpp-chunky data into fully planar data + uint8_t dat0 = egaremap2bpp[edat[1]] | (egaremap2bpp[edat[0]] << 4); + uint8_t dat1 = egaremap2bpp[edat[1] >> 1] | (egaremap2bpp[edat[0] >> 1] << 4); + uint8_t dat2 = egaremap2bpp[edat[3]] | (egaremap2bpp[edat[2]] << 4); + uint8_t dat3 = egaremap2bpp[edat[3] >> 1] | (egaremap2bpp[edat[2] >> 1] << 4); + edat[0] = dat0; + edat[1] = dat1; + edat[2] = dat2; + edat[3] = dat3; + } + + for (int i = 0; i < 8; i += 2) { + const int outoffs = i << dwshift; + const int inshift = 6 - i; + uint8_t dat = (edatlookup[(edat[0] >> inshift) & 3][(edat[1] >> inshift) & 3]) + | (edatlookup[(edat[2] >> inshift) & 3][(edat[3] >> inshift) & 3] << 2); + // FIXME: Confirm blink behaviour is actually XOR on real hardware + uint32_t p0 = svga->pallook[svga->egapal[((dat >> 4) & svga->plane_mask) ^ blinkmask]]; + uint32_t p1 = svga->pallook[svga->egapal[(dat & svga->plane_mask) ^ blinkmask]]; + for (int subx = 0; subx < dotwidth; subx++) + p[outoffs + subx] = p0; + for (int subx = 0; subx < dotwidth; subx++) + p[outoffs + subx + dotwidth] = p1; + } + + p += charwidth; } } +// Remap these to the 4bpp renderer +void svga_render_2bpp_lowres(svga_t *svga) { svga_render_4bpp(svga, false, true); } +void svga_render_2bpp_highres(svga_t *svga) { svga_render_4bpp(svga, true, true); } +void svga_render_4bpp_lowres(svga_t *svga) { svga_render_4bpp(svga, false, false); } +void svga_render_4bpp_highres(svga_t *svga) { svga_render_4bpp(svga, true, false); } + void svga_render_8bpp_lowres(svga_t *svga) { From cfda3e1cce830b45245a5437e4c6c2a5b079306e Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 15:40:44 +1300 Subject: [PATCH 3/8] Add 8bpp support to the 4bpp renderer (breaks S3 Trio) It appears that the S3 Trio does something weird with its 8bpp modes. Specifically, it seems to ignore some of the flags needed for dword mode. I will keep looking into that and see if I can find a good solution. --- src/video/vid_svga_render.c | 184 ++++++++++++++++++++++++------------ 1 file changed, 124 insertions(+), 60 deletions(-) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index cee321347..79ca2418e 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -449,10 +449,9 @@ svga_render_2bpp_headland_highres(svga_t *svga) } void -svga_render_4bpp(svga_t *svga, bool highres, bool cga2bpp) +svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) { int x; - int oddeven; uint32_t addr; uint32_t *p; uint8_t edat[4]; @@ -461,16 +460,34 @@ svga_render_4bpp(svga_t *svga, bool highres, bool cga2bpp) const bool blinked = svga->blink & 0x10; const bool attrblink = ((svga->attrregs[0x10] & 0x08) != 0); - const bool wordmode = ((svga->crtc[0x17] & 0x40) == 0); + + // FIXME: + // 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. + const bool is_s3 = true; + 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 = (dwordshift ? 2 : wordshift ? 1 : 0); + const uint32_t incevery = (dwordincr ? 4 : wordincr ? 2 : 1); + const uint32_t loadevery = (dwordload ? 4 : wordload ? 2 : 1); + + const bool shift2bit = ((svga->gdcreg[0x05] & 0x60) == 0x20 ); + const bool shift4bit = ((svga->gdcreg[0x05] & 0x40) == 0x40 ); + const int dwshift = highres ? 0 : 1; const int dotwidth = 1 << dwshift; - const int charwidth = dotwidth * 8; + const int charwidth = dotwidth * (combine8bits ? 4 : 8); const uint8_t blinkmask = (attrblink && blinked ? 0x8 : 0x0); if ((svga->displine + svga->y_add) < 0) return; - if (svga->force_old_addr) { + // FIXME look into SVGA remap func to see what we actually need to do here --GM + if (true || svga->force_old_addr) { changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; } else { changed_offset = svga->remap_func(svga, svga->ma) >> 12; @@ -485,84 +502,129 @@ svga_render_4bpp(svga_t *svga, bool highres, bool cga2bpp) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; + uint32_t incr_counter = 0; + uint32_t load_counter = 0; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += charwidth) { - oddeven = 0; + if (load_counter == 0) { + // Find our address + if (true || svga->force_old_addr) { + addr = ((svga->ma & ~0x3) << incbypow2) & svga->vram_display_mask; - if (svga->force_old_addr) { - addr = svga->ma; + if (incbypow2 == 2) { + // Mapping is from the 82C451 datasheet, minus the chip-specific extensions. + // if (svga->ma & (4<<13)) addr |= 0x8; + // if (svga->ma & (4<<12)) addr |= 0x4; + } else if (incbypow2 == 1) { + if ((svga->crtc[0x17] & 0x20)) { + if (svga->ma & (4<<15)) addr |= 0x4; + } else { + if (svga->ma & (4<<13)) addr |= 0x4; + } + } else { + // Nothing + } - if (wordmode) { - addr = (addr << 1) & svga->vram_mask; - - if (svga->seqregs[1] & 4) - oddeven = (addr & 4) ? 1 : 0; - - addr &= ~7; - - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) - addr |= 4; - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) - addr |= 4; + if (!(svga->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + if (!(svga->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + } else { + addr = svga->remap_func(svga, svga->ma); } - if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); - if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + // Load VRAM + *(uint32_t *)&edat[0] = *(uint32_t *)&svga->vram[addr]; + + if (shift4bit) { + // Remap VGA 4bpp-chunky data into fully planar data + // Plane 3 LSbit is aligned with MSbit + uint8_t tmpdat[4] = {0, 0, 0, 0}; + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 8; i++) { + tmpdat[j] <<= 1; + tmpdat[j] |= (edat[i>>1] >> (((0x1&~i)<<2)+j)) & 0x1; + } + } + *(uint32_t *) (&edat[0]) = *(uint32_t *) (&tmpdat[0]); + } + + if (shift2bit) { + // Remap CGA 2bpp-chunky data into fully planar data + uint8_t dat0 = egaremap2bpp[edat[1]] | (egaremap2bpp[edat[0]] << 4); + uint8_t dat1 = egaremap2bpp[edat[1] >> 1] | (egaremap2bpp[edat[0] >> 1] << 4); + uint8_t dat2 = egaremap2bpp[edat[3]] | (egaremap2bpp[edat[2]] << 4); + uint8_t dat3 = egaremap2bpp[edat[3] >> 1] | (egaremap2bpp[edat[2] >> 1] << 4); + edat[0] = dat0; + edat[1] = dat1; + edat[2] = dat2; + edat[3] = dat3; + } } else { - addr = svga->remap_func(svga, svga->ma); + // According to the 82C451 VGA clone chipset datasheet, all 4 planes chain in a ring. + // So, rotate them all around. + *(uint32_t *)&edat[0] + = ((*(uint32_t *)&edat[0]) >> 8) + | ((*(uint32_t *)&edat[0]) << 24); + } + load_counter += 1; + if (load_counter >= loadevery) { + load_counter = 0; } - if (svga->seqregs[1] & 4) { - if (!svga->force_old_addr) { - oddeven = (addr & 4) ? 1 : 0; - } - edat[0] = svga->vram[addr | oddeven]; - edat[2] = svga->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - svga->ma += 2; - } else { - *(uint32_t *) (&edat[0]) = *(uint32_t *) (&svga->vram[addr]); + if (incr_counter == 0) { svga->ma += 4; + // DISCREPANCY TODO FIXME 2/4bpp used vram_mask, 8bpp used vram_display_mask --GM + svga->ma &= svga->vram_display_mask; } - svga->ma &= svga->vram_mask; - - if (cga2bpp) { - // Remap CGA 2bpp-chunky data into fully planar data - uint8_t dat0 = egaremap2bpp[edat[1]] | (egaremap2bpp[edat[0]] << 4); - uint8_t dat1 = egaremap2bpp[edat[1] >> 1] | (egaremap2bpp[edat[0] >> 1] << 4); - uint8_t dat2 = egaremap2bpp[edat[3]] | (egaremap2bpp[edat[2]] << 4); - uint8_t dat3 = egaremap2bpp[edat[3] >> 1] | (egaremap2bpp[edat[2] >> 1] << 4); - edat[0] = dat0; - edat[1] = dat1; - edat[2] = dat2; - edat[3] = dat3; + incr_counter += 1; + if (incr_counter >= incevery) { + incr_counter = 0; } + // + // Now that we've converted it all to planar, convert it (back?) to chunky! + // for (int i = 0; i < 8; i += 2) { - const int outoffs = i << dwshift; const int inshift = 6 - i; - uint8_t dat = (edatlookup[(edat[0] >> inshift) & 3][(edat[1] >> inshift) & 3]) + uint8_t dat + = (edatlookup[(edat[0] >> inshift) & 3][(edat[1] >> inshift) & 3]) | (edatlookup[(edat[2] >> inshift) & 3][(edat[3] >> inshift) & 3] << 2); + // FIXME: Confirm blink behaviour is actually XOR on real hardware - uint32_t p0 = svga->pallook[svga->egapal[((dat >> 4) & svga->plane_mask) ^ blinkmask]]; - uint32_t p1 = svga->pallook[svga->egapal[(dat & svga->plane_mask) ^ blinkmask]]; - for (int subx = 0; subx < dotwidth; subx++) - p[outoffs + subx] = p0; - for (int subx = 0; subx < dotwidth; subx++) - p[outoffs + subx + dotwidth] = p1; + uint32_t c0 = ((dat >> 4) & svga->plane_mask) ^ blinkmask; + uint32_t c1 = (dat & svga->plane_mask) ^ blinkmask; + if (combine8bits) { + uint32_t ccombined = (c0 << 4) | c1; + uint32_t p0 = svga->map8[ccombined]; + const int outoffs = (i >> 1) << dwshift; + for (int subx = 0; subx < dotwidth; subx++) + p[outoffs + subx] = p0; + } else { + uint32_t p0 = svga->pallook[svga->egapal[c0]]; + uint32_t p1 = svga->pallook[svga->egapal[c1]]; + const int outoffs = i << dwshift; + for (int subx = 0; subx < dotwidth; subx++) + p[outoffs + subx] = p0; + for (int subx = 0; subx < dotwidth; subx++) + p[outoffs + subx + dotwidth] = p1; + } } p += charwidth; } } -// Remap these to the 4bpp renderer -void svga_render_2bpp_lowres(svga_t *svga) { svga_render_4bpp(svga, false, true); } -void svga_render_2bpp_highres(svga_t *svga) { svga_render_4bpp(svga, true, true); } -void svga_render_4bpp_lowres(svga_t *svga) { svga_render_4bpp(svga, false, false); } -void svga_render_4bpp_highres(svga_t *svga) { svga_render_4bpp(svga, true, false); } +// Remap these to the paletted renderer +// (*, highres, combine8bits) +void svga_render_2bpp_lowres(svga_t *svga) { svga_render_indexed_gfx(svga, false, false); } +void svga_render_2bpp_highres(svga_t *svga) { svga_render_indexed_gfx(svga, true, false); } +void svga_render_4bpp_lowres(svga_t *svga) { svga_render_indexed_gfx(svga, false, false); } +void svga_render_4bpp_highres(svga_t *svga) { svga_render_indexed_gfx(svga, true, false); } +void svga_render_8bpp_lowres(svga_t *svga) { svga_render_indexed_gfx(svga, false, true); } +void svga_render_8bpp_highres(svga_t *svga) { svga_render_indexed_gfx(svga, true, true); } +// TODO: Integrate more of this into the generic paletted renderer --GM +#if 0 void svga_render_8bpp_lowres(svga_t *svga) { @@ -717,6 +779,8 @@ svga_render_8bpp_highres(svga_t *svga) } } } +#endif + void svga_render_8bpp_tseng_lowres(svga_t *svga) From 2166ae0fb7b6f02d7a2aaccd65d60a7fb8f9099a Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 16:54:45 +1300 Subject: [PATCH 4/8] Get S3 Trio working in mode 13h + Mode-X again Outside of that, we're now using the remappers properly. --- src/include/86box/vid_svga_render.h | 2 ++ src/video/vid_svga_render.c | 23 ++++++++++------------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/include/86box/vid_svga_render.h b/src/include/86box/vid_svga_render.h index 3ad9e401c..8a93b4089 100644 --- a/src/include/86box/vid_svga_render.h +++ b/src/include/86box/vid_svga_render.h @@ -53,6 +53,8 @@ void svga_render_4bpp_lowres(svga_t *svga); void svga_render_4bpp_highres(svga_t *svga); void svga_render_8bpp_lowres(svga_t *svga); void svga_render_8bpp_highres(svga_t *svga); +void svga_render_8bpp_s3_lowres(svga_t *svga); +void svga_render_8bpp_s3_highres(svga_t *svga); void svga_render_8bpp_tseng_lowres(svga_t *svga); void svga_render_8bpp_tseng_highres(svga_t *svga); void svga_render_8bpp_gs_lowres(svga_t *svga); diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index 79ca2418e..afeddef85 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -461,19 +461,18 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) const bool blinked = svga->blink & 0x10; const bool attrblink = ((svga->attrregs[0x10] & 0x08) != 0); - // FIXME: // 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. - const bool is_s3 = true; + // Forcing it to use incbypow2=0, incevery=1, loadevery=1 makes it behave. 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 = (dwordshift ? 2 : wordshift ? 1 : 0); - const uint32_t incevery = (dwordincr ? 4 : wordincr ? 2 : 1); - const uint32_t loadevery = (dwordload ? 4 : wordload ? 2 : 1); + const uint32_t incbypow2 = combine8bits && svga->force_old_addr ? 0 : (dwordshift ? 2 : wordshift ? 1 : 0); + const uint32_t incevery = combine8bits && svga->force_old_addr ? 1 : (dwordincr ? 4 : wordincr ? 2 : 1); + const uint32_t loadevery = combine8bits && svga->force_old_addr ? 1 : (dwordload ? 4 : wordload ? 2 : 1); const bool shift2bit = ((svga->gdcreg[0x05] & 0x60) == 0x20 ); const bool shift4bit = ((svga->gdcreg[0x05] & 0x40) == 0x40 ); @@ -486,8 +485,7 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) if ((svga->displine + svga->y_add) < 0) return; - // FIXME look into SVGA remap func to see what we actually need to do here --GM - if (true || svga->force_old_addr) { + if (svga->force_old_addr) { changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; } else { changed_offset = svga->remap_func(svga, svga->ma) >> 12; @@ -507,13 +505,12 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += charwidth) { if (load_counter == 0) { // Find our address - if (true || svga->force_old_addr) { - addr = ((svga->ma & ~0x3) << incbypow2) & svga->vram_display_mask; + if (svga->force_old_addr) { + addr = ((svga->ma & ~0x3) << incbypow2); if (incbypow2 == 2) { - // Mapping is from the 82C451 datasheet, minus the chip-specific extensions. - // if (svga->ma & (4<<13)) addr |= 0x8; - // if (svga->ma & (4<<12)) addr |= 0x4; + if (svga->ma & (4<<15)) addr |= 0x8; + if (svga->ma & (4<<14)) addr |= 0x4; } else if (incbypow2 == 1) { if ((svga->crtc[0x17] & 0x20)) { if (svga->ma & (4<<15)) addr |= 0x4; @@ -531,6 +528,7 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) } else { addr = svga->remap_func(svga, svga->ma); } + addr &= svga->vram_display_mask; // Load VRAM *(uint32_t *)&edat[0] = *(uint32_t *)&svga->vram[addr]; @@ -781,7 +779,6 @@ svga_render_8bpp_highres(svga_t *svga) } #endif - void svga_render_8bpp_tseng_lowres(svga_t *svga) { From 81b8150a6bc2c427d85481d869a789c2781571cb Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 19:25:26 +1300 Subject: [PATCH 5/8] (S)VGA: Increment CRTC address just before it needs to be used This gives more likely behaviour when one loads more often than the address is incremented. The behaviour matches an Intel GMA 4500MHD (2008) which is the earliest hardware I'm able to test right now. --- src/video/vid_svga_render.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index afeddef85..b9330f4c0 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -569,14 +569,12 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) load_counter = 0; } - if (incr_counter == 0) { - svga->ma += 4; - // DISCREPANCY TODO FIXME 2/4bpp used vram_mask, 8bpp used vram_display_mask --GM - svga->ma &= svga->vram_display_mask; - } incr_counter += 1; if (incr_counter >= incevery) { incr_counter = 0; + svga->ma += 4; + // DISCREPANCY TODO FIXME 2/4bpp used vram_mask, 8bpp used vram_display_mask --GM + svga->ma &= svga->vram_display_mask; } // From 220d5fa237a49f9fbc3226bb1d23900e26c6dda1 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 19:32:43 +1300 Subject: [PATCH 6/8] (S)VGA: Do redraws if blink is enabled in graphics mode too Easy test case in QBASIC: SCREEN 10 PSET (2,0),2 There should be a blinking pixel in the top-left. --- src/video/vid_svga.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index c48baeb6e..b2347f87c 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1001,7 +1001,7 @@ svga_poll(void *priv) else svga->cursoron = svga->blink & (16 + (16 * blink_delay)); - if (!(svga->gdcreg[6] & 1) && !(svga->blink & 15)) + if (!(svga->blink & 15)) svga->fullchange = 2; svga->blink = (svga->blink + 1) & 0x7f; From 9903e12e69b76080e962f2c21e63110d4531ae60 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 19:39:30 +1300 Subject: [PATCH 7/8] (S)VGA: Update graphics mode blink behaviour to match something more feasible --- src/video/vid_svga_render.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index b9330f4c0..0a6be44fa 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -480,7 +480,8 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) const int dwshift = highres ? 0 : 1; const int dotwidth = 1 << dwshift; const int charwidth = dotwidth * (combine8bits ? 4 : 8); - const uint8_t blinkmask = (attrblink && blinked ? 0x8 : 0x0); + const uint8_t blinkmask = (attrblink ? 0x7 : 0xF); + const uint8_t blinkval = (attrblink && blinked ? 0x8 : 0x0); if ((svga->displine + svga->y_add) < 0) return; @@ -586,9 +587,13 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) = (edatlookup[(edat[0] >> inshift) & 3][(edat[1] >> inshift) & 3]) | (edatlookup[(edat[2] >> inshift) & 3][(edat[3] >> inshift) & 3] << 2); - // FIXME: Confirm blink behaviour is actually XOR on real hardware - uint32_t c0 = ((dat >> 4) & svga->plane_mask) ^ blinkmask; - uint32_t c1 = (dat & svga->plane_mask) ^ blinkmask; + // FIXME: Confirm blink behaviour on real hardware + // This is how it behaves on an Intel GMA 4500MHD (2008). + // That includes 8bpp modes. + // However, an AMD Stoney Ridge (2016) seems to ignore blink in 8bpp modes. + + uint32_t c0 = ((dat >> 4) & svga->plane_mask & blinkmask) | blinkval; + uint32_t c1 = (dat & svga->plane_mask & blinkmask) | blinkval; if (combine8bits) { uint32_t ccombined = (c0 << 4) | c1; uint32_t p0 = svga->map8[ccombined]; From 35eb025c50333a612f15d7e4bc0837e3e741c3f9 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 19:40:15 +1300 Subject: [PATCH 8/8] Remove some nonexistent function prototypes I was going to use the existing 8bpp renderers as-is for the S3 stuff but then found out how to make it work on the new generic renderer. --- src/include/86box/vid_svga_render.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/include/86box/vid_svga_render.h b/src/include/86box/vid_svga_render.h index 8a93b4089..3ad9e401c 100644 --- a/src/include/86box/vid_svga_render.h +++ b/src/include/86box/vid_svga_render.h @@ -53,8 +53,6 @@ void svga_render_4bpp_lowres(svga_t *svga); void svga_render_4bpp_highres(svga_t *svga); void svga_render_8bpp_lowres(svga_t *svga); void svga_render_8bpp_highres(svga_t *svga); -void svga_render_8bpp_s3_lowres(svga_t *svga); -void svga_render_8bpp_s3_highres(svga_t *svga); void svga_render_8bpp_tseng_lowres(svga_t *svga); void svga_render_8bpp_tseng_highres(svga_t *svga); void svga_render_8bpp_gs_lowres(svga_t *svga);