aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaroslav Hensl <emulator@emulace.cz>2023-04-10 14:53:37 +0200
committerJaroslav Hensl <emulator@emulace.cz>2023-04-10 14:53:37 +0200
commit503e91046f60a86823629d43e64e2d0fcc006549 (patch)
tree7f4815da1ae1a94ede4d35aeb32b7ec2b32427e2
downloadvmdisp9x-503e91046f60a86823629d43e64e2d0fcc006549.tar.gz
public release
-rw-r--r--.gitignore16
-rw-r--r--LICENSE21
-rw-r--r--README.md64
-rw-r--r--boxv.c171
-rw-r--r--boxv.h52
-rw-r--r--boxv9x.def67
-rw-r--r--boxvint.h149
-rw-r--r--code32.h4
-rw-r--r--control.c624
-rw-r--r--control_svga.c2
-rw-r--r--control_vxd.c212
-rw-r--r--control_vxd.h10
-rw-r--r--dbgprint.c288
-rw-r--r--dbgprint32.c2
-rw-r--r--ddk/dibeng.def49
-rw-r--r--ddk/dibeng.h248
-rw-r--r--ddk/dibeng.lbc46
-rw-r--r--ddk/gdidefs.h828
-rw-r--r--ddk/minivdd.h114
-rw-r--r--ddk/valmode.h20
-rw-r--r--dibcall.c114
-rw-r--r--dibthunk.asm114
-rw-r--r--docs/font-bug.pngbin0 -> 25491 bytes
-rw-r--r--dpmi.h119
-rw-r--r--drvlib.c48
-rw-r--r--drvlib.h7
-rw-r--r--enable.c465
-rw-r--r--init.c176
-rw-r--r--intr.h248
-rw-r--r--io.h94
-rw-r--r--io32.h113
-rw-r--r--makefile325
-rw-r--r--minidrv.h132
-rw-r--r--minivdd32.h112
-rw-r--r--minivdd_func.h70
-rw-r--r--minivdd_svga.c325
-rw-r--r--modes.c621
-rw-r--r--modes_svga.c2
-rw-r--r--palette.c89
-rw-r--r--palette_svga.c2
-rw-r--r--readdev.txt89
-rw-r--r--readme-orig.txt13
-rw-r--r--res/boxvmini.rc19
-rw-r--r--res/colortab.c62
-rw-r--r--res/config.c74
-rw-r--r--res/display.rcv82
-rw-r--r--res/fonts.c6
-rw-r--r--res/fonts120.c6
-rw-r--r--res/fonttmpl.c55
-rw-r--r--res/vmws_vxd.rc12
-rw-r--r--res/vmwsmini.rc19
-rw-r--r--scrsw.c229
-rw-r--r--scrsw_svga.c2
-rw-r--r--sswhook.asm126
-rw-r--r--tools/copyinf.c208
-rw-r--r--types16.h40
-rw-r--r--version.h34
-rw-r--r--vmdisp9x.inf196
-rw-r--r--vmm.h704
-rw-r--r--vmware/pci.c277
-rw-r--r--vmware/pci.h101
-rw-r--r--vmware/pci32.c2
-rw-r--r--vmware/svga.c1971
-rw-r--r--vmware/svga.h153
-rw-r--r--vmware/svga32.c2
-rw-r--r--vmware/svga3d.c1222
-rw-r--r--vmware/svga3d.h149
-rw-r--r--vmware/svga3d_caps.h140
-rw-r--r--vmware/svga3d_reg.h3189
-rw-r--r--vmware/svga_all.h13
-rw-r--r--vmware/svga_escape.h89
-rw-r--r--vmware/svga_overlay.h201
-rw-r--r--vmware/svga_reg.h1610
-rw-r--r--vmwsvxd.c417
-rw-r--r--vmwsvxd.h22
-rw-r--r--winhack.h18
76 files changed, 17715 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7ae0c2a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,16 @@
+#backup
+/old/
+
+*.drv
+*.vxd
+*.sym
+*.res
+*.bin
+*.obj
+*.lib
+*.map
+*.err
+*.exe
+*.bat
+*.bak
+boxv9x.img
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..4ebcdf6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 JHRobotics
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4b615a6
--- /dev/null
+++ b/README.md
@@ -0,0 +1,64 @@
+# VMDisp9x
+Virtual Display driver for Windows 95/98/Me. Supported devices are:
+- Bochs VBE Extensions (Bochs: VBE, VirtulBox: VboxVGA, QEMU: std-vga)
+- VMWare SVGA-II (VMWare Workstation/Player, VirtulBox: VMSVGA, QEMU: vmware-svga)
+- VBox SVGA (VirtulBox: VBoxSVGA)
+
+Supported and tested virtualization software are:
+~~- VirtualBox 6.0 (2D, software 3D)~~
+- VirtualBox 6.1 (2D, hardware OpenGL 2.1 through DX9 or OpenGL)
+- VirtualBox 7.0 (2D, hardware OpenGL 2.1 through DX9 or OpenGL)
+- VMWare Player 16 (2D, software 3D)
+~~- VMWare Player 17 (2D, software 3D)~~
+
+2D driver is very generic and probably works with other Virtualization software as well, 3D part required my Mesa port = https://github.com/JHRobotics/mesa9x. See its documentation for more info.
+
+## Full acceleration package
+This repository contains only basic 2D driver, for 3D (hardware or software) acceleration you need sort of addition libraries and wrappers. My all-in-one package is here: https://github.com/JHRobotics/softgpu
+
+## Origin
+Driver is based on [Michal Necasek's VirtualBox driver](http://www.os2museum.com/wp/windows-9x-video-minidriver-hd/). With my modifications:
+- added VMWare SVGA and VirtualBox SVGA support
+- added OpenGL ICD support (simple command that only returns the name of OpenGL implementation library)
+- added 32bit mini-VDD driver stub (required for future development to better support for 16-bit applications)
+- added access to VMWare/VBox SVGA registers and FIFO to support real 3D acceleration from user space driver
+
+## OpenGL ICD support
+OpenGL is much more driver independent than DirectX, if fact, there is only 1 (ONE by words) function that needs to be served by driver, 0x1101. More on https://github.com/JHRobotics/mesa9x
+
+## Glide support
+3dfx proprietary API (later open sourced) for their Voodoo Graphics 3D accelerator cards. This has nothing to do with the display driver - keep in mind, that original Voodoo and Voodoo 2 cards were only 3D accretors and you still need some other video card to draw 2D part (= all system things). Calling from user space was through DLL (Glide2x.dll, Glide3x.dll) in Windows or driver (Glide.vxd) in DOS and they made the rest.
+
+If you have some OpenGL driver, you can use OpenGlide to translate Glide call to OpenGL. My port of Open Glide for Windows 9x is here: https://github.com/JHRobotics/openglide9x
+
+## DirectX support
+Microsoft DirectDraw/DirectX is complex and relatively complicated API handled by DDI driver. For Windows 9x there are 4 version of this API DirectX: DirectX 2.0 - 6.1 through DDRAW.dll, DirectX 7 still through DDRAW.dll, DirectX through D3D8.dll and DirectX 9 through D3D9.dll. DDI driver has feature level (basically equals API version request with some forward compatibility) and every API required minimum level, for example DirectX 8 required DDI version 6 as minimum, DirectX 9 required 7. Behaviour changes with DirectX 10 which required DDI version 10. If you wish to implement DDI 9 you must also implement all older. This change with DirectX 11 where is needed only actual feature set and all older DDI can be emulated - but is out of reach by Windows 9x and we still stuck DirectX 9.
+
+There no DDI support in this driver, but here is Wine project (and with set called WineD3D) which can translate DirectX (and DirectDraw too) calls to OpenGL. Minimum is OpenGL with version 2.1 or better. My port WineD3D for Windows 9x is here: https://github.com/JHRobotics/wine9x
+
+Of course, there is alternative for DX8 and DX9 called Swiftshader 2.0
+
+## Technical
+`*.drv` = 16bit driver runs in 16-bit protected mode in RING 3 (!) bud with access to I/O instructions
+`*.vxd` = 32bit driver runs in 32-bit protected mode in RING 0
+`*.dll` = 32bit user library runs in 32-bit protected mode in RING 3
+
+## Security
+In 2D mode any application could read and write guest frame buffer and rest of video ram. If 3D is enabled and works (on hypervisor site) is possible by any application to write virtual GPU FIFO which could leads to read memory of different process (in same guest) or crash the guest. These risks are noted but needs to be mentioned that these old systems haven't or has only minimal security management. For example, Microsoft Windows 9x system hasn't no file system rights, all process has mapped system memory (in last 1 GB of 32bit memory space) and any user could run 16bit application where have access to everything including I/O because of compatibility.
+
+## Compilation from source
+Install [Open Watcom 1.9](http://openwatcom.org/ftp/install/), then type
+```
+wmake
+```
+Edit `makefile` to enable addition logging and you can read original [readdev.txt](readdev.txt).
+
+## Toto
+- Complete recomended mini-VDD function in [minivdd.c](minivdd.c), stubs here and cites from original MSDN are in comments.
+- Complete GPU10 functions (with synchronization with Mesa)
+- DDI?
+
+## External links
+http://www.os2museum.com/wp/windows-9x-video-minidriver-hd/
+https://wiki.osdev.org/Bochs_VBE_Extensions
+https://wiki.osdev.org/VMWare_SVGA-II
diff --git a/boxv.c b/boxv.c
new file mode 100644
index 0000000..5d63947
--- /dev/null
+++ b/boxv.c
@@ -0,0 +1,171 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022 Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* Core boxv implementation. */
+
+#include "boxv.h" /* Public interface. */
+#include "boxvint.h" /* Implementation internals. */
+#define NEEDVIDEO
+#include "io.h" /* I/O access layer, host specific. */
+
+#pragma code_seg( _INIT )
+
+/* Write a single value to an indexed register at a specified
+ * index. Suitable for the CRTC or graphics controller.
+ */
+inline void vid_wridx( void *cx, int idx_reg, int idx, v_byte data )
+{
+ vid_outw( cx, idx_reg, idx | (data << 8) );
+}
+
+/* Set an extended non-VGA mode with given parameters. 8bpp and higher only.
+ * Returns non-zero value on failure.
+ */
+int BOXV_ext_mode_set( void *cx, int xres, int yres, int bpp, int v_xres, int v_yres )
+{
+ /* Do basic parameter validation. */
+ if( v_xres < xres || v_yres < yres )
+ return( -1 );
+
+ /* Put the hardware into a state where the mode can be safely set. */
+ vid_inb( cx, VGA_STAT_ADDR ); /* Reset flip-flop. */
+ vid_outb( cx, VGA_ATTR_W, 0 ); /* Disable palette. */
+ vid_wridx( cx, VGA_SEQUENCER, VGA_SR_RESET, VGA_SR_RESET );
+
+ /* Disable the extended display registers. */
+ vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE );
+ vid_outw( cx, VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED );
+
+ /* Program the extended non-VGA registers. */
+
+ /* Set X resoultion. */
+ vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES );
+ vid_outw( cx, VBE_DISPI_IOPORT_DATA, xres );
+ /* Set Y resoultion. */
+ vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES );
+ vid_outw( cx, VBE_DISPI_IOPORT_DATA, yres );
+ /* Set bits per pixel. */
+ vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP );
+ vid_outw( cx, VBE_DISPI_IOPORT_DATA, bpp );
+ /* Set the virtual resolution. */
+ vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_WIDTH );
+ vid_outw( cx, VBE_DISPI_IOPORT_DATA, v_xres );
+ vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_HEIGHT );
+ vid_outw( cx, VBE_DISPI_IOPORT_DATA, v_yres );
+ /* Reset the current bank. */
+ vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BANK );
+ vid_outw( cx, VBE_DISPI_IOPORT_DATA, 0 );
+ /* Set the X and Y display offset to 0. */
+ vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_X_OFFSET );
+ vid_outw( cx, VBE_DISPI_IOPORT_DATA, 0 );
+ vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_Y_OFFSET );
+ vid_outw( cx, VBE_DISPI_IOPORT_DATA, 0 );
+ /* Enable the extended display registers. */
+ vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE );
+ vid_outw( cx, VBE_DISPI_IOPORT_DATA, VBE_DISPI_ENABLED | VBE_DISPI_8BIT_DAC );
+
+ /* Re-enable the sequencer. */
+ vid_wridx( cx, VGA_SEQUENCER, VGA_SR_RESET, VGA_SR0_NORESET );
+
+ /* Reset flip-flop again and re-enable palette. */
+ vid_inb( cx, VGA_STAT_ADDR );
+ vid_outb( cx, VGA_ATTR_W, 0x20 );
+
+ return( 0 );
+}
+
+/* Program the DAC. Each of the 'count' entries is 4 bytes in size,
+ * red/green/blue/unused.
+ * Returns non-zero on failure.
+ */
+int BOXV_dac_set( void *cx, unsigned start, unsigned count, void *pal )
+{
+ v_byte *prgbu = pal;
+
+ /* Basic argument validation. */
+ if( start + count > 256 )
+ return( -1 );
+
+ /* Write the starting index. */
+ vid_outb( cx, VGA_DAC_W_INDEX, start );
+ /* Load the RGB data. */
+ while( count-- ) {
+ vid_outb( cx, VGA_DAC_DATA, *prgbu++ );
+ vid_outb( cx, VGA_DAC_DATA, *prgbu++ );
+ vid_outb( cx, VGA_DAC_DATA, *prgbu++ );
+ ++prgbu;
+ }
+ return( 0 );
+}
+
+/* Detect the presence of a supported adapter and amount of installed
+ * video memory. Returns zero if not found.
+ */
+int BOXV_detect( void *cx, unsigned long *vram_size )
+{
+ v_word boxv_id;
+
+ vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID );
+ boxv_id = vid_inw( cx, VBE_DISPI_IOPORT_DATA );
+ if( vram_size ) {
+ *vram_size = vid_ind( cx, VBE_DISPI_IOPORT_DATA );
+ }
+ if( boxv_id >= VBE_DISPI_ID0 && boxv_id <= VBE_DISPI_ID4 )
+ return( boxv_id );
+ else
+ return( 0 );
+}
+
+/* Disable extended mode and place the hardware into a VGA compatible state.
+ * Returns non-zero on failure.
+ */
+int BOXV_ext_disable( void *cx )
+{
+ /* Disable the extended display registers. */
+ vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE );
+ vid_outw( cx, VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED );
+ return( 0 );
+}
+
+/* Return the physical base address of the framebuffer. Needed in environments
+ * that do not query the base through PCI.
+ */
+unsigned long BOXV_get_lfb_base( void *cx )
+{
+ unsigned long fb_base;
+
+ /* Ask the virtual hardware for the high 16 bits. */
+ vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_FB_BASE_HI );
+ fb_base = vid_inw( cx, VBE_DISPI_IOPORT_DATA );
+
+ /* Old versions didn't support that, so use the default
+ * if the value looks like garbage.
+ */
+ if( fb_base != 0 && fb_base != 0xffff )
+ fb_base = fb_base << 16;
+ else
+ fb_base = VBE_DISPI_LFB_PHYSICAL_ADDRESS;
+
+ return( fb_base );
+}
diff --git a/boxv.h b/boxv.h
new file mode 100644
index 0000000..99ba836
--- /dev/null
+++ b/boxv.h
@@ -0,0 +1,52 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022 Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/*
+ * Public interface to the boxv library.
+ */
+
+/* PCI vendor and device IDs. */
+#define BOXV_PCI_VEN 0x80EE
+#define BOXV_PCI_DEV 0xBEEF
+
+/* A structure describing mode information. Note: The mode numbers
+ * usually match VBE, but this should not be relied upon.
+ */
+typedef struct {
+ int mode_no; /* Mode number */
+ int xres; /* Horizontal resolution */
+ int yres; /* Vertical resolution */
+ int bpp; /* Color depth */
+} BOXV_mode_t;
+
+extern void BOXV_mode_enumerate( void *cx, int (cb)( void *cx, BOXV_mode_t *mode ) );
+extern int BOXV_detect( void *cx, unsigned long *vram_size );
+extern int BOXV_ext_mode_set( void *cx, int xres, int yres, int bpp, int v_xres, int v_yres );
+extern int BOXV_mode_set( void *cx, int mode_no );
+extern int BOXV_dac_set( void *cx, unsigned start, unsigned count, void *pal );
+extern int BOXV_ext_disable( void *cx );
+extern unsigned long BOXV_get_lfb_base( void *cx );
+
+#define PCI_VENDOR_ID_VMWARE 0x15AD
+#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
diff --git a/boxv9x.def b/boxv9x.def
new file mode 100644
index 0000000..f6543f1
--- /dev/null
+++ b/boxv9x.def
@@ -0,0 +1,67 @@
+;
+; Standard display driver .DEF file
+;
+LIBRARY DISPLAY
+
+;
+; The magic numbers are: Aspect ratio, Horizontal DPI, Vertical DPI
+;
+DESCRIPTION 'DISPLAY : 100, 96, 96 : DIB Engine based Mini display driver.'
+EXETYPE WINDOWS
+
+DATA PRELOAD FIXED SINGLE
+
+SEGMENTS
+ _TEXT PRELOAD SHARED
+ _INIT PRELOAD MOVEABLE
+
+EXPORTS
+ BitBlt @1
+ ColorInfo @2
+ Control @3
+ Disable @4
+ Enable @5
+ EnumDFonts @6
+ EnumObj @7
+ Output @8
+ Pixel @9
+ RealizeObject @10
+ StrBlt @11
+ ScanLR @12
+ DeviceMode @13 NODATA
+
+ ExtTextOut @14
+ GetCharWidth @15 NODATA
+ DeviceBitmap @16 NODATA
+ FastBorder @17
+ SetAttribute @18 NODATA
+
+ DibBlt @19 ; Device Independent Bitmap group
+ CreateDIBitmap @20
+ DibToDevice @21
+
+ SetPalette @22 ; Windows 3.0 palette group
+ GetPalette @23
+
+ SetPaletteTranslate @24
+ GetPaletteTranslate @25
+ UpdateColors @26
+ StretchBlt @27
+ StretchDIBits @28
+
+ SelectBitmap @29
+ BitmapBits @30
+ ReEnable @31
+
+ Inquire @101 ; Mouse cursor function group
+ SetCursor @102
+ MoveCursor @103
+ CheckCursor @104
+
+ GetDriverResourceID @450 ; Undocumented USER callback
+ UserRepaintDisable @500 ; Undocumented USER callback
+
+ ValidateMode @700
+
+IMPORTS
+ GlobalSmartPageLock = KERNEL.230 ; Undocumented function
diff --git a/boxvint.h b/boxvint.h
new file mode 100644
index 0000000..6ec2bf3
--- /dev/null
+++ b/boxvint.h
@@ -0,0 +1,149 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022 Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* Internal definitions used by the boxv library. */
+
+/*-------------- VGA Specific ----------------*/
+
+/* VGA I/O port addresses. */
+#define VGA_CRTC 0x3D4 /* Color only! */
+#define VGA_ATTR_W 0x3C0
+#define VGA_ATTR_R 0x3C1
+#define VGA_MISC_OUT_W 0x3C2
+#define VGA_SEQUENCER 0x3C4
+#define VGA_SEQUENCER_DATA 0x3C5
+#define VGA_PIXEL_MASK 0x3C6
+#define VGA_DAC_W_INDEX 0x3C8
+#define VGA_DAC_DATA 0x3C9
+#define VGA_MISC_OUT_R 0x3CC
+#define VGA_GRAPH_CNTL 0x3CE
+#define VGA_GRAPH_CNTL_DATA 0x3CF
+#define VGA_STAT_ADDR 0x3DA /* Color only! */
+
+/* VGA Attribute Controller register indexes. */
+#define VGA_AR_MODE 0x10
+#define VGA_AR_OVERSCAN 0x11
+#define VGA_AR_PLANE_EN 0x12
+#define VGA_AR_PIX_PAN 0x13
+#define VGA_AR_COLOR_SEL 0x14
+
+/* VGA Graphics Controller register indexes. */
+#define VGA_GR_SET_RESET 0x00
+#define VGA_GR_DATA_ROTATE 0x03
+#define VGA_GR_READ_MAP_SEL 0x04
+#define VGA_GR_MODE 0x05
+#define VGA_GR_MISC 0x06
+#define VGA_GR_BIT_MASK 0x08
+
+/* VGA Sequencer register indexes. */
+#define VGA_SR_RESET 0x00
+#define VGA_SR_CLK_MODE 0x01
+#define VGA_SR_PLANE_MASK 0x02
+#define VGA_SR_MEM_MODE 0x04
+
+/* Sequencer constants. */
+#define VGA_SR0_NORESET 0x03
+#define VGA_SR0_RESET 0x00
+#define VGA_SR1_BLANK 0x20
+
+/* VGA CRTC register indexes. */
+#define VGA_CR_HORZ_TOTAL 0x00
+#define VGA_CR_CUR_START 0x0A
+#define VGA_CR_CUR_END 0x0B
+#define VGA_CR_START_HI 0x0C
+#define VGA_CR_START_LO 0x0D
+#define VGA_CR_CUR_POS_HI 0x0E
+#define VGA_CR_CUR_POS_LO 0x0F
+#define VGA_CR_VSYNC_START 0x10
+#define VGA_CR_VSYNC_END 0x11
+
+/* VGA Input Status Register 1 constants. */
+#define VGA_STAT_VSYNC 0x08
+
+/*------------ End VGA Specific --------------*/
+
+/*------------- bochs Specific ---------------*/
+
+#define VBE_DISPI_BANK_ADDRESS 0xA0000
+#define VBE_DISPI_BANK_SIZE_KB 64
+
+#define VBE_DISPI_MAX_XRES 1024
+#define VBE_DISPI_MAX_YRES 768
+
+#define VBE_DISPI_IOPORT_INDEX 0x01CE
+#define VBE_DISPI_IOPORT_DATA 0x01CF
+
+#define VBE_DISPI_INDEX_ID 0x0
+#define VBE_DISPI_INDEX_XRES 0x1
+#define VBE_DISPI_INDEX_YRES 0x2
+#define VBE_DISPI_INDEX_BPP 0x3
+#define VBE_DISPI_INDEX_ENABLE 0x4
+#define VBE_DISPI_INDEX_BANK 0x5
+#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
+#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
+#define VBE_DISPI_INDEX_X_OFFSET 0x8
+#define VBE_DISPI_INDEX_Y_OFFSET 0x9
+#define VBE_DISPI_INDEX_VBOX_VIDEO 0xa
+#define VBE_DISPI_INDEX_FB_BASE_HI 0xb
+
+#define VBE_DISPI_ID0 0xB0C0
+#define VBE_DISPI_ID1 0xB0C1
+#define VBE_DISPI_ID2 0xB0C2
+#define VBE_DISPI_ID3 0xB0C3
+#define VBE_DISPI_ID4 0xB0C4
+
+#define VBE_DISPI_DISABLED 0x00
+#define VBE_DISPI_ENABLED 0x01
+#define VBE_DISPI_GETCAPS 0x02
+#define VBE_DISPI_8BIT_DAC 0x20
+#define VBE_DISPI_LFB_ENABLED 0x40
+#define VBE_DISPI_NOCLEARMEM 0x80
+
+/* Default LFB base. Might be different! */
+#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
+
+/*------------ End bochs Specific -------------*/
+
+
+typedef unsigned char v_byte;
+typedef unsigned short v_word;
+
+/* A structure describing the contents of VGA registers for a mode set. */
+typedef struct {
+ v_byte misc; /* Miscellaneous register. */
+ v_byte seq[5]; /* Sequencer registers. */
+ v_byte crtc[25]; /* CRTC registers. */
+ v_byte gctl[9]; /* Graphics controller registers. */
+ v_byte atr[21]; /* Attribute registers. */
+} v_vgaregs;
+
+/* A structure fully describing a graphics or text mode. */
+typedef struct {
+ int mode_no; /* Internal mode number. */
+ int xres; /* Horizontal (X) resolution. */
+ int yres; /* Vertical (Y) resolution. */
+ int bpp; /* Bits per pixel. */
+ int ext; /* Non-zero for extended modes. */
+ v_vgaregs *vgaregs; /* Contents of VGA registers. */
+} v_mode;
diff --git a/code32.h b/code32.h
new file mode 100644
index 0000000..290662e
--- /dev/null
+++ b/code32.h
@@ -0,0 +1,4 @@
+/* code and data is same segment */
+#pragma data_seg("_LTEXT", "CODE")
+#pragma code_seg("_LTEXT", "CODE")
+#pragma const_seg("_LTEXT", "CODE")
diff --git a/control.c b/control.c
new file mode 100644
index 0000000..dedec69
--- /dev/null
+++ b/control.c
@@ -0,0 +1,624 @@
+/*****************************************************************************
+
+Copyright (c) 2022-2023 Jaroslav Hensl <emulator@emulace.cz>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* WINAPI Escape/ExtEscape calls ends there */
+
+#include "winhack.h"
+#include <gdidefs.h>
+#include <dibeng.h>
+#include "minidrv.h"
+#include "drvlib.h"
+#include <wchar.h> /* wchar_t */
+#include <string.h> /* _fmemset */
+
+#include "version.h"
+
+#ifdef SVGA
+# include "svga_all.h"
+# include "control_vxd.h"
+#endif
+
+/*
+ * MS supported functions
+ */
+
+#define QUERYESCSUPPORT 8
+#define OPENGL_GETINFO 0x1101
+/* list of neighbor 'known' functions */
+#define OPENGL_CMD 0x1100
+#define WNDOBJ_SETUP 0x1102
+
+/*
+ * new escape codes
+ */
+
+/* all frame buffer devices */
+#define FBHDA_REQ 0x110A
+
+/* check for drv <-> vxd <-> dll match */
+#define SVGA_API 0x110F
+
+/* VMWare SVGA II codes */
+#define SVGA_READ_REG 0x1110
+#define SVGA_HDA_REQ 0x1112
+#define SVGA_REGION_CREATE 0x1114
+#define SVGA_REGION_FREE 0x1115
+#define SVGA_SYNC 0x1116
+#define SVGA_RING 0x1117
+
+#define SVGA_HWINFO_REGS 0x1121
+#define SVGA_HWINFO_FIFO 0x1122
+#define SVGA_HWINFO_CAPS 0x1123
+
+/**
+ * OpenGL ICD driver name (0x1101):
+ * -------------------------------------
+ * Dump from real nvidia driver:
+ * 0x0000: 0x02
+ * 0x0006: 0x01
+ * 0x0008: 0x82 (R)
+ * 0x0009: 0x73 (I)
+ * 0x000a: 0x86 (V)
+ * 0x000b: 0x65 (A)
+ * 0x000c: 0x84 (T)
+ * 0x000d: 0x78 (N)
+ * 0x000e: 0x84 (T)
+ * ------------------------------------
+ * Buffer length in opengl32.dll is 532 bytes (0x214)
+ *
+ * Struct info is here:
+ * https://community.khronos.org/t/how-to-get-icd-driver-name/50988
+ *
+ **/
+typedef struct _opengl_icd_t
+{
+ long Version;
+ long DriverVersion;
+ char DLL[262]; /* wchat_t DLL */
+} opengl_icd_t;
+
+#define OPENGL_ICD_SIZE sizeof(opengl_icd_t)
+
+/* software OpenGL (Mesa3D softpipe/llvmpipe) */
+const static opengl_icd_t software_icd = {
+ 0x2,
+ 0x1,
+ "SOFTWARE"
+};
+
+#ifdef SVGA
+/* Mesa3D SVGA3D OpengGL */
+const static opengl_icd_t vmwsvga_icd = {
+ 0x2,
+ 0x1,
+ "VMWSVGA"
+};
+
+#pragma pack(push)
+#pragma pack(1)
+
+/* SVGA HDA = hardware direct access */
+typedef struct _svga_hda_t
+{
+ uint32_t vram_linear; /* frame buffer address from PM32 (shared memory region, accesable with user space programs too) */
+ uint8_t __far *vram_pm16; /* access from THIS code */
+ uint32_t vram_physical; /* physical address only for drivers */
+ uint32_t vram_size; /* video ram size */
+
+ uint32_t fifo_linear;
+ uint32_t __far *fifo_pm16;
+ uint32_t fifo_physical;
+ uint32_t fifo_size;
+
+ uint32_t ul_flags_index;
+ uint32_t ul_fence_index;
+ uint32_t ul_gmr_start;
+ uint32_t ul_gmr_count;
+ uint32_t ul_ctx_start;
+ uint32_t ul_ctx_count;
+ uint32_t ul_surf_start;
+ uint32_t ul_surf_count;
+ uint32_t __far *userlist_pm16;
+ uint32_t userlist_linear;
+ uint32_t userlist_length;
+} svga_hda_t;
+
+#pragma pack(pop)
+
+#define ULF_DIRTY 0
+#define ULF_WIDTH 1
+#define ULF_HEIGHT 2
+#define ULF_BPP 3
+#define ULF_PITCH 4
+
+static svga_hda_t SVGAHDA;
+
+#endif /* SVGA only */
+
+#pragma code_seg( _INIT )
+
+#ifdef SVGA
+uint32_t GetDevCap(uint32_t search_id);
+
+/*
+ * Fix SVGA caps which are known as bad:
+ * - VirtualBox returning A4R4G4B4 instead of R5G6B5,
+ * try to guess it's value from X8R8G8B8.
+ *
+ */
+uint32_t FixDevCap(uint32_t cap_id, uint32_t cap_val)
+{
+ switch(cap_id)
+ {
+ case SVGA3D_DEVCAP_SURFACEFMT_R5G6B5:
+ if(cap_val & SVGA3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET) /* VirtualBox BUG */
+ {
+ uint32_t xrgb8888 = GetDevCap(SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8);
+ xrgb8888 &= ~SVGA3DFORMAT_OP_SRGBWRITE; /* nvidia */
+ return xrgb8888;
+ }
+
+ if((cap_val & SVGA3DFORMAT_OP_3DACCELERATION) == 0) /* VirtualBox BUG, older drivers */
+ {
+ uint32_t xrgb8888 = GetDevCap(SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8);
+ xrgb8888 &= ~SVGA3DFORMAT_OP_SRGBWRITE; /* nvidia */
+ if(xrgb8888 & SVGA3DFORMAT_OP_3DACCELERATION)
+ {
+ return xrgb8888;
+ }
+ }
+
+ break;
+ }
+
+ return cap_val;
+}
+
+/**
+ * Read HW cap, supported old way (GPU gen9):
+ * struct SVGA_FIFO_3D_CAPS in FIFO,
+ * and new way (GPU gen10):
+ * SVGA_REG_DEV_CAP HW register
+ *
+ **/
+uint32_t GetDevCap(uint32_t search_id)
+{
+ if (gSVGA.capabilities & SVGA_CAP_GBOBJECTS)
+ {
+ /* new way to read device CAPS */
+ SVGA_WriteReg(SVGA_REG_DEV_CAP, search_id);
+ return FixDevCap(search_id, SVGA_ReadReg(SVGA_REG_DEV_CAP));
+ }
+ else
+ {
+ SVGA3dCapsRecord __far *pCaps = (SVGA3dCapsRecord __far *)&(gSVGA.fifoMem[SVGA_FIFO_3D_CAPS]);
+ while(pCaps->header.length != 0)
+ {
+ if(pCaps->header.type == SVGA3DCAPS_RECORD_DEVCAPS)
+ {
+ uint32_t datalen = (pCaps->header.length - 2)/2;
+ SVGA3dCapPair __far *pData = (SVGA3dCapPair __far *)(&pCaps->data);
+ uint32_t i;
+
+ for(i = 0; i < datalen; i++)
+ {
+ uint32_t id = pData[i][0];
+ uint32_t val = pData[i][1];
+
+ if(id == search_id)
+ {
+ return FixDevCap(search_id, val);
+ }
+ }
+ }
+ pCaps = (SVGA3dCapsRecord __far *)((uint32_t __far *)pCaps + pCaps->header.length);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Check for 3D support:
+ * - we need SVGA_FIFO_CAP_FENCE ans SVGA_FIFO_CAP_SCREEN_OBJECT
+ * - SVGA3D_DEVCAP_3D is none zero
+ * - at last SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8 is accelerated (GPU gen9 feature,
+ * GPU gen10 - eg. DirectX surfaces jet aren't supported)
+ *
+ **/
+WORD SVGA_3DSupport()
+{
+ if(SVGA_HasFIFOCap(SVGA_FIFO_CAP_FENCE) && (SVGA_HasFIFOCap(SVGA_FIFO_CAP_SCREEN_OBJECT) || SVGA_HasFIFOCap(SVGA_FIFO_CAP_SCREEN_OBJECT_2)))
+ {
+ if(GetDevCap(SVGA3D_DEVCAP_3D)) /* is 3D enabled */
+ {
+ uint32_t surfcap = GetDevCap(SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8);
+ if((surfcap & SVGA3DFORMAT_OP_3DACCELERATION) != 0) /* at last X8R8G8B8 needs to be accelerated! */
+ {
+ return 1;
+ }
+ }
+ else
+ {
+ dbg_printf("!GetDevCap(SVGA3D_DEVCAP_3D)\n");
+ }
+ }
+ else
+ {
+ dbg_printf("no SVGA_FIFO_CAP_FENCE || SVGA_FIFO_CAP_SCREEN_OBJECT\n");
+ }
+
+ return 0;
+}
+
+/**
+ * init SVGAHDA -> memory map between user space and (virtual) hardware memory
+ *
+ **/
+void SVGAHDA_init()
+{
+ _fmemset(&SVGAHDA, 0, sizeof(svga_hda_t));
+
+ SVGAHDA.ul_flags_index = 0; // dirty, width, height, bpp, pitch
+ SVGAHDA.ul_fence_index = SVGAHDA.ul_flags_index + 5;
+ SVGAHDA.ul_gmr_start = SVGAHDA.ul_fence_index + 1;
+ SVGAHDA.ul_gmr_count = SVGA_ReadReg(SVGA_REG_GMR_MAX_IDS);
+ SVGAHDA.ul_ctx_start = SVGAHDA.ul_gmr_start + SVGAHDA.ul_gmr_count*3;
+ SVGAHDA.ul_ctx_count = GetDevCap(SVGA3D_DEVCAP_MAX_CONTEXT_IDS);
+ SVGAHDA.ul_surf_start = SVGAHDA.ul_ctx_start + SVGAHDA.ul_ctx_count;
+ SVGAHDA.ul_surf_count = GetDevCap(SVGA3D_DEVCAP_MAX_SURFACE_IDS);
+ SVGAHDA.userlist_length = SVGAHDA.ul_surf_start + SVGAHDA.ul_surf_count;
+
+ SVGAHDA.userlist_pm16 = drv_malloc(SVGAHDA.userlist_length * sizeof(uint32_t), &SVGAHDA.userlist_linear);
+
+ if(SVGAHDA.userlist_pm16)
+ {
+ SVGAHDA.userlist_pm16[ULF_DIRTY] = 0xFFFFFFFFUL;
+
+ /* zero the memory, because is large than 64k, is much easier do it in PM32 */
+ if(VXD_load())
+ {
+ VXD_zeromem(SVGAHDA.userlist_linear, SVGAHDA.userlist_length * sizeof(uint32_t));
+ }
+
+ SVGAHDA.vram_linear = gSVGA.fbLinear;
+ SVGAHDA.vram_pm16 = gSVGA.fbMem;
+ SVGAHDA.vram_physical = gSVGA.fbPhy;
+ SVGAHDA.vram_size = gSVGA.vramSize;
+
+ SVGAHDA.fifo_linear = gSVGA.fifoLinear;
+ SVGAHDA.fifo_pm16 = gSVGA.fifoMem;
+ SVGAHDA.fifo_physical = gSVGA.fifoPhy;
+ SVGAHDA.fifo_size = gSVGA.fifoSize;
+ }
+}
+
+/**
+ * This is called after every screen change
+ **/
+void SVGAHDA_update(DWORD width, DWORD height, DWORD bpp, DWORD pitch)
+{
+ if(SVGAHDA.userlist_pm16)
+ {
+ SVGAHDA.userlist_pm16[ULF_WIDTH] = width;
+ SVGAHDA.userlist_pm16[ULF_HEIGHT] = height;
+ SVGAHDA.userlist_pm16[ULF_BPP] = bpp;
+ SVGAHDA.userlist_pm16[ULF_PITCH] = pitch;
+ }
+}
+
+#endif /* SVGA only */
+
+/**
+ * 2022:
+ * Control now serve system QUERYESCSUPPORT (0x8), OPENGL_ICD_DRIVER (0x1101),
+ *
+ * For second one there is no documentation known to me, so functionality was
+ * reverse-enginered from exists drivers and system's opengl32.dll.
+ * (update: some note here: https://community.khronos.org/t/how-to-get-icd-driver-name/50988)
+ *
+ * Retuned driver names is 'SOFTWARE' and OpenGL library name could be
+ * located here:
+ * HKLM\Software\Microsoft\Windows\CurrentVersion\OpenGLDrivers
+ * For example:
+ * "SOFTWARE"="mesa3d.dll"
+ *
+ * 2023:
+ * Added driver specific call to:
+ * 1) accelerate drawing to access framebuffer directly
+ FBHDA_REQ
+ * 2) access VMWare SVGA II registers and memory to real GPU acceleration
+ *
+ **/
+LONG WINAPI __loadds Control(LPVOID lpDevice, UINT function,
+ LPVOID lpInput, LPVOID lpOutput)
+{
+ LONG rc = -1;
+
+ if(function == QUERYESCSUPPORT)
+ {
+ WORD function_code = 0;
+ function_code = *((LPWORD)lpInput);
+ switch(function_code)
+ {
+ case OPENGL_GETINFO:
+ case FBHDA_REQ:
+#ifdef SVGA
+ case SVGA_API:
+
+ /*
+ * allow read HW registry/fifo registry and caps even if 3D is
+ * disabled for diagnostic tool to check why is disabled
+ */
+ case SVGA_HWINFO_REGS:
+ case SVGA_HWINFO_FIFO:
+ case SVGA_HWINFO_CAPS:
+#endif
+ rc = 1;
+ break;
+#ifdef SVGA
+ case SVGA_READ_REG:
+ case SVGA_HDA_REQ:
+ case SVGA_REGION_CREATE:
+ case SVGA_REGION_FREE:
+ case SVGA_SYNC:
+ case SVGA_RING:
+ if(wMesa3DEnabled)
+ {
+ rc = 1;
+ }
+ break;
+#endif
+ }
+ //dbg_printf("Control: function check for: %x\n", function_code);
+ }
+ else if(function == OPENGL_GETINFO) /* input: NULL, output: opengl_icd_t */
+ {
+#ifdef SVGA
+ if(wMesa3DEnabled == 0)
+ {
+ _fmemcpy(lpOutput, &software_icd, OPENGL_ICD_SIZE); /* no 3D use software OPENGL */
+ }
+ else
+ {
+ _fmemcpy(lpOutput, &vmwsvga_icd, OPENGL_ICD_SIZE); /* accelerated OPENGL */
+ }
+#else
+ _fmemcpy(lpOutput, &software_icd, OPENGL_ICD_SIZE);
+#endif
+
+ rc = 1;
+ }
+ else if(function == FBHDA_REQ) /* input: NULL, output: uint32 */
+ {
+ uint32_t __far *lpOut = lpOutput;
+ lpOut[0] = FBHDA_linear;
+ dbg_printf("FBHDA request: %lX\n", FBHDA_linear);
+
+ rc = 1;
+ }
+#ifdef SVGA
+ else if(function == SVGA_READ_REG) /* input: uint32_t, output: uint32_t */
+ {
+ unsigned long val;
+ unsigned long regname = *((unsigned long __far *)lpInput);
+
+ if(regname == SVGA_REG_ID)
+ {
+ val = gSVGA.deviceVersionId;
+ }
+ else if(regname == SVGA_REG_CAPABILITIES)
+ {
+ val = gSVGA.capabilities;
+ }
+ else
+ {
+ val = SVGA_ReadReg(regname);
+ }
+
+ *((unsigned long __far *)lpOutput) = val;
+
+ rc = 1;
+ }
+ else if(function == SVGA_HDA_REQ) /* input: NULL, output: svga_hda_t */
+ {
+ svga_hda_t __far *lpHDA = lpOutput;
+ _fmemcpy(lpHDA, &SVGAHDA, sizeof(svga_hda_t));
+ rc = 1;
+ }
+ else if(function == SVGA_REGION_CREATE) /* input: 2*uint32_t, output: 2*uint32_t */
+ {
+ uint32_t __far *lpIn = lpInput;
+ uint32_t __far *lpOut = lpOutput;
+ uint32_t rid = lpIn[0];
+
+ dbg_printf("Region id = %ld\n", rid);
+
+ if(rid)
+ {
+ uint32_t lAddr;
+ uint32_t ppn;
+
+ VXD_load();
+
+ if(VXD_CreateRegion(lpIn[1], &lAddr, &ppn)) /* allocate physical memory */
+ {
+ dbg_printf("Region address = %lX, PPN = %lX\n", lAddr, ppn);
+
+ SVGA_WriteReg(SVGA_REG_GMR_ID, rid);
+ SVGA_WriteReg(SVGA_REG_GMR_DESCRIPTOR, ppn);
+
+ /* refresh all register, so make sure that new commands will accepts this region */
+ SVGA_Flush();
+
+ lpOut[0] = rid;
+ lpOut[1] = lAddr + 4096;
+ }
+ else
+ {
+ lpOut[0] = 0;
+ lpOut[1] = 0;
+ }
+ }
+
+ rc = 1;
+ }
+ else if(function == SVGA_REGION_FREE) /* input: 2*uint32_t, output: NULL */
+ {
+ uint32_t __far *lpin = lpInput;
+ uint32_t id = lpin[0];
+ uint32_t linear = lpin[1] - 4096;
+
+ /* flush all register inc. fifo so make sure, that all commands are processed */
+ SVGA_Flush();
+
+ SVGA_WriteReg(SVGA_REG_GMR_ID, id);
+ SVGA_WriteReg(SVGA_REG_GMR_DESCRIPTOR, 0);
+
+ /* sync again */
+ SVGA_Flush();
+
+ /* region physical delete */
+ VXD_load();
+ VXD_FreeRegion(linear);
+
+ rc = 1;
+ }
+ else if(function == SVGA_HWINFO_REGS) /* input: NULL, output: 256*uint32_t */
+ {
+ int i;
+ uint32_t __far *lpreg = lpOutput;
+ for(i = 0; i < 256; i++)
+ {
+ *lpreg = SVGA_ReadReg(i);
+ lpreg++;
+ }
+
+ rc = 1;
+ }
+ else if(function == SVGA_HWINFO_FIFO) /* input: NULL, output: 1024*uint32_t */
+ {
+ int i;
+ uint32_t __far *lpreg = lpOutput;
+
+ for(i = 0; i < 1024; i++)
+ {
+ *lpreg = gSVGA.fifoMem[i];
+ lpreg++;
+ }
+
+ rc = 1;
+ }
+ else if(function == SVGA_HWINFO_CAPS) /* input: NULL, output: 512*uint32_t */
+ {
+ int i;
+ uint32_t __far *lpreg = lpOutput;
+ SVGA3dCapsRecord __far *pCaps;
+ SVGA3dCapPair __far *pData;
+
+
+ if (gSVGA.capabilities & SVGA_CAP_GBOBJECTS)
+ {
+ /* new way to read device CAPS */
+ for (i = 0; i < 512; i++)
+ {
+ SVGA_WriteReg(SVGA_REG_DEV_CAP, i);
+ lpreg[i] = FixDevCap(i, SVGA_ReadReg(SVGA_REG_DEV_CAP));
+ dbg_printf("VMSVGA3d_3: cap[%d]=0x%lX\n", i, lpreg[i]);
+ }
+ }
+ else
+ {
+ /* old way to read device CAPS */
+ pCaps = (SVGA3dCapsRecord __far *)&(gSVGA.fifoMem[SVGA_FIFO_3D_CAPS]);
+
+ while(pCaps->header.length != 0)
+ {
+ dbg_printf("SVGA_FIFO_3D_CAPS: %ld, %ld\n", pCaps->header.type, pCaps->header.length);
+ if(pCaps->header.type == SVGA3DCAPS_RECORD_DEVCAPS)
+ {
+ uint32_t datalen = (pCaps->header.length - 2)/2;
+ pData = (SVGA3dCapPair __far *)(&pCaps->data);
+ for(i = 0; i < datalen; i++)
+ {
+ uint32_t id = pData[i][0];
+ uint32_t val = pData[i][1];
+
+ if(id < 512)
+ {
+ lpreg[id] = FixDevCap(id, val);
+ }
+
+ dbg_printf("VMSVGA3d_2: cap[%ld]=0x%lX\n", id, val);
+ }
+ }
+ dbg_printf("SVGA_FIFO_3D_CAPS: end\n");
+
+ pCaps = (SVGA3dCapsRecord __far *)((uint32_t __far *)pCaps + pCaps->header.length);
+ }
+ }
+
+ rc = 1;
+ }
+ else if(function == SVGA_SYNC) /* input: NULL, output: NULL */
+ {
+ SVGA_Flush();
+
+ rc = 1;
+ }
+ else if(function == SVGA_RING) /* input: NULL, output: NULL */
+ {
+ SVGA_WriteReg(SVGA_REG_SYNC, 1);
+
+ rc = 1;
+ }
+ else if(function == SVGA_API) /* input: NULL, output: 2x DWORD */
+ {
+ uint32_t __far *lpver = lpOutput;
+
+ lpver[0] = DRV_API_LEVEL;
+
+ if(VXD_load())
+ {
+ lpver[1] = VXD_apiver();
+ }
+ else
+ {
+ lpver[1] = 0;
+ }
+
+ rc = 1;
+ }
+#endif /* SVGA only */
+
+ /* if command accepted, return */
+ if(rc >= 0)
+ {
+ return rc;
+ }
+
+ /* else, call DIB_Control handle */
+ dbg_printf("Control: unknown code: %d\n", function);
+ return DIB_Control(lpDevice, function, lpInput, lpOutput);
+}
diff --git a/control_svga.c b/control_svga.c
new file mode 100644
index 0000000..e9004cf
--- /dev/null
+++ b/control_svga.c
@@ -0,0 +1,2 @@
+#define SVGA
+#include "control.c"
diff --git a/control_vxd.c b/control_vxd.c
new file mode 100644
index 0000000..23630af
--- /dev/null
+++ b/control_vxd.c
@@ -0,0 +1,212 @@
+/*****************************************************************************
+
+Copyright (c) 2023 Jaroslav Hensl <emulator@emulace.cz>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+/* Communication from ring3 PM16 -> ring0 PM32 */
+
+#include <wchar.h> /* wchar_t */
+#include <string.h> /* _fmemset */
+#include <stdint.h>
+#include "winhack.h" /* BOOL */
+
+#include "vmwsvxd.h"
+#include "control_vxd.h"
+
+#ifdef DBGPRINT
+extern void dbg_printf( const char *s, ... );
+#else
+#define dbg_printf(...)
+#endif
+
+static uint32_t VXD_srv = 0;
+
+#pragma code_seg( _INIT )
+
+BOOL VXD_load()
+{
+ if(VXD_srv != 0)
+ {
+ return TRUE;
+ }
+
+ _asm{
+ push es
+ push ax
+ push dx
+ push bx
+ push di
+
+ xor di,di
+ mov es,di
+ mov ax, 1684H
+ mov bx, VMWSVXD_DEVICE_ID
+ int 2FH
+ mov word ptr [VXD_srv],di
+ mov word ptr [VXD_srv+2],es
+
+ pop di
+ pop bx
+ pop dx
+ pop ax
+ pop es
+ };
+
+ return VXD_srv != 0;
+}
+
+BOOL VXD_CreateRegion(uint32_t nPages, uint32_t __far *lpLAddr, uint32_t __far *lpPPN)
+{
+ static uint32_t snPages;
+ static uint32_t sLAddr;
+ static uint32_t sPPN;
+ static uint16_t state = 0;
+
+ snPages = nPages;
+
+ if(VXD_srv != 0)
+ {
+ _asm
+ {
+ .386
+ push eax
+ push edx
+ push ecx
+
+ mov edx, VMWSVXD_PM16_CREATE_REGION
+ mov ecx, [snPages]
+ call dword ptr [VXD_srv]
+ mov [state], ax
+ mov [sLAddr], edx
+ mov [sPPN], ecx
+
+ pop ecx
+ pop edx
+ pop eax
+ };
+
+ if(state == 1)
+ {
+ *lpLAddr = sLAddr;
+ *lpPPN = sPPN;
+
+ return TRUE;
+ }
+ else
+ {
+ dbg_printf("state: %X, LAddr: %lX, PPN: %lX\n", state, sLAddr, sPPN);
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL VXD_FreeRegion(uint32_t LAddr)
+{
+ static uint32_t sLAddr;
+ static uint16_t state;
+
+ sLAddr = LAddr;
+
+ if(VXD_srv != 0)
+ {
+ _asm
+ {
+ .386
+ push eax
+ push edx
+ push ecx
+
+ mov edx, VMWSVXD_PM16_DESTROY_REGION
+ mov ecx, [LAddr]
+ call dword ptr [VXD_srv]
+ mov [state], ax
+
+ pop ecx
+ pop edx
+ pop eax
+ };
+
+ if(state == 1)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+void VXD_zeromem(uint32_t LAddr, uint32_t size)
+{
+ static uint32_t sLAddr;
+ static uint32_t ssize;
+
+ sLAddr = LAddr;
+ ssize = size;
+
+ if(VXD_srv != 0)
+ {
+ _asm
+ {
+ .386
+ push eax
+ push edx
+ push ecx
+ push esi
+
+ mov edx, VMWSVXD_PM16_ZEROMEM
+ mov esi, [sLAddr]
+ mov ecx, [ssize]
+ call dword ptr [VXD_srv]
+
+ pop esi
+ pop ecx
+ pop edx
+ pop eax
+ }
+ }
+}
+
+uint32_t VXD_apiver()
+{
+ static uint32_t sver = 0;
+
+ if(VXD_srv != 0)
+ {
+ _asm
+ {
+ .386
+ push eax
+ push edx
+ push ecx
+
+ mov edx, VMWSVXD_PM16_APIVER
+ call dword ptr [VXD_srv]
+ mov [sver], ecx
+
+ pop ecx
+ pop edx
+ pop eax
+ }
+ }
+
+ return sver;
+}
diff --git a/control_vxd.h b/control_vxd.h
new file mode 100644
index 0000000..a515731
--- /dev/null
+++ b/control_vxd.h
@@ -0,0 +1,10 @@
+#ifndef __CONTROL_VXD_H__INCLUDED__
+#define __CONTROL_VXD_H__INCLUDED__
+
+BOOL VXD_load();
+BOOL VXD_CreateRegion(uint32_t nPages, uint32_t __far *lpLAddr, uint32_t __far *lpPPN);
+BOOL VXD_FreeRegion(uint32_t LAddr);
+void VXD_zeromem(uint32_t LAddr, uint32_t size);
+uint32_t VXD_apiver();
+
+#endif
diff --git a/dbgprint.c b/dbgprint.c
new file mode 100644
index 0000000..d460c0c
--- /dev/null
+++ b/dbgprint.c
@@ -0,0 +1,288 @@
+/*****************************************************************************
+
+Copyright (c) 2022 Michal Necasek
+ 2023 Jaroslav Hensl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* Homegrown printf support. The C runtime printf() is hard to use without
+ * dragging in much of the library, and much worse, the small model runtime
+ * can't operate with SS != DS. So we roll our own very simplified printf()
+ * subset, good enough for what we need.
+ */
+
+#include <stdint.h>
+#include <stdarg.h>
+#include <ctype.h>
+#ifndef VXD32
+#include <conio.h>
+#else
+#define IO_IN8
+#define IO_OUT8
+#include "io32.h"
+#include "code32.h"
+#endif
+
+
+/* Backdoor logging I/O ports. */
+#ifdef COM2
+/* COM2 I/O */
+#define INFO_PORT 0x2F8
+#else
+/* default COM1 I/O */
+#define INFO_PORT 0x3F8
+#endif
+
+#define FULL_SERIAL
+/* ^ inicialize serial and waiting for transmit same way as with real HW serial
+ * if defined. VirtualBox usually require it.
+ */
+
+#pragma code_seg( _INIT );
+
+#ifdef FULL_SERIAL
+static int serial_inited = 0;
+
+static void init_serial() {
+ outp(INFO_PORT + 1, 0x00); // Disable all interrupts
+ outp(INFO_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
+ outp(INFO_PORT + 0, 0x12); // Set divisor to 3 (lo byte) 38400 baud
+ outp(INFO_PORT + 1, 0x00); // (hi byte)
+ outp(INFO_PORT + 3, 0x03); // 8 bits, no parity, one stop bit
+ outp(INFO_PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
+ //outp(INFO_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
+}
+
+static int is_transmit_empty()
+{
+ return inp(INFO_PORT + 5) & 0x20;
+}
+#endif
+
+static void prt_ch( char c )
+{
+#ifdef FULL_SERIAL
+ if(serial_inited == 0)
+ {
+ init_serial();
+ serial_inited = 1;
+ }
+
+ while (is_transmit_empty() == 0);
+#endif
+
+ outp(INFO_PORT, c);
+}
+
+#ifdef VXD32
+int dbg_isdigit( int c )
+{
+ if(c >= '0' && c <= '9')
+ {
+ return 1;
+ }
+ return 0;
+}
+#else
+#define dbg_isdigit isdigit
+#endif
+
+static void prt_u32( uint32_t val, int width )
+{
+ uint32_t uval;
+ uint32_t base;
+ char buf[16]; /* It's 12 digits max. */
+ int n = 0;
+
+ uval = val;
+
+ do {
+ base = uval / 10;
+ buf[n++] = uval - base * 10 + '0';
+ uval = base;
+ } while( uval );
+
+ /* Pad with spaces. */
+ while( width > n ) {
+ prt_ch( ' ' );
+ --width;
+ }
+
+ do {
+ prt_ch( buf[--n] );
+ } while( n );
+}
+
+static void prt_i32( int32_t val, int width )
+{
+ uint32_t uval;
+
+ if( val < 0 ) {
+ prt_ch( '-' );
+ uval = -val;
+ if( width > 0 )
+ --width;
+ } else {
+ uval = val;
+ }
+
+ prt_u32( uval, width );
+}
+
+static void prt_hex32( uint32_t val, int width, char hexa )
+{
+ char buf[8]; /* Enough for a dword. */
+ int n = 0;
+ int nibble;
+
+ do {
+ nibble = val & 0xF;
+ val >>= 4;
+ buf[n++] = nibble + (nibble > 9 ? hexa - 10 : '0');
+ } while( val );
+
+ /* Pad with zeros. */
+ while( width > n ) {
+ prt_ch( '0' );
+ --width;
+ }
+
+ do {
+ prt_ch( buf[--n] );
+ } while( n );
+}
+
+static void prt_str( const char __far *s )
+{
+ while( *s )
+ prt_ch( *s++ );
+}
+
+void dbg_printf( const char *s, ... )
+{
+ char type_len;
+ char conv;
+ char hexa;
+ int width;
+ uint16_t word;
+ uint32_t dword;
+ va_list args;
+
+ va_start( args, s );
+
+ /* Go until end of format string. */
+ while( *s ) {
+ /* Is it a format specifier? */
+ if( *s == '%' ) {
+ ++s; /* Eat the % sign. */
+ conv = 0;
+ width = 0;
+ type_len = 0;
+
+ /* Process field width, if any. */
+ while( dbg_isdigit( *s ) ) {
+ width *= 10;
+ width += *s++ - '0';
+ }
+
+ /* Process type length specifier, if any. */
+ switch( *s ) {
+ case 'l': /* Long integers. */
+ case 'W': /* Far pointers. */
+ type_len = *s++;
+ break;
+ default: /* Do nothing. */
+ break;
+ }
+
+ /* Now check if a supported conversion is there. */
+ switch( *s ) {
+ case 'c':
+ case 'd':
+ case 'u':
+ case 'p':
+ case 'P':
+ case 's':
+ case 'x':
+ case 'X':
+ conv = *s++;
+ break;
+ default: /* Do nothing. */
+ break;
+ }
+
+ if( conv ) {
+ /* Time to start grabbing stuff off the stack. */
+ word = va_arg( args, uint16_t );
+ /* If argument is double wide, build a doubleword. */
+ if( type_len == 'l' || type_len == 'W' ) {
+ dword = va_arg( args, uint16_t );
+ dword <<= 16;
+ dword |= word;
+ }
+ if( conv == 'c' ) {
+ prt_ch( word );
+ } else if( conv == 'd' ) {
+ if( type_len == 'l' )
+ prt_i32( dword, width );
+ else
+ prt_i32( (int16_t)word, width );
+ } else if( conv == 'u' ) {
+ if( type_len == 'l' )
+ prt_u32( dword, width );
+ else
+ prt_u32( word, width );
+ } else if( conv == 'p' || conv == 'P' ) {
+ hexa = conv - 'P' + 'A';
+ if( type_len == 'W' ) {
+ prt_hex32( dword >> 16, 4, hexa );
+ prt_ch( ':' );
+ prt_hex32( word, 4, hexa );
+ } else {
+ prt_hex32( word, 4, hexa );
+ }
+ } else if( conv == 's' ) {
+ if( type_len == 'W' )
+ prt_str( (const char __far *)dword );
+ else
+ prt_str( (const char *)word );
+ } else if( conv == 'x' || conv == 'X' ) {
+ hexa = conv - 'X' + 'A';
+ if( type_len == 'l' ) {
+ if( !width )
+ width = 8;
+ prt_hex32( dword, width, hexa );
+ } else {
+ if( !width )
+ width = 4;
+ prt_hex32( word, width, hexa );
+ }
+ }
+ } else {
+ /* Just print whatever is there. */
+ prt_ch( *s++ );
+ }
+ } else {
+ prt_ch( *s++ );
+ }
+ }
+ va_end( args );
+}
diff --git a/dbgprint32.c b/dbgprint32.c
new file mode 100644
index 0000000..3608351
--- /dev/null
+++ b/dbgprint32.c
@@ -0,0 +1,2 @@
+#define VXD32
+#include "dbgprint.c"
diff --git a/ddk/dibeng.def b/ddk/dibeng.def
new file mode 100644
index 0000000..f53ea67
--- /dev/null
+++ b/ddk/dibeng.def
@@ -0,0 +1,49 @@
+EXPORTS
+LIBRARY DIBENG
+ DIB_BitBlt @1
+ DIB_ColorInfo @2
+ DIB_Control @3
+ DIB_Disable @4
+ DIB_Enable @5
+ DIB_EnumDFonts @6
+ DIB_EnumObj @7
+ DIB_Output @8
+ DIB_Pixel @9
+ DIB_RealizeObject @10
+ DIB_StrBlt @11
+ DIB_ScanLR @12
+ DIB_DeviceMode @13
+ DIB_ExtTextOut @14
+ DIB_GetCharWidth @15
+ DIB_DeviceBitmap @16
+ DIB_FastBorder @17
+ DIB_SetAttribute @18
+ DIB_DibBlt @19
+ DIB_CreateDIBitmap @20
+ DIB_DibToDevice @21
+ DIB_SetPalette @22
+ DIB_GetPalette @23
+ DIB_SetPaletteTranslate @24
+ DIB_GetPaletteTranslate @25
+ DIB_UpdateColors @26
+ DIB_StretchBlt @27
+ DIB_StretchDIBits @28
+ DIB_SelectBitmap @29
+ DIB_BitmapBits @30
+ DIB_Inquire @101
+ DIB_SetCursorExt @102
+ DIB_MoveCursorExt @103
+ DIB_CheckCursorExt @104
+ DIB_BeginAccess @105
+ DIB_EndAccess @106
+ CreateDIBPDevice @300
+ DIB_RealizeObjectExt @400
+ DIB_DibBltExt @401
+ DIB_EnumObjExt @402
+ DIB_ExtTextOutExt @403
+ DIB_UpdateColorsExt @404
+ DIB_SetPaletteExt @405
+ DIB_GetPaletteExt @406
+ DIB_SetPaletteTranslateExt @407
+ DIB_GetPaletteTranslateExt @408
+
diff --git a/ddk/dibeng.h b/ddk/dibeng.h
new file mode 100644
index 0000000..259a58c
--- /dev/null
+++ b/ddk/dibeng.h
@@ -0,0 +1,248 @@
+/* DIB Engine interface. */
+
+#define BRUSHSIZE 8
+#define VER_DIBENG 0x400
+#define TYPE_DIBENG 0x5250 /* 'RP' */
+
+#define deCursorExclude deBeginAccess
+#define deCursorUnexclude deEndAccess
+
+/* DIB Engine PDevice structure. The deType field will be 'DI' when GDI
+ * calls the Engine; deType will be null or a selector if a minidriver is
+ * calls the DIB Engine.
+ */
+typedef struct {
+ WORD deType; /* TYPE_DIBENG or zero. */
+ WORD deWidth; /* DIB width in pixels. */
+ WORD deHeight; /* DIB height in pixels. */
+ WORD deWidthBytes; /* Scanline length in bytes. */
+ BYTE dePlanes; /* Number of bit planes. */
+ BYTE deBitsPixel; /* Number of bits per pixel. */
+ DWORD deReserved1; /* Not used. */
+ DWORD deDeltaScan; /* Scanline delta, can be negative.*/
+ LPBYTE delpPDevice; /* Associated PDevice pointer. */
+ DWORD deBitsOffset; /* 48-bit pointer to */
+ WORD deBitsSelector; /* DIB bits storage. */
+ WORD deFlags; /* More flags. */
+ WORD deVersion; /* Major/minor (0400h = 4.0). */
+ LPBITMAPINFO deBitmapInfo; /* Bitmapinfo header pointer. */
+ void (WINAPI *deBeginAccess)(); /* Surface access begin callback. */
+ void (WINAPI *deEndAccess)(); /* Surface access end callback. */
+ DWORD deDriverReserved; /* Reserved for minidrivers. */
+} DIBENGINE, FAR *LPDIBENGINE;
+
+/* if pdType is zero, structure is identical to PBITMAP */
+typedef struct tagPDEVICE {
+ short pdType;
+} PDEVICE;
+
+/* DIBEngine.deFlags */
+#define MINIDRIVER 0x0001 /* Mini display driver. */
+#define PALETTIZED 0x0002 /* Has a palette. */
+#define SELECTEDDIB 0x0004 /* DIB Section. */
+#define OFFSCREEN 0x0008 /* Offscreen surface in VRAM. */
+#define BUSY 0x0010 /* Busy. */
+#define NOT_FRAMEBUFFER 0x0020 /* No FB access (like 8514/A). */
+#define FIVE6FIVE 0x0040 /* 5-6-5 16bpp mode. */
+#define NON64KBANK 0x0080 /* Bank size != 64K. */
+#define VRAM 0x8000 /* Have VRAM access. */
+#define BANKEDVRAM 0x4000 /* VFlatD simulating LFB. */
+#define BANKEDSCAN 0x2000 /* VFlatD with scanlines crossing banks. */
+#define PALETTE_XLAT 0x1000 /* Bkgnd palette translation. */
+#define VGADITHER 0x0800 /* Dither to VGA colors. */
+#define CTCHANGE 0x0400 /* Color table changed/ */
+#define DITHER256 0x0200 /* Dither to 256 colors. */
+
+#define BUSY_BIT 4 /* Number of bit to test for busy. */
+
+/* DIB_Brush??.dp??BrushFlags */
+#define COLORSOLID 0x01 /* Color part solid. */
+#define MONOSOLID 0x02 /* Mono part solid. */
+#define PATTERNMONO 0x04 /* Brush originated from mono bitmap. */
+#define MONOVALID 0x08 /* Mono part valid. */
+#define MASKVALID 0x10 /* Mask valid. */
+#define PRIVATEDATA 0x20 /* Vendor defined bit. */
+
+/* Fake typedefs to avoid conflicts between windows.h and gdidefs.h. */
+typedef LPVOID LPPDEVICE;
+typedef LPVOID LPPPEN;
+typedef LPVOID LPPBRUSH;
+typedef LPVOID LPBRUSH;
+typedef LPVOID LPPCOLOR;
+typedef LPINT LPSHORT;
+
+/* DIB Engine functions. */
+/* NB: Based on DDK documentation which may be inaccurate. */
+//extern void WINAPI DIB_Control( void );
+extern LONG WINAPI DIB_Control(LPVOID lpDevice, UINT function, LPVOID lpInput, LPVOID lpOutput);
+extern WORD WINAPI DIB_EnumObjExt( LPPDEVICE lpDestDev, WORD wStyle, FARPROC lpCallbackFunc,
+ LPVOID lpClientData, LPPDEVICE lpDisplayDev );
+extern VOID WINAPI DIB_CheckCursorExt( LPPDEVICE lpDevice );
+extern WORD WINAPI DIB_Output( LPPDEVICE lpDestDev, WORD wStyle, WORD wCount,
+ LPPOINT lpPoints, LPPPEN lpPPen, LPPBRUSH lpPBrush,
+ LPDRAWMODE lpDrawMode, LPRECT lpClipRect);
+extern DWORD WINAPI DIB_RealizeObject( LPPDEVICE lpDestDev, WORD wStyle, LPVOID lpInObj,
+ LPVOID lpOutObj, LPTEXTXFORM lpTextXForm );
+extern WORD WINAPI DIB_RealizeObjectExt( LPPDEVICE lpDestDev, WORD wStyle, LPVOID lpInObj,
+ LPVOID lpOutObj, LPTEXTXFORM lpTextXForm,
+ LPPDEVICE lpDisplayDev );
+extern BOOL WINAPI DIB_BitBlt( LPPDEVICE lpDestDev, WORD wDestX, WORD wDestY, LPPDEVICE lpSrcDev,
+ WORD wSrcX, WORD wSrcY, WORD wXext, WORD wYext, DWORD dwRop3,
+ LPBRUSH lpPBrush, LPDRAWMODE lpDrawMode );
+extern BOOL WINAPI DIB_BitmapBits( LPPDEVICE lpDevice, DWORD fFlags, DWORD dwCount, LPSTR lpBits );
+extern VOID WINAPI DIB_DibBlt( LPPDEVICE lpBitmap, WORD fGet, WORD iStart, WORD cScans, LPSTR lpDIBits,
+ LPBITMAPINFO lpBitmapInfo, LPDRAWMODE lpDrawMode, LPINT lpTranslate );
+extern WORD WINAPI DIB_DibToDevice( LPPDEVICE lpDestDev, WORD X, WORD Y, WORD iScan, WORD cScans,
+ LPRECT lpClipRect, LPDRAWMODE lpDrawMode, LPSTR lpDIBits,
+ LPBITMAPINFO lpBitmapInfo, LPINT lpTranslate );
+extern DWORD WINAPI DIB_Pixel( LPPDEVICE lpDestDev, WORD X, WORD Y, DWORD dwPhysColor, LPDRAWMODE lpDrawMode );
+extern WORD WINAPI DIB_ScanLR( LPPDEVICE lpDestDev, WORD X, WORD Y, DWORD dwPhysColor, WORD wStyle );
+extern BOOL WINAPI DIB_SelectBitmap(LPPDEVICE lpDevice, LPBITMAP lpPrevBitmap, LPBITMAP lpBitmap, DWORD fFlags );
+extern BOOL WINAPI DIB_StretchBlt( LPPDEVICE lpDestDev, WORD wDestX, WORD wDestY, WORD wDestWidth,
+ WORD wDestHeight, LPPDEVICE lpSrcDev, WORD wSrcX, WORD wSrcY,
+ WORD wSrcWidth, WORD wtSrcHeight, DWORD dwRop3, LPBRUSH lpPBrush,
+ LPDRAWMODE lpDrawMode, LPRECT lpClipRect );
+extern BOOL WINAPI DIB_StretchDIBits( LPPDEVICE lpDestDev, WORD fGet, WORD wDestX, WORD wDestY, WORD wDestWidth,
+ WORD wDestHeight, WORD wSrcX, WORD wSrcY, WORD wSrcWidth, WORD wSrcHeight,
+ VOID *lpBits, LPBITMAPINFO lpInfo, LPINT lpTranslate, DWORD dwRop3,
+ LPBRUSH lpPBrush, LPDRAWMODE lpDrawMode, LPRECT lpClipRect );
+extern DWORD WINAPI DIB_ExtTextOut( LPPDEVICE lpDestDev, WORD wDestXOrg, WORD wDestYOrg, LPRECT lpClipRect,
+ LPSTR lpString, int wCount, LPFONTINFO lpFontInfo, LPDRAWMODE lpDrawMode,
+ LPTEXTXFORM lpTextXForm, LPSHORT lpCharWidths, LPRECT lpOpaqueRect, WORD wOptions );
+extern DWORD WINAPI DIB_ExtTextOutExt( LPPDEVICE lpDestDev, WORD wDestXOrg, WORD wDestYOrg, LPRECT lpClipRect,
+ LPSTR lpString, WORD wCount, LPFONTINFO lpFontInfo, LPDRAWMODE lpDrawMode,
+ LPTEXTXFORM lpTextXForm, LPSHORT lpCharWidths, LPRECT lpOpaqueRect,
+ WORD wOptions, LPVOID *lpDrawTextBitmap, LPVOID *lpDrawRect );
+extern WORD WINAPI DIB_GetCharWidth( LPPDEVICE lpDestDev, LPWORD lpBuffer, WORD wFirstChar, WORD wLastChar,
+ LPFONTINFO lpFontInfo, LPDRAWMODE lpDrawMode, LPTEXTXFORM lpFontTrans );
+
+extern DWORD WINAPI DIB_StrBlt( LPPDEVICE lpDestDev, WORD wDestXOrg, WORD wDestYOrg, LPRECT lpClipRect, LPSTR lpString,
+ WORD wCount, LPFONTINFO lpFontInfo, LPDRAWMODE lpDrawMode, LPTEXTXFORM lpTextXForm );
+extern DWORD WINAPI DIB_ColorInfo( LPPDEVICE lpDestDev, DWORD dwColorin, LPPCOLOR lpPColor );
+extern VOID WINAPI DIB_GetPalette( WORD nStartIndex, WORD nNumEntries, RGBQUAD lpPalette );
+extern VOID WINAPI DIB_GetPaletteExt( WORD nStartIndex, WORD nNumEntries, RGBQUAD lpPalette, LPPDEVICE lpDIBEngine );
+extern VOID WINAPI DIB_GetPaletteTranslate( LPWORD lpIndexes );
+extern VOID WINAPI DIB_GetPaletteTranslateExt( LPWORD lpIndexes, LPPDEVICE lpDIBEngine );
+extern VOID WINAPI DIB_SetPalette( WORD nStartIndex, WORD nNumEntries, LPVOID lpPalette );
+extern VOID WINAPI DIB_SetPaletteExt( WORD nStartIndex, WORD nNumEntries, LPVOID lpPalette, LPPDEVICE lpDIBEngine );
+extern VOID WINAPI DIB_SetPaletteTranslate( LPWORD lpIndexes );
+extern VOID WINAPI DIB_SetPaletteTranslateExt( LPWORD lpIndexes, LPPDEVICE lpDIBEngine );
+extern VOID WINAPI DIB_UpdateColorsExt( WORD wStartX, WORD wStart, WORD wExtX, WORD wExtY,
+ LPWORD lpTranslate, LPPDEVICE lpDIBEngine );
+extern VOID WINAPI DIB_SetCursorExt( LPPDEVICE lpDevice, LPVOID lpCursorShape );
+extern VOID WINAPI DIB_CheckCursorExt( LPPDEVICE lpDevice );
+extern VOID WINAPI DIB_MoveCursorExt( LPPDEVICE lpDevice, WORD absX, WORD absY );
+extern VOID WINAPI DIB_Inquire( LPVOID lpCursorInfo );
+extern VOID WINAPI DIB_BeginAccess( LPPDEVICE lpDevice, WORD wLeft, WORD wTop, WORD wRight, WORD wBottom, WORD wFlags );
+extern VOID WINAPI DIB_EndAccess( LPPDEVICE lpDevice, WORD wFlags );
+extern WORD WINAPI DIB_CreateDIBitmap( void );
+extern WORD WINAPI DIB_DeviceBitmap( LPPDEVICE lpDestDev, WORD wCommand, LPBITMAP lpBitmap, LPSTR lpBits );
+extern WORD WINAPI DIB_DeviceMode( HWND hWnd, HINSTANCE hInst, LPVOID lpDeviceType, LPVOID lpOutputFile );
+extern UINT WINAPI DIB_Enable( LPPDEVICE lpDevice, WORD wStyle, LPSTR lpDeviceType, LPSTR lpOutputFile, LPVOID lpStuff );
+extern VOID WINAPI DIB_Disable( LPPDEVICE lpDestDev );
+extern WORD WINAPI DIB_EnumDFonts( LPPDEVICE lpDestDev, LPSTR lpFaceName, FARPROC lpCallbackFunc, LPVOID lpClientData );
+extern WORD WINAPI DIB_SetAttribute( LPPDEVICE lpDevice, WORD wStateNum, WORD wIndex, DWORD dwAttribute );
+
+
+/* WARNING: CreateDIBPDevice returns the result in EAX, not DX:AX! */
+extern DWORD WINAPI CreateDIBPDevice( LPBITMAPINFO lpInfo, LPPDEVICE lpDevice, LPVOID lpBits, WORD wFlags );
+
+#define FB_ACCESS 0x0001
+#define CURSOREXCLUDE 0x0008
+
+#define GREY_BIT 0x40 /* Physical color MSB. */
+
+/* DIB Engine Color Table entry. A lot like RGBQUAD. */
+typedef struct {
+ BYTE dceBlue;
+ BYTE dceGreen;
+ BYTE dceRed;
+ BYTE dceFlags;
+} DIBColorEntry;
+
+/* DIBColorEntry.dceFlags */
+#define NONSTATIC 0x80
+#define MAPTOWHITE 0x01
+
+
+/* DIB Engine Physical Object Definitions */
+
+typedef struct {
+ WORD dpPenStyle;
+ BYTE dpPenFlags;
+ BYTE dpPenBpp;
+ DWORD dpPenMono;
+ DWORD dpPenColor;
+} DIB_Pen;
+
+typedef struct {
+ BYTE dp1BrushFlags; /* Accelerator for solids */
+ BYTE dp1BrushBpp; /* Brush Bits per pixel format */
+ WORD dp1BrushStyle; /* Style of the brush */
+ DWORD dp1FgColor; /* Physical fg color */
+ WORD dp1Hatch; /* Hatching style */
+ DWORD dp1BgColor; /* Physical bg color */
+ BYTE dp1BrushMono[BRUSHSIZE*4]; /* Mono portion */
+ BYTE dp1BrushMask[BRUSHSIZE*4]; /* transparency mask (hatch pattern) */
+ BYTE dp1BrushBits[BRUSHSIZE*4]; /* 8 rows, 8 columns of 1 bit/pixel */
+} DIB_Brush1;
+
+typedef struct {
+ BYTE dp4BrushFlags; /* Accelerator for solids */
+ BYTE dp4BrushBpp; /* Brush Bits per pixel format */
+ WORD dp4BrushStyle; /* Style of the brush */
+ DWORD dp4FgColor; /* Physical fg color */
+ WORD dp4Hatch; /* Hatching style */
+ DWORD dp4BgColor; /* Physical bg color */
+ BYTE dp4BrushMono[BRUSHSIZE*4]; /* Mono portion */
+ BYTE dp4BrushMask[BRUSHSIZE*4]; /* transparency mask (hatch pattern) */
+ BYTE dp4BrushBits[BRUSHSIZE*4]; /* 8 rows, 8 columns of 4 bit/pixel */
+} DIB_Brush4;
+
+typedef struct {
+ BYTE dp8BrushFlags; /* Accelerator for solids */
+ BYTE dp8BrushBpp; /* Brush Bits per pixel format */
+ WORD dp8BrushStyle; /* Style of the brush */
+ DWORD dp8FgColor; /* Physical fg color */
+ WORD dp8Hatch; /* Hatching style */
+ DWORD dp8BgColor; /* Physical bg color */
+ BYTE dp8BrushMono[BRUSHSIZE*4]; /* Mono portion */
+ BYTE dp8BrushMask[BRUSHSIZE*4]; /* transparency mask (hatch pattern) */
+ BYTE dp8BrushBits[BRUSHSIZE*8]; /* 8 rows,8 columns of 8 bit/pixel */
+} DIB_Brush8;
+
+typedef struct {
+ BYTE dp16BrushFlags; /* Accelerator for solids */
+ BYTE dp16BrushBpp; /* Brush Bits per pixel format */
+ WORD dp16BrushStyle; /* Style of the brush */
+ DWORD dp16FgColor; /* Physical fg color */
+ WORD dp16Hatch; /* Hatching style */
+ DWORD dp16BgColor; /* Physical bg color */
+ BYTE dp16BrushMono[BRUSHSIZE*4]; /* Mono portion */
+ BYTE dp16BrushMask[BRUSHSIZE*4]; /* transparency mask (hatch pattern) */
+ BYTE dp16BrushBits[BRUSHSIZE*16];/* 8 rows,8 columns of 16 bit/pixel */
+} DIB_Brush16;
+
+typedef struct {
+ BYTE dp24BrushFlags; /* Accelerator for solids */
+ BYTE dp24BrushBpp; /* Brush Bits per pixel format */
+ WORD dp24BrushStyle; /* Style of the brush */
+ DWORD dp24FgColor; /* Physical fg color */
+ WORD dp24Hatch; /* Hatching style */
+ DWORD dp24BgColor; /* Physical bg color */
+ BYTE dp24BrushMono[BRUSHSIZE*4]; /* Mono portion */
+ BYTE dp24BrushMask[BRUSHSIZE*4]; /* transparency mask (hatch pattern) */
+ BYTE dp24BrushBits[BRUSHSIZE*24];/* 8 rows,8 columns of 24 bit/pixel */
+} DIB_Brush24;
+
+typedef struct {
+ BYTE dp32BrushFlags; /* Accelerator for solids */
+ BYTE dp32BrushBpp; /* Brush Bits per pixel format */
+ WORD dp32BrushStyle; /* Style of the brush */
+ DWORD dp32FgColor; /* Physical fg color */
+ WORD dp32Hatch; /* Hatching style */
+ DWORD dp32BgColor; /* Physical bg color */
+ BYTE dp32BrushMono[BRUSHSIZE*4]; /* Mono portion */
+ BYTE dp32BrushMask[BRUSHSIZE*4]; /* transparency mask (hatch pattern) */
+ BYTE dp32BrushBits[BRUSHSIZE*32];/* 8 rows,8 columns of 32 bit/pixel */
+} DIB_Brush32;
diff --git a/ddk/dibeng.lbc b/ddk/dibeng.lbc
new file mode 100644
index 0000000..75e59cf
--- /dev/null
+++ b/ddk/dibeng.lbc
@@ -0,0 +1,46 @@
+++DIB_BitBlt.DIBENG.1
+++DIB_ColorInfo.DIBENG.2
+++DIB_Control.DIBENG.3
+++DIB_Disable.DIBENG.4
+++DIB_Enable.DIBENG.5
+++DIB_EnumDFonts.DIBENG.6
+++DIB_EnumObj.DIBENG.7
+++DIB_Output.DIBENG.8
+++DIB_Pixel.DIBENG.9
+++DIB_RealizeObject.DIBENG.10
+++DIB_StrBlt.DIBENG.11
+++DIB_ScanLR.DIBENG.12
+++DIB_DeviceMode.DIBENG.13
+++DIB_ExtTextOut.DIBENG.14
+++DIB_GetCharWidth.DIBENG.15
+++DIB_DeviceBitmap.DIBENG.16
+++DIB_FastBorder.DIBENG.17
+++DIB_SetAttribute.DIBENG.18
+++DIB_DibBlt.DIBENG.19
+++DIB_CreateDIBitmap.DIBENG.20
+++DIB_DibToDevice.DIBENG.21
+++DIB_SetPalette.DIBENG.22
+++DIB_GetPalette.DIBENG.23
+++DIB_SetPaletteTranslate.DIBENG.24
+++DIB_GetPaletteTranslate.DIBENG.25
+++DIB_UpdateColors.DIBENG.26
+++DIB_StretchBlt.DIBENG.27
+++DIB_StretchDIBits.DIBENG.28
+++DIB_SelectBitmap.DIBENG.29
+++DIB_BitmapBits.DIBENG.30
+++DIB_Inquire.DIBENG.101
+++DIB_SetCursorExt.DIBENG.102
+++DIB_MoveCursorExt.DIBENG.103
+++DIB_CheckCursorExt.DIBENG.104
+++DIB_BeginAccess.DIBENG.105
+++DIB_EndAccess.DIBENG.106
+++CreateDIBPDevice.DIBENG.300
+++DIB_RealizeObjectExt.DIBENG.400
+++DIB_DibBltExt.DIBENG.401
+++DIB_EnumObjExt.DIBENG.402
+++DIB_ExtTextOutExt.DIBENG.403
+++DIB_UpdateColorsExt.DIBENG.404
+++DIB_SetPaletteExt.DIBENG.405
+++DIB_GetPaletteExt.DIBENG.406
+++DIB_SetPaletteTranslateExt.DIBENG.407
+++DIB_GetPaletteTranslateExt.DIBENG.408
diff --git a/ddk/gdidefs.h b/ddk/gdidefs.h
new file mode 100644
index 0000000..0f16bf7
--- /dev/null
+++ b/ddk/gdidefs.h
@@ -0,0 +1,828 @@
+
+/* Definitions for GDI drivers. */
+
+/* Physical Bitmap structure. */
+typedef struct {
+ short int bmType;
+ unsigned short int bmWidth;
+ unsigned short int bmHeight;
+ unsigned short int bmWidthBytes;
+ BYTE bmPlanes;
+ BYTE bmBitsPixel;
+ BYTE FAR *bmBits;
+ unsigned long int bmWidthPlanes;
+ BYTE FAR *bmlpPDevice;
+ unsigned short int bmSegmentIndex;
+ unsigned short int bmScanSegment;
+ unsigned short int bmFillBytes;
+ unsigned short int futureUse4;
+ unsigned short int futureUse5;
+} BITMAP;
+
+/* DIB structs also defined in windows.h. */
+typedef struct {
+ DWORD bcSize;
+ WORD bcWidth;
+ WORD bcHeight;
+ WORD bcPlanes;
+ WORD bcBitCount;
+} BITMAPCOREHEADER;
+typedef BITMAPCOREHEADER FAR *LPBITMAPCOREHEADER;
+typedef BITMAPCOREHEADER *PBITMAPCOREHEADER;
+
+typedef struct {
+ DWORD biSize;
+ DWORD biWidth;
+ DWORD biHeight;
+ WORD biPlanes;
+ WORD biBitCount;
+ DWORD biCompression;
+ DWORD biSizeImage;
+ DWORD biXPelsPerMeter;
+ DWORD biYPelsPerMeter;
+ DWORD biClrUsed;
+ DWORD biClrImportant;
+} BITMAPINFOHEADER;
+
+typedef BITMAPINFOHEADER FAR *LPBITMAPINFOHEADER;
+typedef BITMAPINFOHEADER *PBITMAPINFOHEADER;
+
+typedef struct {
+ BYTE rgbtBlue;
+ BYTE rgbtGreen;
+ BYTE rgbtRed;
+} RGBTRIPLE;
+
+typedef struct {
+ BYTE rgbBlue;
+ BYTE rgbGreen;
+ BYTE rgbRed;
+ BYTE rgbReserved;
+} RGBQUAD;
+
+/* ICM Color Definitions */
+typedef long FXPT16DOT16, FAR *LPFXPT16DOT16;
+typedef long FXPT2DOT30, FAR *LPFXPT2DOT30;
+
+typedef struct tagCIEXYZ
+{
+ FXPT2DOT30 ciexyzX;
+ FXPT2DOT30 ciexyzY;
+ FXPT2DOT30 ciexyzZ;
+} CIEXYZ;
+typedef CIEXYZ FAR *LPCIEXYZ;
+
+typedef struct tagICEXYZTRIPLE
+{
+ CIEXYZ ciexyzRed;
+ CIEXYZ ciexyzGreen;
+ CIEXYZ ciexyzBlue;
+} CIEXYZTRIPLE;
+typedef CIEXYZTRIPLE FAR *LPCIEXYZTRIPLE;
+
+typedef struct {
+ BITMAPCOREHEADER bmciHeader;
+ RGBQUAD bmciColors[1];
+} BITMAPCOREINFO;
+
+typedef BITMAPCOREINFO FAR *LPBITMAPCOREINFO;
+typedef BITMAPCOREINFO *PBITMAPCOREINFO;
+
+typedef struct {
+ BITMAPINFOHEADER bmiHeader;
+ RGBQUAD bmiColors[1];
+} BITMAPINFO;
+
+typedef BITMAPINFO FAR *LPBITMAPINFO;
+typedef BITMAPINFO *PBITMAPINFO;
+
+typedef struct {
+ DWORD bV4Size;
+ LONG bV4Width;
+ LONG bV4Height;
+ WORD bV4Planes;
+ WORD bV4BitCount;
+ DWORD bV4V4Compression;
+ DWORD bV4SizeImage;
+ LONG bV4XPelsPerMeter;
+ LONG bV4YPelsPerMeter;
+ DWORD bV4ClrUsed;
+ DWORD bV4ClrImportant;
+ DWORD bV4RedMask;
+ DWORD bV4GreenMask;
+ DWORD bV4BlueMask;
+ DWORD bV4AlphaMask;
+ DWORD bV4CSType;
+ CIEXYZTRIPLE bV4Endpoints;
+ DWORD bV4GammaRed;
+ DWORD bV4GammaGreen;
+ DWORD bV4GammaBlue;
+} BITMAPV4HEADER, FAR *LPBITMAPV4HEADER, *PBITMAPV4HEADER;
+
+typedef struct {
+ BITMAPV4HEADER bmv4Header;
+ RGBQUAD bmv4Colors[1];
+} BITMAPV4INFO;
+
+typedef BITMAPV4INFO FAR *LPBITMAPV4INFO;
+typedef BITMAPV4INFO *PBITMAPV4INFO;
+
+/* currently, if the low byte of biCompression is non zero,
+ * it must be one of following */
+
+#define BI_RGB 0x00
+#define BI_RLE8 0x01
+#define BI_RLE4 0x02
+#define BI_BITFIELDS 0x03
+
+#define BITMAP_SELECTED 0x01
+#define BITMAP_64K 0x01
+
+#define DIBSIGNATURE 0x4944
+
+/* Point types are optional. */
+#ifndef NOPTRC
+
+typedef struct {
+ short int xcoord;
+ short int ycoord;
+} PTTYPE;
+typedef PTTYPE *PPOINT;
+typedef PTTYPE FAR *LPPOINT;
+
+#define POINT PTTYPE
+
+typedef struct {
+ short int left;
+ short int top;
+ short int right;
+ short int bottom;
+} RECT;
+typedef RECT *PRECT;
+
+#endif
+
+typedef struct {
+ PTTYPE min;
+ PTTYPE ext;
+} BOXTYPE;
+typedef RECT FAR *LPRECT;
+
+/* Object definitions used by GDI support routines written in C */
+
+#define OBJ_PEN 1
+#define OBJ_BRUSH 2
+#define OBJ_FONT 3
+
+typedef struct {
+ unsigned short int lbStyle;
+ unsigned long int lbColor;
+ unsigned short int lbHatch;
+ unsigned long int lbBkColor;
+ unsigned long int lbhcmXform;
+} LOGBRUSH;
+
+#define lbPattern lbColor
+
+/* Brush Style definitions. */
+#define BS_SOLID 0
+#define BS_HOLLOW 1
+#define BS_HATCHED 2
+#define BS_PATTERN 3
+
+#define MaxBrushStyle 3
+
+/* Hatch Style definitions. */
+#define HS_HORIZONTAL 0 /* ----- */
+#define HS_VERTICAL 1 /* ||||| */
+#define HS_FDIAGONAL 2 /* ///// */
+#define HS_BDIAGONAL 3 /* \\\\\ */
+#define HS_CROSS 4 /* +++++ */
+#define HS_DIAGCROSS 5 /* xxxxx */
+
+#define MaxHatchStyle 5
+
+
+/* Logical Pen Structure. */
+typedef struct {
+ unsigned short int lopnStyle;
+ PTTYPE lopnWidth;
+ unsigned long int lopnColor;
+ unsigned short int lopnStyle2;
+ unsigned long int lopnhcmXform;
+} LOGPEN;
+
+/* Line Style definitions. */
+#define LS_SOLID 0
+#define LS_DASHED 1
+#define LS_DOTTED 2
+#define LS_DOTDASHED 3
+#define LS_DASHDOTDOT 4
+#define LS_NOLINE 5
+#define LS_INSIDEFRAME 6
+#define MaxLineStyle LS_NOLINE
+
+#define LS_ENDCAP_FLAT 0x01
+#define LS_ENDCAP_ROUND 0x02
+#define LS_ENDCAP_SQUARE 0x04
+#define LS_JOIN_BEVEL 0x08
+#define LS_JOIN_MITER 0x10
+#define LS_JOIN_ROUND 0x20
+
+
+/* The size to allocate for the lfFaceName field in the logical font. */
+#ifndef LF_FACESIZE
+#define LF_FACESIZE 32
+#endif
+
+/* Various constants for defining a logical font. */
+#define OUT_DEFAULT_PRECIS 0
+#define OUT_STRING_PRECIS 1
+#define OUT_CHARACTER_PRECIS 2
+#define OUT_STROKE_PRECIS 3
+#define OUT_TT_PRECIS 4
+#define OUT_DEVICE_PRECIS 5
+#define OUT_RASTER_PRECIS 6
+#define OUT_TT_ONLY_PRECIS 7
+
+#define CLIP_DEFAULT_PRECIS 0
+#define CLIP_CHARACTER_PRECIS 1
+#define CLIP_STROKE_PRECIS 2
+#define CLIP_MASK 0x0F
+#define CLIP_LH_ANGLES 0x10
+#define CLIP_TT_ALWAYS 0x20
+#define CLIP_EMBEDDED 0x80
+
+#define DEFAULT_QUALITY 0
+#define DRAFT_QUALITY 1
+#define PROOF_QUALITY 2
+
+#define DEFAULT_PITCH 0
+#define FIXED_PITCH 1
+#define VARIABLE_PITCH 2
+
+#define ANSI_CHARSET 0
+#define DEFAULT_CHARSET 1
+#define SYMBOL_CHARSET 2
+#define MAC_CHARSET 77
+#define SHIFTJIS_CHARSET 128
+#define HANGEUL_CHARSET 129
+#define CHINESEBIG5_CHARSET 136
+#define OEM_CHARSET 255
+
+
+/* GDI font families. */
+#define FF_DONTCARE (0<<4) /* Don't care or don't know. */
+#define FF_ROMAN (1<<4) /* Variable stroke width, serifed. */
+ /* Times Roman, Century Schoolbook, etc.*/
+#define FF_SWISS (2<<4) /* Variable stroke width, sans-serifed. */
+ /* Helvetica, Swiss, etc. */
+#define FF_MODERN (3<<4) /* Constant stroke width, serifed or sans-serifed. */
+ /* Pica, Elite, Courier, etc. */
+#define FF_SCRIPT (4<<4) /* Cursive, etc. */
+#define FF_DECORATIVE (5<<4) /* Old English, etc. */
+
+
+/* Font weights lightest to heaviest. */
+#define FW_DONTCARE 0
+#define FW_THIN 100
+#define FW_EXTRALIGHT 200
+#define FW_LIGHT 300
+#define FW_NORMAL 400
+#define FW_MEDIUM 500
+#define FW_SEMIBOLD 600
+#define FW_BOLD 700
+#define FW_EXTRABOLD 800
+#define FW_HEAVY 900
+
+#define FW_ULTRALIGHT FW_EXTRALIGHT
+#define FW_REGULAR FW_NORMAL
+#define FW_DEMIBOLD FW_SEMIBOLD
+#define FW_ULTRABOLD FW_EXTRABOLD
+#define FW_BLACK FW_HEAVY
+
+/* Enumeration font types. */
+#define RASTER_FONTTYPE 1
+#define DEVICE_FONTTYPE 2
+
+
+
+typedef struct {
+ short int lfHeight;
+ short int lfWidth;
+ short int lfEscapement;
+ short int lfOrientation;
+ short int lfWeight;
+ BYTE lfItalic;
+ BYTE lfUnderline;
+ BYTE lfStrikeOut;
+ BYTE lfCharSet;
+ BYTE lfOutPrecision;
+ BYTE lfClipPrecision;
+ BYTE lfQuality;
+ BYTE lfPitchAndFamily;
+ BYTE lfFaceName[LF_FACESIZE];
+} LOGFONT;
+
+
+#define InquireInfo 0x01 /* Inquire Device GDI Info */
+#define EnableDevice 0x00 /* Enable Device */
+#define InfoContext 0x8000 /* Inquire/Enable for info context */
+
+/* Device Technology types */
+#define DT_PLOTTER 0 /* Vector plotter */
+#define DT_RASDISPLAY 1 /* Raster display */
+#define DT_RASPRINTER 2 /* Raster printer */
+#define DT_RASCAMERA 3 /* Raster camera */
+#define DT_CHARSTREAM 4 /* Character-stream, PLP */
+#define DT_METAFILE 5 /* Metafile, VDM */
+#define DT_DISPFILE 6 /* Display-file */
+#define DT_JUMBO 11 /* SPAG LJ cool thing */
+
+/* Curve Capabilities */
+#define CC_NONE 0x0000 /* Curves not supported */
+#define CC_CIRCLES 0x0001 /* Can do circles */
+#define CC_PIE 0x0002 /* Can do pie wedges */
+#define CC_CHORD 0x0004 /* Can do chord arcs */
+#define CC_ELLIPSES 0x0008 /* Can do ellipese */
+#define CC_WIDE 0x0010 /* Can do wide lines */
+#define CC_STYLED 0x0020 /* Can do styled lines */
+#define CC_WIDESTYLED 0x0040 /* Can do wide styled lines*/
+#define CC_INTERIORS 0x0080 /* Can do interiors */
+#define CC_ROUNDRECT 0x0100 /* Can do round rectangles */
+#define CC_POLYBEZIER 0x0200 /* Can do polybeziers */
+
+/* Line Capabilities */
+#define LC_NONE 0x0000 /* Lines not supported */
+#define LC_POLYSCANLINE 0x0001 /* Poly Scanlines supported*/
+#define LC_POLYLINE 0x0002 /* Can do polylines */
+#define LC_MARKER 0x0004 /* Can do markers */
+#define LC_POLYMARKER 0x0008 /* Can do polymarkers */
+#define LC_WIDE 0x0010 /* Can do wide lines */
+#define LC_STYLED 0x0020 /* Can do styled lines */
+#define LC_WIDESTYLED 0x0040 /* Can do wide styled lines*/
+#define LC_INTERIORS 0x0080 /* Can do interiors */
+
+/* Polygonal Capabilities */
+#define PC_NONE 0x0000 /* Polygonals not supported*/
+#define PC_ALTPOLYGON 0x0001 /* Can do even odd polygons*/
+#define PC_POLYGON 0x0001 /* old name for ALTPOLYGON */
+#define PC_RECTANGLE 0x0002 /* Can do rectangles */
+#define PC_WINDPOLYGON 0x0004 /* Can do winding polygons */
+#define PC_TRAPEZOID 0x0004 /* old name for WINDPOLYGON*/
+#define PC_SCANLINE 0x0008 /* Can do scanlines */
+#define PC_WIDE 0x0010 /* Can do wide borders */
+#define PC_STYLED 0x0020 /* Can do styled borders */
+#define PC_WIDESTYLED 0x0040 /* Can do wide styled borders*/
+#define PC_INTERIORS 0x0080 /* Can do interiors */
+#define PC_POLYPOLYGON 0x0100 /* Can do PolyPolygons */
+
+/* Clipping Capabilities */
+#define CP_NONE 0x0000 /* no clipping of Output */
+#define CP_RECTANGLE 0x0001 /* Output clipped to Rects */
+#define CP_REGION 0x0002 /* not supported */
+#define CP_REGION32 0x0004 /* Output clipped to regions */
+
+/* Text Capabilities */
+#define TC_OP_CHARACTER 0x0001 /* Can do OutputPrecision CHARACTER */
+#define TC_OP_STROKE 0x0002 /* Can do OutputPrecision STROKE */
+#define TC_CP_STROKE 0x0004 /* Can do ClipPrecision STROKE */
+#define TC_CR_90 0x0008 /* Can do CharRotAbility 90 */
+#define TC_CR_ANY 0x0010 /* Can do CharRotAbility ANY */
+#define TC_SF_X_YINDEP 0x0020 /* Can do ScaleFreedom X_YINDEPENDENT */
+#define TC_SA_DOUBLE 0x0040 /* Can do ScaleAbility DOUBLE */
+#define TC_SA_INTEGER 0x0080 /* Can do ScaleAbility INTEGER */
+#define TC_SA_CONTIN 0x0100 /* Can do ScaleAbility CONTINUOUS */
+#define TC_EA_DOUBLE 0x0200 /* Can do EmboldenAbility DOUBLE */
+#define TC_IA_ABLE 0x0400 /* Can do ItalisizeAbility ABLE */
+#define TC_UA_ABLE 0x0800 /* Can do UnderlineAbility ABLE */
+#define TC_SO_ABLE 0x1000 /* Can do StrikeOutAbility ABLE */
+#define TC_RA_ABLE 0x2000 /* Can do RasterFontAble ABLE */
+#define TC_VA_ABLE 0x4000 /* Can do VectorFontAble ABLE */
+#define TC_RESERVED 0x8000 /* Reserved. Must be returned zero. */
+
+/* Raster Capabilities */
+#define RC_NONE 0x0000 /* No Raster Capabilities */
+#define RC_BITBLT 0x0001 /* Can do bitblt */
+#define RC_BANDING 0x0002 /* Requires banding support */
+#define RC_SCALING 0x0004 /* does scaling while banding */
+#define RC_BITMAP64 0x0008 /* supports >64k bitmaps */
+#define RC_GDI20_OUTPUT 0x0010 /* has 2.0 output calls */
+#define RC_GDI20_STATE 0x0020 /* dc has a state block */
+#define RC_SAVEBITMAP 0x0040 /* can save bitmaps locally */
+#define RC_DI_BITMAP 0x0080 /* can do DIBs */
+#define RC_PALETTE 0x0100 /* can do color pal management */
+#define RC_DIBTODEV 0x0200 /* can do SetDIBitsToDevice */
+#define RC_BIGFONT 0x0400 /* can do BIGFONTs */
+#define RC_STRETCHBLT 0x0800 /* can do StretchBlt */
+#define RC_FLOODFILL 0x1000 /* can do FloodFill */
+#define RC_STRETCHDIB 0x2000 /* can do StretchDIBits */
+#define RC_OP_DX_OUTPUT 0x4000 /* can do smart ExtTextOut w/dx */
+#define RC_DEVBITS 0x8000 /* supports device bitmaps */
+
+/* DC Management Flags */
+#define DC_SPDevice 0000001 /* Seperate PDevice required per device/filename */
+#define DC_1PDevice 0000002 /* Only 1 PDevice allowed per device/filename */
+#define DC_IgnoreDFNP 0000004 /* Ignore device/filename pairs when matching */
+
+/* dpCaps1 capability bits */
+#define C1_TRANSPARENT 0x0001 /* supports transparency */
+#define TC_TT_ABLE 0x0002 /* can do TT through DDI or brute */
+#define C1_TT_CR_ANY 0x0004 /* can do rotated TT fonts */
+#define C1_EMF_COMPLIANT 0x0008 /* Win95 - supports metafile spooling */
+#define C1_DIBENGINE 0x0010 /* DIB Engine compliant driver */
+#define C1_GAMMA_RAMP 0x0020 /* supports gamma ramp setting */
+#define C1_ICM 0x0040 /* does some form of ICM support */
+#define C1_REINIT_ABLE 0x0080 /* Driver supports ReEnable */
+#define C1_GLYPH_INDEX 0x0100 /* Driver supports glyph index fonts */
+#define C1_BIT_PACKED 0x0200 /* Supports bit-packed glyphs */
+#define C1_BYTE_PACKED 0x0400 /* Supports byte-packed glyphs */
+#define C1_COLORCURSOR 0x0800 /* Driver supports color_cursors and async SetCursor */
+#define C1_CMYK_ABLE 0x1000 /* Driver supports CMYK ColorRefs */
+#define C1_SLOW_CARD 0x2000 /* Little or no acceleration (VGA, etc.)*/
+
+/* dpCapsFE capability bits */
+#define FEC_TT_DBCS 0x0020 /* can output DBCS TT fonts correctly */
+#define FEC_WIFE_ABLE 0x0080 /* can handle WIFE font as Engine font */
+
+typedef struct {
+ short int dpVersion;
+ short int dpTechnology;
+ short int dpHorzSize;
+ short int dpVertSize;
+ short int dpHorzRes;
+ short int dpVertRes;
+ short int dpBitsPixel;
+ short int dpPlanes;
+ short int dpNumBrushes;
+ short int dpNumPens;
+ short int dpCapsFE;
+ short int dpNumFonts;
+ short int dpNumColors;
+ short int dpDEVICEsize;
+ unsigned short int dpCurves;
+ unsigned short int dpLines;
+ unsigned short int dpPolygonals;
+ unsigned short int dpText;
+ unsigned short int dpClip;
+ unsigned short int dpRaster;
+ short int dpAspectX;
+ short int dpAspectY;
+ short int dpAspectXY;
+ short int dpStyleLen;
+ PTTYPE dpMLoWin;
+ PTTYPE dpMLoVpt;
+ PTTYPE dpMHiWin;
+ PTTYPE dpMHiVpt;
+ PTTYPE dpELoWin;
+ PTTYPE dpELoVpt;
+ PTTYPE dpEHiWin;
+ PTTYPE dpEHiVpt;
+ PTTYPE dpTwpWin;
+ PTTYPE dpTwpVpt;
+ short int dpLogPixelsX;
+ short int dpLogPixelsY;
+ short int dpDCManage;
+ unsigned short int dpCaps1;
+ short int futureuse4;
+ short int futureuse5;
+ short int futureuse6;
+ short int futureuse7;
+ WORD dpNumPalReg;
+ WORD dpPalReserved;
+ WORD dpColorRes;
+} GDIINFO;
+
+/* This bit in the dfType field signals that the dfBitsOffset field is an
+ absolute memory address and should not be altered. */
+#define PF_BITS_IS_ADDRESS 4
+
+/* This bit in the dfType field signals that the font is device realized. */
+#define PF_DEVICE_REALIZED 0x80
+
+/* These bits in the dfType give the fonttype -
+ raster, vector, other1, other2. */
+#define PF_RASTER_TYPE 0
+#define PF_VECTOR_TYPE 1
+#define PF_OTHER1_TYPE 2
+#define PF_OTHER2_TYPE 3
+#define PF_GLYPH_INDEX 0x20
+#define PF_WIFE_TYPE 0x08
+
+/* Glyph types for EngineGetGlyphBmp */
+#define EGB_BITMAP 1
+#define EGB_OUTLINE 2
+#define EGB_GRAY2_BITMAP 8
+#define EGB_GRAY4_BITMAP 9
+#define EGB_GRAY8_BITMAP 10
+
+
+/* The size to allocate for the dfMaps field in the physical font. */
+#ifndef DF_MAPSIZE
+#define DF_MAPSIZE 1
+#endif
+
+/* Font structure. */
+typedef struct {
+ short int dfType;
+ short int dfPoints;
+ short int dfVertRes;
+ short int dfHorizRes;
+ short int dfAscent;
+ short int dfInternalLeading;
+ short int dfExternalLeading;
+ BYTE dfItalic;
+ BYTE dfUnderline;
+ BYTE dfStrikeOut;
+ short int dfWeight;
+ BYTE dfCharSet;
+ short int dfPixWidth;
+ short int dfPixHeight;
+ BYTE dfPitchAndFamily;
+ short int dfAvgWidth;
+ short int dfMaxWidth;
+ BYTE dfFirstChar;
+ BYTE dfLastChar;
+ BYTE dfDefaultChar;
+ BYTE dfBreakChar;
+ short int dfWidthBytes;
+ unsigned long int dfDevice;
+ unsigned long int dfFace;
+ unsigned long int dfBitsPointer;
+ unsigned long int dfBitsOffset;
+ BYTE dfReservedByte;
+ unsigned short dfMaps[DF_MAPSIZE];
+} FONTINFO;
+
+
+typedef struct {
+ short int erType;
+ short int erPoints;
+ short int erVertRes;
+ short int erHorizRes;
+ short int erAscent;
+ short int erInternalLeading;
+ short int erExternalLeading;
+ BYTE erItalic;
+ BYTE erUnderline;
+ BYTE erStrikeOut;
+ short int erWeight;
+ BYTE erCharSet;
+ short int erPixWidth;
+ short int erPixHeight;
+ BYTE erPitchAndFamily;
+ short int erAvgWidth;
+ short int erMaxWidth;
+ BYTE erFirstChar;
+ BYTE erLastChar;
+ BYTE erDefaultChar;
+ BYTE erBreakChar;
+ short int erWidthBytes;
+ unsigned long int erDevice;
+ unsigned long int erFace;
+ unsigned long int erBitsPointer;
+ unsigned long int erBitsOffset;
+ BYTE erReservedByte;
+ short int erUnderlinePos;
+ short int erUnderlineThick;
+ short int erStrikeoutPos;
+ short int erStrikeoutThick;
+} SCALABLEFONTINFO;
+
+
+typedef struct {
+ short int ftHeight;
+ short int ftWidth;
+ short int ftEscapement;
+ short int ftOrientation;
+ short int ftWeight;
+ BYTE ftItalic;
+ BYTE ftUnderline;
+ BYTE ftStrikeOut;
+ BYTE ftOutPrecision;
+ BYTE ftClipPrecision;
+ unsigned short int ftAccelerator;
+ short int ftOverhang;
+} TEXTXFORM;
+
+
+typedef struct {
+ short int tmHeight;
+ short int tmAscent;
+ short int tmDescent;
+ short int tmInternalLeading;
+ short int tmExternalLeading;
+ short int tmAveCharWidth;
+ short int tmMaxCharWidth;
+ short int tmWeight;
+ BYTE tmItalic;
+ BYTE tmUnderlined;
+ BYTE tmStruckOut;
+ BYTE tmFirstChar;
+ BYTE tmLastChar;
+ BYTE tmDefaultChar;
+ BYTE tmBreakChar;
+ BYTE tmPitchAndFamily;
+ BYTE tmCharSet;
+ short int tmOverhang;
+ short int tmDigitizedAspectX;
+ short int tmDigitizedAspectY;
+} TEXTMETRIC;
+
+typedef struct {
+ short int Rop2;
+ short int bkMode;
+ unsigned long int bkColor;
+ unsigned long int TextColor;
+ short int TBreakExtra;
+ short int BreakExtra;
+ short int BreakErr;
+ short int BreakRem;
+ short int BreakCount;
+ short int CharExtra;
+ unsigned long int LbkColor;
+ unsigned long int LTextColor;
+ DWORD ICMCXform;
+ short StretchBltMode;
+ DWORD eMiterLimit;
+} DRAWMODE;
+
+
+/* Background Mode definitions. */
+#define TRANSPARENT 1
+#define OPAQUE 2
+
+#define BKMODE_TRANSPARENT 1
+#define BKMODE_OPAQUE 2
+#define BKMODE_LEVEL1 3
+#define BKMODE_LEVEL2 4
+#define BKMODE_LEVEL3 5
+#define BKMODE_TRANSLATE 6
+
+/* StretchBlt Mode definitions. */
+#define STRETCH_ANDSCANS 1
+#define STRETCH_ORSCANS 2
+#define STRETCH_DELETESCANS 3
+#define STRETCH_HALFTONE 4
+
+#define SBM_BLACKONWHITE STRETCH_ANDSCANS
+#define SBM_WHITEONBLACK STRETCH_ORSCANS
+#define SBM_COLORONCOLOR STRETCH_DELETESCANS
+#define SBM_HALFTONE STRETCH_HALFTONE
+
+typedef struct {
+ short int scnPntCnt;
+ short int scnPntTop;
+ short int scnPntBottom;
+ short int scnPntX[2];
+ short int scnPntCntToo;
+} SCAN, FAR* LPSCAN;
+
+typedef struct {
+ DWORD cbSize;
+ LPVOID lpDestDev;
+ DWORD nEscape;
+ DWORD cbInput;
+ LPVOID lpInput;
+ POINT ptOrigin;
+ DWORD dwUniq;
+ RECT rcBBox;
+ DWORD cScans;
+ LPSCAN lpScan;
+} DRAWESCAPE, FAR* LPDRAWESCAPE;
+
+typedef struct {
+ WORD id;
+ WORD cbSize;
+ LPRECT lprcClip;
+ DWORD dwUniq;
+ RECT rcBBox;
+ DWORD cScans;
+ LPSCAN lpScan;
+} REGION, FAR* LPREGION;
+
+
+/* Output Style definitions. */
+
+#define OS_POLYBEZIER 1
+#define OS_ARC 3
+#define OS_SCANLINES 4
+#define OS_POLYSCANLINE 5
+#define OS_RECTANGLE 6
+#define OS_ELLIPSE 7
+#define OS_MARKER 8
+#define OS_POLYLINE 18
+#define OS_TRAPEZOID 20
+#define OS_WINDPOLYGON OS_TRAPEZOID
+#define OS_POLYGON 22
+#define OS_ALTPOLYGON OS_POLYGON
+#define OS_PIE 23
+#define OS_POLYMARKER 24
+#define OS_CHORD 39
+#define OS_CIRCLE 55
+
+#define OS_POLYPOLYGON 0x4000 /* ORed with OS_WIND/ALTPOLYGON. */
+
+#define OS_BEGINNSCAN 80
+#define OS_ENDNSCAN 81
+
+#define OEM_FAILED 0x80000000L
+
+#define NEWFRAME 1
+#define ABORTDOC 2
+#define NEXTBAND 3
+#define SETCOLORTABLE 4
+#define GETCOLORTABLE 5
+#define FLUSHOUTPUT 6
+#define DRAFTMODE 7
+#define QUERYESCSUPPORT 8
+#define SETPRINTERDC 9 /* DDK: between GDI and Driver. */
+#define SETABORTPROC 9 /* SDK: between application and GDI. */
+#define STARTDOC 10
+#define ENDDOC 11
+#define GETPHYSPAGESIZE 12
+#define GETPRINTINGOFFSET 13
+#define GETSCALINGFACTOR 14
+#define MFCOMMENT 15
+#define GETPENWIDTH 16
+#define SETCOPYCOUNT 17
+#define SELECTPAPERSOURCE 18
+#define DEVICEDATA 19
+#define PASSTHROUGH 19
+#define GETTECHNOLGY 20
+#define GETTECHNOLOGY 20
+#define SETLINECAP 21
+#define SETLINEJOIN 22
+#define SETMITERLIMIT 23
+#define BANDINFO 24
+#define DRAWPATTERNRECT 25
+#define GETVECTORPENSIZE 26
+#define GETVECTORBRUSHSIZE 27
+#define ENABLEDUPLEX 28
+#define GETSETPAPERBINS 29
+#define GETSETPRINTORIENT 30
+#define ENUMPAPERBINS 31
+#define SETDIBSCALING 32
+#define EPSPRINTING 33
+#define ENUMPAPERMETRICS 34
+#define GETSETPAPERMETRICS 35
+#define GETVERSION 36
+#define POSTSCRIPT_DATA 37
+#define POSTSCRIPT_IGNORE 38
+#define QUERYROPSUPPORT 40
+#define GETDEVICEUNITS 42
+#define RESETDEVICE 128
+#define GETEXTENDEDTEXTMETRICS 256
+#define GETEXTENTTABLE 257
+#define GETPAIRKERNTABLE 258
+#define GETTRACKKERNTABLE 259
+#define EXTTEXTOUT 512
+#define GETFACENAME 513
+#define DOWNLOADFACE 514
+#define ENABLERELATIVEWIDTHS 768
+#define ENABLEPAIRKERNING 769
+#define SETKERNTRACK 770
+#define SETALLJUSTVALUES 771
+#define SETCHARSET 772
+#define STRETCHBLT 2048
+#define QUERYDIBSUPPORT 3073
+#define QDI_SETDIBITS 0x0001
+#define QDI_GETDIBITS 0x0002
+#define QDI_DIBTOSCREEN 0x0004
+#define QDI_STRETCHDIB 0x0008
+#define DCICOMMAND 3075
+#define BEGIN_PATH 4096
+#define CLIP_TO_PATH 4097
+#define END_PATH 4098
+#define EXT_DEVICE_CAPS 4099
+#define RESTORE_CTM 4100
+#define SAVE_CTM 4101
+#define SET_ARC_DIRECTION 4102
+#define SET_BACKGROUND_COLOR 4103
+#define SET_POLY_MODE 4104
+#define SET_SCREEN_ANGLE 4105
+#define SET_SPREAD 4106
+#define TRANSFORM_CTM 4107
+#define SET_CLIP_BOX 4108
+#define SET_BOUNDS 4109
+#define OPENCHANNEL 4110
+#define DOWNLOADHEADER 4111
+#define CLOSECHANNEL 4112
+#define SETGDIXFORM 4113
+#define RESETPAGE 4114
+#define POSTSCRIPT_PASSTHROUGH 4115
+#define ENCAPSULATED_POSTSCRIPT 4116
+
+
+typedef FONTINFO FAR *LPFONTINFO;
+typedef DRAWMODE FAR *LPDRAWMODE;
+typedef TEXTXFORM FAR *LPTEXTXFORM;
+typedef TEXTMETRIC FAR *LPTEXTMETRIC;
+typedef LOGFONT FAR *LPLOGFONT;
+typedef LOGPEN FAR *LPLOGPEN;
+typedef LOGBRUSH FAR *LPLOGBRUSH;
+typedef BITMAP FAR *LPBITMAP;
+typedef FARPROC FAR *LPFARPROC;
+typedef GDIINFO FAR *LPGDIINFO;
+typedef SCALABLEFONTINFO FAR * LPSCALABLEFONTINFO;
+
diff --git a/ddk/minivdd.h b/ddk/minivdd.h
new file mode 100644
index 0000000..6fa7d4e
--- /dev/null
+++ b/ddk/minivdd.h
@@ -0,0 +1,114 @@
+
+/* Functions callable via VDD's API entry point, usually called by display
+ * drivers.
+ */
+#define MINIVDD_SVC_BASE_OFFSET 0x80
+#define VDD_DRIVER_REGISTER (0 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_DRIVER_UNREGISTER (1 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_SAVE_DRIVER_STATE (2 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_REGISTER_DISPLAY_DRIVER_INFO (3 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_REGISTER_SSB_FLAGS (4 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_GET_DISPLAY_CONFIG (5 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_PRE_MODE_CHANGE (6 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_POST_MODE_CHANGE (7 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_SET_USER_FLAGS (8 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_SET_BUSY_FLAG_ADDR (9 + MINIVDD_SVC_BASE_OFFSET)
+
+/* The DISPLAYINFO structure for querying Registry information. */
+typedef struct {
+ WORD diHdrSize;
+ WORD diInfoFlags;
+ DWORD diDevNodeHandle;
+ char diDriverName[16];
+ WORD diXRes;
+ WORD diYRes;
+ WORD diDPI;
+ BYTE diPlanes;
+ BYTE diBpp;
+ WORD diRefreshRateMax;
+ WORD diRefreshRateMin;
+ WORD diLowHorz;
+ WORD diHighHorz;
+ WORD diLowVert;
+ WORD diHighVert;
+ DWORD diMonitorDevNodeHandle;
+ BYTE diHorzSyncPolarity;
+ BYTE diVertSyncPolarity;
+} DISPLAYINFO;
+
+/* diInfoFlags */
+#define RETURNED_DATA_IS_STALE 0x001 /* VDD couldn't read Registry, data could be old. */
+#define MINIVDD_FAILED_TO_LOAD 0x002 /* MiniVDD did not load, probably bad config. */
+#define MINIVDD_CHIP_ID_DIDNT_MATCH 0x004 /* ChipID mismatch, probably bad config. */
+#define REGISTRY_BPP_NOT_VALID 0x008 /* BPP could not be read from Registry. */
+#define REGISTRY_RESOLUTION_NOT_VALID 0x010 /* Resolution could not be read from Registry. */
+#define REGISTRY_DPI_NOT_VALID 0x020 /* DPI could not be read from Registry. */
+#define MONITOR_DEVNODE_NOT_ACTIVE 0x040 /* Devnode not there, no refresh rate data. */
+#define MONITOR_INFO_NOT_VALID 0x080 /* Refresh rate data could not be read. */
+#define MONITOR_INFO_DISABLED_BY_USER 0x100 /* Refresh rate data not valid. */
+#define REFRESH_RATE_MAX_ONLY 0x200 /* Only diRefreshRateMax is valid. */
+#define CARD_VDD_LOADED_OK 0x400 /* Second MiniVDD loaded fine. */
+
+/* Funcrions callable in a mini-VDD. */
+#define REGISTER_DISPLAY_DRIVER 0
+#define GET_VDD_BANK 1
+#define SET_VDD_BANK 2
+#define RESET_BANK 3
+#define PRE_HIRES_TO_VGA 4
+#define POST_HIRES_TO_VGA 5
+#define PRE_VGA_TO_HIRES 6
+#define POST_VGA_TO_HIRES 7
+#define SAVE_REGISTERS 8
+#define RESTORE_REGISTERS 9
+#define MODIFY_REGISTER_STATE 10
+#define ACCESS_VGA_MEMORY_MODE 11
+#define ACCESS_LINEAR_MEMORY_MODE 12
+#define ENABLE_TRAPS 13
+#define DISABLE_TRAPS 14
+#define MAKE_HARDWARE_NOT_BUSY 15
+#define VIRTUALIZE_CRTC_IN 16
+#define VIRTUALIZE_CRTC_OUT 17
+#define VIRTUALIZE_SEQUENCER_IN 18
+#define VIRTUALIZE_SEQUENCER_OUT 19
+#define VIRTUALIZE_GCR_IN 20
+#define VIRTUALIZE_GCR_OUT 21
+#define SET_LATCH_BANK 22
+#define RESET_LATCH_BANK 23
+#define SAVE_LATCHES 24
+#define RESTORE_LATCHES 25
+#define DISPLAY_DRIVER_DISABLING 26
+#define SELECT_PLANE 27
+#define PRE_CRTC_MODE_CHANGE 28
+#define POST_CRTC_MODE_CHANGE 29
+#define VIRTUALIZE_DAC_OUT 30
+#define VIRTUALIZE_DAC_IN 31
+#define GET_CURRENT_BANK_WRITE 32
+#define GET_CURRENT_BANK_READ 33
+#define SET_BANK 34
+#define CHECK_HIRES_MODE 35
+#define GET_TOTAL_VRAM_SIZE 36
+#define GET_BANK_SIZE 37
+#define SET_HIRES_MODE 38
+#define PRE_HIRES_SAVE_RESTORE 39
+#define POST_HIRES_SAVE_RESTORE 40
+#define VESA_SUPPORT 41
+#define GET_CHIP_ID 42
+#define CHECK_SCREEN_SWITCH_OK 43
+#define VIRTUALIZE_BLTER_IO 44
+#define SAVE_MESSAGE_MODE_STATE 45
+#define SAVE_FORCED_PLANAR_STATE 46
+#define VESA_CALL_POST_PROCESSING 47
+#define PRE_INT_10_MODE_SET 48
+
+#define NBR_MINI_VDD_FUNCTIONS 49
+
+/* Port sizes. */
+#define BYTE_LENGTHED 1
+#define WORD_LENGTHED 2
+
+/* Flag bits. */
+#define GOING_TO_WINDOWS_MODE 1
+#define GOING_TO_VGA_MODE 2
+#define DISPLAY_DRIVER_DISABLED 4
+#define IN_WINDOWS_HIRES_MODE 8
+
diff --git a/ddk/valmode.h b/ddk/valmode.h
new file mode 100644
index 0000000..0fccdcb
--- /dev/null
+++ b/ddk/valmode.h
@@ -0,0 +1,20 @@
+
+/* Return values for ValidateMode. */
+#define VALMODE_YES 0 /* Mode is good. */
+#define VALMODE_NO_WRONGDRV 1 /* Hardware not supported by driver. */
+#define VALMODE_NO_NOMEM 2 /* Insufficient video memory. */
+#define VALMODE_NO_NODAC 3 /* DAC cannot handle bit depth. */
+#define VALMODE_NO_UNKNOWN 4 /* Some other problem. */
+
+
+/* Structure describing a display mode. */
+typedef struct {
+ UINT dvmSize; /* Size of this struct. */
+ UINT dvmBpp; /* Mode color depth. */
+ int dvmXRes; /* Mode X resolution. */
+ int dvmYRes; /* Mode Y resolution. */
+} DISPVALMODE;
+
+/* Must be exported by name from driver. Recommended ordinal is 700. */
+extern UINT WINAPI ValidateMode( DISPVALMODE FAR *lpMode );
+
diff --git a/dibcall.c b/dibcall.c
new file mode 100644
index 0000000..7591b44
--- /dev/null
+++ b/dibcall.c
@@ -0,0 +1,114 @@
+/*****************************************************************************
+
+Copyright (c) 2022 Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+
+#include "winhack.h"
+#include <gdidefs.h>
+#include <dibeng.h>
+#include <minivdd.h>
+
+#include "minidrv.h"
+
+/*
+ * What's this all about? Most of the required exported driver functions can
+ * be passed straight to the DIB Engine. The DIB Engine in some cases requires
+ * an additional parameter.
+ *
+ * See the dibthunk.asm module for functions that can be handled easily. Note
+ * that although the logic could be implemented in C, it can be done more
+ * efficiently in assembly. Forwarders turn into simple jumps, and functions
+ * with an extra parameter can be implemented with very small overhead, saving
+ * stack space and extra copying.
+ *
+ * This module deals with the very few functions that need additional logic but
+ * are not hardware specific.
+ */
+
+#pragma code_seg( _TEXT )
+
+/* Exported as DISPLAY.104 */
+void WINAPI __loadds CheckCursor( void )
+{
+ if( wEnabled ) {
+ DIB_CheckCursorExt( lpDriverPDevice );
+ }
+}
+
+/* If there is no hardware screen-to-screen BitBlt, there's no point in
+ * this and we can just forward BitBlt to the DIB Engine.
+ */
+#ifdef HWBLT
+
+extern BOOL WINAPI (* BitBltDevProc)( LPDIBENGINE, WORD, WORD, LPPDEVICE, WORD, WORD,
+ WORD, WORD, DWORD, LPBRUSH, LPDRAWMODE );
+
+/* See if a hardware BitBlt can be done. */
+BOOL WINAPI __loadds BitBlt( LPDIBENGINE lpDestDev, WORD wDestX, WORD wDestY, LPPDEVICE lpSrcDev,
+ WORD wSrcX, WORD wSrcY, WORD wXext, WORD wYext, DWORD dwRop3,
+ LPBRUSH lpPBrush, LPDRAWMODE lpDrawMode )
+{
+ WORD dstFlags = lpDestDev->deFlags;
+
+ /* The destination must be video memory and not busy. */
+ if( (dstFlags & VRAM) && !(dstFlags & BUSY) ) {
+ /* If palette translation is needed, only proceed if source
+ * and destination device are identical.
+ */
+ if( !(dstFlags & PALETTE_XLAT) || (lpDestDev == lpSrcDev) ) {
+ /* If there is a hardware acceleration callback, use it. */
+ if( BitBltDevProc ) {
+ return( BitBltDevProc( lpDestDev, wDestX, wDestY, lpSrcDev, wSrcX, wSrcY, wXext, wYext, dwRop3, lpPBrush, lpDrawMode ) );
+ }
+ }
+ }
+ return( DIB_BitBlt( lpDestDev, wDestX, wDestY, lpSrcDev, wSrcX, wSrcY, wXext, wYext, dwRop3, lpPBrush, lpDrawMode ) );
+}
+
+#endif
+
+#ifndef ETO_GLYPH_INDEX
+#define ETO_GLYPH_INDEX 0x0010
+#endif
+
+DWORD WINAPI __loadds ExtTextOut( LPDIBENGINE lpDestDev, WORD wDestXOrg, WORD wDestYOrg, LPRECT lpClipRect,
+ LPSTR lpString, int wCount, LPFONTINFO lpFontInfo, LPDRAWMODE lpDrawMode,
+ LPTEXTXFORM lpTextXForm, LPSHORT lpCharWidths, LPRECT lpOpaqueRect, WORD wOptions )
+{
+/* if(wOptions & ETO_GLYPH_INDEX)
+ {
+ return 0x80000000UL;
+ }*/
+
+ /*if(wCount > 0)
+ {
+ dbg_printf("ExtTextOut: ");
+ for(i = 0; i < wCount; i++)
+ {
+ dbg_printf("%c", lpString[i]);
+ }
+ dbg_printf("(%X) %d\n", lpString[0], wCount);
+ }*/
+
+ return DIB_ExtTextOut(lpDestDev, wDestXOrg, wDestYOrg, lpClipRect, lpString, wCount, lpFontInfo, lpDrawMode, lpTextXForm, lpCharWidths, lpOpaqueRect, wOptions);
+}
diff --git a/dibthunk.asm b/dibthunk.asm
new file mode 100644
index 0000000..3bcdde7
--- /dev/null
+++ b/dibthunk.asm
@@ -0,0 +1,114 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Copyright (c) 2022 Michal Necasek
+;
+; Permission is hereby granted, free of charge, to any person obtaining a copy
+; of this software and associated documentation files (the "Software"), to deal
+; in the Software without restriction, including without limitation the rights
+; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+; copies of the Software, and to permit persons to whom the Software is
+; furnished to do so, subject to the following conditions:
+;
+; The above copyright notice and this permission notice shall be included in
+; all copies or substantial portions of the Software.
+;
+; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+; THE SOFTWARE.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Define a macro which produces a DIB engine thunk, taking care of all
+; externs and publics.
+; The DIB_xxxExt functions take one additional parameter. To minimize
+; stack space copying and usage, the thunk pops off the return address,
+; pushes the additional parameter (always the last parameter of
+; DIB_xxxExt), pushes the return address back, and jumps to DIB_xxxExt.
+; The AX, ECX, and ES registers are modified with no ill effect since
+; they aren't used by the Pascal calling convention to pass arguments.
+
+;; Thunk macro with additional parameters.
+DIBTHK macro name, param
+extrn DIB_&name&Ext : far
+public name
+name:
+ mov ax, DGROUP ; Load ES with our data segment.
+ mov es, ax
+ assume es:DGROUP
+ pop ecx ; Save the 16:16 return address in ECX.
+ push param ; Push the additional parameter.
+ push ecx ; Put the return address back.
+ jmp DIB_&name&Ext ; Off to the DIB Engine we go.
+ endm
+
+;; Simple forwarder macro.
+DIBFWD macro name
+extrn DIB_&name : far
+public name
+name:
+ jmp DIB_&name ; Just jump to the DIB Engine.
+ endm
+
+;; Additional variables that need to be pushed are in the data segment.
+_DATA segment public 'DATA'
+
+extrn _lpDriverPDevice : dword
+extrn _wPalettized : word
+
+_DATA ends
+
+DGROUP group _DATA
+
+_TEXT segment public 'CODE'
+
+.386
+assume ds:nothing, es:nothing
+
+;; Thunks that push an additional parameter.
+;; Sorted by ordinal number.
+DIBTHK EnumObj, _lpDriverPDevice
+DIBTHK RealizeObject, _lpDriverPDevice
+DIBTHK DibBlt, _wPalettized
+DIBTHK GetPalette, _lpDriverPDevice
+DIBTHK SetPaletteTranslate, _lpDriverPDevice
+DIBTHK GetPaletteTranslate, _lpDriverPDevice
+DIBTHK UpdateColors, _lpDriverPDevice
+DIBTHK SetCursor, _lpDriverPDevice
+DIBTHK MoveCursor, _lpDriverPDevice
+
+;; Forwarders that simply jump to the DIB Engine.
+;; Sorted by ordinal number.
+ifndef HWBLT
+DIBFWD BitBlt
+endif
+DIBFWD ColorInfo
+;DIBFWD Control
+DIBFWD EnumDFonts
+DIBFWD Output
+DIBFWD Pixel
+DIBFWD Strblt
+DIBFWD ScanLR
+DIBFWD DeviceMode
+;DIBFWD ExtTextOut
+DIBFWD GetCharWidth
+DIBFWD DeviceBitmap
+DIBFWD FastBorder
+DIBFWD SetAttribute
+DIBFWD CreateDIBitmap
+DIBFWD DibToDevice
+DIBFWD StretchBlt
+DIBFWD StretchDIBits
+DIBFWD SelectBitmap
+DIBFWD BitmapBits
+DIBFWD Inquire
+
+
+
+_TEXT ends
+
+end
+
diff --git a/docs/font-bug.png b/docs/font-bug.png
new file mode 100644
index 0000000..81dd609
--- /dev/null
+++ b/docs/font-bug.png
Binary files differ
diff --git a/dpmi.h b/dpmi.h
new file mode 100644
index 0000000..aab6467
--- /dev/null
+++ b/dpmi.h
@@ -0,0 +1,119 @@
+#ifndef __DPMI_H__INCLUDED__
+#define __DPMI_H__INCLUDED__
+
+extern WORD DPMI_AllocLDTDesc( WORD cSelectors );
+#pragma aux DPMI_AllocLDTDesc = \
+ "xor ax, ax" \
+ "int 31h" \
+ "jnc OK" \
+ "xor ax, ax" \
+ "OK:" \
+ parm [cx];
+
+extern DWORD DPMI_GetSegBase( WORD Selector );
+#pragma aux DPMI_GetSegBase = \
+ "mov ax, 6" \
+ "int 31h" \
+ "mov ax, cx" \
+ "xchg ax, dx" \
+ parm [bx] modify [cx];
+
+extern void DPMI_SetSegBase( WORD Selector, DWORD Base );
+#pragma aux DPMI_SetSegBase = \
+ "mov ax, 7" \
+ "int 31h" \
+ parm [bx] [cx dx];
+
+extern void DPMI_SetSegLimit( WORD Selector, DWORD Limit );
+#pragma aux DPMI_SetSegLimit = \
+ "mov ax, 8" \
+ "int 31h" \
+ parm [bx] [cx dx];
+
+/* NB: Compiler insists on CX:BX and DI:SI, DPMI needs it word swapped. */
+extern DWORD DPMI_MapPhys( DWORD Base, DWORD Size );
+#pragma aux DPMI_MapPhys = \
+ "xchg cx, bx" \
+ "xchg si, di" \
+ "mov ax, 800h" \
+ "int 31h" \
+ "jnc OK" \
+ "xor bx, bx" \
+ "xor cx, cx" \
+ "OK:" \
+ "mov dx, bx" \
+ "mov ax, cx" \
+ parm [cx bx] [di si];
+
+extern DWORD DPMI_AllocMemBlk(DWORD Size);
+#pragma aux DPMI_AllocMemBlk = \
+ "xchg cx, bx" \
+ "mov ax, 501h" \
+ "int 31h" \
+ "jnc alloc_ok" \
+ "xor bx, bx" \
+ "xor cx, cx" \
+ "alloc_ok:" \
+ "mov dx, bx" \
+ "mov ax, cx" \
+ parm [cx bx] modify [di si];
+
+
+static DWORD DPMI_AllocLinBlk_LinAddress = 0;
+static DWORD DPMI_AllocLinBlk_MHandle = 0;
+
+extern WORD DPMI_AllocLinBlk(DWORD size);
+#pragma aux DPMI_AllocLinBlk = \
+ ".386" \
+ "push ebx" \
+ "push ecx" \
+ "push esi" \
+ "push edx" \
+ "push eax" \
+ "shl ecx, 16" \
+ "mov cx, bx" \
+ "xor ebx, ebx" \
+ "mov edx, 1" \
+ "mov eax, 504h" /* alloc linear address (in EBX, handle in ESI) */ \
+ "int 31h" \
+ "jc alloc_fail" \
+ "mov dword ptr [DPMI_AllocLinBlk_LinAddress], ebx" \
+ "mov dword ptr [DPMI_AllocLinBlk_MHandle], esi" \
+ "pop eax" \
+ "mov ax, 0" \
+ "pop edx" \
+ "pop esi" \
+ "pop ecx" \
+ "pop ebx" \
+ "jmp alloc_end" \
+ "alloc_fail:" \
+ "mov dword ptr [DPMI_AllocLinBlk_LinAddress], ecx" \
+ "mov dx, ax" \
+ "pop eax" \
+ "mov ax, dx" \
+ "pop edx" \
+ "pop esi" \
+ "pop ecx" \
+ "pop ebx" \
+ "alloc_end:" \
+ parm [cx bx] modify [ax];
+
+extern WORD DPMI_LockRegion(DWORD linAddress, DWORD size);
+#pragma aux DPMI_LockRegion = \
+ "xchg cx, bx" \
+ "xchg si, di" \
+ "mov ax, 600h" \
+ "int 31h" \
+ "jc lock_fail" \
+ "xor ax, ax" \
+ "lock_fail:" \
+ parm [cx bx] [di si] modify [ax];
+
+extern void DPMI_FreeLDTDesc ( WORD desc);
+#pragma aux DPMI_FreeLDTDesc = \
+ "mov ax, 1" \
+ "int 31h" \
+ parm [bx];
+
+
+#endif /* __DPMI_H__INCLUDED__ */
diff --git a/drvlib.c b/drvlib.c
new file mode 100644
index 0000000..f25db8a
--- /dev/null
+++ b/drvlib.c
@@ -0,0 +1,48 @@
+#include <string.h>
+#include "winhack.h"
+
+#include "drvlib.h"
+#include "dpmi.h"
+
+#pragma code_seg( _INIT )
+
+void drv_memcpy(void __far *dst, void __far *src, long size)
+{
+ unsigned char __far *psrc = src;
+ unsigned char __far *pdst = dst;
+
+
+ while(size-- > 0)
+ {
+ *pdst = *psrc;
+
+ psrc++;
+ pdst++;
+ }
+}
+
+
+void __far *drv_malloc(DWORD dwSize, DWORD __far *lpLinear)
+{
+ WORD wSel;
+ DWORD dwLin;
+
+ wSel = DPMI_AllocLDTDesc(1);
+ if(!wSel)
+ return NULL;
+
+ /* Map the framebuffer physical memory. */
+ dwLin = DPMI_AllocMemBlk(dwSize);
+
+ if(dwLin)
+ {
+ DPMI_SetSegBase(wSel, dwLin);
+ DPMI_SetSegLimit(wSel, dwSize - 1);
+
+ *lpLinear = dwLin;
+
+ return wSel :> 0;
+ }
+
+ return NULL;
+}
diff --git a/drvlib.h b/drvlib.h
new file mode 100644
index 0000000..5755bf5
--- /dev/null
+++ b/drvlib.h
@@ -0,0 +1,7 @@
+#ifndef __DRVLIB_H__INCLUDED__
+#define __DRVLIB_H__INCLUDED__
+
+void drv_memcpy(void __far *dst, void __far *src, long size);
+void __far *drv_malloc(DWORD dwSize, DWORD __far *lpLinear);
+
+#endif /* __DRVLIB_H__INCLUDED__ */
diff --git a/enable.c b/enable.c
new file mode 100644
index 0000000..7aa3271
--- /dev/null
+++ b/enable.c
@@ -0,0 +1,465 @@
+/*****************************************************************************
+
+Copyright (c) 2022 Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* GDI Enable (with ReEnable) and Disable implementation. */
+
+#include "winhack.h"
+#include <gdidefs.h>
+#include <dibeng.h>
+#include <minivdd.h>
+#include "minidrv.h"
+
+#include <string.h>
+
+/* Pretend we have a 208 by 156 mm screen. */
+#define DISPLAY_HORZ_MM 208
+#define DISPLAY_VERT_MM 156
+
+/* Size in English units. Looks pretty random. */
+#define DISPLAY_SIZE_EN 325
+/* Size in twips. Just as random. */
+#define DISPLAY_SIZE_TWP 2340
+
+LPDIBENGINE lpDriverPDevice = 0; /* This device's PDEV that's passed to GDI. */
+WORD wEnabled = 0; /* Is this device enabled? */
+RGBQUAD FAR *lpColorTable = 0; /* Current color table. */
+
+static BYTE bReEnabling = 0; /* Set when re-enabling PDEV. */
+static WORD wDIBPdevSize = 0;
+
+
+/* 1bpp Color Table (non-palettized). */
+const DIBColorEntry DIB1ColorTable[] = {
+ /* blue red green flags */
+ { 0 , 0 , 0 , 0 },
+ { 0xFF, 0xFF, 0xFF, MAPTOWHITE }
+};
+
+/* 4bpp Color Table (non-palettized). */
+const DIBColorEntry DIB4ColorTable[] = {
+ /* blue red green flags */
+ { 0 , 0 , 0 , 0 },
+ { 0 , 0 , 0x80, 0 },
+ { 0 , 0x80, 0 , 0 },
+ { 0 , 0x80, 0x80, 0 },
+ { 0x80, 0 , 0 , 0 },
+ { 0x80, 0 , 0x80, 0 },
+ { 0x80, 0x80, 0 , 0 },
+ { 0xC0, 0xC0, 0xC0, MAPTOWHITE },
+ { 0x80, 0x80, 0x80, MAPTOWHITE },
+ { 0 , 0 , 0xFF, 0 },
+ { 0 , 0xFF, 0 , MAPTOWHITE },
+ { 0 , 0xFF, 0xFF, MAPTOWHITE },
+ { 0xFF, 0 , 0 , 0 },
+ { 0xFF, 0 , 0xFF, 0 },
+ { 0xFF, 0xFF, 0 , MAPTOWHITE },
+ { 0xFF, 0xFF, 0xFF, MAPTOWHITE }
+};
+
+/* 8bpp Color Table (palettized), first 10 entries. */
+const DIBColorEntry DIB8ColorTable1[] = {
+ /* blue red green flags */
+ { 0 , 0 , 0 , 0 },
+ { 0 , 0 , 0x80, 0 },
+ { 0 , 0x80, 0 , 0 },
+ { 0 , 0x80, 0x80, 0 },
+ { 0x80, 0 , 0 , 0 },
+ { 0x80, 0 , 0x80, 0 },
+ { 0x80, 0x80, 0 , 0 },
+ { 0xC0, 0xC0, 0xC0, MAPTOWHITE },
+ { 0xC0, 0xDC, 0xC0, MAPTOWHITE | NONSTATIC },
+ { 0xF0, 0xCA, 0xA6, MAPTOWHITE | NONSTATIC }
+};
+
+/* 8bpp Color Table (palettized), all middle entries (10-245). */
+const DIBColorEntry DIB8ColorTable2[] = {
+ /* blue red green flags */
+ { 0, 0, 0, NONSTATIC }
+};
+
+/* 8bpp Color Table (palettized), last 10 entries (246-255). */
+const DIBColorEntry DIB8ColorTable3[] = {
+ /* blue red green flags */
+ { 0xF0, 0xFB, 0xFF, MAPTOWHITE | NONSTATIC },
+ { 0xA4, 0xA0, 0xA0, MAPTOWHITE | NONSTATIC },
+ { 0x80, 0x80, 0x80, MAPTOWHITE },
+ { 0 , 0 , 0xFF, 0 },
+ { 0 , 0xFF, 0 , MAPTOWHITE },
+ { 0 , 0xFF, 0xFF, MAPTOWHITE },
+ { 0xFF, 0 , 0 , 0 },
+ { 0xFF, 0 , 0xFF, 0 },
+ { 0xFF, 0xFF, 0 , MAPTOWHITE },
+ { 0xFF, 0xFF, 0xFF, MAPTOWHITE }
+};
+
+/* An undocumented function called by USER to check if display driver
+ * contains a more suitable version of a resource.
+ * Exported as ordinal 450.
+ */
+DWORD WINAPI __loadds GetDriverResourceID( WORD wResID, LPSTR lpResType )
+{
+ if( wResID == OBJ_FONT ) {
+ if( wDpi != 96 ) {
+ return( 2003 ); /* If DPI is not 96, return fonts120.bin instead. */
+ }
+ }
+ return( wResID );
+}
+
+/* Some genius at Microsoft decided that CreateDIBPDevice returns the result
+ * in EAX, not DX:AX. This is not at all documented in the Win95 DDK, but it
+ * is stated clearly in U.S. Patent 6,525,743 (granted in 2003).
+ * We just create a tiny thunk to produce a sane calling convention.
+ */
+DWORD PASCAL CreateDIBPDeviceX( LPBITMAPINFO lpInfo, LPPDEVICE lpDevice, LPVOID lpBits, WORD wFlags );
+#pragma aux CreateDIBPDeviceX = \
+ "call CreateDIBPDevice" \
+ "mov dx, ax" \
+ "shr eax, 16" \
+ "xchg ax, dx"
+
+#pragma code_seg( _INIT )
+
+/* GDI calls Enable twice at startup, first to query the GDIINFO structure
+ * and then to initialize the video hardware.
+ */
+UINT WINAPI __loadds Enable( LPVOID lpDevice, UINT style, LPSTR lpDeviceType,
+ LPSTR lpOutputFile, LPVOID lpStuff )
+{
+ WORD rc;
+ WORD wPalCnt;
+
+ dbg_printf( "Enable: lpDevice=%WP style=%X bReEnabling=%u wPalettized=%u\n", lpDevice, style, bReEnabling, wPalettized );
+ if( !(style & 1) ) { /* Only test the low bit! */
+ LPDIBENGINE lpEng = lpDevice;
+ LPBITMAPINFO lpInfo;
+ WORD wFlags;
+ DWORD dwRet;
+
+ /* Initialize the PDEVICE. */
+ lpDriverPDevice = lpDevice;
+ rc = PhysicalEnable();
+ if( !rc ) {
+ dbg_printf( "Enable: PhysicalEnable failed!\n" );
+ return( 0 );
+ }
+ if( !bReEnabling ) {
+ int_2Fh( STOP_IO_TRAP );
+ }
+
+ /* Pass down to the DIB engine. */
+ DIB_Enable( lpDevice, style, lpDeviceType, lpOutputFile, lpStuff );
+
+ if( wPalettized )
+ DIB_SetPaletteTranslateExt( NULL, lpDriverPDevice );
+
+ dbg_printf( "Enable: wBpp=%u wDpi=%u wScreenX=%u wScreenY=%u wDIBPdevSize=%x\n",
+ wBpp, wDpi, wScreenX, wScreenY, wDIBPdevSize );
+
+ /* Fill out the bitmap header. */
+ /// @todo Does wDIBPdevSize have to equal sizeof(DIBENGINE)?
+ lpInfo = (LPVOID)((LPBYTE)lpDevice + wDIBPdevSize);
+ _fmemset( &lpInfo->bmiHeader, 0, sizeof( lpInfo->bmiHeader ) );
+ lpInfo->bmiHeader.biSize = sizeof( lpInfo->bmiHeader );
+ lpInfo->bmiHeader.biWidth = wScreenX;
+ lpInfo->bmiHeader.biHeight = wScreenY;
+ lpInfo->bmiHeader.biPlanes = 1;
+ lpInfo->bmiHeader.biBitCount = wBpp;
+
+ /* Set up the color table for non-direct color modes. */
+ if( wBpp <= 8 ) {
+ DIBColorEntry FAR *lpDefaultClr;
+
+ switch( wBpp ) {
+ case 8:
+ lpDefaultClr = DIB8ColorTable1;
+ wPalCnt = sizeof( DIB8ColorTable1 );
+ break;
+ case 4:
+ lpDefaultClr = DIB4ColorTable;
+ wPalCnt = sizeof( DIB4ColorTable );
+ break;
+ case 1:
+ default:
+ lpDefaultClr = DIB1ColorTable;
+ wPalCnt = sizeof( DIB1ColorTable );
+ break;
+ }
+ lpColorTable = &lpInfo->bmiColors;
+
+ if( !bReEnabling ) {
+ _fmemcpy( lpColorTable, lpDefaultClr, wPalCnt );
+ /* For 8bpp, fix up the rest of the palette. */
+ if( wBpp == 8 ) {
+ int i;
+
+ /* The entries at index 10 to 245 are all the same. */
+ for( i = 10; i < 246; ++i )
+ lpColorTable[i] = DIB8ColorTable2[0];
+
+ _fmemcpy( &lpColorTable[246], DIB8ColorTable3, sizeof( DIB8ColorTable3 ) );
+ }
+ }
+ }
+
+ wFlags = wPDeviceFlags;
+ if( wPalettized )
+ wFlags |= PALETTIZED;
+
+ /* Call the DIB Engine to set up the PDevice. */
+ dbg_printf( "lpInfo=%WP lpDevice=%WP lpColorTable=%WP wFlags=%X ScreenSelector=%X\n", lpInfo, lpDevice, lpColorTable, wFlags, ScreenSelector );
+ dwRet = CreateDIBPDeviceX( lpInfo, lpDevice, ScreenSelector :> 0, wFlags );
+ if( !dwRet ) {
+ dbg_printf( "Enable: CreateDIBPDevice failed!\n" );
+ return( 0 );
+ }
+ dbg_printf( "Enable: CreateDIBPDevice returned %lX\n", dwRet );
+
+ /* Now fill out the begin/end access callbacks. */
+ lpEng->deBeginAccess = DIB_BeginAccess;
+ lpEng->deEndAccess = DIB_EndAccess;
+
+ /* Program the DAC in non-direct color modes. */
+ if( wBpp <= 8 ) {
+ switch( wBpp ) {
+ case 8:
+ wPalCnt = 256;
+ break;
+ case 4:
+ wPalCnt = 16;
+ break;
+ case 1:
+ default:
+ wPalCnt = 2;
+ break;
+ }
+ SetRAMDAC_far( 0, wPalCnt, lpColorTable );
+ }
+
+ if( !bReEnabling ) {
+ HookInt2Fh();
+ }
+ wEnabled = 1;
+
+ return( 1 );
+ } else {
+ /* Fill out GDIINFO for GDI. */
+ LPGDIINFO lpInfo = lpDevice;
+
+ /* Start with passing down to the DIB engine. It will set dpCurves through dpStyleLen. */
+ DIB_Enable( lpDevice, style, lpDeviceType, lpOutputFile, lpStuff );
+
+ /* Fill out some static data. Note that some fields are set by the DIB Engine
+ * and we don't touch them (curves, lines, polygons etc.).
+ */
+ lpInfo->dpVersion = DRV_VERSION;
+ lpInfo->dpTechnology = DT_RASDISPLAY;
+ lpInfo->dpHorzSize = DISPLAY_HORZ_MM;
+ lpInfo->dpVertSize = DISPLAY_VERT_MM;
+ lpInfo->dpPlanes = 1;
+ lpInfo->dpCapsFE = 0;
+ lpInfo->dpNumFonts = 0;
+
+ /* Now set the fields that depend on current mode. */
+ lpInfo->dpHorzRes = wScrX;
+ lpInfo->dpVertRes = wScrY;
+
+ lpInfo->dpMLoWin.xcoord = DISPLAY_HORZ_MM * 10;
+ lpInfo->dpMLoWin.ycoord = DISPLAY_VERT_MM * 10;
+ lpInfo->dpMLoVpt.xcoord = wScrX;
+ lpInfo->dpMLoVpt.ycoord = -wScrY;
+
+ lpInfo->dpMHiWin.xcoord = DISPLAY_HORZ_MM * 100;
+ lpInfo->dpMHiWin.ycoord = DISPLAY_VERT_MM * 100;
+ lpInfo->dpMHiVpt.xcoord = wScrX;
+ lpInfo->dpMHiVpt.ycoord = -wScrY;
+
+ /* These calculations are a wild guess and probably don't matter. */
+ lpInfo->dpELoWin.xcoord = DISPLAY_SIZE_EN;
+ lpInfo->dpELoWin.ycoord = DISPLAY_SIZE_EN;
+ lpInfo->dpELoVpt.xcoord = wScrX / 5;
+ lpInfo->dpELoVpt.ycoord = -lpInfo->dpELoVpt.xcoord;
+
+ lpInfo->dpELoWin.xcoord = DISPLAY_SIZE_EN * 5;
+ lpInfo->dpELoWin.ycoord = DISPLAY_SIZE_EN * 5;
+ lpInfo->dpEHiVpt.xcoord = wScrX / 10;
+ lpInfo->dpEHiVpt.ycoord = -lpInfo->dpEHiVpt.xcoord;
+
+ lpInfo->dpTwpWin.xcoord = DISPLAY_SIZE_TWP;
+ lpInfo->dpTwpWin.ycoord = DISPLAY_SIZE_TWP;
+ lpInfo->dpTwpVpt.xcoord = wScrX / 10;
+ lpInfo->dpTwpVpt.ycoord = -lpInfo->dpTwpVpt.xcoord;
+
+ /* Update more GDIINFO bits. */
+ lpInfo->dpLogPixelsX = wDpi;
+ lpInfo->dpLogPixelsY = wDpi;
+ lpInfo->dpBitsPixel = wBpp;
+ lpInfo->dpDCManage = DC_IgnoreDFNP;
+ /* In theory we should set the C1_SLOW_CARD flag since this driver is unaccelerated.
+ * This flag disables certain visual effects like "embossed" disabled text or animations.
+ * Realistically, software rendering in a VM on a modern system is going to be a lot
+ * faster than most mid-1990s graphics cards.
+ */
+ lpInfo->dpCaps1 |= C1_COLORCURSOR | C1_REINIT_ABLE | C1_GLYPH_INDEX | C1_BYTE_PACKED; /* | C1_SLOW_CARD */;
+ //lpInfo->dpCaps1 &= ~C1_GLYPH_INDEX;
+
+ dbg_printf( "lpInfo->dpCaps1: %lX\n", (DWORD)lpInfo->dpCaps1);
+
+ /* Grab the DIB Engine PDevice size before we add to it. */
+ wDIBPdevSize = lpInfo->dpDEVICEsize;
+ dbg_printf( "Enable: wDIBPdevSize=%X wScrX=%u wScrY=%u wBpp=%u wDpi=%u wScreenX=%u wScreenY=%u\n",
+ wDIBPdevSize, wScrX, wScrY, wBpp, wDpi, wScreenX, wScreenY );
+
+ lpInfo->dpNumBrushes = -1; /* Too many to count, always the same.. */
+
+ if( wBpp == 8 ) {
+ if( wPalettized ) {
+ lpInfo->dpNumPens = 16; /* Pens realized by driver. */
+ lpInfo->dpNumColors = 20; /* Colors in color table. */
+ lpInfo->dpNumPalReg = 256;
+ lpInfo->dpPalReserved = 20;
+ lpInfo->dpColorRes = 18;
+ lpInfo->dpRaster |= RC_DIBTODEV + RC_PALETTE + RC_SAVEBITMAP;
+ } else {
+ lpInfo->dpNumPens = 256; /* Pens realized by driver. */
+ lpInfo->dpNumColors = 256; /* Colors in color table. */
+ lpInfo->dpNumPalReg = 0;
+ lpInfo->dpPalReserved = 0;
+ lpInfo->dpColorRes = 0;
+ lpInfo->dpRaster |= RC_DIBTODEV;
+ }
+ lpInfo->dpDEVICEsize += sizeof( BITMAPINFOHEADER ) + 256 * 4;
+ } else if( wBpp > 8 ) {
+ lpInfo->dpNumPens = -1; /* Pens realized by driver. */
+ lpInfo->dpNumColors = -1; /* Colors in color table. */
+ lpInfo->dpNumPalReg = 0;
+ lpInfo->dpPalReserved = 0;
+ lpInfo->dpColorRes = 0;
+ lpInfo->dpRaster |= RC_DIBTODEV;
+ lpInfo->dpDEVICEsize += sizeof( BITMAPINFOHEADER );
+ } else if( wBpp < 8 ) {
+ WORD wCount;
+
+ wCount = 1 << wBpp; /* 2 or 4 for 2 or 16 bpp. */
+ lpInfo->dpNumPens = wCount; /* Pens realized by driver. */
+ lpInfo->dpNumColors = wCount; /* Colors in color table. */
+ lpInfo->dpNumPalReg = 0;
+ lpInfo->dpPalReserved = 0;
+ lpInfo->dpColorRes = 0;
+ lpInfo->dpRaster |= RC_DIBTODEV;
+ wCount *= 4;
+ lpInfo->dpDEVICEsize += sizeof( BITMAPINFOHEADER ) + 8 + wCount;
+ }
+
+ dbg_printf( "sizeof(GDIINFO)=%d (%X), dpDEVICEsize=%X\n", sizeof( GDIINFO ), sizeof( GDIINFO ), lpInfo->dpDEVICEsize );
+ return( sizeof( GDIINFO ) );
+ }
+}
+
+
+/* The ReEnable function is called to dynamically change resolution.
+ * It must query the new display mode settings and then call Enable.
+ * NB: Windows 9x will not dynamically change the color depth, only
+ * resolution. Documented in MS KB Article Q127139.
+ */
+UINT WINAPI __loadds ReEnable( LPVOID lpDevice, LPGDIINFO lpInfo )
+{
+ WORD wLastValidBpp = wBpp;
+ WORD wLastValidX = wScreenX;
+ WORD wLastValidY = wScreenY;
+ WORD rc;
+
+ dbg_printf( "ReEnable: lpDevice=%WP lpInfo=%WP wScreenX=%u wScreenY=%u\n", lpDevice, lpInfo, wScreenX, wScreenY );
+
+ /* Figure out the new mode. */
+ ReadDisplayConfig();
+ dbg_printf( "ReEnable: wScreenX=%u wScreenY=%u wBpp=%u\n", wScreenX, wScreenY, wBpp );
+
+ /* Let Enable know it doesn't need to do everything. */
+ bReEnabling = 1;
+
+ /* Don't let the cursor mess with things. */
+ DIB_BeginAccess( lpDevice, 0, 0, wScreenX - 1, wScreenY - 1, CURSOREXCLUDE );
+
+ /* Create a new PDevice and set the new mode. Returns zero on failure. */
+ rc = Enable( lpDevice, 0, NULL, NULL, NULL );
+
+ /* Drawing the cursor is safe again. */
+ DIB_EndAccess( lpDevice, CURSOREXCLUDE );
+
+ if( rc ) {
+ /* Enable succeeded, fill out GDIINFO. */
+ Enable( lpInfo, 1, NULL, NULL, NULL );
+ rc = 1;
+ } else {
+ dbg_printf( "ReEnable: Enable failed!\n" );
+ /* Couldn't set new mode. Try to get the old one back. */
+ wScreenX = wLastValidX;
+ wScreenY = wLastValidY;
+ wBpp = wLastValidBpp;
+
+ Enable( lpDevice, 0, NULL, NULL, NULL );
+
+ /* And force a repaint. */
+ RepaintFunc();
+ rc = 0;
+ }
+
+ bReEnabling = 0;
+ return( rc );
+}
+
+void int_10h( unsigned ax );
+#pragma aux int_10h = \
+ "int 10h" \
+ parm [ax];
+
+/* Disable graphics and go back to a text mode. */
+UINT WINAPI __loadds Disable( LPVOID lpDevice )
+{
+ LPDIBENGINE lpEng = lpDevice;
+
+ dbg_printf( "Disable: lpDevice=%WP\n", lpDevice );
+
+ /* Start disabling and mark the PDevice busy. */
+ wEnabled = 0;
+ lpEng->deFlags |= BUSY; /// @todo Does this need to be a locked op?
+
+ /* Re-enable I/O trapping before we start setting a standard VGA mode. */
+ int_2Fh( START_IO_TRAP );
+
+ /* Disable device if needed */
+ PhysicalDisable();
+
+ /* Tell VDD we're going away. */
+ CallVDD( VDD_DRIVER_UNREGISTER );
+
+ /* Set standard 80x25 text mode using the BIOS. */
+ int_10h( 3 );
+
+ /* And unhook INT 2F. */
+ UnhookInt2Fh();
+
+ return( 1 );
+}
diff --git a/init.c b/init.c
new file mode 100644
index 0000000..0f961dd
--- /dev/null
+++ b/init.c
@@ -0,0 +1,176 @@
+/*****************************************************************************
+
+Copyright (c) 2022 Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* Display driver module initialization. */
+
+#include "winhack.h"
+#include <gdidefs.h>
+#include <dibeng.h>
+#include <minivdd.h>
+#include "minidrv.h"
+
+
+/* GlobalSmartPageLock is a semi-undocumented function. Not officially
+ * documented but described in KB Article Q180586. */
+UINT WINAPI GlobalSmartPageLock( HGLOBAL hglb );
+
+WORD wScrX = 640; /* Current X resolution. */
+WORD wScrY = 480; /* Current Y resolution. */
+WORD wDpi = 96; /* Current DPI setting. */
+WORD wBpp = 8; /* Current BPP setting. */
+WORD wPalettized = 0; /* Non-zero if palettized. */
+
+WORD OurVMHandle = 0; /* The current VM's ID. */
+DWORD VDDEntryPoint = 0; /* The VDD entry point. */
+
+/* On Entry:
+ * EAX = Function code (VDD_GET_DISPLAY_CONFIG)
+ * EBX = This VM's handle
+ * ECX = Size of DISPLAYINFO structure
+ * EDX = Zero to tell VDD to try virtualizing
+ * ES:EDI = Pointer to DISPLAYINFO structure to be
+ * filled
+ *
+ * On Return:
+ * EAX = Return code (0 = succeess, -1 = failed)
+ */
+extern DWORD CallVDDGetDispConf( WORD Function, WORD wDInfSize, LPVOID pDInf );
+#pragma aux CallVDDGetDispConf = \
+ ".386" \
+ "movzx eax, ax" \
+ "movzx ecx, cx" \
+ "movzx ebx, OurVMHandle" \
+ "movzx edi, di" \
+ "call dword ptr VDDEntryPoint"\
+ "mov edx, eax" \
+ "shr edx, 16" \
+ parm [ax] [cx] [es di];
+
+
+#pragma code_seg( _INIT )
+
+/* Read the display settings from SYSTEM.INI or Registry.
+ */
+void ReadDisplayConfig( void )
+{
+ WORD wX, wY;
+ UINT bIgnoreRegistry;
+ MODEDESC mode;
+
+ /* Get the DPI, default to 96. */
+ wDpi = GetPrivateProfileInt( "display", "dpi", 96, "system.ini" );
+
+ /* Get X and Y resolution. */
+ wX = GetPrivateProfileInt( "display", "x_resolution", 0, "system.ini" );
+ wY = GetPrivateProfileInt( "display", "y_resolution", 0, "system.ini" );
+
+ /* Get the bits per pixel. */
+ wBpp = GetPrivateProfileInt( "display", "bpp", 0, "system.ini" );
+
+ dbg_printf( "SYSTEM.INI: %ux%u %ubpp %udpi\n", wX, wY, wBpp, wDpi );
+
+ bIgnoreRegistry = GetPrivateProfileInt( "display", "IgnoreRegistry", 0, "system.ini" );
+
+ if( !bIgnoreRegistry ) {
+ DISPLAYINFO DispInfo;
+ DWORD dwRc;
+
+ dwRc = CallVDDGetDispConf( VDD_GET_DISPLAY_CONFIG, sizeof( DispInfo ), &DispInfo );
+ if( (dwRc != VDD_GET_DISPLAY_CONFIG) && !dwRc ) {
+ /* Call succeeded, use the data. */
+ wScrX = DispInfo.diXRes;
+ wScrY = DispInfo.diYRes;
+ wBpp = DispInfo.diBpp;
+
+ dbg_printf( "Registry: %ux%u %ubpp %udpi\n", DispInfo.diXRes, DispInfo.diYRes, DispInfo.diBpp, DispInfo.diDPI );
+
+ /* DPI might not be set, careful. */
+ if( DispInfo.diDPI )
+ wDpi = DispInfo.diDPI;
+ } else {
+ dbg_printf( "VDD_GET_DISPLAY_CONFIG failed, dwRc=%lX\n",dwRc );
+ }
+ }
+
+ mode.xRes = wScrX;
+ mode.yRes = wScrY;
+ mode.bpp = wBpp;
+
+ dbg_printf( "Entry: %ux%u\n", wScrX, wScrY);
+
+ if( !FixModeInfo( &mode ) ) {
+ /* Values were changed. */
+ wScrX = mode.xRes;
+ wScrY = mode.yRes;
+ wBpp = mode.bpp;
+ }
+
+ dbg_printf( "After fix: %ux%u %u bpp\n", wScrX, wScrY, wBpp);
+
+ /* For 8bpp, read the 'palettized' setting. Default to enabled. */
+ if( wBpp == 8 )
+ wPalettized = GetPrivateProfileInt( "display", "palettized", 1, "system.ini" );
+ else
+ wPalettized = 0;
+}
+
+#define VDD_ID 10 /* Virtual Display Driver ID. */
+
+/* Get Device API Entry Point. */
+void __far *int_2F_GetEP( unsigned ax, unsigned bx );
+#pragma aux int_2F_GetEP = \
+ "int 2Fh" \
+ parm [ax] [bx] value [es di];
+
+/* Get "magic number" (current Virtual Machine ID) for VDD calls. */
+WORD int_2F_GetVMID( unsigned ax );
+#pragma aux int_2F_GetVMID = \
+ "int 2Fh" \
+ parm [ax] value [bx];
+
+/* Dummy pointer to get at the _TEXT segment. Is there any easier way? */
+extern char __based( __segname( "_TEXT" ) ) *pText;
+
+/* This is a standard DLL entry point. Note that DS is already set
+ * to point to this DLL's data segment on entry.
+ */
+#pragma aux DriverInit parm [cx] [di] [es si]
+UINT FAR DriverInit( UINT cbHeap, UINT hModule, LPSTR lpCmdLine )
+{
+ /* Lock the code segment. */
+ GlobalSmartPageLock( (__segment)pText );
+
+ /* Query the entry point of the Virtual Display Device. */
+ VDDEntryPoint = (DWORD)int_2F_GetEP( 0x1684, VDD_ID );
+
+ /* Obtain the "magic number" needed for VDD calls. */
+ OurVMHandle = int_2F_GetVMID( 0x1683 );
+
+ dbg_printf( "DriverInit: VDDEntryPoint=%WP, OurVMHandle=%x\n", VDDEntryPoint, OurVMHandle );
+
+ /* Read the display configuration before doing anything else. */
+ ReadDisplayConfig();
+
+ return( 1 ); /* Success. */
+}
diff --git a/intr.h b/intr.h
new file mode 100644
index 0000000..3a5c862
--- /dev/null
+++ b/intr.h
@@ -0,0 +1,248 @@
+/* -*- Mode: C; c-basic-offset: 3 -*-
+ *
+ * intr.h - Interrupt vector management and interrupt routing.
+ *
+ * This file is part of Metalkit, a simple collection of modules for
+ * writing software that runs on the bare metal. Get the latest code
+ * at http://svn.navi.cx/misc/trunk/metalkit/
+ *
+ * Copyright (c) 2008-2009 Micah Dowty
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __INTR_H__
+#define __INTR_H__
+
+#include "types.h"
+#include "io.h"
+
+#define NUM_INTR_VECTORS 256
+#define NUM_FAULT_VECTORS 0x20
+#define NUM_IRQ_VECTORS 0x10
+#define IRQ_VECTOR_BASE NUM_FAULT_VECTORS
+#define IRQ_VECTOR(irq) ((irq) + IRQ_VECTOR_BASE)
+#define USER_VECTOR_BASE (IRQ_VECTOR_BASE + NUM_IRQ_VECTORS)
+#define USER_VECTOR(n) ((n) + USER_VECTOR_BASE)
+
+#define IRQ_TIMER 0
+#define IRQ_KEYBOARD 1
+
+#define FAULT_DE 0x00 // Divide error
+#define FAULT_NMI 0x02 // Non-maskable interrupt
+#define FAULT_BP 0x03 // Breakpoint
+#define FAULT_OF 0x04 // Overflow
+#define FAULT_BR 0x05 // Bound range
+#define FAULT_UD 0x06 // Undefined opcode
+#define FAULT_NM 0x07 // No FPU
+#define FAULT_DF 0x08 // Double Fault
+#define FAULT_TS 0x0A // Invalid TSS
+#define FAULT_NP 0x0B // Segment not present
+#define FAULT_SS 0x0C // Stack-segment fault
+#define FAULT_GP 0x0D // General Protection Fault
+#define FAULT_PF 0x0E // Page fault
+#define FAULT_MF 0x10 // Math fault
+#define FAULT_AC 0x11 // Alignment check
+#define FAULT_MC 0x12 // Machine check
+#define FAULT_XM 0x13 // SIMD floating point exception
+
+#define PIC1_COMMAND_PORT 0x20
+#define PIC1_DATA_PORT 0x21
+#define PIC2_COMMAND_PORT 0xA0
+#define PIC2_DATA_PORT 0xA1
+
+typedef void (*IntrHandler)(int vector);
+typedef void (*IntrContextFn)(void);
+
+fastcall void Intr_Init(void);
+fastcall void Intr_SetFaultHandlers(IntrHandler handler);
+
+static inline void
+Intr_Enable(void) {
+ asm volatile ("sti");
+}
+
+static inline void
+Intr_Disable(void) {
+ asm volatile ("cli");
+}
+
+static inline Bool
+Intr_Save(void) {
+ uint32 eflags;
+ asm volatile ("pushf; pop %0" : "=r" (eflags));
+ return (eflags & 0x200) != 0;
+}
+
+static inline void
+Intr_Restore(Bool flag) {
+ if (flag) {
+ Intr_Enable();
+ } else {
+ Intr_Disable();
+ }
+}
+
+static inline void
+Intr_Halt(void) {
+ asm volatile ("hlt");
+}
+
+static inline void
+Intr_Break(void) {
+ asm volatile ("int3");
+}
+
+/*
+ * This structure describes all execution state that's saved when an
+ * interrupt or a setjmp occurs. In the case of an interrupt, this
+ * structure actually describes the stack frame of the interrupt
+ * trampoline.
+ *
+ * An interrupt handler can get a pointer to its IntrContext by
+ * passing its first argument to the Intr_GetContext macro. This
+ * allows an interrupt handler to examine the execution context in
+ * which the interrupt occurred, to modify the interrupt's return
+ * address, or even to implement input and output for OS traps.
+ *
+ * This module also provides functions for directly saving and
+ * restoring IntrContext structures. This can be used much like
+ * setjmp/longjmp, or it can even be used for simple cooperative or
+ * preemptive multithreading. An interrupt handler can perform a
+ * context switch by overwriting its IntrContext with a saved context.
+ *
+ * The definition of this structure must be kept in sync with the
+ * machine code in our interrupt trampolines, and with the
+ * assembly-language implementation of SaveContext and RestoreContext.
+ */
+
+typedef struct IntrContext {
+ /*
+ * General purpose registers. These are all saved after the value
+ * of %esp is captured.
+ */
+
+ uint32 edi;
+ uint32 esi;
+ uint32 ebp;
+ uint32 esp;
+ uint32 ebx;
+ uint32 edx;
+ uint32 ecx;
+ uint32 eax;
+
+ /*
+ * These values are save by the CPU during an interrupt. By
+ * convention, these values are at the top of the stack when %esp
+ * was saved.
+ *
+ * The values of cs and eflags are ignored by Intr_SaveContext
+ * and Intr_RestoreContext.
+ */
+
+ uint32 eip;
+ uint32 cs;
+ uint32 eflags;
+} IntrContext;
+
+/*
+ * Always use the 'volatile' keyword when storing the result
+ * of Intr_GetContext. GCC can erroneously decide to optimize
+ * out any copies to this pointer, because it doesn't know the
+ * values will be used by our trampoline.
+ */
+
+#define Intr_GetContext(arg) ((IntrContext*) &(&arg)[1])
+
+uint32 Intr_SaveContext(IntrContext *ctx);
+void Intr_RestoreContext(IntrContext *ctx);
+fastcall void Intr_InitContext(IntrContext *ctx, uint32 *stack, IntrContextFn main);
+
+/*
+ * To save space, we don't include assembly-language trampolines for
+ * each interrupt vector. Instead, we allocate a table in the BSS
+ * segment which we can fill in at runtime with simple trampoline
+ * functions. This structure actually describes executable 32-bit
+ * code.
+ */
+
+typedef struct {
+ uint16 code1;
+ uint32 arg;
+ uint8 code2;
+ IntrHandler handler;
+ uint32 code3;
+ uint32 code4;
+ uint32 code5;
+ uint32 code6;
+ uint32 code7;
+ uint32 code8;
+} PACKED IntrTrampolineType;
+
+extern IntrTrampolineType ALIGNED(4) IntrTrampoline[NUM_INTR_VECTORS];
+
+/*
+ * Intr_SetHandler --
+ *
+ * Set a C-language interrupt handler for a particular vector.
+ * Note that the argument is a vector number, not an IRQ.
+ */
+
+static inline void
+Intr_SetHandler(int vector, IntrHandler handler)
+{
+ IntrTrampoline[vector].handler = handler;
+}
+
+/*
+ * Intr_SetMask --
+ *
+ * (Un)mask a particular IRQ.
+ */
+
+static inline void
+Intr_SetMask(int irq, Bool enable)
+{
+ uint8 port, bit, mask;
+
+ if (irq >= 8) {
+ bit = 1 << (irq - 8);
+ port = PIC2_DATA_PORT;
+ } else {
+ bit = 1 << irq;
+ port = PIC1_DATA_PORT;
+ }
+
+ mask = IO_In8(port);
+
+ /* A '1' bit in the mask inhibits the interrupt. */
+ if (enable) {
+ mask &= ~bit;
+ } else {
+ mask |= bit;
+ }
+
+ IO_Out8(port, mask);
+}
+
+
+#endif /* __INTR_H__ */
diff --git a/io.h b/io.h
new file mode 100644
index 0000000..ae25f33
--- /dev/null
+++ b/io.h
@@ -0,0 +1,94 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022 Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+#include <conio.h> /* For port I/O prototypes. */
+
+/* The 16-bit compiler does not do inpd(). We have to do it ourselves.
+ * NB: It might be OK to trash the high bits of EAX but better be safe.
+ */
+/* Warning: Destroys high bits of EAX. */
+unsigned long inpd_asm( unsigned port );
+#pragma aux inpd_asm = \
+ ".386" \
+ "push eax" \
+ "in eax, dx" \
+ "mov dx, ax" \
+ "shr eax, 16" \
+ "xchg bx, ax" \
+ "pop eax" \
+ "xchg bx, ax" \
+ "xchg ax, dx" \
+ parm [dx] value [dx ax] modify [bx] nomemory;
+
+void outpd_asm( unsigned port, unsigned long val );
+#pragma aux outpd_asm = \
+ ".386" \
+ "push eax" \
+ "xchg bx, ax" \
+ "shl eax, 16" \
+ "mov ax, bx" \
+ "out dx, eax" \
+ "pop eax" \
+ parm [dx] [bx ax] nomemory;
+
+#ifdef NEEDVIDEO
+
+static void vid_outb( void *cx, unsigned port, unsigned val )
+{
+ outp( port, val );
+}
+
+static void vid_outw( void *cx, unsigned port, unsigned val )
+{
+ outpw( port, val );
+}
+
+static unsigned vid_inb( void *cx, unsigned port )
+{
+ return( inp( port ) );
+}
+
+static unsigned vid_inw( void *cx, unsigned port )
+{
+ return( inpw( port ) );
+}
+
+static unsigned long vid_ind( void *cx, unsigned port )
+{
+ return( inpd_asm( port ) );
+}
+
+#else
+
+static unsigned long inpd(unsigned port )
+{
+ return( inpd_asm( port ) );
+}
+
+static void outpd( unsigned port, unsigned long val )
+{
+ outpd_asm( port, val );
+}
+
+#endif
diff --git a/io32.h b/io32.h
new file mode 100644
index 0000000..7eb78c8
--- /dev/null
+++ b/io32.h
@@ -0,0 +1,113 @@
+/*****************************************************************************
+
+Copyright (c) 2023 Jaroslav Hensl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+unsigned long inpd_asm(unsigned short port);
+#pragma aux inpd_asm = \
+ ".386" \
+ "in eax, dx" \
+ parm [dx] value [eax];
+
+void outpd_asm(unsigned short port, unsigned long val);
+#pragma aux outpd_asm = \
+ ".386" \
+ "out dx, eax" \
+ parm [dx] [eax];
+
+unsigned short inpw_asm(unsigned short port);
+#pragma aux inpw_asm = \
+ ".386" \
+ "in ax, dx" \
+ parm [dx] value [ax];
+
+void outpw_asm(unsigned short port, unsigned short val);
+#pragma aux outpw_asm = \
+ ".386" \
+ "out dx, ax" \
+ parm [dx] [ax];
+
+unsigned char inpb_asm(unsigned short port);
+#pragma aux inpb_asm = \
+ ".386" \
+ "in al, dx" \
+ parm [dx] value [al];
+
+void outp_asm(unsigned short port, unsigned char val);
+#pragma aux outp_asm = \
+ ".386" \
+ "out dx, al" \
+ parm [dx] [al];
+
+/*
+ * Watcom complaining if have unused static function so, before include
+ * this file define one or more folowing defines to specify which function
+ * your code using:
+ * IO_IN32
+ * IN_OUT32
+ * IO_IN16
+ * IN_OUT16
+ * IO_IN8
+ * IN_OUT8
+ *
+ */
+#ifdef IO_IN32
+static unsigned long inpd(unsigned short port)
+{
+ return inpd_asm(port);
+}
+#endif
+
+#ifdef IO_OUT32
+static void outpd( unsigned short port, unsigned long val)
+{
+ outpd_asm(port, val);
+}
+#endif
+
+#ifdef IO_IN16
+static unsigned short inpw(unsigned short port)
+{
+ return inpw_asm(port);
+}
+#endif
+
+#ifdef IO_OUT16
+static void outpw( unsigned short port, unsigned short val)
+{
+ outpw_asm(port, val);
+}
+#endif
+
+#ifdef IO_IN8
+static unsigned char inp(unsigned short port)
+{
+ return inpb_asm(port);
+}
+#endif
+
+#ifdef IO_OUT8
+static void outp(unsigned short port, unsigned char val)
+{
+ outp_asm(port, val);
+}
+#endif
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..106e3ae
--- /dev/null
+++ b/makefile
@@ -0,0 +1,325 @@
+OBJS = dibthunk.obj dibcall.obj enable.obj init.obj palette.obj &
+ scrsw.obj sswhook.obj modes.obj boxv.obj control.obj &
+ drvlib.obj control_vxd.obj minivdd_svga.obj vmwsvxd.obj &
+ scrsw_svga.obj control_svga.obj modes_svga.obj palette_svga.obj &
+ pci.obj svga.obj svga3d.obj svga32.obj pci32.obj &
+
+INCS = -I$(%WATCOM)\h\win -Iddk -Ivmware
+
+VER_BUILD = 1
+
+FLAGS = -DDRV_VER_BUILD=$(VER_BUILD)
+
+# Define HWBLT if BitBlt can be accelerated.
+#FLAGS += -DHWBLT
+
+# Set DBGPRINT to add debug printf logging.
+#DBGPRINT = 1
+
+!ifdef DBGPRINT
+FLAGS += -DDBGPRINT
+OBJS += dbgprint.obj dbgprint32.obj
+# Need this to work with pre-made boxv9x.lnk
+DBGFILE = file dbgprint.obj
+DBGFILE32 = file dbgprint32.obj
+!else
+DBGFILE =
+DBGFILE32 =
+!endif
+CFLAGS = -q -wx -s -zu -zls -6 -fp6
+CFLAGS32 = -q -wx -s -zls -6s -fp6 -mf
+CC = wcc
+CC32 = wcc386
+
+# Log VXD to com2
+!ifdef DBGPRINT
+CFLAGS32 += -DCOM2
+!endif
+
+all : boxvmini.drv vmwsmini.drv vmwsmini.vxd
+
+# Object files
+drvlib.obj : drvlib.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+boxv.obj : boxv.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+pci.obj : vmware/pci.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+pci32.obj : vmware/pci32.c .autodepend
+ $(CC32) $(CFLAGS32) $(INCS) $(FLAGS) $<
+
+svga.obj : vmware/svga.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+svga32.obj : vmware/svga32.c .autodepend
+ $(CC32) $(CFLAGS32) $(INCS) $(FLAGS) $<
+
+svga3d.obj : vmware/svga3d.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+dbgprint.obj : dbgprint.c .autodepend
+ $(CC) $(CFLAGS) -zW $(FLAGS) $<
+
+dbgprint32.obj : dbgprint32.c .autodepend
+ $(CC32) $(CFLAGS32) $(FLAGS) $<
+
+dibcall.obj : dibcall.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+dibthunk.obj : dibthunk.asm
+ wasm -q $(FLAGS) $<
+
+enable.obj : enable.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+init.obj : init.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+control.obj : control.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+control_svga.obj : control_svga.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+control_vxd.obj : control_vxd.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+palette.obj : palette.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+palette_svga.obj : palette_svga.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+sswhook.obj : sswhook.asm
+ wasm -q $(FLAGS) $<
+
+modes.obj : modes.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+modes_svga.obj : modes_svga.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+scrsw.obj : scrsw.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+scrsw_svga.obj : scrsw_svga.c .autodepend
+ $(CC) $(CFLAGS) -zW $(INCS) $(FLAGS) $<
+
+vmwsvxd.obj : vmwsvxd.c .autodepend
+ $(CC32) $(CFLAGS32) $(INCS) $(FLAGS) $<
+
+minivdd_svga.obj : minivdd_svga.c .autodepend
+ $(CC32) $(CFLAGS32) $(INCS) $(FLAGS) $<
+
+# Resources
+boxvmini.res : res/boxvmini.rc res/colortab.bin res/config.bin res/fonts.bin res/fonts120.bin .autodepend
+ wrc -q -r -ad -bt=windows -fo=$@ -Ires -I$(%WATCOM)/h/win $(FLAGS) res/boxvmini.rc
+
+vmwsmini.res : res/vmwsmini.rc res/colortab.bin res/config.bin res/fonts.bin res/fonts120.bin .autodepend
+ wrc -q -r -ad -bt=windows -fo=$@ -Ires -I$(%WATCOM)/h/win $(FLAGS) res/vmwsmini.rc
+
+vmws_vxd.res : res/vmws_vxd.rc .autodepend
+ wrc -q -r -ad -bt=nt -fo=$@ -Ires -I$(%WATCOM)/h/win $(FLAGS) res/vmws_vxd.rc
+
+res/colortab.bin : res/colortab.c
+ wcc -q $(INCS) $<
+ wlink op quiet disable 1014, 1023 name $@ sys dos output raw file colortab.obj
+
+res/config.bin : res/config.c
+ wcc -q $(INCS) $<
+ wlink op quiet disable 1014, 1023 name $@ sys dos output raw file config.obj
+
+res/fonts.bin : res/fonts.c .autodepend
+ wcc -q $(INCS) $<
+ wlink op quiet disable 1014, 1023 name $@ sys dos output raw file fonts.obj
+
+res/fonts120.bin : res/fonts120.c .autodepend
+ wcc -q $(INCS) $<
+ wlink op quiet disable 1014, 1023 name $@ sys dos output raw file fonts120.obj
+
+# Libraries
+dibeng.lib : ddk/dibeng.lbc
+ wlib -b -q -n -fo -ii @$< $@
+
+boxvmini.drv : $(OBJS) boxvmini.res dibeng.lib
+ wlink op quiet, start=DriverInit_ disable 2055 $(DBGFILE) @<<boxvmini.lnk
+system windows dll initglobal
+file dibthunk.obj
+file dibcall.obj
+file drvlib.obj
+file enable.obj
+file init.obj
+file palette.obj
+file scrsw.obj
+file sswhook.obj
+file modes.obj
+file boxv.obj
+file control.obj
+name boxvmini.drv
+option map=boxvmini.map
+library dibeng.lib
+library clibs.lib
+option modname=DISPLAY
+option description 'DISPLAY : 100, 96, 96 : DIB Engine based Mini display driver.'
+option oneautodata
+segment type data preload fixed
+segment '_TEXT' preload shared
+segment '_INIT' preload moveable
+export BitBlt.1
+export ColorInfo.2
+export Control.3
+export Disable.4
+export Enable.5
+export EnumDFonts.6
+export EnumObj.7
+export Output.8
+export Pixel.9
+export RealizeObject.10
+export StrBlt.11
+export ScanLR.12
+export DeviceMode.13
+export ExtTextOut.14
+export GetCharWidth.15
+export DeviceBitmap.16
+export FastBorder.17
+export SetAttribute.18
+export DibBlt.19
+export CreateDIBitmap.20
+export DibToDevice.21
+export SetPalette.22
+export GetPalette.23
+export SetPaletteTranslate.24
+export GetPaletteTranslate.25
+export UpdateColors.26
+export StretchBlt.27
+export StretchDIBits.28
+export SelectBitmap.29
+export BitmapBits.30
+export ReEnable.31
+export Inquire.101
+export SetCursor.102
+export MoveCursor.103
+export CheckCursor.104
+export GetDriverResourceID.450
+export UserRepaintDisable.500
+export ValidateMode.700
+import GlobalSmartPageLock KERNEL.230
+<<
+ wrc -q boxvmini.res $@
+
+vmwsmini.drv : $(OBJS) vmwsmini.res dibeng.lib
+ wlink op quiet, start=DriverInit_ disable 2055 $(DBGFILE) @<<vmwsmini.lnk
+system windows dll initglobal
+file dibthunk.obj
+file dibcall.obj
+file drvlib.obj
+file enable.obj
+file init.obj
+file palette_svga.obj
+file scrsw_svga.obj
+file sswhook.obj
+file modes_svga.obj
+file svga.obj
+file svga3d.obj
+file pci.obj
+file control_svga.obj
+file control_vxd.obj
+name vmwsmini.drv
+option map=vmwsmini.map
+library dibeng.lib
+library clibs.lib
+option modname=DISPLAY
+option description 'DISPLAY : 100, 96, 96 : DIB Engine based Mini display driver.'
+option oneautodata
+segment type data preload fixed
+segment '_TEXT' preload shared
+segment '_INIT' preload moveable
+export BitBlt.1
+export ColorInfo.2
+export Control.3
+export Disable.4
+export Enable.5
+export EnumDFonts.6
+export EnumObj.7
+export Output.8
+export Pixel.9
+export RealizeObject.10
+export StrBlt.11
+export ScanLR.12
+export DeviceMode.13
+export ExtTextOut.14
+export GetCharWidth.15
+export DeviceBitmap.16
+export FastBorder.17
+export SetAttribute.18
+export DibBlt.19
+export CreateDIBitmap.20
+export DibToDevice.21
+export SetPalette.22
+export GetPalette.23
+export SetPaletteTranslate.24
+export GetPaletteTranslate.25
+export UpdateColors.26
+export StretchBlt.27
+export StretchDIBits.28
+export SelectBitmap.29
+export BitmapBits.30
+export ReEnable.31
+export Inquire.101
+export SetCursor.102
+export MoveCursor.103
+export CheckCursor.104
+export GetDriverResourceID.450
+export UserRepaintDisable.500
+export ValidateMode.700
+import GlobalSmartPageLock KERNEL.230
+<<
+ wrc -q vmwsmini.res $@
+
+vmwsmini.vxd : $(OBJS) vmws_vxd.res
+ wlink op quiet $(DBGFILE32) @<<vmwsmini.lnk
+system win_vxd dynamic
+option map=vmwsvxd.map
+option nodefaultlibs
+name vmwsmini.vxd
+file vmwsvxd.obj
+file minivdd_svga.obj
+file pci32.obj
+file svga32.obj
+segment '_LTEXT' PRELOAD NONDISCARDABLE
+segment '_TEXT' PRELOAD NONDISCARDABLE
+segment '_DATA' PRELOAD NONDISCARDABLE
+export VMWS_DDB.1
+<<
+
+# not working now
+# wrc -q vmws_vxd.res $@
+
+
+# Cleanup
+clean : .symbolic
+ rm *.obj
+ rm *.err
+ rm *.lib
+ rm *.drv
+ rm *.vxd
+ rm *.map
+ rm *.res
+ rm *.img
+ rm res/*.obj
+ rm res/*.bin
+ rm vmware/*.obj
+
+image : .symbolic boxv9x.img
+
+# Create a 1.44MB distribution floppy image.
+# NB: The mkimage tool is not supplied.
+boxv9x.img : boxvmini.drv boxv9x.inf readme.txt
+ if not exist dist mkdir dist
+ copy boxvmini.drv dist
+ copy boxv9x.inf dist
+ copy readme.txt dist
+ mkimage -l BOXV9X -o boxv9x.img dist
diff --git a/minidrv.h b/minidrv.h
new file mode 100644
index 0000000..ca1db99
--- /dev/null
+++ b/minidrv.h
@@ -0,0 +1,132 @@
+/*****************************************************************************
+
+Copyright (c) 2022 Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* First definitions that don't appear to be in any "official" header. */
+
+#define DRV_VERSION 0x0400 /* Windows 4.0 aka Windows 95. */
+
+/* Int 2Fh subfunctions. */
+#define STOP_IO_TRAP 0x4000 /* Stop trapping video I/O. */
+#define SCREEN_SWITCH_OUT 0x4001 /* DOS session going to background. */
+#define SCREEN_SWITCH_IN 0x4002 /* DOS session going to foreground. */
+#define ENTER_CRIT_REG 0x4003 /* Enter critical section notification. */
+#define EXIT_CRIT_REG 0x4004 /* Leave critical section notification. */
+#define START_IO_TRAP 0x4007 /* Start trapping video I/O. */
+
+/* Internal interfaces within minidriver. */
+
+/* A simple mode descriptor structure. */
+typedef struct {
+ WORD xRes;
+ WORD yRes;
+ WORD bpp;
+} MODEDESC, FAR *LPMODEDESC;
+
+
+extern WORD FixModeInfo( LPMODEDESC lpMode );
+extern int PhysicalEnable( void );
+extern void PhysicalDisable( void );
+extern void FAR SetRAMDAC_far( UINT bStart, UINT bCount, RGBQUAD FAR *lpPal );
+extern void ReadDisplayConfig( void );
+extern void FAR RestoreDesktopMode( void );
+extern FARPROC RepaintFunc;
+extern void HookInt2Fh( void );
+extern void UnhookInt2Fh( void );
+
+#ifdef DBGPRINT
+extern void dbg_printf( const char *s, ... );
+#else
+/* The "Meaningless use of an expression" warning gets too annoying. */
+//#pragma disable_message( 111 );
+//#define dbg_printf 1 ? (void)0 : (void)
+#define dbg_printf(...)
+#endif
+
+extern LPDIBENGINE lpDriverPDevice; /* DIB Engine PDevice. */
+extern WORD ScreenSelector; /* Selector of video memory. */
+extern WORD wPalettized; /* Non-zero if palettized device. */
+extern WORD wPDeviceFlags; /* Current GDI device flags. */
+extern WORD wDpi; /* Current DPI. */
+extern WORD wBpp; /* Current bits per pixel. */
+extern WORD wScrX; /* Configured X resolution. */
+extern WORD wScrY; /* Configured Y resolution. */
+extern WORD wScreenX; /* Screen width in pixels. */
+extern WORD wScreenY; /* Screen height in pixels. */
+extern WORD wEnabled; /* PDevice enabled flag. */
+extern RGBQUAD FAR *lpColorTable; /* Current color table. */
+
+extern DWORD dwScreenFlatAddr; /* Linear address of frame buffer */
+
+extern DWORD VDDEntryPoint;
+extern WORD OurVMHandle;
+
+extern WORD wMesa3DEnabled; /* Is possible to accelerate though Mesa3D SVGA */
+
+extern DWORD dwLock32cnt; /* Acceleration is posible only in 32 mode, so locking it's enumaration if active */
+
+typedef void (__far * FastBitBlt_t) (unsigned dx, unsigned dy, unsigned sx, unsigned sy, unsigned w, unsigned h);
+extern FastBitBlt_t FastBitBlt;
+
+/*
+ * frame buffer direct hadrware access, allow user space programs/drivers write
+ * to device frame buffer directly
+ */
+#pragma pack(push)
+#pragma pack(1)
+typedef struct _FBHDA
+{
+ DWORD width;
+ DWORD height;
+ DWORD bpp;
+ DWORD pitch;
+ DWORD fb_pm32; /* eq. linear address, mapped to shared or kernel space*/
+ void __far * fb_pm16; /* usable in this driver */
+} FBHDA;
+#pragma pack(pop)
+
+extern FBHDA __far * FBHDA_ptr;
+extern DWORD FBHDA_linear;
+
+/* Inlines needed in multiple modules. */
+
+void int_2Fh( unsigned ax );
+#pragma aux int_2Fh = \
+ "int 2Fh" \
+ parm [ax];
+
+/* NB: It's unclear of EAX/EBX really need preserving. */
+extern void CallVDD( unsigned Function );
+#pragma aux CallVDD = \
+ ".386" \
+ "push eax" \
+ "push ebx" \
+ "movzx eax, ax" \
+ "movzx ebx, OurVMHandle" \
+ "call dword ptr VDDEntryPoint" \
+ "pop ebx" \
+ "pop eax" \
+ parm [ax];
+
+
+
diff --git a/minivdd32.h b/minivdd32.h
new file mode 100644
index 0000000..38c3a4c
--- /dev/null
+++ b/minivdd32.h
@@ -0,0 +1,112 @@
+#ifndef __MINIVDD32_H__INCLUDED__
+#define __MINIVDD32_H__INCLUDED__
+
+#ifdef DBGPRINT
+void dbg_printf( const char *s, ... );
+#else
+#define dbg_printf(s, ...)
+#endif
+
+/* function codes */
+#define REGISTER_DISPLAY_DRIVER 0
+#define GET_VDD_BANK 1
+#define SET_VDD_BANK 2
+#define RESET_BANK 3
+#define PRE_HIRES_TO_VGA 4
+#define POST_HIRES_TO_VGA 5
+#define PRE_VGA_TO_HIRES 6
+#define POST_VGA_TO_HIRES 7
+#define SAVE_REGISTERS 8
+#define RESTORE_REGISTERS 9
+#define MODIFY_REGISTER_STATE 10
+#define ACCESS_VGA_MEMORY_MODE 11
+#define ACCESS_LINEAR_MEMORY_MODE 12
+#define ENABLE_TRAPS 13
+#define DISABLE_TRAPS 14
+#define MAKE_HARDWARE_NOT_BUSY 15
+#define VIRTUALIZE_CRTC_IN 16
+#define VIRTUALIZE_CRTC_OUT 17
+#define VIRTUALIZE_SEQUENCER_IN 18
+#define VIRTUALIZE_SEQUENCER_OUT 19
+#define VIRTUALIZE_GCR_IN 20
+#define VIRTUALIZE_GCR_OUT 21
+#define SET_LATCH_BANK 22
+#define RESET_LATCH_BANK 23
+#define SAVE_LATCHES 24
+#define RESTORE_LATCHES 25
+#define DISPLAY_DRIVER_DISABLING 26
+#define SELECT_PLANE 27
+#define PRE_CRTC_MODE_CHANGE 28
+#define POST_CRTC_MODE_CHANGE 29
+#define VIRTUALIZE_DAC_OUT 30
+#define VIRTUALIZE_DAC_IN 31
+#define GET_CURRENT_BANK_WRITE 32
+#define GET_CURRENT_BANK_READ 33
+#define SET_BANK 34
+#define CHECK_HIRES_MODE 35
+#define GET_TOTAL_VRAM_SIZE 36
+#define GET_BANK_SIZE 37
+#define SET_HIRES_MODE 38
+#define PRE_HIRES_SAVE_RESTORE 39
+#define POST_HIRES_SAVE_RESTORE 40
+#define VESA_SUPPORT 41
+#define GET_CHIP_ID 42
+#define CHECK_SCREEN_SWITCH_OK 43
+#define VIRTUALIZE_BLTER_IO 44
+#define SAVE_MESSAGE_MODE_STATE 45
+#define SAVE_FORCED_PLANAR_STATE 46
+#define VESA_CALL_POST_PROCESSING 47
+#define PRE_INT_10_MODE_SET 48
+#define NBR_MINI_VDD_FUNCTIONS_40 49
+#define GET_NUM_UNITS 49
+#define TURN_VGA_OFF 50
+#define TURN_VGA_ON 51
+#define SET_ADAPTER_POWER_STATE 52
+#define GET_ADAPTER_POWER_STATE_CAPS 53
+#define SET_MONITOR_POWER_STATE 54
+#define GET_MONITOR_POWER_STATE_CAPS 55
+#define GET_MONITOR_INFO 56
+#define I2C_OPEN 57
+#define I2C_ACCESS 58
+#define GPIO_OPEN 59
+#define GPIO_ACCESS 60
+#define COPYPROTECTION_ACCESS 61
+#define NBR_MINI_VDD_FUNCTIONS_41 62
+
+/* VxDCall(VDD, ...) constants */
+#define VDD__Get_Version 0
+#define VDD__PIF_State 1
+#define VDD__Get_GrabRtn 2
+#define VDD__Hide_Cursor 3
+#define VDD__Set_VMType 4
+#define VDD__Get_ModTime 5
+#define VDD__Set_HCurTrk 6
+#define VDD__Msg_ClrScrn 7
+#define VDD__Msg_ForColor 8
+#define VDD__Msg_BakColor 9
+#define VDD__Msg_TextOut 10
+#define VDD__Msg_SetCursPos 11
+#define VDD__Query_Access 12
+#define VDD__Check_Update_Soon 13
+#define VDD__Get_Mini_Dispatch_Table 14 /* edi -> pointer to table, ecx -> table items count */
+#define VDD__Register_Virtual_Port 15
+#define VDD__Get_VM_Info 16
+#define VDD__Get_Special_VM_IDs 17
+#define VDD__Register_Extra_Screen_Selector 18
+#define VDD__Takeover_VGA_Port 19
+#define VDD__Get_DISPLAYINFO 20
+#define VDD__Do_Physical_IO 21
+#define VDD__Set_Sleep_Flag_Addr 22
+#define VDD__EnableDevice 23
+
+/* generate prototypes */
+#define VDDFUNC(_fnname, _procname) void __stdcall _procname ## _proc(PCRS_32 state);
+#include "minivdd_func.h"
+#undef VDDFUNC
+
+#define VDDPROC(_fnname, _procname) void __stdcall _procname ## _proc(PCRS_32 state)
+
+#define VDD_CY state->Client_EFlags |= 0x1
+#define VDD_NC state->Client_EFlags &= 0xFFFFFFFEUL
+
+#endif /* __MINIVDD32_H__INCLUDED__ */
diff --git a/minivdd_func.h b/minivdd_func.h
new file mode 100644
index 0000000..53d15c3
--- /dev/null
+++ b/minivdd_func.h
@@ -0,0 +1,70 @@
+/*
+ * list for generating function prototypes, assembly entry generating,
+ * and fill dispatch table.
+ * comment out functions without usage
+ */
+
+VDDFUNC(REGISTER_DISPLAY_DRIVER, register_display_driver)
+//VDDFUNC(GET_VDD_BANK, get_vdd_bank)
+//VDDFUNC(SET_VDD_BANK, set_vdd_bank)
+//VDDFUNC(RESET_BANK, reset_bank)
+//VDDFUNC(PRE_HIRES_TO_VGA, pre_hires_to_vga)
+//VDDFUNC(POST_HIRES_TO_VGA, post_hires_to_vga)
+//VDDFUNC(PRE_VGA_TO_HIRES, pre_vga_to_hires)
+//VDDFUNC(POST_VGA_TO_HIRES, post_vga_to_hires)
+//VDDFUNC(SAVE_REGISTERS, save_registers)
+//VDDFUNC(RESTORE_REGISTERS, restore_registers)
+//VDDFUNC(MODIFY_REGISTER_STATE, modify_register_state)
+//VDDFUNC(ACCESS_VGA_MEMORY_MODE, access_vga_memory_mode)
+//VDDFUNC(ACCESS_LINEAR_MEMORY_MODE, access_linear_memory_mode)
+//VDDFUNC(ENABLE_TRAPS, enable_traps)
+//VDDFUNC(DISABLE_TRAPS, disable_traps)
+//VDDFUNC(MAKE_HARDWARE_NOT_BUSY, make_hardware_not_busy)
+//VDDFUNC(VIRTUALIZE_CRTC_IN, virtualize_crtc_in)
+//VDDFUNC(VIRTUALIZE_CRTC_OUT, virtualize_crtc_out)
+//VDDFUNC(VIRTUALIZE_SEQUENCER_IN, virtualize_sequencer_in)
+//VDDFUNC(VIRTUALIZE_SEQUENCER_OUT, virtualize_sequencer_out)
+//VDDFUNC(VIRTUALIZE_GCR_IN, virtualize_gcr_in)
+//VDDFUNC(VIRTUALIZE_GCR_OUT, virtualize_gcr_out)
+//VDDFUNC(SET_LATCH_BANK, set_latch_bank)
+//VDDFUNC(RESET_LATCH_BANK, reset_latch_bank)
+//VDDFUNC(SAVE_LATCHES, save_latches)
+//VDDFUNC(RESTORE_LATCHES, restore_latches)
+//VDDFUNC(DISPLAY_DRIVER_DISABLING, display_driver_disabling)
+//VDDFUNC(SELECT_PLANE, select_plane)
+//VDDFUNC(PRE_CRTC_MODE_CHANGE, pre_crtc_mode_change)
+//VDDFUNC(POST_CRTC_MODE_CHANGE, post_crtc_mode_change)
+//VDDFUNC(VIRTUALIZE_DAC_OUT, virtualize_dac_out)
+//VDDFUNC(VIRTUALIZE_DAC_IN, virtualize_dac_in)
+///! VDDFUNC(GET_CURRENT_BANK_WRITE, get_current_bank_write)
+//VDDFUNC(GET_CURRENT_BANK_READ, get_current_bank_read)
+///! VDDFUNC(SET_BANK, set_bank)
+//VDDFUNC(CHECK_HIRES_MODE, check_hires_mode)
+VDDFUNC(GET_TOTAL_VRAM_SIZE, get_total_vram_size)
+///! VDDFUNC(GET_BANK_SIZE, get_bank_size)
+///! VDDFUNC(SET_HIRES_MODE, set_hires_mode)
+///! VDDFUNC(PRE_HIRES_SAVE_RESTORE, pre_hires_save_restore)
+///! VDDFUNC(POST_HIRES_SAVE_RESTORE, post_hires_save_restore)
+///! VDDFUNC(VESA_SUPPORT, vesa_support)
+VDDFUNC(GET_CHIP_ID, get_chip_id)
+///! VDDFUNC(CHECK_SCREEN_SWITCH_OK, check_screen_switch_ok)
+//VDDFUNC(VIRTUALIZE_BLTER_IO, virtualize_blter_io)
+//VDDFUNC(SAVE_MESSAGE_MODE_STATE, save_message_mode_state)
+//VDDFUNC(SAVE_FORCED_PLANAR_STATE, save_forced_planar_state)
+///! VDDFUNC(VESA_CALL_POST_PROCESSING, vesa_call_post_processing)
+//VDDFUNC(PRE_INT_10_MODE_SET, pre_int_10_mode_set)
+//VDDFUNC(NBR_MINI_VDD_FUNCTIONS_40, nbr_mini_vdd_functions_40)
+//VDDFUNC(GET_NUM_UNITS, get_num_units)
+//VDDFUNC(TURN_VGA_OFF, turn_vga_off)
+//VDDFUNC(TURN_VGA_ON, turn_vga_on)
+//VDDFUNC(SET_ADAPTER_POWER_STATE, set_adapter_power_state)
+//VDDFUNC(GET_ADAPTER_POWER_STATE_CAPS, get_adapter_power_state_caps)
+//VDDFUNC(SET_MONITOR_POWER_STATE, set_monitor_power_state)
+//VDDFUNC(GET_MONITOR_POWER_STATE_CAPS, get_monitor_power_state_caps)
+//VDDFUNC(GET_MONITOR_INFO, get_monitor_info)
+//VDDFUNC(I2C_OPEN, i2c_open)
+//VDDFUNC(I2C_ACCESS, i2c_access)
+//VDDFUNC(GPIO_OPEN, gpio_open)
+//VDDFUNC(GPIO_ACCESS, gpio_access)
+//VDDFUNC(COPYPROTECTION_ACCESS, copyprotection_access)
+//VDDFUNC(NBR_MINI_VDD_FUNCTIONS_41, nbr_mini_vdd_functions_41)
diff --git a/minivdd_svga.c b/minivdd_svga.c
new file mode 100644
index 0000000..8ea2cd1
--- /dev/null
+++ b/minivdd_svga.c
@@ -0,0 +1,325 @@
+/*****************************************************************************
+
+Copyright (c) 2023 Jaroslav Hensl <emulator@emulace.cz>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+#include "winhack.h"
+#include "vmm.h"
+#include "vmwsvxd.h"
+
+#include "minivdd32.h"
+
+#include "svga_all.h"
+
+/* code and data is same segment */
+#include "code32.h"
+
+extern Bool svga_init_success;
+
+/*
+You can implement all the VESA support entirely in your mini-VDD. Doing so will
+cause VESA applications to run more efficiently since all of the VESA support is
+done at Ring 0. You can expect a 20% speed increase by implementing VESA
+unctionality in your mini-VDD over using a real mode VESA driver.
+Following are the VESA functions you can implement in your mini-VDD:
+ CHECK_HIRES_MODE
+ CHECK_SCREEN_SWITCH_OK
+ GET_BANK_SIZE
+ GET_CURRENT_BANK_READ
+ GET_CURRENT_BANK_WRITE
+ GET_TOTAL_VRAM_SIZE
+ POST_HIRES_SAVE_RESTORE
+ PRE_HIRES_SAVE_RESTORE
+ SET_BANK
+ SET_HIRES_MODE
+ VESA_CALL_POST_PROCESSING
+ VESA_SUPPORT
+*/
+
+
+/**
+REGISTER_DISPLAY_DRIVER (Function 0)
+Call With
+EBX: Contains the Windows VM handle.
+EBP: Contains the Windows VM's Client Registers.
+All other registers are via agreement between the display driver and the mini-VDD.
+Return Values
+Whatever is agreed upon by the display driver and mini-VDD.
+Remarks
+This function is called in response to a display driver call to the Main VDD function VDD_REGISTER_DISPLAY_DRIVER_INFO.
+See also VDD_REGISTER_DISPLAY_DRIVER_INFO.
+
+**/
+VDDPROC(REGISTER_DISPLAY_DRIVER, register_display_driver)
+{
+ VDD_NC;
+}
+
+/**
+GET_CHIP_ID (Function 42)
+Call With
+EBX: Contains the VM handle (always the Windows VM).
+EBP: Points to the Windows VM's Client Registers.
+Return Values
+Save everything that you use. EAX contains the ChipID.
+Remarks
+Several mini-VDD's support multiple chipsets that utilize different display drivers.
+For example, ATI's mini-VDD supports the VGA Wonder which uses SUPERVGA.DRV, the Mach8
+which uses ATIM8.DRV, the Mach32 which uses ATIM32.DRV, and the Mach64 which uses ATIM64.DRV.
+Therefore, the detection for each of these chipsets is included in the ATI mini-VDD.
+GET_CHIP_ID is the only way the Main VDD Plug & Play support code can differentiate between
+display cards that use the same mini-VDD.
+
+The Main VDD calls the function MiniVDD_Dynamic_Init when the mini-VDD is loaded.
+If MiniVDD_Dynamic_Init returns with the carry flag clear (indicating success),
+the Main VDD calls GET_CHIP_ID as a second check to make sure that the user has
+not changed the video card since the last time Windows was run. The Main VDD compares
+the value returned by GET_CHIP_ID with the value stored in the registry and if they
+are different, it reports the error to the Plug & Play subsystem.
+
+If the mini-VDD fails to detect one of the cards it supports, MiniVDD_Dynamic_Init
+returns with the carry flag set (indicating failure) and the Windows 95's Plug & Play
+code loads the standard VGA driver.
+
+If the value returned by GET_CHIP_ID is different than the value stored in the registry,
+or if MiniVDD_Dynamic_Init returns failure, the system displays an error message to
+the user concerning the problem with the display settings and allows the user to run
+hardware detection to re-detect the video card.
+
+**/
+VDDPROC(GET_CHIP_ID, get_chip_id)
+{
+ if(svga_init_success)
+ {
+ uint32 chip_id = (((uint32)gSVGA.vendorId) << 16) || ((uint32)gSVGA.deviceId);
+ state->Client_EAX = chip_id;
+ return;
+ }
+ state->Client_EAX = 0;
+}
+
+/**
+CHECK_SCREEN_SWITCH_OK (Function 43)
+Call With
+EAX: Contains -1 if running in a known VESA mode.
+EBX: Contains the VM handle (always the Windows VM).
+ECX: Contains the video mode number (if known).
+EBP: Points to the Windows VM's Client Registers.
+Return Values
+CY indicates that the hi-res application may not be switched away from. NC indicates
+that it is safe to switch away from the hi-res application.
+Remarks
+The Main VDD calls this routine whenever a user presses ALT-ENTER or ALT-TAB to
+switch away from a full-screen MS-DOS prompt. The mini-VDD should determine if
+it knows how to restore this mode. If it is a VESA mode or standard VGA mode,
+the Main VDD knows how to restore it and unless the mini-VDD has special
+considerations, it should return NC. Otherwise, it should return CY causing the
+system to beep to alert the user that the hi-res VM cannot be switched away from.
+This notification is not given if a user presses CTRL-ALT-DEL to terminate a full-screen
+application. In this case, no save of the screen is attempted and it will be impossible
+to restore the screen if the user tries to switch back. In this case, if the user tries
+to switch back, the system terminates the application.
+
+**/
+VDDPROC(CHECK_SCREEN_SWITCH_OK, check_screen_switch_ok)
+{
+
+}
+
+/**
+GET_BANK_SIZE (Function 37)
+Call With
+EBX: Contains the VM handle (always the currently executing VM).
+ECX: Contains the VESA BIOS mode number that is currently running.
+EBP: Points to the Windows VM's Client Registers.
+Return Values
+Save everything that you use. CY returned means that mini-VDD handled the call. EDX contains the current bank size. EAX contains the physical address of the memory aperture or zero to indicate a standard memory aperture at physical address A000:0h.
+Remarks
+This routine is called during the save process of a VESA hi-res screen. It tells the Main VDD how large each bank is (so that during the save and restore process, it will know how many bytes to process per pass of the save/restore loop). It also informs the Main VDD where to access the VRAM. Most VESA programs currently set their VRAM at A000:0h. However, VESA version 2 does allow for flat linear apertures. The mini-VDD should determine if the VESA program is using an aperture and return the correct data to the Main VDD.
+
+**/
+VDDPROC(GET_BANK_SIZE, get_bank_size)
+{
+
+}
+
+/**
+GET_CURRENT_BANK_READ (Function 33)
+The parameters and return values for this function are the same as for GET_CURRENT_BANK_WRITE. See GET_CURRENT_BANK_WRITE for details.
+See also GET_CURRENT_BANK_WRITE.
+
+**/
+VDDPROC(GET_CURRENT_BANK_READ, get_current_bank_read)
+{
+
+}
+
+/**
+GET_CURRENT_BANK_WRITE (Function 32)
+Call With
+EBX: Contains the VM handle (always the currently executing VM).
+EBP: Points to the Windows VM's Client Registers.
+Return Values
+Save everything that you use. CY returned means that the mini-VDD handled the call. NC returned means that Main VDD should use a VESA call to retrieve the bank. If successful, EDX contains the current bank (write or read) as set in hardware.
+Remarks
+GET_CURRENT_BANK_WRITE and GET_CURRENT_BANK_READ are made when the user presses ALT-TAB to switch away from a VESA hi-res application. The Main VDD uses GET_CURRENT_BANK_WRITE to retrieve the current state of the banking registers (which are "Windows" in VESA terminology). It then saves these for later restoration when the user presses ALT-TAB back to the VESA hi-res application. The Main VDD uses VESA function 4F05h to get the bank if the mini-VDD fails this call.
+
+**/
+VDDPROC(GET_CURRENT_BANK_WRITE, get_current_bank_write)
+{
+
+}
+
+/**
+GET_TOTAL_VRAM_SIZE (Function 36)
+Call With
+EBX: Contains the VM handle (always the currently executing VM).
+EBP: Contains the Windows VM's Client Registers.
+Return Values
+Save everything that you use. CY returned means that mini-VDD handled the call.
+ECX contains the total size of VRAM on the card.
+Remarks
+Whenever the VDD saves a hi-res mode, it saves all of the card's video memory to
+the swap file. This is because VESA applications have full access to the total memory
+on the card, even if their visible screen size is less than the total VRAM size on the card.
+Therefore, the Main VDD must know the total VRAM size. If the mini-VDD does not
+handle this call, the Main VDD will do a time-consuming call to
+VESA BIOS function 4F00h to obtain this information.
+For performance reasons, you should implement this function.
+
+**/
+VDDPROC(GET_TOTAL_VRAM_SIZE, get_total_vram_size)
+{
+ if(svga_init_success)
+ {
+ uint32 vram_size = SVGA_ReadReg(SVGA_REG_VRAM_SIZE);
+ state->Client_ECX = vram_size;
+
+ VDD_CY;
+ return;
+ }
+
+ state->Client_ECX = 0;
+ VDD_NC;
+}
+
+/**
+PRE_HIRES_SAVE_RESTORE (Function 39)
+Call With
+EBX: Contains the VM handle (always the currently executing VM).
+EBP: Points to the Windows VM's Client Registers.
+Return Values
+Save everything that you use. No values or flags need to be returned.
+Remarks
+This call is very similar to PRE_HIRES_TO_VGA in that it allows the mini-VDD to modify port trapping, set flags, etc. in preparation for the mode change into the VESA/hi-res mode. In fact, the S3 example mini-VDD dispatches this call to the exact same routine as PRE_HIRES_TO_VGA.
+
+**/
+VDDPROC(PRE_HIRES_SAVE_RESTORE, pre_hires_save_restore)
+{
+
+}
+
+/**
+POST_HIRES_SAVE_RESTORE (Function 40)
+Call With
+EBX: Contains the VM handle (always the currently executing VM).
+EBP: Points to the Windows VM's Client Registers.
+Return Values
+Save everything that you use. No values or flags need to be returned.
+Remarks
+This function is very similar to POST_HIRES_TO_VGA in that it allows the mini-VDD to modify port trapping, set flags, etc. after the mode change into the VESA/hi-res mode. The S3 example mini-VDD dispatches this call to the exact same routine as POST_HIRES_TO_VGA.
+
+**/
+VDDPROC(POST_HIRES_SAVE_RESTORE, post_hires_save_restore)
+{
+
+}
+
+/**
+SET_BANK (Function 34)
+Call With
+EAX: Contains the read bank to set.
+EBX: Contains the VM handle (always the currently executing VM).
+EDX: Contains the write bank to set.
+EBP: Points to the Windows VM's Client Registers.
+Return Values
+Save everything that you use. CY returned means that the mini-VDD handled the call. NC returned means that the Main VDD should use a VESA call to set the bank.
+Remarks
+This call requests the mini-VDD to set the read/write bank passed in EAX/EDX. The mini-VDD simply needs to set the bank into hardware and return CY to the Main VDD.
+
+**/
+VDDPROC(SET_BANK, set_bank)
+{
+
+}
+
+/**
+SET_HIRES_MODE (Function 38)
+Call With
+EAX: Contains hi-res mode number to set (may be a VESA or non-VESA mode).
+EBX: Contains the VM handle (always the currently executing VM).
+EBP: Points to the Windows VM's Client Registers.
+Return Values
+Save everything that you use. CY returned means that the mini-VDD handled the call. NC returned indicates that the mini-VDD did not handle the call.
+Remarks
+This routine is called by the VESA/hi-res restore routine in the Main VDD when the user switches back to a full screen VESA/hi-res mode VM. If you are only interested in being able to restore VESA standard hi-res modes, then you do not need to implement this function since the Main VDD will call Interrupt 10h Function 4F02h in order to set the VESA mode number. You should only implement this function if you are going to save/restore chipset specific modes that are not VESA modes.
+If the mode number passed in EAX is a VESA mode number, you should return NC and let the Main VDD set the mode. If the mode number passed in EAX is a non-VESA hi-res mode that is particular to your card, if possible, this function should not touch VRAM since this could cause page faults and confuse the register state of the mode set. In other words, try not to erase the screen during the mode set if possible.
+
+**/
+VDDPROC(SET_HIRES_MODE, set_hires_mode)
+{
+
+}
+
+/**
+VESA_CALL_POST_PROCESSING (Function 47)
+Call With
+EBX: Contains the VM handle in which the VESA call was made.
+EDX: The low word contains the VESA function code that was just done. The high word contains the VESA mode number if a VESA mode change (function 4F02h) has just occurred.
+EBP: Points to the VM's client registers. The client registers contain the return values from the VESA call.
+Return Values
+Save everything that you use. Nothing is returned to the caller.
+Remarks
+This function allows a mini-VDD to perform any necessary processing after a VESA call. For example, this function could fix up the hardware that might have been put in an unexpected state by the VESA call, or it could readjust register trapping. The S3 sample mini-VDD has an example of how this hook could be used to by a mini-VDD.
+
+**/
+VDDPROC(VESA_CALL_POST_PROCESSING, vesa_call_post_processing)
+{
+
+}
+
+/**
+VESA_SUPPORT (Function 41)
+Call With
+EBX: Contains the VM handle (always the currently executing VM).
+EBP: Points to the Windows VM's Client Registers. Client registers contain the VESA call values.
+Return Values
+Save everything that you use. CY returned means that the mini-VDD completely handled the VESA call and that the VESA.COM or VESA BIOS should not be called. NC returned means that the mini-VDD did not completely handle the call and that the VESA.COM or VESA BIOS should be called. The client registers contain the return values from the VESA call if the mini-VDD handles the call.
+Remarks
+This routine is the "hook" by which a mini-VDD could implement an entire Ring 0 protected mode VESA support. This is recommended, since it eliminates all of the problems of old VESA.COM programs. It also allows much faster VESA performance since the functions are supported at 32 bit Ring 0.
+The mini-VDD's VESA support decides what to do based on values in the Client registers. For example, Client_AX will contain 4Fxx indicating what VESA call the application is doing. Then, the mini-VDD can handle the call, filling in return structures (such as those returned by VESA function 4F00h), etc., and return CY to the Main VDD.
+This routine could also be used to setup a VESA call while still letting the Ring 3 VESA BIOS handle the call. The mini-VDD would do what it wants to do, and then return NC indicating that the Main VDD should call the Ring 3 VESA BIOS or VESA.COM program.
+
+**/
+VDDPROC(VESA_SUPPORT, vesa_support)
+{
+
+}
diff --git a/modes.c b/modes.c
new file mode 100644
index 0000000..ee17f57
--- /dev/null
+++ b/modes.c
@@ -0,0 +1,621 @@
+/*****************************************************************************
+
+Copyright (c) 2022 Michal Necasek
+ 2023 Jaroslav Hensl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* Display driver mode management. */
+
+#include "winhack.h"
+#include <gdidefs.h>
+#include <dibeng.h>
+#include <valmode.h>
+#include <minivdd.h>
+
+#include "minidrv.h"
+#include "boxv.h"
+
+#ifdef SVGA
+# include "svga_all.h"
+#endif
+
+#include "drvlib.h"
+#include "dpmi.h"
+
+#include <string.h> /* _fmemset */
+#include <stdlib.h> /* abs */
+
+/* Somewhat arbitrary max resolution. */
+#define RES_MAX_X (5 * 1024)
+#define RES_MAX_Y (5 * 768)
+
+WORD wScreenX = 0;
+WORD wScreenY = 0;
+WORD BitBltDevProc = 0;
+WORD ScreenSelector = 0;
+WORD wPDeviceFlags = 0;
+
+#ifdef SVGA
+WORD wMesa3DEnabled = 0; /* 3D is enabled (by hypervisor) */
+#endif
+
+/* FBHDA structure pointers */
+FBHDA __far * FBHDA_ptr = NULL;
+DWORD FBHDA_linear = 0;
+
+ DWORD dwScreenFlatAddr = 0; /* 32-bit flat address of VRAM. */
+static DWORD dwVideoMemorySize = 0; /* Installed VRAM in bytes. */
+static WORD wScreenPitchBytes = 0; /* Current scanline pitch. */
+static DWORD dwPhysVRAM = 0; /* Physical LFB base address. */
+
+/* These are currently calculated not needed in the absence of
+ * offscreen video memory.
+ */
+static WORD wMaxWidth = 0;
+static WORD wMaxHeight = 0;
+
+/* On Entry:
+ * EAX = Function code (VDD_DRIVER_REGISTER)
+ * EBX = This VM's handle
+ * ECX = Size of all visible scanlines in bytes
+ * EDX = Zero to tell VDD to try virtualizing
+ * ES:DI = Pointer to function called when switching
+ * back from fullscreen.
+ *
+ * On Return:
+ * EAX = Amount of video memory used by VDD in bytes,
+ * or function code if VDD call failed.
+ */
+extern DWORD CallVDDRegister( WORD Function, WORD wPitch, WORD wHeight, void _far *fRHR );
+#pragma aux CallVDDRegister = \
+ ".386" \
+ "movzx eax, ax" \
+ "movzx edx, dx" \
+ "mul edx" \
+ "mov ecx, eax" \
+ "movzx eax, bx" \
+ "movzx ebx, OurVMHandle" \
+ "xor edx, edx" \
+ "call dword ptr VDDEntryPoint"\
+ "mov edx, eax" \
+ "shr edx, 16" \
+ parm [bx] [ax] [dx] [es di];
+
+
+/* from control.c */
+#ifdef SVGA
+void SVGAHDA_init();
+WORD SVGA_3DSupport();
+void SVGAHDA_update(DWORD width, DWORD height, DWORD bpp, DWORD pitch);
+#endif
+
+#pragma code_seg( _INIT );
+
+/* Take a mode descriptor and change it to be a valid
+ * mode if it isn't already. Return zero if mode needed
+ * fixing (wasn't valid).
+ */
+WORD FixModeInfo( LPMODEDESC lpMode )
+{
+ WORD rc = 1; /* Assume valid mode. */
+
+ /* First validate bits per pixel. */
+ switch( lpMode->bpp ) {
+ case 8:
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ lpMode->bpp = 8; /* Default to 8 bpp. */
+ rc = 0; /* Mode wasn't valid. */
+ }
+
+ /* Validate mode. If resolution is under 640x480 in
+ * either direction, force 640x480.
+ */
+ if( lpMode->xRes < 640 || lpMode->yRes < 480 )
+ {
+ lpMode->xRes = 640; /* Force 640x480. */
+ lpMode->yRes = 480;
+ rc = 0; /* Mode wasn't valid. */
+ }
+
+ /* Clip the resolution to something that probably won't make
+ * Windows have a cow.
+ */
+ if( lpMode->xRes > RES_MAX_X ) {
+ lpMode->xRes = RES_MAX_X;
+ rc = 0;
+ }
+ if( lpMode->yRes > RES_MAX_Y ) {
+ lpMode->yRes = RES_MAX_Y;
+ rc = 0;
+ }
+
+ return( rc );
+}
+
+
+/* Calculate pitch for a given horizontal resolution and bpp. */
+WORD CalcPitch( WORD x, WORD bpp )
+{
+ WORD wPitch;
+
+ /* Valid BPP must be a multiple of 8 so it's simple. */
+ wPitch = x * (bpp / 8);
+
+ /* Align to 32 bits. */
+ wPitch = (wPitch + 3) & ~3;
+
+ return( wPitch );
+}
+
+
+/* Return non-zero if given mode is supported. */
+static int IsModeOK( WORD wXRes, WORD wYRes, WORD wBpp )
+{
+ MODEDESC mode;
+ DWORD dwModeMem;
+
+ mode.bpp = wBpp;
+ mode.xRes = wXRes;
+ mode.yRes = wYRes;
+
+ /* If mode needed fixing, it's not valid. */
+ if( !FixModeInfo( &mode ) )
+ return( 0 );
+
+#ifdef SVGA
+ /* not working in vmware, in vbox working without acceleration, so only confusing users */
+ if(wBpp == 24)
+ {
+ return 0;
+ }
+#endif
+
+ /* Make sure there's enough VRAM for it. */
+ dwModeMem = (DWORD)CalcPitch( wXRes, wBpp ) * wYRes;
+ if( dwModeMem > dwVideoMemorySize )
+ return( 0 );
+
+ return( 1 );
+}
+
+
+/* Clear the visible screen by setting it to all black (zeros).
+ * NB: Assumes there is no off-screen region to the right of
+ * the visible area.
+ */
+static void ClearVisibleScreen( void )
+{
+ LPDWORD lpScr;
+ WORD wLines = wScreenY;
+ WORD i;
+
+ lpScr = ScreenSelector :> 0;
+ while( wLines-- ) {
+ for( i = 0; i < wScreenPitchBytes / 4; ++i )
+ {
+ lpScr[i] = 0;
+ }
+ lpScr += wScreenPitchBytes; // Scanline pitch.
+ }
+}
+
+/* Map physical memory to memory space, lpLinAddress is option pointer to store
+ * mapped linear address
+ */
+static DWORD AllocLinearSelector(DWORD dwPhysAddr, DWORD dwSize, DWORD __far * lpLinAddress)
+{
+ WORD wSel;
+ DWORD dwLinear;
+
+ wSel = DPMI_AllocLDTDesc( 1 ); /* One descriptor, please. */
+ if( !wSel )
+ return( 0 );
+
+ /* Map the framebuffer physical memory. */
+ dwLinear = DPMI_MapPhys( dwPhysAddr, dwSize );
+
+ /* Now set the allocated selector to point to VRAM. */
+ DPMI_SetSegBase( wSel, dwLinear );
+ DPMI_SetSegLimit( wSel, dwSize - 1 );
+
+ if(lpLinAddress != NULL)
+ {
+ *lpLinAddress = dwLinear;
+ }
+
+ return( wSel );
+}
+
+#ifdef SVGA
+/*
+ * Define the screen for accelerated rendering.
+ * Keep on mind, that this works only in 32bit mode
+ * For other use is required using legacy registers.
+ */
+static void SVGA_defineScreen(unsigned wXRes, unsigned wYRes)
+{
+ SVGAFifoCmdDefineScreen __far *screen;
+
+ /* create screen 0 */
+ screen = SVGA_FIFOReserveCmd(SVGA_CMD_DEFINE_SCREEN, sizeof(SVGAFifoCmdDefineScreen));
+
+ if(screen)
+ {
+ _fmemset(screen, 0, sizeof(SVGAFifoCmdDefineScreen));
+ screen->screen.structSize = sizeof(SVGAScreenObject);
+ screen->screen.id = 0;
+ screen->screen.flags = SVGA_SCREEN_MUST_BE_SET | SVGA_SCREEN_IS_PRIMARY;
+ screen->screen.size.width = wXRes;
+ screen->screen.size.height = wYRes;
+ screen->screen.root.x = 0;
+ screen->screen.root.y = 0;
+ screen->screen.cloneCount = 0;
+ SVGA_FIFOCommitAll();
+ }
+}
+
+/* Check if screen acceleration is available */
+static BOOL SVGA_hasAccelScreen()
+{
+ if(wBpp == 32){
+ if(SVGA_HasFIFOCap(SVGA_FIFO_CAP_SCREEN_OBJECT | SVGA_FIFO_CAP_SCREEN_OBJECT_2))
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* Initialize SVGA structure and map FIFO to memory */
+static int __loadds SVGA_full_init()
+{
+ int rc = 0;
+ DWORD fifosel = 0;
+
+ dbg_printf("VMWare SVGA-II init\n");
+
+ rc = SVGA_Init(FALSE);
+
+ if(rc != 0)
+ {
+ return rc;
+ }
+
+ /* gSVGA.fifoMem now holding physical address, map it to linear and convert this address to far pointer */
+ gSVGA.fifoPhy = (uint32)gSVGA.fifoMem;
+ fifosel = AllocLinearSelector(gSVGA.fifoPhy, gSVGA.fifoSize, &gSVGA.fifoLinear);
+ if(fifosel == 0)
+ {
+ dbg_printf("SVGA: Failed to map FIFO memory!\n");
+ return 2;
+ }
+
+ dbg_printf("SVGA: memory selector for fifo: %lX (physical: %lX, size: %lX)\n", fifosel, gSVGA.fifoMem, gSVGA.fifoSize);
+ gSVGA.fifoMem = fifosel :> 0x0;
+
+ /* from PM16 cannot be accesed full fifo buffer properly, so allocate selector to maping as 64K sector */
+ gSVGA.fifoSel = DPMI_AllocLDTDesc(1);
+ if(gSVGA.fifoSel)
+ {
+ DPMI_SetSegLimit(gSVGA.fifoSel, 0xFFFF);
+
+ gSVGA.fifoAct = 0;
+ DPMI_SetSegBase(gSVGA.fifoSel, gSVGA.fifoLinear);
+ }
+
+ /* sets FIFO */
+ SVGA_Enable();
+
+ return 0;
+}
+#endif
+
+/* Set the currently configured mode (wXRes/wYRes) in hardware.
+ * If bFullSet is non-zero, then also reinitialize globals.
+ * When re-establishing a previously set mode (e.g. coming
+ * back from fullscreen), bFullSet will be zero.
+ * NB: BPP won't change at runtime.
+ */
+static int SetDisplayMode( WORD wXRes, WORD wYRes, int bFullSet )
+{
+ dbg_printf( "SetDisplayMode: wXRes=%u wYRes=%u\n", wXRes, wYRes );
+
+ /* Inform the VDD that the mode is about to change. */
+ CallVDD( VDD_PRE_MODE_CHANGE );
+
+#ifdef SVGA
+ /* Make sure, that we drain full FIFO */
+ SVGA_Flush();
+
+ SVGA_SetMode(wXRes, wYRes, wBpp);
+ wMesa3DEnabled = 0;
+ if(SVGA3D_Init())
+ {
+ wMesa3DEnabled = SVGA_3DSupport();
+ }
+
+ if(wMesa3DEnabled && SVGA_hasAccelScreen())
+ {
+ SVGA_defineScreen(wXRes, wYRes);
+ }
+
+ SVGA_WriteReg(SVGA_REG_TRACES, TRUE);
+ SVGA_WriteReg(SVGA_REG_ENABLE, TRUE);
+ SVGA_Flush();
+
+ SVGAHDA_update(wScrX, wScrY, wBpp, SVGA_ReadReg(SVGA_REG_BYTES_PER_LINE));
+#else
+ BOXV_ext_mode_set( 0, wXRes, wYRes, wBpp, wXRes, wYRes );
+
+#endif
+
+ if(FBHDA_ptr)
+ {
+ FBHDA_ptr->width = wScrX;
+ FBHDA_ptr->height = wScrY;
+ FBHDA_ptr->bpp = wBpp;
+#ifdef SVGA
+ FBHDA_ptr->pitch = SVGA_ReadReg(SVGA_REG_BYTES_PER_LINE);
+#else
+ FBHDA_ptr->pitch = CalcPitch( wScrX, wBpp );
+#endif
+ }
+
+ if( bFullSet ) {
+ wScreenX = wXRes;
+ wScreenY = wYRes;
+#ifdef SVGA
+ wScreenPitchBytes = SVGA_ReadReg(SVGA_REG_BYTES_PER_LINE);
+#else
+ wScreenPitchBytes = CalcPitch( wXRes, wBpp );
+#endif
+
+ BitBltDevProc = NULL; /* No acceleration implemented. */
+
+ wPDeviceFlags = MINIDRIVER | VRAM /* | OFFSCREEN */;
+ if( wBpp == 16 ) {
+ wPDeviceFlags |= FIVE6FIVE; /* Needed for 16bpp modes. */
+ }
+
+ wMaxWidth = wScreenPitchBytes / (wBpp / 8); /* We know bpp is a multiple of 8. */
+ wMaxHeight = dwVideoMemorySize / wScreenPitchBytes;
+
+ /* Offscreen regions could be calculated here. We do not use those. */
+ }
+ return( 1 );
+}
+
+
+/* Forward declaration. */
+void __far RestoreDesktopMode( void );
+
+int PhysicalEnable( void )
+{
+ DWORD dwRegRet;
+
+ if( !ScreenSelector ) {
+#ifdef SVGA
+ int rc = 0;
+ dbg_printf("PhysicalEnable: entry mode %ux%u\n", wScrX, wScrY);
+ rc = SVGA_full_init();
+
+ /* Extra work if driver hasn't yet been initialized. */
+ if(rc != 0)
+ {
+ dbg_printf("SVGA_Init() failure: %d, wrong device?\n", rc);
+ return 0;
+ }
+
+ dwVideoMemorySize = SVGA_ReadReg(SVGA_REG_VRAM_SIZE);
+ dwPhysVRAM = SVGA_ReadReg(SVGA_REG_FB_START);
+#else
+ int iChipID;
+
+ /* Extra work if driver hasn't yet been initialized. */
+ iChipID = BOXV_detect( 0, &dwVideoMemorySize );
+ if( !iChipID ) {
+ return( 0 );
+ }
+ dwPhysVRAM = BOXV_get_lfb_base( 0 );
+#endif
+ dbg_printf( "PhysicalEnable: Hardware detected, dwVideoMemorySize=%lX dwPhysVRAM=%lX\n", dwVideoMemorySize, dwPhysVRAM );
+ }
+
+ dbg_printf("PhysicalEnable: continue with %ux%u\n", wScrX, wScrY);
+ if( !IsModeOK( wScrX, wScrY, wBpp ) ) {
+ /* Can't find mode, oopsie. */
+ dbg_printf( "PhysicalEnable: Mode not valid! wScrX=%u wScrY=%u wBpp=%u\n", wScrX, wScrY, wBpp );
+ return( 0 );
+ }
+
+ if( !SetDisplayMode( wScrX, wScrY, 1 ) ) {
+ /* This is not good. */
+ dbg_printf( "PhysicalEnable: SetDisplayMode failed! wScrX=%u wScrY=%u wBpp=%u\n", wScrX, wScrY, wBpp );
+ return( 0 );
+ }
+
+ /* Allocate an LDT selector for the screen. */
+ if( !ScreenSelector ) {
+ //ScreenSelector = AllocLinearSelector( dwPhysVRAM, dwVideoMemorySize );
+ ScreenSelector = AllocLinearSelector(dwPhysVRAM, dwVideoMemorySize, &dwScreenFlatAddr);
+ if( !ScreenSelector ) {
+ dbg_printf( "PhysicalEnable: AllocScreenSelector failed!\n" );
+ return( 0 );
+ }
+
+#ifdef SVGA
+ gSVGA.fbLinear = dwScreenFlatAddr;
+ gSVGA.fbPhy = dwPhysVRAM;
+ gSVGA.fbMem = ScreenSelector :> 0;
+
+ /* init userspace hardware access */
+ SVGAHDA_init();
+#endif
+ }
+
+ /* NB: Currently not used. DirectDraw would need the segment base. */
+ /* JH: we need it for FIFO (SVGA) or direct FB rendering, but retuned by AllocLinearSelector in one CALL */
+ //dwScreenFlatAddr = DPMI_GetSegBase( ScreenSelector ); /* Not expected to fail. */
+
+ dbg_printf( "PhysicalEnable: RestoreDesktopMode is at %WP\n", RestoreDesktopMode );
+ dwRegRet = CallVDDRegister( VDD_DRIVER_REGISTER, wScreenPitchBytes, wScreenY, RestoreDesktopMode );
+ if( dwRegRet != VDD_DRIVER_REGISTER ) {
+ /* NB: It's not fatal if CallVDDRegister() fails. */
+ /// @todo What can we do with the returned value?
+ }
+
+ /* allocate and fill FBHDA */
+ if(FBHDA_ptr == NULL)
+ {
+ FBHDA_ptr = drv_malloc(sizeof(FBHDA), &FBHDA_linear);
+ if(FBHDA_ptr)
+ {
+ FBHDA_ptr->width = wScrX;
+ FBHDA_ptr->height = wScrY;
+ FBHDA_ptr->bpp = wBpp;
+ FBHDA_ptr->pitch = wScreenPitchBytes;
+
+ FBHDA_ptr->fb_pm32 = dwScreenFlatAddr;
+ FBHDA_ptr->fb_pm16 = ScreenSelector :> 0;
+ }
+ else
+ {
+ dbg_printf( "FBHDA_ptr = drv_malloc FAIL\n" );
+ }
+ }
+
+#ifdef SVGA
+ /* update SVGAHDA */
+ SVGAHDA_update(wScrX, wScrY, wBpp, wScreenPitchBytes);
+#endif
+
+ /* Let the VDD know that the mode changed. */
+ CallVDD( VDD_POST_MODE_CHANGE );
+ CallVDD( VDD_SAVE_DRIVER_STATE );
+
+ ClearVisibleScreen();
+
+ return( 1 ); /* All good. */
+}
+
+
+/* Check if the requested mode can be set. Return yes, no (with a reason),
+ * or maybe. .
+ * Must be exported by name, recommended ordinal 700.
+ * NB: Can be called when the driver is not the current display driver.
+ */
+#pragma aux ValidateMode loadds; /* __loadds not operational due to prototype in valmode.h */
+UINT WINAPI __loadds ValidateMode( DISPVALMODE FAR *lpValMode )
+{
+ UINT rc = VALMODE_YES;
+
+ //dbg_printf( "ValidateMode: X=%u Y=%u bpp=%u\n", lpValMode->dvmXRes, lpValMode->dvmYRes, lpValMode->dvmBpp );
+ do {
+ if( !ScreenSelector ) {
+#ifdef SVGA
+ int svga_rc = SVGA_Init(FALSE); /* only load registers but not enabling device yet */
+
+ /* Extra work if driver hasn't yet been initialized. */
+ if(svga_rc != 0)
+ {
+ rc = VALMODE_NO_WRONGDRV;
+ break;
+ }
+
+ dwVideoMemorySize = SVGA_ReadReg(SVGA_REG_VRAM_SIZE);
+ dwPhysVRAM = SVGA_ReadReg(SVGA_REG_FB_START);
+#else
+ int iChipID;
+
+ /* Additional checks if driver isn't running. */
+ iChipID = BOXV_detect( 0, &dwVideoMemorySize );
+ if( !iChipID ) {
+ rc = VALMODE_NO_WRONGDRV;
+ break;
+ }
+ dwPhysVRAM = BOXV_get_lfb_base( 0 );
+#endif
+ dbg_printf( "ValidateMode: Hardware detected, dwVideoMemorySize=%lX dwPhysVRAM=%lX\n", dwVideoMemorySize, dwPhysVRAM );
+ }
+
+ if( !IsModeOK( lpValMode->dvmXRes, lpValMode->dvmYRes, lpValMode->dvmBpp ) ) {
+ rc = VALMODE_NO_NOMEM;
+ }
+ } while( 0 );
+
+ //dbg_printf( "ValidateMode: rc=%u\n", rc );
+ return( rc );
+}
+
+void PhysicalDisable(void)
+{
+#ifdef SVGA
+ SVGA_Disable();
+#endif
+}
+
+#pragma code_seg( _TEXT );
+
+/* Called by the VDD in order to restore the video state when switching back
+ * to the system VM. Function is in locked memory (_TEXT segment).
+ * NB: Must reload DS, but apparently need not save/restore DS.
+ */
+#pragma aux RestoreDesktopMode loadds;
+void __far RestoreDesktopMode( void )
+{
+ dbg_printf( "RestoreDesktopMode: %ux%u, wBpp=%u\n", wScreenX, wScreenY, wBpp );
+
+ /* Set the current desktop mode again. */
+ SetDisplayMode( wScreenX, wScreenY, 0 );
+
+ /* Reprogram the DAC if relevant. */
+ if( wBpp <= 8 ) {
+ UINT wPalCnt;
+
+ switch( wBpp ) {
+ case 8:
+ wPalCnt = 256;
+ break;
+ case 4:
+ wPalCnt = 16;
+ break;
+ default:
+ wPalCnt = 2;
+ break;
+ }
+ SetRAMDAC_far( 0, wPalCnt, lpColorTable );
+ }
+
+ /* Clear the busy flag. Quite important. */
+ lpDriverPDevice->deFlags &= ~BUSY;
+
+ /* Poke the VDD now that everything is restored. */
+ CallVDD( VDD_SAVE_DRIVER_STATE );
+
+ ClearVisibleScreen();
+}
+
diff --git a/modes_svga.c b/modes_svga.c
new file mode 100644
index 0000000..a383dcb
--- /dev/null
+++ b/modes_svga.c
@@ -0,0 +1,2 @@
+#define SVGA
+#include "modes.c"
diff --git a/palette.c b/palette.c
new file mode 100644
index 0000000..9721f0c
--- /dev/null
+++ b/palette.c
@@ -0,0 +1,89 @@
+/*****************************************************************************
+
+Copyright (c) 2022 Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* Display driver palette (RAMDAC) functions. */
+
+#include "winhack.h"
+#include <gdidefs.h>
+#include <dibeng.h>
+#include "minidrv.h"
+#include <conio.h> /* For port I/O prototypes. */
+#include "boxvint.h" /* For VGA register definitions. */
+
+#ifdef SVGA
+#include "svga_all.h"
+
+#pragma code_seg( _INIT )
+
+static void __loadds __far SetColor(unsigned index, unsigned char r, unsigned char g, unsigned char b)
+{
+ UINT sIndex = SVGA_PALETTE_BASE + index*3;
+
+ SVGA_WriteReg(sIndex+0, r);
+ SVGA_WriteReg(sIndex+1, g);
+ SVGA_WriteReg(sIndex+2, b);
+}
+#endif
+
+#pragma code_seg( _TEXT )
+
+/* Load the VGA DAC with values from color table. */
+static void SetRAMDAC( UINT bStart, UINT bCount, RGBQUAD FAR *lpPal )
+{
+#ifdef SVGA
+ BYTE bIndex = bStart;
+
+ while( bCount-- ) {
+ SetColor(bIndex++, lpPal[bIndex].rgbRed, lpPal[bIndex].rgbGreen, lpPal[bIndex].rgbBlue);
+ }
+#else
+ BYTE bIndex = bStart;
+
+ /* The data format is too weird for BOXV_dac_set(). Do it by hand. */
+ outp( VGA_DAC_W_INDEX, bIndex ); /* Set starting index. */
+ while( bCount-- ) {
+ outp( VGA_DAC_DATA, lpPal[bIndex].rgbRed );
+ outp( VGA_DAC_DATA, lpPal[bIndex].rgbGreen );
+ outp( VGA_DAC_DATA, lpPal[bIndex].rgbBlue );
+ ++bIndex;
+ }
+#endif
+}
+
+/* Allow calls from the _INIT segment. */
+void __far SetRAMDAC_far( UINT bStart, UINT bCount, RGBQUAD FAR *lpPal )
+{
+ SetRAMDAC( bStart, bCount, lpPal );
+}
+
+UINT WINAPI __loadds SetPalette( UINT wStartIndex, UINT wNumEntries, LPVOID lpPalette )
+{
+ /* Let the DIB engine do what it can. */
+ DIB_SetPaletteExt( wStartIndex, wNumEntries, lpPalette, lpDriverPDevice );
+
+ if( !(lpDriverPDevice->deFlags & BUSY) )
+ SetRAMDAC( wStartIndex, wNumEntries, lpColorTable );
+
+ return( 0 );
+}
diff --git a/palette_svga.c b/palette_svga.c
new file mode 100644
index 0000000..b607145
--- /dev/null
+++ b/palette_svga.c
@@ -0,0 +1,2 @@
+#define SVGA
+#include "palette.c"
diff --git a/readdev.txt b/readdev.txt
new file mode 100644
index 0000000..22d58e7
--- /dev/null
+++ b/readdev.txt
@@ -0,0 +1,89 @@
+ Development Notes
+ =================
+
+ This Windows 9x display minidriver is almost entirely written in C. It is
+a 16-bit DLL running with SS != DS. The compiler switches were carefully
+chosen.
+
+ The driver is compiled as small model code and although it uses some C
+library functions (e.g. _fmemcpy(), _fmemset()), it does not use the C runtime
+startup code at all.
+
+ An interrupt 2Fh handler is written in assembler, and so are forwarders and
+thunks directing exported functions to the DIB Engine. The latter could be
+written in C, but assembly is significantly more efficient and not at all
+complex.
+
+ The driver is by necessity similar to Windows 95/98 DDK sample code, except
+it's written almost completely in C whereas the DDK sample drivers are written
+100% in assembly, in the tradition of Windows 3.x and 2.x display drivers.
+
+ Although the driver is a 16-bit DLL, it can freely use 386 instructions,
+since it requires a 386 or later CPU by virtue of running on Windows 95 or
+later. The driver also can and does use 32-bit registers in some situations.
+
+ The ddk subdirectory contains files which are directly derived from the
+Win9x DDK. The DDK is not used or required to build this driver, although DDK
+documentation is very useful in understanding the code. Note that the Windows
+9x DDK documentation may not cover topics documented in the Windows 3.x DDKs.
+
+ The original DDK drivers are split into two code segments, _TEXT and _INIT.
+This driver also uses those segments, but they are combined into a single
+physical segment by the linker. This simplifies the code (e.g. no problem with
+near calls into the C runtime) and given the small size of the driver, likely
+is not at all disadvantageous overall.
+
+ Note that the driver written in C is actually smaller (about 7KB vs. 8KB)
+than the assembler-only DDK sample. The C code is smarter and does not waste
+space on tables full of zeros and such, enabling it to be overall smaller even
+with the overhead of a higher level language.
+
+
+ Debug Logging
+ -------------
+
+ When built with DBGPRINT (e.g. wmake clean && wmake DBGPRINT=1), the driver
+includes debug logging implemented as dbg_printf() function. This is a small
+printf() subset with output directed to the VirtualBox debug port, such that
+the output appears in the VBox.log file.
+
+ It would be much nicer to use the C runtime printf(), but that is not at all
+possible because the small model library printf() cannot operate with SS != DS
+and is thus unusable, even if all other, less showstopping problems were
+overcome.
+
+ See driver code for dbg_printf() usage examples.
+
+
+ Building with Open Watcom 1.9
+ -----------------------------
+
+ The driver source was slightly adapted so that it builds with the released
+Open Watcom C/C++ 1.9 compiler.
+
+ The only real issue is that the ms2wlink utility shipped with Open Watcom
+version 1.9 cannot correctly process boxv9x.def, and therefore a working
+boxv9x.lnk file is supplied.
+
+ The build process was only tested on Windows 10 hosts. It should work,
+possibly with minor adaptations, on other platforms as well. That includes
+Windows 9x hosts.
+
+ The step of building a floppy image is optional and requires the mkimage
+utility (part of the OS/2 Museum's fdimg project) which is not included.
+
+
+ Replacing Active Driver
+ -----------------------
+
+ Once the boxvmini.drv driver is installed, it cannot be replaced while
+Windows 9x is running because the file is locked. It can be replaced in safe
+mode or command line boot (F8 key early in Win9x startup).
+
+ It can also be replaced by shutting down Windows 9x (not Windows Me) to
+MS-DOS compatibility mode, copying over boxvmini.drv to the WINDOWS\SYSTEM
+directory, and exiting back to Windows.
+
+ It is always possible to use the driver update dialog to install a rebuilt
+driver, but that requires more clicking and Windows must be restarted
+anyway.
diff --git a/readme-orig.txt b/readme-orig.txt
new file mode 100644
index 0000000..7eb8e8f
--- /dev/null
+++ b/readme-orig.txt
@@ -0,0 +1,13 @@
+This is a display minidriver for the Windows 9x family of operating systems,
+designed to run on the virtual hardware provided by VirtualBox.
+
+The driver can be installed through the Display Settings dialog or through
+the Device Manager.
+
+Supported color depths are 8/16/24/32 bits per pixel. The driver supports
+many common resolutions, limited by the available video memory (VRAM).
+
+The driver does not have a built in list of modes. It will set more or less
+any resolution between 640x480 and 5120x3840. The INF file determines the
+set of predefined modes. By editing the INF file or the resolution information
+copied into the Registry, users can add or remove available modes.
diff --git a/res/boxvmini.rc b/res/boxvmini.rc
new file mode 100644
index 0000000..3ecffa0
--- /dev/null
+++ b/res/boxvmini.rc
@@ -0,0 +1,19 @@
+/*
+ * Windows 9x minidriver resource file.
+ * Most of the contents is defined by backward compatibility
+ * requirements. Much of the detail is explained in the Windows 3.x
+ * and 2.x DDKs.
+ */
+
+#include "windows.h"
+
+#define VER_ORIGINALFILENAME_STR "boxvmini.drv"
+
+#include "display.rcv"
+
+1 oembin PRELOAD config.bin
+2 oembin colortab.bin
+3 oembin PRELOAD fonts.bin
+fonts oembin fonts.bin
+
+2003 oembin PRELOAD fonts120.bin
diff --git a/res/colortab.c b/res/colortab.c
new file mode 100644
index 0000000..7634f08
--- /dev/null
+++ b/res/colortab.c
@@ -0,0 +1,62 @@
+#include "winhack.h"
+#include <gdidefs.h>
+
+/* Color table for the Control Panel. */
+
+typedef struct {
+ WORD wCount;
+ RGBQUAD rgbColors[];
+} COLORTABLE;
+
+COLORTABLE ColorTbl = {
+ 48, /* Number of entries in table. */
+ 0xFF, 0x80, 0x80, 0,
+ 0xFF, 0xFF, 0xE8, 0,
+ 0x80, 0xFF, 0x80, 0,
+ 0x00, 0xFF, 0x80, 0,
+ 0x80, 0xFF, 0xFF, 0,
+ 0x00, 0x80, 0xFF, 0,
+ 0xFF, 0x80, 0xC0, 0,
+ 0xFF, 0x80, 0xFF, 0,
+ 0xFF, 0x00, 0x00, 0,
+ 0xFF, 0xFF, 0x80, 0,
+ 0x80, 0xFF, 0x00, 0,
+ 0x00, 0xFF, 0x40, 0,
+ 0x00, 0xFF, 0xFF, 0,
+ 0x00, 0x80, 0xC0, 0,
+ 0x80, 0x80, 0xC0, 0,
+ 0xFF, 0x00, 0xFF, 0,
+ 0x80, 0x40, 0x40, 0,
+ 0xFF, 0xFF, 0x00, 0,
+ 0x00, 0xFF, 0x00, 0,
+ 0x00, 0x80, 0x80, 0,
+ 0x00, 0x40, 0x80, 0,
+ 0x80, 0x80, 0xFF, 0,
+ 0x80, 0x00, 0x40, 0,
+ 0xFF, 0x00, 0x80, 0,
+ 0x80, 0x00, 0x00, 0,
+ 0xFF, 0x80, 0x00, 0,
+ 0x00, 0x80, 0x00, 0,
+ 0x00, 0x80, 0x40, 0,
+ 0x00, 0x00, 0xFF, 0,
+ 0x00, 0x00, 0xA0, 0,
+ 0x80, 0x00, 0x80, 0,
+ 0x80, 0x00, 0xFF, 0,
+ 0x40, 0x00, 0x00, 0,
+ 0x80, 0x40, 0x00, 0,
+ 0x00, 0x40, 0x00, 0,
+ 0x00, 0x40, 0x40, 0,
+ 0x00, 0x00, 0x80, 0,
+ 0x00, 0x00, 0x40, 0,
+ 0x40, 0x00, 0x40, 0,
+ 0x40, 0x00, 0x80, 0,
+ 0x00, 0x00, 0x00, 0,
+ 0x80, 0x80, 0x00, 0,
+ 0x80, 0x80, 0x40, 0,
+ 0x80, 0x80, 0x80, 0,
+ 0x40, 0x80, 0x80, 0,
+ 0xC0, 0xC0, 0xC0, 0,
+ 0x82, 0x82, 0x82, 0,
+ 0xFF, 0xFF, 0xFF, 0
+};
+
diff --git a/res/config.c b/res/config.c
new file mode 100644
index 0000000..81b3aa7
--- /dev/null
+++ b/res/config.c
@@ -0,0 +1,74 @@
+#include "winhack.h"
+#include <gdidefs.h>
+
+/* Typedef from Windows 3.1 DDK. */
+
+typedef struct {
+
+ /* machine-dependent parameters */
+ short VertThumHeight; /* vertical thumb height (in pixels) */
+ short HorizThumWidth; /* horizontal thumb width (in pixels) */
+ short IconXRatio; /* icon width (in pixels) */
+ short IconYRatio; /* icon height (in pixels) */
+ short CurXRatio; /* cursor width (in pixels) */
+ short CurYRatio; /* cursor height (in pixels) */
+ short Reserved; /* reserved */
+ short XBorder; /* vertical-line width */
+ short YBorder; /* horizontal-line width */
+
+ /* default-system color values */
+ RGBQUAD clrScrollbar;
+ RGBQUAD clrDesktop;
+ RGBQUAD clrActiveCaption;
+ RGBQUAD clrInactiveCaption;
+ RGBQUAD clrMenu;
+ RGBQUAD clrWindow;
+ RGBQUAD clrWindowFrame;
+ RGBQUAD clrMenuText;
+ RGBQUAD clrWindowText;
+ RGBQUAD clrCaptionText;
+ RGBQUAD clrActiveBorder;
+ RGBQUAD clrInactiveBorder;
+ RGBQUAD clrAppWorkspace;
+ RGBQUAD clrHiliteBk;
+ RGBQUAD clrHiliteText;
+ RGBQUAD clrBtnFace;
+ RGBQUAD clrBtnShadow;
+ RGBQUAD clrGrayText;
+ RGBQUAD clrBtnText;
+ RGBQUAD clrInactiveCaptionText;
+} CONFIG_BIN;
+
+
+CONFIG_BIN Config = {
+ 17,
+ 17,
+ 2,
+ 2,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+
+ 192, 192, 192, 0,
+ 192, 192, 192, 0,
+ 000, 000, 128, 0,
+ 255, 255, 255, 0,
+ 255, 255, 255, 0,
+ 255, 255, 255, 0,
+ 000, 000, 000, 0,
+ 000, 000, 000, 0,
+ 000, 000, 000, 0,
+ 255, 255, 255, 0,
+ 192, 192, 192, 0,
+ 192, 192, 192, 0,
+ 255, 255, 255, 0,
+ 000, 000, 128, 0,
+ 255, 255, 255, 0,
+ 192, 192, 192, 0,
+ 128, 128, 128, 0,
+ 192, 192, 192, 0,
+ 000, 000, 000, 0,
+ 000, 000, 000, 0
+};
diff --git a/res/display.rcv b/res/display.rcv
new file mode 100644
index 0000000..54879f4
--- /dev/null
+++ b/res/display.rcv
@@ -0,0 +1,82 @@
+#include <ver.h>
+#include "version.h"
+
+/* Macros for use in the version resource. */
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_DISPLAY
+#define VER_FILEDESCRIPTION_STR "Windows 9x Display Minidriver"
+#define VER_INTERNALNAME_STR "DISPLAY"
+#define VER_LEGALCOPYRIGHT_YEARS "2012-2023"
+
+#define VER_LEGALCOPYRIGHT_STR "Copyright \251 The OS/2 Museum " VER_LEGALCOPYRIGHT_YEARS
+#define VER_COMPANYNAME_STR "OS/2 Museum\0"
+
+#define VER_PRODUCTNAME_STR "Windows 9x Display Driver\0"
+#define VER_PRODUCTVERSION DRV_VER_NUM
+#define VER_PRODUCTVERSION_STR DRV_VER_STR "\0"
+
+#define VER_FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+
+#ifdef DEBUG
+#define VER_FILEFLAGS VS_FF_DEBUG
+#else
+#define VER_FILEFLAGS 0
+#endif
+
+#define VER_FILEOS VOS_DOS_WINDOWS16
+
+#ifndef VER_FILEVERSION
+#define VER_FILEVERSION VER_PRODUCTVERSION
+#endif
+
+#ifndef VER_FILEVERSION_STR
+#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR
+#endif
+
+/* Actual version resource structure. */
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION VER_FILEVERSION
+PRODUCTVERSION VER_PRODUCTVERSION
+FILEFLAGSMASK VER_FILEFLAGSMASK
+FILEFLAGS VER_FILEFLAGS
+FILEOS VER_FILEOS
+FILETYPE VER_FILETYPE
+FILESUBTYPE VER_FILESUBTYPE
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName" , VER_COMPANYNAME_STR
+ VALUE "FileDescription" , VER_FILEDESCRIPTION_STR
+ VALUE "FileVersion" , VER_FILEVERSION_STR
+ VALUE "InternalName" , VER_INTERNALNAME_STR
+ VALUE "LegalCopyright" , VER_LEGALCOPYRIGHT_STR
+ VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR
+ VALUE "ProductName" , VER_PRODUCTNAME_STR
+ VALUE "ProductVersion" , VER_PRODUCTVERSION_STR
+ END
+
+#ifdef INTL
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName" , VER_COMPANYNAME_STR
+ VALUE "FileDescription" , VER_FILEDESCRIPTION_STR
+ VALUE "FileVersion" , VER_FILEVERSION_STR
+ VALUE "InternalName" , VER_INTERNALNAME_STR
+ VALUE "LegalCopyright" , VER_LEGALCOPYRIGHT_STR
+ VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR
+ VALUE "ProductName" , VER_PRODUCTNAME_STR
+ VALUE "ProductVersion" , VER_PRODUCTVERSION_STR
+ END
+#endif
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 0x04E4 /* Needs updating. */
+ END
+END
+
diff --git a/res/fonts.c b/res/fonts.c
new file mode 100644
index 0000000..d4ab867
--- /dev/null
+++ b/res/fonts.c
@@ -0,0 +1,6 @@
+/* Standard font resource for 96 DPI. */
+
+#define OEM_FNT_HEIGHT 12
+#define OEM_FNT_WIDTH 8
+
+#include "fonttmpl.c"
diff --git a/res/fonts120.c b/res/fonts120.c
new file mode 100644
index 0000000..f98ab60
--- /dev/null
+++ b/res/fonts120.c
@@ -0,0 +1,6 @@
+/* Font resource for 120 DPI. */
+
+#define OEM_FNT_HEIGHT 10
+#define OEM_FNT_WIDTH 20
+
+#include "fonttmpl.c"
diff --git a/res/fonttmpl.c b/res/fonttmpl.c
new file mode 100644
index 0000000..f5ad573
--- /dev/null
+++ b/res/fonttmpl.c
@@ -0,0 +1,55 @@
+#include "winhack.h"
+/* Trick to get a variable-size LOGFONT structure. */
+#define LF_FACESIZE
+#include <gdidefs.h>
+
+LOGFONT OEMFixed = {
+ OEM_FNT_HEIGHT,
+ OEM_FNT_WIDTH,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 255, /* Charset. */
+ 0,
+ 2, /* Clip precision. */
+ 2, /* Quality. */
+ 1, /* Pitch. */
+ "Terminal" /* Font face. */
+};
+
+LOGFONT ANSIFixed = {
+ 12, /* Width. */
+ 9, /* Height. */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0, /* Charset. */
+ 0,
+ 2, /* Clip precision. */
+ 2, /* Quality. */
+ 1, /* Pitch. */
+ "Courier" /* Font face. */
+};
+
+LOGFONT ANSIVar = {
+ 12, /* Width. */
+ 9, /* Height. */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0, /* Charset. */
+ 0,
+ 2, /* Clip precision. */
+ 2, /* Quality. */
+ 2, /* Pitch. */
+ "Helv" /* Font face. */
+};
diff --git a/res/vmws_vxd.rc b/res/vmws_vxd.rc
new file mode 100644
index 0000000..0ad9778
--- /dev/null
+++ b/res/vmws_vxd.rc
@@ -0,0 +1,12 @@
+/*
+ * Windows 9x minidriver resource file.
+ * Most of the contents is defined by backward compatibility
+ * requirements. Much of the detail is explained in the Windows 3.x
+ * and 2.x DDKs.
+ */
+
+#include "windows.h"
+
+#define VER_ORIGINALFILENAME_STR "vmsvmini.vxd"
+
+#include "display.rcv"
diff --git a/res/vmwsmini.rc b/res/vmwsmini.rc
new file mode 100644
index 0000000..4df0da1
--- /dev/null
+++ b/res/vmwsmini.rc
@@ -0,0 +1,19 @@
+/*
+ * Windows 9x minidriver resource file.
+ * Most of the contents is defined by backward compatibility
+ * requirements. Much of the detail is explained in the Windows 3.x
+ * and 2.x DDKs.
+ */
+
+#include "windows.h"
+
+#define VER_ORIGINALFILENAME_STR "vmsvmini.drv"
+
+#include "display.rcv"
+
+1 oembin PRELOAD config.bin
+2 oembin colortab.bin
+3 oembin PRELOAD fonts.bin
+fonts oembin fonts.bin
+
+2003 oembin PRELOAD fonts120.bin
diff --git a/scrsw.c b/scrsw.c
new file mode 100644
index 0000000..892b15d
--- /dev/null
+++ b/scrsw.c
@@ -0,0 +1,229 @@
+/*****************************************************************************
+
+Copyright (c) 2022 Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* Screen switching support (C code). */
+
+#include "winhack.h"
+#include <gdidefs.h>
+#include <dibeng.h>
+#include "minidrv.h"
+#ifdef SVGA
+#include "svga_all.h"
+#endif
+
+/* SwitchFlags bits. */
+#define PREVENT_SWITCH 0x80 /* Don't allow screen switching. */
+#define INT_2F_HOOKED 0x01 /* INT 2Fh is hooked. */
+
+/* Accessed from sswhook.asm. */
+BYTE SwitchFlags = 0; /* Screen switch flags, see above. */
+
+static BOOL bNoRepaint = 0; /* Set when USER disables repaints. */
+static BOOL bPaintPending = 0; /* Set when repaint was postponed.*/
+
+FARPROC RepaintFunc = 0; /* Address of repaint callback. */
+
+/* Screen switch hook for INT 2Fh. */
+extern void __far SWHook( void );
+
+#pragma code_seg( _INIT )
+
+/* The pointer is in the code (_TEXT) segment, not data segment.
+ * Defined in sswhook.asm.
+ */
+extern void __far * __based( __segname( "_TEXT" ) ) OldInt2Fh;
+
+
+/* Call DOS to get an interrupt vector. */
+void __far *DOSGetIntVec( BYTE bIntNo );
+#pragma aux DOSGetIntVec = \
+ "mov ah, 35h" \
+ "int 21h" \
+ parm [al] value [es bx];
+
+/* Call DOS to set an interrupt vector. */
+void DOSSetIntVec( BYTE bIntNo, void __far *NewVector );
+#pragma aux DOSSetIntVec = \
+ "mov ah, 25h" \
+ "push ds" \
+ "push es" \
+ "pop ds" \
+ "int 21h" \
+ "pop ds" \
+ parm [al] [es dx];
+
+
+/* Ordinal of the repaint callback in USER. Of course undocumented. */
+#define REPAINT_ORDINAL 275
+
+/* Fun times. Undocumented function to create a writable alias of a code
+ * selector. In MS KB Q67165, Microsoft claimed that the function "is not
+ * documented and will not be supported in future versions of Windows".
+ * Clearly they lied, as it happily works on Win9x.
+ */
+extern UINT WINAPI AllocCStoDSAlias( UINT selCode );
+
+/* Internal function to install INT 2Fh hook. */
+void HookInt2Fh( void )
+{
+ WORD selAlias;
+ void __far * __far *OldInt2FhAlias; /* This is fun! */
+
+ /* If not already set, get repaing callback from USER. */
+ if( !RepaintFunc ) {
+ HMODULE hMod;
+
+ hMod = GetModuleHandle( "USER" );
+ RepaintFunc = GetProcAddress( hMod, (LPCSTR)REPAINT_ORDINAL );
+ }
+ dbg_printf( "HookInt2Fh: RepaintFunc=%WP\n", RepaintFunc );
+
+ /* Now hook INT 2Fh. Since the address of the previous INT 2Fh handler
+ * is in the code segment, we have to create a writable alias. Just
+ * a little tricky.
+ */
+ selAlias = AllocCStoDSAlias( (__segment)&OldInt2Fh );
+
+ SwitchFlags |= INT_2F_HOOKED;
+ /* Build a pointer to OldInt2Fh using the aliased selector. */
+ OldInt2FhAlias = selAlias :> (WORD)&OldInt2Fh;
+ *OldInt2FhAlias = DOSGetIntVec( 0x2F );
+ DOSSetIntVec( 0x2F, SWHook );
+
+ FreeSelector( selAlias );
+}
+
+/* Internal function to unhook INT 2Fh. */
+void UnhookInt2Fh( void )
+{
+ if( SwitchFlags & INT_2F_HOOKED ) {
+ /* We have INT 2Fh hooked, undo that. */
+ SwitchFlags &= ~INT_2F_HOOKED;
+ DOSSetIntVec( 0x2F, OldInt2Fh );
+ }
+}
+
+#ifdef SVGA
+static void __far __loadds SVGA_background()
+{
+ SVGA_WriteReg(SVGA_REG_ENABLE, FALSE);
+}
+
+static void __far __loadds SVGA_foreground()
+{
+ SVGA_WriteReg(SVGA_REG_ENABLE, TRUE);
+}
+#endif /* SVGA */
+
+#pragma code_seg( _TEXT )
+
+/* Repaint screen or postpone for later.
+ * Internal near call.
+ */
+void RepaintScreen( void )
+{
+ dbg_printf( "RepaintScreen: RepaintFunc=%WP, bNoRepaint=%u\n", RepaintFunc, bNoRepaint );
+
+ /* Do we have a repaint callback? */
+ if( RepaintFunc ) {
+ /* Either do the work or set the pending flag. */
+ if( !bNoRepaint )
+ RepaintFunc();
+ else
+ bPaintPending = TRUE;
+ }
+}
+
+/* This function is exported as DISPLAY.500 and called by USER
+ * to inform the driver that screen repaint requests should not
+ * be sent. When we need to repaint while repaints are disabled,
+ * we set an internal flag and do the redraw as soon as repaints
+ * are enabled again.
+ */
+VOID WINAPI __loadds UserRepaintDisable( BOOL bDisable )
+{
+ bNoRepaint = bDisable;
+ if( !bDisable && bPaintPending ) {
+ RepaintScreen();
+ bPaintPending = 0;
+ }
+}
+
+/* Called from INT 2Fh hook when the device is switching to the
+ * background and needs to disable drawing.
+ * Internal near call.
+ */
+void SwitchToBgnd( void )
+{
+ dbg_printf( "SwitchToBgnd\n" );
+#ifdef SVGA
+ SVGA_background();
+#endif
+
+ lpDriverPDevice->deFlags |= BUSY; /// @todo Does this need to be a locked op?
+}
+
+/* Called from INT 2Fh hook when the device is switching to the
+ * foreground and needs re-enable drawing, repaiting the screen
+ * and possibly restoring the display mode.
+ * Internal near call.
+ */
+void SwitchToFgnd( void )
+{
+ dbg_printf( "SwitchToFgnd\n" );
+#ifdef SVGA
+ SVGA_foreground();
+#endif
+
+ /* If the PDevice is busy, we need to reset the display mode. */
+ if( lpDriverPDevice->deFlags & BUSY )
+ RestoreDesktopMode(); /* Will clear the BUSY flag. */
+ RepaintScreen();
+}
+
+/* This minidriver does not currently disable or enable switching.
+ * Should the functions be needed, they can be enabled.
+ */
+#if 0
+
+/* Called to prevent screen switching.
+ * Internal near call.
+ */
+void ScrSwDisable( void )
+{
+ int_2Fh( ENTER_CRIT_REG );
+ SwitchFlags |= PREVENT_SWITCH;
+}
+
+/* Called to re-enable screen switching again.
+ * Internal near call.
+ */
+void ScrSwEnable( void )
+{
+ int_2Fh( EXIT_CRIT_REG );
+ SwitchFlags &= ~PREVENT_SWITCH;
+}
+
+#endif
+
diff --git a/scrsw_svga.c b/scrsw_svga.c
new file mode 100644
index 0000000..6cdf4ae
--- /dev/null
+++ b/scrsw_svga.c
@@ -0,0 +1,2 @@
+#define SVGA
+#include "scrsw.c"
diff --git a/sswhook.asm b/sswhook.asm
new file mode 100644
index 0000000..76bc075
--- /dev/null
+++ b/sswhook.asm
@@ -0,0 +1,126 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Copyright (c) 2022 Michal Necasek
+;
+; Permission is hereby granted, free of charge, to any person obtaining a copy
+; of this software and associated documentation files (the "Software"), to deal
+; in the Software without restriction, including without limitation the rights
+; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+; copies of the Software, and to permit persons to whom the Software is
+; furnished to do so, subject to the following conditions:
+;
+; The above copyright notice and this permission notice shall be included in
+; all copies or substantial portions of the Software.
+;
+; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+; THE SOFTWARE.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Screen switching hook written in assembler.
+
+; See minidrv.h for more.
+SCREEN_SWITCH_OUT equ 4001h
+SCREEN_SWITCH_IN equ 4002h
+
+; Defined by us, must match minidrv.h
+PREVENT_SWITCH equ 80h
+
+; Carry flag bit on the stack
+FLAG_CF equ 0001h
+
+public _OldInt2Fh
+public SWHook_
+
+; Callbacks written in C
+extrn SwitchToBgnd_ : far
+extrn SwitchToFgnd_ : far
+
+_DATA segment public 'DATA'
+
+; Defined in C code
+extrn _SwitchFlags : byte
+
+; Dispatch table. Only used locally.
+dsp_tbl label word
+ dw SwitchToBgnd_ ; SCREEN_SWITCH_OUT handler
+ dw SwitchToFgnd_ ; SCREEN_SWITCH_IN handler
+
+_DATA ends
+
+DGROUP group _DATA
+
+_TEXT segment public 'CODE'
+
+; Defined in code segment so that we can chain to the old interrupt
+; handler without needing to mess with DS.
+_OldInt2Fh dd 0
+
+ .386
+
+; Screen switching hook for INT 2Fh. We need to handle screen switch
+; notifications ourselves and let the previous handler deal with the
+; rest.
+SWHook_ proc far
+
+ ; Cannot assume anything
+ assume ds:nothing, es:nothing
+
+ ; Check if the subfunction is one of those we're
+ ; interested in and chain to previous handler if not.
+ cmp ax, SCREEN_SWITCH_OUT
+ jz handle_fn
+ cmp ax, SCREEN_SWITCH_IN
+ jz handle_fn
+ jmp _OldInt2Fh ; Registers undisturbed (except flags)
+
+ ; We are going to handle this interrupt and not chain.
+handle_fn:
+ push ds ; Save what we can
+ pushad
+
+ ; Establish data segment addressing
+ mov bx, _DATA ; We'll overwrite BX later
+ mov ds, bx
+ assume ds:DGROUP
+
+ mov bx, ax ; We will need the function later
+ mov bp, sp ; So we can address stack
+
+ ; See if switching is disabled
+ mov al, _SwitchFlags
+ test al, PREVENT_SWITCH
+ jz dispatch ; If not set, do do the work
+
+ ; It's disabled; set carry flag and return.
+
+ ; To get to the saved flags, we need to skip the
+ ; return address (4 bytes), saved DS (2 bytes), and
+ ; saved registers (8 * 4 bytes)
+FLG_OFS equ 4 + 2 + 8 * 4
+
+ or word ptr [bp + FLG_OFS], FLAG_CF
+ jmp exit
+
+ ; Screen switching is not disabled; clear carry flag,
+ ; process the screen switch notification, and return.
+dispatch:
+ and word ptr [bp + FLG_OFS], NOT FLAG_CF
+ and bx, 2 ; Bit 1 of the subfunction
+ call dsp_tbl[bx] ; Call handler in C
+
+exit:
+ popad ; Restore and return
+ pop ds
+ iret
+
+SWHook_ endp
+
+
+_TEXT ends
+ end
diff --git a/tools/copyinf.c b/tools/copyinf.c
new file mode 100644
index 0000000..0dfb125
--- /dev/null
+++ b/tools/copyinf.c
@@ -0,0 +1,208 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define MAX_SECTION 128
+
+#define MAX_LINE 2048
+static char linebuf[MAX_LINE];
+
+int read_line(FILE *fr)
+{
+ int i = 0;
+ int c;
+ for(;;)
+ {
+ c = fgetc(fr);
+ switch(c)
+ {
+ case '\r':
+ break;
+ case '\n':
+ case EOF:
+ linebuf[i] = '\0';
+ break;
+ default:
+ if(i < MAX_LINE-1)
+ {
+ linebuf[i] = c;
+ i++;
+ }
+ break;
+ }
+
+ if(c == '\n') break;
+ if(c == EOF)
+ {
+ if(i == 0) return 0;
+ }
+ }
+
+ return 1;
+}
+
+void put_line(FILE *fw)
+{
+ size_t s = strlen(linebuf);
+ fwrite(linebuf, 1, s, fw);
+ fputc('\r', fw);
+ fputc('\n', fw);
+}
+
+void help(const char *progname)
+{
+ printf("%s [options] <source inf> <dest. inf> [enabled-section-1, [enable-section-2, [...]]]\n"
+ "options:\n"
+ "\t--softgpu\n"
+ "\t--build <num>\n"
+ "\t--day <num>\n"
+ "\t--month <num>\n"
+ "\t--year <num>\n\n",
+ progname);
+}
+
+int main(int argc, char **argv)
+{
+ int i = 0;
+ char **sections = calloc(argc, sizeof(char**));
+ int sections_count = 0;
+ char *src = NULL;
+ char *dst = NULL;
+ int softgpu = 0;
+ int build = 0;
+ int day;
+ int month;
+ int year;
+ int print_help = 0;
+ char section_test[MAX_SECTION+3];
+
+ time_t atime;
+ struct tm *gmt;
+
+ time(&atime);
+ gmt = gmtime(&atime);
+
+ day = gmt->tm_mday;
+ month = gmt->tm_mon + 1;
+ year = gmt->tm_year + 1900;
+
+ for(i = 1; i < argc; i++)
+ {
+ if(strcmp(argv[i], "--help") == 0)
+ {
+ print_help = 1;
+ }
+ else if(strcmp(argv[i], "--softgpu") == 0)
+ {
+ softgpu = 1;
+ }
+ else if(strcmp(argv[i], "--build") == 0)
+ {
+ if(i+1 < argc)
+ {
+ build = atoi(argv[i+1]);
+ i++;
+ }
+ }
+ else if(strcmp(argv[i], "--day") == 0)
+ {
+ if(i+1 < argc)
+ {
+ day = atoi(argv[i+1]);
+ i++;
+ }
+ }
+ else if(strcmp(argv[i], "--month") == 0)
+ {
+ if(i+1 < argc)
+ {
+ month = atoi(argv[i+1]);
+ i++;
+ }
+ }
+ else if(strcmp(argv[i], "--year") == 0)
+ {
+ if(i+1 < argc)
+ {
+ year = atoi(argv[i+1]);
+ i++;
+ }
+ }
+ else
+ {
+ if(src == NULL)
+ {
+ src = argv[i];
+ }
+ else if(dst == NULL)
+ {
+ dst = argv[i];
+ }
+ else
+ {
+ sections[sections_count] = argv[i];
+ sections_count++;
+ }
+ }
+ }
+
+ if(print_help)
+ {
+ help(argv[0]);
+ return 0;
+ }
+
+ if(dst == NULL)
+ {
+ printf("source and destination are required!\n\n");
+ help(argv[0]);
+ return 1;
+ }
+
+ FILE *out = NULL;
+ FILE *in = fopen(src, "rb");
+ if(in)
+ {
+ out = fopen(dst, "wb");
+ if(out)
+ {
+ while(read_line(in))
+ {
+ if(strstr(linebuf, "DriverVer=") == linebuf)
+ {
+ sprintf(linebuf, "DriverVer=%02d/%02d/%04d, %d.%d.0.%d", month, day, year, softgpu+1, year, build);
+ }
+ else
+ {
+ for(i = 0; i < sections_count; i++)
+ {
+ sprintf(section_test, ";%s:", sections[i]);
+
+ if(strstr(linebuf, section_test) == linebuf)
+ {
+ size_t lb_len = strlen(linebuf);
+ size_t s_len = strlen(section_test);
+
+ memmove(linebuf, linebuf+s_len, lb_len-s_len+1);
+ }
+ }
+ }
+
+ put_line(out);
+ }
+ }
+ else
+ {
+ fprintf(stderr, "Failed to open output: %s\n", dst);
+ }
+
+ fclose(in);
+ }
+ else
+ {
+ fprintf(stderr, "Failed to open input: %s\n", src);
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/types16.h b/types16.h
new file mode 100644
index 0000000..62a4092
--- /dev/null
+++ b/types16.h
@@ -0,0 +1,40 @@
+#ifndef __TYPES16_H_INCLUDED__
+#define __TYPES16_H_INCLUDED__
+
+#ifndef VXD32
+/* 16bit */
+typedef long int32;
+typedef unsigned long uint32;
+
+typedef int int16;
+typedef unsigned int uint16;
+
+typedef signed char int8;
+typedef unsigned char uint8;
+
+#define fastcall
+
+#else
+/* 32bit */
+typedef long int32;
+typedef unsigned long uint32;
+
+typedef short int16;
+typedef unsigned short uint16;
+
+typedef signed char int8;
+typedef unsigned char uint8;
+
+#endif
+
+typedef int Bool;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#endif /* __TYPES16_H_INCLUDED__ */
diff --git a/version.h b/version.h
new file mode 100644
index 0000000..f135e2f
--- /dev/null
+++ b/version.h
@@ -0,0 +1,34 @@
+#ifndef __VERSION_H__INCLUDED__
+#define __VERSION_H__INCLUDED__
+
+#define DRV_STR_(x) #x
+#define DRV_STR(x) DRV_STR_(x)
+
+/* DRV, VXD and DLL have to have the same */
+#define DRV_API_LEVEL 20230326UL
+
+/* on binaries equals 1 and for INF is 1 = separate driver, 2 = softgpu pack */
+#define DRV_VER_MAJOR 1
+
+/* the YEAR */
+#define DRV_VER_MINOR 2023
+
+/* build version is deducted fom GIT */
+#define DRV_VER_BUILD_FAILBACK 1
+
+#ifndef DRV_VER_BUILD
+#define DRV_VER_BUILD DRV_VER_BUILD_FAILBACK
+#endif
+
+#define DRV_VER_STR_BUILD(_ma, _mi, _pa, _bd) \
+ _ma "." _mi "." _pa "." _bd
+
+#define DRV_VER_STR DRV_VER_STR_BUILD( \
+ DRV_STR(DRV_VER_MAJOR), \
+ DRV_STR(DRV_VER_MINOR), \
+ DRV_STR(0), \
+ DRV_STR(DRV_VER_BUILD))
+
+#define DRV_VER_NUM DRV_VER_MAJOR,DRV_VER_MINOR,0,DRV_VER_BUILD
+
+#endif
diff --git a/vmdisp9x.inf b/vmdisp9x.inf
new file mode 100644
index 0000000..cca3431
--- /dev/null
+++ b/vmdisp9x.inf
@@ -0,0 +1,196 @@
+;
+; INF file for VirtualBox VGA Win9x display driver
+; VirtualBox SVGA Win9x display driver
+; VMWare SVGA-II Win9x display driver
+; Copyright 2012-2022, The OS/2 Museum
+; 2023, Jaroslav Hensl
+
+[version]
+DriverVer=01/01/2023, 1.2023.0.0
+Class=DISPLAY
+signature="$CHICAGO$"
+Provider=%Mfg%
+
+[DestinationDirs]
+DefaultDestDir=11 ; LDID_SYS
+VBox.Copy=11
+VMSvga.Copy=11
+DX.Copy=11
+Voodoo.Copy=11
+DX.CopyBackup=10,SYSBCKUP
+
+[SourceDisksNames]
+; BOXV9X is the driver disk volume label
+1="Virtual Display Driver for Win9x Disk",,0
+
+[SourceDisksFiles]
+boxvmini.drv=1
+vmwsmini.drv=1
+vmwsmini.vxd=1
+;mesa:mesa3d.dll=1
+;mesa:vmwsgl32.dll=1
+;openglide:glide2x.dll=1
+;openglide:glide3x.dll=1
+;openglide:wined3d.dll=1
+;wined3d:dwine.dll=1
+;wined3d:ddraw.dll=1
+;wined3d:ddrawme.dll=1
+;wined3d:d3d8.dll=1
+;wined3d:d3d9.dll=1
+;3dfx:3dfxSpl2.dll=1,vgw9x
+;3dfx:3dfxSpl3.dll=1,vgw9x
+;wined3d:ddr95.dll=1,dx
+;wined3d:ddr98.dll=1,dx
+
+[Manufacturer]
+%Mfg%=Mfg.VM
+
+[Mfg.VM]
+%VBoxVideoVGA.DeviceDesc%=VBox, PCI\VEN_80EE&DEV_BEEF&SUBSYS_00000000
+%VBoxVideoSVGA.DeviceDesc%=VBoxSvga, PCI\VEN_80EE&DEV_BEEF&SUBSYS_040515AD
+%VBoxVideoVM.DeviceDesc%=VMSvga, PCI\VEN_15AD&DEV_0405&SUBSYS_040515AD
+
+[VBox]
+CopyFiles=VBox.Copy,Dx.Copy,DX.CopyBackup,Voodoo.Copy
+DelReg=VM.DelReg
+AddReg=VBox.AddReg,VM.AddReg,DX.addReg
+
+[VBoxSvga]
+CopyFiles=VMSvga.Copy,Dx.Copy,DX.CopyBackup,Voodoo.Copy
+DelReg=VM.DelReg
+AddReg=VMSvga.AddReg,VM.AddReg,DX.addReg
+
+[VMSvga]
+CopyFiles=VMSvga.Copy,Dx.Copy,DX.CopyBackup,Voodoo.Copy
+DelReg=VM.DelReg
+AddReg=VMSvga.AddReg,VM.AddReg,DX.addReg
+
+[VBox.Copy]
+boxvmini.drv,,,0x00000004
+;mesa:mesa3d.dll,,,0x00000004
+
+[VMSvga.Copy]
+vmwsmini.drv,,,0x00000004
+vmwsmini.vxd,,,0x00000004
+;mesa:vmwsgl32.dll,,,0x00000004
+;mesa:mesa3d.dll,,,0x00000004
+
+[Voodoo.Copy]
+;3dfx:3dfxspl2.dll,,,0x00000010
+;3dfx:3dfxspl3.dll,,,0x00000010
+;openglide:glide2x.dll,,,0x00000004
+;openglide:glide3x.dll,,,0x00000004
+
+[DX.Copy]
+;wined3d:wined3d.dll,,,0x00000004
+;wined3d:dwine.dll,,,0x00000004
+;wined3d:ddraw.dll,,,0x00000004
+;wined3d:ddrawme.dll,,,0x00000004
+;wined3d:d3d8.dll,,,0x00000004
+;wined3d:d3d9.dll,,,0x00000004
+;wined3d:ddr95.dll,,,0x00000004
+;wined3d:ddr98.dll,,,0x00000004
+
+[DX.CopyBackup]
+;wined3d:ddraw.dll,,,0x00000004
+;wined3d:d3d8.dll,,,0x00000004
+;wined3d:d3d9.dll,,,0x00000004
+
+[VBox.AddReg]
+HKR,DEFAULT,drv,,boxvmini.drv
+;HKR,DEFAULT,minivdd,,boxvmini.vxd
+
+[VMSvga.AddReg]
+HKR,DEFAULT,drv,,vmwsmini.drv
+HKR,DEFAULT,minivdd,,vmwsmini.vxd
+
+[VM.DelReg]
+HKR,,Ver
+HKR,,DevLoader
+HKR,DEFAULT
+HKR,MODES
+HKR,CURRENT
+HKLM,Software\Microsoft\Windows\CurrentVersion\OpenGLdrivers,SOFTWARE
+HKLM,Software\Microsoft\Windows\CurrentVersion\OpenGLdrivers,VMWSVGA
+
+[VM.AddReg]
+HKR,,Ver,,4.0
+HKR,,DevLoader,,*vdd
+HKR,DEFAULT,Mode,,"8,640,480"
+HKR,DEFAULT,vdd,,"*vdd,*vflatd"
+;HKR,DEFAULT,carddvdd,,cardsamp.vxd
+HKR,DEFAULT,RefreshRate,,-1
+HKR,DEFAULT,DDC,,1
+HKR,DEFAULT,ExtModeSwitch,,0
+HKR,"MODES\4\640,480",drv,,vga.drv
+HKR,"MODES\4\640,480",vdd,,*vdd
+HKR,"MODES\4\800,600",drv,,supervga.drv
+HKR,"MODES\4\800,600",vdd,,*vdd
+HKR,"MODES\8\640,480"
+HKR,"MODES\8\800,600"
+HKR,"MODES\8\1024,768"
+HKR,"MODES\8\1152,864"
+HKR,"MODES\8\1280,720"
+HKR,"MODES\8\1280,800"
+HKR,"MODES\8\1280,960"
+HKR,"MODES\8\1280,1024"
+HKR,"MODES\8\1400,1050"
+HKR,"MODES\8\1600,1200"
+HKR,"MODES\8\1600,900"
+HKR,"MODES\8\1680,1050"
+HKR,"MODES\8\1920,1080"
+HKR,"MODES\8\1920,1200"
+HKR,"MODES\16\640,480"
+HKR,"MODES\16\800,600"
+HKR,"MODES\16\1024,768"
+HKR,"MODES\16\1152,864"
+HKR,"MODES\16\1280,720"
+HKR,"MODES\16\1280,800"
+HKR,"MODES\16\1280,960"
+HKR,"MODES\16\1280,1024"
+HKR,"MODES\16\1400,1050"
+HKR,"MODES\16\1600,900"
+HKR,"MODES\16\1600,1200"
+HKR,"MODES\16\1680,1050"
+HKR,"MODES\16\1920,1080"
+HKR,"MODES\16\1920,1200"
+HKR,"MODES\24\640,480"
+HKR,"MODES\24\800,600"
+HKR,"MODES\24\1024,768"
+HKR,"MODES\24\1152,864"
+HKR,"MODES\24\1280,720"
+HKR,"MODES\24\1280,800"
+HKR,"MODES\24\1280,960"
+HKR,"MODES\24\1280,1024"
+HKR,"MODES\24\1400,1050"
+HKR,"MODES\24\1600,900"
+HKR,"MODES\24\1600,1200"
+HKR,"MODES\24\1680,1050"
+HKR,"MODES\24\1920,1080"
+HKR,"MODES\24\1920,1200"
+HKR,"MODES\32\640,480"
+HKR,"MODES\32\800,600"
+HKR,"MODES\32\1024,768"
+HKR,"MODES\32\1152,864"
+HKR,"MODES\32\1280,720"
+HKR,"MODES\32\1280,800"
+HKR,"MODES\32\1280,960"
+HKR,"MODES\32\1280,1024"
+HKR,"MODES\32\1400,1050"
+HKR,"MODES\32\1600,900"
+HKR,"MODES\32\1600,1200"
+HKR,"MODES\32\1680,1050"
+HKR,"MODES\32\1920,1080"
+HKR,"MODES\32\1920,1200"
+;mesa:HKLM,Software\Microsoft\Windows\CurrentVersion\OpenGLdrivers,SOFTWARE,2,"mesa3d.dll"
+;mesa:HKLM,Software\Microsoft\Windows\CurrentVersion\OpenGLdrivers,VMWSVGA,2,"vmwsgl32.dll"
+;mesa:HKLM,Software\Mesa3D\global,LP_NATIVE_VECTOR_WIDTH,,128
+
+[DX.addReg]
+;wined3d:HKLM,System\CurrentControlSet\Control\SessionManager\KnownDLLs,DDRAW,2,"ddrawme.dll"
+
+[Strings]
+Mfg="VirtualBox"
+VBoxVideoVGA.DeviceDesc="VBox VGA PCI Adapter"
+VBoxVideoSVGA.DeviceDesc="VBox SVGA PCI Adapter"
+VBoxVideoVM.DeviceDesc="VMWare SVGA-II PCI Adapter"
diff --git a/vmm.h b/vmm.h
new file mode 100644
index 0000000..72bab3a
--- /dev/null
+++ b/vmm.h
@@ -0,0 +1,704 @@
+/*****************************************************************************
+
+Copyright (c) 2023 Jaroslav Hensl <emulator@emulace.cz>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/**
+ * This is attempt to port VMM/VXD api to OPEN WATCOM, generaly this file
+ * is fuzzy of my own macros and MSVC H header form DDK98 and H header from
+ * VMM.H from tutorial sample by Bryan A. Woodruff
+ *
+ **/
+#ifndef __VMM_H__INCLUDED__
+#define __VMM_H__INCLUDED__
+
+/* MS types */
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef unsigned long ULONG;
+typedef void * PVOID;
+typedef char * PSTR;
+
+#pragma pack(push)
+#pragma pack(1)
+typedef struct tagVxD_Desc_Block
+{
+ DWORD DDB_Next ; // VMM reserved field
+ WORD DDB_SDK_Version ; // VMM reserved field
+ WORD DDB_Req_Device_Number ; // Required device number
+ BYTE DDB_Dev_Major_Version ; // Major device number
+ BYTE DDB_Dev_Minor_Version ; // Minor device number
+ WORD DDB_Flags ; // Flags for init calls complete
+ BYTE DDB_Name[ 8 ] ; // Device name
+ DWORD DDB_Init_Order ; // Initialization Order
+ DWORD DDB_Control_Proc ; // Offset of control procedure
+ DWORD DDB_V86_API_Proc ; // Offset of API procedure
+ DWORD DDB_PM_API_Proc ; // Offset of API procedure
+ DWORD DDB_V86_API_CSIP ; // CS:IP of API entry point
+ DWORD DDB_PM_API_CSIP ; // CS:IP of API entry point
+ DWORD DDB_Reference_Data ; // Reference data from real mode
+ DWORD DDB_Service_Table_Ptr ; // Pointer to service table
+ DWORD DDB_Service_Table_Size ; // Number of services
+ DWORD DDB_Win32_Service_Table ;
+ DWORD DDB_Prev ;
+ DWORD DDB_Size;
+ DWORD DDB_Reserved1;
+ DWORD DDB_Reserved2;
+ DWORD DDB_Reserved3;
+} DDB ;
+#pragma pack(pop)
+
+#define DDK_VERSION 0x30A
+//#define DDK_VERSION 0x400
+//#define DDK_VERSION 0x40A
+// version 3.10 is required or Windows 95 can't load VXD
+
+#define UNDEFINED_DEVICE_ID 0x00000
+#define VMM_DEVICE_ID 0x00001 // USED FOR DYNALINK TABLE
+#define DEBUG_DEVICE_ID 0x00002
+#define VPICD_DEVICE_ID 0x00003
+#define VDMAD_DEVICE_ID 0x00004
+#define VTD_DEVICE_ID 0x00005
+#define V86MMGR_DEVICE_ID 0x00006
+#define PAGESWAP_DEVICE_ID 0x00007
+#define PARITY_DEVICE_ID 0x00008
+#define REBOOT_DEVICE_ID 0x00009
+#define VDD_DEVICE_ID 0x0000A
+#define VSD_DEVICE_ID 0x0000B
+#define VMD_DEVICE_ID 0x0000C
+#define VKD_DEVICE_ID 0x0000D
+#define VCD_DEVICE_ID 0x0000E
+#define VPD_DEVICE_ID 0x0000F
+#define BLOCKDEV_DEVICE_ID 0x00010
+#define VMCPD_DEVICE_ID 0x00011
+#define EBIOS_DEVICE_ID 0x00012
+#define BIOSXLAT_DEVICE_ID 0x00013
+#define VNETBIOS_DEVICE_ID 0x00014
+#define DOSMGR_DEVICE_ID 0x00015
+#define WINLOAD_DEVICE_ID 0x00016
+#define SHELL_DEVICE_ID 0x00017
+#define VMPOLL_DEVICE_ID 0x00018
+#define VPROD_DEVICE_ID 0x00019
+#define DOSNET_DEVICE_ID 0x0001A
+#define VFD_DEVICE_ID 0x0001B
+#define VDD2_DEVICE_ID 0x0001C // SECONDARY DISPLAY ADAPTER
+#define WINDEBUG_DEVICE_ID 0x0001D
+#define TSRLOAD_DEVICE_ID 0x0001E // TSR INSTANCE UTILITY ID
+#define BIOSHOOK_DEVICE_ID 0x0001F // BIOS INTERRUPT HOOKER VXD
+#define INT13_DEVICE_ID 0x00020
+#define PAGEFILE_DEVICE_ID 0x00021 // PAGING FILE DEVICE
+#define SCSI_DEVICE_ID 0x00022 // SCSI DEVICE
+#define MCA_POS_DEVICE_ID 0x00023 // MCA_POS DEVICE
+#define SCSIFD_DEVICE_ID 0x00024 // SCSI FASTDISK DEVICE
+#define VPEND_DEVICE_ID 0x00025 // PEN DEVICE
+#define APM_DEVICE_ID 0x00026 // POWER MANAGEMENT DEVICE
+
+#define VMM_Init_Order 0x000000000
+#define APM_Init_Order 0x001000000
+#define Debug_Init_Order 0x004000000
+#define BiosHook_Init_Order 0x006000000
+#define VPROD_Init_Order 0x008000000
+#define VPICD_Init_Order 0x00C000000
+#define VTD_Init_Order 0x014000000
+#define PageFile_Init_Order 0x018000000
+#define PageSwap_Init_Order 0x01C000000
+#define Parity_Init_Order 0x020000000
+#define Reboot_Init_Order 0x024000000
+#define EBIOS_Init_Order 0x026000000
+#define VDD_Init_Order 0x028000000
+#define VSD_Init_Order 0x02C000000
+#define VCD_Init_Order 0x030000000
+#define VMD_Init_Order 0x034000000
+#define VKD_Init_Order 0x038000000
+#define VPD_Init_Order 0x03C000000
+#define BlockDev_Init_Order 0x040000000
+#define MCA_POS_Init_Order 0x041000000
+#define SCSIFD_Init_Order 0x041400000
+#define SCSIMaster_Init_Order 0x041800000
+#define Int13_Init_Order 0x042000000
+#define VFD_Init_Order 0x044000000
+#define VMCPD_Init_Order 0x048000000
+#define BIOSXlat_Init_Order 0x050000000
+#define VNETBIOS_Init_Order 0x054000000
+#define DOSMGR_Init_Order 0x058000000
+#define DOSNET_Init_Order 0x05C000000
+#define WINLOAD_Init_Order 0x060000000
+#define VMPoll_Init_Order 0x064000000
+
+#define Undefined_Init_Order 0x080000000
+
+#define WINDEBUG_Init_Order 0x081000000
+#define VDMAD_Init_Order 0x090000000
+#define V86MMGR_Init_Order 0x0A0000000
+
+//----------------------------------------------------------------------------
+//
+// System control call messages
+//
+//----------------------------------------------------------------------------
+
+#define Sys_Critical_Init 0x0000
+#define Device_Init 0x0001
+#define Init_Complete 0x0002
+#define Sys_VM_Init 0x0003
+#define Sys_VM_Terminate 0x0004
+#define System_Exit 0x0005
+#define Sys_Critical_Exit 0x0006
+#define Create_VM 0x0007
+#define VM_Critical_Init 0x0008
+#define VM_Init 0x0009
+#define VM_Terminate 0x000A
+#define VM_Not_Executable 0x000B
+#define Destroy_VM 0x000C
+#define VM_Suspend 0x000D
+#define VM_Resume 0x000E
+#define Set_Device_Focus 0x000F
+#define Begin_Message_Mode 0x0010
+#define End_Message_Mode 0x0011
+
+#define Reboot_Processor 0x0012
+#define Query_Destroy 0x0013
+#define Debug_Query 0x0014
+
+#define Begin_PM_App 0x0015
+
+#define BPA_32_Bit 0x0001
+#define BPA_32_Bit_Flag 0x0001
+
+#define End_PM_App 0x0016
+
+#define Device_Reboot_Notify 0x0017
+#define Crit_Reboot_Notify 0x0018
+
+#define Close_VM_Notify 0x0019
+
+#define CVNF_Crit_Close 0x0001
+#define CNVF_Crit_Close_Bit 0x0000
+
+#define Power_Event 0x001A
+
+
+/*
+ * Macro to call VXD service
+ * @param _vxd: VXD name (numeric id must be defined as _vxd ## _DEVICE_ID)
+ * @param _service: service name (numeric order must be defined as _vxd ## __ ## _service)
+ */
+#define VxDCall(_vxd, _service) \
+ _asm int 20h \
+ _asm dw (_vxd ## __ ## _service) \
+ _asm dw (_vxd ## _DEVICE_ID)
+
+
+#define VxDJmp(_vxd, _service) \
+ _asm int 20h \
+ _asm dw 0x8000 + (_vxd ## __ ## _service) \
+ _asm dw (_vxd ## _DEVICE_ID)
+
+/*
+ * Macro to VMM call
+ * shortcut to VXDCall(VMM, _service_)
+ */
+#define VMMCall(_service) VxDCall(VMM, _service)
+
+#define VMMJmp(_service) VxDJmp(VMM, _service)
+
+/*
+ * WATCOM not supporting enum labels in inline assembly and
+ * C macro expansions, so service IDs needs to be manually
+ * defined as numbers
+ */
+
+#define VMM__Get_VMM_Version 0
+#define VMM__Get_Cur_VM_Handle 1
+#define VMM__Test_Cur_VM_Handle 2
+#define VMM__Get_Sys_VM_Handle 3
+#define VMM__Test_Sys_VM_Handle 4
+#define VMM__Validate_VM_Handle 5
+
+#define VMM__Get_VMM_Reenter_Count 6
+#define VMM__Begin_Reentrant_Execution 7
+#define VMM__End_Reentrant_Execution 8
+
+#define VMM__Install_V86_Break_Point 9
+#define VMM__Remove_V86_Break_Point 10
+#define VMM__Allocate_V86_Call_Back 11
+#define VMM__Allocate_PM_Call_Back 12
+
+#define VMM__Call_When_VM_Returns 13
+
+#define VMM__Schedule_Global_Event 14
+#define VMM__Schedule_VM_Event 15
+#define VMM__Call_Global_Event 16
+#define VMM__Call_VM_Event 17
+#define VMM__Cancel_Global_Event 18
+#define VMM__Cancel_VM_Event 19
+#define VMM__Call_Priority_VM_Event 20
+#define VMM__Cancel_Priority_VM_Event 21
+
+#define VMM__Get_NMI_Handler_Addr 22
+#define VMM__Set_NMI_Handler_Addr 23
+#define VMM__Hook_NMI_Event 24
+
+#define VMM__Call_When_VM_Ints_Enabled 25
+#define VMM__Enable_VM_Ints 26
+#define VMM__Disable_VM_Ints 27
+
+#define VMM__Map_Flat 28
+#define VMM__Map_Lin_To_VM_Addr 29
+
+// Scheduler services
+
+#define VMM__Adjust_Exec_Priority 30
+#define VMM__Begin_Critical_Section 31
+#define VMM__End_Critical_Section 32
+#define VMM__End_Crit_And_Suspend 33
+#define VMM__Claim_Critical_Section 34
+#define VMM__Release_Critical_Section 35
+#define VMM__Call_When_Not_Critical 36
+#define VMM__Create_Semaphore 37
+#define VMM__Destroy_Semaphore 38
+#define VMM__Wait_Semaphore 39
+#define VMM__Signal_Semaphore 40
+#define VMM__Get_Crit_Section_Status 41
+#define VMM__Call_When_Task_Switched 42
+#define VMM__Suspend_VM 43
+#define VMM__Resume_VM 44
+#define VMM__No_Fail_Resume_VM 45
+#define VMM__Nuke_VM 46
+#define VMM__Crash_Cur_VM 47
+
+#define VMM__Get_Execution_Focus 48
+#define VMM__Set_Execution_Focus 49
+#define VMM__Get_Time_Slice_Priority 50
+#define VMM__Set_Time_Slice_Priority 51
+#define VMM__Get_Time_Slice_Granularity 52
+#define VMM__Set_Time_Slice_Granularity 53
+#define VMM__Get_Time_Slice_Info 54
+#define VMM__Adjust_Execution_Time 55
+#define VMM__Release_Time_Slice 56
+#define VMM__Wake_Up_VM 57
+#define VMM__Call_When_Idle 58
+
+#define VMM__Get_Next_VM_Handle 59
+
+// Time-out and system timer services
+
+#define VMM__Set_Global_Time_Out 60
+#define VMM__Set_VM_Time_Out 61
+#define VMM__Cancel_Time_Out 62
+#define VMM__Get_System_Time 63
+#define VMM__Get_VM_Exec_Time 64
+
+#define VMM__Hook_V86_Int_Chain 65
+#define VMM__Get_V86_Int_Vector 66
+#define VMM__Set_V86_Int_Vector 67
+#define VMM__Get_PM_Int_Vector 68
+#define VMM__Set_PM_Int_Vector 69
+
+#define VMM__Simulate_Int 70
+#define VMM__Simulate_Iret 71
+#define VMM__Simulate_Far_Call 72
+#define VMM__Simulate_Far_Jmp 73
+#define VMM__Simulate_Far_Ret 74
+#define VMM__Simulate_Far_Ret_N 75
+#define VMM__Build_Int_Stack_Frame 76
+
+#define VMM__Simulate_Push 77
+#define VMM__Simulate_Pop 78
+
+// Heap Manager
+
+#define VMM___HeapAllocate 79
+#define VMM___HeapReAllocate 80
+#define VMM___HeapFree 81
+#define VMM___HeapGetSize 82
+
+/*ENDMACROS*/
+
+/****************************************************
+ *
+ * Flags for heap allocator calls
+ *
+ * NOTE: HIGH 8 BITS (bits 24-31) are reserved
+ *
+ ***************************************************/
+
+#define HEAPZEROINIT 0x00000001
+#define HEAPZEROREINIT 0x00000002
+#define HEAPNOCOPY 0x00000004
+#define HEAPLOCKEDIFDP 0x00000100
+#define HEAPSWAP 0x00000200
+#define HEAPINIT 0x00000400
+#define HEAPCLEAN 0x00000800
+
+// Page Manager
+
+/*MACROS*/
+#define VMM___PageAllocate 83
+#define VMM___PageReAllocate 84
+#define VMM___PageFree 85
+#define VMM___PageLock 86
+#define VMM___PageUnLock 87
+#define VMM___PageGetSizeAddr 88
+#define VMM___PageGetAllocInfo 89
+#define VMM___GetFreePageCount 90
+#define VMM___GetSysPageCount 91
+#define VMM___GetVMPgCount 92
+#define VMM___MapIntoV86 93
+#define VMM___PhysIntoV86 94
+#define VMM___TestGlobalV86Mem 95
+#define VMM___ModifyPageBits 96
+#define VMM___CopyPageTable 97
+#define VMM___LinMapIntoV86 98
+#define VMM___LinPageLock 98
+#define VMM___LinPageUnLock 99
+#define VMM___SetResetV86Pageable 100
+#define VMM___GetV86PageableArray 101
+#define VMM___PageCheckLinRange 102
+#define VMM___PageOutDirtyPages 103
+#define VMM___PageDiscardPages 104
+/*ENDMACROS*/
+
+/****************************************************
+ *
+ * Flags for other page allocator calls
+ *
+ * NOTE: HIGH 8 BITS (bits 24-31) are reserved
+ *
+ ***************************************************/
+
+#define PAGEZEROINIT 0x00000001
+#define PAGEUSEALIGN 0x00000002
+#define PAGECONTIG 0x00000004
+#define PAGEFIXED 0x00000008
+#define PAGEDEBUGNULFAULT 0x00000010
+#define PAGEZEROREINIT 0x00000020
+#define PAGENOCOPY 0x00000040
+#define PAGELOCKED 0x00000080
+#define PAGELOCKEDIFDP 0x00000100
+#define PAGESETV86PAGEABLE 0x00000200
+#define PAGECLEARV86PAGEABLE 0x00000400
+#define PAGESETV86INTSLOCKED 0x00000800
+#define PAGECLEARV86INTSLOCKED 0x00001000
+#define PAGEMARKPAGEOUT 0x00002000
+#define PAGEPDPSETBASE 0x00004000
+#define PAGEPDPCLEARBASE 0x00008000
+#define PAGEDISCARD 0x00010000
+#define PAGEPDPQUERYDIRTY 0x00020000
+#define PAGEMAPFREEPHYSREG 0x00040000
+#define PAGENOMOVE 0x10000000
+#define PAGEMAPGLOBAL 0x40000000
+#define PAGEMARKDIRTY 0x80000000
+
+/****************************************************
+ *
+ * Flags for _PhysIntoV86,
+ * _MapIntoV86, and _LinMapIntoV86
+ *
+ ***************************************************/
+
+#define MAPV86_IGNOREWRAP 0x00000001
+
+
+// Informational services
+
+/*MACROS*/
+#define VMM___GetNulPageHandle 105
+#define VMM___GetFirstV86Page 106
+#define VMM___MapPhysToLinear 107
+#define VMM___GetAppFlatDSAlias 108
+#define VMM___SelectorMapFlat 109
+#define VMM___GetDemandPageInfo 110
+#define VMM___GetSetPageOutCount 111
+/*ENDMACROS*/
+
+/*
+ * Flags bits for _GetSetPageOutCount
+ */
+#define GSPOC_F_GET 0x00000001
+
+// Device VM page manager
+
+/*MACROS*/
+#define VMM__Hook_V86_Page 112
+#define VMM___Assign_Device_V86_Pages 113
+#define VMM___DeAssign_Device_V86_Pages 114
+#define VMM___Get_Device_V86_Pages_Array 115
+#define VMM__MMGR_SetNULPageAddr 116
+
+// GDT/LDT management
+
+#define VMM___Allocate_GDT_Selector 117
+#define VMM___Free_GDT_Selector 118
+#define VMM___Allocate_LDT_Selector 119
+#define VMM___Free_LDT_Selector 120
+#define VMM___BuildDescriptorDWORDs 121
+#define VMM___GetDescriptor 122
+#define VMM___SetDescriptor 123
+/*ENDMACROS*/
+
+/*
+* Flag equates for _Allocate_GDT_Selector
+*/
+#define ALLOCFROMEND 0x40000000
+
+
+/*
+ * Flag equates for _BuildDescriptorDWORDs
+ */
+#define BDDEXPLICITDPL 0x00000001
+
+/*
+ * Flag equates for _Allocate_LDT_Selector
+ */
+#define ALDTSPECSEL 0x00000001
+
+/*MACROS*/
+#define VMM___MMGR_Toggle_HMA 124
+/*ENDMACROS*/
+
+/*
+ * Flag equates for _MMGR_Toggle_HMA
+ */
+#define MMGRHMAPHYSICAL 0x00000001
+#define MMGRHMAENABLE 0x00000002
+#define MMGRHMADISABLE 0x00000004
+#define MMGRHMAQUERY 0x00000008
+
+/*MACROS*/
+#define VMM__Get_Fault_Hook_Addrs 125
+#define VMM__Hook_V86_Fault 126
+#define VMM__Hook_PM_Fault 127
+#define VMM__Hook_VMM_Fault 128
+#define VMM__Begin_Nest_V86_Exec 129
+#define VMM__Begin_Nest_Exec 130
+#define VMM__Exec_Int 131
+#define VMM__Resume_Exec 132
+#define VMM__End_Nest_Exec 133
+
+#define VMM__Allocate_PM_App_CB_Area 134
+#define VMM__Get_Cur_PM_App_CB 135
+#define VMM__Set_V86_Exec_Mode 136
+#define VMM__Set_PM_Exec_Mode 137
+
+#define VMM__Begin_Use_Locked_PM_Stack 138
+#define VMM__End_Use_Locked_PM_Stack 139
+
+#define VMM__Save_Client_State 140
+#define VMM__Restore_Client_State 141
+
+#define VMM__Exec_VxD_Int 142
+
+#define VMM__Hook_Device_Service 143
+#define VMM__Hook_Device_V86_API 144
+#define VMM__Hook_Device_PM_API 145
+
+#define VMM__System_Control 146
+// I/O and software interrupt hooks
+
+#define VMM__Simulate_IO 147
+#define VMM__Install_Mult_IO_Handlers 148
+#define VMM__Install_IO_Handler 149
+#define VMM__Enable_Global_Trapping 150
+#define VMM__Enable_Local_Trapping 151
+#define VMM__Disable_Global_Trapping 152
+#define VMM__Disable_Local_Trapping 153
+
+// Linked List Abstract Data Type Services
+
+#define VMM__List_Create 154
+#define VMM__List_Destroy 155
+#define VMM__List_Allocate 156
+#define VMM__List_Attach 157
+#define VMM__List_Attach_Tail 158
+#define VMM__List_Insert 159
+#define VMM__List_Remove 160
+#define VMM__List_Deallocate 161
+#define VMM__List_Get_First 162
+#define VMM__List_Get_Next 163
+#define VMM__List_Remove_First 164
+/*ENDMACROS*/
+
+/*
+ * Flags used by List_Create
+ */
+#define LF_ASYNC_BIT 0
+#define LF_ASYNC (1 << LF_ASYNC_BIT)
+#define LF_USE_HEAP_BIT 1
+#define LF_USE_HEAP (1 << LF_USE_HEAP_BIT)
+#define LF_ALLOC_ERROR_BIT 2
+#define LF_ALLOC_ERROR (1 << LF_ALLOC_ERROR_BIT)
+/*
+ * Swappable lists must use the heap.
+ */
+#define LF_SWAP (LF_USE_HEAP + (1 << 3))
+
+/******************************************************************************
+ * I N I T I A L I Z A T I O N P R O C E D U R E S
+ ******************************************************************************/
+
+// Instance data manager
+
+/*MACROS*/
+#define VMM___AddInstanceItem 165
+
+// System structure data manager
+
+#define VMM___Allocate_Device_CB_Area 166
+#define VMM___Allocate_Global_V86_Data_Area 167
+#define VMM___Allocate_Temp_V86_Data_Area 168
+#define VMM___Free_Temp_V86_Data_Area 169
+/*ENDMACROS*/
+
+#pragma pack(push)
+#pragma pack(1)
+typedef struct tagCRS_32
+{
+ DWORD Client_EDI ;
+ DWORD Client_ESI ;
+ DWORD Client_EBP ;
+ DWORD dwReserved_1 ; // ESP at pushall
+ DWORD Client_EBX ;
+ DWORD Client_EDX ;
+ DWORD Client_ECX ;
+ DWORD Client_EAX ;
+ DWORD Client_Error ; // DWORD error code
+ DWORD Client_EIP ;
+ WORD Client_CS ;
+ WORD wReserved_2 ; // (padding)
+ DWORD Client_EFlags ;
+ DWORD Client_ESP ;
+ WORD Client_SS ;
+ WORD wReserved_3 ; // (padding)
+ WORD Client_ES ;
+ WORD WReserved_4 ; // (padding)
+ WORD Client_DS ;
+ WORD wReserved_5 ; // (padding)
+ WORD Client_FS ;
+ WORD wReserved_6 ; // (padding)
+ WORD Client_GS ;
+ WORD wReserved_7 ; // (padding)
+
+ DWORD Client_Alt_EIP ;
+ WORD Client_Alt_CS ;
+ WORD wReserved_8 ; // (padding)
+ DWORD Client_Alt_EFlags ;
+ DWORD Client_Alt_ESP ;
+ WORD Client_Alt_SS ;
+ WORD wReserved_9 ; // (padding)
+ WORD Client_Alt_ES ;
+ WORD WReserved_10 ; // (padding)
+ WORD Client_Alt_DS ;
+ WORD wReserved_11 ; // (padding)
+ WORD Client_Alt_FS ;
+ WORD wReserved_12 ; // (padding)
+ WORD Client_Alt_GS ;
+ WORD wReserved_13 ; // (padding)
+
+} CRS_32, *PCRS_32;
+#pragma pack(pop)
+
+/******************************************************************************
+ * PAGE TABLE EQUATES
+ *****************************************************************************/
+
+#define P_SIZE 0x1000 /* page size */
+
+/******************************************************************************
+ *
+ * PAGE TABLE ENTRY BITS
+ *
+ *****************************************************************************/
+
+#define P_PRESBIT 0
+#define P_PRES (1 << P_PRESBIT)
+#define P_WRITEBIT 1
+#define P_WRITE (1 << P_WRITEBIT)
+#define P_USERBIT 2
+#define P_USER (1 << P_USERBIT)
+#define P_ACCBIT 5
+#define P_ACC (1 << P_ACCBIT)
+#define P_DIRTYBIT 6
+#define P_DIRTY (1 << P_DIRTYBIT)
+
+#define P_AVAIL (P_PRES+P_WRITE+P_USER) /* avail to user & present */
+
+/****************************************************
+ *
+ * Page types for page allocator calls
+ *
+ ***************************************************/
+
+#define PG_VM 0
+#define PG_SYS 1
+#define PG_RESERVED1 2
+#define PG_PRIVATE 3
+#define PG_RESERVED2 4
+#define PG_RELOCK 5 /* PRIVATE to MMGR */
+#define PG_INSTANCE 6
+#define PG_HOOKED 7
+#define PG_IGNORE 0xFFFFFFFF
+
+/****************************************************
+ *
+ * Definitions for the access byte in a descriptor
+ *
+ ***************************************************/
+
+/*
+ * Following fields are common to segment and control descriptors
+ */
+#define D_PRES 0x080 /* present in memory */
+#define D_NOTPRES 0 /* not present in memory */
+
+#define D_DPL0 0 /* Ring 0 */
+#define D_DPL1 0x020 /* Ring 1 */
+#define D_DPL2 0x040 /* Ring 2 */
+#define D_DPL3 0x060 /* Ring 3 */
+
+#define D_SEG 0x010 /* Segment descriptor */
+#define D_CTRL 0 /* Control descriptor */
+
+#define D_GRAN_BYTE 0x000 /* Segment length is byte granular */
+#define D_GRAN_PAGE 0x080 /* Segment length is page granular */
+#define D_DEF16 0x000 /* Default operation size is 16 bits */
+#define D_DEF32 0x040 /* Default operation size is 32 bits */
+
+
+/*
+ * Following fields are specific to segment descriptors
+ */
+#define D_CODE 0x08 /* code */
+#define D_DATA 0 /* data */
+
+#define D_X 0 /* if code, exec only */
+#define D_RX 0x02 /* if code, readable */
+#define D_C 0x04 /* if code, conforming */
+
+#define D_R 0 /* if data, read only */
+#define D_W 0x02 /* if data, writable */
+#define D_ED 0x04 /* if data, expand down */
+
+#define D_ACCESSED 1 /* segment accessed bit */
+
+
+#endif /* __VMM_H__INCLUDED__ */
diff --git a/vmware/pci.c b/vmware/pci.c
new file mode 100644
index 0000000..93647b4
--- /dev/null
+++ b/vmware/pci.c
@@ -0,0 +1,277 @@
+/* -*- Mode: C; c-basic-offset: 3 -*-
+ *
+ * pci.c - Simple PCI configuration interface. This implementation
+ * only supports type 1 accesses to configuration space,
+ * and it ignores the PCI BIOS.
+ *
+ * This file is part of Metalkit, a simple collection of modules for
+ * writing software that runs on the bare metal. Get the latest code
+ * at http://svn.navi.cx/misc/trunk/metalkit/
+ *
+ * Copyright (c) 2008-2009 Micah Dowty
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <stdlib.h>
+#include "svga_all.h"
+
+#ifdef VXD32
+#define IO_IN32
+#define IO_OUT32
+#define IO_OUT16
+#define IO_IN16
+#define IO_IN8
+#include "io32.h"
+#else
+#include "io.h"
+#endif
+
+/*
+ * There can be up to 256 PCI busses, but it takes a noticeable
+ * amount of time to scan that whole space. Limit the number of
+ * supported busses to something more reasonable...
+ */
+#define PCI_MAX_BUSSES 0x20
+
+#define PCI_REG_CONFIG_ADDRESS 0xCF8
+#define PCI_REG_CONFIG_DATA 0xCFC
+
+#ifndef VXD32
+#pragma code_seg( _INIT )
+#else
+#include "code32.h"
+#endif
+
+/*
+ * PCIConfigPackAddress --
+ *
+ * Pack a 32-bit CONFIG_ADDRESS value.
+ */
+
+static uint32
+PCIConfigPackAddress(const PCIAddress __far *addr, uint16 offset)
+{
+ const uint32 enableBit = 0x80000000UL;
+
+ return (((uint32)addr->bus << 16) |
+ ((uint32)addr->device << 11) |
+ ((uint32)addr->function << 8) |
+ offset | enableBit);
+}
+
+
+/*
+ * PCI_ConfigRead32 --
+ * PCI_ConfigRead16 --
+ * PCI_ConfigRead8 --
+ * PCI_ConfigWrite32 --
+ * PCI_ConfigWrite16 --
+ * PCI_ConfigWrite8 --
+ *
+ * Access a device's PCI configuration space, using configuration
+ * mechanism #1. All new machines should use method #1, method #2
+ * is for legacy compatibility.
+ *
+ * See http://www.osdev.org/wiki/PCI
+ */
+
+uint32
+PCI_ConfigRead32(const PCIAddress __far *addr, uint16 offset)
+{
+ outpd(PCI_REG_CONFIG_ADDRESS, PCIConfigPackAddress(addr, offset));
+ return inpd(PCI_REG_CONFIG_DATA);
+}
+
+uint16
+PCI_ConfigRead16(const PCIAddress __far *addr, uint16 offset)
+{
+ outpd(PCI_REG_CONFIG_ADDRESS, PCIConfigPackAddress(addr, offset));
+ return inpw(PCI_REG_CONFIG_DATA);
+}
+
+uint8
+PCI_ConfigRead8(const PCIAddress __far *addr, uint16 offset)
+{
+ outpd(PCI_REG_CONFIG_ADDRESS, PCIConfigPackAddress(addr, offset));
+ return inp(PCI_REG_CONFIG_DATA);
+}
+
+void
+PCI_ConfigWrite32(const PCIAddress __far *addr, uint16 offset, uint32 data)
+{
+ outpd(PCI_REG_CONFIG_ADDRESS, PCIConfigPackAddress(addr, offset));
+ outpd(PCI_REG_CONFIG_DATA, data);
+}
+
+void
+PCI_ConfigWrite16(const PCIAddress __far *addr, uint16 offset, uint16 data)
+{
+ outpd(PCI_REG_CONFIG_ADDRESS, PCIConfigPackAddress(addr, offset));
+ outpw(PCI_REG_CONFIG_DATA, data);
+}
+
+void
+PCI_ConfigWrite8(const PCIAddress __far *addr, uint16 offset, uint8 data)
+{
+ outpd(PCI_REG_CONFIG_ADDRESS, PCIConfigPackAddress(addr, offset));
+ outpd(PCI_REG_CONFIG_DATA, data);
+}
+
+
+/*
+ * PCI_ScanBus --
+ *
+ * Scan the PCI bus for devices. Before starting a scan,
+ * the caller should zero the PCIScanState structure.
+ * Every time this function is called, it returns the next
+ * device in sequence.
+ *
+ * Returns TRUE if a device was found, leaving that device's
+ * vendorId, productId, and address in 'state'.
+ *
+ * Returns FALSE if there are no more devices.
+ */
+
+Bool
+PCI_ScanBus(PCIScanState __far *state)
+{
+ PCIConfigSpace config;
+
+ for (;;) {
+ config.words[0] = PCI_ConfigRead32(&state->nextAddr, 0);
+
+ state->addr = state->nextAddr;
+
+ if (++state->nextAddr.function == 0x8) {
+ state->nextAddr.function = 0;
+ if (++state->nextAddr.device == 0x20) {
+ state->nextAddr.device = 0;
+ if (++state->nextAddr.bus == PCI_MAX_BUSSES) {
+ return FALSE;
+ }
+ }
+ }
+
+ if (config.words[0] != 0xFFFFFFFFUL) {
+ state->vendorId = config.vendorId;
+ state->deviceId = config.deviceId;
+ return TRUE;
+ }
+ }
+}
+
+
+/*
+ * PCI_FindDevice --
+ *
+ * Scan the PCI bus for a device with a specific vendor and device ID.
+ *
+ * On success, returns TRUE and puts the device address into 'addrOut'.
+ * If the device was not found, returns FALSE.
+ */
+
+Bool
+PCI_FindDevice(uint16 vendorId, uint16 deviceId, PCIAddress __far *addrOut)
+{
+ PCIScanState busScan = {0};
+
+ while (PCI_ScanBus(&busScan)) {
+ if (busScan.vendorId == vendorId && busScan.deviceId == deviceId) {
+ *addrOut = busScan.addr;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/*
+ * PCI_SetBAR --
+ *
+ * Set one of a device's Base Address Registers to the provided value.
+ */
+
+void
+PCI_SetBAR(const PCIAddress __far *addr, int index, uint32 value)
+{
+ // PCI_ConfigWrite32(addr, offsetof(PCIConfigSpace, BAR[index]), value);
+ PCI_ConfigWrite32(addr, 16+4*index, value);
+}
+
+
+/*
+ * PCI_GetBARAddr --
+ *
+ * Get the current address set in one of the device's Base Address Registers.
+ * We mask off the lower bits that are not part of the address. IO bars are
+ * 4 byte aligned so we mask lower 2 bits, and memory bars are 16-byte aligned
+ * so we mask the lower 4 bits.
+ */
+
+uint32
+PCI_GetBARAddr(const PCIAddress __far *addr, int index)
+{
+ // uint32 bar = PCI_ConfigRead32(addr, offsetof(PCIConfigSpace, BAR[index]));
+ uint32 bar = PCI_ConfigRead32(addr, 16+4*index);
+ uint32 mask = (bar & PCI_CONF_BAR_IO) ? 0x3 : 0xf;
+
+ return bar & ~mask;
+}
+
+uint32
+PCI_GetSubsystem(const PCIAddress __far *addr)
+{
+ uint32 subsys = PCI_ConfigRead32(addr, 44);
+
+ return subsys;
+}
+
+
+/*
+ * PCI_SetMemEnable --
+ *
+ * Enable or disable a device's memory and IO space. This must be
+ * called to enable a device's resources after setting all
+ * applicable BARs. Also enables/disables bus mastering.
+ */
+
+void
+PCI_SetMemEnable(const PCIAddress __far *addr, Bool enable)
+{
+ //uint16 command = PCI_ConfigRead16(addr, offsetof(PCIConfigSpace, command));
+ uint16 command = PCI_ConfigRead16(addr, 4);
+
+ /* Mem space enable, IO space enable, bus mastering. */
+ const uint16 flags = 0x0007;
+
+ if (enable) {
+ command |= flags;
+ } else {
+ command &= ~flags;
+ }
+
+ //PCI_ConfigWrite16(addr, offsetof(PCIConfigSpace, command), command);
+ PCI_ConfigWrite16(addr, 4, command);
+
+}
+
diff --git a/vmware/pci.h b/vmware/pci.h
new file mode 100644
index 0000000..080fc86
--- /dev/null
+++ b/vmware/pci.h
@@ -0,0 +1,101 @@
+/* -*- Mode: C; c-basic-offset: 3 -*-
+ *
+ * pci.h - Simple PCI configuration interface. This implementation
+ * only supports type 1 accesses to configuration space,
+ * and it ignores the PCI BIOS.
+ *
+ * This file is part of Metalkit, a simple collection of modules for
+ * writing software that runs on the bare metal. Get the latest code
+ * at http://svn.navi.cx/misc/trunk/metalkit/
+ *
+ * Copyright (c) 2008-2009 Micah Dowty
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __PCI_H__
+#define __PCI_H__
+
+#include "types16.h"
+
+#pragma pack(push)
+#pragma pack(1)
+typedef union PCIConfigSpace {
+ uint32 words[16];
+ struct { // offset
+ uint16 vendorId; // 0
+ uint16 deviceId; // 2
+ uint16 command; // 4
+ uint16 status; // 6
+ uint16 revisionId; // 8
+ uint8 subclass; // 10
+ uint8 classCode; // 11
+ uint8 cacheLineSize; // 12
+ uint8 latTimer; // 13
+ uint8 headerType; // 14
+ uint8 BIST; // 15
+ uint32 BAR[6]; // 16
+ uint32 cardbusCIS; // 40
+ uint16 subsysVendorId; // 44
+ uint16 subsysId; // 46
+ uint32 expansionRomAddr; // 48
+ uint32 reserved0; // 52
+ uint32 reserved1; // 56
+ uint8 intrLine; // 60
+ uint8 intrPin; // 61
+ uint8 minGrant; // 62
+ uint8 maxLatency; // 63
+ };
+} PCIConfigSpace;
+#pragma pack(pop)
+
+typedef struct PCIAddress {
+ uint8 bus, device, function, padding;
+} PCIAddress;
+
+typedef struct PCIScanState {
+ uint16 vendorId;
+ uint16 deviceId;
+ PCIAddress nextAddr;
+ PCIAddress addr;
+} PCIScanState;
+
+// BAR bits
+#define PCI_CONF_BAR_IO 0x01
+#define PCI_CONF_BAR_64BIT 0x04
+#define PCI_CONF_BAR_PREFETCH 0x08
+
+uint32 PCI_ConfigRead32(const PCIAddress __far *addr, uint16 offset);
+uint16 PCI_ConfigRead16(const PCIAddress __far *addr, uint16 offset);
+uint8 PCI_ConfigRead8(const PCIAddress __far *addr, uint16 offset);
+void PCI_ConfigWrite32(const PCIAddress __far *addr, uint16 offset, uint32 data);
+void PCI_ConfigWrite16(const PCIAddress __far *addr, uint16 offset, uint16 data);
+void PCI_ConfigWrite8(const PCIAddress __far *addr, uint16 offset, uint8 data);
+
+Bool PCI_ScanBus(PCIScanState __far *state);
+Bool PCI_FindDevice(uint16 vendorId, uint16 deviceId, PCIAddress __far *addrOut);
+void PCI_SetBAR(const PCIAddress __far *addr, int index, uint32 value);
+uint32 PCI_GetBARAddr(const PCIAddress __far *addr, int index);
+void PCI_SetMemEnable(const PCIAddress __far *addr, Bool enable);
+uint32 PCI_GetSubsystem(const PCIAddress __far *addr);
+
+#endif /* __PCI_H__ */
diff --git a/vmware/pci32.c b/vmware/pci32.c
new file mode 100644
index 0000000..cd00f19
--- /dev/null
+++ b/vmware/pci32.c
@@ -0,0 +1,2 @@
+#define VXD32
+#include "pci.c"
diff --git a/vmware/svga.c b/vmware/svga.c
new file mode 100644
index 0000000..76d69fb
--- /dev/null
+++ b/vmware/svga.c
@@ -0,0 +1,1971 @@
+/**********************************************************
+ * Copyright 2008-2009 VMware, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/*
+ * svga.c --
+ *
+ * This is a simple example driver for the VMware SVGA device.
+ * It handles initialization, register accesses, low-level
+ * command FIFO writes, and host/guest synchronization.
+ */
+
+//#include <string.h> /* include some basics like NULL */
+#include "winhack.h"
+
+#include "svga_all.h"
+#include "pci.h"
+
+#ifdef VXD32
+#define IO_IN32
+#define IO_OUT32
+#include "io32.h"
+#else
+#include "io.h"
+#endif
+
+#include "drvlib.h"
+
+#ifndef VXD32
+#include "dpmi.h"
+#endif
+
+#ifdef DBGPRINT
+void dbg_printf( const char *s, ... );
+#else
+#define dbg_printf(...)
+#endif
+
+#ifndef MIN
+#define MIN(a, b) (((a) > (b)) ? (b) : (a))
+#endif
+
+#ifndef MAX
+#define MAX(a, b) (((b) > (a)) ? (b) : (a))
+#endif
+
+#ifdef VXD32
+#include "code32.h"
+#endif
+
+
+SVGADevice gSVGA;
+
+static void SVGAFIFOFull(void);
+
+#ifndef REALLY_TINY
+static void SVGAInterruptHandler(int vector);
+#endif
+
+#ifdef REALLY_TINY
+# ifdef VXD32
+# define Console_Panic(x)
+# define SVGA_Panic(x)
+# else
+# define Console_Panic(x) dbg_printf("PANIC: %s\n", x)
+# define SVGA_Panic(x) dbg_printf("PANIC: %s\n", x)
+# endif
+#endif
+
+#ifndef VXD32
+#pragma code_seg( _INIT )
+#endif
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_Init --
+ *
+ * Initialize the global SVGA device. This locates it on the PCI bus,
+ * negotiates device version, and maps the command FIFO and framebuffer
+ * memory.
+ *
+ * Intr_Init() must have already been called. If the SVGA device
+ * supports interrupts, this will initalize them.
+ *
+ * Does not switch video modes.
+ *
+ * Results:
+ * void.
+ *
+ * Side effects:
+ * Steals various IOspace and memory regions.
+ * In this example code they're constant addresses, but in reality
+ * you'll need to negotiate these with the operating system.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+SVGA_Init(Bool enableFIFO)
+{
+ int vga_found = 0;
+
+ if (PCI_FindDevice(PCI_VENDOR_ID_VMWARE, PCI_DEVICE_ID_VMWARE_SVGA2,
+ &gSVGA.pciAddr)) {
+ gSVGA.vendorId = PCI_VENDOR_ID_VMWARE;
+ gSVGA.deviceId = PCI_DEVICE_ID_VMWARE_SVGA2;
+#ifndef VXD32
+ dbg_printf("PCI VMWare SVGA-II: %X:%X\n", gSVGA.vendorId, gSVGA.deviceId);
+#endif
+
+ vga_found = 1;
+ }
+
+ if (PCI_FindDevice(PCI_VENDOR_ID_INNOTEK, PCI_DEVICE_ID_VBOX_VGA, &gSVGA.pciAddr)) {
+ uint32 subsys = PCI_GetSubsystem(&gSVGA.pciAddr);
+ if(subsys == PCI_SUBCLASS_ID_SVGA2)
+ {
+ gSVGA.vendorId = PCI_VENDOR_ID_INNOTEK;
+ gSVGA.deviceId = PCI_DEVICE_ID_VBOX_VGA;
+#ifndef VXD32
+ dbg_printf("PCI VBox SVGA: %X:%X\n", gSVGA.vendorId, gSVGA.deviceId);
+#endif
+ vga_found = 1;
+ }
+ else
+ {
+#ifndef VXD32
+ dbg_printf("PCI VBox VGA, subclass %lX = this driver is not for it!\n", subsys);
+#endif
+ }
+ }
+
+ if(vga_found == 0)
+ {
+ Console_Panic("No VMware SVGA device found.");
+ return 1;
+ }
+
+ /*
+ * Use the default base address for each memory region.
+ * We must map at least ioBase before using ReadReg/WriteReg.
+ */
+
+ PCI_SetMemEnable(&gSVGA.pciAddr, TRUE);
+ if(gSVGA.deviceId == PCI_DEVICE_ID_VBOX_VGA) {
+ /* VBox SVGA have swapped IO and VRAM in PCI BAR */
+ gSVGA.fbMem = (void __far*) PCI_GetBARAddr(&gSVGA.pciAddr, 0);
+ gSVGA.ioBase = PCI_GetBARAddr(&gSVGA.pciAddr, 1);
+ } else {
+ gSVGA.ioBase = PCI_GetBARAddr(&gSVGA.pciAddr, 0);
+ gSVGA.fbMem = (void __far*) PCI_GetBARAddr(&gSVGA.pciAddr, 1);
+ }
+ gSVGA.fifoMem = (void __far*) PCI_GetBARAddr(&gSVGA.pciAddr, 2);
+
+#ifndef VXD32 /* version negotiation is done in PM16 driver, only get addresses here */
+ /*
+ * Version negotiation:
+ *
+ * 1. Write to SVGA_REG_ID the maximum ID supported by this driver.
+ * 2. Read from SVGA_REG_ID
+ * a. If we read back the same value, this ID is supported. We're done.
+ * b. If not, decrement the ID and repeat.
+ */
+
+ gSVGA.deviceVersionId = SVGA_ID_2;
+ do {
+ SVGA_WriteReg(SVGA_REG_ID, gSVGA.deviceVersionId);
+ if (SVGA_ReadReg(SVGA_REG_ID) == gSVGA.deviceVersionId) {
+ break;
+ } else {
+ gSVGA.deviceVersionId--;
+ }
+ } while (gSVGA.deviceVersionId >= SVGA_ID_0);
+
+ if (gSVGA.deviceVersionId < SVGA_ID_0) {
+ Console_Panic("Error negotiating SVGA device version.");
+ }
+#endif
+
+ /*
+ * We must determine the FIFO and FB size after version
+ * negotiation, since the default version (SVGA_ID_0)
+ * does not support the FIFO buffer at all.
+ */
+
+ gSVGA.vramSize = SVGA_ReadReg(SVGA_REG_VRAM_SIZE);
+ gSVGA.fbSize = SVGA_ReadReg(SVGA_REG_FB_SIZE);
+ gSVGA.fifoSize = SVGA_ReadReg(SVGA_REG_MEM_SIZE);
+
+ /*
+ * Sanity-check the FIFO and framebuffer sizes.
+ * These are arbitrary values.
+ */
+
+ if (gSVGA.fbSize < 0x100000) {
+ SVGA_Panic("FB size very small, probably incorrect.");
+ }
+ if (gSVGA.fifoSize < 0x20000) {
+ SVGA_Panic("FIFO size very small, probably incorrect.");
+ }
+
+ /*
+ * If the device is new enough to support capability flags, get the
+ * capabilities register.
+ */
+
+ if (gSVGA.deviceVersionId >= SVGA_ID_1) {
+ gSVGA.capabilities = SVGA_ReadReg(SVGA_REG_CAPABILITIES);
+ }
+
+ /*
+ * Optional interrupt initialization.
+ *
+ * This uses the default IRQ that was assigned to our
+ * device by the BIOS.
+ */
+
+#ifndef REALLY_TINY
+ if (gSVGA.capabilities & SVGA_CAP_IRQMASK) {
+ uint8 irq = PCI_ConfigRead8(&gSVGA.pciAddr, offsetof(PCIConfigSpace, intrLine));
+
+ /* Start out with all SVGA IRQs masked */
+ SVGA_WriteReg(SVGA_REG_IRQMASK, 0);
+
+ /* Clear all pending IRQs stored by the device */
+ IO_Out32(gSVGA.ioBase + SVGA_IRQSTATUS_PORT, 0xFF);
+
+ /* Clear all pending IRQs stored by us */
+ SVGA_ClearIRQ();
+
+ /* Enable the IRQ */
+ Intr_SetHandler(IRQ_VECTOR(irq), SVGAInterruptHandler);
+ Intr_SetMask(irq, TRUE);
+ }
+#endif
+ gSVGA.fifoLinear = 0;
+ gSVGA.fifoSel = 0;
+ gSVGA.fifoAct = 0;
+
+ if(enableFIFO)
+ {
+ SVGA_Enable();
+ }
+
+ return 0;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_Enable --
+ *
+ * Enable the SVGA device along with the SVGA FIFO.
+ *
+ * Results:
+ * void.
+ *
+ * Side effects:
+ * Initializes the command FIFO.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_Enable(void)
+{
+ /*
+ * Initialize the command FIFO. The beginning of FIFO memory is
+ * used for an additional set of registers, the "FIFO registers".
+ * These are higher-performance memory mapped registers which
+ * happen to live in the same space as the FIFO. The driver is
+ * responsible for allocating space for these registers, according
+ * to the maximum number of registers supported by this driver
+ * release.
+ */
+
+ gSVGA.fifoMem[SVGA_FIFO_MIN] = SVGA_FIFO_NUM_REGS * sizeof(uint32);
+ gSVGA.fifoMem[SVGA_FIFO_MAX] = gSVGA.fifoSize;
+ //gSVGA.fifoMem[SVGA_FIFO_MAX] = 0xFFFCUL - gSVGA.fifoMem[SVGA_FIFO_MIN];
+ gSVGA.fifoMem[SVGA_FIFO_NEXT_CMD] = gSVGA.fifoMem[SVGA_FIFO_MIN];
+ gSVGA.fifoMem[SVGA_FIFO_STOP] = gSVGA.fifoMem[SVGA_FIFO_MIN];
+
+ /*
+ * Prep work for 3D version negotiation. See SVGA3D_Init for
+ * details, but we have to give the host our 3D protocol version
+ * before enabling the FIFO.
+ */
+
+ if (SVGA_HasFIFOCap(SVGA_CAP_EXTENDED_FIFO) &&
+ SVGA_IsFIFORegValid(SVGA_FIFO_GUEST_3D_HWVERSION)) {
+
+ gSVGA.fifoMem[SVGA_FIFO_GUEST_3D_HWVERSION] = SVGA3D_HWVERSION_CURRENT;
+ }
+
+ /*
+ * Enable the SVGA device and FIFO.
+ */
+
+ SVGA_WriteReg(SVGA_REG_ENABLE, TRUE);
+ SVGA_WriteReg(SVGA_REG_CONFIG_DONE, TRUE);
+
+ /*
+ * Now that the FIFO is initialized, we can do an IRQ sanity check.
+ * This makes sure that the VM's chipset and our own IRQ code
+ * works. Better to find out now if something's wrong, than to
+ * deadlock later.
+ *
+ * This inserts a FIFO fence, does a legacy sync to drain the FIFO,
+ * then ensures that we received all applicable interrupts.
+ */
+
+#ifndef REALLY_TINY
+ if (gSVGA.capabilities & SVGA_CAP_IRQMASK) {
+
+ SVGA_WriteReg(SVGA_REG_IRQMASK, SVGA_IRQFLAG_ANY_FENCE);
+ SVGA_ClearIRQ();
+
+ SVGA_InsertFence();
+
+ SVGA_WriteReg(SVGA_REG_SYNC, 1);
+ while (SVGA_ReadReg(SVGA_REG_BUSY) != FALSE);
+
+ SVGA_WriteReg(SVGA_REG_IRQMASK, 0);
+
+ /* Check whether the interrupt occurred without blocking. */
+ if ((gSVGA.irq.pending & SVGA_IRQFLAG_ANY_FENCE) == 0) {
+ SVGA_Panic("SVGA IRQ appears to be present but broken.");
+ }
+
+ SVGA_WaitForIRQ();
+ }
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_Disable --
+ *
+ * Disable the SVGA portion of the video adapter, switching back
+ * to VGA mode.
+ *
+ * Results:
+ * void.
+ *
+ * Side effects:
+ * Switches modes. Disables the command FIFO, without flushing it.
+ * (Any commands still in the FIFO will be lost.)
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_Disable(void)
+{
+ SVGA_WriteReg(SVGA_REG_ENABLE, FALSE);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_SetMode --
+ *
+ * This switches the SVGA video mode and enables SVGA device.
+ *
+ * Results:
+ * void.
+ *
+ * Side effects:
+ * Transitions to SVGA mode if SVGA device currently disabled.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_SetMode(uint32 width, // IN
+ uint32 height, // IN
+ uint32 bpp) // IN
+{
+ gSVGA.width = width;
+ gSVGA.height = height;
+ gSVGA.bpp = bpp;
+
+ SVGA_WriteReg(SVGA_REG_WIDTH, width);
+ SVGA_WriteReg(SVGA_REG_HEIGHT, height);
+ SVGA_WriteReg(SVGA_REG_BITS_PER_PIXEL, bpp);
+ SVGA_ReadReg(SVGA_REG_FB_OFFSET);
+ SVGA_WriteReg(SVGA_REG_ENABLE, TRUE);
+ gSVGA.pitch = SVGA_ReadReg(SVGA_REG_BYTES_PER_LINE);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_Panic --
+ *
+ * This is a Panic handler which works in SVGA mode. It disables SVGA,
+ * then executes the Console's panic handler.
+ *
+ * Results:
+ * Never returns.
+ *
+ * Side effects:
+ * Disables SVGA mode, initializes VGA text mode.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#ifndef REALLY_TINY
+void
+SVGA_Panic(const char *msg) // IN
+{
+ SVGA_Disable();
+ ConsoleVGA_Init();
+ Console_Panic(msg);
+}
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_DefaultFaultHandler --
+ *
+ * This is a default fault handler which works in SVGA mode. It
+ * disables SVGA, then executes the Console's default fault
+ * handler.
+ *
+ * Results:
+ * Never returns.
+ *
+ * Side effects:
+ * Disables SVGA mode, initializes VGA text mode.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_DefaultFaultHandler(int vector) // IN
+{
+#ifndef REALLY_TINY
+ SVGA_Disable();
+ Console_UnhandledFault(vector);
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_ReadReg --
+ *
+ * Read an SVGA device register (SVGA_REG_*).
+ * This must be called after the PCI device's IOspace has been mapped.
+ *
+ * Results:
+ * 32-bit register value.
+ *
+ * Side effects:
+ * Depends on the register value. Some special registers
+ * like SVGA_REG_BUSY have significant side-effects.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+uint32
+SVGA_ReadReg(uint32 index) // IN
+{
+ outpd(gSVGA.ioBase + SVGA_INDEX_PORT, index);
+ return inpd(gSVGA.ioBase + SVGA_VALUE_PORT);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_WriteReg --
+ *
+ * Write an SVGA device register (SVGA_REG_*).
+ * This must be called after the PCI device's IOspace has been mapped.
+ *
+ * Results:
+ * void.
+ *
+ * Side effects:
+ * Depends on the register value.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_WriteReg(uint32 index, // IN
+ uint32 value) // IN
+{
+ outpd(gSVGA.ioBase + SVGA_INDEX_PORT, index);
+ outpd(gSVGA.ioBase + SVGA_VALUE_PORT, value);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_IsFIFORegValid --
+ *
+ * Check whether space has been allocated for a particular FIFO register.
+ *
+ * This isn't particularly useful for our simple examples, since the
+ * same binary is responsible for both allocating and using the FIFO,
+ * but a real driver may need to check this if the module which handles
+ * initialization and mode switches is separate from the module which
+ * actually writes to the FIFO.
+ *
+ * Results:
+ * TRUE if the register has been allocated, FALSE if the register
+ * does not exist.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+SVGA_IsFIFORegValid(int reg)
+{
+ return gSVGA.fifoMem[SVGA_FIFO_MIN] > (reg << 2);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_HasFIFOCap --
+ *
+ * Check whether the SVGA device has a particular FIFO capability bit.
+ *
+ * Results:
+ * TRUE if the capability is present, FALSE if it's absent.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+SVGA_HasFIFOCap(unsigned long cap)
+{
+ return (gSVGA.fifoMem[SVGA_FIFO_CAPABILITIES] & cap) != 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_FIFOReserve --
+ *
+ * Begin writing a command to the FIFO buffer. There are several
+ * examples floating around which show how to write to the FIFO
+ * buffer, but this is the preferred method: write directly to
+ * FIFO memory in the common case, but if the command would not
+ * be contiguous, use a bounce buffer.
+ *
+ * This method is easy to use, and quite fast. The X.org driver
+ * does not yet use this method, but recent Windows drivers use
+ * it.
+ *
+ * The main principles here are:
+ *
+ * - There are multiple code paths. In the best case, we write
+ * directly to the FIFO. In the next-best case, we use a
+ * static bounce buffer. If you need to support arbitrarily
+ * large commands, you can have a worst case in which you use
+ * a dynamically sized bounce buffer.
+ *
+ * - We must tell the host that we're reserving FIFO
+ * space. This is important because the device doesn't
+ * guarantee it will preserve the contents of FIFO memory
+ * which hasn't been reserved. If we write to a totally
+ * unused portion of the FIFO and the VM is suspended, on
+ * resume that data will no longer exist.
+ *
+ * This function is not re-entrant. If your driver is
+ * multithreaded or may be used from multiple processes
+ * concurrently, you must make sure to serialize all FIFO
+ * commands.
+ *
+ * The caller must pair this command with SVGA_FIFOCommit or
+ * SVGA_FIFOCommitAll.
+ *
+ * Results:
+ * Returns a pointer to the location where the FIFO command can
+ * be written. There will be room for at least 'bytes' bytes of
+ * data.
+ *
+ * Side effects:
+ * Begins a FIFO command, reserves space in the FIFO.
+ * May block (in SVGAFIFOFull) if the FIFO is full.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void __far *
+SVGA_FIFOReserve(uint32 bytes) // IN
+{
+ volatile uint32 __far *fifo = gSVGA.fifoMem;
+ uint32 max = fifo[SVGA_FIFO_MAX];
+ uint32 min = fifo[SVGA_FIFO_MIN];
+#if 0
+ uint32 nextCmd = fifo[SVGA_FIFO_NEXT_CMD];
+ Bool reserveable = SVGA_HasFIFOCap(SVGA_FIFO_CAP_RESERVE);
+#endif
+
+ /*
+ * This example implementation uses only a statically allocated
+ * buffer. If you want to support arbitrarily large commands,
+ * dynamically allocate a buffer if and only if it's necessary.
+ */
+
+ if (bytes > sizeof gSVGA.fifo.bounceBuffer ||
+ bytes > (max - min)) {
+ SVGA_Panic("FIFO command too large");
+ }
+
+ if (bytes % sizeof(uint32)) {
+ SVGA_Panic("FIFO command length not 32-bit aligned");
+ }
+
+ if (gSVGA.fifo.reservedSize != 0) {
+ SVGA_Panic("FIFOReserve before FIFOCommit");
+ }
+
+ gSVGA.fifo.reservedSize = bytes;
+
+#if 0
+ while (1) {
+ uint32 stop = fifo[SVGA_FIFO_STOP];
+ Bool reserveInPlace = FALSE;
+ Bool needBounce = FALSE;
+
+ /*
+ * Find a strategy for dealing with "bytes" of data:
+ * - reserve in place, if there's room and the FIFO supports it
+ * - reserve in bounce buffer, if there's room in FIFO but not
+ * contiguous or FIFO can't safely handle reservations
+ * - otherwise, sync the FIFO and try again.
+ */
+
+ if (nextCmd >= stop) {
+ /* There is no valid FIFO data between nextCmd and max */
+
+ if (nextCmd + bytes < max ||
+ (nextCmd + bytes == max && stop > min)) {
+ /*
+ * Fastest path 1: There is already enough contiguous space
+ * between nextCmd and max (the end of the buffer).
+ *
+ * Note the edge case: If the "<" path succeeds, we can
+ * quickly return without performing any other tests. If
+ * we end up on the "==" path, we're writing exactly up to
+ * the top of the FIFO and we still need to make sure that
+ * there is at least one unused DWORD at the bottom, in
+ * order to be sure we don't fill the FIFO entirely.
+ *
+ * If the "==" test succeeds, but stop <= min (the FIFO
+ * would be completely full if we were to reserve this
+ * much space) we'll end up hitting the FIFOFull path below.
+ */
+ reserveInPlace = TRUE;
+ } else if ((max - nextCmd) + (stop - min) <= bytes) {
+ /*
+ * We have to split the FIFO command into two pieces,
+ * but there still isn't enough total free space in
+ * the FIFO to store it.
+ *
+ * Note the "<=". We need to keep at least one DWORD
+ * of the FIFO free at all times, or we won't be able
+ * to tell the difference between full and empty.
+ */
+ SVGAFIFOFull();
+ } else {
+ /*
+ * Data fits in FIFO but only if we split it.
+ * Need to bounce to guarantee contiguous buffer.
+ */
+ needBounce = TRUE;
+ }
+
+ } else {
+ /* There is FIFO data between nextCmd and max */
+
+ if (nextCmd + bytes < stop) {
+ /*
+ * Fastest path 2: There is already enough contiguous space
+ * between nextCmd and stop.
+ */
+ reserveInPlace = TRUE;
+ } else {
+ /*
+ * There isn't enough room between nextCmd and stop.
+ * The FIFO is too full to accept this command.
+ */
+ SVGAFIFOFull();
+ }
+ }
+
+ /*
+ * If we decided we can write directly to the FIFO, make sure
+ * the VMX can safely support this.
+ */
+ if (reserveInPlace) {
+ if (reserveable || bytes <= sizeof(uint32)) {
+ gSVGA.fifo.usingBounceBuffer = FALSE;
+ if (reserveable) {
+ fifo[SVGA_FIFO_RESERVED] = bytes;
+ }
+ return nextCmd + (uint8 __far*) fifo;
+ } else {
+ /*
+ * Need to bounce because we can't trust the VMX to safely
+ * handle uncommitted data in FIFO.
+ */
+ needBounce = TRUE;
+ }
+ }
+
+ /*
+ * If we reach here, either we found a full FIFO, called
+ * SVGAFIFOFull to make more room, and want to try again, or we
+ * decided to use a bounce buffer instead.
+ */
+ if (needBounce) {
+ gSVGA.fifo.usingBounceBuffer = TRUE;
+ return (void __far *)(&gSVGA.fifo.bounceBuffer[0]);
+ }
+ } /* while (1) */
+#else
+ gSVGA.fifo.usingBounceBuffer = TRUE;
+ return (void __far *)(&gSVGA.fifo.bounceBuffer[0]);
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_FIFOCommit --
+ *
+ * Commit a block of FIFO data which was placed in the buffer
+ * returned by SVGA_FIFOReserve. Every Reserve must be paired
+ * with exactly one Commit, but the sizes don't have to match.
+ * The caller is free to commit less space than they
+ * reserved. This can be used if the command size isn't known in
+ * advance, but it is reasonable to make a worst-case estimate.
+ *
+ * The commit size does not have to match the size of a single
+ * FIFO command. This can be used to write a partial command, or
+ * to write multiple commands at once.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+
+#ifndef VXD32
+static void WriteFifo(uint32 pos, uint32 dw)
+{
+ uint32 act = pos >> 16;
+ uint16 off = pos & 0xFFFF;
+
+ uint32 __far *ptr;
+
+ if(act != gSVGA.fifoAct)
+ {
+ DPMI_SetSegBase(gSVGA.fifoSel, gSVGA.fifoLinear + (act << 16));
+ gSVGA.fifoAct = act;
+ }
+
+ //dbg_printf("Fifo: %ld (%X:%X)\n", pos, gSVGA.fifoAct, off);
+
+ ptr = (uint32 __far *)(gSVGA.fifoSel :> off);
+
+ *ptr = dw;
+}
+#endif
+
+void
+SVGA_FIFOCommit(uint32 bytes) // IN
+{
+ volatile uint32 __far *fifo = gSVGA.fifoMem;
+ uint32 nextCmd = fifo[SVGA_FIFO_NEXT_CMD];
+ uint32 max = fifo[SVGA_FIFO_MAX];
+ uint32 min = fifo[SVGA_FIFO_MIN];
+ Bool reserveable = 0; //SVGA_HasFIFOCap(SVGA_FIFO_CAP_RESERVE);
+
+ if (gSVGA.fifo.reservedSize == 0) {
+ SVGA_Panic("FIFOCommit before FIFOReserve");
+ }
+ gSVGA.fifo.reservedSize = 0;
+
+ if (gSVGA.fifo.usingBounceBuffer) {
+ /*
+ * Slow paths: copy out of a bounce buffer.
+ */
+ uint8 __far *buffer = gSVGA.fifo.bounceBuffer;
+
+ if (reserveable) {
+ /*
+ * Slow path: bulk copy out of a bounce buffer in two chunks.
+ *
+ * Note that the second chunk may be zero-length if the reserved
+ * size was large enough to wrap around but the commit size was
+ * small enough that everything fit contiguously into the FIFO.
+ *
+ * Note also that we didn't need to tell the FIFO about the
+ * reservation in the bounce buffer, but we do need to tell it
+ * about the data we're bouncing from there into the FIFO.
+ */
+
+ uint32 chunkSize = MIN(bytes, max - nextCmd);
+ fifo[SVGA_FIFO_RESERVED] = bytes;
+ drv_memcpy(nextCmd + (uint8 __far*) fifo, buffer, chunkSize);
+ drv_memcpy(min + (uint8 __far*) fifo, buffer + chunkSize, bytes - chunkSize);
+
+ } else {
+ /*
+ * Slowest path: copy one dword at a time, updating NEXT_CMD as
+ * we go, so that we bound how much data the guest has written
+ * and the host doesn't know to checkpoint.
+ */
+
+ uint32 *dword = (uint32 *)buffer;
+
+ while (bytes > 0) {
+ //fifo[nextCmd / sizeof(uint32)] = *dword++;
+
+#ifndef VXD32
+ WriteFifo(nextCmd, *dword);
+#else
+ fifo[nextCmd / sizeof(uint32)] = *dword;
+#endif
+ dword++;
+
+ nextCmd += sizeof(uint32);
+ if (nextCmd >= max) {
+ nextCmd = min;
+ }
+ fifo[SVGA_FIFO_NEXT_CMD] = nextCmd;
+ bytes -= sizeof *dword;
+ }
+ }
+ }
+
+ /*
+ * Atomically update NEXT_CMD, if we didn't already
+ */
+ if (!gSVGA.fifo.usingBounceBuffer || reserveable) {
+ nextCmd += bytes;
+ if (nextCmd >= max) {
+ nextCmd -= max - min;
+ }
+ fifo[SVGA_FIFO_NEXT_CMD] = nextCmd;
+ }
+
+ /*
+ * Clear the reservation in the FIFO.
+ */
+ if (reserveable) {
+ fifo[SVGA_FIFO_RESERVED] = 0;
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_FIFOCommitAll --
+ *
+ * This is a convenience wrapper for SVGA_FIFOCommit(), which
+ * always commits the last reserved block in its entirety.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * SVGA_FIFOCommit.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_FIFOCommitAll(void)
+{
+ SVGA_FIFOCommit(gSVGA.fifo.reservedSize);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_FIFOReserveCmd --
+ *
+ * This is a convenience wrapper around SVGA_FIFOReserve, which
+ * prefixes the reserved memory block with a uint32 that
+ * indicates the command type.
+ *
+ * Results:
+ * Always returns a pointer to 'bytes' bytes of reserved space in the FIFO.
+ *
+ * Side effects:
+ * Begins a FIFO command, reserves space in the FIFO. Writes a
+ * 1-word header into the FIFO. May block (in SVGAFIFOFull) if
+ * the FIFO is full.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void __far *
+SVGA_FIFOReserveCmd(uint32 type, // IN
+ uint32 bytes) // IN
+{
+ uint32 __far *cmd = SVGA_FIFOReserve(bytes + sizeof type);
+ cmd[0] = type;
+ return cmd + 1;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_FIFOReserveEscape --
+ *
+ * This is a convenience wrapper around SVGA_FIFOReserve, which
+ * prefixes the reserved memory block with an ESCAPE command header.
+ *
+ * ESCAPE commands are a way of encoding extensible and
+ * variable-length packets within the basic FIFO protocol
+ * itself. ESCAPEs are used for some SVGA device functionality,
+ * like video overlays, for VMware's internal debugging tools,
+ * and for communicating with third party code that can load into
+ * the SVGA device.
+ *
+ * Results:
+ * Always returns a pointer to 'bytes' bytes of reserved space in the FIFO.
+ *
+ * Side effects:
+ * Begins a FIFO command, reserves space in the FIFO. Writes a
+ * 3-word header into the FIFO. May block (in SVGAFIFOFull) if
+ * the FIFO is full.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void __far *
+SVGA_FIFOReserveEscape(uint32 nsid, // IN
+ uint32 bytes) // IN
+{
+ uint32 paddedBytes = (bytes + 3) & ~3UL;
+#pragma pack(push)
+#pragma pack(1)
+ struct {
+ uint32 cmd;
+ uint32 nsid;
+ uint32 size;
+ } __far *header;
+#pragma pack(pop)
+
+ header = SVGA_FIFOReserve(paddedBytes + sizeof(*header));
+
+ header->cmd = SVGA_CMD_ESCAPE;
+ header->nsid = nsid;
+ header->size = bytes;
+
+ return header + 1;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGAFIFOFull --
+ *
+ * This function is called repeatedly as long as the FIFO has too
+ * little free space for us to continue.
+ *
+ * The simplest implementation of this function is a no-op. This
+ * will just burn guest CPU until space is available. (That's a
+ * bad idea, since the host probably needs that CPU in order to
+ * make progress on emptying the FIFO.)
+ *
+ * A better implementation would sleep until a FIFO progress
+ * interrupt occurs. Depending on the OS you're writing drivers
+ * for, this may deschedule the calling task or it may simply put
+ * the CPU to sleep.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#if 0
+void
+SVGAFIFOFull(void)
+{
+#ifndef REALLY_TINY
+ if (SVGA_IsFIFORegValid(SVGA_FIFO_FENCE_GOAL) &&
+ (gSVGA.capabilities & SVGA_CAP_IRQMASK)) {
+
+ /*
+ * On hosts which support interrupts, we can sleep until the
+ * FIFO_PROGRESS interrupt occurs. This is the most efficient
+ * thing to do when the FIFO fills up.
+ *
+ * As with the IRQ-based SVGA_SyncToFence(), this will only work
+ * on Workstation 6.5 virtual machines and later.
+ */
+
+ SVGA_WriteReg(SVGA_REG_IRQMASK, SVGA_IRQFLAG_FIFO_PROGRESS);
+ SVGA_ClearIRQ();
+ SVGA_RingDoorbell();
+ SVGA_WaitForIRQ();
+ SVGA_WriteReg(SVGA_REG_IRQMASK, 0);
+
+ } else {
+
+ /*
+ * Fallback implementation: Perform one iteration of the
+ * legacy-style sync. This synchronously processes FIFO commands
+ * for an arbitrary amount of time, then returns control back to
+ * the guest CPU.
+ */
+
+ SVGA_WriteReg(SVGA_REG_SYNC, 1);
+ SVGA_ReadReg(SVGA_REG_BUSY);
+ }
+#endif
+}
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_InsertFence --
+ *
+ * Write a new fence value to the FIFO.
+ *
+ * Fences are the basis of the SVGA device's synchronization
+ * model. A fence is a marker inserted into the FIFO by the
+ * guest. The host processes all FIFO commands in order. Once the
+ * fence is reached, the host does two things:
+ *
+ * - The fence value is written to the SVGA_FIFO_FENCE register.
+ * - Optionally, an interrupt is raised.
+ *
+ * There are multiple ways to use fences for synchronization. See
+ * SVGA_SyncToFence and SVGA_HasFencePassed.
+ *
+ * Results:
+ *
+ * Returns the value of the fence we inserted. Fence values
+ * increment, wrapping around at 32 bits. Fence value zero is
+ * reserved to mean "no fence". This function never returns zero.
+ *
+ * Certain very old versions of the VMware SVGA device do not
+ * support fences. On these devices, we always return 1. On these
+ * devices, SyncToFence will always do a full Sync and
+ * SyncToFence will always return FALSE, so the actual fence
+ * value we use is unimportant. Code written to use fences will
+ * run inefficiently, but it will still be correct.
+ *
+ * Side effects:
+ * Writes to the FIFO. Increments our nextFence.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+uint32
+SVGA_InsertFence(void)
+{
+ uint32 fence;
+
+#pragma pack(push)
+#pragma pack(1)
+ struct {
+ uint32 id;
+ uint32 fence;
+ } __far *cmd;
+#pragma pack(pop)
+
+ if (!SVGA_HasFIFOCap(SVGA_FIFO_CAP_FENCE)) {
+ return 1;
+ }
+
+ if (gSVGA.fifo.nextFence == 0) {
+ gSVGA.fifo.nextFence = 1;
+ }
+ fence = gSVGA.fifo.nextFence++;
+
+ cmd = SVGA_FIFOReserve(sizeof *cmd);
+ cmd->id = SVGA_CMD_FENCE;
+ cmd->fence = fence;
+ SVGA_FIFOCommitAll();
+
+ return fence;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_SyncToFence --
+ *
+ * Sleep until the SVGA device has processed all FIFO commands
+ * prior to the insertion point of the specified fence.
+ *
+ * This is the most important way to maintain synchronization
+ * between the driver and the SVGA3D device itself. It can be
+ * used to provide flow control between the host and the guest,
+ * or to ensure that DMA operations have completed before reusing
+ * guest memory.
+ *
+ * If the provided fence is zero or it has already passed,
+ * this is a no-op.
+ *
+ * If the SVGA device and virtual machine hardware version are
+ * both new enough (Workstation 6.5 or later), this will use an
+ * efficient interrupt-driven mechanism to sleep until just after
+ * the host processes the fence.
+ *
+ * If not, this will use a less efficient synchronization
+ * mechanism which may require the host to process significantly
+ * more of the FIFO than is necessary.
+ *
+ * Results:
+ * void.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_SyncToFence(uint32 fence) // IN
+{
+ if (!fence) {
+ return;
+ }
+
+ if (!SVGA_HasFIFOCap(SVGA_FIFO_CAP_FENCE)) {
+ /*
+ * Fall back on the legacy sync if the host does not support
+ * fences. This is the old sync mechanism that has been
+ * supported in the SVGA device pretty much since the dawn of
+ * time: write to the SYNC register, then read from BUSY until
+ * it's nonzero. This will drain the entire FIFO.
+ *
+ * The parameter we write to SVGA_REG_SYNC is an arbitrary
+ * nonzero value which can be used for debugging, but which is
+ * ignored by release builds of VMware products.
+ */
+
+ SVGA_WriteReg(SVGA_REG_SYNC, 1);
+ while (SVGA_ReadReg(SVGA_REG_BUSY) != FALSE);
+ return;
+ }
+
+ if (SVGA_HasFencePassed(fence)) {
+ /*
+ * Nothing to do
+ */
+
+ return;
+ }
+
+#ifndef REALLY_TINY
+ if (SVGA_IsFIFORegValid(SVGA_FIFO_FENCE_GOAL) &&
+ (gSVGA.capabilities & SVGA_CAP_IRQMASK)) {
+
+ /*
+ * On hosts which support interrupts and which support the
+ * FENCE_GOAL interrupt, we can use our preferred
+ * synchronization mechanism.
+ *
+ * This provides low latency notification both from guest to
+ * host and from host to guest, and it doesn't block the guest
+ * while we're waiting.
+ *
+ * This will only work on Workstation 6.5 virtual machines
+ * or later. Older virtual machines did not allocate an IRQ
+ * for the SVGA device, and the IRQMASK capability will be
+ * unset.
+ */
+
+ /*
+ * Set the fence goal. This asks the host to send an interrupt
+ * when this specific fence has been reached.
+ */
+
+ gSVGA.fifoMem[SVGA_FIFO_FENCE_GOAL] = fence;
+ SVGA_WriteReg(SVGA_REG_IRQMASK, SVGA_IRQFLAG_FENCE_GOAL);
+
+ SVGA_ClearIRQ();
+
+ /*
+ * Must check again, in case we reached the fence between the
+ * first HasFencePassed and when we set up the IRQ.
+ *
+ * As a small performance optimization, we check yet again after
+ * RingDoorbell, since there's a chance that RingDoorbell will
+ * deschedule this VM and process some SVGA FIFO commands in a
+ * way that appears synchronous from the VM's point of view.
+ */
+
+ if (!SVGA_HasFencePassed(fence)) {
+ /*
+ * We're about to go to sleep. Make sure the host is awake.
+ */
+ SVGA_RingDoorbell();
+
+ if (!SVGA_HasFencePassed(fence)) {
+ SVGA_WaitForIRQ();
+ }
+ }
+
+ SVGA_WriteReg(SVGA_REG_IRQMASK, 0);
+
+ } else
+#endif // REALLY_TINY
+ {
+ /*
+ * Sync-to-fence mechanism for older hosts. Wake up the host,
+ * and spin on BUSY until we've reached the fence. This
+ * processes FIFO commands synchronously, blocking the VM's
+ * execution entirely until it's done.
+ */
+
+ Bool busy = TRUE;
+
+ SVGA_WriteReg(SVGA_REG_SYNC, 1);
+
+ while (!SVGA_HasFencePassed(fence) && busy) {
+ busy = (SVGA_ReadReg(SVGA_REG_BUSY) != 0);
+ }
+ }
+
+#ifndef REALLY_TINY
+ if (!SVGA_HasFencePassed(fence)) {
+ /*
+ * This shouldn't happen. If it does, there might be a bug in
+ * the SVGA device.
+ */
+ SVGA_Panic("SyncToFence failed!");
+ }
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_HasFencePassed --
+ *
+ * Test whether the host has processed all FIFO commands prior to
+ * the insertion point of the specified fence.
+ *
+ * This function tolerates fence wrap-around, but it will return
+ * the wrong result if 'fence' is more than 2^31 fences old. It
+ * is recommended that callers don't allow fence values to
+ * persist indefinitely. Once we notice that a fence has been
+ * passed, that fence variable should be set to zero so we don't
+ * test it in the future.
+ *
+ * Results:
+ * TRUE if the fence has been passed,
+ * TRUE if fence==0 (no fence),
+ * FALSE if the fence has not been passed,
+ * FALSE if the SVGA device does not support fences.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+SVGA_HasFencePassed(uint32 fence) // IN
+{
+ if (!fence) {
+ return TRUE;
+ }
+
+ if (!SVGA_HasFIFOCap(SVGA_FIFO_CAP_FENCE)) {
+ return FALSE;
+ }
+
+ return ((int32)(gSVGA.fifoMem[SVGA_FIFO_FENCE] - fence)) >= 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_RingDoorbell --
+ *
+ * FIFO fences are fundamentally a host-to-guest notification
+ * mechanism. This is the opposite: we can explicitly wake up
+ * the host when we know there is work for it to do.
+ *
+ * Background: The host processes the SVGA command FIFO in a
+ * separate thread which runs asynchronously with the virtual
+ * machine's CPU and other I/O devices. When the SVGA device is
+ * idle, this thread is sleeping. It periodically wakes up to
+ * poll for new commands. This polling must occur for various
+ * reasons, but it's mostly related to the historical way in
+ * which the SVGA device processes 2D updates.
+ *
+ * This polling introduces significant latency between when the
+ * first new command is placed in an empty FIFO, and when the
+ * host begins processing it. Normally this isn't a huge problem
+ * since the host and guest run fairly asynchronously, but in
+ * a synchronization-heavy workload this can be a bottleneck.
+ *
+ * For example, imagine an application with a worst-case
+ * synchronization bottleneck: The guest enqueues a single FIFO
+ * command, then waits for that command to finish using
+ * SyncToFence, then the guest spends a little time doing
+ * CPU-intensive processing before the cycle repeats. The
+ * workload may be latency-bound if the host-to-guest or
+ * guest-to-host notifications ever block.
+ *
+ * One solution would be for the guest to explicitly wake up the
+ * SVGA3D device any time a command is enqueued. This would solve
+ * the latency bottleneck above, but it would be inefficient on
+ * single-CPU host machines. One could easily imagine a situation
+ * in which we wake up the host after enqueueing one FIFO
+ * command, the physical CPU context switches to the SVGA
+ * device's thread, the single command is processed, then we
+ * context switch back to running guest code.
+ *
+ * Our recommended solution is to wake up the host only either:
+ *
+ * - After a "significant" amount of work has been enqueued into
+ * the FIFO. For example, at least one 3D drawing command.
+ *
+ * - After a complete frame has been rendered.
+ *
+ * - Just before the guest sleeps for any reason.
+ *
+ * This function implements the above guest wakeups. It uses the
+ * SVGA_FIFO_BUSY register to quickly assess whether the SVGA
+ * device may be idle. If so, it asynchronously wakes up the host
+ * by writing to SVGA_REG_SYNC.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * May wake up the SVGA3D device.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_RingDoorbell(void)
+{
+ if (SVGA_IsFIFORegValid(SVGA_FIFO_BUSY) &&
+ gSVGA.fifoMem[SVGA_FIFO_BUSY] == FALSE) {
+
+ /* Remember that we already rang the doorbell. */
+ gSVGA.fifoMem[SVGA_FIFO_BUSY] = TRUE;
+
+ /*
+ * Asynchronously wake up the SVGA3D device. The second
+ * parameter is an arbitrary nonzero 'sync reason' which can be
+ * used for debugging, but which isn't part of the SVGA3D
+ * protocol proper and which isn't used by release builds of
+ * VMware products.
+ */
+ SVGA_WriteReg(SVGA_REG_SYNC, 1);
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_Flush --
+ *
+ * Force to apply all register changes. Useful if registry changes
+ * needs be applyed immediately
+ *
+ *-----------------------------------------------------------------------------
+ */
+void SVGA_Flush(void)
+{
+ SVGA_WriteReg(SVGA_REG_SYNC, 1);
+ while (SVGA_ReadReg(SVGA_REG_BUSY) != FALSE);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_ClearIRQ --
+ *
+ * Clear all pending IRQs. Any IRQs which occurred prior to this
+ * function call will be ignored by the next SVGA_WaitForIRQ()
+ * call.
+ *
+ * Does not affect the current IRQ mask. This function is not
+ * useful unless the SVGA device has IRQ support.
+ *
+ * Results:
+ * Returns a mask of all the interrupt flags that were set prior
+ * to the clear.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+#ifndef REALLY_TINY
+/*
+uint32
+SVGA_ClearIRQ(void)
+{
+ uint32 flags = 0;
+ Atomic_Exchange(gSVGA.irq.pending, flags);
+
+ return flags;
+}*/
+
+uint32 SVGA_ClearIRQ(void);
+#pragma aux SVGA_ClearIRQ = \
+ ".386" \
+ "push eax" \
+ "xor eax, eax" \
+ "xchg ptr gSVGA.irq.pending, eax" \
+ "mov dx, ax" \
+ "shr eax, 16" \
+ "xchg dx, ax" \
+ "xchg bx, ax" \
+ "pop eax" \
+ "xchg bx, ax" \
+ value [dx ax] modify [bx];
+
+#endif
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_WaitForIRQ --
+ *
+ * Sleep until an SVGA interrupt occurs. When we wake up, return
+ * a mask of all SVGA IRQs which occurred while we were asleep.
+ *
+ * The design of this function will be different for every OS,
+ * but it is imperative that you ensure it will work properly
+ * no matter when the interrupt actually occurs. The IRQ could have
+ * already happened (any time since the last ClearIRQ, it could
+ * happen while this function is running, or it could happen
+ * after we decide to sleep.
+ *
+ * In this example:
+ *
+ * 1. If the IRQ occurred before this function was called,
+ * the bit will already be set in irq.pending. We can return.
+ *
+ * 2. If the IRQ occurs while this function is executing, we
+ * ask our IRQ handler to do a light-weight context switch
+ * back to the beginning of this function, so we can
+ * re-examine irq.pending before sleeping.
+ *
+ * 3. If the IRQ occurs while we're sleeping, we wake up
+ * from the HLT instruction and re-test irq.pending.
+ *
+ * Results:
+ * Returns a mask of all the interrupt flags that were set prior
+ * to the clear. This will always be nonzero.
+ *
+ * Side effects:
+ * Clears the irq.pending flags for exactly the set of IRQs we return.
+ *
+ *-----------------------------------------------------------------------------
+ */
+#ifndef REALLY_TINY
+static __attribute__ ((noinline)) uint32
+SVGAWaitForIRQInternal(void *arg, ...)
+{
+ uint32 flags = 0;
+
+ /*
+ * switchContext must be set to TRUE before we halt, or we'll deadlock.
+ * This variable is marked as volatile, plus we use a compiler memory barrier.
+ */
+ gSVGA.irq.switchContext = TRUE;
+ asm volatile ("" ::: "memory");
+
+ Atomic_Exchange(gSVGA.irq.pending, flags);
+
+ if (!flags) {
+ Intr_Halt();
+ }
+
+ /*
+ * Must set switchContext to FALSE before this stack frame is deallocated.
+ */
+ gSVGA.irq.switchContext = FALSE;
+ asm volatile ("" ::: "memory");
+
+ return flags;
+}
+
+uint32
+SVGA_WaitForIRQ(void)
+{
+ uint32 flags;
+
+ /*
+ * Store this CPU context, and tell the IRQ handler to return
+ * here if an IRQ occurs. We use IntrContext here just like a
+ * setjmp/longjmp that works in ISRs.
+ *
+ * This must be above the irq.pending check, so that we re-test
+ * irq.pending if an IRQ occurs after testing irq.pending but
+ * before we halt. Without this, we could deadlock if an IRQ
+ * comes in before we actually halt but after we've decided to
+ * halt.
+ */
+
+ Intr_SaveContext((IntrContext*) &gSVGA.irq.newContext);
+
+ do {
+ /*
+ * XXX: The arguments here are a kludge to prevent the interrupt
+ * stack frame from overlapping the stack frame referenced
+ * by Intr_SaveContext().
+ *
+ * Be sure to look at the generated assembly and compare the
+ * size of this argument list to the amount of stack space
+ * allocated for Intr_SaveContext.
+ */
+ flags = SVGAWaitForIRQInternal(NULL, NULL, NULL, NULL, NULL, NULL);
+
+ } while (flags == 0);
+
+ return flags;
+}
+
+#endif
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGAInterruptHandler --
+ *
+ * This is the ISR for the SVGA device's interrupt. We ask the
+ * SVGA device which interrupt occurred, and clear its flag.
+ *
+ * To report this IRQ to the rest of the driver, we:
+ *
+ * 1. Atomically remember the IRQ in the irq.pending bitmask.
+ *
+ * 2. Optionally switch to a different light-weight thread
+ * or a different place in this thread upon returning.
+ * This is analogous to waking up a sleeping thread in
+ * a driver for a real operating system. See SVGA_WaitForIRQ
+ * for details.
+ *
+ * Results:
+ * void.
+ *
+ * Side effects:
+ * Sets bits in pendingIRQs. Reads and clears the device's IRQ flags.
+ * May switch execution contexts.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#ifndef REALLY_TINY
+void
+SVGAInterruptHandler(int vector) // IN (unused)
+{
+ IntrContext *context = Intr_GetContext(vector);
+
+ /*
+ * The SVGA_IRQSTATUS_PORT is a separate I/O port, not a register.
+ * Reading from it gives us the set of IRQ flags which are
+ * set. Writing a '1' to any bit in this register will clear the
+ * corresponding flag.
+ *
+ * Here, we read then clear all flags.
+ */
+
+ uint16 port = gSVGA.ioBase + SVGA_IRQSTATUS_PORT;
+ uint32 irqFlags = IO_In32(port);
+ IO_Out32(port, irqFlags);
+
+ gSVGA.irq.count++;
+
+ if (!irqFlags) {
+ SVGA_Panic("Spurious SVGA IRQ");
+ }
+
+ Atomic_Or(gSVGA.irq.pending, irqFlags);
+
+ if (gSVGA.irq.switchContext) {
+ drv_memcpy((void*) &gSVGA.irq.oldContext, context, sizeof *context);
+ drv_memcpy(context, (void*) &gSVGA.irq.newContext, sizeof *context);
+ gSVGA.irq.switchContext = FALSE;
+ }
+}
+#endif
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA_AllocGMR --
+ *
+ * Allocate a buffer from the framebuffer GMR for screen/DMA operations.
+ * Returns both a pointer (for us to use) and an SVGAGuestPtr (for the
+ * SVGA device to use).
+ *
+ * XXX: This is a trivial implementation which just returns
+ * consecutive addresses in the framebuffer.
+ *
+ * Results:
+ * Returns a local pointer and an SVGAGuestPtr to unused memory.
+ *
+ * Side effects:
+ * Allocates memory.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void __far *
+SVGA_AllocGMR(uint32 size, // IN
+ SVGAGuestPtr __far *ptr) // OUT
+{
+ static SVGAGuestPtr nextPtr = { SVGA_GMR_FRAMEBUFFER, 0 };
+ *ptr = nextPtr;
+ nextPtr.offset += size;
+ return gSVGA.fbMem + ptr->offset;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_Update --
+ *
+ * Send a 2D update rectangle through the FIFO.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_Update(uint32 x, // IN
+ uint32 y, // IN
+ uint32 width, // IN
+ uint32 height) // IN
+{
+ SVGAFifoCmdUpdate __far *cmd = SVGA_FIFOReserveCmd(SVGA_CMD_UPDATE, sizeof *cmd);
+ cmd->x = x;
+ cmd->y = y;
+ cmd->width = width;
+ cmd->height = height;
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_BeginDefineCursor --
+ *
+ * Begin an SVGA_CMD_DEFINE_CURSOR command. This copies the command header
+ * into the FIFO, and reserves enough space for the cursor image itself.
+ * We return pointers to FIFO memory where the AND/XOR masks can be written.
+ * When finished, the caller must invoke SVGA_FIFOCommitAll().
+ *
+ * Results:
+ * Returns pointers to memory where the caller can store the AND/XOR masks.
+ *
+ * Side effects:
+ * Reserves space in the FIFO.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_BeginDefineCursor(const SVGAFifoCmdDefineCursor __far *cursorInfo, // IN
+ void __far * __far *andMask, // OUT
+ void __far * __far *xorMask) // OUT
+{
+ uint32 andPitch = ((cursorInfo->andMaskDepth * cursorInfo->width + 31) >> 5) << 2;
+ uint32 andSize = andPitch * cursorInfo->height;
+ uint32 xorPitch = ((cursorInfo->xorMaskDepth * cursorInfo->width + 31) >> 5) << 2;
+ uint32 xorSize = xorPitch * cursorInfo->height;
+
+ SVGAFifoCmdDefineCursor __far *cmd = SVGA_FIFOReserveCmd(SVGA_CMD_DEFINE_CURSOR,
+ sizeof *cmd + andSize + xorSize);
+ *cmd = *cursorInfo;
+ *andMask = (void*) (cmd + 1);
+ *xorMask = (void*) (andSize + (uint8 __far*) *andMask);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_BeginDefineAlphaCursor --
+ *
+ * Begin an SVGA_CMD_DEFINE_ALPHA_CURSOR command. This copies the
+ * command header into the FIFO, and reserves enough space for
+ * the cursor image itself. We return a pointer to the FIFO
+ * memory where the caller should write a pre-multiplied BGRA
+ * image. When finished, the caller must invoke SVGA_FIFOCommitAll().
+ *
+ * Results:
+ * Returns pointers to memory where the caller can store the image.
+ *
+ * Side effects:
+ * Reserves space in the FIFO.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_BeginDefineAlphaCursor(const SVGAFifoCmdDefineAlphaCursor __far *cursorInfo, // IN
+ void __far * __far * data) // OUT
+{
+ uint32 imageSize = cursorInfo->width * cursorInfo->height * sizeof(uint32);
+ SVGAFifoCmdDefineAlphaCursor __far *cmd = SVGA_FIFOReserveCmd(SVGA_CMD_DEFINE_ALPHA_CURSOR,
+ sizeof *cmd + imageSize);
+ *cmd = *cursorInfo;
+ *data = (void*) (cmd + 1);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_MoveCursor --
+ *
+ * Change the position or visibility of the hardware cursor, using
+ * the Cursor Bypass 3 protocol.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Modifies FIFO registers.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_MoveCursor(uint32 visible, // IN
+ uint32 x, // IN
+ uint32 y, // IN
+ uint32 screenId) // IN
+{
+ if (SVGA_HasFIFOCap(SVGA_FIFO_CAP_SCREEN_OBJECT)) {
+ gSVGA.fifoMem[SVGA_FIFO_CURSOR_SCREEN_ID] = screenId;
+ }
+
+ if (SVGA_HasFIFOCap(SVGA_FIFO_CAP_CURSOR_BYPASS_3)) {
+ gSVGA.fifoMem[SVGA_FIFO_CURSOR_ON] = visible;
+ gSVGA.fifoMem[SVGA_FIFO_CURSOR_X] = x;
+ gSVGA.fifoMem[SVGA_FIFO_CURSOR_Y] = y;
+ gSVGA.fifoMem[SVGA_FIFO_CURSOR_COUNT]++;
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_BeginVideoSetRegs --
+ *
+ * Begin an SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS command. This can be
+ * used to set an arbitrary number of video registers atomically.
+ *
+ * Results:
+ * Returns a pointer to the command. The caller must fill in (*setRegs)->items.
+ *
+ * Side effects:
+ * Reserves space in the FIFO.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_BeginVideoSetRegs(uint32 streamId, // IN
+ uint32 numItems, // IN
+ SVGAEscapeVideoSetRegs __far * __far * setRegs) // OUT
+{
+ SVGAEscapeVideoSetRegs __far *cmd;
+ uint32 cmdSize = (sizeof *cmd
+ - sizeof cmd->items
+ + numItems * sizeof cmd->items[0]);
+
+ cmd = SVGA_FIFOReserveEscape(SVGA_ESCAPE_NSID_VMWARE, cmdSize);
+ cmd->header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS;
+ cmd->header.streamId = streamId;
+
+ *setRegs = cmd;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_VideoSetReg --
+ *
+ * Atomically set all registers in a video overlay unit.
+ *
+ * 'maxReg' should be the highest video overlay register that the
+ * caller understands. We will not set any registers with IDs
+ * higher than maxReg. This prevents older applications compiled
+ * with newer headers from sending improper values to new overlay
+ * registers.
+ *
+ * Each video overlay unit (specified by streamId) has a collection
+ * of 32-bit registers which control the operation of that overlay.
+ * Changes to these registers take effect at the next Flush.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Writes a FIFO command.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_VideoSetAllRegs(uint32 streamId, // IN
+ SVGAOverlayUnit __far *regs, // IN
+ uint32 maxReg) // IN
+{
+ uint32 __far *regArray = (uint32 __far*) regs;
+ const uint32 numRegs = maxReg + 1;
+ SVGAEscapeVideoSetRegs __far *setRegs;
+ uint32 i;
+
+ SVGA_BeginVideoSetRegs(streamId, numRegs, &setRegs);
+
+ for (i = 0; i < numRegs; i++) {
+ setRegs->items[i].registerId = i;
+ setRegs->items[i].value = regArray[i];
+ }
+
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_VideoSetReg --
+ *
+ * Set a single video overlay register.
+ *
+ * Each video overlay unit (specified by streamId) has a collection
+ * of 32-bit registers which control the operation of that overlay.
+ * Changes to these registers take effect at the next Flush.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Writes a FIFO command.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_VideoSetReg(uint32 streamId, // IN
+ uint32 registerId, // IN
+ uint32 value) // IN
+{
+ SVGAEscapeVideoSetRegs __far *setRegs;
+
+ SVGA_BeginVideoSetRegs(streamId, 1, &setRegs);
+ setRegs->items[0].registerId = registerId;
+ setRegs->items[0].value = value;
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SVGA_VideoFlush --
+ *
+ * Update a video overlay. On a VideoFlush, all register changes
+ * take effect, and the device will perform a DMA transfer to
+ * copy the next frame of video from guest memory.
+ *
+ * The SVGA device will generally perform a DMA transfer from
+ * overlay memory only during a VideoFlush. The DMA operation
+ * will usually be completed before the host moves to the next
+ * FIFO command. However, this is not guaranteed. In unusual
+ * conditions, the device may re-perform the DMA operation at any
+ * time. This means that, as long as an overlay is enabled, its
+ * corresponding guest memory must be valid.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Writes a FIFO command. May cause an asynchronous DMA transfer.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SVGA_VideoFlush(uint32 streamId) // IN
+{
+ SVGAEscapeVideoFlush __far *cmd;
+
+ cmd = SVGA_FIFOReserveEscape(SVGA_ESCAPE_NSID_VMWARE, sizeof *cmd);
+ cmd->cmdType = SVGA_ESCAPE_VMWARE_VIDEO_FLUSH;
+ cmd->streamId = streamId;
+ SVGA_FIFOCommitAll();
+}
diff --git a/vmware/svga.h b/vmware/svga.h
new file mode 100644
index 0000000..6095045
--- /dev/null
+++ b/vmware/svga.h
@@ -0,0 +1,153 @@
+/**********************************************************
+ * Copyright 2008-2009 VMware, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/*
+ * svga.h --
+ *
+ * This is a simple example driver for the VMware SVGA device.
+ * It handles initialization, register accesses, low-level
+ * command FIFO writes, and host/guest synchronization.
+ */
+
+#ifndef __SVGA_H__
+#define __SVGA_H__
+
+#include "types16.h"
+#include "pci.h"
+//#include "intr.h"
+
+#define REALLY_TINY
+
+// XXX: Shouldn't have to do this here.
+//#define INLINE __inline__
+#define INLINE inline
+
+#include "svga_reg.h"
+#include "svga_escape.h"
+#include "svga_overlay.h"
+#include "svga3d_reg.h"
+
+typedef struct SVGADevice {
+ PCIAddress pciAddr; // 0
+ uint32 ioBase; // 4
+ uint32 __far *fifoMem; // 8
+ uint8 __far *fbMem; // 16
+ uint32 fifoSize; // 20
+
+ uint32 fifoLinear; // 24
+ uint16 fifoSel; // 28
+ uint16 fifoAct; // 32
+
+ uint32 fifoPhy;
+
+ uint32 fbSize;
+ uint32 fbLinear;
+ uint32 fbPhy;
+ uint32 vramSize;
+
+ uint32 deviceVersionId;
+ uint32 capabilities;
+
+ uint32 width;
+ uint32 height;
+ uint32 bpp;
+ uint32 pitch;
+
+ struct {
+ uint32 reservedSize;
+ Bool usingBounceBuffer;
+ uint8 bounceBuffer[16 * 1024];
+ uint32 nextFence;
+ } fifo;
+
+ /* VMWare SVGAII and VBox SVGA is same device with different PCI ID */
+ uint16 vendorId;
+ uint16 deviceId;
+
+#ifndef REALLY_TINY
+ volatile struct {
+ uint32 pending;
+ uint32 switchContext;
+ IntrContext oldContext;
+ IntrContext newContext;
+ uint32 count;
+ } irq;
+#endif
+
+} SVGADevice;
+
+extern SVGADevice gSVGA;
+
+#ifndef VXD32
+int __loadds SVGA_Init(Bool enableFIFO);
+#else
+int SVGA_Init(Bool enableFIFO);
+#endif
+void SVGA_Enable(void);
+void SVGA_SetMode(uint32 width, uint32 height, uint32 bpp);
+void SVGA_Disable(void);
+void SVGA_Panic(const char *err);
+void SVGA_DefaultFaultHandler(int vector);
+
+void SVGA_Flush(void);
+
+uint32 SVGA_ReadReg(uint32 index);
+void SVGA_WriteReg(uint32 index, uint32 value);
+uint32 SVGA_ClearIRQ(void);
+uint32 SVGA_WaitForIRQ();
+
+Bool SVGA_IsFIFORegValid(int reg);
+Bool SVGA_HasFIFOCap(unsigned long cap);
+
+void __far *SVGA_FIFOReserve(uint32 bytes);
+void __far *SVGA_FIFOReserveCmd(uint32 type, uint32 bytes);
+void __far *SVGA_FIFOReserveEscape(uint32 nsid, uint32 bytes);
+void SVGA_FIFOCommit(uint32 bytes);
+void SVGA_FIFOCommitAll(void);
+
+uint32 SVGA_InsertFence(void);
+void SVGA_SyncToFence(uint32 fence);
+Bool SVGA_HasFencePassed(uint32 fence);
+void SVGA_RingDoorbell(void);
+
+void __far *SVGA_AllocGMR(uint32 size, SVGAGuestPtr __far *ptr);
+
+/* 2D commands */
+
+void SVGA_Update(uint32 x, uint32 y, uint32 width, uint32 height);
+void SVGA_BeginDefineCursor(const SVGAFifoCmdDefineCursor __far *cursorInfo,
+ void __far * __far *andMask, void __far * __far *xorMask);
+void SVGA_BeginDefineAlphaCursor(const SVGAFifoCmdDefineAlphaCursor __far *cursorInfo,
+ void __far * __far *data);
+void SVGA_MoveCursor(uint32 visible, uint32 x, uint32 y, uint32 screenId);
+
+void SVGA_BeginVideoSetRegs(uint32 streamId, uint32 numItems,
+ SVGAEscapeVideoSetRegs __far * __far *setRegs);
+void SVGA_VideoSetAllRegs(uint32 streamId, SVGAOverlayUnit __far *regs, uint32 maxReg);
+void SVGA_VideoSetReg(uint32 streamId, uint32 registerId, uint32 value);
+void SVGA_VideoFlush(uint32 streamId);
+
+
+#endif /* __SVGA_H__ */
diff --git a/vmware/svga32.c b/vmware/svga32.c
new file mode 100644
index 0000000..1091735
--- /dev/null
+++ b/vmware/svga32.c
@@ -0,0 +1,2 @@
+#define VXD32
+#include "svga.c"
diff --git a/vmware/svga3d.c b/vmware/svga3d.c
new file mode 100644
index 0000000..bd48035
--- /dev/null
+++ b/vmware/svga3d.c
@@ -0,0 +1,1222 @@
+/**********************************************************
+ * Copyright 2008-2009 VMware, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/*
+ * svga3d.c --
+ *
+ * FIFO command level interface to the SVGA3D protocol used by
+ * the VMware SVGA device.
+ */
+
+#include <string.h>
+#include "svga_all.h"
+
+#ifdef DBGPRINT
+void dbg_printf( const char *s, ... );
+#else
+#define dbg_printf(...)
+#endif
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_Init --
+ *
+ * Perform 3D-only initialization for the SVGA device. This
+ * function negotiates SVGA3D protocol versions between the host
+ * and the guest.
+ *
+ * The 3D protocol negotiation works as follows:
+ *
+ * 1. Before enabling the FIFO, the guest writes its 3D protocol
+ * version to the SVGA_FIFO_GUEST_3D_HWVERSION register.
+ * We do this step in SVGA_Init().
+ *
+ * 2. When the FIFO is enabled, the host checks our 3D version
+ * for compatibility. If the host can support our protocol,
+ * the host puts its protocol version in SVGA_FIFO_3D_HWVERSION.
+ * If the host cannot support our protocol, it leaves the
+ * version set to zero.
+ *
+ * This function must be called after the FIFO is enabled.
+ * (After SVGA_SetMode.)
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Panic if the host is incompatible with 3D.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Bool
+SVGA3D_Init(void)
+{
+ SVGA3dHardwareVersion hwVersion;
+
+ if (!(gSVGA.capabilities & SVGA_CAP_EXTENDED_FIFO)) {
+ dbg_printf("3D requires the Extended FIFO capability.");
+ }
+
+ if (SVGA_HasFIFOCap(SVGA_FIFO_CAP_3D_HWVERSION_REVISED)) {
+ hwVersion = gSVGA.fifoMem[SVGA_FIFO_3D_HWVERSION_REVISED];
+ } else {
+ if (gSVGA.fifoMem[SVGA_FIFO_MIN] <= sizeof(uint32) * SVGA_FIFO_GUEST_3D_HWVERSION) {
+ dbg_printf("GUEST_3D_HWVERSION register not present.");
+ }
+ hwVersion = gSVGA.fifoMem[SVGA_FIFO_3D_HWVERSION];
+ }
+
+ /*
+ * Check the host's version, make sure we're binary compatible.
+ */
+
+ if (hwVersion == 0) {
+ dbg_printf("3D disabled by host.");
+ return FALSE;
+ }
+ if (hwVersion < SVGA3D_HWVERSION_WS65_B1) {
+ dbg_printf("Host SVGA3D protocol is too old, not binary compatible.");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_FIFOReserve --
+ *
+ * Reserve space for an SVGA3D FIFO command.
+ *
+ * The 2D SVGA commands have been around for a while, so they
+ * have a rather asymmetric structure. The SVGA3D protocol is
+ * more uniform: each command begins with a header containing the
+ * command number and the full size.
+ *
+ * This is a convenience wrapper around SVGA_FIFOReserve. We
+ * reserve space for the whole command, and write the header.
+ *
+ * This function must be paired with SVGA_FIFOCommitAll().
+ *
+ * Results:
+ * Returns a pointer to the space reserved for command-specific
+ * data. It must be 'cmdSize' bytes long.
+ *
+ * Side effects:
+ * Begins a FIFO reservation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void *
+SVGA3D_FIFOReserve(uint32 cmd, // IN
+ uint32 cmdSize) // IN
+{
+ SVGA3dCmdHeader __far *header;
+
+ header = SVGA_FIFOReserve(sizeof *header + cmdSize);
+ header->id = cmd;
+ header->size = cmdSize;
+
+ return &header[1];
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginDefineSurface --
+ *
+ * Begin a SURFACE_DEFINE command. This reserves space for it in
+ * the FIFO, and returns pointers to the command's faces and
+ * mipsizes arrays.
+ *
+ * This function must be paired with SVGA_FIFOCommitAll().
+ * The faces and mipSizes arrays are initialized to zero.
+ *
+ * This creates a "surface" object in the SVGA3D device,
+ * with the provided surface ID (sid). Surfaces are generic
+ * containers for host VRAM objects like textures, vertex
+ * buffers, and depth/stencil buffers.
+ *
+ * Surfaces are hierarchial:
+ *
+ * - Surface may have multiple faces (for cube maps)
+ *
+ * - Each face has a list of mipmap levels
+ *
+ * - Each mipmap image may have multiple volume
+ * slices, if the image is three dimensional.
+ *
+ * - Each slice is a 2D array of 'blocks'
+ *
+ * - Each block may be one or more pixels.
+ * (Usually 1, more for DXT or YUV formats.)
+ *
+ * Surfaces are generic host VRAM objects. The SVGA3D device
+ * may optimize surfaces according to the format they were
+ * created with, but this format does not limit the ways in
+ * which the surface may be used. For example, a depth surface
+ * can be used as a texture, or a floating point image may
+ * be used as a vertex buffer. Some surface usages may be
+ * lower performance, due to software emulation, but any
+ * usage should work with any surface.
+ *
+ * If 'sid' is already defined, the old surface is deleted
+ * and this new surface replaces it.
+ *
+ * Surface IDs are arbitrary small non-negative integers,
+ * global to the entire SVGA device.
+ *
+ * Results:
+ * Returns pointers to arrays allocated in the FIFO for 'faces'
+ * and 'mipSizes'.
+ *
+ * Side effects:
+ * Begins a FIFO reservation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_BeginDefineSurface(uint32 sid, // IN
+ SVGA3dSurfaceFlags flags, // IN
+ SVGA3dSurfaceFormat format, // IN
+ SVGA3dSurfaceFace **faces, // OUT
+ SVGA3dSize **mipSizes, // OUT
+ uint32 numMipSizes) // IN
+{
+ SVGA3dCmdDefineSurface *cmd;
+
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SURFACE_DEFINE, sizeof *cmd +
+ sizeof **mipSizes * numMipSizes);
+
+ cmd->sid = sid;
+ cmd->surfaceFlags = flags;
+ cmd->format = format;
+
+ *faces = &cmd->face[0];
+ *mipSizes = (SVGA3dSize*) &cmd[1];
+
+ memset(*faces, 0, sizeof **faces * SVGA3D_MAX_SURFACE_FACES);
+ memset(*mipSizes, 0, sizeof **mipSizes * numMipSizes);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_DestroySurface --
+ *
+ * Release the host VRAM encapsulated by a particular surface ID.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_DestroySurface(uint32 sid) // IN
+{
+ SVGA3dCmdDestroySurface *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SURFACE_DESTROY, sizeof *cmd);
+ cmd->sid = sid;
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginSurfaceDMA--
+ *
+ * Begin a SURFACE_DMA command. This reserves space for it in
+ * the FIFO, and returns a pointer to the command's box array.
+ * This function must be paired with SVGA_FIFOCommitAll().
+ *
+ * When the SVGA3D device asynchronously processes this FIFO
+ * command, a DMA operation is performed between host VRAM and
+ * a generic SVGAGuestPtr. The guest pointer may refer to guest
+ * VRAM (provided by the SVGA PCI device) or to guest system
+ * memory that has been set up as a Guest Memory Region (GMR)
+ * by the SVGA device.
+ *
+ * The guest's DMA buffer must remain valid (not freed, paged out,
+ * or overwritten) until the host has finished processing this
+ * command. The guest can determine that the host has finished
+ * by using the SVGA device's FIFO Fence mechanism.
+ *
+ * The guest's image buffer can be an arbitrary size and shape.
+ * Guest image data is interpreted according to the SVGA3D surface
+ * format specified when the surface was defined.
+ *
+ * The caller may optionally define the guest image's pitch.
+ * guestImage->pitch can either be zero (assume image is tightly
+ * packed) or it must be the number of bytes between vertically
+ * adjacent image blocks.
+ *
+ * The provided copybox list specifies which regions of the source
+ * image are to be copied, and where they appear on the destination.
+ *
+ * NOTE: srcx/srcy are always on the guest image and x/y are
+ * always on the host image, regardless of the actual transfer
+ * direction!
+ *
+ * For efficiency, the SVGA3D device is free to copy more data
+ * than specified. For example, it may round copy boxes outwards
+ * such that they lie on particular alignment boundaries.
+ *
+ * The box array is initialized with zeroes.
+ *
+ * Results:
+ * Returns pointers to a box array allocated in the FIFO.
+ *
+ * Side effects:
+ * Begins a FIFO reservation.
+ * Begins a FIFO command which will eventually perform DMA.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_BeginSurfaceDMA(SVGA3dGuestImage *guestImage, // IN
+ SVGA3dSurfaceImageId *hostImage, // IN
+ SVGA3dTransferType transfer, // IN
+ SVGA3dCopyBox **boxes, // OUT
+ uint32 numBoxes) // IN
+{
+ SVGA3dCmdSurfaceDMA *cmd;
+ uint32 boxesSize = sizeof **boxes * numBoxes;
+
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SURFACE_DMA, sizeof *cmd + boxesSize);
+
+ cmd->guest = *guestImage;
+ cmd->host = *hostImage;
+ cmd->transfer = transfer;
+ *boxes = (SVGA3dCopyBox*) &cmd[1];
+
+ memset(*boxes, 0, boxesSize);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_DefineContext --
+ *
+ * Create a new context, to be referred to with the provided ID.
+ *
+ * Context objects encapsulate all render state, and shader
+ * objects are per-context.
+ *
+ * Surfaces are not per-context. The same surface can be shared
+ * between multiple contexts, and surface operations can occur
+ * without a context.
+ *
+ * If the provided context ID already existed, it is redefined.
+ *
+ * Context IDs are arbitrary small non-negative integers,
+ * global to the entire SVGA device.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_DefineContext(uint32 cid) // IN
+{
+ SVGA3dCmdDefineContext *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_CONTEXT_DEFINE, sizeof *cmd);
+ cmd->cid = cid;
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_DestroyContext --
+ *
+ * Delete a context created with SVGA3D_DefineContext.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_DestroyContext(uint32 cid) // IN
+{
+ SVGA3dCmdDestroyContext *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_CONTEXT_DESTROY, sizeof *cmd);
+ cmd->cid = cid;
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetRenderTarget --
+ *
+ * Bind a surface object to a particular render target attachment
+ * point on the current context. Render target attachment points
+ * exist for color buffers, a depth buffer, and a stencil buffer.
+ *
+ * The SVGA3D device is quite lenient about the types of surfaces
+ * that may be used as render targets. The color buffers must
+ * all be the same size, but the depth and stencil buffers do not
+ * have to be the same size as the color buffer. All attachments
+ * are optional.
+ *
+ * Some combinations of render target formats may require software
+ * emulation, depending on the capabilities of the host graphics
+ * API and graphics hardware.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_SetRenderTarget(uint32 cid, // IN
+ SVGA3dRenderTargetType type, // IN
+ SVGA3dSurfaceImageId *target) // IN
+{
+ SVGA3dCmdSetRenderTarget *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SETRENDERTARGET, sizeof *cmd);
+ cmd->cid = cid;
+ cmd->type = type;
+ cmd->target = *target;
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetTransform --
+ *
+ * Set one of the current context's transform matrices.
+ * The 'type' parameter should be an SVGA3D_TRANSFORM_* constant.
+ *
+ * All transformation matrices follow Direct3D-style coordinate
+ * system semantics.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+
+void
+SVGA3D_SetTransform(uint32 cid, // IN
+ SVGA3dTransformType type, // IN
+ const float *matrix) // IN
+{
+ SVGA3dCmdSetTransform *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SETTRANSFORM, sizeof *cmd);
+ cmd->cid = cid;
+ cmd->type = type;
+ memcpy(&cmd->matrix[0], matrix, sizeof(float) * 16);
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetMaterial --
+ *
+ * Set all material data for one SVGA3dFace.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_SetMaterial(uint32 cid, // IN
+ SVGA3dFace face, // IN
+ const SVGA3dMaterial *material) // IN
+{
+ SVGA3dCmdSetMaterial *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SETMATERIAL, sizeof *cmd);
+ cmd->cid = cid;
+ cmd->face = face;
+ memcpy(&cmd->material, material, sizeof *material);
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetLightEnabled --
+ *
+ * Enable or disable one fixed-function light.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_SetLightEnabled(uint32 cid, // IN
+ uint32 index, // IN
+ Bool enabled) // IN
+{
+ SVGA3dCmdSetLightEnabled *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SETLIGHTENABLED, sizeof *cmd);
+ cmd->cid = cid;
+ cmd->index = index;
+ cmd->enabled = enabled;
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetLightData --
+ *
+ * Set all state for one fixed-function light.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_SetLightData(uint32 cid, // IN
+ uint32 index, // IN
+ const SVGA3dLightData *data) // IN
+{
+ SVGA3dCmdSetLightData *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SETLIGHTDATA, sizeof *cmd);
+ cmd->cid = cid;
+ cmd->index = index;
+ memcpy(&cmd->data, data, sizeof *data);
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_DefineShader --
+ *
+ * Upload the bytecode for a new shader. The bytecode is "SVGA3D
+ * format", which is theoretically a binary-compatible superset
+ * of Microsoft's DirectX shader bytecode. In practice, the
+ * SVGA3D bytecode doesn't yet have any extensions to DirectX's
+ * bytecode format.
+ *
+ * The SVGA3D device supports shader models 1.1 through 2.0.
+ *
+ * The caller chooses a shader ID (small positive integer) by
+ * which this shader will be identified in future commands. This
+ * ID is in a namespace which is per-context and per-shader-type.
+ *
+ * 'bytecodeLen' is specified in bytes. It must be a multiple of 4.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_DefineShader(uint32 cid, // IN
+ uint32 shid, // IN
+ SVGA3dShaderType type, // IN
+ const uint32 *bytecode, // IN
+ uint32 bytecodeLen) // IN
+{
+ SVGA3dCmdDefineShader *cmd;
+
+ if (bytecodeLen & 3) {
+ dbg_printf("Shader bytecode length isn't a multiple of 32 bits!");
+ }
+
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SHADER_DEFINE, sizeof *cmd + bytecodeLen);
+ cmd->cid = cid;
+ cmd->shid = shid;
+ cmd->type = type;
+ memcpy(&cmd[1], bytecode, bytecodeLen);
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_DestroyShader --
+ *
+ * Delete a shader that was created by SVGA3D_DefineShader. If
+ * the shader was the current vertex or pixel shader for its
+ * context, rendering results are undefined until a new shader is
+ * bound.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_DestroyShader(uint32 cid, // IN
+ uint32 shid, // IN
+ SVGA3dShaderType type) // IN
+{
+ SVGA3dCmdDestroyShader *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SHADER_DESTROY, sizeof *cmd);
+ cmd->cid = cid;
+ cmd->shid = shid;
+ cmd->type = type;
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetShaderConst --
+ *
+ * Set the value of a shader constant.
+ *
+ * Shader constants are analogous to uniform variables in GLSL,
+ * except that they belong to the render context rather than to
+ * an individual shader.
+ *
+ * Constants may have one of three types: A 4-vector of floats,
+ * a 4-vector of integers, or a single boolean flag.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_SetShaderConst(uint32 cid, // IN
+ uint32 reg, // IN
+ SVGA3dShaderType type, // IN
+ SVGA3dShaderConstType ctype, // IN
+ const void *value) // IN
+{
+ SVGA3dCmdSetShaderConst *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SET_SHADER_CONST, sizeof *cmd);
+ cmd->cid = cid;
+ cmd->reg = reg;
+ cmd->type = type;
+ cmd->ctype = ctype;
+
+ switch (ctype) {
+
+ case SVGA3D_CONST_TYPE_FLOAT:
+ case SVGA3D_CONST_TYPE_INT:
+ memcpy(&cmd->values, value, sizeof cmd->values);
+ break;
+
+ case SVGA3D_CONST_TYPE_BOOL:
+ memset(&cmd->values, 0, sizeof cmd->values);
+ cmd->values[0] = *(uint32*)value;
+ break;
+
+ default:
+ dbg_printf("Bad shader constant type.");
+ break;
+
+ }
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetShader --
+ *
+ * Switch active shaders. This binds a new vertex or pixel shader
+ * to the specified context.
+ *
+ * A shader ID of SVGA3D_INVALID_ID unbinds any shader, switching
+ * back to the fixed function vertex or pixel pipeline.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_SetShader(uint32 cid, // IN
+ SVGA3dShaderType type, // IN
+ uint32 shid) // IN
+{
+ SVGA3dCmdSetShader *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SET_SHADER, sizeof *cmd);
+ cmd->cid = cid;
+ cmd->type = type;
+ cmd->shid = shid;
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginPresent --
+ *
+ * Begin a PRESENT command. This reserves space for it in the
+ * FIFO, and returns a pointer to the command's rectangle array.
+ * This function must be paired with SVGA_FIFOCommitAll().
+ *
+ * Present is the SVGA3D device's way of transferring fully
+ * rendered images to the 2D portion of the SVGA device. Present
+ * is a hardware accelerated surface-to-screen blit.
+ *
+ * Important caveats:
+ *
+ * - Present may or may not modify the guest-visible 2D
+ * framebuffer. If you need to read back rendering results,
+ * use an surface DMA transfer.
+ *
+ * - Present is a good place to think about flow control
+ * between the host and the guest. If the host and guest
+ * have no other form of synchronization, the FIFO could
+ * fill with many frames worth of rendering commands. The
+ * host will visibly lag the guest. Depending on the
+ * size of the FIFO and the size of the frames, it could
+ * lag by hours! It is advisable to use FIFO fences in order
+ * to guarantee that no more than one or two Presents are
+ * queued in the FIFO at any given time.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * May or may not write to the 2D framebuffer.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_BeginPresent(uint32 sid, // IN
+ SVGA3dCopyRect **rects, // OUT
+ uint32 numRects) // IN
+{
+ SVGA3dCmdPresent *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_PRESENT, sizeof *cmd +
+ sizeof **rects * numRects);
+ cmd->sid = sid;
+ *rects = (SVGA3dCopyRect*) &cmd[1];
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginClear --
+ *
+ * Begin a CLEAR command. This reserves space for it in the FIFO,
+ * and returns a pointer to the command's rectangle array. This
+ * function must be paired with SVGA_FIFOCommitAll().
+ *
+ * Clear is a rendering operation which fills a list of
+ * rectangles with constant values on all render target types
+ * indicated by 'flags'.
+ *
+ * Clear is not affected by clipping, depth test, or other
+ * render state which affects the fragment pipeline.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * May write to attached render target surfaces.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_BeginClear(uint32 cid, // IN
+ SVGA3dClearFlag flags, // IN
+ uint32 color, // IN
+ float depth, // IN
+ uint32 stencil, // IN
+ SVGA3dRect **rects, // OUT
+ uint32 numRects) // IN
+{
+ SVGA3dCmdClear *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_CLEAR, sizeof *cmd +
+ sizeof **rects * numRects);
+ cmd->cid = cid;
+ cmd->clearFlag = flags;
+ cmd->color = color;
+ cmd->depth = depth;
+ cmd->stencil = stencil;
+ *rects = (SVGA3dRect*) &cmd[1];
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginDrawPrimitives --
+ *
+ * Begin a DRAW_PRIMITIVES command. This reserves space for it in
+ * the FIFO, and returns a pointer to the command's arrays.
+ * This function must be paired with SVGA_FIFOCommitAll().
+ *
+ * Drawing commands consist of two variable-length arrays:
+ * SVGA3dVertexDecl elements declare a set of vertex buffers to
+ * use while rendering, and SVGA3dPrimitiveRange elements specify
+ * groups of primitives each with an optional index buffer.
+ *
+ * The decls and ranges arrays are initialized to zero.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * May write to attached render target surfaces.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_BeginDrawPrimitives(uint32 cid, // IN
+ SVGA3dVertexDecl **decls, // OUT
+ uint32 numVertexDecls, // IN
+ SVGA3dPrimitiveRange **ranges, // OUT
+ uint32 numRanges) // IN
+{
+ SVGA3dCmdDrawPrimitives *cmd;
+ SVGA3dVertexDecl *declArray;
+ SVGA3dPrimitiveRange *rangeArray;
+ uint32 declSize = sizeof **decls * numVertexDecls;
+ uint32 rangeSize = sizeof **ranges * numRanges;
+
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_DRAW_PRIMITIVES, sizeof *cmd +
+ declSize + rangeSize);
+
+ cmd->cid = cid;
+ cmd->numVertexDecls = numVertexDecls;
+ cmd->numRanges = numRanges;
+
+ declArray = (SVGA3dVertexDecl*) &cmd[1];
+ rangeArray = (SVGA3dPrimitiveRange*) &declArray[numVertexDecls];
+
+ memset(declArray, 0, declSize);
+ memset(rangeArray, 0, rangeSize);
+
+ *decls = declArray;
+ *ranges = rangeArray;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginSurfaceCopy --
+ *
+ * Begin a SURFACE_COPY command. This reserves space for it in
+ * the FIFO, and returns a pointer to the command's arrays. This
+ * function must be paired with SVGA_FIFOCommitAll().
+ *
+ * The box array is initialized with zeroes.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Asynchronously copies a list of boxes from surface to surface.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_BeginSurfaceCopy(SVGA3dSurfaceImageId *src, // IN
+ SVGA3dSurfaceImageId *dest, // IN
+ SVGA3dCopyBox **boxes, // OUT
+ uint32 numBoxes) // IN
+{
+ SVGA3dCmdSurfaceCopy *cmd;
+ uint32 boxesSize = sizeof **boxes * numBoxes;
+
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SURFACE_COPY, sizeof *cmd + boxesSize);
+
+ cmd->src = *src;
+ cmd->dest = *dest;
+ *boxes = (SVGA3dCopyBox*) &cmd[1];
+
+ memset(*boxes, 0, boxesSize);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SurfaceStretchBlt --
+ *
+ * Issue a SURFACE_STRETCHBLT command: an asynchronous
+ * surface-to-surface blit, with scaling.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Asynchronously copies one box from surface to surface.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_SurfaceStretchBlt(SVGA3dSurfaceImageId *src, // IN
+ SVGA3dSurfaceImageId *dest, // IN
+ SVGA3dBox *boxSrc, // IN
+ SVGA3dBox *boxDest, // IN
+ SVGA3dStretchBltMode mode) // IN
+{
+ SVGA3dCmdSurfaceStretchBlt *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SURFACE_STRETCHBLT, sizeof *cmd);
+ cmd->src = *src;
+ cmd->dest = *dest;
+ cmd->boxSrc = *boxSrc;
+ cmd->boxDest = *boxDest;
+ cmd->mode = mode;
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetViewport --
+ *
+ * Set the current context's viewport rectangle. The viewport
+ * is clipped to the dimensions of the current render target,
+ * then all rendering is clipped to the viewport.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_SetViewport(uint32 cid, // IN
+ SVGA3dRect *rect) // IN
+{
+ SVGA3dCmdSetViewport *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SETVIEWPORT, sizeof *cmd);
+ cmd->cid = cid;
+ cmd->rect = *rect;
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetZRange --
+ *
+ * Set the range of the depth buffer to use. 'min' and 'max'
+ * are values between 0.0 and 1.0.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_SetZRange(uint32 cid, // IN
+ float zMin, // IN
+ float zMax) // IN
+{
+ SVGA3dCmdSetZRange *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SETZRANGE, sizeof *cmd);
+ cmd->cid = cid;
+ cmd->zRange.min = zMin;
+ cmd->zRange.max = zMax;
+ SVGA_FIFOCommitAll();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginSetTextureState --
+ *
+ * Begin a SETTEXTURESTATE command. This reserves space for it in
+ * the FIFO, and returns a pointer to the command's texture state
+ * array. This function must be paired with SVGA_FIFOCommitAll().
+ *
+ * This command sets rendering state which is per-texture-unit.
+ *
+ * XXX: Individual texture states need documentation. However,
+ * they are very similar to the texture states defined by
+ * Direct3D. The D3D documentation is a good starting point
+ * for understanding SVGA3D texture states.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_BeginSetTextureState(uint32 cid, // IN
+ SVGA3dTextureState **states, // OUT
+ uint32 numStates) // IN
+{
+ SVGA3dCmdSetTextureState *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SETTEXTURESTATE, sizeof *cmd +
+ sizeof **states * numStates);
+ cmd->cid = cid;
+ *states = (SVGA3dTextureState*) &cmd[1];
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginSetRenderState --
+ *
+ * Begin a SETRENDERSTATE command. This reserves space for it in
+ * the FIFO, and returns a pointer to the command's texture state
+ * array. This function must be paired with SVGA_FIFOCommitAll().
+ *
+ * This command sets rendering state which is global to the context.
+ *
+ * XXX: Individual render states need documentation. However,
+ * they are very similar to the render states defined by
+ * Direct3D. The D3D documentation is a good starting point
+ * for understanding SVGA3D render states.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_BeginSetRenderState(uint32 cid, // IN
+ SVGA3dRenderState **states, // OUT
+ uint32 numStates) // IN
+{
+ SVGA3dCmdSetRenderState *cmd;
+ cmd = SVGA3D_FIFOReserve(SVGA_3D_CMD_SETRENDERSTATE, sizeof *cmd +
+ sizeof **states * numStates);
+ cmd->cid = cid;
+ *states = (SVGA3dRenderState*) &cmd[1];
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginPresentReadback --
+ *
+ * Begin a PRESENT_READBACK command. This reserves space for it
+ * in the FIFO, and returns a pointer to the command's SVGA3dRect
+ * array. This function must be paired with
+ * SVGA_FIFOCommitAll().
+ *
+ * This command will update the 2D framebuffer with the most
+ * recently presented data in the supplied regions.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_BeginPresentReadback(SVGA3dRect **rects, // OUT
+ uint32 numRects) // IN
+{
+ void *cmd;
+ cmd = (void *) SVGA3D_FIFOReserve(SVGA_3D_CMD_PRESENT_READBACK,
+ sizeof **rects * numRects);
+ *rects = (SVGA3dRect*) cmd;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginBlitSurfaceToScreen --
+ *
+ * Begin a BLIT_SURFACE_TO_SCREEN command. This reserves space
+ * for it in the FIFO, and optionally returns a pointer to the
+ * command's clip rectangle array. This function must be paired
+ * with SVGA_FIFOCommitAll().
+ *
+ * Copy an SVGA3D surface image to a Screen Object. This command
+ * requires the SVGA Screen Object capability to be present.
+ * Copies a rectangular region of a surface image to a
+ * rectangular region of a screen or a portion of the virtual
+ * coordinate space that contains all screens.
+ *
+ * If destScreenId is SVGA_ID_INVALID, the destination rectangle
+ * is in virtual coordinates rather than in screen coordinates.
+ *
+ * If the source and destination rectangle are different sizes,
+ * the image will be scaled using a backend-specific algorithm.
+ *
+ * This command may optionally include a clip rectangle list. If
+ * zero rectangles are specified, there is no clip region. The
+ * entire destination rectangle is drawn. If one or more
+ * rectangles are specified, they describe a destination clipping
+ * region in the same coordinate system as destRect.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Writes to the Screen Object.
+ * Begins a new FIFO command.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_BeginBlitSurfaceToScreen(const SVGA3dSurfaceImageId *srcImage, // IN
+ const SVGASignedRect *srcRect, // IN
+ uint32 destScreenId, // IN (optional)
+ const SVGASignedRect *destRect, // IN
+ SVGASignedRect **clipRects, // IN (optional)
+ uint32 numClipRects) // IN (optional)
+{
+ SVGA3dCmdBlitSurfaceToScreen *cmd =
+ SVGA3D_FIFOReserve(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN,
+ sizeof *cmd + numClipRects * sizeof(SVGASignedRect));
+
+ cmd->srcImage = *srcImage;
+ cmd->srcRect = *srcRect;
+ cmd->destScreenId = destScreenId;
+ cmd->destRect = *destRect;
+
+ if (clipRects) {
+ *clipRects = (SVGASignedRect*) &cmd[1];
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BlitSurfaceToScreen --
+ *
+ * This is a convenience wrapper around
+ * SVGA3D_BeginBlitSurfaceToScreen, for callers who do not
+ * require a clip rectangle list.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Writes to the Screen Object.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+SVGA3D_BlitSurfaceToScreen(const SVGA3dSurfaceImageId *srcImage, // IN
+ const SVGASignedRect *srcRect, // IN
+ uint32 destScreenId, // IN (optional)
+ const SVGASignedRect *destRect) // IN
+{
+ SVGA3D_BeginBlitSurfaceToScreen(srcImage, srcRect, destScreenId, destRect, NULL, 0);
+ SVGA_FIFOCommitAll();
+}
diff --git a/vmware/svga3d.h b/vmware/svga3d.h
new file mode 100644
index 0000000..1242754
--- /dev/null
+++ b/vmware/svga3d.h
@@ -0,0 +1,149 @@
+/**********************************************************
+ * Copyright 2008-2009 VMware, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/*
+ * svga3d.h --
+ *
+ * FIFO command level interface to the SVGA3D protocol used by
+ * the VMware SVGA device.
+ */
+
+#ifndef __SVGA3D_H__
+#define __SVGA3D_H__
+
+#include "svga.h"
+#include "svga3d_reg.h"
+
+
+/*
+ * SVGA Device Interoperability
+ */
+
+Bool SVGA3D_Init(void);
+void SVGA3D_BeginPresent(uint32 sid, SVGA3dCopyRect **rects, uint32 numRects);
+void SVGA3D_BeginPresentReadback(SVGA3dRect **rects, uint32 numRects);
+void SVGA3D_BlitSurfaceToScreen(const SVGA3dSurfaceImageId *srcImage,
+ const SVGASignedRect *srcRect,
+ uint32 destScreenId,
+ const SVGASignedRect *destRect);
+void SVGA3D_BeginBlitSurfaceToScreen(const SVGA3dSurfaceImageId *srcImage,
+ const SVGASignedRect *srcRect,
+ uint32 destScreenId,
+ const SVGASignedRect *destRect,
+ SVGASignedRect **clipRects,
+ uint32 numClipRects);
+
+
+/*
+ * Surface Management
+ */
+
+void SVGA3D_BeginDefineSurface(uint32 sid,
+ SVGA3dSurfaceFlags flags,
+ SVGA3dSurfaceFormat format,
+ SVGA3dSurfaceFace **faces,
+ SVGA3dSize **mipSizes,
+ uint32 numMipSizes);
+void SVGA3D_DestroySurface(uint32 sid);
+void SVGA3D_BeginSurfaceDMA(SVGA3dGuestImage *guestImage,
+ SVGA3dSurfaceImageId *hostImage,
+ SVGA3dTransferType transfer,
+ SVGA3dCopyBox **boxes,
+ uint32 numBoxes);
+
+
+/*
+ * Context Management
+ */
+
+void SVGA3D_DefineContext(uint32 cid);
+void SVGA3D_DestroyContext(uint32 cid);
+
+
+/*
+ * Drawing Operations
+ */
+
+void SVGA3D_BeginClear(uint32 cid, SVGA3dClearFlag flags,
+ uint32 color, float depth, uint32 stencil,
+ SVGA3dRect **rects, uint32 numRects);
+void SVGA3D_BeginDrawPrimitives(uint32 cid,
+ SVGA3dVertexDecl **decls,
+ uint32 numVertexDecls,
+ SVGA3dPrimitiveRange **ranges,
+ uint32 numRanges);
+
+/*
+ * Blits
+ */
+
+void SVGA3D_BeginSurfaceCopy(SVGA3dSurfaceImageId *src,
+ SVGA3dSurfaceImageId *dest,
+ SVGA3dCopyBox **boxes, uint32 numBoxes);
+
+void SVGA3D_SurfaceStretchBlt(SVGA3dSurfaceImageId *src,
+ SVGA3dSurfaceImageId *dest,
+ SVGA3dBox *boxSrc, SVGA3dBox *boxDest,
+ SVGA3dStretchBltMode mode);
+
+/*
+ * Shared FFP/Shader Render State
+ */
+
+void SVGA3D_SetRenderTarget(uint32 cid, SVGA3dRenderTargetType type,
+ SVGA3dSurfaceImageId *target);
+void SVGA3D_SetZRange(uint32 cid, float zMin, float zMax);
+void SVGA3D_SetViewport(uint32 cid, SVGA3dRect *rect);
+void SVGA3D_SetScissorRect(uint32 cid, SVGA3dRect *rect);
+void SVGA3D_SetClipPlane(uint32 cid, uint32 index, const float *plane);
+void SVGA3D_BeginSetTextureState(uint32 cid, SVGA3dTextureState **states,
+ uint32 numStates);
+void SVGA3D_BeginSetRenderState(uint32 cid, SVGA3dRenderState **states,
+ uint32 numStates);
+
+
+/*
+ * Fixed-function Render State
+ */
+
+void SVGA3D_SetTransform(uint32 cid, SVGA3dTransformType type,
+ const float *matrix);
+void SVGA3D_SetMaterial(uint32 cid, SVGA3dFace face, const SVGA3dMaterial *material);
+void SVGA3D_SetLightData(uint32 cid, uint32 index, const SVGA3dLightData *data);
+void SVGA3D_SetLightEnabled(uint32 cid, uint32 index, Bool enabled);
+
+
+/*
+ * Shaders
+ */
+
+void SVGA3D_DefineShader(uint32 cid, uint32 shid, SVGA3dShaderType type,
+ const uint32 *bytecode, uint32 bytecodeLen);
+void SVGA3D_DestroyShader(uint32 cid, uint32 shid, SVGA3dShaderType type);
+void SVGA3D_SetShaderConst(uint32 cid, uint32 reg, SVGA3dShaderType type,
+ SVGA3dShaderConstType ctype, const void *value);
+void SVGA3D_SetShader(uint32 cid, SVGA3dShaderType type, uint32 shid);
+
+#endif /* __SVGA3D_H__ */
diff --git a/vmware/svga3d_caps.h b/vmware/svga3d_caps.h
new file mode 100644
index 0000000..3eab532
--- /dev/null
+++ b/vmware/svga3d_caps.h
@@ -0,0 +1,140 @@
+/**********************************************************
+ * Copyright 2007-2009 VMware, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/*
+ * svga3d_caps.h --
+ *
+ * Definitions for SVGA3D hardware capabilities. Capabilities
+ * are used to query for optional rendering features during
+ * driver initialization. The capability data is stored as very
+ * basic key/value dictionary within the "FIFO register" memory
+ * area at the beginning of BAR2.
+ *
+ * Note that these definitions are only for 3D capabilities.
+ * The SVGA device also has "device capabilities" and "FIFO
+ * capabilities", which are non-3D-specific and are stored as
+ * bitfields rather than key/value pairs.
+ */
+
+#ifndef _SVGA3D_CAPS_H_
+#define _SVGA3D_CAPS_H_
+
+#define SVGA_FIFO_3D_CAPS_SIZE (SVGA_FIFO_3D_CAPS_LAST - \
+ SVGA_FIFO_3D_CAPS + 1)
+
+
+/*
+ * SVGA3dCapsRecordType
+ *
+ * Record types that can be found in the caps block.
+ * Related record types are grouped together numerically so that
+ * SVGA3dCaps_FindRecord() can be applied on a range of record
+ * types.
+ */
+
+typedef enum {
+ SVGA3DCAPS_RECORD_UNKNOWN = 0,
+ SVGA3DCAPS_RECORD_DEVCAPS_MIN = 0x100,
+ SVGA3DCAPS_RECORD_DEVCAPS = 0x100,
+ SVGA3DCAPS_RECORD_DEVCAPS_MAX = 0x1ff,
+ SVGA3DCAPS_RECORD_DEVCAPS_FORCE32 = 0xffffffff
+} SVGA3dCapsRecordType;
+
+
+/*
+ * SVGA3dCapsRecordHeader
+ *
+ * Header field leading each caps block record. Contains the offset (in
+ * register words, NOT bytes) to the next caps block record (or the end
+ * of caps block records which will be a zero word) and the record type
+ * as defined above.
+ */
+
+typedef
+struct SVGA3dCapsRecordHeader {
+ uint32 length;
+ SVGA3dCapsRecordType type;
+}
+SVGA3dCapsRecordHeader;
+
+
+/*
+ * SVGA3dCapsRecord
+ *
+ * Caps block record; "data" is a placeholder for the actual data structure
+ * contained within the record; for example a record containing a FOOBAR
+ * structure would be of size "sizeof(SVGA3dCapsRecordHeader) +
+ * sizeof(FOOBAR)".
+ */
+
+typedef
+struct SVGA3dCapsRecord {
+ SVGA3dCapsRecordHeader header;
+ uint32 data[1];
+}
+SVGA3dCapsRecord;
+
+
+typedef uint32 SVGA3dCapPair[2];
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3dCaps_FindRecord
+ *
+ * Finds the record with the highest-valued type within the given range
+ * in the caps block.
+ *
+ * Result: pointer to found record, or NULL if not found.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static INLINE SVGA3dCapsRecord *
+SVGA3dCaps_FindRecord(const uint32 *capsBlock,
+ SVGA3dCapsRecordType recordTypeMin,
+ SVGA3dCapsRecordType recordTypeMax)
+{
+ SVGA3dCapsRecord *record, *found = NULL;
+ uint32 offset;
+
+ /*
+ * Search linearly through the caps block records for the specified type.
+ */
+ for (offset = 0; capsBlock[offset] != 0; offset += capsBlock[offset]) {
+ record = (SVGA3dCapsRecord *) (capsBlock + offset);
+ if ((record->header.type >= recordTypeMin) &&
+ (record->header.type <= recordTypeMax) &&
+ (!found || (record->header.type > found->header.type))) {
+ found = record;
+ }
+ }
+
+ return found;
+}
+
+
+#endif // _SVGA3D_CAPS_H_
diff --git a/vmware/svga3d_reg.h b/vmware/svga3d_reg.h
new file mode 100644
index 0000000..9b009d5
--- /dev/null
+++ b/vmware/svga3d_reg.h
@@ -0,0 +1,3189 @@
+/**********************************************************
+ * Copyright 1998-2009 VMware, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/*
+ * svga3d_reg.h --
+ *
+ * SVGA 3D hardware definitions
+ */
+
+#ifndef _SVGA3D_REG_H_
+#define _SVGA3D_REG_H_
+
+#include "svga_reg.h"
+
+/*
+ * Extra types
+ */
+
+typedef struct uint64 {
+ uint32 low;
+ uint32 hi;
+} uint64;
+
+typedef uint16 SVGA3dLogicOp;
+typedef uint32 SVGA3dSurface1Flags;
+typedef uint32 SVGA3dSurface2Flags;
+typedef uint64 SVGA3dSurfaceAllFlags;
+typedef uint32 SVGAMobId;
+
+#define SVGA3D_INVALID_ID ((uint32)-1)
+
+typedef uint64 PPN64;
+typedef uint32 PPN;
+
+/*
+ * Limits
+ */
+#define SVGA3D_NUM_TEXTURE_UNITS 32
+#define SVGA3D_NUM_LIGHTS 8
+
+/*
+ * 3D Hardware Version
+ *
+ * The hardware version is stored in the SVGA_FIFO_3D_HWVERSION fifo
+ * register. Is set by the host and read by the guest. This lets
+ * us make new guest drivers which are backwards-compatible with old
+ * SVGA hardware revisions. It does not let us support old guest
+ * drivers. Good enough for now.
+ *
+ */
+
+#define SVGA3D_MAKE_HWVERSION(major, minor) (((unsigned long)(major) << 16) | ((unsigned long)(minor) & 0xFF))
+#define SVGA3D_MAJOR_HWVERSION(version) ((unsigned long)(version) >> 16)
+#define SVGA3D_MINOR_HWVERSION(version) ((unsigned long)(version) & 0xFF)
+
+typedef enum {
+ SVGA3D_HWVERSION_WS5_RC1 = SVGA3D_MAKE_HWVERSION(0, 1),
+ SVGA3D_HWVERSION_WS5_RC2 = SVGA3D_MAKE_HWVERSION(0, 2),
+ SVGA3D_HWVERSION_WS51_RC1 = SVGA3D_MAKE_HWVERSION(0, 3),
+ SVGA3D_HWVERSION_WS6_B1 = SVGA3D_MAKE_HWVERSION(1, 1),
+ SVGA3D_HWVERSION_FUSION_11 = SVGA3D_MAKE_HWVERSION(1, 4),
+ SVGA3D_HWVERSION_WS65_B1 = SVGA3D_MAKE_HWVERSION(2, 0),
+ SVGA3D_HWVERSION_WS8_B1 = SVGA3D_MAKE_HWVERSION(2, 1),
+ SVGA3D_HWVERSION_CURRENT = SVGA3D_HWVERSION_WS8_B1,
+} SVGA3dHardwareVersion;
+
+/*
+ * Generic Types
+ */
+
+typedef uint32 SVGA3dBool; /* 32-bit Bool definition */
+#define SVGA3D_NUM_CLIPPLANES 6
+#define SVGA3D_MAX_SIMULTANEOUS_RENDER_TARGETS 8
+#define SVGA3D_MAX_CONTEXT_IDS 256
+#define SVGA3D_MAX_SURFACE_IDS (32 * 1024)
+
+/*
+ * Surface formats.
+ *
+ * If you modify this list, be sure to keep GLUtil.c in sync. It
+ * includes the internal format definition of each surface in
+ * GLUtil_ConvertSurfaceFormat, and it contains a table of
+ * human-readable names in GLUtil_GetFormatName.
+ */
+
+typedef enum SVGA3dSurfaceFormat {
+ SVGA3D_FORMAT_INVALID = 0,
+
+ SVGA3D_X8R8G8B8 = 1,
+ SVGA3D_A8R8G8B8 = 2,
+
+ SVGA3D_R5G6B5 = 3,
+ SVGA3D_X1R5G5B5 = 4,
+ SVGA3D_A1R5G5B5 = 5,
+ SVGA3D_A4R4G4B4 = 6,
+
+ SVGA3D_Z_D32 = 7,
+ SVGA3D_Z_D16 = 8,
+ SVGA3D_Z_D24S8 = 9,
+ SVGA3D_Z_D15S1 = 10,
+
+ SVGA3D_LUMINANCE8 = 11,
+ SVGA3D_LUMINANCE4_ALPHA4 = 12,
+ SVGA3D_LUMINANCE16 = 13,
+ SVGA3D_LUMINANCE8_ALPHA8 = 14,
+
+ SVGA3D_DXT1 = 15,
+ SVGA3D_DXT2 = 16,
+ SVGA3D_DXT3 = 17,
+ SVGA3D_DXT4 = 18,
+ SVGA3D_DXT5 = 19,
+
+ SVGA3D_BUMPU8V8 = 20,
+ SVGA3D_BUMPL6V5U5 = 21,
+ SVGA3D_BUMPX8L8V8U8 = 22,
+ SVGA3D_BUMPL8V8U8 = 23,
+
+ SVGA3D_ARGB_S10E5 = 24, /* 16-bit floating-point ARGB */
+ SVGA3D_ARGB_S23E8 = 25, /* 32-bit floating-point ARGB */
+
+ SVGA3D_A2R10G10B10 = 26,
+
+ /* signed formats */
+ SVGA3D_V8U8 = 27,
+ SVGA3D_Q8W8V8U8 = 28,
+ SVGA3D_CxV8U8 = 29,
+
+ /* mixed formats */
+ SVGA3D_X8L8V8U8 = 30,
+ SVGA3D_A2W10V10U10 = 31,
+
+ SVGA3D_ALPHA8 = 32,
+
+ /* Single- and dual-component floating point formats */
+ SVGA3D_R_S10E5 = 33,
+ SVGA3D_R_S23E8 = 34,
+ SVGA3D_RG_S10E5 = 35,
+ SVGA3D_RG_S23E8 = 36,
+
+ /*
+ * Any surface can be used as a buffer object, but SVGA3D_BUFFER is
+ * the most efficient format to use when creating new surfaces
+ * expressly for index or vertex data.
+ */
+
+ SVGA3D_BUFFER = 37,
+
+ SVGA3D_Z_D24X8 = 38,
+
+ SVGA3D_V16U16 = 39,
+
+ SVGA3D_G16R16 = 40,
+ SVGA3D_A16B16G16R16 = 41,
+
+ /* Packed Video formats */
+ SVGA3D_UYVY = 42,
+ SVGA3D_YUY2 = 43,
+
+ /* Planar video formats */
+ SVGA3D_NV12 = 44,
+
+ /* Video format with alpha */
+ SVGA3D_AYUV = 45,
+
+ SVGA3D_BC4_UNORM = 108,
+ SVGA3D_BC5_UNORM = 111,
+
+ /* Advanced D3D9 depth formats. */
+ SVGA3D_Z_DF16 = 118,
+ SVGA3D_Z_DF24 = 119,
+ SVGA3D_Z_D24S8_INT = 120,
+
+ SVGA3D_FORMAT_MAX
+} SVGA3dSurfaceFormat;
+
+typedef uint32 SVGA3dColor; /* a, r, g, b */
+
+/*
+ * These match the D3DFORMAT_OP definitions used by Direct3D. We need
+ * them so that we can query the host for what the supported surface
+ * operations are (when we're using the D3D backend, in particular),
+ * and so we can send those operations to the guest.
+ */
+typedef enum {
+ SVGA3DFORMAT_OP_TEXTURE = 0x00000001,
+ SVGA3DFORMAT_OP_VOLUMETEXTURE = 0x00000002,
+ SVGA3DFORMAT_OP_CUBETEXTURE = 0x00000004,
+ SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET = 0x00000008,
+ SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET = 0x00000010,
+ SVGA3DFORMAT_OP_ZSTENCIL = 0x00000040,
+ SVGA3DFORMAT_OP_ZSTENCIL_WITH_ARBITRARY_COLOR_DEPTH = 0x00000080,
+
+/*
+ * This format can be used as a render target if the current display mode
+ * is the same depth if the alpha channel is ignored. e.g. if the device
+ * can render to A8R8G8B8 when the display mode is X8R8G8B8, then the
+ * format op list entry for A8R8G8B8 should have this cap.
+ */
+ SVGA3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET = 0x00000100,
+
+/*
+ * This format contains DirectDraw support (including Flip). This flag
+ * should not to be set on alpha formats.
+ */
+ SVGA3DFORMAT_OP_DISPLAYMODE = 0x00000400,
+
+/*
+ * The rasterizer can support some level of Direct3D support in this format
+ * and implies that the driver can create a Context in this mode (for some
+ * render target format). When this flag is set, the SVGA3DFORMAT_OP_DISPLAYMODE
+ * flag must also be set.
+ */
+ SVGA3DFORMAT_OP_3DACCELERATION = 0x00000800,
+
+/*
+ * This is set for a private format when the driver has put the bpp in
+ * the structure.
+ */
+ SVGA3DFORMAT_OP_PIXELSIZE = 0x00001000,
+
+/*
+ * Indicates that this format can be converted to any RGB format for which
+ * SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB is specified
+ */
+ SVGA3DFORMAT_OP_CONVERT_TO_ARGB = 0x00002000,
+
+/*
+ * Indicates that this format can be used to create offscreen plain surfaces.
+ */
+ SVGA3DFORMAT_OP_OFFSCREENPLAIN = 0x00004000,
+
+/*
+ * Indicated that this format can be read as an SRGB texture (meaning that the
+ * sampler will linearize the looked up data)
+ */
+ SVGA3DFORMAT_OP_SRGBREAD = 0x00008000,
+
+/*
+ * Indicates that this format can be used in the bumpmap instructions
+ */
+ SVGA3DFORMAT_OP_BUMPMAP = 0x00010000,
+
+/*
+ * Indicates that this format can be sampled by the displacement map sampler
+ */
+ SVGA3DFORMAT_OP_DMAP = 0x00020000,
+
+/*
+ * Indicates that this format cannot be used with texture filtering
+ */
+ SVGA3DFORMAT_OP_NOFILTER = 0x00040000,
+
+/*
+ * Indicates that format conversions are supported to this RGB format if
+ * SVGA3DFORMAT_OP_CONVERT_TO_ARGB is specified in the source format.
+ */
+ SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB = 0x00080000,
+
+/*
+ * Indicated that this format can be written as an SRGB target (meaning that the
+ * pixel pipe will DE-linearize data on output to format)
+ */
+ SVGA3DFORMAT_OP_SRGBWRITE = 0x00100000,
+
+/*
+ * Indicates that this format cannot be used with alpha blending
+ */
+ SVGA3DFORMAT_OP_NOALPHABLEND = 0x00200000,
+
+/*
+ * Indicates that the device can auto-generated sublevels for resources
+ * of this format
+ */
+ SVGA3DFORMAT_OP_AUTOGENMIPMAP = 0x00400000,
+
+/*
+ * Indicates that this format can be used by vertex texture sampler
+ */
+ SVGA3DFORMAT_OP_VERTEXTEXTURE = 0x00800000,
+
+/*
+ * Indicates that this format supports neither texture coordinate wrap
+ * modes, nor mipmapping
+ */
+ SVGA3DFORMAT_OP_NOTEXCOORDWRAPNORMIP = 0x01000000
+} SVGA3dFormatOp;
+
+/*
+ * This structure is a conversion of SVGA3DFORMAT_OP_*.
+ * Entries must be located at the same position.
+ */
+typedef union {
+ uint32 value;
+ struct {
+ uint32 texture : 1;
+ uint32 volumeTexture : 1;
+ uint32 cubeTexture : 1;
+ uint32 offscreenRenderTarget : 1;
+ uint32 sameFormatRenderTarget : 1;
+ uint32 unknown1 : 1;
+ uint32 zStencil : 1;
+ uint32 zStencilArbitraryDepth : 1;
+ uint32 sameFormatUpToAlpha : 1;
+ uint32 unknown2 : 1;
+ uint32 displayMode : 1;
+ uint32 acceleration3d : 1;
+ uint32 pixelSize : 1;
+ uint32 convertToARGB : 1;
+ uint32 offscreenPlain : 1;
+ uint32 sRGBRead : 1;
+ uint32 bumpMap : 1;
+ uint32 dmap : 1;
+ uint32 noFilter : 1;
+ uint32 memberOfGroupARGB : 1;
+ uint32 sRGBWrite : 1;
+ uint32 noAlphaBlend : 1;
+ uint32 autoGenMipMap : 1;
+ uint32 vertexTexture : 1;
+ uint32 noTexCoordWrapNorMip : 1;
+ };
+} SVGA3dSurfaceFormatCaps;
+
+/*
+ * SVGA_3D_CMD_SETRENDERSTATE Types. All value types
+ * must fit in a uint32.
+ */
+
+typedef enum {
+ SVGA3D_RS_INVALID = 0,
+ SVGA3D_RS_ZENABLE = 1, /* SVGA3dBool */
+ SVGA3D_RS_ZWRITEENABLE = 2, /* SVGA3dBool */
+ SVGA3D_RS_ALPHATESTENABLE = 3, /* SVGA3dBool */
+ SVGA3D_RS_DITHERENABLE = 4, /* SVGA3dBool */
+ SVGA3D_RS_BLENDENABLE = 5, /* SVGA3dBool */
+ SVGA3D_RS_FOGENABLE = 6, /* SVGA3dBool */
+ SVGA3D_RS_SPECULARENABLE = 7, /* SVGA3dBool */
+ SVGA3D_RS_STENCILENABLE = 8, /* SVGA3dBool */
+ SVGA3D_RS_LIGHTINGENABLE = 9, /* SVGA3dBool */
+ SVGA3D_RS_NORMALIZENORMALS = 10, /* SVGA3dBool */
+ SVGA3D_RS_POINTSPRITEENABLE = 11, /* SVGA3dBool */
+ SVGA3D_RS_POINTSCALEENABLE = 12, /* SVGA3dBool */
+ SVGA3D_RS_STENCILREF = 13, /* uint32 */
+ SVGA3D_RS_STENCILMASK = 14, /* uint32 */
+ SVGA3D_RS_STENCILWRITEMASK = 15, /* uint32 */
+ SVGA3D_RS_FOGSTART = 16, /* float */
+ SVGA3D_RS_FOGEND = 17, /* float */
+ SVGA3D_RS_FOGDENSITY = 18, /* float */
+ SVGA3D_RS_POINTSIZE = 19, /* float */
+ SVGA3D_RS_POINTSIZEMIN = 20, /* float */
+ SVGA3D_RS_POINTSIZEMAX = 21, /* float */
+ SVGA3D_RS_POINTSCALE_A = 22, /* float */
+ SVGA3D_RS_POINTSCALE_B = 23, /* float */
+ SVGA3D_RS_POINTSCALE_C = 24, /* float */
+ SVGA3D_RS_FOGCOLOR = 25, /* SVGA3dColor */
+ SVGA3D_RS_AMBIENT = 26, /* SVGA3dColor */
+ SVGA3D_RS_CLIPPLANEENABLE = 27, /* SVGA3dClipPlanes */
+ SVGA3D_RS_FOGMODE = 28, /* SVGA3dFogMode */
+ SVGA3D_RS_FILLMODE = 29, /* SVGA3dFillMode */
+ SVGA3D_RS_SHADEMODE = 30, /* SVGA3dShadeMode */
+ SVGA3D_RS_LINEPATTERN = 31, /* SVGA3dLinePattern */
+ SVGA3D_RS_SRCBLEND = 32, /* SVGA3dBlendOp */
+ SVGA3D_RS_DSTBLEND = 33, /* SVGA3dBlendOp */
+ SVGA3D_RS_BLENDEQUATION = 34, /* SVGA3dBlendEquation */
+ SVGA3D_RS_CULLMODE = 35, /* SVGA3dFace */
+ SVGA3D_RS_ZFUNC = 36, /* SVGA3dCmpFunc */
+ SVGA3D_RS_ALPHAFUNC = 37, /* SVGA3dCmpFunc */
+ SVGA3D_RS_STENCILFUNC = 38, /* SVGA3dCmpFunc */
+ SVGA3D_RS_STENCILFAIL = 39, /* SVGA3dStencilOp */
+ SVGA3D_RS_STENCILZFAIL = 40, /* SVGA3dStencilOp */
+ SVGA3D_RS_STENCILPASS = 41, /* SVGA3dStencilOp */
+ SVGA3D_RS_ALPHAREF = 42, /* float (0.0 .. 1.0) */
+ SVGA3D_RS_FRONTWINDING = 43, /* SVGA3dFrontWinding */
+ SVGA3D_RS_COORDINATETYPE = 44, /* SVGA3dCoordinateType */
+ SVGA3D_RS_ZBIAS = 45, /* float */
+ SVGA3D_RS_RANGEFOGENABLE = 46, /* SVGA3dBool */
+ SVGA3D_RS_COLORWRITEENABLE = 47, /* SVGA3dColorMask */
+ SVGA3D_RS_VERTEXMATERIALENABLE = 48, /* SVGA3dBool */
+ SVGA3D_RS_DIFFUSEMATERIALSOURCE = 49, /* SVGA3dVertexMaterial */
+ SVGA3D_RS_SPECULARMATERIALSOURCE = 50, /* SVGA3dVertexMaterial */
+ SVGA3D_RS_AMBIENTMATERIALSOURCE = 51, /* SVGA3dVertexMaterial */
+ SVGA3D_RS_EMISSIVEMATERIALSOURCE = 52, /* SVGA3dVertexMaterial */
+ SVGA3D_RS_TEXTUREFACTOR = 53, /* SVGA3dColor */
+ SVGA3D_RS_LOCALVIEWER = 54, /* SVGA3dBool */
+ SVGA3D_RS_SCISSORTESTENABLE = 55, /* SVGA3dBool */
+ SVGA3D_RS_BLENDCOLOR = 56, /* SVGA3dColor */
+ SVGA3D_RS_STENCILENABLE2SIDED = 57, /* SVGA3dBool */
+ SVGA3D_RS_CCWSTENCILFUNC = 58, /* SVGA3dCmpFunc */
+ SVGA3D_RS_CCWSTENCILFAIL = 59, /* SVGA3dStencilOp */
+ SVGA3D_RS_CCWSTENCILZFAIL = 60, /* SVGA3dStencilOp */
+ SVGA3D_RS_CCWSTENCILPASS = 61, /* SVGA3dStencilOp */
+ SVGA3D_RS_VERTEXBLEND = 62, /* SVGA3dVertexBlendFlags */
+ SVGA3D_RS_SLOPESCALEDEPTHBIAS = 63, /* float */
+ SVGA3D_RS_DEPTHBIAS = 64, /* float */
+
+
+ /*
+ * Output Gamma Level
+ *
+ * Output gamma effects the gamma curve of colors that are output from the
+ * rendering pipeline. A value of 1.0 specifies a linear color space. If the
+ * value is <= 0.0, gamma correction is ignored and linear color space is
+ * used.
+ */
+
+ SVGA3D_RS_OUTPUTGAMMA = 65, /* float */
+ SVGA3D_RS_ZVISIBLE = 66, /* SVGA3dBool */
+ SVGA3D_RS_LASTPIXEL = 67, /* SVGA3dBool */
+ SVGA3D_RS_CLIPPING = 68, /* SVGA3dBool */
+ SVGA3D_RS_WRAP0 = 69, /* SVGA3dWrapFlags */
+ SVGA3D_RS_WRAP1 = 70, /* SVGA3dWrapFlags */
+ SVGA3D_RS_WRAP2 = 71, /* SVGA3dWrapFlags */
+ SVGA3D_RS_WRAP3 = 72, /* SVGA3dWrapFlags */
+ SVGA3D_RS_WRAP4 = 73, /* SVGA3dWrapFlags */
+ SVGA3D_RS_WRAP5 = 74, /* SVGA3dWrapFlags */
+ SVGA3D_RS_WRAP6 = 75, /* SVGA3dWrapFlags */
+ SVGA3D_RS_WRAP7 = 76, /* SVGA3dWrapFlags */
+ SVGA3D_RS_WRAP8 = 77, /* SVGA3dWrapFlags */
+ SVGA3D_RS_WRAP9 = 78, /* SVGA3dWrapFlags */
+ SVGA3D_RS_WRAP10 = 79, /* SVGA3dWrapFlags */
+ SVGA3D_RS_WRAP11 = 80, /* SVGA3dWrapFlags */
+ SVGA3D_RS_WRAP12 = 81, /* SVGA3dWrapFlags */
+ SVGA3D_RS_WRAP13 = 82, /* SVGA3dWrapFlags */
+ SVGA3D_RS_WRAP14 = 83, /* SVGA3dWrapFlags */
+ SVGA3D_RS_WRAP15 = 84, /* SVGA3dWrapFlags */
+ SVGA3D_RS_MULTISAMPLEANTIALIAS = 85, /* SVGA3dBool */
+ SVGA3D_RS_MULTISAMPLEMASK = 86, /* uint32 */
+ SVGA3D_RS_INDEXEDVERTEXBLENDENABLE = 87, /* SVGA3dBool */
+ SVGA3D_RS_TWEENFACTOR = 88, /* float */
+ SVGA3D_RS_ANTIALIASEDLINEENABLE = 89, /* SVGA3dBool */
+ SVGA3D_RS_COLORWRITEENABLE1 = 90, /* SVGA3dColorMask */
+ SVGA3D_RS_COLORWRITEENABLE2 = 91, /* SVGA3dColorMask */
+ SVGA3D_RS_COLORWRITEENABLE3 = 92, /* SVGA3dColorMask */
+ SVGA3D_RS_SEPARATEALPHABLENDENABLE = 93, /* SVGA3dBool */
+ SVGA3D_RS_SRCBLENDALPHA = 94, /* SVGA3dBlendOp */
+ SVGA3D_RS_DSTBLENDALPHA = 95, /* SVGA3dBlendOp */
+ SVGA3D_RS_BLENDEQUATIONALPHA = 96, /* SVGA3dBlendEquation */
+ SVGA3D_RS_TRANSPARENCYANTIALIAS = 97, /* SVGA3dTransparencyAntialiasType */
+ SVGA3D_RS_LINEAA = 98, /* SVGA3dBool */
+ SVGA3D_RS_LINEWIDTH = 99, /* float */
+ SVGA3D_RS_MAX
+} SVGA3dRenderStateName;
+
+typedef enum {
+ SVGA3D_TRANSPARENCYANTIALIAS_NORMAL = 0,
+ SVGA3D_TRANSPARENCYANTIALIAS_ALPHATOCOVERAGE = 1,
+ SVGA3D_TRANSPARENCYANTIALIAS_SUPERSAMPLE = 2,
+ SVGA3D_TRANSPARENCYANTIALIAS_MAX
+} SVGA3dTransparencyAntialiasType;
+
+typedef enum {
+ SVGA3D_VERTEXMATERIAL_NONE = 0, /* Use the value in the current material */
+ SVGA3D_VERTEXMATERIAL_DIFFUSE = 1, /* Use the value in the diffuse component */
+ SVGA3D_VERTEXMATERIAL_SPECULAR = 2, /* Use the value in the specular component */
+} SVGA3dVertexMaterial;
+
+typedef enum {
+ SVGA3D_FILLMODE_INVALID = 0,
+ SVGA3D_FILLMODE_POINT = 1,
+ SVGA3D_FILLMODE_LINE = 2,
+ SVGA3D_FILLMODE_FILL = 3,
+ SVGA3D_FILLMODE_MAX
+} SVGA3dFillModeType;
+
+
+typedef
+union {
+ struct {
+ uint16 mode; /* SVGA3dFillModeType */
+ uint16 face; /* SVGA3dFace */
+ };
+ uint32 uintValue;
+} SVGA3dFillMode;
+
+typedef enum {
+ SVGA3D_SHADEMODE_INVALID = 0,
+ SVGA3D_SHADEMODE_FLAT = 1,
+ SVGA3D_SHADEMODE_SMOOTH = 2,
+ SVGA3D_SHADEMODE_PHONG = 3, /* Not supported */
+ SVGA3D_SHADEMODE_MAX
+} SVGA3dShadeMode;
+
+typedef
+union {
+ struct {
+ uint16 repeat;
+ uint16 pattern;
+ };
+ uint32 uintValue;
+} SVGA3dLinePattern;
+
+typedef enum {
+ SVGA3D_BLENDOP_INVALID = 0,
+ SVGA3D_BLENDOP_ZERO = 1,
+ SVGA3D_BLENDOP_ONE = 2,
+ SVGA3D_BLENDOP_SRCCOLOR = 3,
+ SVGA3D_BLENDOP_INVSRCCOLOR = 4,
+ SVGA3D_BLENDOP_SRCALPHA = 5,
+ SVGA3D_BLENDOP_INVSRCALPHA = 6,
+ SVGA3D_BLENDOP_DESTALPHA = 7,
+ SVGA3D_BLENDOP_INVDESTALPHA = 8,
+ SVGA3D_BLENDOP_DESTCOLOR = 9,
+ SVGA3D_BLENDOP_INVDESTCOLOR = 10,
+ SVGA3D_BLENDOP_SRCALPHASAT = 11,
+ SVGA3D_BLENDOP_BLENDFACTOR = 12,
+ SVGA3D_BLENDOP_INVBLENDFACTOR = 13,
+ SVGA3D_BLENDOP_MAX
+} SVGA3dBlendOp;
+
+typedef enum {
+ SVGA3D_BLENDEQ_INVALID = 0,
+ SVGA3D_BLENDEQ_ADD = 1,
+ SVGA3D_BLENDEQ_SUBTRACT = 2,
+ SVGA3D_BLENDEQ_REVSUBTRACT = 3,
+ SVGA3D_BLENDEQ_MINIMUM = 4,
+ SVGA3D_BLENDEQ_MAXIMUM = 5,
+ SVGA3D_BLENDEQ_MAX
+} SVGA3dBlendEquation;
+
+typedef enum {
+ SVGA3D_FRONTWINDING_INVALID = 0,
+ SVGA3D_FRONTWINDING_CW = 1,
+ SVGA3D_FRONTWINDING_CCW = 2,
+ SVGA3D_FRONTWINDING_MAX
+} SVGA3dFrontWinding;
+
+typedef enum {
+ SVGA3D_FACE_INVALID = 0,
+ SVGA3D_FACE_NONE = 1,
+ SVGA3D_FACE_FRONT = 2,
+ SVGA3D_FACE_BACK = 3,
+ SVGA3D_FACE_FRONT_BACK = 4,
+ SVGA3D_FACE_MAX
+} SVGA3dFace;
+
+/*
+ * The order and the values should not be changed
+ */
+
+typedef enum {
+ SVGA3D_CMP_INVALID = 0,
+ SVGA3D_CMP_NEVER = 1,
+ SVGA3D_CMP_LESS = 2,
+ SVGA3D_CMP_EQUAL = 3,
+ SVGA3D_CMP_LESSEQUAL = 4,
+ SVGA3D_CMP_GREATER = 5,
+ SVGA3D_CMP_NOTEQUAL = 6,
+ SVGA3D_CMP_GREATEREQUAL = 7,
+ SVGA3D_CMP_ALWAYS = 8,
+ SVGA3D_CMP_MAX
+} SVGA3dCmpFunc;
+
+/*
+ * SVGA3D_FOGFUNC_* specifies the fog equation, or PER_VERTEX which allows
+ * the fog factor to be specified in the alpha component of the specular
+ * (a.k.a. secondary) vertex color.
+ */
+typedef enum {
+ SVGA3D_FOGFUNC_INVALID = 0,
+ SVGA3D_FOGFUNC_EXP = 1,
+ SVGA3D_FOGFUNC_EXP2 = 2,
+ SVGA3D_FOGFUNC_LINEAR = 3,
+ SVGA3D_FOGFUNC_PER_VERTEX = 4
+} SVGA3dFogFunction;
+
+/*
+ * SVGA3D_FOGTYPE_* specifies if fog factors are computed on a per-vertex
+ * or per-pixel basis.
+ */
+typedef enum {
+ SVGA3D_FOGTYPE_INVALID = 0,
+ SVGA3D_FOGTYPE_VERTEX = 1,
+ SVGA3D_FOGTYPE_PIXEL = 2,
+ SVGA3D_FOGTYPE_MAX = 3
+} SVGA3dFogType;
+
+/*
+ * SVGA3D_FOGBASE_* selects depth or range-based fog. Depth-based fog is
+ * computed using the eye Z value of each pixel (or vertex), whereas range-
+ * based fog is computed using the actual distance (range) to the eye.
+ */
+typedef enum {
+ SVGA3D_FOGBASE_INVALID = 0,
+ SVGA3D_FOGBASE_DEPTHBASED = 1,
+ SVGA3D_FOGBASE_RANGEBASED = 2,
+ SVGA3D_FOGBASE_MAX = 3
+} SVGA3dFogBase;
+
+typedef enum {
+ SVGA3D_STENCILOP_INVALID = 0,
+ SVGA3D_STENCILOP_KEEP = 1,
+ SVGA3D_STENCILOP_ZERO = 2,
+ SVGA3D_STENCILOP_REPLACE = 3,
+ SVGA3D_STENCILOP_INCRSAT = 4,
+ SVGA3D_STENCILOP_DECRSAT = 5,
+ SVGA3D_STENCILOP_INVERT = 6,
+ SVGA3D_STENCILOP_INCR = 7,
+ SVGA3D_STENCILOP_DECR = 8,
+ SVGA3D_STENCILOP_MAX
+} SVGA3dStencilOp;
+
+typedef enum {
+ SVGA3D_CLIPPLANE_0 = (1 << 0),
+ SVGA3D_CLIPPLANE_1 = (1 << 1),
+ SVGA3D_CLIPPLANE_2 = (1 << 2),
+ SVGA3D_CLIPPLANE_3 = (1 << 3),
+ SVGA3D_CLIPPLANE_4 = (1 << 4),
+ SVGA3D_CLIPPLANE_5 = (1 << 5),
+} SVGA3dClipPlanes;
+
+typedef enum {
+ SVGA3D_CLEAR_COLOR = 0x1,
+ SVGA3D_CLEAR_DEPTH = 0x2,
+ SVGA3D_CLEAR_STENCIL = 0x4
+} SVGA3dClearFlag;
+
+typedef enum {
+ SVGA3D_RT_DEPTH = 0,
+ SVGA3D_RT_STENCIL = 1,
+ SVGA3D_RT_COLOR0 = 2,
+ SVGA3D_RT_COLOR1 = 3,
+ SVGA3D_RT_COLOR2 = 4,
+ SVGA3D_RT_COLOR3 = 5,
+ SVGA3D_RT_COLOR4 = 6,
+ SVGA3D_RT_COLOR5 = 7,
+ SVGA3D_RT_COLOR6 = 8,
+ SVGA3D_RT_COLOR7 = 9,
+ SVGA3D_RT_MAX,
+ SVGA3D_RT_INVALID = ((uint32)-1),
+} SVGA3dRenderTargetType;
+
+#define SVGA3D_MAX_RT_COLOR (SVGA3D_RT_COLOR7 - SVGA3D_RT_COLOR0 + 1)
+
+typedef
+union {
+ struct {
+ uint32 red : 1;
+ uint32 green : 1;
+ uint32 blue : 1;
+ uint32 alpha : 1;
+ };
+ uint32 uintValue;
+} SVGA3dColorMask;
+
+typedef enum {
+ SVGA3D_VBLEND_DISABLE = 0,
+ SVGA3D_VBLEND_1WEIGHT = 1,
+ SVGA3D_VBLEND_2WEIGHT = 2,
+ SVGA3D_VBLEND_3WEIGHT = 3,
+} SVGA3dVertexBlendFlags;
+
+typedef enum {
+ SVGA3D_WRAPCOORD_0 = 1 << 0,
+ SVGA3D_WRAPCOORD_1 = 1 << 1,
+ SVGA3D_WRAPCOORD_2 = 1 << 2,
+ SVGA3D_WRAPCOORD_3 = 1 << 3,
+ SVGA3D_WRAPCOORD_ALL = 0xF,
+} SVGA3dWrapFlags;
+
+/*
+ * SVGA_3D_CMD_TEXTURESTATE Types. All value types
+ * must fit in a uint32.
+ */
+
+typedef enum {
+ SVGA3D_TS_INVALID = 0,
+ SVGA3D_TS_MIN = 1,
+ SVGA3D_TS_BIND_TEXTURE = 1, /* SVGA3dSurfaceId */
+ SVGA3D_TS_COLOROP = 2, /* SVGA3dTextureCombiner */
+ SVGA3D_TS_COLORARG1 = 3, /* SVGA3dTextureArgData */
+ SVGA3D_TS_COLORARG2 = 4, /* SVGA3dTextureArgData */
+ SVGA3D_TS_ALPHAOP = 5, /* SVGA3dTextureCombiner */
+ SVGA3D_TS_ALPHAARG1 = 6, /* SVGA3dTextureArgData */
+ SVGA3D_TS_ALPHAARG2 = 7, /* SVGA3dTextureArgData */
+ SVGA3D_TS_ADDRESSU = 8, /* SVGA3dTextureAddress */
+ SVGA3D_TS_ADDRESSV = 9, /* SVGA3dTextureAddress */
+ SVGA3D_TS_MIPFILTER = 10, /* SVGA3dTextureFilter */
+ SVGA3D_TS_MAGFILTER = 11, /* SVGA3dTextureFilter */
+ SVGA3D_TS_MINFILTER = 12, /* SVGA3dTextureFilter */
+ SVGA3D_TS_BORDERCOLOR = 13, /* SVGA3dColor */
+ SVGA3D_TS_TEXCOORDINDEX = 14, /* uint32 */
+ SVGA3D_TS_TEXTURETRANSFORMFLAGS = 15, /* SVGA3dTexTransformFlags */
+ SVGA3D_TS_TEXCOORDGEN = 16, /* SVGA3dTextureCoordGen */
+ SVGA3D_TS_BUMPENVMAT00 = 17, /* float */
+ SVGA3D_TS_BUMPENVMAT01 = 18, /* float */
+ SVGA3D_TS_BUMPENVMAT10 = 19, /* float */
+ SVGA3D_TS_BUMPENVMAT11 = 20, /* float */
+ SVGA3D_TS_TEXTURE_MIPMAP_LEVEL = 21, /* uint32 */
+ SVGA3D_TS_TEXTURE_LOD_BIAS = 22, /* float */
+ SVGA3D_TS_TEXTURE_ANISOTROPIC_LEVEL = 23, /* uint32 */
+ SVGA3D_TS_ADDRESSW = 24, /* SVGA3dTextureAddress */
+
+
+ /*
+ * Sampler Gamma Level
+ *
+ * Sampler gamma effects the color of samples taken from the sampler. A
+ * value of 1.0 will produce linear samples. If the value is <= 0.0 the
+ * gamma value is ignored and a linear space is used.
+ */
+
+ SVGA3D_TS_GAMMA = 25, /* float */
+ SVGA3D_TS_BUMPENVLSCALE = 26, /* float */
+ SVGA3D_TS_BUMPENVLOFFSET = 27, /* float */
+ SVGA3D_TS_COLORARG0 = 28, /* SVGA3dTextureArgData */
+ SVGA3D_TS_ALPHAARG0 = 29, /* SVGA3dTextureArgData */
+ SVGA3D_TS_PREGB_MAX = 30, /* Max value before GBObjects */
+ SVGA3D_TS_CONSTANT = 30, /* SVGA3dColor */
+ SVGA3D_TS_COLOR_KEY_ENABLE = 31, /* SVGA3dBool */
+ SVGA3D_TS_COLOR_KEY = 32, /* SVGA3dColor */
+ SVGA3D_TS_MAX
+} SVGA3dTextureStateName;
+
+typedef enum {
+ SVGA3D_TC_INVALID = 0,
+ SVGA3D_TC_DISABLE = 1,
+ SVGA3D_TC_SELECTARG1 = 2,
+ SVGA3D_TC_SELECTARG2 = 3,
+ SVGA3D_TC_MODULATE = 4,
+ SVGA3D_TC_ADD = 5,
+ SVGA3D_TC_ADDSIGNED = 6,
+ SVGA3D_TC_SUBTRACT = 7,
+ SVGA3D_TC_BLENDTEXTUREALPHA = 8,
+ SVGA3D_TC_BLENDDIFFUSEALPHA = 9,
+ SVGA3D_TC_BLENDCURRENTALPHA = 10,
+ SVGA3D_TC_BLENDFACTORALPHA = 11,
+ SVGA3D_TC_MODULATE2X = 12,
+ SVGA3D_TC_MODULATE4X = 13,
+ SVGA3D_TC_DSDT = 14,
+ SVGA3D_TC_DOTPRODUCT3 = 15,
+ SVGA3D_TC_BLENDTEXTUREALPHAPM = 16,
+ SVGA3D_TC_ADDSIGNED2X = 17,
+ SVGA3D_TC_ADDSMOOTH = 18,
+ SVGA3D_TC_PREMODULATE = 19,
+ SVGA3D_TC_MODULATEALPHA_ADDCOLOR = 20,
+ SVGA3D_TC_MODULATECOLOR_ADDALPHA = 21,
+ SVGA3D_TC_MODULATEINVALPHA_ADDCOLOR = 22,
+ SVGA3D_TC_MODULATEINVCOLOR_ADDALPHA = 23,
+ SVGA3D_TC_BUMPENVMAPLUMINANCE = 24,
+ SVGA3D_TC_MULTIPLYADD = 25,
+ SVGA3D_TC_LERP = 26,
+ SVGA3D_TC_MAX
+} SVGA3dTextureCombiner;
+
+#define SVGA3D_TC_CAP_BIT(svga3d_tc_op) (svga3d_tc_op ? (1 << (svga3d_tc_op - 1)) : 0)
+
+typedef enum {
+ SVGA3D_TEX_ADDRESS_INVALID = 0,
+ SVGA3D_TEX_ADDRESS_WRAP = 1,
+ SVGA3D_TEX_ADDRESS_MIRROR = 2,
+ SVGA3D_TEX_ADDRESS_CLAMP = 3,
+ SVGA3D_TEX_ADDRESS_BORDER = 4,
+ SVGA3D_TEX_ADDRESS_MIRRORONCE = 5,
+ SVGA3D_TEX_ADDRESS_EDGE = 6,
+ SVGA3D_TEX_ADDRESS_MAX
+} SVGA3dTextureAddress;
+
+/*
+ * SVGA3D_TEX_FILTER_NONE as the minification filter means mipmapping is
+ * disabled, and the rasterizer should use the magnification filter instead.
+ */
+typedef enum {
+ SVGA3D_TEX_FILTER_NONE = 0,
+ SVGA3D_TEX_FILTER_NEAREST = 1,
+ SVGA3D_TEX_FILTER_LINEAR = 2,
+ SVGA3D_TEX_FILTER_ANISOTROPIC = 3,
+ SVGA3D_TEX_FILTER_FLATCUBIC = 4, // Deprecated, not implemented
+ SVGA3D_TEX_FILTER_GAUSSIANCUBIC = 5, // Deprecated, not implemented
+ SVGA3D_TEX_FILTER_PYRAMIDALQUAD = 6, // Not currently implemented
+ SVGA3D_TEX_FILTER_GAUSSIANQUAD = 7, // Not currently implemented
+ SVGA3D_TEX_FILTER_MAX
+} SVGA3dTextureFilter;
+
+typedef enum {
+ SVGA3D_TEX_TRANSFORM_OFF = 0,
+ SVGA3D_TEX_TRANSFORM_S = (1 << 0),
+ SVGA3D_TEX_TRANSFORM_T = (1 << 1),
+ SVGA3D_TEX_TRANSFORM_R = (1 << 2),
+ SVGA3D_TEX_TRANSFORM_Q = (1 << 3),
+ SVGA3D_TEX_PROJECTED = (1 << 15),
+} SVGA3dTexTransformFlags;
+
+typedef enum {
+ SVGA3D_TEXCOORD_GEN_OFF = 0,
+ SVGA3D_TEXCOORD_GEN_EYE_POSITION = 1,
+ SVGA3D_TEXCOORD_GEN_EYE_NORMAL = 2,
+ SVGA3D_TEXCOORD_GEN_REFLECTIONVECTOR = 3,
+ SVGA3D_TEXCOORD_GEN_SPHERE = 4,
+ SVGA3D_TEXCOORD_GEN_MAX
+} SVGA3dTextureCoordGen;
+
+/*
+ * Texture argument constants for texture combiner
+ */
+typedef enum {
+ SVGA3D_TA_INVALID = 0,
+ SVGA3D_TA_CONSTANT = 1,
+ SVGA3D_TA_PREVIOUS = 2,
+ SVGA3D_TA_DIFFUSE = 3,
+ SVGA3D_TA_TEXTURE = 4,
+ SVGA3D_TA_SPECULAR = 5,
+ SVGA3D_TA_MAX
+} SVGA3dTextureArgData;
+
+#define SVGA3D_TM_MASK_LEN 4
+
+/* Modifiers for texture argument constants defined above. */
+typedef enum {
+ SVGA3D_TM_NONE = 0,
+ SVGA3D_TM_ALPHA = (1 << SVGA3D_TM_MASK_LEN),
+ SVGA3D_TM_ONE_MINUS = (2 << SVGA3D_TM_MASK_LEN),
+} SVGA3dTextureArgModifier;
+
+#define SVGA3D_INVALID_ID ((uint32)-1)
+#define SVGA3D_MAX_CLIP_PLANES 6
+
+/*
+ * This is the limit to the number of fixed-function texture
+ * transforms and texture coordinates we can support. It does *not*
+ * correspond to the number of texture image units (samplers) we
+ * support!
+ */
+#define SVGA3D_MAX_TEXTURE_COORDS 8
+
+/*
+ * Vertex declarations
+ *
+ * Notes:
+ *
+ * SVGA3D_DECLUSAGE_POSITIONT is for pre-transformed vertices. If you
+ * draw with any POSITIONT vertex arrays, the programmable vertex
+ * pipeline will be implicitly disabled. Drawing will take place as if
+ * no vertex shader was bound.
+ */
+
+typedef enum {
+ SVGA3D_DECLUSAGE_POSITION = 0,
+ SVGA3D_DECLUSAGE_BLENDWEIGHT, // 1
+ SVGA3D_DECLUSAGE_BLENDINDICES, // 2
+ SVGA3D_DECLUSAGE_NORMAL, // 3
+ SVGA3D_DECLUSAGE_PSIZE, // 4
+ SVGA3D_DECLUSAGE_TEXCOORD, // 5
+ SVGA3D_DECLUSAGE_TANGENT, // 6
+ SVGA3D_DECLUSAGE_BINORMAL, // 7
+ SVGA3D_DECLUSAGE_TESSFACTOR, // 8
+ SVGA3D_DECLUSAGE_POSITIONT, // 9
+ SVGA3D_DECLUSAGE_COLOR, // 10
+ SVGA3D_DECLUSAGE_FOG, // 11
+ SVGA3D_DECLUSAGE_DEPTH, // 12
+ SVGA3D_DECLUSAGE_SAMPLE, // 13
+ SVGA3D_DECLUSAGE_MAX
+} SVGA3dDeclUsage;
+
+typedef enum {
+ SVGA3D_DECLMETHOD_DEFAULT = 0,
+ SVGA3D_DECLMETHOD_PARTIALU,
+ SVGA3D_DECLMETHOD_PARTIALV,
+ SVGA3D_DECLMETHOD_CROSSUV, // Normal
+ SVGA3D_DECLMETHOD_UV,
+ SVGA3D_DECLMETHOD_LOOKUP, // Lookup a displacement map
+ SVGA3D_DECLMETHOD_LOOKUPPRESAMPLED, // Lookup a pre-sampled displacement map
+} SVGA3dDeclMethod;
+
+typedef enum {
+ SVGA3D_DECLTYPE_FLOAT1 = 0,
+ SVGA3D_DECLTYPE_FLOAT2 = 1,
+ SVGA3D_DECLTYPE_FLOAT3 = 2,
+ SVGA3D_DECLTYPE_FLOAT4 = 3,
+ SVGA3D_DECLTYPE_D3DCOLOR = 4,
+ SVGA3D_DECLTYPE_UBYTE4 = 5,
+ SVGA3D_DECLTYPE_SHORT2 = 6,
+ SVGA3D_DECLTYPE_SHORT4 = 7,
+ SVGA3D_DECLTYPE_UBYTE4N = 8,
+ SVGA3D_DECLTYPE_SHORT2N = 9,
+ SVGA3D_DECLTYPE_SHORT4N = 10,
+ SVGA3D_DECLTYPE_USHORT2N = 11,
+ SVGA3D_DECLTYPE_USHORT4N = 12,
+ SVGA3D_DECLTYPE_UDEC3 = 13,
+ SVGA3D_DECLTYPE_DEC3N = 14,
+ SVGA3D_DECLTYPE_FLOAT16_2 = 15,
+ SVGA3D_DECLTYPE_FLOAT16_4 = 16,
+ SVGA3D_DECLTYPE_MAX,
+} SVGA3dDeclType;
+
+/*
+ * This structure is used for the divisor for geometry instancing;
+ * it's a direct translation of the Direct3D equivalent.
+ */
+typedef union {
+ struct {
+ /*
+ * For index data, this number represents the number of instances to draw.
+ * For instance data, this number represents the number of
+ * instances/vertex in this stream
+ */
+ uint32 count : 30;
+
+ /*
+ * This is 1 if this is supposed to be the data that is repeated for
+ * every instance.
+ */
+ uint32 indexedData : 1;
+
+ /*
+ * This is 1 if this is supposed to be the per-instance data.
+ */
+ uint32 instanceData : 1;
+ };
+
+ uint32 value;
+} SVGA3dVertexDivisor;
+
+typedef enum {
+ SVGA3D_PRIMITIVE_INVALID = 0,
+ SVGA3D_PRIMITIVE_TRIANGLELIST = 1,
+ SVGA3D_PRIMITIVE_POINTLIST = 2,
+ SVGA3D_PRIMITIVE_LINELIST = 3,
+ SVGA3D_PRIMITIVE_LINESTRIP = 4,
+ SVGA3D_PRIMITIVE_TRIANGLESTRIP = 5,
+ SVGA3D_PRIMITIVE_TRIANGLEFAN = 6,
+ SVGA3D_PRIMITIVE_MAX
+} SVGA3dPrimitiveType;
+
+typedef enum {
+ SVGA3D_COORDINATE_INVALID = 0,
+ SVGA3D_COORDINATE_LEFTHANDED = 1,
+ SVGA3D_COORDINATE_RIGHTHANDED = 2,
+ SVGA3D_COORDINATE_MAX
+} SVGA3dCoordinateType;
+
+typedef enum {
+ SVGA3D_TRANSFORM_INVALID = 0,
+ SVGA3D_TRANSFORM_WORLD = 1,
+ SVGA3D_TRANSFORM_VIEW = 2,
+ SVGA3D_TRANSFORM_PROJECTION = 3,
+ SVGA3D_TRANSFORM_TEXTURE0 = 4,
+ SVGA3D_TRANSFORM_TEXTURE1 = 5,
+ SVGA3D_TRANSFORM_TEXTURE2 = 6,
+ SVGA3D_TRANSFORM_TEXTURE3 = 7,
+ SVGA3D_TRANSFORM_TEXTURE4 = 8,
+ SVGA3D_TRANSFORM_TEXTURE5 = 9,
+ SVGA3D_TRANSFORM_TEXTURE6 = 10,
+ SVGA3D_TRANSFORM_TEXTURE7 = 11,
+ SVGA3D_TRANSFORM_WORLD1 = 12,
+ SVGA3D_TRANSFORM_WORLD2 = 13,
+ SVGA3D_TRANSFORM_WORLD3 = 14,
+ SVGA3D_TRANSFORM_MAX
+} SVGA3dTransformType;
+
+typedef enum {
+ SVGA3D_LIGHTTYPE_INVALID = 0,
+ SVGA3D_LIGHTTYPE_POINT = 1,
+ SVGA3D_LIGHTTYPE_SPOT1 = 2, /* 1-cone, in degrees */
+ SVGA3D_LIGHTTYPE_SPOT2 = 3, /* 2-cone, in radians */
+ SVGA3D_LIGHTTYPE_DIRECTIONAL = 4,
+ SVGA3D_LIGHTTYPE_MAX
+} SVGA3dLightType;
+
+typedef enum {
+ SVGA3D_CUBEFACE_POSX = 0,
+ SVGA3D_CUBEFACE_NEGX = 1,
+ SVGA3D_CUBEFACE_POSY = 2,
+ SVGA3D_CUBEFACE_NEGY = 3,
+ SVGA3D_CUBEFACE_POSZ = 4,
+ SVGA3D_CUBEFACE_NEGZ = 5,
+} SVGA3dCubeFace;
+
+typedef enum {
+ SVGA3D_SHADERTYPE_INVALID = 0,
+ SVGA3D_SHADERTYPE_MIN = 1,
+ SVGA3D_SHADERTYPE_VS = 1,
+ SVGA3D_SHADERTYPE_PS = 2,
+ SVGA3D_SHADERTYPE_PREDX_MAX = 3,
+ SVGA3D_SHADERTYPE_GS = 3,
+ SVGA3D_SHADERTYPE_DX10_MAX = 4,
+ SVGA3D_SHADERTYPE_HS = 4,
+ SVGA3D_SHADERTYPE_DS = 5,
+ SVGA3D_SHADERTYPE_CS = 6,
+ SVGA3D_SHADERTYPE_MAX = 7
+} SVGA3dShaderType;
+
+#define SVGA3D_NUM_SHADERTYPE_PREDX \
+ (SVGA3D_SHADERTYPE_PREDX_MAX - SVGA3D_SHADERTYPE_MIN)
+
+#define SVGA3D_NUM_SHADERTYPE_DX10 \
+ (SVGA3D_SHADERTYPE_DX10_MAX - SVGA3D_SHADERTYPE_MIN)
+
+#define SVGA3D_NUM_SHADERTYPE \
+ (SVGA3D_SHADERTYPE_MAX - SVGA3D_SHADERTYPE_MIN)
+
+/*
+ * Register limits for shader consts.
+ */
+#define SVGA3D_CONSTREG_MAX 256
+#define SVGA3D_CONSTINTREG_MAX 16
+#define SVGA3D_CONSTBOOLREG_MAX 16
+
+typedef enum {
+ SVGA3D_CONST_TYPE_FLOAT = 0,
+ SVGA3D_CONST_TYPE_INT = 1,
+ SVGA3D_CONST_TYPE_BOOL = 2,
+} SVGA3dShaderConstType;
+
+#define SVGA3D_MAX_SURFACE_FACES 6
+
+typedef enum {
+ SVGA3D_STRETCH_BLT_POINT = 0,
+ SVGA3D_STRETCH_BLT_LINEAR = 1,
+ SVGA3D_STRETCH_BLT_MAX
+} SVGA3dStretchBltMode;
+
+typedef enum {
+ SVGA3D_QUERYTYPE_OCCLUSION = 0,
+ SVGA3D_QUERYTYPE_MAX
+} SVGA3dQueryType;
+
+typedef enum {
+ SVGA3D_QUERYSTATE_PENDING = 0, /* Waiting on the host (set by guest) */
+ SVGA3D_QUERYSTATE_SUCCEEDED = 1, /* Completed successfully (set by host) */
+ SVGA3D_QUERYSTATE_FAILED = 2, /* Completed unsuccessfully (set by host) */
+ SVGA3D_QUERYSTATE_NEW = 3, /* Never submitted (For guest use only) */
+} SVGA3dQueryState;
+
+typedef enum {
+ SVGA3D_WRITE_HOST_VRAM = 1,
+ SVGA3D_READ_HOST_VRAM = 2,
+} SVGA3dTransferType;
+
+/*
+ * The maximum number of vertex arrays we're guaranteed to support in
+ * SVGA_3D_CMD_DRAWPRIMITIVES.
+ */
+#define SVGA3D_MAX_VERTEX_ARRAYS 32
+
+/*
+ * The maximum number of primitive ranges we're guaranteed to support
+ * in SVGA_3D_CMD_DRAWPRIMITIVES.
+ */
+#define SVGA3D_MAX_DRAW_PRIMITIVE_RANGES 32
+
+/*
+ * Identifiers for commands in the command FIFO.
+ *
+ * IDs between 1000 and 1039 (inclusive) were used by obsolete versions of
+ * the SVGA3D protocol and remain reserved; they should not be used in the
+ * future.
+ *
+ * IDs between 1040 and 1999 (inclusive) are available for use by the
+ * current SVGA3D protocol.
+ *
+ * FIFO clients other than SVGA3D should stay below 1000, or at 2000
+ * and up.
+ */
+
+#define SVGA_3D_CMD_LEGACY_BASE 1000
+#define SVGA_3D_CMD_BASE 1040
+
+#define SVGA_3D_CMD_SURFACE_DEFINE SVGA_3D_CMD_BASE + 0 // Deprecated
+#define SVGA_3D_CMD_SURFACE_DESTROY SVGA_3D_CMD_BASE + 1
+#define SVGA_3D_CMD_SURFACE_COPY SVGA_3D_CMD_BASE + 2
+#define SVGA_3D_CMD_SURFACE_STRETCHBLT SVGA_3D_CMD_BASE + 3
+#define SVGA_3D_CMD_SURFACE_DMA SVGA_3D_CMD_BASE + 4
+#define SVGA_3D_CMD_CONTEXT_DEFINE SVGA_3D_CMD_BASE + 5
+#define SVGA_3D_CMD_CONTEXT_DESTROY SVGA_3D_CMD_BASE + 6
+#define SVGA_3D_CMD_SETTRANSFORM SVGA_3D_CMD_BASE + 7
+#define SVGA_3D_CMD_SETZRANGE SVGA_3D_CMD_BASE + 8
+#define SVGA_3D_CMD_SETRENDERSTATE SVGA_3D_CMD_BASE + 9
+#define SVGA_3D_CMD_SETRENDERTARGET SVGA_3D_CMD_BASE + 10
+#define SVGA_3D_CMD_SETTEXTURESTATE SVGA_3D_CMD_BASE + 11
+#define SVGA_3D_CMD_SETMATERIAL SVGA_3D_CMD_BASE + 12
+#define SVGA_3D_CMD_SETLIGHTDATA SVGA_3D_CMD_BASE + 13
+#define SVGA_3D_CMD_SETLIGHTENABLED SVGA_3D_CMD_BASE + 14
+#define SVGA_3D_CMD_SETVIEWPORT SVGA_3D_CMD_BASE + 15
+#define SVGA_3D_CMD_SETCLIPPLANE SVGA_3D_CMD_BASE + 16
+#define SVGA_3D_CMD_CLEAR SVGA_3D_CMD_BASE + 17
+#define SVGA_3D_CMD_PRESENT SVGA_3D_CMD_BASE + 18 // Deprecated
+#define SVGA_3D_CMD_SHADER_DEFINE SVGA_3D_CMD_BASE + 19
+#define SVGA_3D_CMD_SHADER_DESTROY SVGA_3D_CMD_BASE + 20
+#define SVGA_3D_CMD_SET_SHADER SVGA_3D_CMD_BASE + 21
+#define SVGA_3D_CMD_SET_SHADER_CONST SVGA_3D_CMD_BASE + 22
+#define SVGA_3D_CMD_DRAW_PRIMITIVES SVGA_3D_CMD_BASE + 23
+#define SVGA_3D_CMD_SETSCISSORRECT SVGA_3D_CMD_BASE + 24
+#define SVGA_3D_CMD_BEGIN_QUERY SVGA_3D_CMD_BASE + 25
+#define SVGA_3D_CMD_END_QUERY SVGA_3D_CMD_BASE + 26
+#define SVGA_3D_CMD_WAIT_FOR_QUERY SVGA_3D_CMD_BASE + 27
+#define SVGA_3D_CMD_PRESENT_READBACK SVGA_3D_CMD_BASE + 28 // Deprecated
+#define SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN SVGA_3D_CMD_BASE + 29
+#define SVGA_3D_CMD_SURFACE_DEFINE_V2 SVGA_3D_CMD_BASE + 30
+#define SVGA_3D_CMD_GENERATE_MIPMAPS SVGA_3D_CMD_BASE + 31
+#define SVGA_3D_CMD_ACTIVATE_SURFACE SVGA_3D_CMD_BASE + 40
+#define SVGA_3D_CMD_DEACTIVATE_SURFACE SVGA_3D_CMD_BASE + 41
+//#define SVGA_3D_CMD_MAX SVGA_3D_CMD_BASE + 42
+
+/* GPU10 commands */
+#define SVGA_3D_CMD_SCREEN_DMA 1082
+#define SVGA_3D_CMD_DEAD1 1083
+#define SVGA_3D_CMD_DEAD2 1084
+
+#define SVGA_3D_CMD_DEAD12 1085
+#define SVGA_3D_CMD_DEAD13 1086
+#define SVGA_3D_CMD_DEAD14 1087
+#define SVGA_3D_CMD_DEAD15 1088
+#define SVGA_3D_CMD_DEAD16 1089
+#define SVGA_3D_CMD_DEAD17 1090
+
+#define SVGA_3D_CMD_SET_OTABLE_BASE 1091
+#define SVGA_3D_CMD_READBACK_OTABLE 1092
+
+#define SVGA_3D_CMD_DEFINE_GB_MOB 1093
+#define SVGA_3D_CMD_DESTROY_GB_MOB 1094
+#define SVGA_3D_CMD_DEAD3 1095
+#define SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING 1096
+
+#define SVGA_3D_CMD_DEFINE_GB_SURFACE 1097
+#define SVGA_3D_CMD_DESTROY_GB_SURFACE 1098
+#define SVGA_3D_CMD_BIND_GB_SURFACE 1099
+#define SVGA_3D_CMD_COND_BIND_GB_SURFACE 1100
+#define SVGA_3D_CMD_UPDATE_GB_IMAGE 1101
+#define SVGA_3D_CMD_UPDATE_GB_SURFACE 1102
+#define SVGA_3D_CMD_READBACK_GB_IMAGE 1103
+#define SVGA_3D_CMD_READBACK_GB_SURFACE 1104
+#define SVGA_3D_CMD_INVALIDATE_GB_IMAGE 1105
+#define SVGA_3D_CMD_INVALIDATE_GB_SURFACE 1106
+
+#define SVGA_3D_CMD_DEFINE_GB_CONTEXT 1107
+#define SVGA_3D_CMD_DESTROY_GB_CONTEXT 1108
+#define SVGA_3D_CMD_BIND_GB_CONTEXT 1109
+#define SVGA_3D_CMD_READBACK_GB_CONTEXT 1110
+#define SVGA_3D_CMD_INVALIDATE_GB_CONTEXT 1111
+
+#define SVGA_3D_CMD_DEFINE_GB_SHADER 1112
+#define SVGA_3D_CMD_DESTROY_GB_SHADER 1113
+#define SVGA_3D_CMD_BIND_GB_SHADER 1114
+
+#define SVGA_3D_CMD_SET_OTABLE_BASE64 1115
+
+#define SVGA_3D_CMD_BEGIN_GB_QUERY 1116
+#define SVGA_3D_CMD_END_GB_QUERY 1117
+#define SVGA_3D_CMD_WAIT_FOR_GB_QUERY 1118
+
+#define SVGA_3D_CMD_NOP 1119
+
+#define SVGA_3D_CMD_ENABLE_GART 1120
+#define SVGA_3D_CMD_DISABLE_GART 1121
+#define SVGA_3D_CMD_MAP_MOB_INTO_GART 1122
+#define SVGA_3D_CMD_UNMAP_GART_RANGE 1123
+
+#define SVGA_3D_CMD_DEFINE_GB_SCREENTARGET 1124
+#define SVGA_3D_CMD_DESTROY_GB_SCREENTARGET 1125
+#define SVGA_3D_CMD_BIND_GB_SCREENTARGET 1126
+#define SVGA_3D_CMD_UPDATE_GB_SCREENTARGET 1127
+
+#define SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL 1128
+#define SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL 1129
+
+#define SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE 1130
+
+#define SVGA_3D_CMD_GB_SCREEN_DMA 1131
+#define SVGA_3D_CMD_BIND_GB_SURFACE_WITH_PITCH 1132
+#define SVGA_3D_CMD_GB_MOB_FENCE 1133
+#define SVGA_3D_CMD_DEFINE_GB_SURFACE_V2 1134
+#define SVGA_3D_CMD_DEFINE_GB_MOB64 1135
+#define SVGA_3D_CMD_REDEFINE_GB_MOB64 1136
+#define SVGA_3D_CMD_NOP_ERROR 1137
+
+#define SVGA_3D_CMD_SET_VERTEX_STREAMS 1138
+#define SVGA_3D_CMD_SET_VERTEX_DECLS 1139
+#define SVGA_3D_CMD_SET_VERTEX_DIVISORS 1140
+#define SVGA_3D_CMD_DRAW 1141
+#define SVGA_3D_CMD_DRAW_INDEXED 1142
+
+#define SVGA_3D_CMD_DX_MIN 1143
+#define SVGA_3D_CMD_DX_DEFINE_CONTEXT 1143
+#define SVGA_3D_CMD_DX_DESTROY_CONTEXT 1144
+#define SVGA_3D_CMD_DX_BIND_CONTEXT 1145
+#define SVGA_3D_CMD_DX_READBACK_CONTEXT 1146
+#define SVGA_3D_CMD_DX_INVALIDATE_CONTEXT 1147
+#define SVGA_3D_CMD_DX_SET_SINGLE_CONSTANT_BUFFER 1148
+#define SVGA_3D_CMD_DX_SET_SHADER_RESOURCES 1149
+#define SVGA_3D_CMD_DX_SET_SHADER 1150
+#define SVGA_3D_CMD_DX_SET_SAMPLERS 1151
+#define SVGA_3D_CMD_DX_DRAW 1152
+#define SVGA_3D_CMD_DX_DRAW_INDEXED 1153
+#define SVGA_3D_CMD_DX_DRAW_INSTANCED 1154
+#define SVGA_3D_CMD_DX_DRAW_INDEXED_INSTANCED 1155
+#define SVGA_3D_CMD_DX_DRAW_AUTO 1156
+#define SVGA_3D_CMD_DX_SET_INPUT_LAYOUT 1157
+#define SVGA_3D_CMD_DX_SET_VERTEX_BUFFERS 1158
+#define SVGA_3D_CMD_DX_SET_INDEX_BUFFER 1159
+#define SVGA_3D_CMD_DX_SET_TOPOLOGY 1160
+#define SVGA_3D_CMD_DX_SET_RENDERTARGETS 1161
+#define SVGA_3D_CMD_DX_SET_BLEND_STATE 1162
+#define SVGA_3D_CMD_DX_SET_DEPTHSTENCIL_STATE 1163
+#define SVGA_3D_CMD_DX_SET_RASTERIZER_STATE 1164
+#define SVGA_3D_CMD_DX_DEFINE_QUERY 1165
+#define SVGA_3D_CMD_DX_DESTROY_QUERY 1166
+#define SVGA_3D_CMD_DX_BIND_QUERY 1167
+#define SVGA_3D_CMD_DX_SET_QUERY_OFFSET 1168
+#define SVGA_3D_CMD_DX_BEGIN_QUERY 1169
+#define SVGA_3D_CMD_DX_END_QUERY 1170
+#define SVGA_3D_CMD_DX_READBACK_QUERY 1171
+#define SVGA_3D_CMD_DX_SET_PREDICATION 1172
+#define SVGA_3D_CMD_DX_SET_SOTARGETS 1173
+#define SVGA_3D_CMD_DX_SET_VIEWPORTS 1174
+#define SVGA_3D_CMD_DX_SET_SCISSORRECTS 1175
+#define SVGA_3D_CMD_DX_CLEAR_RENDERTARGET_VIEW 1176
+#define SVGA_3D_CMD_DX_CLEAR_DEPTHSTENCIL_VIEW 1177
+#define SVGA_3D_CMD_DX_PRED_COPY_REGION 1178
+#define SVGA_3D_CMD_DX_PRED_COPY 1179
+#define SVGA_3D_CMD_DX_PRESENTBLT 1180
+#define SVGA_3D_CMD_DX_GENMIPS 1181
+#define SVGA_3D_CMD_DX_UPDATE_SUBRESOURCE 1182
+#define SVGA_3D_CMD_DX_READBACK_SUBRESOURCE 1183
+#define SVGA_3D_CMD_DX_INVALIDATE_SUBRESOURCE 1184
+#define SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW 1185
+#define SVGA_3D_CMD_DX_DESTROY_SHADERRESOURCE_VIEW 1186
+#define SVGA_3D_CMD_DX_DEFINE_RENDERTARGET_VIEW 1187
+#define SVGA_3D_CMD_DX_DESTROY_RENDERTARGET_VIEW 1188
+#define SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_VIEW 1189
+#define SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_VIEW 1190
+#define SVGA_3D_CMD_DX_DEFINE_ELEMENTLAYOUT 1191
+#define SVGA_3D_CMD_DX_DESTROY_ELEMENTLAYOUT 1192
+#define SVGA_3D_CMD_DX_DEFINE_BLEND_STATE 1193
+#define SVGA_3D_CMD_DX_DESTROY_BLEND_STATE 1194
+#define SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_STATE 1195
+#define SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_STATE 1196
+#define SVGA_3D_CMD_DX_DEFINE_RASTERIZER_STATE 1197
+#define SVGA_3D_CMD_DX_DESTROY_RASTERIZER_STATE 1198
+#define SVGA_3D_CMD_DX_DEFINE_SAMPLER_STATE 1199
+#define SVGA_3D_CMD_DX_DESTROY_SAMPLER_STATE 1200
+#define SVGA_3D_CMD_DX_DEFINE_SHADER 1201
+#define SVGA_3D_CMD_DX_DESTROY_SHADER 1202
+#define SVGA_3D_CMD_DX_BIND_SHADER 1203
+#define SVGA_3D_CMD_DX_DEFINE_STREAMOUTPUT 1204
+#define SVGA_3D_CMD_DX_DESTROY_STREAMOUTPUT 1205
+#define SVGA_3D_CMD_DX_SET_STREAMOUTPUT 1206
+#define SVGA_3D_CMD_DX_SET_COTABLE 1207
+#define SVGA_3D_CMD_DX_READBACK_COTABLE 1208
+#define SVGA_3D_CMD_DX_BUFFER_COPY 1209
+#define SVGA_3D_CMD_DX_TRANSFER_FROM_BUFFER 1210
+#define SVGA_3D_CMD_DX_SURFACE_COPY_AND_READBACK 1211
+#define SVGA_3D_CMD_DX_MOVE_QUERY 1212
+#define SVGA_3D_CMD_DX_BIND_ALL_QUERY 1213
+#define SVGA_3D_CMD_DX_READBACK_ALL_QUERY 1214
+#define SVGA_3D_CMD_DX_PRED_TRANSFER_FROM_BUFFER 1215
+#define SVGA_3D_CMD_DX_MOB_FENCE_64 1216
+#define SVGA_3D_CMD_DX_BIND_ALL_SHADER 1217
+#define SVGA_3D_CMD_DX_HINT 1218
+#define SVGA_3D_CMD_DX_BUFFER_UPDATE 1219
+#define SVGA_3D_CMD_DX_SET_VS_CONSTANT_BUFFER_OFFSET 1220
+#define SVGA_3D_CMD_DX_SET_PS_CONSTANT_BUFFER_OFFSET 1221
+#define SVGA_3D_CMD_DX_SET_GS_CONSTANT_BUFFER_OFFSET 1222
+#define SVGA_3D_CMD_DX_SET_HS_CONSTANT_BUFFER_OFFSET 1223
+#define SVGA_3D_CMD_DX_SET_DS_CONSTANT_BUFFER_OFFSET 1224
+#define SVGA_3D_CMD_DX_SET_CS_CONSTANT_BUFFER_OFFSET 1225
+
+#define SVGA_3D_CMD_DX_COND_BIND_ALL_SHADER 1226
+#define SVGA_3D_CMD_DX_MAX 1227
+
+#define SVGA_3D_CMD_SCREEN_COPY 1227
+
+#define SVGA_3D_CMD_RESERVED1 1228
+#define SVGA_3D_CMD_RESERVED2 1229
+#define SVGA_3D_CMD_RESERVED3 1230
+#define SVGA_3D_CMD_RESERVED4 1231
+#define SVGA_3D_CMD_RESERVED5 1232
+#define SVGA_3D_CMD_RESERVED6 1233
+#define SVGA_3D_CMD_RESERVED7 1234
+#define SVGA_3D_CMD_RESERVED8 1235
+
+#define SVGA_3D_CMD_GROW_OTABLE 1236
+#define SVGA_3D_CMD_DX_GROW_COTABLE 1237
+#define SVGA_3D_CMD_INTRA_SURFACE_COPY 1238
+
+#define SVGA_3D_CMD_DEFINE_GB_SURFACE_V3 1239
+
+#define SVGA_3D_CMD_DX_RESOLVE_COPY 1240
+#define SVGA_3D_CMD_DX_PRED_RESOLVE_COPY 1241
+#define SVGA_3D_CMD_DX_PRED_CONVERT_REGION 1242
+#define SVGA_3D_CMD_DX_PRED_CONVERT 1243
+#define SVGA_3D_CMD_WHOLE_SURFACE_COPY 1244
+
+#define SVGA_3D_CMD_DX_DEFINE_UA_VIEW 1245
+#define SVGA_3D_CMD_DX_DESTROY_UA_VIEW 1246
+#define SVGA_3D_CMD_DX_CLEAR_UA_VIEW_UINT 1247
+#define SVGA_3D_CMD_DX_CLEAR_UA_VIEW_FLOAT 1248
+#define SVGA_3D_CMD_DX_COPY_STRUCTURE_COUNT 1249
+#define SVGA_3D_CMD_DX_SET_UA_VIEWS 1250
+
+#define SVGA_3D_CMD_DX_DRAW_INDEXED_INSTANCED_INDIRECT 1251
+#define SVGA_3D_CMD_DX_DRAW_INSTANCED_INDIRECT 1252
+#define SVGA_3D_CMD_DX_DISPATCH 1253
+#define SVGA_3D_CMD_DX_DISPATCH_INDIRECT 1254
+
+#define SVGA_3D_CMD_WRITE_ZERO_SURFACE 1255
+#define SVGA_3D_CMD_UPDATE_ZERO_SURFACE 1256
+#define SVGA_3D_CMD_DX_TRANSFER_TO_BUFFER 1257
+#define SVGA_3D_CMD_DX_SET_STRUCTURE_COUNT 1258
+
+#define SVGA_3D_CMD_LOGICOPS_BITBLT 1259
+#define SVGA_3D_CMD_LOGICOPS_TRANSBLT 1260
+#define SVGA_3D_CMD_LOGICOPS_STRETCHBLT 1261
+#define SVGA_3D_CMD_LOGICOPS_COLORFILL 1262
+#define SVGA_3D_CMD_LOGICOPS_ALPHABLEND 1263
+#define SVGA_3D_CMD_LOGICOPS_CLEARTYPEBLEND 1264
+
+#define SVGA_3D_CMD_DX_COPY_COTABLE_INTO_MOB 1265
+
+#define SVGA_3D_CMD_UPDATE_GB_SCREENTARGET_V2 1266
+
+#define SVGA_3D_CMD_DEFINE_GB_SURFACE_V4 1267
+#define SVGA_3D_CMD_DX_SET_CS_UA_VIEWS 1268
+#define SVGA_3D_CMD_DX_SET_MIN_LOD 1269
+
+#define SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_VIEW_V2 1272
+#define SVGA_3D_CMD_DX_DEFINE_STREAMOUTPUT_WITH_MOB 1273
+#define SVGA_3D_CMD_DX_SET_SHADER_IFACE 1274
+#define SVGA_3D_CMD_DX_BIND_STREAMOUTPUT 1275
+#define SVGA_3D_CMD_SURFACE_STRETCHBLT_NON_MS_TO_MS 1276
+#define SVGA_3D_CMD_DX_BIND_SHADER_IFACE 1277
+
+#define SVGA_3D_CMD_UPDATE_GB_SCREENTARGET_MOVE 1278
+
+#define SVGA_3D_CMD_DX_PRED_STAGING_COPY 1281
+#define SVGA_3D_CMD_DX_STAGING_COPY 1282
+#define SVGA_3D_CMD_DX_PRED_STAGING_COPY_REGION 1283
+#define SVGA_3D_CMD_DX_SET_VERTEX_BUFFERS_V2 1284
+#define SVGA_3D_CMD_DX_SET_INDEX_BUFFER_V2 1285
+#define SVGA_3D_CMD_DX_SET_VERTEX_BUFFERS_OFFSET_AND_SIZE 1286
+#define SVGA_3D_CMD_DX_SET_INDEX_BUFFER_OFFSET_AND_SIZE 1287
+#define SVGA_3D_CMD_DX_DEFINE_RASTERIZER_STATE_V2 1288
+#define SVGA_3D_CMD_DX_PRED_STAGING_CONVERT_REGION 1289
+#define SVGA_3D_CMD_DX_PRED_STAGING_CONVERT 1290
+#define SVGA_3D_CMD_DX_STAGING_BUFFER_COPY 1291
+
+#define SVGA_3D_CMD_MAX 1303
+#define SVGA_3D_CMD_FUTURE_MAX 3000
+
+/*
+ * Common substructures used in multiple FIFO commands:
+ */
+
+typedef struct {
+ union {
+ struct {
+ uint16 function; // SVGA3dFogFunction
+ uint8 type; // SVGA3dFogType
+ uint8 base; // SVGA3dFogBase
+ };
+ uint32 uintValue;
+ };
+} SVGA3dFogMode;
+
+/*
+ * Uniquely identify one image (a 1D/2D/3D array) from a surface. This
+ * is a surface ID as well as face/mipmap indices.
+ */
+
+typedef
+struct SVGA3dSurfaceImageId {
+ uint32 sid;
+ uint32 face;
+ uint32 mipmap;
+} SVGA3dSurfaceImageId;
+
+typedef
+struct SVGA3dGuestImage {
+ SVGAGuestPtr ptr;
+
+ /*
+ * A note on interpretation of pitch: This value of pitch is the
+ * number of bytes between vertically adjacent image
+ * blocks. Normally this is the number of bytes between the first
+ * pixel of two adjacent scanlines. With compressed textures,
+ * however, this may represent the number of bytes between
+ * compression blocks rather than between rows of pixels.
+ *
+ * XXX: Compressed textures currently must be tightly packed in guest memory.
+ *
+ * If the image is 1-dimensional, pitch is ignored.
+ *
+ * If 'pitch' is zero, the SVGA3D device calculates a pitch value
+ * assuming each row of blocks is tightly packed.
+ */
+ uint32 pitch;
+} SVGA3dGuestImage;
+
+
+/*
+ * FIFO command format definitions:
+ */
+
+/*
+ * The data size header following cmdNum for every 3d command
+ */
+typedef
+struct {
+ uint32 id;
+ uint32 size;
+} SVGA3dCmdHeader;
+
+/*
+ * A surface is a hierarchy of host VRAM surfaces: 1D, 2D, or 3D, with
+ * optional mipmaps and cube faces.
+ */
+
+typedef
+struct {
+ uint32 width;
+ uint32 height;
+ uint32 depth;
+} SVGA3dSize;
+
+/*
+ * Guest-backed objects definitions.
+ */
+typedef enum {
+ SVGA_OTABLE_MOB = 0,
+ SVGA_OTABLE_MIN = 0,
+ SVGA_OTABLE_SURFACE = 1,
+ SVGA_OTABLE_CONTEXT = 2,
+ SVGA_OTABLE_SHADER = 3,
+ SVGA_OTABLE_SCREENTARGET = 4,
+
+ SVGA_OTABLE_DX9_MAX = 5,
+
+ SVGA_OTABLE_DXCONTEXT = 5,
+ SVGA_OTABLE_DX_MAX = 6,
+
+ SVGA_OTABLE_RESERVED1 = 6,
+ SVGA_OTABLE_RESERVED2 = 7,
+
+ /*
+ * Additions to this table need to be tied to HW-version features and
+ * checkpointed accordingly.
+ */
+ SVGA_OTABLE_DEVEL_MAX = 8,
+ SVGA_OTABLE_MAX = 8
+} SVGAOTableType;
+
+typedef enum {
+ SVGA_COTABLE_MIN = 0,
+ SVGA_COTABLE_RTVIEW = 0,
+ SVGA_COTABLE_DSVIEW = 1,
+ SVGA_COTABLE_SRVIEW = 2,
+ SVGA_COTABLE_ELEMENTLAYOUT = 3,
+ SVGA_COTABLE_BLENDSTATE = 4,
+ SVGA_COTABLE_DEPTHSTENCIL = 5,
+ SVGA_COTABLE_RASTERIZERSTATE = 6,
+ SVGA_COTABLE_SAMPLER = 7,
+ SVGA_COTABLE_STREAMOUTPUT = 8,
+ SVGA_COTABLE_DXQUERY = 9,
+ SVGA_COTABLE_DXSHADER = 10,
+ SVGA_COTABLE_DX10_MAX = 11,
+ SVGA_COTABLE_UAVIEW = 11,
+ SVGA_COTABLE_MAX = 12,
+} SVGACOTableType;
+
+
+/*
+ * The largest size (number of entries) allowed in a COTable.
+ */
+#define SVGA_COTABLE_MAX_IDS (MAX_UINT16 - 2)
+
+typedef enum SVGAMobFormat {
+ SVGA3D_MOBFMT_INVALID = SVGA3D_INVALID_ID,
+ SVGA3D_MOBFMT_PTDEPTH_0 = 0,
+ SVGA3D_MOBFMT_MIN = 0,
+ SVGA3D_MOBFMT_PTDEPTH_1 = 1,
+ SVGA3D_MOBFMT_PTDEPTH_2 = 2,
+ SVGA3D_MOBFMT_RANGE = 3,
+ SVGA3D_MOBFMT_PTDEPTH64_0 = 4,
+ SVGA3D_MOBFMT_PTDEPTH64_1 = 5,
+ SVGA3D_MOBFMT_PTDEPTH64_2 = 6,
+ SVGA3D_MOBFMT_PREDX_MAX = 7,
+ SVGA3D_MOBFMT_EMPTY = 7,
+ SVGA3D_MOBFMT_MAX,
+
+ /*
+ * This isn't actually used by the guest, but is a mob-format used
+ * internally by the SVGA device (and is therefore not binary compatible).
+ */
+ SVGA3D_MOBFMT_HB,
+} SVGAMobFormat;
+
+#define SVGA3D_MOB_EMPTY_BASE 1
+
+/*
+ * Multisample pattern types.
+ */
+
+typedef enum SVGA3dMSPattern {
+ SVGA3D_MS_PATTERN_NONE = 0,
+ SVGA3D_MS_PATTERN_MIN = 0,
+ SVGA3D_MS_PATTERN_STANDARD = 1,
+ SVGA3D_MS_PATTERN_CENTER = 2,
+ SVGA3D_MS_PATTERN_MAX = 3,
+} SVGA3dMSPattern;
+
+/*
+ * Precision settings for each sample.
+ */
+
+typedef enum SVGA3dMSQualityLevel {
+ SVGA3D_MS_QUALITY_NONE = 0,
+ SVGA3D_MS_QUALITY_MIN = 0,
+ SVGA3D_MS_QUALITY_FULL = 1,
+ SVGA3D_MS_QUALITY_MAX = 2,
+} SVGA3dMSQualityLevel;
+
+
+typedef enum {
+ SVGA3D_SURFACE_CUBEMAP = (1 << 0),
+ SVGA3D_SURFACE_HINT_STATIC = (1 << 1),
+ SVGA3D_SURFACE_HINT_DYNAMIC = (1 << 2),
+ SVGA3D_SURFACE_HINT_INDEXBUFFER = (1 << 3),
+ SVGA3D_SURFACE_HINT_VERTEXBUFFER = (1 << 4),
+ SVGA3D_SURFACE_HINT_TEXTURE = (1 << 5),
+ SVGA3D_SURFACE_HINT_RENDERTARGET = (1 << 6),
+ SVGA3D_SURFACE_HINT_DEPTHSTENCIL = (1 << 7),
+ SVGA3D_SURFACE_HINT_WRITEONLY = (1 << 8),
+ SVGA3D_SURFACE_MASKABLE_ANTIALIAS = (1 << 9),
+ SVGA3D_SURFACE_AUTOGENMIPMAPS = (1 << 10),
+} SVGA3dSurfaceFlags;
+
+typedef
+struct {
+ uint32 numMipLevels;
+} SVGA3dSurfaceFace;
+
+typedef
+struct {
+ uint32 sid;
+ SVGA3dSurfaceFlags surfaceFlags;
+ SVGA3dSurfaceFormat format;
+ /*
+ * If surfaceFlags has SVGA3D_SURFACE_CUBEMAP bit set, all SVGA3dSurfaceFace
+ * structures must have the same value of numMipLevels field.
+ * Otherwise, all but the first SVGA3dSurfaceFace structures must have the
+ * numMipLevels set to 0.
+ */
+ SVGA3dSurfaceFace face[SVGA3D_MAX_SURFACE_FACES];
+ /*
+ * Followed by an SVGA3dSize structure for each mip level in each face.
+ *
+ * A note on surface sizes: Sizes are always specified in pixels,
+ * even if the true surface size is not a multiple of the minimum
+ * block size of the surface's format. For example, a 3x3x1 DXT1
+ * compressed texture would actually be stored as a 4x4x1 image in
+ * memory.
+ */
+} SVGA3dCmdDefineSurface; /* SVGA_3D_CMD_SURFACE_DEFINE */
+
+typedef
+struct {
+ uint32 sid;
+ SVGA3dSurfaceFlags surfaceFlags;
+ SVGA3dSurfaceFormat format;
+ /*
+ * If surfaceFlags has SVGA3D_SURFACE_CUBEMAP bit set, all SVGA3dSurfaceFace
+ * structures must have the same value of numMipLevels field.
+ * Otherwise, all but the first SVGA3dSurfaceFace structures must have the
+ * numMipLevels set to 0.
+ */
+ SVGA3dSurfaceFace face[SVGA3D_MAX_SURFACE_FACES];
+ uint32 multisampleCount;
+ SVGA3dTextureFilter autogenFilter;
+ /*
+ * Followed by an SVGA3dSize structure for each mip level in each face.
+ *
+ * A note on surface sizes: Sizes are always specified in pixels,
+ * even if the true surface size is not a multiple of the minimum
+ * block size of the surface's format. For example, a 3x3x1 DXT1
+ * compressed texture would actually be stored as a 4x4x1 image in
+ * memory.
+ */
+} SVGA3dCmdDefineSurface_v2; /* SVGA_3D_CMD_SURFACE_DEFINE_V2 */
+
+typedef
+struct {
+ uint32 sid;
+} SVGA3dCmdDestroySurface; /* SVGA_3D_CMD_SURFACE_DESTROY */
+
+typedef
+struct {
+ uint32 cid;
+} SVGA3dCmdDefineContext; /* SVGA_3D_CMD_CONTEXT_DEFINE */
+
+typedef
+struct {
+ uint32 cid;
+} SVGA3dCmdDestroyContext; /* SVGA_3D_CMD_CONTEXT_DESTROY */
+
+typedef
+struct {
+ uint32 cid;
+ SVGA3dClearFlag clearFlag;
+ uint32 color;
+ float depth;
+ uint32 stencil;
+ /* Followed by variable number of SVGA3dRect structures */
+} SVGA3dCmdClear; /* SVGA_3D_CMD_CLEAR */
+
+typedef
+struct SVGA3dCopyRect {
+ uint32 x;
+ uint32 y;
+ uint32 w;
+ uint32 h;
+ uint32 srcx;
+ uint32 srcy;
+} SVGA3dCopyRect;
+
+typedef
+struct SVGA3dCopyBox {
+ uint32 x;
+ uint32 y;
+ uint32 z;
+ uint32 w;
+ uint32 h;
+ uint32 d;
+ uint32 srcx;
+ uint32 srcy;
+ uint32 srcz;
+} SVGA3dCopyBox;
+
+typedef
+struct {
+ uint32 x;
+ uint32 y;
+ uint32 w;
+ uint32 h;
+} SVGA3dRect;
+
+typedef
+struct {
+ uint32 x;
+ uint32 y;
+ uint32 z;
+ uint32 w;
+ uint32 h;
+ uint32 d;
+} SVGA3dBox;
+
+typedef
+struct {
+ uint32 x;
+ uint32 y;
+ uint32 z;
+} SVGA3dPoint;
+
+typedef
+struct {
+ SVGA3dLightType type;
+ SVGA3dBool inWorldSpace;
+ float diffuse[4];
+ float specular[4];
+ float ambient[4];
+ float position[4];
+ float direction[4];
+ float range;
+ float falloff;
+ float attenuation0;
+ float attenuation1;
+ float attenuation2;
+ float theta;
+ float phi;
+} SVGA3dLightData;
+
+typedef
+struct {
+ uint32 sid;
+ /* Followed by variable number of SVGA3dCopyRect structures */
+} SVGA3dCmdPresent; /* SVGA_3D_CMD_PRESENT */
+
+typedef
+struct {
+ SVGA3dRenderStateName state;
+ union {
+ uint32 uintValue;
+ float floatValue;
+ };
+} SVGA3dRenderState;
+
+typedef
+struct {
+ uint32 cid;
+ /* Followed by variable number of SVGA3dRenderState structures */
+} SVGA3dCmdSetRenderState; /* SVGA_3D_CMD_SETRENDERSTATE */
+
+typedef
+struct {
+ uint32 cid;
+ SVGA3dRenderTargetType type;
+ SVGA3dSurfaceImageId target;
+} SVGA3dCmdSetRenderTarget; /* SVGA_3D_CMD_SETRENDERTARGET */
+
+typedef
+struct {
+ SVGA3dSurfaceImageId src;
+ SVGA3dSurfaceImageId dest;
+ /* Followed by variable number of SVGA3dCopyBox structures */
+} SVGA3dCmdSurfaceCopy; /* SVGA_3D_CMD_SURFACE_COPY */
+
+typedef
+struct {
+ SVGA3dSurfaceImageId src;
+ SVGA3dSurfaceImageId dest;
+ SVGA3dBox boxSrc;
+ SVGA3dBox boxDest;
+ SVGA3dStretchBltMode mode;
+} SVGA3dCmdSurfaceStretchBlt; /* SVGA_3D_CMD_SURFACE_STRETCHBLT */
+
+typedef
+struct {
+ /*
+ * If the discard flag is present in a surface DMA operation, the host may
+ * discard the contents of the current mipmap level and face of the target
+ * surface before applying the surface DMA contents.
+ */
+ uint32 discard : 1;
+
+ /*
+ * If the unsynchronized flag is present, the host may perform this upload
+ * without syncing to pending reads on this surface.
+ */
+ uint32 unsynchronized : 1;
+
+ /*
+ * Guests *MUST* set the reserved bits to 0 before submitting the command
+ * suffix as future flags may occupy these bits.
+ */
+ uint32 reserved : 30;
+} SVGA3dSurfaceDMAFlags;
+
+typedef
+struct {
+ SVGA3dGuestImage guest;
+ SVGA3dSurfaceImageId host;
+ SVGA3dTransferType transfer;
+ /*
+ * Followed by variable number of SVGA3dCopyBox structures. For consistency
+ * in all clipping logic and coordinate translation, we define the
+ * "source" in each copyBox as the guest image and the
+ * "destination" as the host image, regardless of transfer
+ * direction.
+ *
+ * For efficiency, the SVGA3D device is free to copy more data than
+ * specified. For example, it may round copy boxes outwards such
+ * that they lie on particular alignment boundaries.
+ */
+} SVGA3dCmdSurfaceDMA; /* SVGA_3D_CMD_SURFACE_DMA */
+
+/*
+ * SVGA3dCmdSurfaceDMASuffix --
+ *
+ * This is a command suffix that will appear after a SurfaceDMA command in
+ * the FIFO. It contains some extra information that hosts may use to
+ * optimize performance or protect the guest. This suffix exists to preserve
+ * backwards compatibility while also allowing for new functionality to be
+ * implemented.
+ */
+
+typedef
+struct {
+ uint32 suffixSize;
+
+ /*
+ * The maximum offset is used to determine the maximum offset from the
+ * guestPtr base address that will be accessed or written to during this
+ * surfaceDMA. If the suffix is supported, the host will respect this
+ * boundary while performing surface DMAs.
+ *
+ * Defaults to MAX_UINT32
+ */
+ uint32 maximumOffset;
+
+ /*
+ * A set of flags that describes optimizations that the host may perform
+ * while performing this surface DMA operation. The guest should never rely
+ * on behaviour that is different when these flags are set for correctness.
+ *
+ * Defaults to 0
+ */
+ SVGA3dSurfaceDMAFlags flags;
+} SVGA3dCmdSurfaceDMASuffix;
+
+/*
+ * SVGA_3D_CMD_DRAW_PRIMITIVES --
+ *
+ * This command is the SVGA3D device's generic drawing entry point.
+ * It can draw multiple ranges of primitives, optionally using an
+ * index buffer, using an arbitrary collection of vertex buffers.
+ *
+ * Each SVGA3dVertexDecl defines a distinct vertex array to bind
+ * during this draw call. The declarations specify which surface
+ * the vertex data lives in, what that vertex data is used for,
+ * and how to interpret it.
+ *
+ * Each SVGA3dPrimitiveRange defines a collection of primitives
+ * to render using the same vertex arrays. An index buffer is
+ * optional.
+ */
+
+typedef
+struct {
+ /*
+ * A range hint is an optional specification for the range of indices
+ * in an SVGA3dArray that will be used. If 'last' is zero, it is assumed
+ * that the entire array will be used.
+ *
+ * These are only hints. The SVGA3D device may use them for
+ * performance optimization if possible, but it's also allowed to
+ * ignore these values.
+ */
+ uint32 first;
+ uint32 last;
+} SVGA3dArrayRangeHint;
+
+typedef
+struct {
+ /*
+ * Define the origin and shape of a vertex or index array. Both
+ * 'offset' and 'stride' are in bytes. The provided surface will be
+ * reinterpreted as a flat array of bytes in the same format used
+ * by surface DMA operations. To avoid unnecessary conversions, the
+ * surface should be created with the SVGA3D_BUFFER format.
+ *
+ * Index 0 in the array starts 'offset' bytes into the surface.
+ * Index 1 begins at byte 'offset + stride', etc. Array indices may
+ * not be negative.
+ */
+ uint32 surfaceId;
+ uint32 offset;
+ uint32 stride;
+} SVGA3dArray;
+
+typedef
+struct {
+ /*
+ * Describe a vertex array's data type, and define how it is to be
+ * used by the fixed function pipeline or the vertex shader. It
+ * isn't useful to have two VertexDecls with the same
+ * VertexArrayIdentity in one draw call.
+ */
+ SVGA3dDeclType type;
+ SVGA3dDeclMethod method;
+ SVGA3dDeclUsage usage;
+ uint32 usageIndex;
+} SVGA3dVertexArrayIdentity;
+
+typedef
+struct {
+ SVGA3dVertexArrayIdentity identity;
+ SVGA3dArray array;
+ SVGA3dArrayRangeHint rangeHint;
+} SVGA3dVertexDecl;
+
+typedef
+struct {
+ /*
+ * Define a group of primitives to render, from sequential indices.
+ *
+ * The value of 'primitiveType' and 'primitiveCount' imply the
+ * total number of vertices that will be rendered.
+ */
+ SVGA3dPrimitiveType primType;
+ uint32 primitiveCount;
+
+ /*
+ * Optional index buffer. If indexArray.surfaceId is
+ * SVGA3D_INVALID_ID, we render without an index buffer. Rendering
+ * without an index buffer is identical to rendering with an index
+ * buffer containing the sequence [0, 1, 2, 3, ...].
+ *
+ * If an index buffer is in use, indexWidth specifies the width in
+ * bytes of each index value. It must be less than or equal to
+ * indexArray.stride.
+ *
+ * (Currently, the SVGA3D device requires index buffers to be tightly
+ * packed. In other words, indexWidth == indexArray.stride)
+ */
+ SVGA3dArray indexArray;
+ uint32 indexWidth;
+
+ /*
+ * Optional index bias. This number is added to all indices from
+ * indexArray before they are used as vertex array indices. This
+ * can be used in multiple ways:
+ *
+ * - When not using an indexArray, this bias can be used to
+ * specify where in the vertex arrays to begin rendering.
+ *
+ * - A positive number here is equivalent to increasing the
+ * offset in each vertex array.
+ *
+ * - A negative number can be used to render using a small
+ * vertex array and an index buffer that contains large
+ * values. This may be used by some applications that
+ * crop a vertex buffer without modifying their index
+ * buffer.
+ *
+ * Note that rendering with a negative bias value may be slower and
+ * use more memory than rendering with a positive or zero bias.
+ */
+ int32 indexBias;
+} SVGA3dPrimitiveRange;
+
+typedef
+struct {
+ uint32 cid;
+ uint32 numVertexDecls;
+ uint32 numRanges;
+
+ /*
+ * There are two variable size arrays after the
+ * SVGA3dCmdDrawPrimitives structure. In order,
+ * they are:
+ *
+ * 1. SVGA3dVertexDecl, quantity 'numVertexDecls', but no more than
+ * SVGA3D_MAX_VERTEX_ARRAYS;
+ * 2. SVGA3dPrimitiveRange, quantity 'numRanges', but no more than
+ * SVGA3D_MAX_DRAW_PRIMITIVE_RANGES;
+ * 3. Optionally, SVGA3dVertexDivisor, quantity 'numVertexDecls' (contains
+ * the frequency divisor for the corresponding vertex decl).
+ */
+} SVGA3dCmdDrawPrimitives; /* SVGA_3D_CMD_DRAWPRIMITIVES */
+
+typedef
+struct {
+ uint32 stage;
+ SVGA3dTextureStateName name;
+ union {
+ uint32 value;
+ float floatValue;
+ };
+} SVGA3dTextureState;
+
+typedef
+struct {
+ uint32 cid;
+ /* Followed by variable number of SVGA3dTextureState structures */
+} SVGA3dCmdSetTextureState; /* SVGA_3D_CMD_SETTEXTURESTATE */
+
+typedef
+struct {
+ uint32 cid;
+ SVGA3dTransformType type;
+ float matrix[16];
+} SVGA3dCmdSetTransform; /* SVGA_3D_CMD_SETTRANSFORM */
+
+typedef
+struct {
+ float min;
+ float max;
+} SVGA3dZRange;
+
+typedef
+struct {
+ uint32 cid;
+ SVGA3dZRange zRange;
+} SVGA3dCmdSetZRange; /* SVGA_3D_CMD_SETZRANGE */
+
+typedef
+struct {
+ float diffuse[4];
+ float ambient[4];
+ float specular[4];
+ float emissive[4];
+ float shininess;
+} SVGA3dMaterial;
+
+typedef
+struct {
+ uint32 cid;
+ SVGA3dFace face;
+ SVGA3dMaterial material;
+} SVGA3dCmdSetMaterial; /* SVGA_3D_CMD_SETMATERIAL */
+
+typedef
+struct {
+ uint32 cid;
+ uint32 index;
+ SVGA3dLightData data;
+} SVGA3dCmdSetLightData; /* SVGA_3D_CMD_SETLIGHTDATA */
+
+typedef
+struct {
+ uint32 cid;
+ uint32 index;
+ uint32 enabled;
+} SVGA3dCmdSetLightEnabled; /* SVGA_3D_CMD_SETLIGHTENABLED */
+
+typedef
+struct {
+ uint32 cid;
+ SVGA3dRect rect;
+} SVGA3dCmdSetViewport; /* SVGA_3D_CMD_SETVIEWPORT */
+
+typedef
+struct {
+ uint32 cid;
+ SVGA3dRect rect;
+} SVGA3dCmdSetScissorRect; /* SVGA_3D_CMD_SETSCISSORRECT */
+
+typedef
+struct {
+ uint32 cid;
+ uint32 index;
+ float plane[4];
+} SVGA3dCmdSetClipPlane; /* SVGA_3D_CMD_SETCLIPPLANE */
+
+typedef
+struct {
+ uint32 cid;
+ uint32 shid;
+ SVGA3dShaderType type;
+ /* Followed by variable number of DWORDs for shader bycode */
+} SVGA3dCmdDefineShader; /* SVGA_3D_CMD_SHADER_DEFINE */
+
+typedef
+struct {
+ uint32 cid;
+ uint32 shid;
+ SVGA3dShaderType type;
+} SVGA3dCmdDestroyShader; /* SVGA_3D_CMD_SHADER_DESTROY */
+
+typedef
+struct {
+ uint32 cid;
+ uint32 reg; /* register number */
+ SVGA3dShaderType type;
+ SVGA3dShaderConstType ctype;
+ uint32 values[4];
+} SVGA3dCmdSetShaderConst; /* SVGA_3D_CMD_SET_SHADER_CONST */
+
+typedef
+struct {
+ uint32 cid;
+ SVGA3dShaderType type;
+ uint32 shid;
+} SVGA3dCmdSetShader; /* SVGA_3D_CMD_SET_SHADER */
+
+typedef
+struct {
+ uint32 cid;
+ SVGA3dQueryType type;
+} SVGA3dCmdBeginQuery; /* SVGA_3D_CMD_BEGIN_QUERY */
+
+typedef
+struct {
+ uint32 cid;
+ SVGA3dQueryType type;
+ SVGAGuestPtr guestResult; /* Points to an SVGA3dQueryResult structure */
+} SVGA3dCmdEndQuery; /* SVGA_3D_CMD_END_QUERY */
+
+typedef
+struct {
+ uint32 cid; /* Same parameters passed to END_QUERY */
+ SVGA3dQueryType type;
+ SVGAGuestPtr guestResult;
+} SVGA3dCmdWaitForQuery; /* SVGA_3D_CMD_WAIT_FOR_QUERY */
+
+typedef
+struct {
+ uint32 totalSize; /* Set by guest before query is ended. */
+ SVGA3dQueryState state; /* Set by host or guest. See SVGA3dQueryState. */
+ union { /* Set by host on exit from PENDING state */
+ uint32 result32;
+ };
+} SVGA3dQueryResult;
+
+/*
+ * SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN --
+ *
+ * This is a blit from an SVGA3D surface to a Screen Object. Just
+ * like GMR-to-screen blits, this blit may be directed at a
+ * specific screen or to the virtual coordinate space.
+ *
+ * The blit copies from a rectangular region of an SVGA3D surface
+ * image to a rectangular region of a screen or screens.
+ *
+ * This command takes an optional variable-length list of clipping
+ * rectangles after the body of the command. If no rectangles are
+ * specified, there is no clipping region. The entire destRect is
+ * drawn to. If one or more rectangles are included, they describe
+ * a clipping region. The clip rectangle coordinates are measured
+ * relative to the top-left corner of destRect.
+ *
+ * This clipping region serves multiple purposes:
+ *
+ * - It can be used to perform an irregularly shaped blit more
+ * efficiently than by issuing many separate blit commands.
+ *
+ * - It is equivalent to allowing blits with non-integer
+ * source coordinates. You could blit just one half-pixel
+ * of a source, for example, by specifying a larger
+ * destination rectangle than you need, then removing
+ * part of it using a clip rectangle.
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_SCREEN_OBJECT
+ *
+ * Limitations:
+ *
+ * - Currently, no backend supports blits from a mipmap or face
+ * other than the first one.
+ */
+
+typedef
+struct {
+ SVGA3dSurfaceImageId srcImage;
+ SVGASignedRect srcRect;
+ uint32 destScreenId; /* Screen ID or SVGA_ID_INVALID for virt. coords */
+ SVGASignedRect destRect; /* Supports scaling if src/rest different size */
+ /* Clipping: zero or more SVGASignedRects follow */
+} SVGA3dCmdBlitSurfaceToScreen; /* SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN */
+
+typedef
+struct {
+ uint32 sid;
+ SVGA3dTextureFilter filter;
+} SVGA3dCmdGenerateMipmaps; /* SVGA_3D_CMD_GENERATE_MIPMAPS */
+
+
+/*
+ * Capability query index.
+ *
+ * Notes:
+ *
+ * 1. SVGA3D_DEVCAP_MAX_TEXTURES reflects the maximum number of
+ * fixed-function texture units available. Each of these units
+ * work in both FFP and Shader modes, and they support texture
+ * transforms and texture coordinates. The host may have additional
+ * texture image units that are only usable with shaders.
+ *
+ * 2. The BUFFER_FORMAT capabilities are deprecated, and they always
+ * return TRUE. Even on physical hardware that does not support
+ * these formats natively, the SVGA3D device will provide an emulation
+ * which should be invisible to the guest OS.
+ *
+ * In general, the SVGA3D device should support any operation on
+ * any surface format, it just may perform some of these
+ * operations in software depending on the capabilities of the
+ * available physical hardware.
+ *
+ * XXX: In the future, we will add capabilities that describe in
+ * detail what formats are supported in hardware for what kinds
+ * of operations.
+ */
+
+typedef enum {
+ SVGA3D_DEVCAP_3D = 0,
+ SVGA3D_DEVCAP_MAX_LIGHTS = 1,
+ SVGA3D_DEVCAP_MAX_TEXTURES = 2, /* See note (1) */
+ SVGA3D_DEVCAP_MAX_CLIP_PLANES = 3,
+ SVGA3D_DEVCAP_VERTEX_SHADER_VERSION = 4,
+ SVGA3D_DEVCAP_VERTEX_SHADER = 5,
+ SVGA3D_DEVCAP_FRAGMENT_SHADER_VERSION = 6,
+ SVGA3D_DEVCAP_FRAGMENT_SHADER = 7,
+ SVGA3D_DEVCAP_MAX_RENDER_TARGETS = 8,
+ SVGA3D_DEVCAP_S23E8_TEXTURES = 9,
+ SVGA3D_DEVCAP_S10E5_TEXTURES = 10,
+ SVGA3D_DEVCAP_MAX_FIXED_VERTEXBLEND = 11,
+ SVGA3D_DEVCAP_D16_BUFFER_FORMAT = 12, /* See note (2) */
+ SVGA3D_DEVCAP_D24S8_BUFFER_FORMAT = 13, /* See note (2) */
+ SVGA3D_DEVCAP_D24X8_BUFFER_FORMAT = 14, /* See note (2) */
+ SVGA3D_DEVCAP_QUERY_TYPES = 15,
+ SVGA3D_DEVCAP_TEXTURE_GRADIENT_SAMPLING = 16,
+ SVGA3D_DEVCAP_MAX_POINT_SIZE = 17,
+ SVGA3D_DEVCAP_MAX_SHADER_TEXTURES = 18,
+ SVGA3D_DEVCAP_MAX_TEXTURE_WIDTH = 19,
+ SVGA3D_DEVCAP_MAX_TEXTURE_HEIGHT = 20,
+ SVGA3D_DEVCAP_MAX_VOLUME_EXTENT = 21,
+ SVGA3D_DEVCAP_MAX_TEXTURE_REPEAT = 22,
+ SVGA3D_DEVCAP_MAX_TEXTURE_ASPECT_RATIO = 23,
+ SVGA3D_DEVCAP_MAX_TEXTURE_ANISOTROPY = 24,
+ SVGA3D_DEVCAP_MAX_PRIMITIVE_COUNT = 25,
+ SVGA3D_DEVCAP_MAX_VERTEX_INDEX = 26,
+ SVGA3D_DEVCAP_MAX_VERTEX_SHADER_INSTRUCTIONS = 27,
+ SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_INSTRUCTIONS = 28,
+ SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEMPS = 29,
+ SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_TEMPS = 30,
+ SVGA3D_DEVCAP_TEXTURE_OPS = 31,
+ SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8 = 32,
+ SVGA3D_DEVCAP_SURFACEFMT_A8R8G8B8 = 33,
+ SVGA3D_DEVCAP_SURFACEFMT_A2R10G10B10 = 34,
+ SVGA3D_DEVCAP_SURFACEFMT_X1R5G5B5 = 35,
+ SVGA3D_DEVCAP_SURFACEFMT_A1R5G5B5 = 36,
+ SVGA3D_DEVCAP_SURFACEFMT_A4R4G4B4 = 37,
+ SVGA3D_DEVCAP_SURFACEFMT_R5G6B5 = 38,
+ SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE16 = 39,
+ SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8_ALPHA8 = 40,
+ SVGA3D_DEVCAP_SURFACEFMT_ALPHA8 = 41,
+ SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8 = 42,
+ SVGA3D_DEVCAP_SURFACEFMT_Z_D16 = 43,
+ SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8 = 44,
+ SVGA3D_DEVCAP_SURFACEFMT_Z_D24X8 = 45,
+ SVGA3D_DEVCAP_SURFACEFMT_DXT1 = 46,
+ SVGA3D_DEVCAP_SURFACEFMT_DXT2 = 47,
+ SVGA3D_DEVCAP_SURFACEFMT_DXT3 = 48,
+ SVGA3D_DEVCAP_SURFACEFMT_DXT4 = 49,
+ SVGA3D_DEVCAP_SURFACEFMT_DXT5 = 50,
+ SVGA3D_DEVCAP_SURFACEFMT_BUMPX8L8V8U8 = 51,
+ SVGA3D_DEVCAP_SURFACEFMT_A2W10V10U10 = 52,
+ SVGA3D_DEVCAP_SURFACEFMT_BUMPU8V8 = 53,
+ SVGA3D_DEVCAP_SURFACEFMT_Q8W8V8U8 = 54,
+ SVGA3D_DEVCAP_SURFACEFMT_CxV8U8 = 55,
+ SVGA3D_DEVCAP_SURFACEFMT_R_S10E5 = 56,
+ SVGA3D_DEVCAP_SURFACEFMT_R_S23E8 = 57,
+ SVGA3D_DEVCAP_SURFACEFMT_RG_S10E5 = 58,
+ SVGA3D_DEVCAP_SURFACEFMT_RG_S23E8 = 59,
+ SVGA3D_DEVCAP_SURFACEFMT_ARGB_S10E5 = 60,
+ SVGA3D_DEVCAP_SURFACEFMT_ARGB_S23E8 = 61,
+ SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEXTURES = 63,
+
+ /*
+ * Note that MAX_SIMULTANEOUS_RENDER_TARGETS is a maximum count of color
+ * render targets. This does no include the depth or stencil targets.
+ */
+ SVGA3D_DEVCAP_MAX_SIMULTANEOUS_RENDER_TARGETS = 64,
+
+ SVGA3D_DEVCAP_SURFACEFMT_V16U16 = 65,
+ SVGA3D_DEVCAP_SURFACEFMT_G16R16 = 66,
+ SVGA3D_DEVCAP_SURFACEFMT_A16B16G16R16 = 67,
+ SVGA3D_DEVCAP_SURFACEFMT_UYVY = 68,
+ SVGA3D_DEVCAP_SURFACEFMT_YUY2 = 69,
+ SVGA3D_DEVCAP_MULTISAMPLE_NONMASKABLESAMPLES = 70,
+ SVGA3D_DEVCAP_MULTISAMPLE_MASKABLESAMPLES = 71,
+ SVGA3D_DEVCAP_ALPHATOCOVERAGE = 72,
+ SVGA3D_DEVCAP_SUPERSAMPLE = 73,
+ SVGA3D_DEVCAP_AUTOGENMIPMAPS = 74,
+ SVGA3D_DEVCAP_SURFACEFMT_NV12 = 75,
+ SVGA3D_DEVCAP_SURFACEFMT_AYUV = 76,
+
+ /*
+ * This is the maximum number of SVGA context IDs that the guest
+ * can define using SVGA_3D_CMD_CONTEXT_DEFINE.
+ */
+ SVGA3D_DEVCAP_MAX_CONTEXT_IDS = 77,
+
+ /*
+ * This is the maximum number of SVGA surface IDs that the guest
+ * can define using SVGA_3D_CMD_SURFACE_DEFINE*.
+ */
+ SVGA3D_DEVCAP_MAX_SURFACE_IDS = 78,
+
+ SVGA3D_DEVCAP_SURFACEFMT_Z_DF16 = 79,
+ SVGA3D_DEVCAP_SURFACEFMT_Z_DF24 = 80,
+ SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8_INT = 81,
+
+ SVGA3D_DEVCAP_SURFACEFMT_BC4_UNORM = 82,
+ SVGA3D_DEVCAP_SURFACEFMT_BC5_UNORM = 83,
+
+ /*
+ * Don't add new caps into the previous section; the values in this
+ * enumeration must not change. You can put new values right before
+ * SVGA3D_DEVCAP_MAX.
+ */
+ SVGA3D_DEVCAP_MAX /* This must be the last index. */
+} SVGA3dDevCapIndex;
+
+typedef union {
+ Bool b;
+ uint32 u;
+ int32 i;
+ float f;
+} SVGA3dDevCapResult;
+
+/*******************************************************************************
+ *
+ * G P U 1 0
+ *
+ ******************************************************************************/
+
+/* https://elixir.bootlin.com/linux/v5.2-rc3/source/drivers/gpu/drm/vmwgfx/device_include/svga3d_cmd.h */
+
+/*
+ * Screen DMA command
+ *
+ * Available with SVGA_FIFO_CAP_SCREEN_OBJECT_2. The SVGA_CAP_3D device
+ * cap bit is not required.
+ *
+ * - refBuffer and destBuffer are 32bit BGRX; refBuffer and destBuffer could
+ * be different, but it is required that guest makes sure refBuffer has
+ * exactly the same contents that were written to when last time screen DMA
+ * command is received by host.
+ *
+ * - changemap is generated by lib/blit, and it has the changes from last
+ * received screen DMA or more.
+ */
+
+typedef struct SVGA3dCmdScreenDMA {
+ uint32 screenId;
+ SVGAGuestImage refBuffer;
+ SVGAGuestImage destBuffer;
+ SVGAGuestImage changeMap;
+}
+SVGA3dCmdScreenDMA; /* SVGA_3D_CMD_SCREEN_DMA */
+
+/*
+ * Logic ops
+ */
+
+#define SVGA3D_LOTRANSBLT_HONORALPHA (0x01)
+#define SVGA3D_LOSTRETCHBLT_MIRRORX (0x01)
+#define SVGA3D_LOSTRETCHBLT_MIRRORY (0x02)
+#define SVGA3D_LOALPHABLEND_SRCHASALPHA (0x01)
+
+typedef
+struct SVGA3dCmdLogicOpsBitBlt {
+ /*
+ * All LogicOps surfaces are one-level
+ * surfaces so mipmap & face should always
+ * be zero.
+ */
+ SVGA3dSurfaceImageId src;
+ SVGA3dSurfaceImageId dst;
+ SVGA3dLogicOp logicOp;
+ /* Followed by variable number of SVGA3dCopyBox structures */
+}
+SVGA3dCmdLogicOpsBitBlt; /* SVGA_3D_CMD_LOGICOPS_BITBLT */
+
+
+typedef
+struct SVGA3dCmdLogicOpsTransBlt {
+ /*
+ * All LogicOps surfaces are one-level
+ * surfaces so mipmap & face should always
+ * be zero.
+ */
+ SVGA3dSurfaceImageId src;
+ SVGA3dSurfaceImageId dst;
+ uint32 color;
+ uint32 flags;
+ SVGA3dBox srcBox;
+ SVGA3dBox dstBox;
+}
+SVGA3dCmdLogicOpsTransBlt; /* SVGA_3D_CMD_LOGICOPS_TRANSBLT */
+
+
+typedef
+struct SVGA3dCmdLogicOpsStretchBlt {
+ /*
+ * All LogicOps surfaces are one-level
+ * surfaces so mipmap & face should always
+ * be zero.
+ */
+ SVGA3dSurfaceImageId src;
+ SVGA3dSurfaceImageId dst;
+ uint16 mode;
+ uint16 flags;
+ SVGA3dBox srcBox;
+ SVGA3dBox dstBox;
+}
+SVGA3dCmdLogicOpsStretchBlt; /* SVGA_3D_CMD_LOGICOPS_STRETCHBLT */
+
+
+typedef
+struct SVGA3dCmdLogicOpsColorFill {
+ /*
+ * All LogicOps surfaces are one-level
+ * surfaces so mipmap & face should always
+ * be zero.
+ */
+ SVGA3dSurfaceImageId dst;
+ uint32 color;
+ SVGA3dLogicOp logicOp;
+ /* Followed by variable number of SVGA3dRect structures. */
+}
+SVGA3dCmdLogicOpsColorFill; /* SVGA_3D_CMD_LOGICOPS_COLORFILL */
+
+
+typedef
+struct SVGA3dCmdLogicOpsAlphaBlend {
+ /*
+ * All LogicOps surfaces are one-level
+ * surfaces so mipmap & face should always
+ * be zero.
+ */
+ SVGA3dSurfaceImageId src;
+ SVGA3dSurfaceImageId dst;
+ uint32 alphaVal;
+ uint32 flags;
+ SVGA3dBox srcBox;
+ SVGA3dBox dstBox;
+}
+SVGA3dCmdLogicOpsAlphaBlend; /* SVGA_3D_CMD_LOGICOPS_ALPHABLEND */
+
+#define SVGA3D_CLEARTYPE_INVALID_GAMMA_INDEX 0xFFFFFFFF
+
+#define SVGA3D_CLEARTYPE_GAMMA_WIDTH 512
+#define SVGA3D_CLEARTYPE_GAMMA_HEIGHT 16
+
+typedef
+struct SVGA3dCmdLogicOpsClearTypeBlend {
+ /*
+ * All LogicOps surfaces are one-level
+ * surfaces so mipmap & face should always
+ * be zero.
+ */
+ SVGA3dSurfaceImageId tmp;
+ SVGA3dSurfaceImageId dst;
+ SVGA3dSurfaceImageId gammaSurf;
+ SVGA3dSurfaceImageId alphaSurf;
+ uint32 gamma;
+ uint32 color;
+ uint32 color2;
+ int32 alphaOffsetX;
+ int32 alphaOffsetY;
+ /* Followed by variable number of SVGA3dBox structures */
+}
+SVGA3dCmdLogicOpsClearTypeBlend; /* SVGA_3D_CMD_LOGICOPS_CLEARTYPEBLEND */
+
+
+/*
+ * Guest-backed objects definitions.
+ */
+
+typedef
+struct {
+ SVGAMobFormat ptDepth;
+ uint32 sizeInBytes;
+ PPN64 base;
+}
+SVGAOTableMobEntry;
+#define SVGA3D_OTABLE_MOB_ENTRY_SIZE (sizeof(SVGAOTableMobEntry))
+
+typedef
+struct {
+ SVGA3dSurfaceFormat format;
+ SVGA3dSurface1Flags surface1Flags;
+ uint32 numMipLevels;
+ uint32 multisampleCount;
+ SVGA3dTextureFilter autogenFilter;
+ SVGA3dSize size;
+ SVGAMobId mobid;
+ uint32 arraySize;
+ uint32 mobPitch;
+ SVGA3dSurface2Flags surface2Flags;
+ uint8 multisamplePattern;
+ uint8 qualityLevel;
+ uint8 pad0[2];
+ uint32 pad1[3];
+}
+SVGAOTableSurfaceEntry;
+#define SVGA3D_OTABLE_SURFACE_ENTRY_SIZE (sizeof(SVGAOTableSurfaceEntry))
+
+typedef
+struct {
+ uint32 cid;
+ SVGAMobId mobid;
+}
+SVGAOTableContextEntry;
+#define SVGA3D_OTABLE_CONTEXT_ENTRY_SIZE (sizeof(SVGAOTableContextEntry))
+
+typedef
+struct {
+ SVGA3dShaderType type;
+ uint32 sizeInBytes;
+ uint32 offsetInBytes;
+ SVGAMobId mobid;
+}
+SVGAOTableShaderEntry;
+#define SVGA3D_OTABLE_SHADER_ENTRY_SIZE (sizeof(SVGAOTableShaderEntry))
+
+#define SVGA_STFLAG_PRIMARY (1 << 0)
+#define SVGA_STFLAG_RESERVED (1 << 1) /* Added with cap SVGA_CAP_HP_CMD_QUEUE */
+typedef uint32 SVGAScreenTargetFlags;
+
+typedef
+struct {
+ SVGA3dSurfaceImageId image;
+ uint32 width;
+ uint32 height;
+ int32 xRoot;
+ int32 yRoot;
+ SVGAScreenTargetFlags flags;
+ uint32 dpi;
+ uint32 pad[7];
+}
+SVGAOTableScreenTargetEntry;
+#define SVGA3D_OTABLE_SCREEN_TARGET_ENTRY_SIZE \
+ (sizeof(SVGAOTableScreenTargetEntry))
+
+typedef
+struct {
+ float value[4];
+}
+SVGA3dShaderConstFloat;
+
+typedef
+struct {
+ int32 value[4];
+}
+SVGA3dShaderConstInt;
+
+typedef
+struct {
+ uint32 value;
+}
+SVGA3dShaderConstBool;
+
+typedef
+struct {
+ uint16 streamOffset;
+ uint8 stream;
+ uint8 type;
+ uint8 methodUsage;
+ uint8 usageIndex;
+}
+SVGAGBVertexElement;
+
+typedef
+struct {
+ uint32 sid;
+ uint16 stride;
+ uint32 offset;
+}
+SVGAGBVertexStream;
+typedef
+struct {
+ SVGA3dRect viewport;
+ SVGA3dRect scissorRect;
+ SVGA3dZRange zRange;
+
+ SVGA3dSurfaceImageId renderTargets[SVGA3D_RT_MAX];
+ SVGAGBVertexElement decl1[4];
+
+ uint32 renderStates[SVGA3D_RS_MAX];
+ SVGAGBVertexElement decl2[18];
+ uint32 pad0[2];
+
+ struct {
+ SVGA3dFace face;
+ SVGA3dMaterial material;
+ } material;
+
+ float clipPlanes[SVGA3D_NUM_CLIPPLANES][4];
+ float matrices[SVGA3D_TRANSFORM_MAX][16];
+
+ SVGA3dBool lightEnabled[SVGA3D_NUM_LIGHTS];
+ SVGA3dLightData lightData[SVGA3D_NUM_LIGHTS];
+
+ /*
+ * Shaders currently bound
+ */
+ uint32 shaders[SVGA3D_NUM_SHADERTYPE_PREDX];
+ SVGAGBVertexElement decl3[10];
+ uint32 pad1[3];
+
+ uint32 occQueryActive;
+ uint32 occQueryValue;
+
+ /*
+ * Int/Bool Shader constants
+ */
+ SVGA3dShaderConstInt pShaderIValues[SVGA3D_CONSTINTREG_MAX];
+ SVGA3dShaderConstInt vShaderIValues[SVGA3D_CONSTINTREG_MAX];
+ uint16 pShaderBValues;
+ uint16 vShaderBValues;
+
+
+ SVGAGBVertexStream streams[SVGA3D_MAX_VERTEX_ARRAYS];
+ SVGA3dVertexDivisor divisors[SVGA3D_MAX_VERTEX_ARRAYS];
+ uint32 numVertexDecls;
+ uint32 numVertexStreams;
+ uint32 numVertexDivisors;
+ uint32 pad2[30];
+
+ /*
+ * Texture Stages
+ *
+ * SVGA3D_TS_INVALID through SVGA3D_TS_CONSTANT are in the
+ * textureStages array.
+ * SVGA3D_TS_COLOR_KEY is in tsColorKey.
+ */
+ uint32 tsColorKey[SVGA3D_NUM_TEXTURE_UNITS];
+ uint32 textureStages[SVGA3D_NUM_TEXTURE_UNITS][SVGA3D_TS_CONSTANT + 1];
+ uint32 tsColorKeyEnable[SVGA3D_NUM_TEXTURE_UNITS];
+
+ /*
+ * Float Shader constants.
+ */
+ SVGA3dShaderConstFloat pShaderFValues[SVGA3D_CONSTREG_MAX];
+ SVGA3dShaderConstFloat vShaderFValues[SVGA3D_CONSTREG_MAX];
+}
+SVGAGBContextData;
+#define SVGA3D_CONTEXT_DATA_SIZE (sizeof(SVGAGBContextData))
+
+/*
+ * SVGA3dCmdSetOTableBase --
+ *
+ * This command allows the guest to specify the base PPN of the
+ * specified object table.
+ */
+
+typedef
+struct {
+ SVGAOTableType type;
+ PPN baseAddress;
+ uint32 sizeInBytes;
+ uint32 validSizeInBytes;
+ SVGAMobFormat ptDepth;
+}
+SVGA3dCmdSetOTableBase; /* SVGA_3D_CMD_SET_OTABLE_BASE */
+
+typedef
+struct {
+ SVGAOTableType type;
+ PPN64 baseAddress;
+ uint32 sizeInBytes;
+ uint32 validSizeInBytes;
+ SVGAMobFormat ptDepth;
+}
+SVGA3dCmdSetOTableBase64; /* SVGA_3D_CMD_SET_OTABLE_BASE64 */
+
+/*
+ * Guests using SVGA_3D_CMD_GROW_OTABLE are promising that
+ * the new OTable contains the same contents as the old one, except possibly
+ * for some new invalid entries at the end.
+ *
+ * (Otherwise, guests should use one of the SetOTableBase commands.)
+ */
+typedef
+struct {
+ SVGAOTableType type;
+ PPN64 baseAddress;
+ uint32 sizeInBytes;
+ uint32 validSizeInBytes;
+ SVGAMobFormat ptDepth;
+}
+SVGA3dCmdGrowOTable; /* SVGA_3D_CMD_GROW_OTABLE */
+
+typedef
+struct {
+ SVGAOTableType type;
+}
+SVGA3dCmdReadbackOTable; /* SVGA_3D_CMD_READBACK_OTABLE */
+
+/*
+ * Define a memory object (Mob) in the OTable.
+ */
+
+typedef
+struct SVGA3dCmdDefineGBMob {
+ SVGAMobId mobid;
+ SVGAMobFormat ptDepth;
+ PPN base;
+ uint32 sizeInBytes;
+}
+SVGA3dCmdDefineGBMob; /* SVGA_3D_CMD_DEFINE_GB_MOB */
+
+
+/*
+ * Destroys an object in the OTable.
+ */
+
+typedef
+struct SVGA3dCmdDestroyGBMob {
+ SVGAMobId mobid;
+}
+SVGA3dCmdDestroyGBMob; /* SVGA_3D_CMD_DESTROY_GB_MOB */
+
+
+/*
+ * Define a memory object (Mob) in the OTable with a PPN64 base.
+ */
+
+typedef
+struct SVGA3dCmdDefineGBMob64 {
+ SVGAMobId mobid;
+ SVGAMobFormat ptDepth;
+ PPN64 base;
+ uint32 sizeInBytes;
+}
+SVGA3dCmdDefineGBMob64; /* SVGA_3D_CMD_DEFINE_GB_MOB64 */
+
+/*
+ * Redefine an object in the OTable with PPN64 base.
+ */
+
+typedef
+struct SVGA3dCmdRedefineGBMob64 {
+ SVGAMobId mobid;
+ SVGAMobFormat ptDepth;
+ PPN64 base;
+ uint32 sizeInBytes;
+}
+SVGA3dCmdRedefineGBMob64; /* SVGA_3D_CMD_REDEFINE_GB_MOB64 */
+
+/*
+ * Notification that the page tables have been modified.
+ */
+
+typedef
+struct SVGA3dCmdUpdateGBMobMapping {
+ SVGAMobId mobid;
+}
+SVGA3dCmdUpdateGBMobMapping; /* SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING */
+
+/*
+ * Define a guest-backed surface.
+ */
+
+typedef
+struct SVGA3dCmdDefineGBSurface {
+ uint32 sid;
+ SVGA3dSurface1Flags surfaceFlags;
+ SVGA3dSurfaceFormat format;
+ uint32 numMipLevels;
+ uint32 multisampleCount;
+ SVGA3dTextureFilter autogenFilter;
+ SVGA3dSize size;
+}
+SVGA3dCmdDefineGBSurface; /* SVGA_3D_CMD_DEFINE_GB_SURFACE */
+
+/*
+ * Defines a guest-backed surface, adding the arraySize field.
+ */
+typedef
+struct SVGA3dCmdDefineGBSurface_v2 {
+ uint32 sid;
+ SVGA3dSurface1Flags surfaceFlags;
+ SVGA3dSurfaceFormat format;
+ uint32 numMipLevels;
+ uint32 multisampleCount;
+ SVGA3dTextureFilter autogenFilter;
+ SVGA3dSize size;
+ uint32 arraySize;
+ uint32 pad;
+}
+SVGA3dCmdDefineGBSurface_v2; /* SVGA_3D_CMD_DEFINE_GB_SURFACE_V2 */
+
+/*
+ * Defines a guest-backed surface, adding the larger flags.
+ */
+typedef
+struct SVGA3dCmdDefineGBSurface_v3 {
+ uint32 sid;
+ SVGA3dSurfaceAllFlags surfaceFlags;
+ SVGA3dSurfaceFormat format;
+ uint32 numMipLevels;
+ uint32 multisampleCount;
+ SVGA3dMSPattern multisamplePattern;
+ SVGA3dMSQualityLevel qualityLevel;
+ SVGA3dTextureFilter autogenFilter;
+ SVGA3dSize size;
+ uint32 arraySize;
+}
+SVGA3dCmdDefineGBSurface_v3; /* SVGA_3D_CMD_DEFINE_GB_SURFACE_V3 */
+
+/*
+ * Defines a guest-backed surface, adding buffer byte stride.
+ */
+typedef
+struct SVGA3dCmdDefineGBSurface_v4 {
+ uint32 sid;
+ SVGA3dSurfaceAllFlags surfaceFlags;
+ SVGA3dSurfaceFormat format;
+ uint32 numMipLevels;
+ uint32 multisampleCount;
+ SVGA3dMSPattern multisamplePattern;
+ SVGA3dMSQualityLevel qualityLevel;
+ SVGA3dTextureFilter autogenFilter;
+ SVGA3dSize size;
+ uint32 arraySize;
+ uint32 bufferByteStride;
+}
+SVGA3dCmdDefineGBSurface_v4; /* SVGA_3D_CMD_DEFINE_GB_SURFACE_V4 */
+
+/*
+ * Destroy a guest-backed surface.
+ */
+
+typedef
+struct SVGA3dCmdDestroyGBSurface {
+ uint32 sid;
+}
+SVGA3dCmdDestroyGBSurface; /* SVGA_3D_CMD_DESTROY_GB_SURFACE */
+
+/*
+ * Bind a guest-backed surface to a mob.
+ */
+
+typedef
+struct SVGA3dCmdBindGBSurface {
+ uint32 sid;
+ SVGAMobId mobid;
+}
+SVGA3dCmdBindGBSurface; /* SVGA_3D_CMD_BIND_GB_SURFACE */
+
+typedef
+struct SVGA3dCmdBindGBSurfaceWithPitch {
+ uint32 sid;
+ SVGAMobId mobid;
+ uint32 baseLevelPitch;
+}
+SVGA3dCmdBindGBSurfaceWithPitch; /* SVGA_3D_CMD_BIND_GB_SURFACE_WITH_PITCH */
+
+/*
+ * Conditionally bind a mob to a guest-backed surface if testMobid
+ * matches the currently bound mob. Optionally issue a
+ * readback/update on the surface while it is still bound to the old
+ * mobid if the mobid is changed by this command.
+ */
+
+#define SVGA3D_COND_BIND_GB_SURFACE_FLAG_READBACK (1 << 0)
+#define SVGA3D_COND_BIND_GB_SURFACE_FLAG_UPDATE (1 << 1)
+
+typedef
+struct SVGA3dCmdCondBindGBSurface {
+ uint32 sid;
+ SVGAMobId testMobid;
+ SVGAMobId mobid;
+ uint32 flags;
+}
+SVGA3dCmdCondBindGBSurface; /* SVGA_3D_CMD_COND_BIND_GB_SURFACE */
+
+/*
+ * Update an image in a guest-backed surface.
+ * (Inform the device that the guest-contents have been updated.)
+ */
+
+typedef
+struct SVGA3dCmdUpdateGBImage {
+ SVGA3dSurfaceImageId image;
+ SVGA3dBox box;
+}
+SVGA3dCmdUpdateGBImage; /* SVGA_3D_CMD_UPDATE_GB_IMAGE */
+
+/*
+ * Update an entire guest-backed surface.
+ * (Inform the device that the guest-contents have been updated.)
+ */
+
+typedef
+struct SVGA3dCmdUpdateGBSurface {
+ uint32 sid;
+}
+SVGA3dCmdUpdateGBSurface; /* SVGA_3D_CMD_UPDATE_GB_SURFACE */
+
+/*
+ * Readback an image in a guest-backed surface.
+ * (Request the device to flush the dirty contents into the guest.)
+ */
+
+typedef
+struct SVGA3dCmdReadbackGBImage {
+ SVGA3dSurfaceImageId image;
+}
+SVGA3dCmdReadbackGBImage; /* SVGA_3D_CMD_READBACK_GB_IMAGE */
+
+/*
+ * Readback an entire guest-backed surface.
+ * (Request the device to flush the dirty contents into the guest.)
+ */
+
+typedef
+struct SVGA3dCmdReadbackGBSurface {
+ uint32 sid;
+}
+SVGA3dCmdReadbackGBSurface; /* SVGA_3D_CMD_READBACK_GB_SURFACE */
+
+/*
+ * Readback a sub rect of an image in a guest-backed surface. After
+ * issuing this command the driver is required to issue an update call
+ * of the same region before issuing any other commands that reference
+ * this surface or rendering is not guaranteed.
+ */
+
+typedef
+struct SVGA3dCmdReadbackGBImagePartial {
+ SVGA3dSurfaceImageId image;
+ SVGA3dBox box;
+ uint32 invertBox;
+}
+SVGA3dCmdReadbackGBImagePartial; /* SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL */
+
+
+/*
+ * Invalidate an image in a guest-backed surface.
+ * (Notify the device that the contents can be lost.)
+ */
+
+typedef
+struct SVGA3dCmdInvalidateGBImage {
+ SVGA3dSurfaceImageId image;
+}
+SVGA3dCmdInvalidateGBImage; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE */
+
+/*
+ * Invalidate an entire guest-backed surface.
+ * (Notify the device that the contents if all images can be lost.)
+ */
+
+typedef
+struct SVGA3dCmdInvalidateGBSurface {
+ uint32 sid;
+}
+SVGA3dCmdInvalidateGBSurface; /* SVGA_3D_CMD_INVALIDATE_GB_SURFACE */
+
+/*
+ * Invalidate a sub rect of an image in a guest-backed surface. After
+ * issuing this command the driver is required to issue an update call
+ * of the same region before issuing any other commands that reference
+ * this surface or rendering is not guaranteed.
+ */
+
+typedef
+struct SVGA3dCmdInvalidateGBImagePartial {
+ SVGA3dSurfaceImageId image;
+ SVGA3dBox box;
+ uint32 invertBox;
+}
+SVGA3dCmdInvalidateGBImagePartial; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL */
+
+
+/*
+ * Define a guest-backed context.
+ */
+
+typedef
+struct SVGA3dCmdDefineGBContext {
+ uint32 cid;
+}
+SVGA3dCmdDefineGBContext; /* SVGA_3D_CMD_DEFINE_GB_CONTEXT */
+
+/*
+ * Destroy a guest-backed context.
+ */
+
+typedef
+struct SVGA3dCmdDestroyGBContext {
+ uint32 cid;
+}
+SVGA3dCmdDestroyGBContext; /* SVGA_3D_CMD_DESTROY_GB_CONTEXT */
+
+/*
+ * Bind a guest-backed context.
+ *
+ * validContents should be set to 0 for new contexts,
+ * and 1 if this is an old context which is getting paged
+ * back on to the device.
+ *
+ * For new contexts, it is recommended that the driver
+ * issue commands to initialize all interesting state
+ * prior to rendering.
+ */
+
+typedef
+struct SVGA3dCmdBindGBContext {
+ uint32 cid;
+ SVGAMobId mobid;
+ uint32 validContents;
+}
+SVGA3dCmdBindGBContext; /* SVGA_3D_CMD_BIND_GB_CONTEXT */
+
+/*
+ * Readback a guest-backed context.
+ * (Request that the device flush the contents back into guest memory.)
+ */
+
+typedef
+struct SVGA3dCmdReadbackGBContext {
+ uint32 cid;
+}
+SVGA3dCmdReadbackGBContext; /* SVGA_3D_CMD_READBACK_GB_CONTEXT */
+
+/*
+ * Invalidate a guest-backed context.
+ */
+typedef
+struct SVGA3dCmdInvalidateGBContext {
+ uint32 cid;
+}
+SVGA3dCmdInvalidateGBContext; /* SVGA_3D_CMD_INVALIDATE_GB_CONTEXT */
+
+/*
+ * Define a guest-backed shader.
+ */
+
+typedef
+struct SVGA3dCmdDefineGBShader {
+ uint32 shid;
+ SVGA3dShaderType type;
+ uint32 sizeInBytes;
+}
+SVGA3dCmdDefineGBShader; /* SVGA_3D_CMD_DEFINE_GB_SHADER */
+
+/*
+ * Bind a guest-backed shader.
+ */
+
+typedef
+struct SVGA3dCmdBindGBShader {
+ uint32 shid;
+ SVGAMobId mobid;
+ uint32 offsetInBytes;
+}
+SVGA3dCmdBindGBShader; /* SVGA_3D_CMD_BIND_GB_SHADER */
+
+/*
+ * Destroy a guest-backed shader.
+ */
+
+typedef
+struct SVGA3dCmdDestroyGBShader {
+ uint32 shid;
+}
+SVGA3dCmdDestroyGBShader; /* SVGA_3D_CMD_DESTROY_GB_SHADER */
+
+typedef
+struct {
+ uint32 cid;
+ uint32 regStart;
+ SVGA3dShaderType shaderType;
+ SVGA3dShaderConstType constType;
+
+ /*
+ * Followed by a variable number of shader constants.
+ *
+ * Note that FLOAT and INT constants are 4-dwords in length, while
+ * BOOL constants are 1-dword in length.
+ */
+}
+SVGA3dCmdSetGBShaderConstInline; /* SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE */
+
+
+typedef
+struct {
+ uint32 cid;
+ SVGA3dQueryType type;
+}
+SVGA3dCmdBeginGBQuery; /* SVGA_3D_CMD_BEGIN_GB_QUERY */
+
+typedef
+struct {
+ uint32 cid;
+ SVGA3dQueryType type;
+ SVGAMobId mobid;
+ uint32 offset;
+}
+SVGA3dCmdEndGBQuery; /* SVGA_3D_CMD_END_GB_QUERY */
+
+
+/*
+ * SVGA_3D_CMD_WAIT_FOR_GB_QUERY --
+ *
+ * The semantics of this command are identical to the
+ * SVGA_3D_CMD_WAIT_FOR_QUERY except that the results are written
+ * to a Mob instead of a GMR.
+ */
+
+typedef
+struct {
+ uint32 cid;
+ SVGA3dQueryType type;
+ SVGAMobId mobid;
+ uint32 offset;
+}
+SVGA3dCmdWaitForGBQuery; /* SVGA_3D_CMD_WAIT_FOR_GB_QUERY */
+
+
+typedef
+struct {
+ SVGAMobId mobid;
+ uint32 mustBeZero;
+ uint32 initialized;
+}
+SVGA3dCmdEnableGart; /* SVGA_3D_CMD_ENABLE_GART */
+
+typedef
+struct {
+ SVGAMobId mobid;
+ uint32 gartOffset;
+}
+SVGA3dCmdMapMobIntoGart; /* SVGA_3D_CMD_MAP_MOB_INTO_GART */
+
+
+typedef
+struct {
+ uint32 gartOffset;
+ uint32 numPages;
+}
+SVGA3dCmdUnmapGartRange; /* SVGA_3D_CMD_UNMAP_GART_RANGE */
+
+
+/*
+ * Screen Targets
+ */
+
+typedef
+struct {
+ uint32 stid;
+ uint32 width;
+ uint32 height;
+ int32 xRoot;
+ int32 yRoot;
+ SVGAScreenTargetFlags flags;
+
+ /*
+ * The physical DPI that the guest expects this screen displayed at.
+ *
+ * Guests which are not DPI-aware should set this to zero.
+ */
+ uint32 dpi;
+}
+SVGA3dCmdDefineGBScreenTarget; /* SVGA_3D_CMD_DEFINE_GB_SCREENTARGET */
+
+typedef
+struct {
+ uint32 stid;
+}
+SVGA3dCmdDestroyGBScreenTarget; /* SVGA_3D_CMD_DESTROY_GB_SCREENTARGET */
+
+typedef
+struct {
+ uint32 stid;
+ SVGA3dSurfaceImageId image;
+}
+SVGA3dCmdBindGBScreenTarget; /* SVGA_3D_CMD_BIND_GB_SCREENTARGET */
+
+typedef
+struct {
+ uint32 stid;
+ SVGA3dRect rect;
+}
+SVGA3dCmdUpdateGBScreenTarget; /* SVGA_3D_CMD_UPDATE_GB_SCREENTARGET */
+
+typedef
+struct SVGA3dCmdGBScreenDMA {
+ uint32 screenId;
+ uint32 dead;
+ SVGAMobId destMobID;
+ uint32 destPitch;
+ SVGAMobId changeMapMobID;
+}
+SVGA3dCmdGBScreenDMA; /* SVGA_3D_CMD_GB_SCREEN_DMA */
+
+typedef
+struct {
+ uint32 value;
+ uint32 mobId;
+ uint32 mobOffset;
+}
+SVGA3dCmdGBMobFence; /* SVGA_3D_CMD_GB_MOB_FENCE */
+
+typedef
+struct {
+ uint32 stid;
+ SVGA3dSurfaceImageId dest;
+
+ uint32 statusMobId;
+ uint32 statusMobOffset;
+
+ /* Reserved fields */
+ uint32 mustBeInvalidId;
+ uint32 mustBeZero;
+}
+SVGA3dCmdScreenCopy; /* SVGA_3D_CMD_SCREEN_COPY */
+
+#define SVGA_SCREEN_COPY_STATUS_FAILURE 0x00
+#define SVGA_SCREEN_COPY_STATUS_SUCCESS 0x01
+#define SVGA_SCREEN_COPY_STATUS_INVALID 0xFFFFFFFF
+
+
+#endif /* _SVGA3D_REG_H_ */
diff --git a/vmware/svga_all.h b/vmware/svga_all.h
new file mode 100644
index 0000000..de26664
--- /dev/null
+++ b/vmware/svga_all.h
@@ -0,0 +1,13 @@
+#ifndef __SVGA_ALL_H__INCLUDED__
+#define __SVGA_ALL_H__INCLUDED__
+
+#pragma pack(push)
+#pragma pack(1)
+#include "svga.h"
+#include "svga_reg.h"
+#include "svga3d.h"
+#include "svga3d_reg.h"
+#include "svga3d_caps.h"
+#pragma pack(pop)
+
+#endif /* __SVGA_ALL_H__INCLUDED__ */
diff --git a/vmware/svga_escape.h b/vmware/svga_escape.h
new file mode 100644
index 0000000..7b85e9b
--- /dev/null
+++ b/vmware/svga_escape.h
@@ -0,0 +1,89 @@
+/**********************************************************
+ * Copyright 2007-2009 VMware, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/*
+ * svga_escape.h --
+ *
+ * Definitions for our own (vendor-specific) SVGA Escape commands.
+ */
+
+#ifndef _SVGA_ESCAPE_H_
+#define _SVGA_ESCAPE_H_
+
+
+/*
+ * Namespace IDs for the escape command
+ */
+
+#define SVGA_ESCAPE_NSID_VMWARE 0x00000000
+#define SVGA_ESCAPE_NSID_DEVEL 0xFFFFFFFF
+
+
+/*
+ * Within SVGA_ESCAPE_NSID_VMWARE, we multiplex commands according to
+ * the first DWORD of escape data (after the nsID and size). As a
+ * guideline we're using the high word and low word as a major and
+ * minor command number, respectively.
+ *
+ * Major command number allocation:
+ *
+ * 0000: Reserved
+ * 0001: SVGA_ESCAPE_VMWARE_LOG (svga_binary_logger.h)
+ * 0002: SVGA_ESCAPE_VMWARE_VIDEO (svga_overlay.h)
+ * 0003: SVGA_ESCAPE_VMWARE_HINT (svga_escape.h)
+ */
+
+#define SVGA_ESCAPE_VMWARE_MAJOR_MASK 0xFFFF0000
+
+
+/*
+ * SVGA Hint commands.
+ *
+ * These escapes let the SVGA driver provide optional information to
+ * he host about the state of the guest or guest applications. The
+ * host can use these hints to make user interface or performance
+ * decisions.
+ *
+ * Notes:
+ *
+ * - SVGA_ESCAPE_VMWARE_HINT_FULLSCREEN is deprecated for guests
+ * that use the SVGA Screen Object extension. Instead of sending
+ * this escape, use the SVGA_SCREEN_FULLSCREEN_HINT flag on your
+ * Screen Object.
+ */
+
+#define SVGA_ESCAPE_VMWARE_HINT 0x00030000
+#define SVGA_ESCAPE_VMWARE_HINT_FULLSCREEN 0x00030001 // Deprecated
+
+typedef
+struct {
+ uint32 command;
+ uint32 fullscreen;
+ struct {
+ int32 x, y;
+ } monitorPosition;
+} SVGAEscapeHintFullscreen;
+
+#endif /* _SVGA_ESCAPE_H_ */
diff --git a/vmware/svga_overlay.h b/vmware/svga_overlay.h
new file mode 100644
index 0000000..82c1d3f
--- /dev/null
+++ b/vmware/svga_overlay.h
@@ -0,0 +1,201 @@
+/**********************************************************
+ * Copyright 2007-2009 VMware, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/*
+ * svga_overlay.h --
+ *
+ * Definitions for video-overlay support.
+ */
+
+#ifndef _SVGA_OVERLAY_H_
+#define _SVGA_OVERLAY_H_
+
+#include "svga_reg.h"
+
+/*
+ * Video formats we support
+ */
+
+#define VMWARE_FOURCC_YV12 0x32315659 // 'Y' 'V' '1' '2'
+#define VMWARE_FOURCC_YUY2 0x32595559 // 'Y' 'U' 'Y' '2'
+#define VMWARE_FOURCC_UYVY 0x59565955 // 'U' 'Y' 'V' 'Y'
+
+typedef enum {
+ SVGA_OVERLAY_FORMAT_INVALID = 0,
+ SVGA_OVERLAY_FORMAT_YV12 = VMWARE_FOURCC_YV12,
+ SVGA_OVERLAY_FORMAT_YUY2 = VMWARE_FOURCC_YUY2,
+ SVGA_OVERLAY_FORMAT_UYVY = VMWARE_FOURCC_UYVY,
+} SVGAOverlayFormat;
+
+#define SVGA_VIDEO_COLORKEY_MASK 0x00ffffff
+
+#define SVGA_ESCAPE_VMWARE_VIDEO 0x00020000
+
+#define SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS 0x00020001
+ /* FIFO escape layout:
+ * Type, Stream Id, (Register Id, Value) pairs */
+
+#define SVGA_ESCAPE_VMWARE_VIDEO_FLUSH 0x00020002
+ /* FIFO escape layout:
+ * Type, Stream Id */
+
+typedef
+struct SVGAEscapeVideoSetRegs {
+ struct {
+ uint32 cmdType;
+ uint32 streamId;
+ } header;
+
+ // May include zero or more items.
+ struct {
+ uint32 registerId;
+ uint32 value;
+ } items[1];
+} SVGAEscapeVideoSetRegs;
+
+typedef
+struct SVGAEscapeVideoFlush {
+ uint32 cmdType;
+ uint32 streamId;
+} SVGAEscapeVideoFlush;
+
+
+/*
+ * Struct definitions for the video overlay commands built on
+ * SVGAFifoCmdEscape.
+ */
+typedef
+struct {
+ uint32 command;
+ uint32 overlay;
+} SVGAFifoEscapeCmdVideoBase;
+
+typedef
+struct {
+ SVGAFifoEscapeCmdVideoBase videoCmd;
+} SVGAFifoEscapeCmdVideoFlush;
+
+typedef
+struct {
+ SVGAFifoEscapeCmdVideoBase videoCmd;
+ struct {
+ uint32 regId;
+ uint32 value;
+ } items[1];
+} SVGAFifoEscapeCmdVideoSetRegs;
+
+typedef
+struct {
+ SVGAFifoEscapeCmdVideoBase videoCmd;
+ struct {
+ uint32 regId;
+ uint32 value;
+ } items[SVGA_VIDEO_NUM_REGS];
+} SVGAFifoEscapeCmdVideoSetAllRegs;
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMwareVideoGetAttributes --
+ *
+ * Computes the size, pitches and offsets for YUV frames.
+ *
+ * Results:
+ * TRUE on success; otherwise FALSE on failure.
+ *
+ * Side effects:
+ * Pitches and offsets for the given YUV frame are put in 'pitches'
+ * and 'offsets' respectively. They are both optional though.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static INLINE Bool
+VMwareVideoGetAttributes(const SVGAOverlayFormat format, // IN
+ uint32 *width, // IN / OUT
+ uint32 *height, // IN / OUT
+ uint32 *size, // OUT
+ uint32 *pitches, // OUT (optional)
+ uint32 *offsets) // OUT (optional)
+{
+ int tmp;
+
+ *width = (*width + 1) & ~1;
+
+ if (offsets) {
+ offsets[0] = 0;
+ }
+
+ switch (format) {
+ case VMWARE_FOURCC_YV12:
+ *height = (*height + 1) & ~1;
+ *size = (*width + 3) & ~3;
+
+ if (pitches) {
+ pitches[0] = *size;
+ }
+
+ *size *= *height;
+
+ if (offsets) {
+ offsets[1] = *size;
+ }
+
+ tmp = ((*width >> 1) + 3) & ~3;
+
+ if (pitches) {
+ pitches[1] = pitches[2] = tmp;
+ }
+
+ tmp *= (*height >> 1);
+ *size += tmp;
+
+ if (offsets) {
+ offsets[2] = *size;
+ }
+
+ *size += tmp;
+ break;
+
+ case VMWARE_FOURCC_YUY2:
+ case VMWARE_FOURCC_UYVY:
+ *size = *width * 2;
+
+ if (pitches) {
+ pitches[0] = *size;
+ }
+
+ *size *= *height;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#endif // _SVGA_OVERLAY_H_
diff --git a/vmware/svga_reg.h b/vmware/svga_reg.h
new file mode 100644
index 0000000..04707c3
--- /dev/null
+++ b/vmware/svga_reg.h
@@ -0,0 +1,1610 @@
+/**********************************************************
+ * Copyright 1998-2009 VMware, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/*
+ * svga_reg.h --
+ *
+ * Virtual hardware definitions for the VMware SVGA II device.
+ */
+
+#ifndef _SVGA_REG_H_
+#define _SVGA_REG_H_
+
+/*
+ * PCI device IDs.
+ */
+#define PCI_VENDOR_ID_VMWARE 0x15AD
+#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
+
+#define PCI_VENDOR_ID_INNOTEK 0x80EE
+#define PCI_DEVICE_ID_VBOX_VGA 0xBEEF
+
+#define PCI_SUBCLASS_ID_SVGA2 0x040515ADUL
+
+/*
+ * SVGA_REG_ENABLE bit definitions.
+ */
+#define SVGA_REG_ENABLE_DISABLE 0
+#define SVGA_REG_ENABLE_ENABLE 1
+#define SVGA_REG_ENABLE_HIDE 2
+#define SVGA_REG_ENABLE_ENABLE_HIDE (SVGA_REG_ENABLE_ENABLE |\
+ SVGA_REG_ENABLE_HIDE)
+
+/*
+ * Legal values for the SVGA_REG_CURSOR_ON register in old-fashioned
+ * cursor bypass mode. This is still supported, but no new guest
+ * drivers should use it.
+ */
+#define SVGA_CURSOR_ON_HIDE 0x0 /* Must be 0 to maintain backward compatibility */
+#define SVGA_CURSOR_ON_SHOW 0x1 /* Must be 1 to maintain backward compatibility */
+#define SVGA_CURSOR_ON_REMOVE_FROM_FB 0x2 /* Remove the cursor from the framebuffer because we need to see what's under it */
+#define SVGA_CURSOR_ON_RESTORE_TO_FB 0x3 /* Put the cursor back in the framebuffer so the user can see it */
+
+/*
+ * The maximum framebuffer size that can traced for e.g. guests in VESA mode.
+ * The changeMap in the monitor is proportional to this number. Therefore, we'd
+ * like to keep it as small as possible to reduce monitor overhead (using
+ * SVGA_VRAM_MAX_SIZE for this increases the size of the shared area by over
+ * 4k!).
+ *
+ * NB: For compatibility reasons, this value must be greater than 0xff0000.
+ * See bug 335072.
+ */
+#define SVGA_FB_MAX_TRACEABLE_SIZE 0x1000000
+
+#define SVGA_MAX_PSEUDOCOLOR_DEPTH 8
+#define SVGA_MAX_PSEUDOCOLORS (1UL << SVGA_MAX_PSEUDOCOLOR_DEPTH)
+#define SVGA_NUM_PALETTE_REGS (3UL * SVGA_MAX_PSEUDOCOLORS)
+
+#define SVGA_MAGIC 0x900000UL
+#define SVGA_MAKE_ID(ver) (SVGA_MAGIC << 8 | (ver))
+
+#define SVGA_VERSION_3 3
+#define SVGA_ID_3 SVGA_MAKE_ID(SVGA_VERSION_3)
+
+/* Version 2 let the address of the frame buffer be unsigned on Win32 */
+#define SVGA_VERSION_2 2
+#define SVGA_ID_2 SVGA_MAKE_ID(SVGA_VERSION_2)
+
+/* Version 1 has new registers starting with SVGA_REG_CAPABILITIES so
+ PALETTE_BASE has moved */
+#define SVGA_VERSION_1 1
+#define SVGA_ID_1 SVGA_MAKE_ID(SVGA_VERSION_1)
+
+/* Version 0 is the initial version */
+#define SVGA_VERSION_0 0
+#define SVGA_ID_0 SVGA_MAKE_ID(SVGA_VERSION_0)
+
+/* "Invalid" value for all SVGA IDs. (Version ID, screen object ID, surface ID...) */
+#define SVGA_ID_INVALID 0xFFFFFFFF
+
+/* Port offsets, relative to BAR0 */
+#define SVGA_INDEX_PORT 0x0
+#define SVGA_VALUE_PORT 0x1
+#define SVGA_BIOS_PORT 0x2
+#define SVGA_IRQSTATUS_PORT 0x8
+
+/*
+ * Interrupt source flags for IRQSTATUS_PORT and IRQMASK.
+ *
+ * Interrupts are only supported when the
+ * SVGA_CAP_IRQMASK capability is present.
+ */
+#define SVGA_IRQFLAG_ANY_FENCE 0x1 /* Any fence was passed */
+#define SVGA_IRQFLAG_FIFO_PROGRESS 0x2 /* Made forward progress in the FIFO */
+#define SVGA_IRQFLAG_FENCE_GOAL 0x4 /* SVGA_FIFO_FENCE_GOAL reached */
+
+/*
+ * Registers
+ */
+
+enum {
+ SVGA_REG_ID = 0,
+ SVGA_REG_ENABLE = 1,
+ SVGA_REG_WIDTH = 2,
+ SVGA_REG_HEIGHT = 3,
+ SVGA_REG_MAX_WIDTH = 4,
+ SVGA_REG_MAX_HEIGHT = 5,
+ SVGA_REG_DEPTH = 6,
+ SVGA_REG_BITS_PER_PIXEL = 7, /* Current bpp in the guest */
+ SVGA_REG_PSEUDOCOLOR = 8,
+ SVGA_REG_RED_MASK = 9,
+ SVGA_REG_GREEN_MASK = 10,
+ SVGA_REG_BLUE_MASK = 11,
+ SVGA_REG_BYTES_PER_LINE = 12,
+ SVGA_REG_FB_START = 13, /* (Deprecated) */
+ SVGA_REG_FB_OFFSET = 14,
+ SVGA_REG_VRAM_SIZE = 15,
+ SVGA_REG_FB_SIZE = 16,
+
+ /* ID 0 implementation only had the above registers, then the palette */
+
+ SVGA_REG_CAPABILITIES = 17,
+ SVGA_REG_MEM_START = 18, /* (Deprecated) */
+ SVGA_REG_MEM_SIZE = 19,
+ SVGA_REG_CONFIG_DONE = 20, /* Set when memory area configured */
+ SVGA_REG_SYNC = 21, /* See "FIFO Synchronization Registers" */
+ SVGA_REG_BUSY = 22, /* See "FIFO Synchronization Registers" */
+ SVGA_REG_GUEST_ID = 23, /* Set guest OS identifier */
+ SVGA_REG_CURSOR_ID = 24, /* (Deprecated) */
+ SVGA_REG_CURSOR_X = 25, /* (Deprecated) */
+ SVGA_REG_CURSOR_Y = 26, /* (Deprecated) */
+ SVGA_REG_CURSOR_ON = 27, /* (Deprecated) */
+ SVGA_REG_HOST_BITS_PER_PIXEL = 28, /* (Deprecated) */
+ SVGA_REG_SCRATCH_SIZE = 29, /* Number of scratch registers */
+ SVGA_REG_MEM_REGS = 30, /* Number of FIFO registers */
+ SVGA_REG_NUM_DISPLAYS = 31, /* (Deprecated) */
+ SVGA_REG_PITCHLOCK = 32, /* Fixed pitch for all modes */
+ SVGA_REG_IRQMASK = 33, /* Interrupt mask */
+
+ /* Legacy multi-monitor support */
+ SVGA_REG_NUM_GUEST_DISPLAYS = 34,/* Number of guest displays in X/Y direction */
+ SVGA_REG_DISPLAY_ID = 35, /* Display ID for the following display attributes */
+ SVGA_REG_DISPLAY_IS_PRIMARY = 36,/* Whether this is a primary display */
+ SVGA_REG_DISPLAY_POSITION_X = 37,/* The display position x */
+ SVGA_REG_DISPLAY_POSITION_Y = 38,/* The display position y */
+ SVGA_REG_DISPLAY_WIDTH = 39, /* The display's width */
+ SVGA_REG_DISPLAY_HEIGHT = 40, /* The display's height */
+
+ /* See "Guest memory regions" below. */
+ SVGA_REG_GMR_ID = 41,
+ SVGA_REG_GMR_DESCRIPTOR = 42,
+ SVGA_REG_GMR_MAX_IDS = 43,
+ SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH = 44,
+
+ SVGA_REG_TRACES = 45, /* Enable trace-based updates even when FIFO is on */
+ SVGA_REG_GMRS_MAX_PAGES = 46, /* Maximum number of 4KB pages for all GMRs */
+ SVGA_REG_MEMORY_SIZE = 47, /* Total dedicated device memory excluding FIFO */
+
+ /* SVGA_3 registers */
+ SVGA_REG_COMMAND_LOW = 48,
+ SVGA_REG_COMMAND_HIGH = 49,
+ SVGA_REG_MAX_PRIMARY_MEM = 50,
+ SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB = 51,
+ SVGA_REG_DEV_CAP = 52,
+ SVGA_REG_CMD_PREPEND_LOW = 53,
+ SVGA_REG_CMD_PREPEND_HIGH = 54,
+ SVGA_REG_SCREENTARGET_MAX_WIDTH = 55,
+ SVGA_REG_SCREENTARGET_MAX_HEIGHT = 56,
+ SVGA_REG_MOB_MAX_SIZE = 57,
+ SVGA_REG_BLANK_SCREEN_TARGETS = 58,
+ SVGA_REG_CAP2 = 59,
+ SVGA_REG_DEVEL_CAP = 60,
+ SVGA_REG_GUEST_DRIVER_ID = 61,
+ SVGA_REG_GUEST_DRIVER_VERSION1 = 62,
+ SVGA_REG_GUEST_DRIVER_VERSION2 = 63,
+ SVGA_REG_GUEST_DRIVER_VERSION3 = 64,
+ SVGA_REG_CURSOR_MOBID = 65,
+ SVGA_REG_CURSOR_MAX_BYTE_SIZE = 66,
+ SVGA_REG_CURSOR_MAX_DIMENSION = 67,
+ SVGA_REG_FIFO_CAPS = 68,
+ SVGA_REG_FENCE = 69,
+ SVGA_REG_CURSOR4_ON = 70,
+ SVGA_REG_CURSOR4_X = 71,
+ SVGA_REG_CURSOR4_Y = 72,
+ SVGA_REG_CURSOR4_SCREEN_ID = 73,
+ SVGA_REG_CURSOR4_SUBMIT = 74,
+ SVGA_REG_SCREENDMA = 75,
+ SVGA_REG_GBOBJECT_MEM_SIZE_KB = 76,
+ SVGA_REG_REGS_START_HIGH32 = 77,
+ SVGA_REG_REGS_START_LOW32 = 78,
+ SVGA_REG_FB_START_HIGH32 = 79,
+ SVGA_REG_FB_START_LOW32 = 80,
+ SVGA_REG_MSHINT = 81,
+ SVGA_REG_IRQ_STATUS = 82,
+ SVGA_REG_DIRTY_TRACKING = 83,
+ SVGA_REG_FENCE_GOAL = 84,
+ SVGA_REG_TOP = 85, /* Must be 1 more than the last register */
+
+ SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */
+ /* Next 768 (== 256*3) registers exist for colormap */
+
+ SVGA_SCRATCH_BASE = SVGA_PALETTE_BASE + SVGA_NUM_PALETTE_REGS
+ /* Base of scratch registers */
+ /* Next reg[SVGA_REG_SCRATCH_SIZE] registers exist for scratch usage:
+ First 4 are reserved for VESA BIOS Extension; any remaining are for
+ the use of the current SVGA driver. */
+};
+
+
+/*
+ * Guest memory regions (GMRs):
+ *
+ * This is a new memory mapping feature available in SVGA devices
+ * which have the SVGA_CAP_GMR bit set. Previously, there were two
+ * fixed memory regions available with which to share data between the
+ * device and the driver: the FIFO ('MEM') and the framebuffer. GMRs
+ * are our name for an extensible way of providing arbitrary DMA
+ * buffers for use between the driver and the SVGA device. They are a
+ * new alternative to framebuffer memory, usable for both 2D and 3D
+ * graphics operations.
+ *
+ * Since GMR mapping must be done synchronously with guest CPU
+ * execution, we use a new pair of SVGA registers:
+ *
+ * SVGA_REG_GMR_ID --
+ *
+ * Read/write.
+ * This register holds the 32-bit ID (a small positive integer)
+ * of a GMR to create, delete, or redefine. Writing this register
+ * has no side-effects.
+ *
+ * SVGA_REG_GMR_DESCRIPTOR --
+ *
+ * Write-only.
+ * Writing this register will create, delete, or redefine the GMR
+ * specified by the above ID register. If this register is zero,
+ * the GMR is deleted. Any pointers into this GMR (including those
+ * currently being processed by FIFO commands) will be
+ * synchronously invalidated.
+ *
+ * If this register is nonzero, it must be the physical page
+ * number (PPN) of a data structure which describes the physical
+ * layout of the memory region this GMR should describe. The
+ * descriptor structure will be read synchronously by the SVGA
+ * device when this register is written. The descriptor need not
+ * remain allocated for the lifetime of the GMR.
+ *
+ * The guest driver should write SVGA_REG_GMR_ID first, then
+ * SVGA_REG_GMR_DESCRIPTOR.
+ *
+ * SVGA_REG_GMR_MAX_IDS --
+ *
+ * Read-only.
+ * The SVGA device may choose to support a maximum number of
+ * user-defined GMR IDs. This register holds the number of supported
+ * IDs. (The maximum supported ID plus 1)
+ *
+ * SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH --
+ *
+ * Read-only.
+ * The SVGA device may choose to put a limit on the total number
+ * of SVGAGuestMemDescriptor structures it will read when defining
+ * a single GMR.
+ *
+ * The descriptor structure is an array of SVGAGuestMemDescriptor
+ * structures. Each structure may do one of three things:
+ *
+ * - Terminate the GMR descriptor list.
+ * (ppn==0, numPages==0)
+ *
+ * - Add a PPN or range of PPNs to the GMR's virtual address space.
+ * (ppn != 0, numPages != 0)
+ *
+ * - Provide the PPN of the next SVGAGuestMemDescriptor, in order to
+ * support multi-page GMR descriptor tables without forcing the
+ * driver to allocate physically contiguous memory.
+ * (ppn != 0, numPages == 0)
+ *
+ * Note that each physical page of SVGAGuestMemDescriptor structures
+ * can describe at least 2MB of guest memory. If the driver needs to
+ * use more than one page of descriptor structures, it must use one of
+ * its SVGAGuestMemDescriptors to point to an additional page. The
+ * device will never automatically cross a page boundary.
+ *
+ * Once the driver has described a GMR, it is immediately available
+ * for use via any FIFO command that uses an SVGAGuestPtr structure.
+ * These pointers include a GMR identifier plus an offset into that
+ * GMR.
+ *
+ * The driver must check the SVGA_CAP_GMR bit before using the GMR
+ * registers.
+ */
+
+/*
+ * Special GMR IDs, allowing SVGAGuestPtrs to point to framebuffer
+ * memory as well. In the future, these IDs could even be used to
+ * allow legacy memory regions to be redefined by the guest as GMRs.
+ *
+ * Using the guest framebuffer (GFB) at BAR1 for general purpose DMA
+ * is being phased out. Please try to use user-defined GMRs whenever
+ * possible.
+ */
+#define SVGA_GMR_NULL ((uint32) -1)
+#define SVGA_GMR_FRAMEBUFFER ((uint32) -2) // Guest Framebuffer (GFB)
+
+typedef
+struct SVGAGuestMemDescriptor {
+ uint32 ppn;
+ uint32 numPages;
+} SVGAGuestMemDescriptor;
+
+typedef
+struct SVGAGuestPtr {
+ uint32 gmrId;
+ uint32 offset;
+} SVGAGuestPtr;
+
+
+/*
+ * SVGAGMRImageFormat --
+ *
+ * This is a packed representation of the source 2D image format
+ * for a GMR-to-screen blit. Currently it is defined as an encoding
+ * of the screen's color depth and bits-per-pixel, however, 16 bits
+ * are reserved for future use to identify other encodings (such as
+ * RGBA or higher-precision images).
+ *
+ * Currently supported formats:
+ *
+ * bpp depth Format Name
+ * --- ----- -----------
+ * 32 24 32-bit BGRX
+ * 24 24 24-bit BGR
+ * 16 16 RGB 5-6-5
+ * 16 15 RGB 5-5-5
+ *
+ */
+
+typedef
+struct SVGAGMRImageFormat {
+ union {
+ struct {
+ uint32 bitsPerPixel : 8;
+ uint32 colorDepth : 8;
+ uint32 reserved : 16; // Must be zero
+ };
+
+ uint32 value;
+ };
+} SVGAGMRImageFormat;
+
+typedef
+struct SVGAGuestImage {
+ SVGAGuestPtr ptr;
+
+ /*
+ * A note on interpretation of pitch: This value of pitch is the
+ * number of bytes between vertically adjacent image
+ * blocks. Normally this is the number of bytes between the first
+ * pixel of two adjacent scanlines. With compressed textures,
+ * however, this may represent the number of bytes between
+ * compression blocks rather than between rows of pixels.
+ *
+ * XXX: Compressed textures currently must be tightly packed in guest memory.
+ *
+ * If the image is 1-dimensional, pitch is ignored.
+ *
+ * If 'pitch' is zero, the SVGA3D device calculates a pitch value
+ * assuming each row of blocks is tightly packed.
+ */
+ uint32 pitch;
+} SVGAGuestImage;
+
+/*
+ * SVGAColorBGRX --
+ *
+ * A 24-bit color format (BGRX), which does not depend on the
+ * format of the legacy guest framebuffer (GFB) or the current
+ * GMRFB state.
+ */
+
+typedef
+struct SVGAColorBGRX {
+ union {
+ struct {
+ uint32 b : 8;
+ uint32 g : 8;
+ uint32 r : 8;
+ uint32 x : 8; // Unused
+ };
+
+ uint32 value;
+ };
+} SVGAColorBGRX;
+
+
+/*
+ * SVGASignedRect --
+ * SVGASignedPoint --
+ *
+ * Signed rectangle and point primitives. These are used by the new
+ * 2D primitives for drawing to Screen Objects, which can occupy a
+ * signed virtual coordinate space.
+ *
+ * SVGASignedRect specifies a half-open interval: the (left, top)
+ * pixel is part of the rectangle, but the (right, bottom) pixel is
+ * not.
+ */
+
+typedef
+struct SVGASignedRect {
+ int32 left;
+ int32 top;
+ int32 right;
+ int32 bottom;
+} SVGASignedRect;
+
+typedef
+struct SVGASignedPoint {
+ int32 x;
+ int32 y;
+} SVGASignedPoint;
+
+
+/*
+ * Capabilities
+ *
+ * Note the holes in the bitfield. Missing bits have been deprecated,
+ * and must not be reused. Those capabilities will never be reported
+ * by new versions of the SVGA device.
+ *
+ * SVGA_CAP_GMR2 --
+ * Provides asynchronous commands to define and remap guest memory
+ * regions. Adds device registers SVGA_REG_GMRS_MAX_PAGES and
+ * SVGA_REG_MEMORY_SIZE.
+ *
+ * SVGA_CAP_SCREEN_OBJECT_2 --
+ * Allow screen object support, and require backing stores from the
+ * guest for each screen object.
+ */
+
+#define SVGA_CAP_NONE 0x00000000UL
+#define SVGA_CAP_RECT_COPY 0x00000002UL
+#define SVGA_CAP_CURSOR 0x00000020UL
+#define SVGA_CAP_CURSOR_BYPASS 0x00000040UL // Legacy (Use Cursor Bypass 3 instead)
+#define SVGA_CAP_CURSOR_BYPASS_2 0x00000080UL // Legacy (Use Cursor Bypass 3 instead)
+#define SVGA_CAP_8BIT_EMULATION 0x00000100UL
+#define SVGA_CAP_ALPHA_CURSOR 0x00000200UL
+#define SVGA_CAP_3D 0x00004000UL
+#define SVGA_CAP_EXTENDED_FIFO 0x00008000UL
+#define SVGA_CAP_MULTIMON 0x00010000UL // Legacy multi-monitor support
+#define SVGA_CAP_PITCHLOCK 0x00020000UL
+#define SVGA_CAP_IRQMASK 0x00040000UL
+#define SVGA_CAP_DISPLAY_TOPOLOGY 0x00080000UL // Legacy multi-monitor support
+#define SVGA_CAP_GMR 0x00100000UL
+#define SVGA_CAP_TRACES 0x00200000UL
+#define SVGA_CAP_GMR2 0x00400000UL
+#define SVGA_CAP_SCREEN_OBJECT_2 0x00800000UL
+/* svga3 caps */
+#define SVGA_CAP_COMMAND_BUFFERS 0x01000000UL
+#define SVGA_CAP_DEAD1 0x02000000UL
+#define SVGA_CAP_CMD_BUFFERS_2 0x04000000UL
+#define SVGA_CAP_GBOBJECTS 0x08000000UL
+#define SVGA_CAP_DX 0x10000000UL
+#define SVGA_CAP_HP_CMD_QUEUE 0x20000000UL
+#define SVGA_CAP_NO_BB_RESTRICTION 0x40000000UL
+#define SVGA_CAP_CAP2_REGISTER 0x80000000UL
+
+/*
+ * FIFO register indices.
+ *
+ * The FIFO is a chunk of device memory mapped into guest physmem. It
+ * is always treated as 32-bit words.
+ *
+ * The guest driver gets to decide how to partition it between
+ * - FIFO registers (there are always at least 4, specifying where the
+ * following data area is and how much data it contains; there may be
+ * more registers following these, depending on the FIFO protocol
+ * version in use)
+ * - FIFO data, written by the guest and slurped out by the VMX.
+ * These indices are 32-bit word offsets into the FIFO.
+ */
+
+enum {
+ /*
+ * Block 1 (basic registers): The originally defined FIFO registers.
+ * These exist and are valid for all versions of the FIFO protocol.
+ */
+
+ SVGA_FIFO_MIN = 0,
+ SVGA_FIFO_MAX, /* The distance from MIN to MAX must be at least 10K */
+ SVGA_FIFO_NEXT_CMD,
+ SVGA_FIFO_STOP,
+
+ /*
+ * Block 2 (extended registers): Mandatory registers for the extended
+ * FIFO. These exist if the SVGA caps register includes
+ * SVGA_CAP_EXTENDED_FIFO; some of them are valid only if their
+ * associated capability bit is enabled.
+ *
+ * Note that when originally defined, SVGA_CAP_EXTENDED_FIFO implied
+ * support only for (FIFO registers) CAPABILITIES, FLAGS, and FENCE.
+ * This means that the guest has to test individually (in most cases
+ * using FIFO caps) for the presence of registers after this; the VMX
+ * can define "extended FIFO" to mean whatever it wants, and currently
+ * won't enable it unless there's room for that set and much more.
+ */
+
+ SVGA_FIFO_CAPABILITIES = 4,
+ SVGA_FIFO_FLAGS,
+ // Valid with SVGA_FIFO_CAP_FENCE:
+ SVGA_FIFO_FENCE,
+
+ /*
+ * Block 3a (optional extended registers): Additional registers for the
+ * extended FIFO, whose presence isn't actually implied by
+ * SVGA_CAP_EXTENDED_FIFO; these exist if SVGA_FIFO_MIN is high enough to
+ * leave room for them.
+ *
+ * These in block 3a, the VMX currently considers mandatory for the
+ * extended FIFO.
+ */
+
+ // Valid if exists (i.e. if extended FIFO enabled):
+ SVGA_FIFO_3D_HWVERSION, /* See SVGA3dHardwareVersion in svga3d_reg.h */
+ // Valid with SVGA_FIFO_CAP_PITCHLOCK:
+ SVGA_FIFO_PITCHLOCK,
+
+ // Valid with SVGA_FIFO_CAP_CURSOR_BYPASS_3:
+ SVGA_FIFO_CURSOR_ON, /* Cursor bypass 3 show/hide register */
+ SVGA_FIFO_CURSOR_X, /* Cursor bypass 3 x register */
+ SVGA_FIFO_CURSOR_Y, /* Cursor bypass 3 y register */
+ SVGA_FIFO_CURSOR_COUNT, /* Incremented when any of the other 3 change */
+ SVGA_FIFO_CURSOR_LAST_UPDATED,/* Last time the host updated the cursor */
+
+ // Valid with SVGA_FIFO_CAP_RESERVE:
+ SVGA_FIFO_RESERVED, /* Bytes past NEXT_CMD with real contents */
+
+ /*
+ * Valid with SVGA_FIFO_CAP_SCREEN_OBJECT or SVGA_FIFO_CAP_SCREEN_OBJECT_2:
+ *
+ * By default this is SVGA_ID_INVALID, to indicate that the cursor
+ * coordinates are specified relative to the virtual root. If this
+ * is set to a specific screen ID, cursor position is reinterpreted
+ * as a signed offset relative to that screen's origin.
+ */
+ SVGA_FIFO_CURSOR_SCREEN_ID,
+
+ /*
+ * Valid with SVGA_FIFO_CAP_DEAD
+ *
+ * An arbitrary value written by the host, drivers should not use it.
+ */
+ SVGA_FIFO_DEAD,
+
+ /*
+ * Valid with SVGA_FIFO_CAP_3D_HWVERSION_REVISED:
+ *
+ * Contains 3D HWVERSION (see SVGA3dHardwareVersion in svga3d_reg.h)
+ * on platforms that can enforce graphics resource limits.
+ */
+ SVGA_FIFO_3D_HWVERSION_REVISED,
+
+ /*
+ * XXX: The gap here, up until SVGA_FIFO_3D_CAPS, can be used for new
+ * registers, but this must be done carefully and with judicious use of
+ * capability bits, since comparisons based on SVGA_FIFO_MIN aren't
+ * enough to tell you whether the register exists: we've shipped drivers
+ * and products that used SVGA_FIFO_3D_CAPS but didn't know about some of
+ * the earlier ones. The actual order of introduction was:
+ * - PITCHLOCK
+ * - 3D_CAPS
+ * - CURSOR_* (cursor bypass 3)
+ * - RESERVED
+ * So, code that wants to know whether it can use any of the
+ * aforementioned registers, or anything else added after PITCHLOCK and
+ * before 3D_CAPS, needs to reason about something other than
+ * SVGA_FIFO_MIN.
+ */
+
+ /*
+ * 3D caps block space; valid with 3D hardware version >=
+ * SVGA3D_HWVERSION_WS6_B1.
+ */
+ SVGA_FIFO_3D_CAPS = 32,
+ SVGA_FIFO_3D_CAPS_LAST = 32 + 255,
+
+ /*
+ * End of VMX's current definition of "extended-FIFO registers".
+ * Registers before here are always enabled/disabled as a block; either
+ * the extended FIFO is enabled and includes all preceding registers, or
+ * it's disabled entirely.
+ *
+ * Block 3b (truly optional extended registers): Additional registers for
+ * the extended FIFO, which the VMX already knows how to enable and
+ * disable with correct granularity.
+ *
+ * Registers after here exist if and only if the guest SVGA driver
+ * sets SVGA_FIFO_MIN high enough to leave room for them.
+ */
+
+ // Valid if register exists:
+ SVGA_FIFO_GUEST_3D_HWVERSION, /* Guest driver's 3D version */
+ SVGA_FIFO_FENCE_GOAL, /* Matching target for SVGA_IRQFLAG_FENCE_GOAL */
+ SVGA_FIFO_BUSY, /* See "FIFO Synchronization Registers" */
+
+ /*
+ * Always keep this last. This defines the maximum number of
+ * registers we know about. At power-on, this value is placed in
+ * the SVGA_REG_MEM_REGS register, and we expect the guest driver
+ * to allocate this much space in FIFO memory for registers.
+ */
+ SVGA_FIFO_NUM_REGS
+};
+
+
+/*
+ * Definition of registers included in extended FIFO support.
+ *
+ * The guest SVGA driver gets to allocate the FIFO between registers
+ * and data. It must always allocate at least 4 registers, but old
+ * drivers stopped there.
+ *
+ * The VMX will enable extended FIFO support if and only if the guest
+ * left enough room for all registers defined as part of the mandatory
+ * set for the extended FIFO.
+ *
+ * Note that the guest drivers typically allocate the FIFO only at
+ * initialization time, not at mode switches, so it's likely that the
+ * number of FIFO registers won't change without a reboot.
+ *
+ * All registers less than this value are guaranteed to be present if
+ * svgaUser->fifo.extended is set. Any later registers must be tested
+ * individually for compatibility at each use (in the VMX).
+ *
+ * This value is used only by the VMX, so it can change without
+ * affecting driver compatibility; keep it that way?
+ */
+#define SVGA_FIFO_EXTENDED_MANDATORY_REGS (SVGA_FIFO_3D_CAPS_LAST + 1)
+
+
+/*
+ * FIFO Synchronization Registers
+ *
+ * This explains the relationship between the various FIFO
+ * sync-related registers in IOSpace and in FIFO space.
+ *
+ * SVGA_REG_SYNC --
+ *
+ * The SYNC register can be used in two different ways by the guest:
+ *
+ * 1. If the guest wishes to fully sync (drain) the FIFO,
+ * it will write once to SYNC then poll on the BUSY
+ * register. The FIFO is sync'ed once BUSY is zero.
+ *
+ * 2. If the guest wants to asynchronously wake up the host,
+ * it will write once to SYNC without polling on BUSY.
+ * Ideally it will do this after some new commands have
+ * been placed in the FIFO, and after reading a zero
+ * from SVGA_FIFO_BUSY.
+ *
+ * (1) is the original behaviour that SYNC was designed to
+ * support. Originally, a write to SYNC would implicitly
+ * trigger a read from BUSY. This causes us to synchronously
+ * process the FIFO.
+ *
+ * This behaviour has since been changed so that writing SYNC
+ * will *not* implicitly cause a read from BUSY. Instead, it
+ * makes a channel call which asynchronously wakes up the MKS
+ * thread.
+ *
+ * New guests can use this new behaviour to implement (2)
+ * efficiently. This lets guests get the host's attention
+ * without waiting for the MKS to poll, which gives us much
+ * better CPU utilization on SMP hosts and on UP hosts while
+ * we're blocked on the host GPU.
+ *
+ * Old guests shouldn't notice the behaviour change. SYNC was
+ * never guaranteed to process the entire FIFO, since it was
+ * bounded to a particular number of CPU cycles. Old guests will
+ * still loop on the BUSY register until the FIFO is empty.
+ *
+ * Writing to SYNC currently has the following side-effects:
+ *
+ * - Sets SVGA_REG_BUSY to TRUE (in the monitor)
+ * - Asynchronously wakes up the MKS thread for FIFO processing
+ * - The value written to SYNC is recorded as a "reason", for
+ * stats purposes.
+ *
+ * If SVGA_FIFO_BUSY is available, drivers are advised to only
+ * write to SYNC if SVGA_FIFO_BUSY is FALSE. Drivers should set
+ * SVGA_FIFO_BUSY to TRUE after writing to SYNC. The MKS will
+ * eventually set SVGA_FIFO_BUSY on its own, but this approach
+ * lets the driver avoid sending multiple asynchronous wakeup
+ * messages to the MKS thread.
+ *
+ * SVGA_REG_BUSY --
+ *
+ * This register is set to TRUE when SVGA_REG_SYNC is written,
+ * and it reads as FALSE when the FIFO has been completely
+ * drained.
+ *
+ * Every read from this register causes us to synchronously
+ * process FIFO commands. There is no guarantee as to how many
+ * commands each read will process.
+ *
+ * CPU time spent processing FIFO commands will be billed to
+ * the guest.
+ *
+ * New drivers should avoid using this register unless they
+ * need to guarantee that the FIFO is completely drained. It
+ * is overkill for performing a sync-to-fence. Older drivers
+ * will use this register for any type of synchronization.
+ *
+ * SVGA_FIFO_BUSY --
+ *
+ * This register is a fast way for the guest driver to check
+ * whether the FIFO is already being processed. It reads and
+ * writes at normal RAM speeds, with no monitor intervention.
+ *
+ * If this register reads as TRUE, the host is guaranteeing that
+ * any new commands written into the FIFO will be noticed before
+ * the MKS goes back to sleep.
+ *
+ * If this register reads as FALSE, no such guarantee can be
+ * made.
+ *
+ * The guest should use this register to quickly determine
+ * whether or not it needs to wake up the host. If the guest
+ * just wrote a command or group of commands that it would like
+ * the host to begin processing, it should:
+ *
+ * 1. Read SVGA_FIFO_BUSY. If it reads as TRUE, no further
+ * action is necessary.
+ *
+ * 2. Write TRUE to SVGA_FIFO_BUSY. This informs future guest
+ * code that we've already sent a SYNC to the host and we
+ * don't need to send a duplicate.
+ *
+ * 3. Write a reason to SVGA_REG_SYNC. This will send an
+ * asynchronous wakeup to the MKS thread.
+ */
+
+
+/*
+ * FIFO Capabilities
+ *
+ * Fence -- Fence register and command are supported
+ * Accel Front -- Front buffer only commands are supported
+ * Pitch Lock -- Pitch lock register is supported
+ * Video -- SVGA Video overlay units are supported
+ * Escape -- Escape command is supported
+ *
+ * XXX: Add longer descriptions for each capability, including a list
+ * of the new features that each capability provides.
+ *
+ * SVGA_FIFO_CAP_SCREEN_OBJECT --
+ *
+ * Provides dynamic multi-screen rendering, for improved Unity and
+ * multi-monitor modes. With Screen Object, the guest can
+ * dynamically create and destroy 'screens', which can represent
+ * Unity windows or virtual monitors. Screen Object also provides
+ * strong guarantees that DMA operations happen only when
+ * guest-initiated. Screen Object deprecates the BAR1 guest
+ * framebuffer (GFB) and all commands that work only with the GFB.
+ *
+ * New registers:
+ * FIFO_CURSOR_SCREEN_ID, VIDEO_DATA_GMRID, VIDEO_DST_SCREEN_ID
+ *
+ * New 2D commands:
+ * DEFINE_SCREEN, DESTROY_SCREEN, DEFINE_GMRFB, BLIT_GMRFB_TO_SCREEN,
+ * BLIT_SCREEN_TO_GMRFB, ANNOTATION_FILL, ANNOTATION_COPY
+ *
+ * New 3D commands:
+ * BLIT_SURFACE_TO_SCREEN
+ *
+ * New guarantees:
+ *
+ * - The host will not read or write guest memory, including the GFB,
+ * except when explicitly initiated by a DMA command.
+ *
+ * - All DMA, including legacy DMA like UPDATE and PRESENT_READBACK,
+ * is guaranteed to complete before any subsequent FENCEs.
+ *
+ * - All legacy commands which affect a Screen (UPDATE, PRESENT,
+ * PRESENT_READBACK) as well as new Screen blit commands will
+ * all behave consistently as blits, and memory will be read
+ * or written in FIFO order.
+ *
+ * For example, if you PRESENT from one SVGA3D surface to multiple
+ * places on the screen, the data copied will always be from the
+ * SVGA3D surface at the time the PRESENT was issued in the FIFO.
+ * This was not necessarily true on devices without Screen Object.
+ *
+ * This means that on devices that support Screen Object, the
+ * PRESENT_READBACK command should not be necessary unless you
+ * actually want to read back the results of 3D rendering into
+ * system memory. (And for that, the BLIT_SCREEN_TO_GMRFB
+ * command provides a strict superset of functionality.)
+ *
+ * - When a screen is resized, either using Screen Object commands or
+ * legacy multimon registers, its contents are preserved.
+ *
+ * SVGA_FIFO_CAP_GMR2 --
+ *
+ * Provides new commands to define and remap guest memory regions (GMR).
+ *
+ * New 2D commands:
+ * DEFINE_GMR2, REMAP_GMR2.
+ *
+ * SVGA_FIFO_CAP_3D_HWVERSION_REVISED --
+ *
+ * Indicates new register SVGA_FIFO_3D_HWVERSION_REVISED exists.
+ * This register may replace SVGA_FIFO_3D_HWVERSION on platforms
+ * that enforce graphics resource limits. This allows the platform
+ * to clear SVGA_FIFO_3D_HWVERSION and disable 3D in legacy guest
+ * drivers that do not limit their resources.
+ *
+ * Note this is an alias to SVGA_FIFO_CAP_GMR2 because these indicators
+ * are codependent (and thus we use a single capability bit).
+ *
+ * SVGA_FIFO_CAP_SCREEN_OBJECT_2 --
+ *
+ * Modifies the DEFINE_SCREEN command to include a guest provided
+ * backing store in GMR memory and the bytesPerLine for the backing
+ * store. This capability requires the use of a backing store when
+ * creating screen objects. However if SVGA_FIFO_CAP_SCREEN_OBJECT
+ * is present then backing stores are optional.
+ *
+ * SVGA_FIFO_CAP_DEAD --
+ *
+ * Drivers should not use this cap bit. This cap bit can not be
+ * reused since some hosts already expose it.
+ */
+
+#define SVGA_FIFO_CAP_NONE 0
+#define SVGA_FIFO_CAP_FENCE (1<<0)
+#define SVGA_FIFO_CAP_ACCELFRONT (1<<1)
+#define SVGA_FIFO_CAP_PITCHLOCK (1<<2)
+#define SVGA_FIFO_CAP_VIDEO (1<<3)
+#define SVGA_FIFO_CAP_CURSOR_BYPASS_3 (1<<4)
+#define SVGA_FIFO_CAP_ESCAPE (1<<5)
+#define SVGA_FIFO_CAP_RESERVE (1<<6)
+#define SVGA_FIFO_CAP_SCREEN_OBJECT (1<<7)
+#define SVGA_FIFO_CAP_GMR2 (1<<8)
+#define SVGA_FIFO_CAP_3D_HWVERSION_REVISED SVGA_FIFO_CAP_GMR2
+#define SVGA_FIFO_CAP_SCREEN_OBJECT_2 (1<<9)
+#define SVGA_FIFO_CAP_DEAD (1<<10)
+
+
+/*
+ * FIFO Flags
+ *
+ * Accel Front -- Driver should use front buffer only commands
+ */
+
+#define SVGA_FIFO_FLAG_NONE 0
+#define SVGA_FIFO_FLAG_ACCELFRONT (1<<0)
+#define SVGA_FIFO_FLAG_RESERVED (1<<31) // Internal use only
+
+/*
+ * FIFO reservation sentinel value
+ */
+
+#define SVGA_FIFO_RESERVED_UNKNOWN 0xffffffff
+
+
+/*
+ * Video overlay support
+ */
+
+#define SVGA_NUM_OVERLAY_UNITS 32
+
+
+/*
+ * Video capabilities that the guest is currently using
+ */
+
+#define SVGA_VIDEO_FLAG_COLORKEY 0x0001
+
+
+/*
+ * Offsets for the video overlay registers
+ */
+
+enum {
+ SVGA_VIDEO_ENABLED = 0,
+ SVGA_VIDEO_FLAGS,
+ SVGA_VIDEO_DATA_OFFSET,
+ SVGA_VIDEO_FORMAT,
+ SVGA_VIDEO_COLORKEY,
+ SVGA_VIDEO_SIZE, // Deprecated
+ SVGA_VIDEO_WIDTH,
+ SVGA_VIDEO_HEIGHT,
+ SVGA_VIDEO_SRC_X,
+ SVGA_VIDEO_SRC_Y,
+ SVGA_VIDEO_SRC_WIDTH,
+ SVGA_VIDEO_SRC_HEIGHT,
+ SVGA_VIDEO_DST_X, // Signed int32
+ SVGA_VIDEO_DST_Y, // Signed int32
+ SVGA_VIDEO_DST_WIDTH,
+ SVGA_VIDEO_DST_HEIGHT,
+ SVGA_VIDEO_PITCH_1,
+ SVGA_VIDEO_PITCH_2,
+ SVGA_VIDEO_PITCH_3,
+ SVGA_VIDEO_DATA_GMRID, // Optional, defaults to SVGA_GMR_FRAMEBUFFER
+ SVGA_VIDEO_DST_SCREEN_ID, // Optional, defaults to virtual coords (SVGA_ID_INVALID)
+ SVGA_VIDEO_NUM_REGS
+};
+
+
+/*
+ * SVGA Overlay Units
+ *
+ * width and height relate to the entire source video frame.
+ * srcX, srcY, srcWidth and srcHeight represent subset of the source
+ * video frame to be displayed.
+ */
+
+typedef struct SVGAOverlayUnit {
+ uint32 enabled;
+ uint32 flags;
+ uint32 dataOffset;
+ uint32 format;
+ uint32 colorKey;
+ uint32 size;
+ uint32 width;
+ uint32 height;
+ uint32 srcX;
+ uint32 srcY;
+ uint32 srcWidth;
+ uint32 srcHeight;
+ int32 dstX;
+ int32 dstY;
+ uint32 dstWidth;
+ uint32 dstHeight;
+ uint32 pitches[3];
+ uint32 dataGMRId;
+ uint32 dstScreenId;
+} SVGAOverlayUnit;
+
+
+/*
+ * SVGAScreenObject --
+ *
+ * This is a new way to represent a guest's multi-monitor screen or
+ * Unity window. Screen objects are only supported if the
+ * SVGA_FIFO_CAP_SCREEN_OBJECT capability bit is set.
+ *
+ * If Screen Objects are supported, they can be used to fully
+ * replace the functionality provided by the framebuffer registers
+ * (SVGA_REG_WIDTH, HEIGHT, etc.) and by SVGA_CAP_DISPLAY_TOPOLOGY.
+ *
+ * The screen object is a struct with guaranteed binary
+ * compatibility. New flags can be added, and the struct may grow,
+ * but existing fields must retain their meaning.
+ *
+ * Added with SVGA_FIFO_CAP_SCREEN_OBJECT_2 are required fields of
+ * a SVGAGuestPtr that is used to back the screen contents. This
+ * memory must come from the GFB. The guest is not allowed to
+ * access the memory and doing so will have undefined results. The
+ * backing store is required to be page aligned and the size is
+ * padded to the next page boundry. The number of pages is:
+ * (bytesPerLine * size.width * 4 + PAGE_SIZE - 1) / PAGE_SIZE
+ *
+ * The pitch in the backingStore is required to be at least large
+ * enough to hold a 32bbp scanline. It is recommended that the
+ * driver pad bytesPerLine for a potential performance win.
+ *
+ * The cloneCount field is treated as a hint from the guest that
+ * the user wants this display to be cloned, countCount times. A
+ * value of zero means no cloning should happen.
+ */
+
+#define SVGA_SCREEN_MUST_BE_SET (1 << 0) // Must be set or results undefined
+#define SVGA_SCREEN_HAS_ROOT SVGA_SCREEN_MUST_BE_SET // Deprecated
+#define SVGA_SCREEN_IS_PRIMARY (1 << 1) // Guest considers this screen to be 'primary'
+#define SVGA_SCREEN_FULLSCREEN_HINT (1 << 2) // Guest is running a fullscreen app here
+
+/*
+ * Added with SVGA_FIFO_CAP_SCREEN_OBJECT_2. When the screen is
+ * deactivated the base layer is defined to lose all contents and
+ * become black. When a screen is deactivated the backing store is
+ * optional. When set backingPtr and bytesPerLine will be ignored.
+ */
+#define SVGA_SCREEN_DEACTIVATE (1 << 3)
+
+/*
+ * Added with SVGA_FIFO_CAP_SCREEN_OBJECT_2. When this flag is set
+ * the screen contents will be outputted as all black to the user
+ * though the base layer contents is preserved. The screen base layer
+ * can still be read and written to like normal though the no visible
+ * effect will be seen by the user. When the flag is changed the
+ * screen will be blanked or redrawn to the current contents as needed
+ * without any extra commands from the driver. This flag only has an
+ * effect when the screen is not deactivated.
+ */
+#define SVGA_SCREEN_BLANKING (1 << 4)
+
+typedef
+struct SVGAScreenObject {
+ uint32 structSize; // sizeof(SVGAScreenObject)
+ uint32 id;
+ uint32 flags;
+ struct {
+ uint32 width;
+ uint32 height;
+ } size;
+ struct {
+ int32 x;
+ int32 y;
+ } root;
+
+ /*
+ * Added and required by SVGA_FIFO_CAP_SCREEN_OBJECT_2, optional
+ * with SVGA_FIFO_CAP_SCREEN_OBJECT.
+ */
+ SVGAGuestImage backingStore;
+ uint32 cloneCount;
+} SVGAScreenObject;
+
+
+/*
+ * Commands in the command FIFO:
+ *
+ * Command IDs defined below are used for the traditional 2D FIFO
+ * communication (not all commands are available for all versions of the
+ * SVGA FIFO protocol).
+ *
+ * Note the holes in the command ID numbers: These commands have been
+ * deprecated, and the old IDs must not be reused.
+ *
+ * Command IDs from 1000 to 1999 are reserved for use by the SVGA3D
+ * protocol.
+ *
+ * Each command's parameters are described by the comments and
+ * structs below.
+ */
+
+typedef enum {
+ SVGA_CMD_INVALID_CMD = 0,
+ SVGA_CMD_UPDATE = 1,
+ SVGA_CMD_RECT_COPY = 3,
+ SVGA_CMD_DEFINE_CURSOR = 19,
+ SVGA_CMD_DEFINE_ALPHA_CURSOR = 22,
+ SVGA_CMD_UPDATE_VERBOSE = 25,
+ SVGA_CMD_FRONT_ROP_FILL = 29,
+ SVGA_CMD_FENCE = 30,
+ SVGA_CMD_ESCAPE = 33,
+ SVGA_CMD_DEFINE_SCREEN = 34,
+ SVGA_CMD_DESTROY_SCREEN = 35,
+ SVGA_CMD_DEFINE_GMRFB = 36,
+ SVGA_CMD_BLIT_GMRFB_TO_SCREEN = 37,
+ SVGA_CMD_BLIT_SCREEN_TO_GMRFB = 38,
+ SVGA_CMD_ANNOTATION_FILL = 39,
+ SVGA_CMD_ANNOTATION_COPY = 40,
+ SVGA_CMD_DEFINE_GMR2 = 41,
+ SVGA_CMD_REMAP_GMR2 = 42,
+ SVGA_CMD_MAX
+} SVGAFifoCmdId;
+
+#define SVGA_CMD_MAX_DATASIZE (256 * 1024)
+#define SVGA_CMD_MAX_ARGS 64
+
+
+/*
+ * SVGA_CMD_UPDATE --
+ *
+ * This is a DMA transfer which copies from the Guest Framebuffer
+ * (GFB) at BAR1 + SVGA_REG_FB_OFFSET to any screens which
+ * intersect with the provided virtual rectangle.
+ *
+ * This command does not support using arbitrary guest memory as a
+ * data source- it only works with the pre-defined GFB memory.
+ * This command also does not support signed virtual coordinates.
+ * If you have defined screens (using SVGA_CMD_DEFINE_SCREEN) with
+ * negative root x/y coordinates, the negative portion of those
+ * screens will not be reachable by this command.
+ *
+ * This command is not necessary when using framebuffer
+ * traces. Traces are automatically enabled if the SVGA FIFO is
+ * disabled, and you may explicitly enable/disable traces using
+ * SVGA_REG_TRACES. With traces enabled, any write to the GFB will
+ * automatically act as if a subsequent SVGA_CMD_UPDATE was issued.
+ *
+ * Traces and SVGA_CMD_UPDATE are the only supported ways to render
+ * pseudocolor screen updates. The newer Screen Object commands
+ * only support true color formats.
+ *
+ * Availability:
+ * Always available.
+ */
+
+typedef
+struct {
+ uint32 x;
+ uint32 y;
+ uint32 width;
+ uint32 height;
+} SVGAFifoCmdUpdate;
+
+
+/*
+ * SVGA_CMD_RECT_COPY --
+ *
+ * Perform a rectangular DMA transfer from one area of the GFB to
+ * another, and copy the result to any screens which intersect it.
+ *
+ * Availability:
+ * SVGA_CAP_RECT_COPY
+ */
+
+typedef
+struct {
+ uint32 srcX;
+ uint32 srcY;
+ uint32 destX;
+ uint32 destY;
+ uint32 width;
+ uint32 height;
+} SVGAFifoCmdRectCopy;
+
+
+/*
+ * SVGA_CMD_DEFINE_CURSOR --
+ *
+ * Provide a new cursor image, as an AND/XOR mask.
+ *
+ * The recommended way to position the cursor overlay is by using
+ * the SVGA_FIFO_CURSOR_* registers, supported by the
+ * SVGA_FIFO_CAP_CURSOR_BYPASS_3 capability.
+ *
+ * Availability:
+ * SVGA_CAP_CURSOR
+ */
+
+typedef
+struct {
+ uint32 id; // Reserved, must be zero.
+ uint32 hotspotX;
+ uint32 hotspotY;
+ uint32 width;
+ uint32 height;
+ uint32 andMaskDepth; // Value must be 1 or equal to BITS_PER_PIXEL
+ uint32 xorMaskDepth; // Value must be 1 or equal to BITS_PER_PIXEL
+ /*
+ * Followed by scanline data for AND mask, then XOR mask.
+ * Each scanline is padded to a 32-bit boundary.
+ */
+} SVGAFifoCmdDefineCursor;
+
+
+/*
+ * SVGA_CMD_DEFINE_ALPHA_CURSOR --
+ *
+ * Provide a new cursor image, in 32-bit BGRA format.
+ *
+ * The recommended way to position the cursor overlay is by using
+ * the SVGA_FIFO_CURSOR_* registers, supported by the
+ * SVGA_FIFO_CAP_CURSOR_BYPASS_3 capability.
+ *
+ * Availability:
+ * SVGA_CAP_ALPHA_CURSOR
+ */
+
+typedef
+struct {
+ uint32 id; // Reserved, must be zero.
+ uint32 hotspotX;
+ uint32 hotspotY;
+ uint32 width;
+ uint32 height;
+ /* Followed by scanline data */
+} SVGAFifoCmdDefineAlphaCursor;
+
+
+/*
+ * SVGA_CMD_UPDATE_VERBOSE --
+ *
+ * Just like SVGA_CMD_UPDATE, but also provide a per-rectangle
+ * 'reason' value, an opaque cookie which is used by internal
+ * debugging tools. Third party drivers should not use this
+ * command.
+ *
+ * Availability:
+ * SVGA_CAP_EXTENDED_FIFO
+ */
+
+typedef
+struct {
+ uint32 x;
+ uint32 y;
+ uint32 width;
+ uint32 height;
+ uint32 reason;
+} SVGAFifoCmdUpdateVerbose;
+
+
+/*
+ * SVGA_CMD_FRONT_ROP_FILL --
+ *
+ * This is a hint which tells the SVGA device that the driver has
+ * just filled a rectangular region of the GFB with a solid
+ * color. Instead of reading these pixels from the GFB, the device
+ * can assume that they all equal 'color'. This is primarily used
+ * for remote desktop protocols.
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_ACCELFRONT
+ */
+
+#define SVGA_ROP_COPY 0x03
+
+typedef
+struct {
+ uint32 color; // In the same format as the GFB
+ uint32 x;
+ uint32 y;
+ uint32 width;
+ uint32 height;
+ uint32 rop; // Must be SVGA_ROP_COPY
+} SVGAFifoCmdFrontRopFill;
+
+
+/*
+ * SVGA_CMD_FENCE --
+ *
+ * Insert a synchronization fence. When the SVGA device reaches
+ * this command, it will copy the 'fence' value into the
+ * SVGA_FIFO_FENCE register. It will also compare the fence against
+ * SVGA_FIFO_FENCE_GOAL. If the fence matches the goal and the
+ * SVGA_IRQFLAG_FENCE_GOAL interrupt is enabled, the device will
+ * raise this interrupt.
+ *
+ * Availability:
+ * SVGA_FIFO_FENCE for this command,
+ * SVGA_CAP_IRQMASK for SVGA_FIFO_FENCE_GOAL.
+ */
+
+typedef
+struct {
+ uint32 fence;
+} SVGAFifoCmdFence;
+
+
+/*
+ * SVGA_CMD_ESCAPE --
+ *
+ * Send an extended or vendor-specific variable length command.
+ * This is used for video overlay, third party plugins, and
+ * internal debugging tools. See svga_escape.h
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_ESCAPE
+ */
+
+typedef
+struct {
+ uint32 nsid;
+ uint32 size;
+ /* followed by 'size' bytes of data */
+} SVGAFifoCmdEscape;
+
+
+/*
+ * SVGA_CMD_DEFINE_SCREEN --
+ *
+ * Define or redefine an SVGAScreenObject. See the description of
+ * SVGAScreenObject above. The video driver is responsible for
+ * generating new screen IDs. They should be small positive
+ * integers. The virtual device will have an implementation
+ * specific upper limit on the number of screen IDs
+ * supported. Drivers are responsible for recycling IDs. The first
+ * valid ID is zero.
+ *
+ * - Interaction with other registers:
+ *
+ * For backwards compatibility, when the GFB mode registers (WIDTH,
+ * HEIGHT, PITCHLOCK, BITS_PER_PIXEL) are modified, the SVGA device
+ * deletes all screens other than screen #0, and redefines screen
+ * #0 according to the specified mode. Drivers that use
+ * SVGA_CMD_DEFINE_SCREEN should destroy or redefine screen #0.
+ *
+ * If you use screen objects, do not use the legacy multi-mon
+ * registers (SVGA_REG_NUM_GUEST_DISPLAYS, SVGA_REG_DISPLAY_*).
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_SCREEN_OBJECT or SVGA_FIFO_CAP_SCREEN_OBJECT_2
+ */
+
+typedef
+struct {
+ SVGAScreenObject screen; // Variable-length according to version
+} SVGAFifoCmdDefineScreen;
+
+
+/*
+ * SVGA_CMD_DESTROY_SCREEN --
+ *
+ * Destroy an SVGAScreenObject. Its ID is immediately available for
+ * re-use.
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_SCREEN_OBJECT or SVGA_FIFO_CAP_SCREEN_OBJECT_2
+ */
+
+typedef
+struct {
+ uint32 screenId;
+} SVGAFifoCmdDestroyScreen;
+
+
+/*
+ * SVGA_CMD_DEFINE_GMRFB --
+ *
+ * This command sets a piece of SVGA device state called the
+ * Guest Memory Region Framebuffer, or GMRFB. The GMRFB is a
+ * piece of light-weight state which identifies the location and
+ * format of an image in guest memory or in BAR1. The GMRFB has
+ * an arbitrary size, and it doesn't need to match the geometry
+ * of the GFB or any screen object.
+ *
+ * The GMRFB can be redefined as often as you like. You could
+ * always use the same GMRFB, you could redefine it before
+ * rendering from a different guest screen, or you could even
+ * redefine it before every blit.
+ *
+ * There are multiple ways to use this command. The simplest way is
+ * to use it to move the framebuffer either to elsewhere in the GFB
+ * (BAR1) memory region, or to a user-defined GMR. This lets a
+ * driver use a framebuffer allocated entirely out of normal system
+ * memory, which we encourage.
+ *
+ * Another way to use this command is to set up a ring buffer of
+ * updates in GFB memory. If a driver wants to ensure that no
+ * frames are skipped by the SVGA device, it is important that the
+ * driver not modify the source data for a blit until the device is
+ * done processing the command. One efficient way to accomplish
+ * this is to use a ring of small DMA buffers. Each buffer is used
+ * for one blit, then we move on to the next buffer in the
+ * ring. The FENCE mechanism is used to protect each buffer from
+ * re-use until the device is finished with that buffer's
+ * corresponding blit.
+ *
+ * This command does not affect the meaning of SVGA_CMD_UPDATE.
+ * UPDATEs always occur from the legacy GFB memory area. This
+ * command has no support for pseudocolor GMRFBs. Currently only
+ * true-color 15, 16, and 24-bit depths are supported. Future
+ * devices may expose capabilities for additional framebuffer
+ * formats.
+ *
+ * The default GMRFB value is undefined. Drivers must always send
+ * this command at least once before performing any blit from the
+ * GMRFB.
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_SCREEN_OBJECT or SVGA_FIFO_CAP_SCREEN_OBJECT_2
+ */
+
+typedef
+struct {
+ SVGAGuestPtr ptr;
+ uint32 bytesPerLine;
+ SVGAGMRImageFormat format;
+} SVGAFifoCmdDefineGMRFB;
+
+
+/*
+ * SVGA_CMD_BLIT_GMRFB_TO_SCREEN --
+ *
+ * This is a guest-to-host blit. It performs a DMA operation to
+ * copy a rectangular region of pixels from the current GMRFB to
+ * one or more Screen Objects.
+ *
+ * The destination coordinate may be specified relative to a
+ * screen's origin (if a screen ID is specified) or relative to the
+ * virtual coordinate system's origin (if the screen ID is
+ * SVGA_ID_INVALID). The actual destination may span zero or more
+ * screens, in the case of a virtual destination rect or a rect
+ * which extends off the edge of the specified screen.
+ *
+ * This command writes to the screen's "base layer": the underlying
+ * framebuffer which exists below any cursor or video overlays. No
+ * action is necessary to explicitly hide or update any overlays
+ * which exist on top of the updated region.
+ *
+ * The SVGA device is guaranteed to finish reading from the GMRFB
+ * by the time any subsequent FENCE commands are reached.
+ *
+ * This command consumes an annotation. See the
+ * SVGA_CMD_ANNOTATION_* commands for details.
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_SCREEN_OBJECT or SVGA_FIFO_CAP_SCREEN_OBJECT_2
+ */
+
+typedef
+struct {
+ SVGASignedPoint srcOrigin;
+ SVGASignedRect destRect;
+ uint32 destScreenId;
+} SVGAFifoCmdBlitGMRFBToScreen;
+
+
+/*
+ * SVGA_CMD_BLIT_SCREEN_TO_GMRFB --
+ *
+ * This is a host-to-guest blit. It performs a DMA operation to
+ * copy a rectangular region of pixels from a single Screen Object
+ * back to the current GMRFB.
+ *
+ * Usage note: This command should be used rarely. It will
+ * typically be inefficient, but it is necessary for some types of
+ * synchronization between 3D (GPU) and 2D (CPU) rendering into
+ * overlapping areas of a screen.
+ *
+ * The source coordinate is specified relative to a screen's
+ * origin. The provided screen ID must be valid. If any parameters
+ * are invalid, the resulting pixel values are undefined.
+ *
+ * This command reads the screen's "base layer". Overlays like
+ * video and cursor are not included, but any data which was sent
+ * using a blit-to-screen primitive will be available, no matter
+ * whether the data's original source was the GMRFB or the 3D
+ * acceleration hardware.
+ *
+ * Note that our guest-to-host blits and host-to-guest blits aren't
+ * symmetric in their current implementation. While the parameters
+ * are identical, host-to-guest blits are a lot less featureful.
+ * They do not support clipping: If the source parameters don't
+ * fully fit within a screen, the blit fails. They must originate
+ * from exactly one screen. Virtual coordinates are not directly
+ * supported.
+ *
+ * Host-to-guest blits do support the same set of GMRFB formats
+ * offered by guest-to-host blits.
+ *
+ * The SVGA device is guaranteed to finish writing to the GMRFB by
+ * the time any subsequent FENCE commands are reached.
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_SCREEN_OBJECT or SVGA_FIFO_CAP_SCREEN_OBJECT_2
+ */
+
+typedef
+struct {
+ SVGASignedPoint destOrigin;
+ SVGASignedRect srcRect;
+ uint32 srcScreenId;
+} SVGAFifoCmdBlitScreenToGMRFB;
+
+
+/*
+ * SVGA_CMD_ANNOTATION_FILL --
+ *
+ * This is a blit annotation. This command stores a small piece of
+ * device state which is consumed by the next blit-to-screen
+ * command. The state is only cleared by commands which are
+ * specifically documented as consuming an annotation. Other
+ * commands (such as ESCAPEs for debugging) may intervene between
+ * the annotation and its associated blit.
+ *
+ * This annotation is a promise about the contents of the next
+ * blit: The video driver is guaranteeing that all pixels in that
+ * blit will have the same value, specified here as a color in
+ * SVGAColorBGRX format.
+ *
+ * The SVGA device can still render the blit correctly even if it
+ * ignores this annotation, but the annotation may allow it to
+ * perform the blit more efficiently, for example by ignoring the
+ * source data and performing a fill in hardware.
+ *
+ * This annotation is most important for performance when the
+ * user's display is being remoted over a network connection.
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_SCREEN_OBJECT or SVGA_FIFO_CAP_SCREEN_OBJECT_2
+ */
+
+typedef
+struct {
+ SVGAColorBGRX color;
+} SVGAFifoCmdAnnotationFill;
+
+
+/*
+ * SVGA_CMD_ANNOTATION_COPY --
+ *
+ * This is a blit annotation. See SVGA_CMD_ANNOTATION_FILL for more
+ * information about annotations.
+ *
+ * This annotation is a promise about the contents of the next
+ * blit: The video driver is guaranteeing that all pixels in that
+ * blit will have the same value as those which already exist at an
+ * identically-sized region on the same or a different screen.
+ *
+ * Note that the source pixels for the COPY in this annotation are
+ * sampled before applying the anqnotation's associated blit. They
+ * are allowed to overlap with the blit's destination pixels.
+ *
+ * The copy source rectangle is specified the same way as the blit
+ * destination: it can be a rectangle which spans zero or more
+ * screens, specified relative to either a screen or to the virtual
+ * coordinate system's origin. If the source rectangle includes
+ * pixels which are not from exactly one screen, the results are
+ * undefined.
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_SCREEN_OBJECT or SVGA_FIFO_CAP_SCREEN_OBJECT_2
+ */
+
+typedef
+struct {
+ SVGASignedPoint srcOrigin;
+ uint32 srcScreenId;
+} SVGAFifoCmdAnnotationCopy;
+
+
+/*
+ * SVGA_CMD_DEFINE_GMR2 --
+ *
+ * Define guest memory region v2. See the description of GMRs above.
+ *
+ * Availability:
+ * SVGA_CAP_GMR2
+ */
+
+typedef
+struct {
+ uint32 gmrId;
+ uint32 numPages;
+}
+SVGAFifoCmdDefineGMR2;
+
+
+/*
+ * SVGA_CMD_REMAP_GMR2 --
+ *
+ * Remap guest memory region v2. See the description of GMRs above.
+ *
+ * This command allows guest to modify a portion of an existing GMR by
+ * invalidating it or reassigning it to different guest physical pages.
+ * The pages are identified by physical page number (PPN). The pages
+ * are assumed to be pinned and valid for DMA operations.
+ *
+ * Description of command flags:
+ *
+ * SVGA_REMAP_GMR2_VIA_GMR: If enabled, references a PPN list in a GMR.
+ * The PPN list must not overlap with the remap region (this can be
+ * handled trivially by referencing a separate GMR). If flag is
+ * disabled, PPN list is appended to SVGARemapGMR command.
+ *
+ * SVGA_REMAP_GMR2_PPN64: If set, PPN list is in PPN64 format, otherwise
+ * it is in PPN32 format.
+ *
+ * SVGA_REMAP_GMR2_SINGLE_PPN: If set, PPN list contains a single entry.
+ * A single PPN can be used to invalidate a portion of a GMR or
+ * map it to to a single guest scratch page.
+ *
+ * Availability:
+ * SVGA_CAP_GMR2
+ */
+
+typedef enum {
+ SVGA_REMAP_GMR2_PPN32 = 0,
+ SVGA_REMAP_GMR2_VIA_GMR = (1 << 0),
+ SVGA_REMAP_GMR2_PPN64 = (1 << 1),
+ SVGA_REMAP_GMR2_SINGLE_PPN = (1 << 2),
+} SVGARemapGMR2Flags;
+
+typedef
+struct {
+ uint32 gmrId;
+ SVGARemapGMR2Flags flags;
+ uint32 offsetPages; // offset in pages to begin remap
+ uint32 numPages; // number of pages to remap
+ /*
+ * Followed by additional data depending on SVGARemapGMR2Flags.
+ *
+ * If flag SVGA_REMAP_GMR2_VIA_GMR is set, single SVGAGuestPtr follows.
+ * Otherwise an array of page descriptors in PPN32 or PPN64 format
+ * (according to flag SVGA_REMAP_GMR2_PPN64) follows. If flag
+ * SVGA_REMAP_GMR2_SINGLE_PPN is set, array contains a single entry.
+ */
+}
+SVGAFifoCmdRemapGMR2;
+
+#endif
diff --git a/vmwsvxd.c b/vmwsvxd.c
new file mode 100644
index 0000000..72c282f
--- /dev/null
+++ b/vmwsvxd.c
@@ -0,0 +1,417 @@
+/*****************************************************************************
+
+Copyright (c) 2023 Jaroslav Hensl <emulator@emulace.cz>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+#include "winhack.h"
+#include "vmm.h"
+#include "vmwsvxd.h"
+
+#include "svga_all.h"
+
+#include "minivdd32.h"
+
+#include "version.h"
+
+#if 0
+/* dynamic VXDs don't using this init function in discardable segment */
+
+#pragma data_seg("_ITEXT", "ICODE")
+#pragma code_seg("_ITEXT", "ICODE")
+
+BOOL __cdecl VMWS_Sys_Critical_Init(DWORD hVM, DWORD dwRefData,
+ PSTR pCmdTail, PCRS_32 pCRS)
+{
+ return TRUE;
+}
+
+BOOL __cdecl VMWS_Device_Init(DWORD hVM, PSTR pCmdTail, PCRS_32 pCRS)
+{
+ return TRUE;
+}
+
+#endif
+
+#include "code32.h"
+
+void VMWS_Control();
+void VMWS_API_Entry();
+
+/*
+ VXD structure
+ this variable must be in first address in code segment.
+ In other cases VXD isn't loadable (WLINK bug?)
+*/
+DDB VMWS_DDB = {
+ NULL, // must be NULL
+ DDK_VERSION, // DDK_Version
+ VMWSVXD_DEVICE_ID, // Device ID
+ VMWSVXD_MAJOR_VER, // Major Version
+ VMWSVXD_MINOR_VER, // Minor Version
+ NULL,
+ "VMWSVXD",
+ VDD_Init_Order, //Undefined_Init_Order,
+ (DWORD)VMWS_Control,
+ (DWORD)VMWS_API_Entry,
+ (DWORD)VMWS_API_Entry,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, // DDB_Win32_Service_Table
+ NULL, // prev
+ sizeof(DDB)
+};
+
+/* string tables */
+char dbg_hello[] = "Hello world!\n";
+char dbg_version[] = "VMM version: ";
+char dbg_region_err[] = "region create error\n";
+
+char dbg_Device_Init_proc[] = "Device_Init_proc\n";
+char dbg_Device_Init_proc_succ[] = "Device_Init_proc success\n";
+
+DWORD *DispatchTable = 0;
+DWORD DispatchTableLength = 0;
+
+Bool svga_init_success = FALSE;
+
+/**
+ * VMM calls wrapers
+ **/
+DWORD Get_VMM_Version()
+{
+ static WORD ver;
+
+ _asm push ecx
+ _asm push eax
+ _asm xor eax, eax
+ VMMCall(Get_VMM_Version);
+ _asm mov [ver],ax
+ _asm pop ecx
+ _asm pop eax
+
+ return ver;
+}
+
+ULONG __declspec(naked) __cdecl _PageAllocate(ULONG nPages, ULONG pType, ULONG VM, ULONG AlignMask, ULONG minPhys, ULONG maxPhys, ULONG *PhysAddr, ULONG flags)
+{
+ VMMJmp(_PageAllocate);
+}
+
+ULONG __declspec(naked) __cdecl _PageFree(PVOID hMem, DWORD flags)
+{
+ VMMJmp(_PageFree);
+}
+
+/**
+ * VDD calls wrapers
+ **/
+void VDD_Get_Mini_Dispatch_Table()
+{
+ VxDCall(VDD, Get_Mini_Dispatch_Table);
+ _asm mov [DispatchTable],edi
+ _asm mov [DispatchTableLength],ecx
+}
+
+/**
+ * Control Handles
+ **/
+void Sys_Critical_Init_proc()
+{
+ // nop
+}
+
+void Device_Init_proc();
+
+/*
+ * service module calls (init, exit, deviceIoControl, ...)
+ * clear carry if succes (this is always success)
+ */
+void __declspec(naked) VMWS_Control()
+{
+ // eax = 0x00 - Sys Critical Init
+ // eax = 0x01 - sys dynamic init
+ // eax = 0x1B - dynamic init
+ // eax = 0x1C - dynamic exit
+ // eax = 0x23 - device IO control
+
+ _asm {
+ pushad
+ cmp eax,Sys_Critical_Init
+ jnz control_1
+ call Sys_Critical_Init_proc
+ control_1:
+ cmp eax,Device_Init
+ jnz control_2
+ call Device_Init_proc
+ control_2:
+ cmp eax,0x1B
+ jnz control_3
+ call Device_Init_proc
+ control_3:
+ popad
+ clc
+ ret
+ };
+}
+
+/**
+ * PM16 driver RING0 calls
+ **/
+BOOL CreateRegion(unsigned int nPages, ULONG *lpLAddr, ULONG *lpPPN)
+{
+ ULONG phy;
+ ULONG laddr;
+ SVGAGuestMemDescriptor *desc;
+ laddr = _PageAllocate(nPages + 1, PG_SYS, 0, 0x00000000, 0, 0x100000, &phy, PAGECONTIG | PAGEUSEALIGN | PAGEFIXED);
+
+ if(laddr)
+ {
+ desc = (SVGAGuestMemDescriptor*)laddr;
+ desc->ppn = (phy/P_SIZE) + 1;
+ desc->numPages = nPages;
+ desc++;
+ desc->ppn = 0;
+ desc->numPages = 0;
+
+ *lpLAddr = laddr;
+ *lpPPN = (phy/P_SIZE);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL FreeRegion(ULONG LAddr)
+{
+ if(_PageFree((PVOID)LAddr, 0) != 0)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+#define MOB_PER_PAGE_CNT (P_SIZE/sizeof(ULONG))
+
+BOOL CreateMOB(unsigned int nPages, ULONG *lpLAddr, ULONG *lpPPN)
+{
+ unsigned int mobBasePages = (nPages + MOB_PER_PAGE_CNT - 1)/MOB_PER_PAGE_CNT;
+ ULONG phy;
+ ULONG laddr;
+
+ laddr = _PageAllocate(nPages + mobBasePages, PG_SYS, 0, 0x00000000, 0, 0x100000, &phy, PAGECONTIG | PAGEUSEALIGN | PAGEFIXED);
+ if(laddr)
+ {
+ unsigned int i;
+ ULONG ppu = (phy/P_SIZE) + mobBasePages;
+ ULONG *ptr = (ULONG*)laddr;
+
+ for(i = 0; i < nPages; i++)
+ {
+ ptr[i] = ppu;
+ ppu++;
+ }
+
+ *lpLAddr = laddr;
+ *lpPPN = (phy/P_SIZE);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL FreeMOB(ULONG LAddr)
+{
+ if(_PageFree((PVOID)LAddr, 0) != 0)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+WORD __stdcall VMWS_API_Proc(PCRS_32 state)
+{
+ WORD rc = 0xFFFF;
+ WORD service = state->Client_EDX & 0xFFFF;
+ switch(service)
+ {
+ case VMWSVXD_PM16_VERSION:
+ rc = (VMWSVXD_MAJOR_VER << 8) | VMWSVXD_MINOR_VER;
+ break;
+ case VMWSVXD_PM16_VMM_VERSION:
+ rc = Get_VMM_Version();
+ break;
+ /* create region = input: ECX - num_pages; output: EDX - lin. address of descriptor, ECX - PPN of descriptor */
+ case VMWSVXD_PM16_CREATE_REGION:
+ {
+ ULONG lAddr;
+ ULONG PPN;
+
+ if(CreateRegion(state->Client_ECX, &lAddr, &PPN))
+ {
+ state->Client_ECX = PPN;
+ state->Client_EDX = lAddr;
+ rc = 1;
+ }
+ else
+ {
+ state->Client_ECX = 0;
+ state->Client_EDX = 0;
+
+ dbg_printf(dbg_region_err);
+
+ rc = 0;
+ }
+ break;
+ }
+ /* free region = input: ECX: lin. address */
+ case VMWSVXD_PM16_DESTROY_REGION:
+ {
+ if(FreeRegion(state->Client_ECX))
+ {
+ rc = 1;
+ }
+ else
+ {
+ rc = 0;
+ }
+ break;
+ }
+ /* Create MOB = input: ECX - num_pages; output: EDX - lin. address of descriptor, ECX - PPN of descriptor */
+ case VMWSVXD_PM16_CREATE_MOB:
+ {
+ ULONG lAddr;
+ ULONG PPN;
+
+ if(CreateMOB(state->Client_ECX, &lAddr, &PPN))
+ {
+ state->Client_ECX = PPN;
+ state->Client_EDX = lAddr;
+ rc = 1;
+ }
+ else
+ {
+ state->Client_ECX = 0;
+ state->Client_EDX = 0;
+
+ dbg_printf(dbg_region_err);
+
+ rc = 0;
+ }
+ break;
+ }
+ /* Free MOB = input: ECX: lin. address */
+ case VMWSVXD_PM16_DESTROY_MOB:
+ {
+ if(FreeMOB(state->Client_ECX))
+ {
+ rc = 1;
+ }
+ else
+ {
+ rc = 0;
+ }
+ break;
+ }
+ /* clear memory on linear address (ESI) by defined size (ECX) */
+ case VMWSVXD_PM16_ZEROMEM:
+ {
+ ULONG i = 0;
+ unsigned char *ptr = (unsigned char *)state->Client_ESI;
+ for(i = 0; i < state->Client_ECX; i++)
+ {
+ ptr[i] = 0;
+ }
+ rc = 1;
+ break;
+ }
+ /* set ECX to actual api version */
+ case VMWSVXD_PM16_APIVER:
+ state->Client_ECX = DRV_API_LEVEL;
+ rc = 1;
+ break;
+ }
+
+ if(rc == 0xFFFF)
+ {
+ state->Client_EFlags |= 0x1; // set carry
+ }
+ else
+ {
+ state->Client_EFlags &= 0xFFFFFFFEUL; // clear carry
+ }
+
+ return rc;
+}
+
+/*
+ * Service calls from protected mode (usually 16 bit) and virtual 86 mode
+ * CPU state before call is already on stack (EBP points it).
+ * Converts the call to __stdcall and call 'VMWS_API_Proc', result of this
+ * function is placed to saved AX register.
+ *
+ */
+void __declspec(naked) VMWS_API_Entry()
+{
+ _asm {
+ push ebp
+ call VMWS_API_Proc
+ mov [ebp+1Ch], ax
+ retn
+ }
+}
+
+/* generate all entry pro VDD function */
+#define VDDFUNC(_fnname, _procname) void __declspec(naked) _procname ## _entry() { \
+ _asm { push ebp }; \
+ _asm { call _procname ## _proc }; \
+ _asm { retn }; \
+ }
+#include "minivdd_func.h"
+#undef VDDFUNC
+
+#define VDDFUNC(id, procname) DispatchTable[id] = (DWORD)(procname ## _entry);
+
+/* init device and fill dispatch table */
+void Device_Init_proc()
+{
+ dbg_printf(dbg_Device_Init_proc);
+ // VMMCall _Allocate_Device_CB_Area
+
+ if(SVGA_Init(FALSE) == 0)
+ {
+ dbg_printf(dbg_Device_Init_proc_succ);
+ svga_init_success = TRUE;
+
+ VDD_Get_Mini_Dispatch_Table();
+ if(DispatchTableLength >= 0x31)
+ {
+ #include "minivdd_func.h"
+ }
+ }
+}
+#undef VDDFUNC
diff --git a/vmwsvxd.h b/vmwsvxd.h
new file mode 100644
index 0000000..3eb2442
--- /dev/null
+++ b/vmwsvxd.h
@@ -0,0 +1,22 @@
+#ifndef __VMWSVXD_H__INCLUDED__
+#define __VMWSVXD_H__INCLUDED__
+
+/* Table of "known" drivers
+ * https://fd.lod.bz/rbil/interrup/windows/2f1684.html#sect-4579
+ * This looks like free
+ */
+#define VMWSVXD_DEVICE_ID 0x7fe7
+
+#define VMWSVXD_MAJOR_VER 2
+#define VMWSVXD_MINOR_VER 0
+
+#define VMWSVXD_PM16_VERSION 0
+#define VMWSVXD_PM16_VMM_VERSION 1
+#define VMWSVXD_PM16_CREATE_REGION 2
+#define VMWSVXD_PM16_DESTROY_REGION 3
+#define VMWSVXD_PM16_CREATE_MOB 4
+#define VMWSVXD_PM16_DESTROY_MOB 5
+#define VMWSVXD_PM16_ZEROMEM 6
+#define VMWSVXD_PM16_APIVER 7
+
+#endif
diff --git a/winhack.h b/winhack.h
new file mode 100644
index 0000000..ae2d041
--- /dev/null
+++ b/winhack.h
@@ -0,0 +1,18 @@
+/* The gdidefs.h header badly conflicts with windows.h. Microsoft's printer
+ * drivers in the Windows DDK solve that by manually defining a large subset
+ * of windows.h. We solve that by including the normal windows.h but hiding
+ * the conflicting definitions.
+ */
+#define NOGDI
+#define PPOINT n_PPOINT
+#define LPPOINT n_LPPOINT
+#define RECT n_RECT
+#define PRECT n_PRECT
+#define LPRECT n_LPRECT
+#include <windows.h>
+#undef PPOINT
+#undef LPPOINT
+#undef RECT
+#undef PRECT
+#undef LPRECT
+