VOGONS


First post, by laserallan

User metadata
Rank Newbie
Rank
Newbie

Hi,

I'm doing some programming for VGA cards on msdos machines using unchained VGA modes (mode-x or mode-y depending on how much of a stickler you are).
I noticed that in dosbox and dosbox-x that:
* When addressing outside of the virtual screen in the x-direction it starts fetching pixels from the next row.
* When addressing outside of the virtual screen in the y-direction it wraps around to the top.
My question is how reliable this behavior is across different graphics cards. I can imagine cards with more than 256k memory might be showing data from what's beyond 256k rather than wrapping.
Anyone have any practical experience with this?

My goal is to be able do double rendering with hardware scrolling so I only need to fill in the new pixels for my window when scrolling and having the wrap around behavior would make my life much easier but I want this to work on a wide range of graphics cards.

Reply 1 of 19, by mkarcher

User metadata
Rank l33t
Rank
l33t
laserallan wrote on 2023-05-03, 17:34:
I'm doing some programming for VGA cards on msdos machines using unchained VGA modes (mode-x or mode-y depending on how much of […]
Show full quote

I'm doing some programming for VGA cards on msdos machines using unchained VGA modes (mode-x or mode-y depending on how much of a stickler you are).
I noticed that in dosbox and dosbox-x that:
* When addressing outside of the virtual screen in the x-direction it starts fetching pixels from the next row.
* When addressing outside of the virtual screen in the y-direction it wraps around to the top.
My question is how reliable this behavior is across different graphics cards. I can imagine cards with more than 256k memory might be showing data from what's beyond 256k rather than wrapping.
Anyone have any practical experience with this?

My goal is to be able do double rendering with hardware scrolling so I only need to fill in the new pixels for my window when scrolling and having the wrap around behavior would make my life much easier but I want this to work on a wide range of graphics cards.

That strategy works perfectly. That's exactly the "magic scrolling technique ID software invented for Commander Keen", IIRC they called it "adaptive tile refresh".

VGA cards with more than 256 KBytes generally have some "super vga enable" bit in the chipset. As long as this bit is clear, you definitely get wrap-around at 256KB.

Reply 2 of 19, by Jo22

User metadata
Rank l33t++
Rank
l33t++

The Commander Keen series uses EGA, if memory serves.
One of the features it uses is dual-page mode, I believe.

ISA VGA's do also have an EGA emulation mode that can be set via mode utility.
In theory, it should make the VGA card behave like an EGA card with full memory expansion (256KB).

So instead of making the Super VGA part compatible with plain IBM VGA,
some could enable the EGA compatibility built into silicon.

"Time, it seems, doesn't flow. For some it's fast, for some it's slow.
In what to one race is no time at all, another race can rise and fall..." - The Minstrel

//My video channel//

Reply 3 of 19, by mkarcher

User metadata
Rank l33t
Rank
l33t
Jo22 wrote on 2023-05-04, 19:11:

The Commander Keen series uses EGA, if memory serves.

That's true. Memory addressing works exactly the same on EGA and VGA, though, so it doesn't matter whether we talk about "EGA" or "VGA" here. VGA adds some modes (like the chain-4 host address mode and the double-word granularity graphics CRTC address mode), but that's just some incremental improvements. The wrap-around at 256K is the same on EGA and VGA.

Jo22 wrote on 2023-05-04, 19:11:

One of the features it uses is dual-page mode, I believe.

It's not just dual-page. In 320x200 mode with 16 colors, EGA with full memory (256KB) provide 8 pages. But you don't have to limit yourself to "8 pages": You can tell the EGA card to start displaying at any point in video memory. And you can tell the EGA card to skip any amount of memory per line displayed. This basically means you can arrange the 524288 pixels in nearly any shape, e.g. 1280 x 400 (four pages wide and two pages high) or 640x800 (two pages wide and 4 pages high), and display any 320x200 area inside that frame. This is how games like Crystal Caves provided the big full-screen scrolling levels.

Commander Keen goes one step further allowing theoretically infinite level sizes by scrolling "over the edge" if needed and drawing only the pixels that get newly scrolled into the view. That's what the OP had in mind.

