VOGONS


Reply 40 of 48, by clb

User metadata
Rank Member
Rank
Member

Hi Mills!

Your engine is really cool, I've followed the development and I think we interacted in the past on some other conversation thread.

In this thread the topic of the discussion is about Commander Keen scrolling sync issues. Reading your comment, I feel a bit like you might not have read the thread before posting(?)

You wrote

This implementation seems to work on all real VGAs which were tested, also on emulated VGAS (Dosbox-x, PCEM,86Box).
Emulated EGA on Dosbox-x updates the PEL register every scanline, and this scroll is also working well on it.

On more recent SVGA cards (including modern GPUs) it still works very smooth, if you boot from freedos in an USB. Other cards may require first waiting for vsync and updating PEL and start address at the same time (at the start or end of a frame).

which paints a rosy picture of the presented code, and reads a bit like you are posting this code as a "here is how to do it instead" type of comment over the earlier comments, although this scheme unfortunately has flaws.

.. but it seems like you already knew that, since I see in your GitHub, you already have this comment

//Choppy on SVGA or modern VGA compatibles

The investigation that we did in this thread aimed to research exactly why Commander Keen sync code was choppy. Based on the investigation that we did, we now know why, and we also know why the code you shared will be choppy on some cards.

It actually has nothing to do with SVGA or "modern VGAs", but instead it has to do about random hardware engineering decisions in latching timings that different vendors took.

See, none of that latching behavior was ever documented or standardized by IBM, which is why different vendors made different (arbitrary) choices as long as it worked with whatever software test batteries the vendors might have tested against.

Here is a video of Little Game Engine when I run it on my vintage PC (DOS 486): https://youtu.be/C2GX_6pM7Xk

And indeed it glitches. 😒

