VOGONS


Vertical retrace sync patch

Topic actions

Reply 21 of 35, by `Moe`

User metadata
Rank Oldbie
Rank
Oldbie
augnober wrote:

This is because DOSBox's timer isn't very accurate. SDL's timer stuff is based on milliseconds, and vsync deals with numbers on the order of 15ms. I believe the non-visible time is something like 1ms... so, in order to fully fix the problem, I need to use a more accurate timer.

There is "nanosleep", which is part of the POSIX standard (i.e., part of all unixish OSes out there). Windows supposedly support some of POSIX, though I don't know how much. With that, you could implement a busy-wait loop to fine-tune timing. Part of the same standard (and various others) is "gettimeofday", which tells you the current time with microsecond resolution. Then there is "setitimer", again with microsecond resolution. All of these might be of help for unixish platforms, and perhaps you find some of them on windows, too.

Reply 22 of 35, by augnober

User metadata
Rank Member
Rank
Member

Here's a minor update for any curious programmers who may or may not have the patch already..

I looked at the timer stuff a bit. The posted patch is using PIC_AddEvent, just as vsync was using before. It seems to use the emulator's internal cycle timing? If so, then it's remarkably consistent... I think it'd be best for me to trigger the vsync in a different way, avoiding the PIC entirely (apps are rarely very sensitive to the vsync timing anyway). Then there needn't be accuracy problems.

Also, I started doing some win32-only stuff, using DirectDraw's GetScanLine(). In doing so, I noticed that it's probably a good idea for me to replace the following line:
PIC_AddEvent(VGA_DrawPart,vga.draw.delay.parts,vga.draw.parts_lines);
with
PIC_AddEvent(VGA_DrawPart,vsynctimerval-(vga.draw.delay.vtotal - vga.draw.delay.parts),vga.draw.parts_lines);
After making this change, dosbox's usual time interval between rendering and the next vsync will be preserved. This isn't a necessity, but it doesn't hurt either.. so I feel better doing this. It's also sort of necessary for the following --