Jo22 wrote on 2023-05-04, 19:11:

ISA VGA's do also have an EGA emulation mode that can be set via mode utility.
In theory, it should make the VGA card behave like an EGA card with full memory expansion (256KB).

For the memory access options, you don't even need an EGA emulation mode. All VGA and SuperVGA cards are EGA compatible in standard EGA/VGA BIOS modes regarding how memory is addressed. Enabling EGA compatibilty will make all VGA-specific features unavailable, including the 256 color mode the OP wants to use, though.

Reply 5 of 19, by keenmaster486

User metadata
Rank l33t
Rank
l33t

Here is some of the Commander Keen EGA scrolling code, for reference.

Seems to me like the theoretical maximum size of the level is that of an unsigned integer, 65535 pixels wide.

You can also see here the code used for certain Super VGA cards that don't have the memory wrap around feature to maintain compatibility with EGA ("SVGA Compatibility Mode").

Keep in mind this is all in EGA.

I didn't think VGA had the "panning" features that EGA does? I'm actually not sure how that works - is it a value you change that points to the beginning of the "screen" in the video memory?

#if GRMODE == EGAGR

/*
=====================
=
= RF_NewPosition EGA
=
=====================
*/

void RF_NewPosition (unsigned x, unsigned y)
{
int mx,my;
byte *page0ptr,*page1ptr;
unsigned updatenum;

RFL_BoundNewOrigin (x,y);
//
// clear out all animating tiles
//
RFL_InitAnimList ();

//
// set up the new update arrays at base position
//
updatestart[0] = baseupdatestart[0];
updatestart[1] = baseupdatestart[1];
updateptr = updatestart[otherpage];

page0ptr = updatestart[0]+PORTTILESWIDE; // used to stick "0"s after rows
page1ptr = updatestart[1]+PORTTILESWIDE;

updatenum = 0; // start at first visable tile

for (my=0;my<PORTTILESHIGH;my++)
{
for (mx=0;mx<PORTTILESWIDE;mx++)
{
RFL_NewTile(updatenum); // puts "1"s in both pages
RFL_CheckForAnimTile(mx+originxtile,my+originytile);
updatenum++;
}
updatenum++;
*page0ptr = *page1ptr = 0; // set a 0 at end of a line of tiles
page0ptr+=(PORTTILESWIDE+1);
page1ptr+=(PORTTILESWIDE+1);
}
*(word *)(page0ptr-PORTTILESWIDE)
= *(word *)(page1ptr-PORTTILESWIDE) = UPDATETERMINATE;
}

//===========================================================================


/*
=====================
=
= RF_Scroll EGA
=
= Move the origin x/y global coordinates, readjust the screen panning, and
Show last 143 lines
= scroll if needed.  If the scroll distance is greater than one tile, the
= entire screen will be redrawn (this could be generalized, but scrolling
= more than one tile per refresh is a bad idea!).
=
=====================
*/

