First post, by NY00123
Please read this first: You should see a later post of mine (from 2012-9-23) for an update to the patch. Especially, it should be noted there is no need to play with the "fulldouble" and "vsyncwait" settings now. As for this post, I'm leaving its original contents for reference.
Original post contents:
Hey all,
I've had the thought of having a second attempt at a VSync patch. An earlier attempt was done by augnober: Vertical retrace sync patch
But now, why should there be any other attempt at all?
Well, the original patch seems to modify the graphics emulation code, while I've thought of a different approach: Modify the way frames are outputted to the screen, but not the emulation itself. The basic idea is to output something only when it is the right time to do so.
Furthermore, a few who aren't yet aware of the consequences may ask something like this: "Can't I just force VSync for OpenGL apps, including vanilla DOSBox with no patches at all?"
Well, it is not working like that in the unmodified DOSBox. After the emulated machine does a screen update, DOSBox attempts to displays it on the screen immediately (along with scaling applied, if any is used). Now, if VSync is enabled in the driver level, a 60Hz display is used but a DOS game wants to render 70fps (or even 60fps), this results in slowdowns: DOSBox needs to wait before a frame can be displayed.
===
How to use this
===
The patch is aimed at SVN revision 3793. You may wish to re-create a new dosbox-SVN.conf file in order to have descriptions of a few new parameters I've added. Or, just read the .diff file for the descriptions. Anyway, these parameters are framecap (a non-negative number), vsync ("false" or "true"), and vsyncwait (a number in the range 1-9999).
===
OpenGL (tested on Windows and Linux)
===
You should set output to "opengl" or "openglnb" and vsync to "true".
===
Surface / DirectDraw (Windows only)
===
Set output to "ddraw" or "surface", vsync to "true" and fulldouble to "true". Note that you probably want "ddraw" to be used.
===
Overlay (NVidia+Linux only)
===
Make sure that you're running Linux with an Nvidia card, using NVidia's drivers. Load nvidia-settings, choose "X Server XVideo Settings" (or similar) and ensure that "Sync to VBlank" is checked.
Now, in the patched DOSBox, set output to "overlay" and vsync to "true".
===
Frame capping
===
As a side effect, this patch lets you apply a frame cap (in FPS) with no VSync. To enable it, set vsync to "false" and framecap to the desired cap. Note that this isn't the main goal of the patch, though. Furthermore, some caps may work better than others on specific conditions.
===
If there are problems
===
You may need to force VSync externally in some way. For OpenGL this is usually achievable as a driver setting. Furthermore, try running DOSBox in fullscreen mode if it's not yet done. If for any reason a measurement of the refresh rate is not done as expected, you may force it via the framecap setting. Finally, lowering the value of vsyncwait may also prove to be helpful, depending on the situation.
Note that by raising vsyncwait a bit, it should give DOSBox more CPU time to process the emulation. If it is too close to the maximum, though, some more frames may be skipped. Slowdowns are also a possibility, although that may not happen.
===
Some relevant ideas
===
- At the moment, if vsync=true and framecap=0, the display's refresh rate is "detected" by measuring it on startup. It takes a little while, although not too much. It could be good to have this done earlier, while the DOSBox splash screen is displayed. However, this is currently done with a fixed mode of 640x400 pixels, using an SDL Surface. Changing this would require some re-shuffling of the code. And then, there are problems to consider when it comes to many possible resolutions being involved.
- Oh, and before you're asking, I'm not currently aware of a reliable and cross-platform way to retrieve the active display's refresh rate, using a function intended for that.
- One issue that VSync cannot solve is the fact that different refresh/frame rates are different. So, if you run a game made for a display mode of 70Hz while your monitor does 60Hz, expect things to be a bit less smooth than on the real thing.
- I have considered trying to solve this by the way of "linear motion interpolation". That is, apply linear interpolation to the frames. This should be possible with OpenGL, taking advantage of Alpha blending. However, it would have a few issues. One is that it'd change what one sees, probably adding a kind of a "ghosting" effect. The other is that it can smooth things out. Think of interpolating Keen 4 or Doom from 35fps to 60fps. Truly, if an approach similar to the "normal2x" scaler is used here (for frames), it may be reduced, but I'm not so sure at the moment.
- The patch in its current form uses a buffer in system memory for drawing (e.g. using a scaler). If output is set to "surface" or "ddraw", the buffer resides in another SDL Surface.
- In an earlier revision of the patch, no frame would be outputted while a new frame is being generated (e.g. with the help of a scaler). While this means that a few frames could be missed, the loss didn't seem to be that great. Furtherhe did state it was not made to work with actual hardware VSyncmore, an extra buffer like the one I've just described hasn't been used, with the exception of a "blit" buffer with output=surface, even when fulldouble=false. With a few more changes this "older" approach may help with the timings in some way, although I'm not sure about this at the moment.
===
To finish
===
I can only hope the patch is going to work as expected. Problem is that the way things are done, they are somewhat sensitive to timing. So, things may easily go wrong!