Skip to content

Commit

Permalink
Add pitch value to modelist, add code to VESAMOED to set the pitch, a…
Browse files Browse the repository at this point in the history
…dd note about Line Wars II S3 acceleration needing -pitch 1024 -mode 0x203 because of strange assumptions
  • Loading branch information
joncampbell123 committed Jul 16, 2024
1 parent 6ca213c commit e837f5a
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 28 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
NEXT
- INT 10 mode list: Add "pitch" parameter. If nonzero, the value
(in pixels) is how to program the pixels per scanline when
setting the mode.
- VESAMOED: Add -pitch option to control the pitch (pixels per
scanline). The intent is to work around DOS games that assume
nonstandard pixels per scanline by allowing the VESA BIOS mode
to use a different one. For example, Line Wars II has an S3
acceleration mode that uses 800x600, but for whatever reason,
assumes the video mode is 1024 pixels per scanline, and will
render garbled graphics if that is not the case. (joncampbell123).
- S3 emulation: Follow S3 Trio64 documentation and mask the Linear
Window Position bits according to the size of the memory. You
can only place it on a multiple of the memory size. This silences
Expand Down
1 change: 1 addition & 0 deletions src/ints/int10.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ struct VideoModeBlock {
Bitu htotal,vtotal;
Bitu hdispend,vdispend;
Bitu special;
Bitu pitch = 0; /* bytes/scanline to use instead of normal calculation */

};
extern VideoModeBlock ModeList_VGA[];
Expand Down
52 changes: 38 additions & 14 deletions src/ints/int10_modes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1738,29 +1738,34 @@ bool INT10_SetVideoMode(uint16_t mode) {
}

/* Offset Register */
Bitu offset;
Bitu offset,ouwidth = (CurMode->pitch != 0) ? CurMode->pitch : CurMode->swidth;
switch (CurMode->type) {
case M_LIN8:
offset = CurMode->swidth/8;
offset = ouwidth/8;
break;
case M_LIN15:
case M_LIN16:
offset = 2 * CurMode->swidth/8;
offset = 2 * ouwidth/8;
break;
case M_LIN24:
offset = 3 * CurMode->swidth/8;
offset = 3 * ouwidth/8;
break;
case M_LIN32:
offset = 4 * CurMode->swidth/8;
offset = 4 * ouwidth/8;
break;
case M_EGA:
if (IS_EGA_ARCH && vga.mem.memsize < 0x20000 && CurMode->vdispend==350)
if (CurMode->pitch != 0)
offset = ouwidth/(2*8);
else if (IS_EGA_ARCH && vga.mem.memsize < 0x20000 && CurMode->vdispend==350)
offset = CurMode->hdispend/4; /* = 0x14, See EGA BIOS listing for entry 10h 16K mode [https://ibmmuseum.com/Adapters/Video/EGA/IBM_EGA_Manual.pdf] */
else
offset = CurMode->hdispend/2;
break;
default:
offset = CurMode->hdispend/2;
if (CurMode->pitch != 0)
offset = ouwidth/(2*8);
else
offset = CurMode->hdispend/2;
break;
}