void RF_Scroll (int x, int y)
{
long neworgx,neworgy;
int i,deltax,deltay,absdx,absdy;
int oldxt,oldyt,move,yy;
unsigned updatespot;
byte *update0,*update1;
unsigned oldpanx,oldpanadjust,oldscreen,newscreen,screencopy;
int screenmove;

oldxt = originxtile;
oldyt = originytile;
oldpanadjust = panadjust;
oldpanx = panx;

RFL_BoundScroll (x,y);

deltax = originxtile - oldxt;
absdx = abs(deltax);
deltay = originytile - oldyt;
absdy = abs(deltay);

if (absdx>1 || absdy>1)
{
//
// scrolled more than one tile, so start from scratch
//
RF_NewPosition(originxglobal,originyglobal);
return;
}

if (!absdx && !absdy)
return; // the screen has not scrolled an entire tile


//
// adjust screens and handle SVGA crippled compatability mode
//
screenmove = deltay*16*SCREENWIDTH + deltax*TILEWIDTH;
for (i=0;i<3;i++)
{
screenstart[i]+= screenmove;
if (compatability && screenstart[i] > (0x10000l-SCREENSPACE) )
{
//
// move the screen to the opposite end of the buffer
//
screencopy = screenmove>0 ? FREEEGAMEM : -FREEEGAMEM;
oldscreen = screenstart[i] - screenmove;
newscreen = oldscreen + screencopy;
screenstart[i] = newscreen + screenmove;
VW_ScreenToScreen (oldscreen,newscreen,
PORTTILESWIDE*2,PORTTILESHIGH*16);

if (i==screenpage)
VW_SetScreen(newscreen+oldpanadjust,oldpanx & xpanmask);
}
}
bufferofs = screenstart[otherpage];
displayofs = screenstart[screenpage];
masterofs = screenstart[2];


//
// float the update regions
//
move = deltax;
if (deltay==1)
move += UPDATEWIDE;
else if (deltay==-1)
move -= UPDATEWIDE;

updatestart[0]+=move;
updatestart[1]+=move;

//
// draw the new tiles just scrolled on to the master screen, and
// mark them as needing to be copied to each screen next refreshes
// Make sure a zero is at the end of each row in update
//

if (deltax)
{
if (deltax==1)
{
RFL_NewRow (1); // new right row
RFL_RemoveAnimsOnX (originxtile-1);
}
else
{
RFL_NewRow (3); // new left row
RFL_RemoveAnimsOnX (originxtile+PORTTILESWIDE);
}

update0 = updatestart[0]+PORTTILESWIDE;
update1 = updatestart[1]+PORTTILESWIDE;
for (yy=0;yy<PORTTILESHIGH;yy++)
{
*update0 = *update1 = 0; // drop a 0 at end of each row
update0+=UPDATEWIDE;
update1+=UPDATEWIDE;
}
}

//----------------

if (deltay)
{
if (deltay==1)
{
updatespot = UPDATEWIDE*(PORTTILESHIGH-1);
RFL_NewRow (2); // new bottom row
RFL_RemoveAnimsOnY (originytile-1);
}
else
{
updatespot = 0;
RFL_NewRow (0); // new top row
RFL_RemoveAnimsOnY (originytile+PORTTILESHIGH);
}

*(updatestart[0]+updatespot+PORTTILESWIDE) =
*(updatestart[1]+updatespot+PORTTILESWIDE) = 0;
}

//----------------

//
// place a new terminator
//
update0 = updatestart[0]+UPDATEWIDE*PORTTILESHIGH-1;
update1 = updatestart[1]+UPDATEWIDE*PORTTILESHIGH-1;
*update0++ = *update1++ = 0;
*(unsigned *)update0 = *(unsigned *)update1 = UPDATETERMINATE;
}

World's foremost 486 enjoyer.

Reply 6 of 19, by mkarcher

User metadata
Rank l33t
Rank
l33t
keenmaster486 wrote on 2023-05-06, 05:40:

You can also see here the code used for certain Super VGA cards that don't have the memory wrap around feature to maintain compatibility with EGA ("SVGA Compatibility Mode").

Which is exactly what the OP was concerned about. Do you know what cards require SVGA compatibility to be enabled?

keenmaster486 wrote on 2023-05-06, 05:40:

Keep in mind this is all in EGA.

I didn't think VGA had the "panning" features that EGA does? I'm actually not sure how that works - is it a value you change that points to the beginning of the "screen" in the video memory?

No, the panning is not the start address (you had that one already on MDA and CGA), but panning is used for fine adjustment. The EGA (and VGA) card fetch 32 bits from video memory at once. In 16 color modes, those 32 bits contain 8 pixels. Changing the start address will select which pack of 8 pixels will be loaded for the pixels at the top left edge. The "panning" register selects how many pixels of the first pack of pixels will be skipped at the start of a scan line, to allow setting every pixel as first pixel, and not just every memory address.

Reply 7 of 19, by VileR

User metadata
Rank l33t
Rank
l33t
keenmaster486 wrote on 2023-05-06, 05:40:

I didn't think VGA had the "panning" features that EGA does? I'm actually not sure how that works - is it a value you change that points to the beginning of the "screen" in the video memory?

When scrolling vertically that's pretty much how it works, yes: you set the start address for the displayed 'window' in CRTC registers 0Ch + 0Dh. Horizontally however, this only lets you scroll in 1-byte increments - since a byte can be up to 8 pixels in graphics modes, there is an additional setting (Attribute Controller register 13h- "Pel Panning" in IBM speak) to control the pixel offset within that byte.

