Here’s a preview of something I’ve been slowly working on, bit by bit:
That screenshot surely looks a little funny. That’s because it is Windows 1.04 running with a heavily modified 256-color Windows 3.x display driver, using resources from a Windows 2.0 VGA driver.
This is mostly the same driver, running real-mode Windows 3.0:
This is the same driver breaking Microsoft’s DDTest utility in Windows 3.1. DDTest is meant to assess performance of Windows 3.x display drivers, but it can’t handle the speed:
DDTest is a little bit buggy and if the display is too fast, it thinks the performance is “poor”.
For good measure, this is again mostly the same driver, running Windows 2.11 and using 8514/A style big fonts (and icons, bitmaps, and cursors).
How did I get there? I started with the 256-color Video 7 driver from the Windows 3.1 DDK. I threw out all the Video 7 specific hardware rendering code and replaced the mode setting logic with code that runs on VirtualBox. The driver is thus a sort of ancestor of the Windows 9x video minidriver.
I had to fix a couple of extremely nasty problems that probably didn’t show up with Video 7 hardware, or at least not usually, but popped up when the generic software rendering was used.
One of the bugs had to do with drawing patterned lines and manifested itself by leaving behind very visible trails when dragging window outlines around. That bug probably would have been seen with the original driver when rendering into memory bitmaps, but without the frequent XOR redraws it would have been extremely difficult to spot.
Another bug was related to software cursor drawing, and again was probably unlikely to trigger with Video 7 hardware because the hardware cursor would have been used more or less all the time.
I also extended the resolution support to go beyond 1024×768 (limit of the original Video 7 driver) up to somewhere around 2048×1536. Note that the driver supports strictly 8 bpp only. Different color depths would require different rendering code.
Once Windows 3.1 worked to my satisfaction, I made a few minor tweaks for the driver to run with Windows 3.0. The changes were very small and the biggest issue were the driver resources. For some reason I still don’t understand, Windows 3.0 failed to load the OEMBIN FONT resource, which caused very interesting failures with fonts.
I also switched around the bitmap, cursor, and icon resources so that Windows 3.0 would use the smaller “96 DPI” variants. Windows 3.1 supports multi-DPI drivers and the driver can tell Windows which resources to use through the
GetDriverResourceID callback. The same binary can run on both Windows 3.0 and 3.1, but on Windows 3.0 the resources are fixed and can’t be adjusted at run-time.
Then I thought, hmm, what would it take to get the driver to run on Windows 2.x? That was a bit more work. It required dropping all APIs that were added in Windows 3.0 to support protected mode:
PrestoChangeoSelector, and more.
However, the GDI rendering functionality remained more or less completely unchanged. That is, GDI in Windows 3.x is strictly a superset of Windows 2.x GDI, with more capabilities (such as palette manager support, transparent blits, etc.) but no changes to existing functionality.
There was again work needed on resources: Microsoft significantly changed the resource format between Windows 2.x and 3.0. Annoyingly, resource compilers and other tools designed for Windows 3.x can’t work with Windows 2.x resources at all. The resource compiler for Windows 2.x has to be used. But that is not an insurmountable problem, and the driver works with Windows 2.x reasonably well.
And then I thought, what the heck, can I make it work on Windows 1.x as well? The answer is yes, but… it was a lot of work. Windows 1.x GDI is again mostly a reduced subset of Windows 2.x GDI, with one big exception: Fonts.
As it turns out, Microsoft significantly reworked the font format between Windows 1.0 and 2.0. In Windows 1.0, all characters are effectively stored in a single wide bitmap, tightly packed together. In Windows 2.0, each character is stored separately, and in column-first (rather than row-first) order. To make matters more fun, the Windows 2.0 SDK documentation is completely wrong and describes the font format incorrectly; it notes that the font format was changed from Windows 1.0, but claims that character bitmaps are stored row by row, when in reality it’s column by column. The Windows 2.1 SDK documentation was corrected and no longer lies (or at least not as much).
The Windows 2.0 font format is easier for the driver to work with, although it is less memory efficient. As an aside, Windows 3.0 introduced yet another font format, though only in protected mode. The 3.0 font format is very similar to the 2.0 format but uses 32-bit pointers, and is thus not limited to 64KB. I assume that with the advent of ATM and later TrueType, combined with higher display resolutions, the 64KB font limitation became too much of a problem.
At any rate, reworking the driver to support Windows 1.0 fonts was quite difficult and is not fully finished yet. The font code in the driver is extremely complicated, with lots of special cases and many parts of code accessing the font data, sometimes in not very obvious ways.
Here’s a screenshot of Write, showing occasional clipping problems at the ends of lines:
It’s not perfect but it is mostly working. So far I made no attempt to use Windows 1.x style resources for the driver, which is why it looks a bit like Windows 2.0.
In the process, I learned to use WDEB386 and SYMDEB (they’re very similar but sometimes weirdly different), and I learned to both appreciate and dislike complex MASM macros that the driver uses a lot.
All in all, an interesting adventure in retro development.
Update: Below is more or less the same screenshot of Write in Windows 1.04 as above, but now using the aggressively cheerful Windows 1.0 colors and the default window decorations:
Later Update: Below is the PALETTE.EXE demo running on Windows 1.04. It uses dithering to display most colors, but with the relatively high resolution it works okay. I believe the driver does not try very hard to use a large palette of physical colors, given that it’s meant to be used with Windows 3.1 which has the palette manager. That could probably be changed.