VOGONS


Dosbox-x vga vsync issue

Topic actions

First post, by hornet1990

User metadata
Rank Newbie
Rank
Newbie

Hi

Not sure if this just a me problem but I unearthed some of my earliest VGA coding experiments from 30 years ago so tried recompiling (Watcom 10.6) and running it in dosbox-x (2nd May release, Visual Studio SDL1 - pretty much out of the box config) but it runs way too fast. The animation rate is tied to the vsync and should be updating every 4 frames (~67ms at 60Hz). The code in question is running double buffered and waiting for the retrace (reading port 0x03da) to copy the back buffer to the VGA memory (0xA0000), so in theory it should be running at ~60 to 75Hz but isn't.

The only way I can get it animating at a sensible speed is to massively drop the cpu cycles. I initially picked the "emulate P100" setting to match my machine of the day, but 53k cycles is way too high, 12k is better although arguably still a bit too quick, but then that drops it to 30fps, 6k drops it to 15fps. The vsync option under the video menu seems to make absolutely zero difference.

I tried another experiment (using Open Watcom 2 beta as my Watcom 10.6 refused to emit RDTSC) reading the RDTSC around the retrace and usually get ridiculously low and/or consistent values indicating that it isn't really waiting, or somehow 0x03da is being set according to the cpu cycles rather than real time of 1 second / refresh rate.

What am I missing? I then tried another test which just writes a pixel to the buffer, waits for the retrace, then copies the changed scanline to the display memory before plotting another pixel. In theory that should be taking 4 to 5 seconds to write a single line of 320 pixels (since it is writing 60-75 pixels per second in theory), but is taking less than a second per line with the same 12k cycle configuration.

The retrace code is this, and as far as I can remember worked fine on real hardware back in the day:

#pragma wait_retrace =  \
"mov dx,0x03da" \
"l1: in al,dx" \
"test al,0x08" \
"jnz l1" \
"l2: in al,dx" \
"test al,0x08" \
"jz l2" \
modify [edx eax] ;

Any ideas? Didn't many games and demos back in the 90's use vsync for their timing?

Thanks

https://rogueone.uk Kyro and other things

Reply 1 of 3, by MagefromAntares

User metadata
Rank Member
Rank
Member

Hi,

There is one of the functions I have used with Watcom C/C++ to wait for vsync, it is very similar, but there might be some difference in the way it is actually compiled as it uses the inline assembler syntax instead of the header pragma assembler syntax:

void wait_for_vsync()
{
_asm
{
push ax
push dx
mov dx, 0x3DAh
wait_vsync_1:
in al, dx
test al, 0x08h
jne wait_vsync_1
wait_vsync_2:
in al, dx
test al, 0x08h
je wait_vsync_2
pop dx
pop ax
}
}

Also note that the VGA refresh frequency for the standard 320x200 256 colour mode is 70Hz not 75Hz.

EDIT:

hornet1990 wrote on Yesterday, 16:30:

The only way I can get it animating at a sensible speed is to massively drop the cpu cycles. I initially picked the "emulate P100" setting to match my machine of the day, but 53k cycles is way too high, 12k is better although arguably still a bit too quick, but then that drops it to 30fps, 6k drops it to 15fps. The vsync option under the video menu seems to make absolutely zero difference.

If it drops to exactly 30 and 15 fps then it means that it vsyncs to half or quarter of 60Hz instead of the 70Hz that the original VGA has, but Dosbox might emulate the VGA mode running the actual display of the computer you are using with a 60Hz refresh mode, and dropping down to 30 and 15 fps is a behaviour very possible when the CPU is too overloaded to get to the vsync loop with enough cycles to spare, so it syncs to half or quarter of the actual vsync frequency instead.

"A process cannot be understood by stopping it. Understanding must move with the flow of the process, must join it and flow with it." - Dune

Reply 2 of 3, by hornet1990

User metadata
Rank Newbie
Rank
Newbie
MagefromAntares wrote on Yesterday, 16:42:

There is one of the functions I have used with Watcom C/C++ to wait for vsync, it is very similar, but there might be some difference in the way it is actually compiled as it uses the inline assembler syntax instead of the header pragma assembler syntax:

Thanks Mage, that did it. Curious though that the only difference is you explicitly save the state of ax and dx then restore it, which is what the modify of the pragma is supposed to tell the compiler to do. Must admit I didn't think to check the compiled code to see if it actually had or not.

Although why it worked at the time with exactly the same compiler install is strange (literally, I had it zipped up with my batch files for setting up the environment and everything). IIRC the inline asm syntax didn't come until Watcom 11, and even then I think they still recommended using the pragma method... <shrugs>

MagefromAntares wrote on Yesterday, 16:42:

EDIT:
If it drops to exactly 30 and 15 fps then it means that it vsyncs to half or quarter of 60Hz instead of the 70Hz that the original VGA has, but Dosbox might emulate the VGA mode running the actual display of the computer you are using with a 60Hz refresh mode, and dropping down to 30 and 15 fps is a behaviour very possible when the CPU is too overloaded to get to the vsync loop with enough cycles to spare, so it syncs to half or quarter of the actual vsync frequency instead.

Yeah, it was one of my first efforts so isn't in the slightest bit optimal - I cringed when I first looked at what the code was doing! I apparently also tried making a mode-x version of it and looking at that code and re-reading Abrash's black book it was very obvious I had little real understanding of the advantages of that mode at the time.

Thanks again!

https://rogueone.uk Kyro and other things

Reply 3 of 3, by MagefromAntares

User metadata
Rank Member
Rank
Member
hornet1990 wrote on Yesterday, 19:11:

Although why it worked at the time with exactly the same compiler install is strange (literally, I had it zipped up with my batch files for setting up the environment and everything). IIRC the inline asm syntax didn't come until Watcom 11, and even then I think they still recommended using the pragma method... <shrugs>

This is exactly why I sent one of my non pragma version of vsync to check 😀, while the pragma method is the preferred one for inline assembly in Watcom C, it also opens up the assembly code for compiler optimization, the modified register list at the end of pragma is to tell the compiler that which registers after the call is in a modified state, it is possible in the case of your code the optimizer made a mistake of what registers were required to push and pop.

hornet1990 wrote on Yesterday, 19:11:

Yeah, it was one of my first efforts so isn't in the slightest bit optimal - I cringed when I first looked at what the code was doing! I apparently also tried making a mode-x version of it and looking at that code and re-reading Abrash's black book it was very obvious I had little real understanding of the advantages of that mode at the time.

If you cannot vsync to the exact 70hz VGA frequency don't worry about it, even John Carmack with Doom decided to go with 35 FPS for the original DOS Doom because keeping a stable 70 FPS was considered even by John Carmack himself to be unstable. Mostly only non-interactive demos syncs to 70hz, for interactive applications syncing to half the refresh rate of VGA is enough.

"A process cannot be understood by stopping it. Understanding must move with the flow of the process, must join it and flow with it." - Dune