Expand Down Expand Up @@ -2265,7 +2270,8 @@ bool INT10_SetVideoMode(uint16_t mode) {
case M_LIN32: reg_50|=S3_XGA_32BPP; break;
default: break;
}
switch(CurMode->swidth) {
unsigned int xgawidth = (CurMode->pitch != 0) ? CurMode->pitch : CurMode->swidth;
switch(xgawidth) {
case 640: reg_50|=S3_XGA_640; break;
case 800: reg_50|=S3_XGA_800; break;
case 1024: reg_50|=S3_XGA_1024; break;
Expand Down Expand Up @@ -2568,12 +2574,19 @@ void INT10_SetJ3ModeCGA4(uint16_t mode)
Bitu INT10_WriteVESAModeList(Bitu max_modes);

/* ====================== VESAMOED.COM ====================== */
/* NOTES:
*
* - Line Wars II: If you use the S3 acceleration mode (800x600)
* use "VESAMOED -mode 0x203 -pitch 1024" to make 800x600 behave
* as the game expects, or else you will get garbled graphics.
*/
class VESAMOED : public Program {
public:
void Run(void) override {
size_t array_i = 0;
std::string arg,tmp;
bool got_opt=false;
int pitch = -1;
int mode = -1;
int fmt = -1;
int w = -1,h = -1;
Expand Down Expand Up @@ -2626,6 +2639,10 @@ class VESAMOED : public Program {
return;
}
}
else if (arg == "pitch") {
cmd->NextOptArgv(/*&*/tmp);
pitch = (int)strtoul(tmp.c_str(),NULL,0);
}
else if (arg == "w") {
cmd->NextOptArgv(/*&*/tmp);
w = (int)strtoul(tmp.c_str(),NULL,0);
Expand Down Expand Up @@ -2740,11 +2757,15 @@ class VESAMOED : public Program {
return;
}

if (!modefind && (w > 0 || h > 0 || fmt >= 0 || ch > 0)) {
if (!modefind && (w > 0 || h > 0 || fmt >= 0 || ch > 0 || pitch >= 0)) {
WriteOut("Changing mode 0x%x parameters\n",(unsigned int)ModeList_VGA[array_i].mode);

ModeList_VGA[array_i].special |= _USER_MODIFIED;

LOG_MSG("pitch %d",pitch);
if (pitch >= 0) {
ModeList_VGA[array_i].pitch = (unsigned int)pitch;
}
if (fmt >= 0) {
ModeList_VGA[array_i].type = (VGAModes)fmt;
/* will require reprogramming width in some cases! */
Expand Down Expand Up @@ -2815,24 +2836,25 @@ class VESAMOED : public Program {
/* if the new mode cannot fit in available memory, then mark as disabled */
{
unsigned int pitch = 0;
unsigned int cwidth = (ModeList_VGA[array_i].pitch != 0) ? ModeList_VGA[array_i].pitch : ModeList_VGA[array_i].swidth;

switch (ModeList_VGA[array_i].type) {
case M_LIN4:
case M_PACKED4:
pitch = (unsigned int)(ModeList_VGA[array_i].swidth / 8) * 4u; /* not totally accurate but close enough */
pitch = (unsigned int)(cwidth / 8) * 4u; /* not totally accurate but close enough */
break;
case M_LIN8:
pitch = (unsigned int)ModeList_VGA[array_i].swidth;
pitch = (unsigned int)cwidth;
break;
case M_LIN15:
case M_LIN16:
pitch = (unsigned int)ModeList_VGA[array_i].swidth * 2u;
pitch = (unsigned int)cwidth * 2u;
break;
case M_LIN24:
pitch = (unsigned int)ModeList_VGA[array_i].swidth * 3u;
pitch = (unsigned int)cwidth * 3u;
break;
case M_LIN32:
pitch = (unsigned int)ModeList_VGA[array_i].swidth * 4u;
pitch = (unsigned int)cwidth * 4u;
break;
default:
break;
Expand Down Expand Up @@ -2867,6 +2889,8 @@ class VESAMOED : public Program {
WriteOut(" -delete Delete video mode\n");
WriteOut(" -disable Disable video mode (list but do not allow setting)\n");
WriteOut(" -enable Enable video mode\n");
WriteOut(" -pitch <x> Change display pitch (pixels per scanline).\n");
WriteOut(" A value of zero will restore normal calculation.\n");
}
};

Expand Down
30 changes: 16 additions & 14 deletions src/ints/int10_vesa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,11 +292,13 @@ uint8_t VESA_GetSVGAModeInformation(uint16_t mode,uint16_t seg,uint16_t off) {
bool allow_res = allow_vesa_lowres_modes ||
(ModeList_VGA[i].swidth >= 640 && ModeList_VGA[i].sheight >= 400);

unsigned int cwidth = (mblock->pitch != 0) ? mblock->pitch : mblock->swidth;

switch (mblock->type) {
case M_PACKED4:
if (!allow_vesa_4bpp_packed && !(ModeList_VGA[i].mode >= 0x202 && ModeList_VGA[i].mode <= 0x208)) return VESA_FAIL;//TODO: New option to disable
pageSize = mblock->sheight * mblock->swidth/2;
var_write(&minfo.BytesPerScanLine,(uint16_t)((((mblock->swidth+15U)/8U)&(~1U))*4)); /* NTS: 4bpp requires even value due to VGA registers, round up */
pageSize = mblock->sheight * cwidth/2;
var_write(&minfo.BytesPerScanLine,(uint16_t)((((cwidth+15U)/8U)&(~1U))*4)); /* NTS: 4bpp requires even value due to VGA registers, round up */
if (!int10.vesa_oldvbe10) { /* optional in VBE 1.0 */
var_write(&minfo.NumberOfPlanes,0x1);
var_write(&minfo.BitsPerPixel,4);
Expand All @@ -307,8 +309,8 @@ uint8_t VESA_GetSVGAModeInformation(uint16_t mode,uint16_t seg,uint16_t off) {
break;
case M_LIN4:
if (!allow_vesa_4bpp) return VESA_FAIL;
pageSize = mblock->sheight * (uint16_t)(((mblock->swidth+15U)/8U)&(~1U));
var_write(&minfo.BytesPerScanLine,(uint16_t)(((mblock->swidth+15U)/8U)&(~1U))); /* NTS: 4bpp requires even value due to VGA registers, round up */
pageSize = mblock->sheight * (uint16_t)(((cwidth+15U)/8U)&(~1U));
var_write(&minfo.BytesPerScanLine,(uint16_t)(((cwidth+15U)/8U)&(~1U))); /* NTS: 4bpp requires even value due to VGA registers, round up */
if (!int10.vesa_oldvbe10) { /* optional in VBE 1.0 */
var_write(&minfo.NumberOfPlanes,0x4);
var_write(&minfo.BitsPerPixel,4); // bits per pixel is 4 as specified by VESA BIOS 2.0 specification
Expand All @@ -318,8 +320,8 @@ uint8_t VESA_GetSVGAModeInformation(uint16_t mode,uint16_t seg,uint16_t off) {
break;
case M_LIN8:
if (!allow_vesa_8bpp || !allow_res) return VESA_FAIL;
pageSize = mblock->sheight * mblock->swidth;
var_write(&minfo.BytesPerScanLine,(uint16_t)mblock->swidth);
pageSize = mblock->sheight * cwidth;
var_write(&minfo.BytesPerScanLine,(uint16_t)cwidth);
if (!int10.vesa_oldvbe10) { /* optional in VBE 1.0 */
var_write(&minfo.NumberOfPlanes,0x1);
var_write(&minfo.BitsPerPixel,8);
Expand All @@ -330,8 +332,8 @@ uint8_t VESA_GetSVGAModeInformation(uint16_t mode,uint16_t seg,uint16_t off) {
break;
case M_LIN15:
if (!allow_vesa_15bpp || !allow_res) return VESA_FAIL;
pageSize = mblock->sheight * mblock->swidth*2;
var_write(&minfo.BytesPerScanLine,(uint16_t)(mblock->swidth*2));
pageSize = mblock->sheight * cwidth*2;
var_write(&minfo.BytesPerScanLine,(uint16_t)(cwidth*2));
if (!int10.vesa_oldvbe10) { /* optional in VBE 1.0 */
var_write(&minfo.NumberOfPlanes,0x1);
var_write(&minfo.BitsPerPixel,15);
Expand All @@ -350,8 +352,8 @@ uint8_t VESA_GetSVGAModeInformation(uint16_t mode,uint16_t seg,uint16_t off) {
break;
case M_LIN16:
if (!allow_vesa_16bpp || !allow_res) return VESA_FAIL;
pageSize = mblock->sheight * mblock->swidth*2;
var_write(&minfo.BytesPerScanLine,(uint16_t)(mblock->swidth*2));
pageSize = mblock->sheight * cwidth*2;
var_write(&minfo.BytesPerScanLine,(uint16_t)(cwidth*2));
if (!int10.vesa_oldvbe10) { /* optional in VBE 1.0 */
var_write(&minfo.NumberOfPlanes,0x1);
var_write(&minfo.BitsPerPixel,16);
Expand All @@ -369,8 +371,8 @@ uint8_t VESA_GetSVGAModeInformation(uint16_t mode,uint16_t seg,uint16_t off) {
case M_LIN24:
if (!allow_vesa_24bpp || !allow_res) return VESA_FAIL;
if (mode >= 0x120 && !allow_explicit_vesa_24bpp) return VESA_FAIL;
pageSize = mblock->sheight * mblock->swidth*3;
var_write(&minfo.BytesPerScanLine,(uint16_t)(mblock->swidth*3));
pageSize = mblock->sheight * cwidth*3;
var_write(&minfo.BytesPerScanLine,(uint16_t)(cwidth*3));
if (!int10.vesa_oldvbe10) { /* optional in VBE 1.0 */
var_write(&minfo.NumberOfPlanes,0x1);
var_write(&minfo.BitsPerPixel,24);
Expand All @@ -387,8 +389,8 @@ uint8_t VESA_GetSVGAModeInformation(uint16_t mode,uint16_t seg,uint16_t off) {
break;
case M_LIN32:
if (!allow_vesa_32bpp || !allow_res) return VESA_FAIL;
pageSize = mblock->sheight * mblock->swidth*4;
var_write(&minfo.BytesPerScanLine,(uint16_t)(mblock->swidth*4));
pageSize = mblock->sheight * cwidth*4;
var_write(&minfo.BytesPerScanLine,(uint16_t)(cwidth*4));
if (!int10.vesa_oldvbe10) { /* optional in VBE 1.0 */
var_write(&minfo.NumberOfPlanes,0x1);
var_write(&minfo.BitsPerPixel,32);
Expand Down

0 comments on commit e837f5a

Please sign in to comment.