Panning works the same way in EGA and VGA, modulo some quirks such as how split-screen operation is affected.

[ WEB ] - [ BLOG ] - [ TUBE ] - [ CODE ]

Reply 8 of 19, by mkarcher

User metadata
Rank l33t
Rank
l33t
VileR wrote on 2023-05-06, 08:15:

Panning works the same way in EGA and VGA, modulo some quirks such as how split-screen operation is affected.

Panning in split-screen is operating in a way on EGA that was considered quirky in practice, so they added extra logic to get more useful behaviour on VGA. Note that panning and split-screen by themselves work fine on EGA, it's just the use of both features at the same time that behaves in a way undesireable in most use cases. IBM made sure to keep compatibility, though: VGA has a bit to select "sane VGA behaviour" or "classic EGA behaviour", which defaults to "classic EGA".

The remainder of this post is not addressed to VileR's remark, but mainly meant to dispel concerns raised by Jo22 and keenmaster486 that EGA compatibility modes might be required for getting "standard scrolling behaviour" on SVGA cards. In my experience, EGA register emulation is not required for these use cases.

So even this quirk is not a reason to switch a VGA card into EGA emulation mode to be properly EGA compatible. VGA cards in VGA mode are properly EGA compatible without emulation, unless you try to modify video timings. So you might need EGA compatibility mode if software sets a video mode without using INT 10, or if it tweaks modes too much. EGA software doing such tweaks is quite rare, because the 640x350 mode was already pushing the IBM ECD (EGA monitor) to its limits, so there isn't much to gain by tweaking.

When talking about soft-scrolling and panning in 16-color modes, all EGA code will work perfectly on VGA, too. In 256-color modes (VGA only), you need to remember that 256-color pixels are internally treated as a pair two 16-color pixels, so you need to adjust panning in increments of two 16-color pixels to achieve scrolling in single 256-color pixels. This is because EGA and VGA behave the same (internal pixel size is 4 bits), not because EGA and VGA are different.

Reply 9 of 19, by VileR

User metadata
Rank l33t
Rank
l33t

Exactly - good rundown. The only practical issue isn't related to programming differences between the EGA and VGA, but to the vertical refresh rate: the same modes that operate at 60Hz on EGA are 70Hz on VGA. So if your code targets one of them, the other one will either show tearing or incorrect timing. (IIRC it was established that Keen was actually developed on VGA hardware, and reportedly the scrolling on EGA isn't perfect due to this difference.)

Of course, that's something that EGA 'compatibility'/'emulation' modes aren't going to fix. Unless we're talking about VGA cards with an additional digital RGBI output, like the Eagle II, but as long as you're using a VGA monitor you'll get 70Hz.

[ WEB ] - [ BLOG ] - [ TUBE ] - [ CODE ]

Reply 10 of 19, by mkarcher

User metadata
Rank l33t
Rank
l33t
VileR wrote on 2023-05-06, 20:47:

Of course, that's something that EGA 'compatibility'/'emulation' modes aren't going to fix. Unless we're talking about VGA cards with an additional digital RGBI output, like the Eagle II, but as long as you're using a VGA monitor you'll get 70Hz.

Likely you do, but I there might be VGA cards that run at 60Hz VSYNC if you set them to EGA emulation. Typical VGA monitors lock on any VSYNC between 58 and 72 Hz, independent of sync polarity. VGA monitors are required to sync on 60 Hz in 480 line mode, but the VGA monitors I tested (not a representative amount of them, I admit) also synced fine to 60Hz in 400 line mode and 350 line mode.

Reply 11 of 19, by Scali

User metadata
Rank l33t
Rank
l33t

'Pixel panning' is what we call 'hardware scrolling' on Commodore 64 and similar platforms.
Basically it is shifting/offsetting the screen at one-pixel increments inside a byte/word, so it enables perfect per-pixel scrolling horizontally.

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 12 of 19, by BitWrangler

User metadata
Rank l33t++
Rank
l33t++

