Antique Display Driving

Here’s a preview of something I’ve been slowly working on, bit by bit:

Windows 1.04 Reversi

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:

High-res 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:

Too fast to be considered fast?

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).

Windows 2.11 fonts

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: AllocSelector and FreeSelector, AllocCSToDSAlias, 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:

Windows 1.04 Write, nearly working

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:

Write in default Windows 1.0 colors

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.

Palette demo on Windows 1.04
This entry was posted in Development, Microsoft, Windows. Bookmark the permalink.

36 Responses to Antique Display Driving

  1. Richard Wells says:

    Congratulations of getting Windows running at higher numbers of colors. How slow is the repainting of uncovered regions?

  2. Michal Necasek says:

    It’s not slow at all. Of course I’m running this on hardware that’s many orders of magnitude faster than what was available in Windows 1.x/2.x/3.x days. The bank switching slows things down but it’s not bad. A linear framebuffer would be faster but getting that working in real-mode Windows would have been far too ugly. Not impossible, just too nasty and complex for the expected payoff.

  3. JRD says:

    What, a 256-color driver, and no screenshots of PALETTE.EXE? πŸ™‚

    More seriously, I’d be interested in the source when you’re finished, especially on the difference between 1.x and 2.x. Because I’ve been playing with the Tandy 2000 version of Windows 1 in MAME emulation, and I’ve been curious what Windows 2.x on the T2000 would have been like. Tandy only wrote T2000 drivers for 1.x. and 1.x drivers don’t work on Win 2.x. It would be a lot of work to convert because all of the drivers, not just Display, would have to be custom-converted from 1.x to 2.x (and assuming it would still run on the custom T2000 DOS 2.11 ), but it’s a neat goal to try for.

    The Tandy 2000 display introduced shared color-planes memory layout before the EGA did, plus the memory map is high up so you get more memory for Windows than a PC can give you.

  4. Spiral says:

    Thirty years ago my old man bought an IBM XT back from work – they were chucking them out and he liberated it from the skip. We upgraded it with an 8-bit VGA card (Paradise, I think it was), then after upping the RAM to the full 640K I managed to get a copy of Windows 3.0 from the small ads in the local newspaper (no eBay back then!)

    Much to my annoyance, it would only display in mono. I had been expecting the same 16 colours that we had on our RM Nimbus 186 PCs at school and it looked kind of crummy in just black and white – no 3D effects on the GUI buttons, for example. Attempting to switch to colour VGA just locked things up every time.

    It was only decades later that I read the reason was the colour VGA driver for Windows 3.0 used 186 opcodes, hence it would never have worked on an XT.

    If only I had this driver back then! Mind you, Windows 3.0 was s-l-o-w on that 4.77MHz 8088 chip – you could actually see the GUI elements pop up in sequence when a dialog box was being shown, for example.

  5. Michal Necasek says:

    I’ve never seen Windows 3.0 on an XT class machine but from people who have, I heard that it was not a pleasant experience. XTs were on the way out at the time, but quite a few were still in service.

  6. Yuhong Bao says:

    I wonder why Wes Cherry only got an XT for the work on Solitaire.

  7. Michal Necasek says:

    Because he was an intern. They probably said “hey, we want to make sure it still runs (crawls) on an XT”.

  8. Yuhong Bao says:

    Admittingly there was a DRAM shortage at the time, but protected mode Windows is very different from real mode.

  9. Peter Hoeg says:

    I’m absolutely going to add “aggressively cheerful” to my vocabulary.

  10. Michal Necasek says:

    I added a screenshot of PALETTE.EXE. It uses dithering, I didn’t investigate how the driver could use more solid colors (I am pretty sure it could).

  11. Darkhog says:

    I wonder how Win 1.x would look on an 1080p widescreen display resolution. Since it is in the range supported by that driver. Probably the UI would be absolutely tiny and stretched, but by how much?

  12. Richard Wells says:

    Win 1.x should have no problems with 1080p if the driver was correctly implemented. The Moniterm Viking I had a resolution of 2048 by 960 and people paid $2600 to use that with Windows Pagemaker. That is close enough to 1920 by 1080 for indicating expectations.

    The major problem with Windows applications came later with a lot of Win 3 and 95 programs having dialog boxes carefully crafted for 640×480. With higher resolutions and larger fonts, list boxes had very few lines available. Describe doesn’t handle 1080p or higher resolutions very well.

    Performance of Windows on an XT was fairly good. Excel came close to matching Lotus 1-2-3 2.x on the same hardware. Without EMS, the system was largely single tasking. The whole floppy only Windows was a massive waste of development time. The reason turbo XTs didn’t see Windows too often was the overall expense of the system. Plug in a good video system and respectable hard drive and a turbo AT offered twice the performance for a 10% increase in cost.

  13. John Elliott says:

    When I got the IM-1024 emulation in PCEM working enough to run the Windows 1 driver, I found that it used 8-bit truecolour (rrrgggbb) rather than dithering (example screenshot: http://www.seasip.info/DOS/Win1/Images/win1_256f.png). Interesting to see another (and more widely applicable) take on Windows 1 in 256 colours.

  14. Michal Necasek says:

    Very interesting. What are those fonts? Something VMI shipped with their drivers? Just curious because Windows 1.x does not even come with any fonts designed for square pixels. I could borrow fonts from Windows 2.x though, with a bit of conversion work.

  15. Chris M. says:

    Looks like a custom font. The difference in palettes is likely due to the IM-1024 driver having a proper global 256 colors. Its kinda weird that the IBM PGC didn’t get Windows 1.0 drivers despite only being 1 year old at the time. Maybe it was a tad too complex to figure out drivers?

    How did you reverse engineer the font format? I know the 1.0 DDK isn’t floating around making this task difficult.

  16. Michal Necasek says:

    The Windows 1.0 SDK documents the font format well enough. I scanned the Programmer’s Reference myself and the PDF is on this site, so that wasn’t particularly hard to find πŸ™‚

    Windows 1.0 was an obscure, nearly useless toy and I doubt the OEMs wrote drivers just for the heck of it, the work would have been significant. Presumably VMI had customers who wanted to run Windows, and IBM didn’t.

  17. John Elliott says:

    The font comes from VMILO.FON in the Windows 1.03 driver pack (V1DSK.ZIP at http://cd.textfiles.com/carousel/030A/ ). I think the same character bitmaps must also have been present in the card ROM, because the driver uses a different drawing opcode when drawing in that particular font. In emulated form I used a fake ‘character ROM’ generated from VMILO.FON using psftools.

    I think it would have been difficult to get a PGC driver working with a reasonable level of performance — copying bitmaps from the PGC to system memory or vice versa is a slow and awkward operation. The IM-1024 command set is a superset of the PGC, and among the extra operations it implements are faster screen-to-screen and screen-to-memory blits.

  18. Victor Khimenko says:

    Actually you are not fully connect.

    MOST versions of Windows 1.x don’t come with fonts for square pixels. Because they were released before VGA and, of course, couldn’t support VGA.

    But there are one exception: Windows 1.04 for PS/2.

    That one supposed to support VGA and, of course, VGA uses square pixels.

    WinWorldPC have the image: https://winworldpc.com/product/windows-10/104

  19. Jb881122 says:

    Hi Michal,

    I just stumbled upon this page after seeing it posted on BetaArchive. I worked on a similar project a few months back with getting Windows 1.0 DR5 to support different color modes and screen resolutions and got it to display at up to 8K resolution and 24-bit color (https://cdn.discordapp.com/attachments/942977818109833256/963263527160807444/dr5_7680x4320.png). My approach, however, was to write it nearly from scratch in C and have functions for plotting and getting pixels, which could then be ported to various devices. It’s slow as a snail (and still incomplete), but extremely flexible. It also can be compiled for Alpha and Beta releases, but support for those is buggier. I hope you make more headway on your project, since it would be a lot faster to use “native” drivers instead of pushing a bunch of stuff to the stack and calling a function for every pixel drawn.

  20. calvin says:

    Honestly, I think writing it in C is the better option, even if you have to implement GDI and friends yourself. Lots of fun possibilities. Would love to see the source for both drivers, as a fellow Windows 3.x driver writer!

  21. Julius Schwartzenberg says:

    Have you considered using it with DOSEMU2? http://github.com/dosemu2

    It’s been challenging to find a good win31 driver that works. The Trident and Super VGA (VESA) drivers are somewhat buggy.

  22. Michal Necasek says:

    Modifying working assembly source is IMO a lot less work than writing in C from scratch, but that probably depends on one’s comfort level with assembly. I wouldn’t call myself a good assembly programmer but I’m good enough that working with the existing code base is not hard.

    Yes, writing a GDI renderer in C is certainly possible, but it is far from trivial and can be problematic in an environment that isn’t entirely C-friendly. Though I think a pure Win16 driver is much cleaner than the mixed 16/32-bit environment in Win9x.

  23. Chris M. says:

    Would it be possible to write one universal driver for 1.0-3.x and just throw a ton of ifdefs for the newer GDI functions? The build script would have to handle the correct resources during linking of course.

    It’s totally cool, impractical, and cursed computing. Just like running Windows 1.0 in 8K resolution, which I didn’t think was possible. I read something ages ago that stated the Windows 3.1x driver model was limited to 4MB of video RAM or something.

    Clearly hardware vendors were taking the safe route of using the reference driver as a base. Writing everything from scratch risked breaking compatibility.

    @Julius. DOSBox and VirtualPC emulate a Trio64, which seems to have stable drivers. The cirrus video (PCI based CL-GD5446) in QEMU should have stable drivers as well. Both chips were well regarded for compatibility back in the day and have drivers for a wide variety of OSes.

  24. Michal Necasek says:

    Yes, conditional compilation is totally possible. For the most part, it is not even strictly necessary because newer Windows versions add GDI calls but don’t modify existing ones (Windows 1.x vs. 2.x fonts are one big exception).

    The driver resources are the biggest practical issue and I don’t think there’s any easy way to have a single binary because of that, due to the resource format differences between Windows 2.x and 3.x.

    There are also numerous Windows kernel calls that a Windows 3.x driver must use but which don’t exist in Windows 2.x. These functions could be dynamically queried at runtime, but again that would make the driver bigger, which is not great for real-mode Windows.

    ETA: And yes, compatibility is a good reason for not writing from scratch. There are often non-obvious corner cases that software relies on, sometimes by accident.

  25. Hernan Di Pietro says:

    Very nice retro experience. A question that I always had when I used Windows 3.x video drivers: what was the purpose of Grabber devices, which had typically 2GR and 3GR extension and described in the file info as. 286 or 386 Grabber?

  26. Michal Necasek says:

    The grabber modules are designed for interfacing with DOS applications. Initially their main purpose was to “grab” the video state of a DOS application so that it could be saved, shown in a window or printed, and restored again. With Windows/386 the grabbers also draw the client area of DOS applications running in a window.

    In other words, grabbers do nothing for Windows applications but are very important for DOS applications.

  27. Ms. Argent says:

    Very nice! Might be fun to take for a spin on my DeskPro 386 – VGA is nice and all, but Windows/386’s weird reduced res workaround for windowed DOS programs always looked a little odd to me.

  28. Joshua says:

    Hello everyone! I’m not sure if that’s helpful, but toastytech.com has a copy of the ancient “PC Magazine Labs Performance Tests” benchmark, both for 1980s Windows and OS/2 Presentation Manager. I think it’s related to the later “WinBench” series.
    Personally, I got it to run on Windows 2.03 and its visual sibling, OS/2 v1.1.
    Maybe it’s useful to compare graphics performance of earlier and newer incarnations of those systems. Or Win-OS/2 vs OS/2, NT vs OS/2, Win-OS/2 vs WoW..

    Direct link: http://toastytech.com/guis/PC%20Magazine%20Labs%20Permance%20Tests.zip

    WinBench: https://www.vogons.org/viewtopic.php?f=63&t=48762

    Best regards, vy73, Joshua

  29. Joshua says:

    “I’ve never seen Windows 3.0 on an XT class machine but from people who have, I heard that it was not a pleasant experience. XTs were on the way out at the time, but quite a few were still in service.”

    Windows 3.0 has a Real-Mode kernal which supports Expanded Memory in a more sophisticated way. Not only does it support Large Frame EMS (256KB frame) in addition to the normal Small Frame EMS (64KB frame), but it also makes Expanded Memory available through the usual Windows API. That’s something which Windows 2.x wasn’t capable of yet, if memory serves.

    Anyway, long story short: Windows 3.x needs contiguous memory to properly function, generally speaking. Without it, the internal memory manager has a lot of work to do. Even if Expanded Memory isn’t exactly “contiguous”, it has a mapping capability to make up for it. Conventional memory and XMS rather rely on copy-operations.

    Now, considering that the 8086/8088 “had to do effective address computation using its general ALU” (src: 80286 article, Wikipedia), I suppose it’s no wonder Windows 3.0 wasn’t blazing fast on the average, underpowered PC/XT. With a real CPU, a NEC V20/30 or 80286, it might have been a better overall experience. – An AT-Bus or XT-IDE HDD instead of a stereotypical slow MFM/RLL HDD with a wrong interleave-factor would have helped, as well, hi. πŸ˜‰

    Or let’s put it this way, an PC/XT system expanded to properly run DESQView would have had run Windows 3.0 much better, as well. A little Expanded Memory board with 512KB to 2MB capacity and EEMS or LIM4 compatibility would have had made a difference. Later Turbo XTs had chipset EMS, also. With Expanded Memory available, Windows 3.0 in Real-Mode will allow the selection of wallpapers, even! πŸ™‚

    Best wishes, vy73, Joshua

  30. Joshua says:

    Hi again, there’s something which I did forget to mention.. As far as I know, Windows 3.0 in Real-Mode supports the old Windows 2.x graphics driver/palette system. It considers 256c as a high colour depth, also. If Windows 2.x drivers are used, Windows 1+2 programs like the picture viewer EASEL, which normally use false colours if run in Windows 3.x in Standard-Mode/Enhanced-Mode, will look fine again. I tried this with the Paradise Professional VGA drivers (PVGA1A, 640×400 in 256; for Windows 2.03/Real-Mode) in DOSBox and on real hardware (Compaq notebook with WD90c30 VGA). Best wishes, vy73, Joshua

  31. Joshua says:

    Hi. Last, but not least, I also recommend having a look at these two links I’ve found.
    They give an idea about how capable the Windows 1/2 video system really was, before it got changed in Windows 3.0.
    Before using palettes, Windows was using dithering and a virtual true-colour approach, which I think was remarkable for its time. Vy73, Joshua

    https://gonnagan.wordpress.com/2011/07/22/windows-2-0-with-256-colors/

    https://web.archive.org/web/20110414135622/http://members.chello.at/theodor.lauppert/windows/colors/

  32. Pingback: Win16 Retro Development | OS/2 Museum

  33. Pingback: A House of Cards | OS/2 Museum

  34. Pingback: Windows 3.x VDDVGA | OS/2 Museum

  35. Yuhong Bao says:

    “There are also numerous Windows kernel calls that a Windows 3.x driver must use but which don’t exist in Windows 2.x.”
    One thing I wished was one of them was a routine to set/get the interrupt flag. DPMI clients must use INT 31h calls to enable/disable interrupts but that would not work in real mode.

  36. Cyberdyne says:

    I know that there are Windows 3.1 VESA 256 color driver, but maybe we get also VESA 256 color for 3.0 and 2.x and even 1.x? So are those drivers vesa compatible or only using some special emulator capability?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.