-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add README, screenshot, and tool used to produce screenshot
- Loading branch information
Showing
3 changed files
with
153 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# vbesvga.drv and vddvbe.386 | ||
Modern Generic SVGA driver for Windows 3.1 | ||
|
||
This is a rewrite of the Windows 3.1 SVGA driver, designed to support **ALL** available 8-bit, 16-bit, 24-bit or 32-bit graphic modes on any system providing the [VESA BIOS Extensions](https://en.wikipedia.org/wiki/VESA_BIOS_Extensions) (hence the `VBE` in the name). It is based on the Video 7 SVGA driver included in the [Win16 Driver Development Kit](http://www.win3x.org/win3board/viewtopic.php?t=2776), with most of the hardware-specific code gutted out, and with support added for multi-byte pixels. | ||
|
||
## Why on Earth did I make such a thing? | ||
|
||
* To demonstrate that it's possible to run Windows 3.1 in True-Colour Full HD | ||
* Because my AMD Radeon RX 5500 XT doesn't support 256-colour modes, rendering the old [VESA Patch](http://www.win3x.org/win3board/viewtopic.php?t=5408&hilit=svga) useless for me | ||
* To help out any fellow enthusiasts who like running old software on new hardware! | ||
|
||
## Screenshot | ||
|
||
![True-Colour Full HD screenshot of Windows 3.1 desktop showing colour settings (on "Bordeaux"), Program Manager, two MS-DOS prompts of different sizes, Solitaire and Minesweeper](./Screenshots/VBESVGA.CLP.rec0.png) | ||
|
||
This True-Colour Full HD screenshot gives you some idea of what's working so far. The colour settings dialogue shows that pretty much the entire Windows GUI renders correctly, and the Program Manager shows icons working well too. The two windowed DOS prompts demonstrate that I am running this on MS-DOS 6.20, and that I'm using a real AMD graphics card with [vendor string](https://fd.lod.bz/rbil/interrup/video/104f00.html) equal to `(C) 1988-2018, Advanced Micro Devices, Inc.` and [product name](https://fd.lod.bz/rbil/interrup/video/104f00.html) equal to `NAVI14`. Minesweeper looks OK, while Solitaire is mostly working, but a few glitches are evident... | ||
|
||
See the Issues page for more details of what is _not_ working at the moment... | ||
|
||
## Building | ||
|
||
### `vbesvga.drv` (needed in both Standard and 386 Enhanced Mode) | ||
|
||
* Install both the [Win16 DDK](http://www.win3x.org/win3board/viewtopic.php?t=2776) and [a contemporary version of Visual C++](http://www.win3x.org/win3board/viewtopic.php?t=1375) | ||
* Place the `VBESVGA` folder from this repository in the DDK hierarchy, at `286/DISPLAY/8PLANE/VBESVGA` | ||
* Ensure `286\TOOLS` from the DDK and `MSVC\BIN` from Visual C++ are in your `PATH` | ||
* Go to the `VBESVGA\mak` folder and run `make vbesvga.mak`; this should create the file `VBESVGA.DRV` which can be loaded by Windows | ||
|
||
### `vddvbe.386` (needed only in 386 Enhanced Mode) | ||
|
||
* Place the `VDDVBE` folder from this repository in the DDK hierarchy, at `386/VDDVBE` | ||
* Ensure `386\TOOLS` from the DDK and `MSVC\BIN` from Visual C++ are in your `PATH` | ||
* Go to the `VDDVBE` folder and run `nmake`; this should create the file `VDDVBE.386` which can be loaded by Windows | ||
|
||
### Tip for using the DDK on a modern system | ||
|
||
To make the debugger `WDEB386` work, you need to change some bytes: | ||
|
||
* At position `63D8`, you need to change `0F 24 F0` to `66 33 C0` | ||
* At position `63DF`, you need to change `0F 24 F8` to `66 33 C0` | ||
|
||
This removes references to the [`TR6` and `TR7` registers](https://en.wikipedia.org/wiki/Test_register), which crash the system since they only existed on the 386, 486 and a few other less-well-known chips! | ||
|
||
## Usage | ||
|
||
The following changes are needed to your `C:\WINDOWS\SYSTEM.INI` file: | ||
|
||
* In the `[boot]` section, change the `display.drv=` line to point to `vbesvga.drv`. You should specify the full path, or else copy the file to `C:\WINDOWS\SYSTEM`. (Note that if the path is too long, it can cause the CodeView debugger to crash on startup!) | ||
* In the `[386Enh]` section, change the `display=` line to point to `vddvbe.386`. Again, you should specify the full path, or else copy the file to `C:\WINDOWS\SYSTEM`. | ||
* Create a `[VBESVGA.DRV]` section to configure the driver, as detailed [below](#configuration-parameters). | ||
|
||
## Configuration parameters | ||
|
||
This table lists the parameters you can specify in the `[VBESVGA.DRV]` section of `SYSTEM.INI`. | ||
|
||
|Parameter |Valid values |Meaning |Default value | | ||
--- | --- | --- | --- | ||
|`Width` | 640 - 65535 | Width in pixels of the desired video mode | 1024 | | ||
|`Height` | 480 - 65535 | Height in scanlines of the desired video mode | 768 | | ||
|`Depth` | 8 - 24 | Significant bits per pixel of the desired video mode ("significant" means that padding bits are excluded, so for example if you choose 24, both 24-bit and 32-bit modes will qualify) | 24 | | ||
|`fontsize` | `small` or `large` | Choose whether to use 96dpi or 120dpi fonts | `small` | | ||
|`dacdepth` | 6 or 8 | Significant bits to use per colour in 256-colour modes | 6 | | ||
|`DoubleBufRefreshRate` | 4 - 255 | Number of times per second to swap buffers if double-buffering is enabled | 60 | | ||
|`PMIDcheck` | `disable`, `none`, `sum` or `sanity` | See [below](#protected-mode-interface) | `sum` | | ||
|
||
### Protected-Mode Interface | ||
|
||
The VESA BIOS Extensions spec allows graphics firmware to provide an interface for Protected-Mode drivers. This driver attempts to use this interface where possible, to avoid needing to allocate DOS memory blocks to communicate with the BIOS. In theory, as per Page 21 of [the spec](http://www.petesqbsite.com/sections/tutorials/tuts/vbe3.pdf), the driver should search the segment `C000h` for a structure beginning with the signature `PMID` and ending with a valid checksum to determine whether or not this interface is supported. However, some firmwares don't set the checksum correctly, and some firmwares "provide" the interface but don't do the QA to ensure it actually works. To account for this, four options are provided: | ||
|
||
|Option |Meaning | | ||
--- | --- | ||
|`PMIDcheck=sum` | The default: the driver searches for the structure beginning with `PMID` and verifies the checksum | | ||
|`PMIDcheck=sanity` | A looser setting: the driver searches for `PMID` and makes sure the other values in the structure match the suggested values on Page 21 of the spec; if they don't all match, it falls back to the checksum | | ||
|`PMIDcheck=none` | NO VERIFICATION: the driver just searches for `PMID` and trusts that whatever comes after it is the correct structure | | ||
|`PMIDcheck=disable` | The driver doesn't use the Protected-Mode Interface at all, even if it's available: **Try this if Windows hangs/crashes during boot!** | | ||
|
||
### Example configuration | ||
|
||
``` | ||
[VBESVGA.DRV] | ||
PMIDcheck=sanity | ||
Width=1920 | ||
Height=1080 | ||
Depth=16 | ||
DoubleBufRefreshRate=75 | ||
``` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
#!/usr/bin/python3 | ||
from PIL import Image | ||
from sys import argv | ||
from construct import * | ||
import os.path | ||
|
||
if len(argv) < 2: | ||
print("You need to specify the CLP path as an argument!") | ||
exit() | ||
|
||
BITMAP = Struct( | ||
"bmType" / Const(0,Int16ul) * "Must be a memory bitmap", | ||
"bmWidth" / Int16ul * "Width in pixels", | ||
"bmHeight" / Int16ul * "Height in rows", | ||
"bmWidthBytes" / Int16ul * "Width in bytes", | ||
"bmPlanes" / Int8ul * "Planes in the bitmap (we only deal with flat ones)", | ||
"bmBitsPixel" / Int8ul * "Bits per pixel", | ||
"bmBits" / Const(0,Int32ul) * "In a file, the pointer is NULL", | ||
"Bits" / Bytes(this.bmHeight * this.bmWidthBytes) * "In a file, the actual data directly follows the header", | ||
) | ||
|
||
FORMATRECORD = Struct( | ||
"FormatId" / Int16ul, | ||
"DataLength" / Int32ul, | ||
"DataOffset" / Int32ul, | ||
"FormatName" / CString("ascii"), | ||
"Data" / Pointer(this.DataOffset, | ||
Switch(this.FormatId, {2: BITMAP,}, Bytes(this.DataLength)) | ||
), | ||
) | ||
|
||
CLPHEADER = Struct( | ||
"FileId" / Const(0xC350,Int16ul), | ||
"FormatCount" / Int16ul, | ||
"ClpRecords" / Array(this.FormatCount, FORMATRECORD), | ||
) | ||
|
||
clpfilename = argv[-1] | ||
clpbasename = os.path.basename(clpfilename) # For saving result into cwd | ||
clpfile = CLPHEADER.parse_file(clpfilename) | ||
|
||
for idx,record in enumerate(clpfile.ClpRecords): | ||
if "Bitmap" not in record.FormatName: | ||
print(f"Record {idx} not a bitmap, skipping...") | ||
continue | ||
bitmap = record.Data | ||
if bitmap.bmPlanes > 1: | ||
print(f"Record {idx} not a flat bitmap, skipping...") | ||
continue | ||
# We have a good flat bitmap, get its size into a tuple | ||
size = (bitmap.bmWidth, bitmap.bmHeight) | ||
if bitmap.bmBitsPixel == 24: | ||
image = Image.frombytes("RGB",size,bitmap.Bits) | ||
elif bitmap.bmBitsPixel == 32: | ||
# The extra eight bits are just padding | ||
image = Image.frombytes("RGBX",size,bitmap.Bits).convert("RGB") | ||
else: | ||
print(f"Record {idx} is a {bitmap.bmBitsPixel}-bit bitmap, but only 24- or 32-bit are supported, skipping...") | ||
continue | ||
# A lot of the time, these DDBs are actually BGR or BGRA | ||
if "--swapchan" in argv: | ||
b,g,r = image.split() | ||
image = Image.merge("RGB",(r,g,b)) | ||
# Save it as a PNG | ||
pngname = f"{clpbasename}.rec{idx}.png" | ||
print(f"Saving record {idx} as {pngname}...") | ||
image.save(pngname) |