Some SVGA windows drivers on some cards, think it's just 98SE and XP can do a pan mode, where if you have a 800x600 monitor say and enough video RAM for a 1024x768 screen/desktop, you can set desktop to that, monitor to lower res and pan with mouse held at edge. Some 90s-00s era linux windows managers supported it too for XFree86. But I guess that doesn't tell you if it's built into lowest VGA standards. It irks me that the feature isn't more common to later windows versions too, as sometimes I would like to clone a desktop to a lower res monitor, either locally or remote.

Unicorn herding operations are proceeding, but all the totes of hens teeth and barrels of rocking horse poop give them plenty of hiding spots.

Reply 13 of 19, by mkarcher

User metadata
Rank l33t
Rank
l33t
BitWrangler wrote on 2023-05-06, 23:01:

But I guess that doesn't tell you if it's built into lowest VGA standards.

The hardware required for smooth panning aka virtual desktops is available since EGA. The main question of this thread is whether all SuperVGA cards limit the pannable area to 256KB video RAM when in standard VGA modes, or you can accidentally overrun into "extended video RAM" by setting a start position at a point sufficiently far into video memory. Most SVGA cards prevent this overrun and wrap back to the start (somehow a similar concept to a closed A20 gate for main RAM), but Commander Keen (which I cited as example that requires the wrap-around) has a special mode that sacrifices some performance to avoid the situation in which wrapping is a relevant. This mode is called "SVGA compatibilty".

While it is known that Commander Keen has some issues with jerky scrolling on some SVGA cards, these issues relate to the timing of register updates, and unconnected to the wrap-around. Missing wrap-around would cause the low part of the screen starting to flicker, displaying garbage every second screen in some game situations. I'm still curious whether SVGA compatiblity mode was added because some early SVGA cards really needed it, or because the authors were afraid that some card might need it.

Reply 14 of 19, by keenmaster486

User metadata
Rank l33t
Rank
l33t
mkarcher wrote on 2023-05-06, 07:52:

No, the panning is not the start address (you had that one already on MDA and CGA), but panning is used for fine adjustment. The EGA (and VGA) card fetch 32 bits from video memory at once. In 16 color modes, those 32 bits contain 8 pixels. Changing the start address will select which pack of 8 pixels will be loaded for the pixels at the top left edge. The "panning" register selects how many pixels of the first pack of pixels will be skipped at the start of a scan line, to allow setting every pixel as first pixel, and not just every memory address.

VileR wrote on 2023-05-06, 08:15:

When scrolling vertically that's pretty much how it works, yes: you set the start address for the displayed 'window' in CRTC registers 0Ch + 0Dh. Horizontally however, this only lets you scroll in 1-byte increments - since a byte can be up to 8 pixels in graphics modes, there is an additional setting (Attribute Controller register 13h- "Pel Panning" in IBM speak) to control the pixel offset within that byte.

mkarcher wrote on 2023-05-06, 08:45:

So even this quirk is not a reason to switch a VGA card into EGA emulation mode to be properly EGA compatible. VGA cards in VGA mode are properly EGA compatible without emulation, unless you try to modify video timings. So you might need EGA compatibility mode if software sets a video mode without using INT 10, or if it tweaks modes too much. EGA software doing such tweaks is quite rare, because the 640x350 mode was already pushing the IBM ECD (EGA monitor) to its limits, so there isn't much to gain by tweaking.

When talking about soft-scrolling and panning in 16-color modes, all EGA code will work perfectly on VGA, too. In 256-color modes (VGA only), you need to remember that 256-color pixels are internally treated as a pair two 16-color pixels, so you need to adjust panning in increments of two 16-color pixels to achieve scrolling in single 256-color pixels. This is because EGA and VGA behave the same (internal pixel size is 4 bits), not because EGA and VGA are different.

Okay, I really want to increase my limited understanding and figure out how this actually works. I'm having trouble wrapping my head around it. So what you guys are telling me is that the horizontal scrolling is different from the vertical scrolling, because the pan register only finetunes the horizontal scrolling, so you have to increment that by 1 each frame until it reaches the end of the 8-pixel wide vertical column (so to speak), and then you can increment the start address - am I thinking correctly about this?