Notice how it glitches exactly like Commander Keen 4-6 did. (horizontal walking glitches, vertical walking doesn't)

The sync code you present is straightforward: it first updates the Display Start Address (DS) register unsynchronized, and it then waits for the start edge of next vsync, and then, with interrupts disabled, updates the Horizontal Pixel Shift Count (HS) register.

I am sure if such a simple method would have worked, id Software would definitely have found and used it! Why after all would anyone overcomplicate things? 😀

I don't want to pick your code down, but let me dissect it a little bit on things that are potential problems with its robustness.

1. The first flaw is that the DS and HS registers are updated at a poor time with respect to the vsync start and end signal. This is what causes the glitchy horizontal scrolling in the above video. I have a Jazz Multimedia G-Force 128 graphics card that has a Tseng chip, and as was found in this table, this kind method of updating the DS (unsynchronized/mostly during visible image) and HS (after start of vsync edge) register that straddles the vsync start edge is not compatible with this vendor.

To fix this flaw, the DS and HS registers should be updated at a time that is compatible with the latching behavior of all hardware, so they don't end up being latched out of sync. The table posted earlier can help there. (the most compatible method with all graphics adapters is to update DS and HS after vblank, but before vsync start)

2. A second flaw is that the code updates the DS register unsynchronized. That is, the graphics card could be anywhere in its vsync period when the DS register is updated. If start of vsync or end of vsync happened to fall just right in between the update of DS and HS registers, these latching of these two registers would be mismatched like above in case 1, and it would result in the scrolling glitching like can be seen on the video (although for just one intermittent frame).

To fix this, the update code should only update the DS code at a known time with respect to start and end of vsync edges, not unsynchronized with respect to vertical refresh where one can't guarantee where during the vertical period this update is being done.

3. A third flaw is that the code does not disable interrupts when it updates the DS register. Because of that, if an interrupt happened just in the middle of updating the DS register, but before the HS register is updated, then that interrupt could again cause the unsynchronization between vsync start and end edge to occur, leading to an intermittent glitched scrolling.

To fix this flaw, interrupts should be cleared already before updating the DS register, rather than updating it while interrupts are enabled.

Issues 2 and 3 manifest in hard-to-debug "one glitched frame every 10 minutes of gameplay for some users" kind of a deal, or a "one poor user out of a hundred gets repeated glitching since their CPU speed is just slow/fast enough with respect to the vertical refresh rate" kind of a deal.

4. A fourth note is that the code waits for start of vsync, and not for the start of vblank. I like to bring this up not to pick on your code, but to pick on IBM, to show how absent-minded they were about EGA/VGA graphics programming.

Not being able to wait for vblank in a straightforward manner start wastes some 0.2 msecs of CPU time (can be more depending on vertical front porch size) that could have been the earliest moment to start page flipping/blitting work. Not a huge deal, but shows that IBM didn't care to be precise with this stuff. The id Software "wait for vblank" method reclaims this 0.2 msecs for good use.

5. A fifth point, which is not necessarily a problem for a specific game if you are in control of authoring all your code, but can be a problem for a generic game engine that could see varying workloads, is that the code you presented disables interrupts at the end of processing a frame, and then pauses to wait for the next start of vsync edge to happen.

This can have catastrophic results for audio, networking , PIT timing and other interrupts, counterintuitively exaggerated as the CPU speed grows.

The reason for this is that ideally, code should spend as little time as possible with interrupts disabled. If a single game update+render frame took close to 16 milliseconds, then there is no problem. But let's say you are running on a fast PC, or have a very lightweight game state (in a menu perhaps), where the game update + render only takes < 1 milliseconds.

That means that the engine will then spend most of the real-world time with interrupts disabled inside that "wait for vsync edge" loop.

Then, if the game then has busy interrupts logic, all this will start to cause trouble. In Keen 4-6 case, the game timing and audio is done interrupts based, and it has busy PIT interrupts ticking 8*70 = 560 times per second.

Initially when I was authoring the smooth 70 Hz Keen 4-6 repository, I tried to remove all of their complex vsync hardware scrolling logic and replace it exactly with that kind of a simple logic like you posted, just to realize that it skews execution of interrupts, and game timing and audio will start to drift. Keen requires a PIT timer to tick 8 times every frame, but if you are on a fast PC (or in an action-less menu screen) where 95% of your frame is spent idle with interrupts locked waiting for vsync, then realistically you'll only get one of those 8 interrupts to fire per frame, and audio and game timing will start to get issues.

So it is not feasible to use sync code that disables interrupts to wait for vsync.

This is actually something that IBM dropped the ball on big time. They never provided an easy mechanism to wait for vblank in a robust way.

So the reason that id Software used the "let's infer the start of vblank from blank interval lengths" code was to avoid this fifth issue above in a way that was also compatible with issue 1 above. id Software just botched up their code by assuming that the ISA/PCI bus speed would stay constant and not speed up as PCs got faster (and then double botched it by assuming that PCI buses wouldn't get faster), which of course was not the case.

Sidenote, CRT Terminator is looking to also fix this issue by adding a safe counter mechanism that can be used to wait for the start of next vblank using a protocol that only needs to disable interrupts when it is getting close to next vblank (e.g. <1-2 msec to go). This way a wait-for-vblank code wastes only some constant <5% of real-world time with interrupts disabled, independent of the user's CPU speed.

In the absence of this type of a silly "CRT Terminator fixed it because we could but you can't rely on it since we can't go back in time to sell it to everyone" type of thing, the most reliable method indeed is to sniff the start of vblank like id Software did - but just don't botch it up like Carmack et al. by assuming that the ISA/PCI bus speed would be the same constant for every PC - rather benchmark the bus speed for the PC at hand first. That is how it works in KEEN70HZ repository in the absence of a CRT Terminator.

I hope you'll be inspired to build some cool games with the engine!

Reply 41 of 48, by mills26

User metadata
Rank Newbie
Rank
Newbie
clb wrote on 2024-01-05, 23:56:
Hi Mills! […]
Show full quote

Hi Mills!

Your engine is really cool, I've followed the development and I think we interacted in the past on some other conversation thread.

In this thread the topic of the discussion is about Commander Keen scrolling sync issues. Reading your comment, I feel a bit like you might not have read the thread before posting(?)

You wrote

This implementation seems to work on all real VGAs which were tested, also on emulated VGAS (Dosbox-x, PCEM,86Box).
Emulated EGA on Dosbox-x updates the PEL register every scanline, and this scroll is also working well on it.

On more recent SVGA cards (including modern GPUs) it still works very smooth, if you boot from freedos in an USB. Other cards may require first waiting for vsync and updating PEL and start address at the same time (at the start or end of a frame).

which paints a rosy picture of the presented code, and reads a bit like you are posting this code as a "here is how to do it instead" type of comment over the earlier comments, although this scheme unfortunately has flaws.

.. but it seems like you already knew that, since I see in your GitHub, you already have this comment

//Choppy on SVGA or modern VGA compatibles

The investigation that we did in this thread aimed to research exactly why Commander Keen sync code was choppy. Based on the investigation that we did, we now know why, and we also know why the code you shared will be choppy on some cards.

It actually has nothing to do with SVGA or "modern VGAs", but instead it has to do about random hardware engineering decisions in latching timings that different vendors took.

See, none of that latching behavior was ever documented or standardized by IBM, which is why different vendors made different (arbitrary) choices as long as it worked with whatever software test batteries the vendors might have tested against.

Here is a video of Little Game Engine when I run it on my vintage PC (DOS 486): https://youtu.be/C2GX_6pM7Xk

And indeed it glitches. 😒

Notice how it glitches exactly like Commander Keen 4-6 did. (horizontal walking glitches, vertical walking doesn't)

The sync code you present is straightforward: it first updates the Display Start Address (DS) register unsynchronized, and it then waits for the start edge of next vsync, and then, with interrupts disabled, updates the Horizontal Pixel Shift Count (HS) register.

I am sure if such a simple method would have worked, id Software would definitely have found and used it! Why after all would anyone overcomplicate things? 😀

I don't want to pick your code down, but let me dissect it a little bit on things that are potential problems with its robustness.

1. The first flaw is that the DS and HS registers are updated at a poor time with respect to the vsync start and end signal. This is what causes the glitchy horizontal scrolling in the above video. I have a Jazz Multimedia G-Force 128 graphics card that has a Tseng chip, and as was found in this table, this kind method of updating the DS (unsynchronized/mostly during visible image) and HS (after start of vsync edge) register that straddles the vsync start edge is not compatible with this vendor.

To fix this flaw, the DS and HS registers should be updated at a time that is compatible with the latching behavior of all hardware, so they don't end up being latched out of sync. The table posted earlier can help there. (the most compatible method with all graphics adapters is to update DS and HS after vblank, but before vsync start)

2. A second flaw is that the code updates the DS register unsynchronized. That is, the graphics card could be anywhere in its vsync period when the DS register is updated. If start of vsync or end of vsync happened to fall just right in between the update of DS and HS registers, these latching of these two registers would be mismatched like above in case 1, and it would result in the scrolling glitching like can be seen on the video (although for just one intermittent frame).

To fix this, the update code should only update the DS code at a known time with respect to start and end of vsync edges, not unsynchronized with respect to vertical refresh where one can't guarantee where during the vertical period this update is being done.

3. A third flaw is that the code does not disable interrupts when it updates the DS register. Because of that, if an interrupt happened just in the middle of updating the DS register, but before the HS register is updated, then that interrupt could again cause the unsynchronization between vsync start and end edge to occur, leading to an intermittent glitched scrolling.

To fix this flaw, interrupts should be cleared already before updating the DS register, rather than updating it while interrupts are enabled.

Issues 2 and 3 manifest in hard-to-debug "one glitched frame every 10 minutes of gameplay for some users" kind of a deal, or a "one poor user out of a hundred gets repeated glitching since their CPU speed is just slow/fast enough with respect to the vertical refresh rate" kind of a deal.

4. A fourth note is that the code waits for start of vsync, and not for the start of vblank. I like to bring this up not to pick on your code, but to pick on IBM, to show how absent-minded they were about EGA/VGA graphics programming.

Not being able to wait for vblank in a straightforward manner start wastes some 0.2 msecs of CPU time (can be more depending on vertical front porch size) that could have been the earliest moment to start page flipping/blitting work. Not a huge deal, but shows that IBM didn't care to be precise with this stuff. The id Software "wait for vblank" method reclaims this 0.2 msecs for good use.

5. A fifth point, which is not necessarily a problem for a specific game if you are in control of authoring all your code, but can be a problem for a generic game engine that could see varying workloads, is that the code you presented disables interrupts at the end of processing a frame, and then pauses to wait for the next start of vsync edge to happen.

This can have catastrophic results for audio, networking , PIT timing and other interrupts, counterintuitively exaggerated as the CPU speed grows.

The reason for this is that ideally, code should spend as little time as possible with interrupts disabled. If a single game update+render frame took close to 16 milliseconds, then there is no problem. But let's say you are running on a fast PC, or have a very lightweight game state (in a menu perhaps), where the game update + render only takes < 1 milliseconds.

That means that the engine will then spend most of the real-world time with interrupts disabled inside that "wait for vsync edge" loop.

Then, if the game then has busy interrupts logic, all this will start to cause trouble. In Keen 4-6 case, the game timing and audio is done interrupts based, and it has busy PIT interrupts ticking 8*70 = 560 times per second.

Initially when I was authoring the smooth 70 Hz Keen 4-6 repository, I tried to remove all of their complex vsync hardware scrolling logic and replace it exactly with that kind of a simple logic like you posted, just to realize that it skews execution of interrupts, and game timing and audio will start to drift. Keen requires a PIT timer to tick 8 times every frame, but if you are on a fast PC (or in an action-less menu screen) where 95% of your frame is spent idle with interrupts locked waiting for vsync, then realistically you'll only get one of those 8 interrupts to fire per frame, and audio and game timing will start to get issues.

So it is not feasible to use sync code that disables interrupts to wait for vsync.

This is actually something that IBM dropped the ball on big time. They never provided an easy mechanism to wait for vblank in a robust way.

So the reason that id Software used the "let's infer the start of vblank from blank interval lengths" code was to avoid this fifth issue above in a way that was also compatible with issue 1 above. id Software just botched up their code by assuming that the ISA/PCI bus speed would stay constant and not speed up as PCs got faster (and then double botched it by assuming that PCI buses wouldn't get faster), which of course was not the case.

Sidenote, CRT Terminator is looking to also fix this issue by adding a safe counter mechanism that can be used to wait for the start of next vblank using a protocol that only needs to disable interrupts when it is getting close to next vblank (e.g. <1-2 msec to go). This way a wait-for-vblank code wastes only some constant <5% of real-world time with interrupts disabled, independent of the user's CPU speed.

In the absence of this type of a silly "CRT Terminator fixed it because we could but you can't rely on it since we can't go back in time to sell it to everyone" type of thing, the most reliable method indeed is to sniff the start of vblank like id Software did - but just don't botch it up like Carmack et al. by assuming that the ISA/PCI bus speed would be the same constant for every PC - rather benchmark the bus speed for the PC at hand first. That is how it works in KEEN70HZ repository in the absence of a CRT Terminator.

I hope you'll be inspired to build some cool games with the engine!

I'm sorry, but there has been a misunderstanding, I did not want to look like the hero who solved the issue 🙁. I just had tested this particular code on a lot of really really ancient computers (8088-86 and 286 PCs) and it was working well. I did not consider 386 or 486, because they can redraw the screen at 30-70 fps without using any hardware scrolling/PEL panning at all, so it's better not to use any VGA function (in fact most games do not bother and redraw everything every frame).

My code and my engine are obviously designed for (at most) a slow 286, and timmers/keyboard readings/music playing occurs only once per frame.
I included a "SVGA" scrolling function which just tries to wait for vsync to start, and then updates everything as fast as the CPU can, If I wanted an engine for a 486, I would ignore all of this and make a simple wait_vsync that only serves as a flip page function.

Has anybody considered making commander keen games just redraw everything (software scroll)? This way the game works better on 386-486+ CPUs. I think someone made a port for tandy cards and it does just this (and it is also very slow), I suppose CGA version also uses software scroll.

Thanks for all the information you posted.

Reply 42 of 48, by pentiumspeed

User metadata
Rank l33t
Rank
l33t
mills26 wrote on 2024-01-07, 17:31:
I'm sorry, but there has been a misunderstanding, I did not want to look like the hero who solved the issue :(. I just had teste […]
Show full quote
clb wrote on 2024-01-05, 23:56:
Hi Mills! […]
Show full quote

Hi Mills!

Your engine is really cool, I've followed the development and I think we interacted in the past on some other conversation thread.

In this thread the topic of the discussion is about Commander Keen scrolling sync issues. Reading your comment, I feel a bit like you might not have read the thread before posting(?)

You wrote

This implementation seems to work on all real VGAs which were tested, also on emulated VGAS (Dosbox-x, PCEM,86Box).
Emulated EGA on Dosbox-x updates the PEL register every scanline, and this scroll is also working well on it.

On more recent SVGA cards (including modern GPUs) it still works very smooth, if you boot from freedos in an USB. Other cards may require first waiting for vsync and updating PEL and start address at the same time (at the start or end of a frame).

which paints a rosy picture of the presented code, and reads a bit like you are posting this code as a "here is how to do it instead" type of comment over the earlier comments, although this scheme unfortunately has flaws.

.. but it seems like you already knew that, since I see in your GitHub, you already have this comment

//Choppy on SVGA or modern VGA compatibles

The investigation that we did in this thread aimed to research exactly why Commander Keen sync code was choppy. Based on the investigation that we did, we now know why, and we also know why the code you shared will be choppy on some cards.

It actually has nothing to do with SVGA or "modern VGAs", but instead it has to do about random hardware engineering decisions in latching timings that different vendors took.

See, none of that latching behavior was ever documented or standardized by IBM, which is why different vendors made different (arbitrary) choices as long as it worked with whatever software test batteries the vendors might have tested against.

Here is a video of Little Game Engine when I run it on my vintage PC (DOS 486): https://youtu.be/C2GX_6pM7Xk

And indeed it glitches. 😒

Notice how it glitches exactly like Commander Keen 4-6 did. (horizontal walking glitches, vertical walking doesn't)

The sync code you present is straightforward: it first updates the Display Start Address (DS) register unsynchronized, and it then waits for the start edge of next vsync, and then, with interrupts disabled, updates the Horizontal Pixel Shift Count (HS) register.

I am sure if such a simple method would have worked, id Software would definitely have found and used it! Why after all would anyone overcomplicate things? 😀

I don't want to pick your code down, but let me dissect it a little bit on things that are potential problems with its robustness.

1. The first flaw is that the DS and HS registers are updated at a poor time with respect to the vsync start and end signal. This is what causes the glitchy horizontal scrolling in the above video. I have a Jazz Multimedia G-Force 128 graphics card that has a Tseng chip, and as was found in this table, this kind method of updating the DS (unsynchronized/mostly during visible image) and HS (after start of vsync edge) register that straddles the vsync start edge is not compatible with this vendor.

To fix this flaw, the DS and HS registers should be updated at a time that is compatible with the latching behavior of all hardware, so they don't end up being latched out of sync. The table posted earlier can help there. (the most compatible method with all graphics adapters is to update DS and HS after vblank, but before vsync start)

2. A second flaw is that the code updates the DS register unsynchronized. That is, the graphics card could be anywhere in its vsync period when the DS register is updated. If start of vsync or end of vsync happened to fall just right in between the update of DS and HS registers, these latching of these two registers would be mismatched like above in case 1, and it would result in the scrolling glitching like can be seen on the video (although for just one intermittent frame).

To fix this, the update code should only update the DS code at a known time with respect to start and end of vsync edges, not unsynchronized with respect to vertical refresh where one can't guarantee where during the vertical period this update is being done.

3. A third flaw is that the code does not disable interrupts when it updates the DS register. Because of that, if an interrupt happened just in the middle of updating the DS register, but before the HS register is updated, then that interrupt could again cause the unsynchronization between vsync start and end edge to occur, leading to an intermittent glitched scrolling.

To fix this flaw, interrupts should be cleared already before updating the DS register, rather than updating it while interrupts are enabled.

Issues 2 and 3 manifest in hard-to-debug "one glitched frame every 10 minutes of gameplay for some users" kind of a deal, or a "one poor user out of a hundred gets repeated glitching since their CPU speed is just slow/fast enough with respect to the vertical refresh rate" kind of a deal.

4. A fourth note is that the code waits for start of vsync, and not for the start of vblank. I like to bring this up not to pick on your code, but to pick on IBM, to show how absent-minded they were about EGA/VGA graphics programming.

Not being able to wait for vblank in a straightforward manner start wastes some 0.2 msecs of CPU time (can be more depending on vertical front porch size) that could have been the earliest moment to start page flipping/blitting work. Not a huge deal, but shows that IBM didn't care to be precise with this stuff. The id Software "wait for vblank" method reclaims this 0.2 msecs for good use.

5. A fifth point, which is not necessarily a problem for a specific game if you are in control of authoring all your code, but can be a problem for a generic game engine that could see varying workloads, is that the code you presented disables interrupts at the end of processing a frame, and then pauses to wait for the next start of vsync edge to happen.

This can have catastrophic results for audio, networking , PIT timing and other interrupts, counterintuitively exaggerated as the CPU speed grows.

The reason for this is that ideally, code should spend as little time as possible with interrupts disabled. If a single game update+render frame took close to 16 milliseconds, then there is no problem. But let's say you are running on a fast PC, or have a very lightweight game state (in a menu perhaps), where the game update + render only takes < 1 milliseconds.

That means that the engine will then spend most of the real-world time with interrupts disabled inside that "wait for vsync edge" loop.

Then, if the game then has busy interrupts logic, all this will start to cause trouble. In Keen 4-6 case, the game timing and audio is done interrupts based, and it has busy PIT interrupts ticking 8*70 = 560 times per second.

Initially when I was authoring the smooth 70 Hz Keen 4-6 repository, I tried to remove all of their complex vsync hardware scrolling logic and replace it exactly with that kind of a simple logic like you posted, just to realize that it skews execution of interrupts, and game timing and audio will start to drift. Keen requires a PIT timer to tick 8 times every frame, but if you are on a fast PC (or in an action-less menu screen) where 95% of your frame is spent idle with interrupts locked waiting for vsync, then realistically you'll only get one of those 8 interrupts to fire per frame, and audio and game timing will start to get issues.

So it is not feasible to use sync code that disables interrupts to wait for vsync.

This is actually something that IBM dropped the ball on big time. They never provided an easy mechanism to wait for vblank in a robust way.

So the reason that id Software used the "let's infer the start of vblank from blank interval lengths" code was to avoid this fifth issue above in a way that was also compatible with issue 1 above. id Software just botched up their code by assuming that the ISA/PCI bus speed would stay constant and not speed up as PCs got faster (and then double botched it by assuming that PCI buses wouldn't get faster), which of course was not the case.

Sidenote, CRT Terminator is looking to also fix this issue by adding a safe counter mechanism that can be used to wait for the start of next vblank using a protocol that only needs to disable interrupts when it is getting close to next vblank (e.g. <1-2 msec to go). This way a wait-for-vblank code wastes only some constant <5% of real-world time with interrupts disabled, independent of the user's CPU speed.

In the absence of this type of a silly "CRT Terminator fixed it because we could but you can't rely on it since we can't go back in time to sell it to everyone" type of thing, the most reliable method indeed is to sniff the start of vblank like id Software did - but just don't botch it up like Carmack et al. by assuming that the ISA/PCI bus speed would be the same constant for every PC - rather benchmark the bus speed for the PC at hand first. That is how it works in KEEN70HZ repository in the absence of a CRT Terminator.

I hope you'll be inspired to build some cool games with the engine!

I'm sorry, but there has been a misunderstanding, I did not want to look like the hero who solved the issue 🙁. I just had tested this particular code on a lot of really really ancient computers (8088-86 and 286 PCs) and it was working well. I did not consider 386 or 486, because they can redraw the screen at 30-70 fps without using any hardware scrolling/PEL panning at all, so it's better not to use any VGA function (in fact most games do not bother and redraw everything every frame).

My code and my engine are obviously designed for (at most) a slow 286, and timmers/keyboard readings/music playing occurs only once per frame.
I included a "SVGA" scrolling function which just tries to wait for vsync to start, and then updates everything as fast as the CPU can, If I wanted an engine for a 486, I would ignore all of this and make a simple wait_vsync that only serves as a flip page function.

Has anybody considered making commander keen games just redraw everything (software scroll)? This way the game works better on 386-486+ CPUs. I think someone made a port for tandy cards and it does just this (and it is also very slow), I suppose CGA version also uses software scroll.

Thanks for all the information you posted.

The major issue was with 286 and later, including pentium classic, mmx and PII and PIII when people had most issues with the game video cards compatibility shows up mostly with AGP and PCI cards and several incompatible ISA cards such as ATI ISA cards. Have you attended to this issues with these hardware you were testing against?

XT and Turbo XT had very limited choice of video cards to support without slowing down too much, mostly MDA and CGA and few incompatible VGA cards.

Cheers,

Great Northern aka Canada.

Reply 43 of 48, by mills26

User metadata
Rank Newbie
Rank
Newbie
pentiumspeed wrote on 2024-01-07, 19:55:

The major issue was with 286 and lateVGAr, including pentium classic, mmx and PII and PIII when people had most issues with the game video cards compatibility shows up mostly with AGP and PCI cards and several incompatible ISA cards such as ATI ISA cards. Have you attended to this issues with these hardware you were testing against?

XT and Turbo XT had very limited choice of video cards to support without slowing down too much, mostly MDA and CGA and few incompatible VGA cards.

Cheers,

As I said, I was only thinking about XT and the first ATs.

Where I live, and I suppose in many other regions, it was incredibly common to see cheap 8088/86/286 + EGA/VGA, around 1991 (my first PC was an 8086, and a lot of neighbours had a 286+VGA). This scrolling thing was only an advantage for these slow CPUs. I suppose id tried to target that (And that's what I did with the engine, resulting in the same bugs for faster systems).

Reply 44 of 48, by clb

User metadata
Rank Member
Rank
Member

Thanks for the clarification mills26, and very sorry to walk so clearly into adding to the confusion.

I forked Little Game Engine and as a test, updated it to use the same synchronization behavior that I authored to KEEN70HZ. The code is here: https://github.com/mills32/Little-Game-Engine … :sync_to_vblank . I authored the code there in C now for clarity.

The added code is the "method 6" from the earlier table.

To my knowledge, it should work for both low-end ISA and high-end AGP DOS PCs. I haven't tested it on a real XT though, there it might benefit from asm conversion (if doing an asm conversion, one gotcha is to make sure that there are some instructions between the cli+sti breathing logic, in the C code there is a goto instruction). I would be curious to know if there are setups where it would fail.

Testing it out on that Jazz Multimedia G-Force 128 Tseng SVGA card that I posted to stutter before, runs smooth with that code.

If peeping vsync code for frame stability, there is one note about DOSBox-X running on a 60 Hz display: there scrolling will occassionally get microstuttering at least on my PC (Ryzen 5950X). Originally I thought that was due to 70 Hz vs 60 Hz discrepancy when I first saw it in Keen, but now I observe that this same microstuttering is also present in the master branch of Little Game Engine that uses your original vsync wait mechanism and runs in 60Hz and not 70 Hz, so I'm now suspecting this microstuttering seems to be caused just by general frame time fluctuation on emulators.

When running DOSBox-X on a 120 Hz display or faster, that emulator microstuttering vanishes for me. So having a gaming display helps with DOSBox-X frame stability at least.

Reply 45 of 48, by mills26

User metadata
Rank Newbie
Rank
Newbie
clb wrote on 2024-01-07, 22:55:
Thanks for the clarification mills26, and very sorry to walk so clearly into adding to the confusion. […]
Show full quote

Thanks for the clarification mills26, and very sorry to walk so clearly into adding to the confusion.

I forked Little Game Engine and as a test, updated it to use the same synchronization behavior that I authored to KEEN70HZ. The code is here: https://github.com/mills32/Little-Game-Engine … :sync_to_vblank . I authored the code there in C now for clarity.

The added code is the "method 6" from the earlier table.

To my knowledge, it should work for both low-end ISA and high-end AGP DOS PCs. I haven't tested it on a real XT though, there it might benefit from asm conversion (if doing an asm conversion, one gotcha is to make sure that there are some instructions between the cli+sti breathing logic, in the C code there is a goto instruction). I would be curious to know if there are setups where it would fail.

Testing it out on that Jazz Multimedia G-Force 128 Tseng SVGA card that I posted to stutter before, runs smooth with that code.

If peeping vsync code for frame stability, there is one note about DOSBox-X running on a 60 Hz display: there scrolling will occassionally get microstuttering at least on my PC (Ryzen 5950X). Originally I thought that was due to 70 Hz vs 60 Hz discrepancy when I first saw it in Keen, but now I observe that this same microstuttering is also present in the master branch of Little Game Engine that uses your original vsync wait mechanism and runs in 60Hz and not 70 Hz, so I'm now suspecting this microstuttering seems to be caused just by general frame time fluctuation on emulators.

When running DOSBox-X on a 120 Hz display or faster, that emulator microstuttering vanishes for me. So having a gaming display helps with DOSBox-X frame stability at least.

Thanks a lot! I'll test it in a few days 😀. I made the function in asm because an 8088 wastes a lot of cycles in the "in/out" instructions, and compilling inport/outport from c, adds another call instruction, so I thought the poor 8088 would have trouble finding a real vblank wasting so many cycles reading the ports 😀.

Reply 46 of 48, by mills26

User metadata
Rank Newbie
Rank
Newbie
clb wrote on 2024-01-07, 22:55:
Thanks for the clarification mills26, and very sorry to walk so clearly into adding to the confusion. […]
Show full quote

Thanks for the clarification mills26, and very sorry to walk so clearly into adding to the confusion.

I forked Little Game Engine and as a test, updated it to use the same synchronization behavior that I authored to KEEN70HZ. The code is here: https://github.com/mills32/Little-Game-Engine … :sync_to_vblank . I authored the code there in C now for clarity.

The added code is the "method 6" from the earlier table.

To my knowledge, it should work for both low-end ISA and high-end AGP DOS PCs. I haven't tested it on a real XT though, there it might benefit from asm conversion (if doing an asm conversion, one gotcha is to make sure that there are some instructions between the cli+sti breathing logic, in the C code there is a goto instruction). I would be curious to know if there are setups where it would fail.

Testing it out on that Jazz Multimedia G-Force 128 Tseng SVGA card that I posted to stutter before, runs smooth with that code.

If peeping vsync code for frame stability, there is one note about DOSBox-X running on a 60 Hz display: there scrolling will occassionally get microstuttering at least on my PC (Ryzen 5950X). Originally I thought that was due to 70 Hz vs 60 Hz discrepancy when I first saw it in Keen, but now I observe that this same microstuttering is also present in the master branch of Little Game Engine that uses your original vsync wait mechanism and runs in 60Hz and not 70 Hz, so I'm now suspecting this microstuttering seems to be caused just by general frame time fluctuation on emulators.

When running DOSBox-X on a 120 Hz display or faster, that emulator microstuttering vanishes for me. So having a gaming display helps with DOSBox-X frame stability at least.

Your function crashes (it is stuck in an infinite loop or something like that) on my 286 6/12 MHz with an OAK OTI-077, it also crashes on FPGA core ao486, (implements a tseng et4000). I should also test KEEN70HZ and see what it does, I hope it is just something I forgot to write, but github is very clear, I just added the new function, and used CalibrateMaxHblankLength() after checking video card.

EDIT: I got it working, I made some mistake while compilling. Thanks again, it is cool to be able to use this scrolling function 😀.

Reply 48 of 48, by Frenkel

User metadata
Rank Newbie
Rank
Newbie
mills26 wrote on 2024-01-07, 17:31:

Has anybody considered making commander keen games just redraw everything (software scroll)? This way the game works better on 386-486+ CPUs. I think someone made a port for tandy cards and it does just this (and it is also very slow), I suppose CGA version also uses software scroll.

That's correct. The CGA version of Commander 4-6 & Keen Dreams redraws everything every frame. I used that code to create a Tandy 1000 version and a MCGA / VGA (16 color) version of Keen 4.

It might be slow, but the Dopefish moves smoother in the Tandy and MCGA versions than in the EGA version 😉