From d5104c622f16c6da2ae72d63a6ca73d9eef9b367 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Thu, 12 Sep 2019 23:04:15 -0400 Subject: [PATCH 1/2] Use faster method to write to VGA --- sys/msdos/portio.h | 4 ++ sys/msdos/vidvga.c | 113 +++++++++++++++++++++++---------------------- 2 files changed, 63 insertions(+), 54 deletions(-) diff --git a/sys/msdos/portio.h b/sys/msdos/portio.h index c069cc28c..97e023b6e 100644 --- a/sys/msdos/portio.h +++ b/sys/msdos/portio.h @@ -44,6 +44,7 @@ #define READ_ABSOLUTE_WORD(x) *(x) #define WRITE_ABSOLUTE(x, y) *(x) = (y) #define WRITE_ABSOLUTE_WORD(x, y) *(x) = (y) +#define WRITE_ABSOLUTE_DWORD(x, y) *(x) = (y) #endif #if defined(__GO32__) || defined(__DJGPP__) @@ -57,6 +58,8 @@ _farpokeb(_go32_conventional_mem_selector(), (unsigned) x, (y)) #define WRITE_ABSOLUTE_WORD(x, y) \ _farpokew(_go32_conventional_mem_selector(), (unsigned) x, (y)) +#define WRITE_ABSOLUTE_DWORD(x, y) \ + _farpokel(_go32_conventional_mem_selector(), (unsigned) x, (y)) #endif #ifdef OBSOLETE /* old djgpp V1.x way of mapping 1st MB */ @@ -66,6 +69,7 @@ #define READ_ABSOLUTE_WORD(x) *(x) #define WRITE_ABSOLUTE(x, y) *(x) = (y) #define WRITE_ABSOLUTE_WORD(x, y) *(x) = (y) +#define WRITE_ABSOLUTE_DWORD(x, y) *(x) = (y) #endif #endif /* MK_PTR */ diff --git a/sys/msdos/vidvga.c b/sys/msdos/vidvga.c index 4e8a18206..a91d0e08b 100644 --- a/sys/msdos/vidvga.c +++ b/sys/msdos/vidvga.c @@ -231,25 +231,20 @@ void vga_clear_screen(colour) int colour; { - char __far *pch; - int y, j; - char volatile a; + unsigned long __far *pch; + unsigned j; - outportb(0x3ce, 5); - outportb(0x3cf, 2); - - for (y = 0; y < SCREENHEIGHT; ++y) { - pch = screentable[y]; - for (j = 0; j < SCREENBYTES; ++j) { - outportb(0x3ce, 8); - outportb(0x3cf, 255); - a = READ_ABSOLUTE(pch); /* Must read , then write */ - WRITE_ABSOLUTE(pch, (char) colour); - ++pch; - } + egawriteplane(colour); + pch = (unsigned long __far *) screentable[0]; + for (j = 0; j < SCREENHEIGHT * SCREENBYTES / 4; ++j) { + WRITE_ABSOLUTE_DWORD(&pch[j], 0xFFFFFFFF); } - outportb(0x3ce, 5); - outportb(0x3cf, 0); + egawriteplane(~colour); + pch = (unsigned long __far *) screentable[0]; + for (j = 0; j < SCREENHEIGHT * SCREENBYTES / 4; ++j) { + WRITE_ABSOLUTE_DWORD(&pch[j], 0x00000000); + } + egawriteplane(15); if (iflags.tile_view) vga_clearmap(); vga_gotoloc(0, 0); /* is this needed? */ @@ -459,28 +454,22 @@ STATIC_OVL void vga_redrawmap(clearfirst) boolean clearfirst; { - int j, x, y, t; - char __far *pch; - char volatile a; + int x, y, t; + unsigned long __far *pch; if (clearfirst) { - /* y here is in pixel rows */ - outportb(0x3ce, 5); - outportb(0x3cf, 2); + unsigned j; t = TOP_MAP_ROW * ROWS_PER_CELL; - for (y = t; y < (ROWNO * ROWS_PER_CELL) + t; ++y) { - pch = screentable[y]; - for (j = 0; j < SCREENBYTES; ++j) { - outportb(0x3ce, 8); - outportb(0x3cf, 255); - /* On VGA mode2, must read first, then write */ - a = READ_ABSOLUTE(pch); - WRITE_ABSOLUTE(pch, (char) BACKGROUND_VGA_COLOR); - ++pch; - } + pch = (unsigned long __far *) screentable[t]; + egawriteplane(BACKGROUND_VGA_COLOR); + for (j = 0; j < ROWNO * ROWS_PER_CELL * SCREENBYTES / 4; ++j) { + WRITE_ABSOLUTE_DWORD(&pch[j], 0xFFFFFFFF); } - outportb(0x3ce, 5); - outportb(0x3cf, 0); + egawriteplane(~BACKGROUND_VGA_COLOR); + for (j = 0; j < ROWNO * ROWS_PER_CELL * SCREENBYTES / 4; ++j) { + WRITE_ABSOLUTE_DWORD(&pch[j], 0x00000000); + } + egawriteplane(15); } /* y here is in screen rows*/ #ifdef ROW_BY_ROW @@ -941,36 +930,52 @@ int chr, col, row, colour; int i; int x, pixy; - char volatile tc; char __far *cp; unsigned char __far *fp = font; unsigned char fnt; int actual_colour = vgacmap[colour]; + int vplane; x = min(col, (CO - 1)); /* min() used protection from callers */ pixy = min(row, (LI - 1)) * 16; /* assumes 8 x 16 char set */ /* if (chr < ' ') chr = ' '; */ /* assumes ASCII set */ - outportb(0x3ce, 5); - outportb(0x3cf, 2); - chr = chr << 4; - for (i = 0; i < MAX_ROWS_PER_CELL; ++i) { - cp = screentable[pixy + i] + x; - fnt = READ_ABSOLUTE((fp + chr + i)); - outportb(0x3ce, 8); - outportb(0x3cf, fnt); - tc = READ_ABSOLUTE(cp); /* wrt mode 2, must read, then write */ - WRITE_ABSOLUTE(cp, (char) actual_colour); - outportb(0x3ce, 8); - outportb(0x3cf, ~fnt); - tc = READ_ABSOLUTE(cp); /* wrt mode 2, must read, then write */ - WRITE_ABSOLUTE(cp, (char) BACKGROUND_VGA_COLOR); + vplane = ~actual_colour & ~BACKGROUND_VGA_COLOR & 0xF; + if (vplane != 0) { + egawriteplane(vplane); + for (i = 0; i < MAX_ROWS_PER_CELL; ++i) { + cp = screentable[pixy + i] + x; + WRITE_ABSOLUTE(cp, (char) 0x00); + } } - outportb(0x3ce, 5); - outportb(0x3cf, 0); - outportb(0x3ce, 8); - outportb(0x3cf, 255); + vplane = actual_colour & ~BACKGROUND_VGA_COLOR & 0xF; + if (vplane != 0) { + egawriteplane(vplane); + for (i = 0; i < MAX_ROWS_PER_CELL; ++i) { + cp = screentable[pixy + i] + x; + fnt = READ_ABSOLUTE((fp + chr + i)); + WRITE_ABSOLUTE(cp, (char) fnt); + } + } + vplane = ~actual_colour & BACKGROUND_VGA_COLOR & 0xF; + if (vplane != 0) { + egawriteplane(vplane); + for (i = 0; i < MAX_ROWS_PER_CELL; ++i) { + cp = screentable[pixy + i] + x; + fnt = ~READ_ABSOLUTE((fp + chr + i)); + WRITE_ABSOLUTE(cp, (char) fnt); + } + } + vplane = actual_colour & BACKGROUND_VGA_COLOR & 0xF; + if (vplane != 0) { + egawriteplane(vplane); + for (i = 0; i < MAX_ROWS_PER_CELL; ++i) { + cp = screentable[pixy + i] + x; + WRITE_ABSOLUTE(cp, (char) 0xFF); + } + } + egawriteplane(15); } /* From 2a66ce54ad83f897ce8722fd1a16207459b037dd Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 13 Sep 2019 00:38:04 -0400 Subject: [PATCH 2/2] use faster method to write characters to VGA in msdos port chasonr's comments in github pull request #220: It was necessary, when updating the MS-DOS port for 3.6, to revise the screen-clearing and character-drawing functions, because the background color is no longer zero. But the 3.6.1 method is rather slow, using write mode 2 and a lot more calls to outportb. outportb is expensive when running under a virtual machine, the typical use case for the MS-DOS port these days, because it traps to the hypervisor rather than actually writing to hardware. This change restores the speed of the 3.4.3 version. The adapter is left in write mode 0. Clearing is accomplished by writing zero to planes where the background color has a zero bit, and 0xFF where the background color has a one bit. Characters are drawn by writing 0x00, 0xFF, the font data, or the inverse of the font data, as appropriate, to each plane. When testing, be sure to use OPTIONS=videomode:vga, because autodetect will go to VESA mode if it can. closes #220 --- doc/fixes36.3 | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/fixes36.3 b/doc/fixes36.3 index 734272ffa..f00cc3e29 100644 --- a/doc/fixes36.3 +++ b/doc/fixes36.3 @@ -294,6 +294,7 @@ curses+'perm_invent': since persistent inventory is narrow, strip off "a", NetHack Community Patches (or Variation) Included ------------------------------------------------- add a couple of engraving suggestions in pull request #79 +chasonr's faster method to write characters to msdos VGA in pull request #220 Code Cleanup and Reorganization