In this video, John Carmack talks about his scrolling routines (starting at 2:24). He mentions having a "64K window" - the amount of video memory in the EGA card, I assume.

I found some info on the EGA bitplanes that clear up how they work a little for me: the card is fetching 32 bits at a time from memory because it's fetching one byte from each bitplane, making 32 bits or 4 bytes total.

Here's the main head-twister I can't understand right now: memory addresses are linear, obviously. I assume the EGA card reads one scanline's worth of memory before moving to the next line. If I increment the start address by 1, won't it cause a shear effect as every other row is now offset since it still grabs 320 pixels or 160 bytes of video memory, cutting into the beginning of the old next row before moving to the next line?

Carmack also talks about two more things in that video:

1. The fact the game is pageflipped - he'd have not one, but two pageflipped screens both scrolling, which since a 320x200x4bit screen is 32,000 bytes, I assume would take up almost all of the EGA video memory. I can kind of envision how this would work but I don't think I'll get it until I figure out the answer to my question above about how EGA translates linear memory into a screen with rows.
2. The SVGA compatibility problem, stating that on some SVGA cards, moving the start address past the end of the 64K EGA memory would not wrap around, but would bring it into uninitialized memory and display garbage, so his solution was to have a compatibility mode that moves the start address back to the beginning and copies the entire screen, producing a "hitch". I've never personally observed this hitch; I think you'd have to have a slow 286 with SVGA compatibility mode enabled to see it. I'll have to try that sometime.

For what it's worth, regarding the 60Hz vs 70Hz issue, I have a regular EGA card with an IBM 5153 in my PC/AT, and I've never noticed anything wrong with the scrolling. The game also runs at the correct speed, which is interesting to me since I was under the impression that the game uses the VGA 70 Hz vertical sync for its internal timer, dividing it in two for 35 fps.

World's foremost 486 enjoyer.

Reply 15 of 19, by mkarcher

User metadata
Rank l33t
Rank
l33t
keenmaster486 wrote on 2023-05-07, 21:32:

Okay, I really want to increase my limited understanding and figure out how this actually works. I'm having trouble wrapping my head around it. So what you guys are telling me is that the horizontal scrolling is different from the vertical scrolling, because the pan register only finetunes the horizontal scrolling, so you have to increment that by 1 each frame until it reaches the end of the 8-pixel wide vertical column (so to speak), and then you can increment the start address - am I thinking correctly about this?

Yes. That's exactly how it works.

keenmaster486 wrote on 2023-05-07, 21:32:

In this video, John Carmack talks about his scrolling routines (starting at 2:24). He mentions having a "64K window" - the amount of video memory in the EGA card, I assume.

The 64K window is actually the full 256KB of EGA memory. The EGA memory architecture is quite arcane, by having 65536 words of 32 bits each. In the graphics mode, each byte access performed by the CPU in the range A000:0000 to A000:FFFF (the 64K window) interacts with the corresponding 32-bit word of video memory. In the most simple setup, for reading, you select which 8-bit part of the 32-bit word you want to read before you do the actual read access, and for writing, you select which of the 4 8-bit parts should receive the value written. The real power of EGA programming is fully understanding the architecture and optimizing drawing code for it. As this post is not about EGA drawing, but about EGA scrolling, I will stop this thread of discussion here.

keenmaster486 wrote on 2023-05-07, 21:32:

I found some info on the EGA bitplanes that clear up how they work a little for me: the card is fetching 32 bits at a time from memory because it's fetching one byte from each bitplane, making 32 bits or 4 bytes total.

"bit plane" is a common term for the 4 8-bit parts of the 32-bit EGA memory words. This term makes a lot of sense, because in 16-color mode, each of the 4 bytes contains information for one of four bits making up the pixel color.

keenmaster486 wrote on 2023-05-07, 21:32:

Here's the main head-twister I can't understand right now: memory addresses are linear, obviously. I assume the EGA card reads one scanline's worth of memory before moving to the next line. If I increment the start address by 1, won't it cause a shear effect as every other row is now offset since it still grabs 320 pixels or 160 bytes of video memory, cutting into the beginning of the old next row before moving to the next line?