(warning: incoming rambling -- I'll just say what I did without providing much introduction -- I just feel like mentioning it before I really step away from the code for a while)
So for win32.. I did that, changed VGA_PARTS to 1, disabled the current persistent timer stuff, and put a retrace wait (a real host retrace wait) in VGA_DrawPart() just before the call to RENDER_EndUpdate() -- this makes it so there is never any shearing on the host. Then to keep programs that use vsync working nicely, it's just necessary to choose a quick enough vsyncrate setting to prevent a double wait. Due to the change to the VGA_DrawPart timer mentioned above (the subtraction), there is a safety interval automatically provided and so it's not difficult to choose a good timing (any timing that lands the wait within that interval is fine). Setting it to your real refresh (or even just close to it) makes it work fine, and very little time is spent in the retrace loop because the timer triggers it immediately before the refresh -- the wait loop is the part that fine-tunes the accuracy and preserves the synchronization. The bad news is that programs that don't use vsync may behave badly, because the host will be needlessly waiting for vsync anyway (in some cases, it could make things smooth by luck, but in others, could cause stuttering, audio break-up, whatever).. so it would be a good idea for me to detect 0x3da port reads automatically so that the user really won't need to adjust any settings. It would also be nice for me to make the code automatically detect the appropriate timer setting, to make it unnecessary for the user to set that as well. There's not much work involved, but I'm always just adding a couple changes in a hurry.

Reply 23 of 35, by vasyl

User metadata
Rank Oldbie
Rank
Oldbie

There was a lengthy discussion about that VGA_PARTS some time ago that ended up in a patch currently on Sourceforge. I wonder if you checked that patch (1357903 - Changes to scheduled rendering) as it seems to be relevant to the stuff you are doing. I was also trying to fix tearing but in my case it was completely within DOSBox, not between DOSBox and host.

Reply 24 of 35, by augnober

User metadata
Rank Member
Rank
Member

I'll be taking a plane tomorrow, so I'll be mostly away -- I may be able to check here once in a while though.

Yeah, fixing the tearing in the internal emulation is important too. Though to completely fix the tearing visible to the user, some retrace syncing in some way is required. Fixing internal tearing's important for video output -- maybe good for harekiet's recent work 😀. Anyway, tearing's mostly fixed after my stuff -- only a few odd cases have it (eg. the bouncing ball in Second Reality -- and Crystal Dream 2 needs to be forced to about 60Hz to fix flicker (though I let the user force that too)).

Reply 25 of 35, by nbd

User metadata
Rank Newbie
Rank
Newbie
augnober wrote:

could be of use to someone after video capture is added.

This is working great with my video capture experiment. Now I can set framerate to NTSC framerate 59.94 and create DVD's out of those good old PC intros and demos.

Thanks!

Reply 26 of 35, by ykhwong

User metadata
Rank Oldbie
Rank
Oldbie

Updated for current cvs. Added an item "host" for vsyncmode.
"host" is for win32 only. - I googled some information about video sync but couldn't get any useful data for crossplatform.
Anyway, it synchronizes dosbox vertical framerate with the "current" host monitor frequency, and it may help some games to get out of a stuttering scrolling problem.

[EDIT] Oops, I didn't notice hal's demovga patch that includes ibmtiming.

Attachments

Reply 27 of 35, by augnober

User metadata
Rank Member
Rank
Member

ykhwong:
cool 😀 At a glance, I think your diff will use the correct refresh frequency, but it appears to be lacking code that would get it in sync with the host display (i.e. the frequency/period is correct, but the offset will be wrong because it was never dealt with). If this theory is correct, then the result is that sometimes in places where there should be smooth scrolling, you will see a steady shear line across the screen (try my vsync.com - found in my patch attachment earlier in this thread-, or some pinball games to test (epic pinball is a good test - just keep shooting the ball up an down, and don't let it go into the play area)). The position of the shear line could be different across runs and systems.. and if you're really lucky, it will not be visible because it's synced correctly. If used in conjunction with a hotkey that uses VGA_TweakUserVsyncOffset(), it should work (in the patch I posted earlier, TweakUserVsyncOffset() in gui/render.cpp did this). Alternatively, a single or occasional sync to the beginning or end of a retrace would work as well (and would be a more convenient solution).
Anyway, I haven't tried it yet. Maybe I missed the offset sync'ing code somewhere. I'm applying it and trying it now with my codebase.

I too was able to find good functions to use on Windows, but not crossplatform. It looks like SDL 1.3 is putting an increased focus on refresh issues, so I hope that will lead to better crossplatform solutions.

Edit: I should mention that for the user to get host syncing with the other vsyncmodes, it is basically essential that two or three hotkeys are available to adjust it (one or two for adjusting timing frequency, and another for adjusting the offset), and that the vsync.com executable is available. Otherwise, the user can't set the offset, and would have a really hard time finding the correct frequency. I didn't notice that your build had applied the vsync patch until long after I released the patch.. but I think it didn't make the hotkeys available. This is probably in part because in my patch release, I only enabled one hotkey. As a result of that, I am perhaps the only person who has seen the vsync patch working as designed (I'm sorry for this). Dosbox had a lack of freely available keys at the time, so I didn't know what to do about it.

Edit2: Ok. I've applied your patch (took a little extra time because I have hal9000's experimental vga patch applied too). It basically has the offset problem that I described.. and the shear line moves down slowly too, because the frequency is a bit inaccurate. The shear line is a bit different than I expected because VGA_PARTS is defined to 4 (so you see multiple wild shear lines). For the vsync patch, it is probably best to define VGA_PARTS to 1. Then when running things that have smooth scrolling (such as vsync.com), I can see the shear line drift slowly down the screen (and the shear line bounces a bit due to the inaccuracy of the timer -- a higher precision timer would be better). So, it's necessary to sync to the host retrace offset somehow. Previously, I did this by using DirectDraw's GetScanLine function.. but it is also possible to discover the retrace timing by recording the time of a page flip, or some other way.

Edit3: (whew) I mentioned Epic Pinball. Because I mentioned it here, I decided to see if there's a cheat-code to scroll the screen without needing to move the ball. It turns out that pressing CursorUp or CursorDown scrolls the table, so you don't need to shoot the ball.

Reply 29 of 35, by rarefluid

User metadata
Rank Newbie
Rank
Newbie

Hi guys, I'm posting because I'm not getting anywhere with vsync here.
I have some demos I want to capture to video (especially this). I tried the experimental vsync patch from hal9000 and tried using the
vsyncmode=on/force
vsyncrate=xx.xxx
stuff. but still there's a lot of tearing during the screen flashes. I also tried using the "normal" cpu instead of the "dynamic" one.
I'm using the surface renderer, no scaler and so on, as I only care about capturing to video. I don't care about a refresh rate that fits my display...

The demo uses VESA mode 190h (== 320x240x32bit). I took a look at the disassembly and it probably does some weird stuff to time vsync using the timer (port 40h/43h).

If any of you had some hints for me I'd be really grateful!
There are some demos from the same era that have the same problem, so it would be great if I had a solution for that...

cheers,

rarefluid

...find some video captures of old DOS demos here...

Reply 32 of 35, by gulikoza

User metadata
Rank Oldbie
Rank
Oldbie

do you use dosbox internal video capture or some external program? if internal video capture shows tearing, then there's nothing you can do since that is how the program draws the screen...

http://www.si-gamer.net/gulikoza

Reply 33 of 35, by augnober

User metadata
Rank Member
Rank
Member

rarefluid:
It looks like you got hal9000's experimental vga patch confused with the vsync patch. They are separate patches. This may be the reason you're not getting results. ykhwong's builds are the only ones using the vsync patch (to my knowledge), and it's handy because he also applied the experimental vga patch (which is nice for demos). I haven't looked at his most recent build in detail to see if it's all working.. but it should be okay 😉. Alternatively, you can apply the patches yourself.

I'm interested in demos and captures too.. so I can help out if necessary (I wrote the vsync patch in the first place, and I apologize that I never finished nor packaged it properly).

Reply 34 of 35, by augnober

User metadata
Rank Member
Rank
Member

ykhwong:
I tried the 'host' vsync mode in your latest build. It still has one important problem that I'm not sure you've understood. The offset of the vsync is wrong. In other words, the timer is set to the an approximately correct frequency.. but it is not started at the right time. Because of this, there is usually a steady shear line visible on the screen when smooth scolling is occurring. If working properly, the shear line should not be visible. This is why my original vsync patch includes some extra code for a hotkey which adjusts the offset of the vsync timer. (the ideal solution would be to periodically adjust the offset automatically, using results from DirectDraw's GetScanLine() or something.. but I removed the call to GetScanLine() because it wasn't cross-platform)

For more information about it, you can refer to my longer post above. I think I was a bit too long-winded in that post, so the main concern was lost.

Reply 35 of 35, by NY00123

User metadata
Rank Member
Rank
Member

After a long break, here is a minor update to the patch so it is compatible with a recent SVN revision (3790). I have changed the default refresh rate to 60, as it is very commonly used with computer monitors these days.
The patch has been tested on Linux with X11 only, and I cannot tell what would happen on configurations other than the one I've just tried this on. I haven't done much more than quickly testing it with two games.

Instructions given earlier in this thread would probably apply. Personally, what has worked for me involves the following:

1. Apply these DOSBox settings, where vsyncrate stands for the current display refresh rate:

output=opengl
.
.
.
vsyncmode=on
vsyncrate=60

2. Force VSync for OpenGL mode.
A WARNING ABOUT FORCING VSYNC: This yields in severe slowness within vanilla DOSBox, in portions of some games. When the patch is applied, though, such slowness is resolved, at least in problematic parts of Commander Keen 4 and Wolfenstein 3D. However, there may still be an impact (possibly small) on the DOSBox emulation rate globally.

As a minor note (probably very system-specific), output=overlay implies the usage of XVideo for me, and VSync can be toggled for XVideo apps here. I confirm that by doing both of these I get proper VSync within the patched DOSBox, along with no slowness in the same tested problematic parts. Furthermore, vsyncmode=force seems to do the job as well.

Attachments

  • Filename
    dosbox-vsync-20120809.diff
    File size
    9.4 KiB
    Downloads
    163 downloads
    File comment
    Updated VSync patch for r3790
    File license
    Fair use/fair dealing exception