Obsolete SolVBE downloads:
follow the link for later releases and docs
Now that that's over with..
SolVBE is an universal VESA 1.2 driver for Win2k and WinXP.
It started from my frustration of getting Terra Nova: Strike Force Centauri running under Windows XP. Some people got TN:SFC running under XP with some hacky VBE "drivers" which just disabled VESA 2.0 linear framebuffer, and thus forced TN to use VESA 1.2 interface.
Unfortunately (or fortunately, depending on your point of view), I couldn't get VESA 1.2 modes working with my display adaptor (Radeon 9700 Pro) under Windows XP. Either the VESA BIOS on the card is broken, or windows, or the display adaptor's own drivers conflict with it. In any case, I was stuck.
My options were either to run the game under DosBox (a dos virtualization effort which allows people to run old DOS games on modern systems), or to wait for VDMSound (soundblaster emulator for NT console) to get VESA support.
DosBox is the way to go, eventually, but currently Terra Nova is too heavy for it. Even on a 2.6GHz P4, the game literarly crawls, before crashing. VDMSound's latest betas have an option saying something about VESA support, but there was no way of telling when or if the support appears.
The alternative was to take the plunge and write my own VESA driver.
So I got my hands on the windows DDK, downloaded OpenWatcom 1.2, and started hacking. Spending my weekends and evenings on the project, in a week and a half (February 24 - March 4) I finally could play TN. Another four days later I had my first full featured beta running and posted on VOGONS.
After that I added simple tweaked mode support (which, unfortunately, doesn't help with Terra Nova due to the way it uses the mode), and tons of tweaking options so that people who have problems can try to get things working.
Let's look at how SolVBE works.
From high enough level, everything looks like a mess.
SolVBE comes in two parts: a 16-bit DOS TSR, which traps the DOS interrupts, and a 32-bit windows VDD, which does the actual work.
The TSR captures interrupts 10h (video services), 33h (mouse services) and optionally either IRQ12 (PS2 mouse) or IRQ0 (timer). The mouse capture is needed since the VDM (Virtual Dos Machine) thinks that we're still in text mode, and thus cannot offer its mouse support.
Additionally, since we're stealing focus from the console, the keyboard events need to be handled. This is done by simply forwarding keyboard events to the console.
The VDD traps several VGA ports. The DDK explicitly says that one should not do that, but it just happens to work right now. It's rather likely that future Windows releases (or even service packs) might render SolVBE unusable because of this.
The ports are used for three things: palette control, vertical retrace simulation, and tweak modes.
The palette control is pretty much mandatory. Although VESA interface includes palette setting functions, pretty much all applications program palette directly through VGA ports.
Vertical retrace simulation is important for two reasons; first being speed (for applications that are frame-bound instead of time-bound), and second being palette synchronization. If vertical retrace isn't simulated properly, some applications will show wrong colors causing irritating blinking to occur.
Tweak modes are achieved by reprogramming the VGA timings. Several different resolutions and refresh rates can be achieved, most famous being 'mode x', 320x240x256 mode which supports page flipping. The other often used mode is 320x400x256. Since these modes use more memory than is available in the video segment (64k), these modes are usually 'planar', meaning that you can only access 1/4 of the memory at any time, but you can switch between the 'plane' you wish to access.
At the time I'm writing this (1.2b), the tweak mode support is pretty basic, and only supports a single-page 320x400 mode.
Interrupt services.
Whenever the DOS application performs an interrupt call, say, to query the current mouse position from the mouse driver via int33h, the TSR captures this call, forwards it to the VDD, which modifies registers in the TSRs stack, and optionally writes something in the application's memory, and then returns access back to the application.
The application never knows that we've just popped into windows protected mode world for a while, and then back. From DOS-era point of view, this is all extremely cpu-power wasting, but we can afford it now.
Display refresh loop
The VDD runs a worker thread which also takes care of the framebuffer window. This thread runs in a loop, and periodically copies memory from the real-mode video segment (a000) to its framebuffer, and then transfers the data to an OpenGL texture, and finally renders this on screen with two triangles.
Additionally, whenever the DOS application changes VESA banks (or tweak mode planes), we need to copy the memory from the video segment into our framebuffer, and we need to copy data back to the video segment from the new location in the framebuffer.
This is because we have no control over what the application does with the video memory. In the worst-case scenario (which happens with Terra Nova: Strike Force Centauri, actually), the application switches tweak mode planes after every single pixel, and thus for a 320x400 screen, we need to transfer a whopping 16777216000 bytes (about 16GB) per frame (or, if we desire 20Hz framerate, 312,5GB/s).
Video setup call chain
SolVBE uses the following buffers for the image data:
The video segment and OpenGL texture are no-brainers, but why use Windows GDI bitmaps for video memory, and why is framebuffer different?
First, GDI bitmaps support 4,8,15,16,24 and 32bit modes. By using those, I don't need to perform any pixel conversions myself; everything "just works". Replacing these with specialized code that just performs the conversions would most likely bring some performance gain, but I don't know if it's worth it.
The framebuffer is pretty much the same thing - pixel conversion. OpenGL's texture format has a different RGB ordering than windows bitmaps generally do, so I'm killing two birds with one stone by blitting the video memory to the framebuffer - first, the pixel conversion is done, and second, byte order is changed to be OpenGL friendly.
Mouse callback.
One unfortunate "feature" in the DOS mouse driver is the mouse callback. It's one of these things that were good ideas at the time, but simulating it on modern machines is a major headache.
Basically, the application registers a function which needs to be called whenever the mouse moves or a button is pressed or released. In order to make this happen, the application flow must be interrupted and this call made. On a real dos machine this is achieved via a hardware interrupt. In our case, we simulate IRQ12 hardware interrupt, and have a tiny piece of code in the TSR which passes the call along to the application.
Unfortunately things don't seem to be this simple. On some applications the mouse movement is very jerky, while others work flawlessly. There are several options one can try in the 1.2b version, including the use of IRQ0 (system timer) instead of IRQ12, and interrupt flooding (where we cause IRQ12 to occur a lot). These are not real fixes, but may help in some cases.
SolVBE has been released under the zlib/libpng license, meaning that you can use the source code for just about anything you like. However, if you make fixes or additions, I'd love to see them so that there's one "good" version of SolVBE.
Any comments etc. can be emailed to me.