One key advantage of the EGA CRTC card over the CGA CRTC (the classic motorola 6845) is that the EGA CRTC can be programmed to skip a certain amount of video memory between two lines. This means that in 320x200 mode, the next line does not necessarily start 40 words after the previous line. The logical line length can be set to 80 words (320 bytes if you count in bytes, but you should stop doing that when trying to understand the EGA architecture), so 40 words (320 pixels) are displayed, and the next 40 words (again 320 pixels) are skipped. This means that continoously increasing the start address from word 0 to word 40 will not "tear around" contents of the second line into the first line.

The key point of adaptive tile refresh is that you just need like 8 or 16 pixels left and right of the currently visible screen. Let's say you program the video card to 48 words per line, that is 384 pixels worth of data per line. You only display the central 320 pixels, and have 32 pixels left and right of that window in video memory. Then you scroll 16 pixels to the right. Now you only have 16 more pixels to the right, but 48 pixels to the left. You then replace the 16 leftmost pixels by the content the is supposed to be right of the visible window, to go back to 32 pixels to the right and 32 pixels to the left.

keenmaster486 wrote on 2023-05-07, 21:32:

1. The fact the game is pageflipped - he'd have not one, but two pageflipped screens both scrolling, which since a 320x200x4bit screen is 32,000 bytes, I assume would take up almost all of the EGA video memory. I can kind of envision how this would work but I don't think I'll get it until I figure out the answer to my question above about how EGA translates linear memory into a screen with rows.

At 320x200, a line takes 40 EGA words (of 32 bits), so the complete image takes 8000 words, using 8000 of the 65535 addresses available in EGA memory space. You can get more than 8 pages into that space, even if you add some margin so pixel-precision scrolling works. The amount of EGA memory is not a problem for that refresh algorithm.

keenmaster486 wrote on 2023-05-07, 21:32:

2. The SVGA compatibility problem, stating that on some SVGA cards, moving the start address past the end of the 64K EGA memory would not wrap around, but would bring it into uninitialized memory and display garbage, so his solution was to have a compatibility mode that moves the start address back to the beginning and copies the entire screen, producing a "hitch". I've never personally observed this hitch; I think you'd have to have a slow 286 with SVGA compatibility mode enabled to see it. I'll have to try that sometime.

Exactly. Although the number of SVGA cards requiring this compatibility mode is quite low. I didn't run into one yet.

keenmaster486 wrote on 2023-05-07, 21:32:

For what it's worth, regarding the 60Hz vs 70Hz issue, I have a regular EGA card with an IBM 5153 in my PC/AT, and I've never noticed anything wrong with the scrolling. The game also runs at the correct speed, which is interesting to me since I was under the impression that the game uses the VGA 70 Hz vertical sync for its internal timer, dividing it in two for 35 fps.

The game will not run at the intended ("correct") speed. It will divide the vertical sync rate by two, so it will run at 30 fps on EGA cards and 35 fps on VGA cards. As it will run as smooth at 30 fps on EGA cards as it runs at 35 fps on VGA cards, it's likely that you didn't notice the 16% speed decrease of the game.

Reply 16 of 19, by cinnabar

User metadata
Rank Newbie
Rank
Newbie
mkarcher wrote on 2023-05-06, 08:45:
VileR wrote on 2023-05-06, 08:15:

Panning works the same way in EGA and VGA, modulo some quirks such as how split-screen operation is affected.

Panning in split-screen is operating in a way on EGA that was considered quirky in practice,

I'm new here, so hi folks!!! 😀

I'm writing a game for the EGA and split screen is as far as I can see is not future compatible from EGA to VGA.

Split screen works via a line compare - when the line counter reaches the value, the memory counter is reset and screen is now fetched from 0000h instead of whatever was in the Start Address registers. To make the split screen 'off' by default, they have the compare value set to 511 on the EGA, a value it will never reach. The ninth bit resides in the CRTC overflow register. On the VGA split screen behavior allows for larger line numbers, and so has a 10th bit in CRTC Maximum Scan Line register which is set on Mode D. This bit didn't exist on the EGA, so a programmer doing split screen for the EGA would have no way of knowing they would be expected to clear a value that doesn't exist yet without having a time machine!

And besides, your split screen for EGA will be broke because the 200 line mode is emulated as 400 line double-scanned and so the value for your line compare needs to be double on the VGA! 🙁 For this reason it seems like register compatible EGA is useful for original EGA code operating properly.

And as you say the PEL panning with split screen enabled at same time is quirky (broken) since it pans the split screen with it on EGA, which sucks. In my game I'm just gonna disable the status split window during map scroll since I want to use the smooth PEL panning.

I've noticed too that 86Box seems broken in its EGA implementation since the Start Address affects the split screen, when its whole point that it doesn't! It works correctly on DOSBOX with EGA selected, the VGA on 86Box works correctly too.

Probably I will try to detect EGA vs VGA and adapt accordingly.

Reply 17 of 19, by cinnabar

User metadata
Rank Newbie
Rank
Newbie

If anyone is interested I created an Issue on 86Box github about the broken EGA behaviour on split screen handling...

https://github.com/86Box/86Box/issues/3386

I patched my own build and it seems to work but I don't really know much about pull requests and all that malarkey i'm a bit of a github n00b

Reply 18 of 19, by mkarcher

User metadata
Rank l33t
Rank
l33t
cinnabar wrote on 2023-06-03, 18:07:

This bit didn't exist on the EGA, so a programmer doing split screen for the EGA would have no way of knowing they would be expected to clear a value that doesn't exist yet without having a time machine!

Indeed.

cinnabar wrote on 2023-06-03, 18:07:

And besides, your split screen for EGA will be broke because the 200 line mode is emulated as 400 line double-scanned and so the value for your line compare needs to be double on the VGA! 🙁

Also true. At least EGA software won't mess up the vertical timing, because all bits in the overflow register except for the scanline compare bit are write protected by default (unless VGA compatible software unlocks them using bit 7 in CRTC register 11h. EGA software won't do read-modify-write on the overflow register, because that register is write-only on EGA cards.

cinnabar wrote on 2023-06-03, 18:07:

For this reason it seems like register compatible EGA is useful for original EGA code operating properly.

I definitely didn't think of issues like this when claiming that EGA and VGA behaves identical regarding the soft scrolling stuff. But I still maintain the point that you don't need to switch most (Super)VGA card into EGA compatiblity mode to get the 64K/256K wraparound the OP asked for.

cinnabar wrote on 2023-06-03, 18:07:

And as you say the PEL panning with split screen enabled at same time is quirky (broken) since it pans the split screen with it on EGA, which sucks. In my game I'm just gonna disable the status split window during map scroll since I want to use the smooth PEL panning.

That sounds like a good approach to handle the quirk. If you have time to do it, you can smoothly decrease the vertical displayed register to gradually hide the status window. If the switch between map scroll and normal game play happens often, not animating the transition is likely better, because that animation is going to annoy the user if it just takes unneccessary time.

cinnabar wrote on 2023-06-03, 18:07:

I've noticed too that 86Box seems broken in its EGA implementation since the Start Address affects the split screen, when its whole point that it doesn't!

Indeed! After a line compare match, the current address counter in the CRTC is supposed to be exactly 0000h on the subsequent scanline, no questions asked.

cinnabar wrote on 2023-06-03, 18:07:

Probably I will try to detect EGA vs VGA and adapt accordingly.

That makes a lot of sense, as there is no abstraction layer (like a BIOS service) for soft scrolling (before the VESA BIOS extensions 1.2, but I don't think you want to force users to install a VBE 1.2 driver for EGA cards, assuming a VESA 1.2 driver that runs on XT class machines exists it all).

Reply 19 of 19, by mills26

User metadata
Rank Newbie
Rank
Newbie

I also exploited this scrolling/wrapping on VGA/EGA and created this engine, very simple because I wanted it to work ok on 8088s: https://github.com/mills32/Little-Game-Engine-for-VGA-EGA.

I had to completely ignore the split screen function, because it is broken on real EGA. Also level maps can't be too large, because tile data is stored at the end on VRAM.

Is there any function on EGA/VGA that wraps the VRAM at the desired address?. I wish I could tell the graphics to wrap at some address while writting tiles, so that I don't overwritte the stored original tiles, and then I could use huge maps.