/******************************Module*Header*******************************\
* Module Name: ddraw.c
*
* Client side stubs for the private DirectDraw system APIs.
*
* Created: 3-Dec-1995
* Author: J. Andrew Goossen [andrewgo]
*
* Copyright (c) 1995-1999 Microsoft Corporation
\**************************************************************************/


#define _D3DTYPES_H_
#define _D3DCAPS_H_
#include "ddrawpr.h"
//#include "ddrawgdi.h"
#include <ddrawint.h>
#include <d3dnthal.h>
#include <winddi.h>
#include <osthunk.h>
#include "ddithunk.h"
#include <d3d8sddi.h>
#include <assert.h>

#define _FACD3D  0x876
#define MAKE_D3DHRESULT( code )  MAKE_HRESULT( 1, _FACD3D, code )
#define D3DERR_DEVICELOST                       MAKE_D3DHRESULT(2152)
#define D3DERR_DRIVERINTERNALERROR              MAKE_D3DHRESULT(2087)
#define D3DERR_NOTAVAILABLE                     MAKE_D3DHRESULT(2154)
#define D3DERR_OUTOFVIDEOMEMORY                 MAKE_D3DHRESULT(380)
#define D3DERR_DEFERRED_DP2ERROR                MAKE_D3DHRESULT(2158)

typedef struct _KNOWNENTRY
{
    DWORD   PCIID;
    DWORD   VersionMajor;       // 0 means all versions
    DWORD   VersionMinor;       // 0 means all versions
    DWORD   Flags;
} KNOWNENTRY;

// The buffer used by GetDriverInfo2 is constrained to the maximum size
// specified below by restrictions in the Win2K kernel. It is vital that
// all data passed to the driver and received from the driver via
// GetDriverInfo2 fit within a buffer of this number of DWORDS.
// This size has to be less than 1K to let the kernel do its own buffer
// overwrite testing.
#define MAX_GDI2_BUFFER_DWORD_SIZE (249)

// Bogus value used to initialize write only fields when communicating
// with the driver in debug builds
#define BOGUS_FIELD_VALUE          0xBAADCAFEul

// Some global variables used to track when surfaces are free for all devices
// in the process.  This is tricky since we don't keep a device list.
DWORD GlobalUniqueness = 0;
DWORD NumDevices = 0;
DWORD NumReadyDevices = 0;

//todo d16 for rage 128 series... need date/time
//todo :G200, G400 new RT+Tex formats... need date/time
//todo: Need driver date/time for Kyro: |KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8
//todo: Trident 8420, 9910: need date/time for D16
//todo: dates for SiS parts D16

const KNOWNENTRY gKnownDeviceList[] =
{
    // NVidia
    {0x12D20018,          0,          0, KNOWN_ZSTENCILDEPTH},                                      // Riva 128         
    {0x10DE0020,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // TNT
    {0x10DE0028,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // TNT2
    {0x10DE0029,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // TNT2 Ultra
    {0x10DE002C,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Vanta
    {0x10DE002D,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // TNT2 Model 64
    {0x10DE00A0,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Aladdin TNT2
    {0x10DE0100,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_MIPPEDCUBEMAPS|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // NV10 (GeForce) 
    {0x10DE0101,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_MIPPEDCUBEMAPS|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // NV10 (GeForce DDR) 
    {0x10DE0103,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_MIPPEDCUBEMAPS|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // NV10 (Quadro) 
    {0x10DE0110,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_MIPPEDCUBEMAPS|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // NV11 (GeForce2 MX) 
    {0x10DE0111,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_MIPPEDCUBEMAPS|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // NV11 (GeForce2 MX) 
    {0x10DE0113,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_MIPPEDCUBEMAPS|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // NV11 (Quadro2 MXR) 
    {0x10DE0150,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_MIPPEDCUBEMAPS|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // NV15 (GeForce2)
    {0x10DE0151,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_MIPPEDCUBEMAPS|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // NV15 (GeForce2 DDR) 
    {0x10DE0152,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_MIPPEDCUBEMAPS|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // NV15 (GeForce2 BR) 
    {0x10DE0153,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_MIPPEDCUBEMAPS|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // NV15 (Quadro2) 
    {0x10DE0200,          0,          0, KNOWN_LIGHTWEIGHT|KNOWN_D16_LOCKABLE|KNOWN_MIPPEDCUBEMAPS|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // NV20 (GeForce 3)
    // 3DFX
    {0x121A0003,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_R5G6B5},            // Banshee
    {0x121A0005,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_R5G6B5},            // Voodoo3
    {0x121a0009,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_A8R8G8B8},       // Voodoo4/5; same PCI-ID
    // ATI                                                                                           
    {0x10024742,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // RagePro
    {0x10024744,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // RagePro
    {0x10024749,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // RagePro
    {0x1002474D,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // RagePro
    {0x1002474E,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // RagePro
    {0x1002474F,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // RagePro
    {0x10024750,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // RagePro
    {0x10024752,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // RagePro
    {0x10024C42,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // RagePro (PCI)
    {0x10024C49,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // RagePro (PCI)
    {0x10024C4E,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // RagePro
    {0x10024C52,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // RagePro
    {0x10024C53,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // RagePro
    {0x10024C60,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // RagePro LT

    {0x10024C4D,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X1R5G5B5},   // Rage Mobility AGP

    {0x10024C46, 0x0005000a, 0x00000404, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // Rage Mobility 128
    {0x10024C46,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // Rage Mobility 128
    {0x10024D46, 0x0005000a, 0x00000404, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // Rage Mobility 128
    {0x10024D46,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // Rage Mobility 128

    {0x10025046, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X TMDS
    {0x10025046,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X TMDS
    {0x10025245, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128
    {0x10025245,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128
    {0x10025246, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128
    {0x10025246,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128
    {0x1002524B, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 VR PCI //DX8.1
    {0x1002524B,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 VR PCI //DX8.1
    {0x1002524C, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128
    {0x1002524C,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128

    //New 128s for DX8.1:
    {0x10025041, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO PCI            DX8.1
    {0x10025041,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO PCI            DX8.1
    {0x10025042, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X         DX8.1
    {0x10025042,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X         DX8.1
    {0x10025043, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X         DX8.1
    {0x10025043,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X         DX8.1
    {0x10025044, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO PCI TMDS       DX8.1
    {0x10025044,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO PCI TMDS       DX8.1
    {0x10025045, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X TMDS    DX8.1
    {0x10025045,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X TMDS    DX8.1
    {0x10025047, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO PCI            DX8.1
    {0x10025047,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO PCI            DX8.1
    {0x10025048, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X         DX8.1
    {0x10025048,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X         DX8.1
    {0x10025049, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X         DX8.1
    {0x10025049,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X         DX8.1
    {0x1002504a, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO PCI TMDS       DX8.1
    {0x1002504a,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO PCI TMDS       DX8.1
    {0x1002504b, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X TMDS    DX8.1
    {0x1002504b,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X TMDS    DX8.1
    {0x1002504c, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X TMDS    DX8.1
    {0x1002504c,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X TMDS    DX8.1
    {0x1002504d, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP            DX8.1
    {0x1002504d,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP            DX8.1
    {0x1002504e, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X         DX8.1
    {0x1002504e,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X         DX8.1
    {0x1002504f, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X         DX8.1
    {0x1002504f,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X         DX8.1
    {0x10025050, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO PCI TMDS       DX8.1
    {0x10025050,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO PCI TMDS       DX8.1
    {0x10025051, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X TMDS    DX8.1
    {0x10025051,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X TMDS    DX8.1
    {0x10025052, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X TMDS    DX8.1
    {0x10025052,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X TMDS    DX8.1
    {0x10025053, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO PCI            DX8.1
    {0x10025053,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO PCI            DX8.1
    {0x10025054, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X         DX8.1
    {0x10025054,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X         DX8.1
    {0x10025055, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X         DX8.1
    {0x10025055,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X         DX8.1
    {0x10025056, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO PCI TMDS       DX8.1
    {0x10025056,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO PCI TMDS       DX8.1
    {0x10025057, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X TMDS    DX8.1
    {0x10025057,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 2X TMDS    DX8.1
    {0x10025058, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X TMDS    DX8.1
    {0x10025058,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO AGP 4X TMDS    DX8.1
                        
    {0x10025345, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X PCI    DX8.1
    {0x10025345,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X PCI    DX8.1
    {0x10025346, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X AGP 2X    DX8.1
    {0x10025346,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X AGP 2X    DX8.1
    {0x10025347, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X AGP 4X    DX8.1
    {0x10025347,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X AGP 4X    DX8.1
    {0x10025348, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X   DX8.1
    {0x10025348,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X   DX8.1
    {0x1002534b, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X PCI    DX8.1
    {0x1002534b,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X PCI    DX8.1
    {0x1002534c, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X AGP 2X    DX8.1
    {0x1002534c,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X AGP 2X    DX8.1
    {0x1002534d, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X AGP 4X    DX8.1
    {0x1002534d,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X AGP 4X    DX8.1
    {0x1002534e, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X     DX8.1
    {0x1002534e,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 4X     DX8.1

    {0x10025446, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO ULTRA GL AGP      DX8.1
    {0x10025446,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO ULTRA GL AGP      DX8.1
    {0x1002544c, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO ULTRA VR AGP      DX8.1
    {0x1002544c,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO ULTRA VR AGP      DX8.1
    {0x10025452, 0x00050001, 0x098a0001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO ULTRA4XL VR-R AGP DX8.1
    {0x10025452,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage128 PRO ULTRA4XL VR-R AGP DX8.1

    {0x10025144,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage6
    {0x10025145,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage6
    {0x10025146,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage6
    {0x10025147,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Rage6

    // Intel                                                                                         
    {0x80867800,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER},  // Intel i740
    {0x80867123,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5},  // Intel 810
    {0x80867125,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5},                              // Intel 810e
    {0x80861132,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_R5G6B5},                                                 // Intel 815
    {0x80861A12,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER},                                            // Intel Timna

    // Matrox                                                                                        
    {0x102b0520, 0x0005000c, 0x000104b0, KNOWN_ZSTENCILDEPTH|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},                                      // G200 PCI
    {0x102b0520,          0,          0, KNOWN_ZSTENCILDEPTH},                                      // G200 PCI
    {0x102b0521, 0x0005000c, 0x000104b0, KNOWN_ZSTENCILDEPTH|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},          // G200 AGP
    {0x102b0521,          0,          0, KNOWN_ZSTENCILDEPTH},          // G200 AGP
    {0x102b0525, 0x0005000c, 0x000104b0, KNOWN_ZSTENCILDEPTH|KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // G400, G450
    {0x102b0525,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // G400, G450
    // 3DLabs                                                                                        
    {0x3d3d0008,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH},                                      // 3DLabs Gamma
    {0x104c3d07,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8}, // Perm2
    {0x3d3d0009,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8},                                      // Perm2
    {0x3d3d000a,          0,          0, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Perm3
    {0x3d3d000a, 0x00050000, 0x08930001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Perm3
    {0x3d3d000c, 0x00050000, 0x08930001, KNOWN_CANMISMATCHRT|KNOWN_ZSTENCILDEPTH|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Perm3
    // Videologic                                                                                    
    {0x104a0010, 0x0004000c, 0x0001080c, KNOWN_ZSTENCILDEPTH|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // PowerVR Kyro updated driver
    {0x104a0010,          0,          0, KNOWN_ZSTENCILDEPTH}, // PowerVR Kyro
    // S3                                                                                            
    {0x53338811,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_X1R5G5B5},          // Virge
    {0x53335631,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_X1R5G5B5},          // Virge
    {0x53338a01,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_X1R5G5B5},          // Virge DX/GX DX8.1
    {0x53338c01,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_X1R5G5B5},          // Virge MX DX8.1
    {0x53338a10,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_X1R5G5B5},          // Virge GX2 DX8.1
    {0x53338a20,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER},          // Savage3D
    {0x53338a22,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},          // Savage4
    {0x53339102,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER},          // Savage2K
    {0x53338c10,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_R5G6B5},          // Savage MX DX8.1
    {0x53338c12,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_R5G6B5},          // Savage IX DX8.1
    {0x53338a25,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},          // Savage Pro DX8.1
    {0x53338a26,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},          // Savage Pro DX8.1
    // Trident
    {0x10239880,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER}, // Trident Blade 3D 9880
    {0x10238500,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Trident Blade 3D/ProMedia DX8.1
    {0x10238400,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Trident Blade 3D/MVP4     DX8.1
    {0x10238420,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Trident CyberBlade i7 
    {0x10239910,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8}, // Trident CyberBlade DX8.1
    // SiS
    {0x10390300, 0x0005000c, 0x0001044c, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},               // SiS 300
    {0x10390300,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_R5G6B5},               // SiS 300
    {0x10396326, 0x0005000c, 0x00010514, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5},          // SiS 6326
    {0x10396326,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_NOTAWINDOWEDBLTQUEUER },          // SiS 6326
    {0x10395300, 0x0005000c, 0x0001044c, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},               // SiS 300
    {0x10395300,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_R5G6B5},               // SiS 300
    {0x10396300, 0x0005000c, 0x0001044c, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},               // SiS 6300
    {0x10396300,          0,          0, KNOWN_ZSTENCILDEPTH|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5},               // SiS 6300
    {0x10390310, 0x0005000d, 0x0001035c, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // SiS 310
    {0x10390315, 0x0005000d, 0x0001035c, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // SiS 315
    {0x10390325, 0x0005000d, 0x000107d0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // SiS 325
    {0x10396325, 0x0005000d, 0x000107d0, KNOWN_ZSTENCILDEPTH|KNOWN_D16_LOCKABLE|KNOWN_CANMISMATCHRT|KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_A1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_A4R4G4B4|KNOWN_RTTEXTURE_X8R8G8B8|KNOWN_RTTEXTURE_A8R8G8B8},   // SiS 640/740
    {0x126f0720,          0,          0, KNOWN_RTTEXTURE_X1R5G5B5|KNOWN_RTTEXTURE_R5G6B5|KNOWN_RTTEXTURE_A1R5G5B5} //Silicon Motion Lynx3DM
};

#define NUM_KNOWN_DEVICES      (sizeof(gKnownDeviceList)/sizeof(KNOWNENTRY))

#define RESPATH_D3D "Software\\Microsoft\\Direct3D"

void InformDriverFreeAGP(HANDLE hDD);
void InformDriverToDeferFrees(HANDLE hDD);
void InformDriverAGPWorkaroundAware(HANDLE hDD);

#ifdef DEBUG
// Debug helper to indicate which surfaces are around
// 
void DebugPrintSurfaceInfo(PDDSURFHANDLE pSurf)
{
    switch (pSurf->Type)
    {
    case D3DRTYPE_SURFACE:
        DPF(0,"  D3DRTYPE_SURFACE");
        break;
    case D3DRTYPE_VOLUME:
        DPF(0,"  D3DRTYPE_VOLUME");
        break;
    case D3DRTYPE_TEXTURE:
        DPF(0,"  D3DRTYPE_TEXTURE");
        break;
    case D3DRTYPE_VOLUMETEXTURE:
        DPF(0,"  D3DRTYPE_VOLUMETEXTURE");
        break;
    case D3DRTYPE_CUBETEXTURE:
        DPF(0,"  D3DRTYPE_CUBETEXTURE");
        break;
    case D3DRTYPE_VERTEXBUFFER:
        DPF(0,"  D3DRTYPE_VERTEXBUFFER");
        break;
    case D3DRTYPE_INDEXBUFFER:
        DPF(0,"  D3DRTYPE_INDEXBUFFER");
        break;
    case D3DRTYPE_COMMANDBUFFER:
        DPF(0,"  D3DRTYPE_COMMANDBUFFER");
        break;
    default:
        DPF(0,"  UNKNOWN SURFACE TYPE");
        break;
    }
} // DebugPrintSurfaceInfo
#endif 



HRESULT MapLegacyResult(HRESULT in)
{
    HRESULT hr;
    switch (in)
    {
    case DD_OK:
        hr = S_OK;
        break;

    case DDERR_OUTOFVIDEOMEMORY:
        hr = D3DERR_OUTOFVIDEOMEMORY;
        break;

    case DDERR_CURRENTLYNOTAVAIL:
    case DDERR_UNSUPPORTED:
        hr = D3DERR_NOTAVAILABLE;
        break;

    case DDERR_OUTOFMEMORY:
        hr = E_OUTOFMEMORY;
        break;

    default:
        hr = D3DERR_DRIVERINTERNALERROR;
    }
    return hr;
}

BOOL CanKnownDriverDoThis(PDDDEVICEHANDLE pDevice, DWORD Flag)
{
    BOOL ret = FALSE;
    int i;

    if (pDevice->ForceFlagsOff & Flag)
    {
        return FALSE;
    }
    else if (pDevice->ForceFlagsOn & Flag)
    {
        return TRUE;
    }

    // Only drivers in our known good list can support lightweight
    // surfaces

    if (pDevice->PCIID == 0)
    {
        D3DADAPTER_IDENTIFIER8  DI;

        GetAdapterInfo(pDevice->szDeviceName, &DI, TRUE, TRUE, FALSE);
        pDevice->PCIID = (DI.VendorId << 16) | DI.DeviceId;
        pDevice->DriverVersionHigh = DI.DriverVersion.HighPart;
        pDevice->DriverVersionLow = DI.DriverVersion.LowPart;
    }
    for (i = 0; i < NUM_KNOWN_DEVICES; i++)
    {
        if ((gKnownDeviceList[i].PCIID == pDevice->PCIID) &&
            (gKnownDeviceList[i].Flags & Flag) &&
            ((pDevice->DriverVersionHigh > gKnownDeviceList[i].VersionMajor) ||
             ((pDevice->DriverVersionHigh == gKnownDeviceList[i].VersionMajor) &&
              (pDevice->DriverVersionLow >= gKnownDeviceList[i].VersionMinor))))
        {
            ret = TRUE;
            break;
        }
    }

    return ret;
}

BOOL FormatCompatibleWithDisplayFormat(
    PDDDEVICEHANDLE pDD,
    D3DFORMAT Format)
{
    // The surface is compatible if formats match
    if (Format == pDD->DisplayFormatWithAlpha)
        return TRUE;
    return FALSE;
}

#undef DPF_MODNAME
#define DPF_MODNAME "ReleaseDX7SurfaceHandle"

void ReleaseDX7SurfaceHandle(HANDLE hDD, DWORD handle)
{
    PDDDEVICEHANDLE pDeviceHandle = (PDDDEVICEHANDLE) hDD;

    pDeviceHandle->SurfaceHandleList.dwList[handle].nextentry =
        pDeviceHandle->SurfaceHandleList.dwFreeList;
    pDeviceHandle->SurfaceHandleList.dwFreeList = handle;
}

#undef DPF_MODNAME
#define DPF_MODNAME "FreeSurfaceObject"

void FreeSurfaceObject (PDDSURFHANDLE pSurf)
{
    DWORD dwRet = DDHAL_DRIVER_NOTHANDLED;

    // If the surface was created by a software driver, we need to call the
    // software driver to destroy it.

    if (IS_SOFTWARE_DRIVER_SURFACE(pSurf))
    {
        // In a creation failure case, we may have not actually called the
        // driver/kernel to create this surface yet.

        // Release the kernel's handle first so that it
        // can finish up whatever it wants to before we free
        // the underlying memory
        if (pSurf->hSurface != 0)
        {
            OsThunkDdDeleteSurfaceObject(pSurf->hSurface);
        }

        // Now free the SW driver's object
        if (pSurf->dwFlags & DDSURF_CREATECOMPLETE)
        {
            dwRet = SwDDIDestroySurface (pSurf->pDevice, pSurf);
        }

    }
    else if (pSurf->hSurface != 0)
    {
        if (pSurf->Pool != D3DPOOL_SYSTEMMEM)
        {
            if ((pSurf->Type == D3DRTYPE_COMMANDBUFFER) ||
                (pSurf->Type == D3DRTYPE_VERTEXBUFFER)  || 
                (pSurf->Type == D3DRTYPE_INDEXBUFFER) )
            {
                OsThunkDdDestroyD3DBuffer(pSurf->hSurface);
            }
            else
            {
                OsThunkDdDestroySurface(pSurf->hSurface, TRUE);
            }
        }
        OsThunkDdDeleteSurfaceObject(pSurf->hSurface);
        pSurf->hSurface = NULL;
    }

    if (pSurf->dwCookie)
    {
        // If CreateSurfaceEx was called on a sysmem surface, we need to tell
        // the driver.  On NT, we only need to tell the software driver since
        // the kernel handles this for a real driver.

        if ((IS_SOFTWARE_DRIVER(pSurf->pDevice)) &&
            (pSurf->dwFlags & DDSURF_CREATECOMPLETE) &&
            (pSurf->Pool == D3DPOOL_SYSTEMMEM))
        {
            // DX7 called CreateSurfaceEx fpVidMem = 0 on each mipmap level
            // (even though it only creates it on the topmost level), so we
            // need to do the same to maintain driver compatibility.

            pSurf->pLcl->lpGbl->fpVidMem = 0;
            SwDDICreateSurfaceEx (pSurf->pDevice->pDD, pSurf->pLcl);
        }

        ReleaseDX7SurfaceHandle(pSurf->pDevice, pSurf->dwCookie);
        pSurf->dwCookie = 0;
    }

    if (pSurf->pLcl != NULL)
    {
        MemFree(pSurf->pLcl);
        pSurf->pLcl = NULL;
    }
}

#undef DPF_MODNAME
#define DPF_MODNAME "CheckForDeviceLost"

BOOL CheckForDeviceLost (HANDLE hDD)
{
    PDDDEVICEHANDLE pDeviceHandle = (PDDDEVICEHANDLE) hDD;
    PDDSURFHANDLE pSurf;
    DWORD           Uniqueness = DdQueryDisplaySettingsUniqueness();

    if (!pDeviceHandle->bDeviceLost &&
        (Uniqueness != pDeviceHandle->DisplayUniqueness))
    {
        // If this is the first device to notice it is lost, then set
        // some state.
        if (InterlockedCompareExchange(&GlobalUniqueness, Uniqueness, GlobalUniqueness) != Uniqueness)
        {
            NumReadyDevices = 0;
        }
        pDeviceHandle->dwFlags &= ~DDDEVICE_READY;

        // The device has transitioned to the lost state, so we need
        // walk through the list and free the vidmem surfaces..

        pDeviceHandle->bDeviceLost  = TRUE;
        pSurf = pDeviceHandle->pSurfList;
        while (pSurf != NULL)
        {
            if (IS_SURFACE_LOOSABLE(pSurf))
            {
                if (pSurf->LockRefCnt == 0)
                {
                    FreeSurfaceObject(pSurf);
                }
                pSurf->fpVidMem = (ULONG_PTR) NULL;
            }
            pSurf = pSurf->pNext;
        }
    }

    return pDeviceHandle->bDeviceLost;
}

#undef DPF_MODNAME
#define DPF_MODNAME "GetDX7SurfaceHandle"

DWORD GetDX7SurfaceHandle (HANDLE hDD)
{
    PDDDEVICEHANDLE pDeviceHandle = (PDDDEVICEHANDLE) hDD;
    DWORD           handle = pDeviceHandle->SurfaceHandleList.dwFreeList;

    if (0==handle)
    {
        // need to grow the dwList
        LPDDSURFACELISTENTRY  newList;
        DWORD   newsize;
        DWORD   index;
        if (NULL != pDeviceHandle->SurfaceHandleList.dwList)
        {
            // old size(current dwFreeList) must not be zero
            DDASSERT(0 != pDeviceHandle->SurfaceHandleList.dwList[0].nextentry);
            // new dwFreeList is always gonna be the old dwList[0].nextentry
            newsize = pDeviceHandle->SurfaceHandleList.dwList[0].nextentry + LISTGROWSIZE;
            newList=(LPDDSURFACELISTENTRY)MemAlloc(newsize*sizeof(DDSURFACELISTENTRY));
            if (NULL == newList)
            {
                DPF_ERR("MemAlloc failure in GetSurfaceHandle(). Can't create new texture/surface/buffer.");
                return  0;
            }
            pDeviceHandle->SurfaceHandleList.dwFreeList =
                pDeviceHandle->SurfaceHandleList.dwList[0].nextentry;
            memcpy((LPVOID)newList,(LPVOID)pDeviceHandle->SurfaceHandleList.dwList,
                pDeviceHandle->SurfaceHandleList.dwList[0].nextentry*sizeof(DDSURFACELISTENTRY));
            MemFree(pDeviceHandle->SurfaceHandleList.dwList);
        }
        else
        {
            newsize = LISTGROWSIZE;
            newList=(LPDDSURFACELISTENTRY)MemAlloc(newsize*sizeof(DDSURFACELISTENTRY));
            if (NULL == newList)
            {
                DPF_ERR("MemAlloc failure in GetSurfaceHandle(). Can't create new texture/surface/buffer");
                return  0;
            }
            // start from one as we don't want 0 as a valid handle
            pDeviceHandle->SurfaceHandleList.dwFreeList = 1;
        }
        pDeviceHandle->SurfaceHandleList.dwList=newList;
        pDeviceHandle->SurfaceHandleList.dwList[0].nextentry=newsize;

        for (index = pDeviceHandle->SurfaceHandleList.dwFreeList;
            index < newsize - 1;
            index++)
        {
            newList[index].nextentry=index+1;
        }
        // indicate end of new FreeList
        newList[newsize-1].nextentry=0;
        // now pop up one and assign it to handle
        handle=pDeviceHandle->SurfaceHandleList.dwFreeList;
    }
    // handle slot is avialable so just remove it from freeList
    pDeviceHandle->SurfaceHandleList.dwFreeList =
    pDeviceHandle->SurfaceHandleList.dwList[handle].nextentry;
#if DBG
    pDeviceHandle->SurfaceHandleList.dwList[handle].nextentry=0xDEADBEEF;
#endif
    pDeviceHandle->SurfaceHandleList.dwList[handle].dwFlags=0;  //mark it's new
    pDeviceHandle->SurfaceHandleList.dwList[handle].lpSurface=NULL;
    DDASSERT (handle > 0);
    DDASSERT (handle < pDeviceHandle->SurfaceHandleList.dwList[0].nextentry);
    return handle;
}

/*****************************Private*Routine******************************\
* DdConvertToOldFormat
*
* History:
*  3-Nov-1999 -by- Scott MacDonald [smac]
* Wrote it.
\**************************************************************************/

#undef DPF_MODNAME
#define DPF_MODNAME "ConvertToOldFormat"

void ConvertToOldFormat(LPDDPIXELFORMAT pOldFormat, D3DFORMAT NewFormat)
{
    // Zero out the format to avoid missing
    // cases where it isn't initialized right
    ZeroMemory(pOldFormat, sizeof(*pOldFormat));

    // Set Size
    pOldFormat->dwSize = sizeof(DDPIXELFORMAT);

    // Convert away
    if (HIWORD((DWORD)NewFormat))
    {
        pOldFormat->dwFlags = DDPF_FOURCC;
        pOldFormat->dwFourCC = (DWORD)NewFormat;
        return;
    }

    switch (NewFormat)
    {
    case D3DFMT_R8G8B8:
        pOldFormat->dwFlags           = DDPF_RGB;
        pOldFormat->dwRBitMask        = 0x00ff0000;
        pOldFormat->dwGBitMask        = 0x0000ff00;
        pOldFormat->dwBBitMask        = 0x000000ff;
        pOldFormat->dwRGBBitCount     = 24;
        break;

    case D3DFMT_A8R8G8B8:
        pOldFormat->dwFlags           = DDPF_RGB | DDPF_ALPHAPIXELS;
        pOldFormat->dwRGBAlphaBitMask = 0xFF000000;
        pOldFormat->dwRBitMask        = 0x00ff0000;
        pOldFormat->dwGBitMask        = 0x0000ff00;
        pOldFormat->dwBBitMask        = 0x000000ff;
        pOldFormat->dwRGBBitCount     = 32;
        break;

    case D3DFMT_X8R8G8B8:
        pOldFormat->dwFlags           = DDPF_RGB;
        pOldFormat->dwRBitMask        = 0x00ff0000;
        pOldFormat->dwGBitMask        = 0x0000ff00;
        pOldFormat->dwBBitMask        = 0x000000ff;
        pOldFormat->dwRGBBitCount     = 32;
        break;

    case D3DFMT_R5G6B5:
        pOldFormat->dwFlags           = DDPF_RGB;
        pOldFormat->dwRBitMask        = 0x0000f800;
        pOldFormat->dwGBitMask        = 0x000007e0;
        pOldFormat->dwBBitMask        = 0x0000001f;
        pOldFormat->dwRGBBitCount     = 16;
        break;

    case D3DFMT_X1R5G5B5:
        pOldFormat->dwFlags           = DDPF_RGB;
        pOldFormat->dwRBitMask        = 0x00007c00;
        pOldFormat->dwGBitMask        = 0x000003e0;
        pOldFormat->dwBBitMask        = 0x0000001f;
        pOldFormat->dwRGBBitCount     = 16;
        break;

    case D3DFMT_A1R5G5B5:
        pOldFormat->dwFlags           = DDPF_RGB | DDPF_ALPHAPIXELS;
        pOldFormat->dwRGBAlphaBitMask = 0x00008000;
        pOldFormat->dwRBitMask        = 0x00007c00;
        pOldFormat->dwGBitMask        = 0x000003e0;
        pOldFormat->dwBBitMask        = 0x0000001f;
        pOldFormat->dwRGBBitCount     = 16;
        break;

    case D3DFMT_A4R4G4B4:
        pOldFormat->dwFlags           = DDPF_RGB | DDPF_ALPHAPIXELS;
        pOldFormat->dwRGBAlphaBitMask = 0x0000f000;
        pOldFormat->dwRBitMask        = 0x00000f00;
        pOldFormat->dwGBitMask        = 0x000000f0;
        pOldFormat->dwBBitMask        = 0x0000000f;
        pOldFormat->dwRGBBitCount     = 16;
        break;

    case D3DFMT_X4R4G4B4:
        pOldFormat->dwFlags           = DDPF_RGB;
        pOldFormat->dwRBitMask        = 0x00000f00;
        pOldFormat->dwGBitMask        = 0x000000f0;
        pOldFormat->dwBBitMask        = 0x0000000f;
        pOldFormat->dwRGBBitCount     = 16;
        break;

    case D3DFMT_R3G3B2:
        pOldFormat->dwFlags           = DDPF_RGB;
        pOldFormat->dwRBitMask        = 0x000000e0;
        pOldFormat->dwGBitMask        = 0x0000001c;
        pOldFormat->dwBBitMask        = 0x00000003;
        pOldFormat->dwRGBBitCount     = 8;
        break;

    case D3DFMT_A8R3G3B2:
        pOldFormat->dwFlags           = DDPF_RGB | DDPF_ALPHAPIXELS;
        pOldFormat->dwRGBAlphaBitMask = 0x0000FF00;
        pOldFormat->dwRBitMask        = 0x000000e0;
        pOldFormat->dwGBitMask        = 0x0000001c;
        pOldFormat->dwBBitMask        = 0x00000003;
        pOldFormat->dwRGBBitCount     = 16;
        break;

    case D3DFMT_A8P8:
        pOldFormat->dwFlags            = DDPF_RGB         |
                                         DDPF_ALPHAPIXELS |
                                         DDPF_PALETTEINDEXED8;

        pOldFormat->dwRGBAlphaBitMask  = 0x0000FF00;
        pOldFormat->dwRGBBitCount      = 16;
        break;

    case D3DFMT_P8:
        pOldFormat->dwFlags            = DDPF_RGB         |
                                         DDPF_PALETTEINDEXED8;
        pOldFormat->dwRGBBitCount      = 8;
        break;

    case D3DFMT_L8:
        pOldFormat->dwFlags             = DDPF_LUMINANCE;
        pOldFormat->dwLuminanceBitMask  = 0x000000FF;
        pOldFormat->dwLuminanceBitCount = 8;
        break;

    case D3DFMT_A8L8:
        pOldFormat->dwFlags                 = DDPF_LUMINANCE |
                                              DDPF_ALPHAPIXELS;
        pOldFormat->dwLuminanceAlphaBitMask = 0x0000FF00;
        pOldFormat->dwLuminanceBitMask      = 0x000000FF;
        pOldFormat->dwLuminanceBitCount     = 16;
        break;

    case D3DFMT_A4L4:
        pOldFormat->dwFlags                 = DDPF_LUMINANCE |
                                              DDPF_ALPHAPIXELS;
        pOldFormat->dwLuminanceAlphaBitMask = 0x000000F0;
        pOldFormat->dwLuminanceBitMask      = 0x0000000F;
        pOldFormat->dwLuminanceBitCount     = 8;
        break;

    case D3DFMT_V8U8:
        pOldFormat->dwFlags                = DDPF_BUMPDUDV;
        pOldFormat->dwBumpDvBitMask        = 0x0000FF00;
        pOldFormat->dwBumpDuBitMask        = 0x000000FF;
        pOldFormat->dwBumpBitCount         = 16;
        break;

    case D3DFMT_L6V5U5:
        pOldFormat->dwFlags                = DDPF_BUMPDUDV |
                                             DDPF_BUMPLUMINANCE;
        pOldFormat->dwBumpLuminanceBitMask = 0x0000FC00;
        pOldFormat->dwBumpDvBitMask        = 0x000003E0;
        pOldFormat->dwBumpDuBitMask        = 0x0000001F;
        pOldFormat->dwBumpBitCount         = 16;
        break;

    case D3DFMT_X8L8V8U8:
        pOldFormat->dwFlags                = DDPF_BUMPDUDV |
                                             DDPF_BUMPLUMINANCE;
        pOldFormat->dwBumpLuminanceBitMask = 0x00FF0000;
        pOldFormat->dwBumpDvBitMask        = 0x0000FF00;
        pOldFormat->dwBumpDuBitMask        = 0x000000FF;
        pOldFormat->dwBumpBitCount         = 32;
        break;

    case D3DFMT_A8:
        pOldFormat->dwFlags                = DDPF_ALPHA;
        pOldFormat->dwAlphaBitDepth        = 8;
        break;

    case D3DFMT_D16:
    case D3DFMT_D16_LOCKABLE:
        pOldFormat->dwFlags                = DDPF_ZBUFFER;
        pOldFormat->dwZBufferBitDepth      = 16;
        pOldFormat->dwZBitMask             = 0xFFFF;
        pOldFormat->dwStencilBitDepth      = 0;
        pOldFormat->dwStencilBitMask       = 0;
        break;

    case D3DFMT_D32:
        pOldFormat->dwFlags                = DDPF_ZBUFFER;
        pOldFormat->dwZBufferBitDepth      = 32;
        pOldFormat->dwZBitMask             = 0xFFFFFFFF;
        pOldFormat->dwStencilBitDepth      = 0;
        pOldFormat->dwStencilBitMask       = 0;
        break;

    case D3DFMT_D15S1:
        pOldFormat->dwFlags                = DDPF_ZBUFFER |
                                             DDPF_STENCILBUFFER;
        pOldFormat->dwZBufferBitDepth      = 16;
        pOldFormat->dwZBitMask             = 0xFFFE;
        pOldFormat->dwStencilBitDepth      = 1;
        pOldFormat->dwStencilBitMask       = 0x0001;
        break;
    case D3DFMT_D24S8:
        pOldFormat->dwFlags                = DDPF_ZBUFFER |
                                             DDPF_STENCILBUFFER;
        pOldFormat->dwZBufferBitDepth      = 32;
        pOldFormat->dwZBitMask             = 0xFFFFFF00;
        pOldFormat->dwStencilBitDepth      = 8;
        pOldFormat->dwStencilBitMask       = 0xFF;
        break;
    case D3DFMT_S1D15:
        pOldFormat->dwFlags                = DDPF_ZBUFFER |
                                             DDPF_STENCILBUFFER;
        pOldFormat->dwZBufferBitDepth      = 16;
        pOldFormat->dwZBitMask             = 0x7FFF;
        pOldFormat->dwStencilBitDepth      = 1;
        pOldFormat->dwStencilBitMask       = 0x8000;
        break;
    case D3DFMT_S8D24:
        pOldFormat->dwFlags                = DDPF_ZBUFFER |
                                             DDPF_STENCILBUFFER;
        pOldFormat->dwZBufferBitDepth      = 32;
        pOldFormat->dwZBitMask             = 0x00FFFFFF;
        pOldFormat->dwStencilBitDepth      = 8;
        pOldFormat->dwStencilBitMask       = 0xFF000000;
        break;
    case D3DFMT_X8D24:
        pOldFormat->dwFlags                = DDPF_ZBUFFER;
        pOldFormat->dwZBufferBitDepth      = 32;
        pOldFormat->dwZBitMask             = 0x00FFFFFF;
        pOldFormat->dwStencilBitDepth      = 0;
        pOldFormat->dwStencilBitMask       = 0x00000000;
        break;
    case D3DFMT_D24X8:
        pOldFormat->dwFlags                = DDPF_ZBUFFER;
        pOldFormat->dwZBufferBitDepth      = 32;
        pOldFormat->dwZBitMask             = 0xFFFFFF00;
        pOldFormat->dwStencilBitDepth      = 0;
        pOldFormat->dwStencilBitMask       = 0x00000000;
        break;
    case D3DFMT_D24X4S4:
        pOldFormat->dwFlags                = DDPF_ZBUFFER |
                                             DDPF_STENCILBUFFER;
        pOldFormat->dwZBufferBitDepth      = 32;
        pOldFormat->dwZBitMask             = 0xFFFFFF00;
        pOldFormat->dwStencilBitDepth      = 4;
        pOldFormat->dwStencilBitMask       = 0x0000000F;
        break;
    case D3DFMT_X4S4D24:
        pOldFormat->dwFlags                = DDPF_ZBUFFER |
                                             DDPF_STENCILBUFFER;
        pOldFormat->dwZBufferBitDepth      = 32;
        pOldFormat->dwZBitMask             = 0x00FFFFFF;
        pOldFormat->dwStencilBitDepth      = 4;
        pOldFormat->dwStencilBitMask       = 0x0F000000;
        break;

    default:
        // All other formats are treated as a
        // FOURCC
        pOldFormat->dwFlags = DDPF_FOURCC;
        pOldFormat->dwFourCC = (DWORD)NewFormat;
        break;
    }

    return;
}


/*****************************Private*Routine******************************\
* InitSurfaceStructures
*
* History:
*  06-Dec-1999 -by- Scott MacDonald [smac]
* Wrote it.
\**************************************************************************/

#undef DPF_MODNAME
#define DPF_MODNAME "InitSurfaceStructure"

void InitSurfaceStructures(
    PD3D8_CREATESURFACEDATA pCreateSurface,
    DD_SURFACE_LOCAL*       pDDSurfaceLocal,
    DD_SURFACE_GLOBAL*      pDDSurfaceGlobal,
    DD_SURFACE_MORE*        pDDSurfaceMore
   )
{
    PDDDEVICEHANDLE pDevice = (PDDDEVICEHANDLE) pCreateSurface->hDD;
    DWORD   i;
    DWORD   j;
    DWORD   dwBit;

    for (i = 0; i < pCreateSurface->dwSCnt; i++)
    {
        // Make sure there's always a valid pixel format for the surface:
        if ((pCreateSurface->Format != D3DFMT_UNKNOWN) &&
            (pCreateSurface->Format != D3DFMT_VERTEXDATA) &&
            (pCreateSurface->Format != D3DFMT_INDEX16) &&
            (pCreateSurface->Format != D3DFMT_INDEX32))
        {
            pDDSurfaceLocal[i].dwFlags |= DDRAWISURF_HASPIXELFORMAT;

            // For non-textures, we want to promote X8R8G8B8 to A8R8G8B8 in some cases;
            // this allows things like RTs and Backbuffers to get created matching the
            // primary which is more consistent with typical DX7 usage.
            if (FormatCompatibleWithDisplayFormat(pDevice, (D3DFORMAT)pCreateSurface->Format) &&
                (pCreateSurface->Type == D3DRTYPE_SURFACE))
            {
                ConvertToOldFormat(&pDDSurfaceGlobal[i].ddpfSurface, pDevice->DisplayFormatWithAlpha);
            }
            else
            {
                ConvertToOldFormat(&pDDSurfaceGlobal[i].ddpfSurface, (D3DFORMAT)pCreateSurface->Format);
            }
        }

        // Setup width/height first
        pDDSurfaceGlobal[i].wWidth       = pCreateSurface->pSList[i].cpWidth;
        pDDSurfaceGlobal[i].wHeight      = pCreateSurface->pSList[i].cpHeight;

        //dwCaps3==1 means 1 sample per pixel.
        pDDSurfaceMore[i].ddsCapsEx.dwCaps3 = DDSCAPS3_MULTISAMPLE_MASK & (DWORD) pCreateSurface->MultiSampleType;

        if (pCreateSurface->dwUsage & D3DUSAGE_ALPHACHANNEL)
        {
            pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_ENABLEALPHACHANNEL;
        }

        switch (pCreateSurface->Type)
        {
        case D3DRTYPE_SURFACE:
            // Surfaces come in three general flavors:
            //  - Primary flip chains
            //  - Z buffers
            //  - OffscreenPlain (RenderTargets or just sys-mem stuff)
            //
            // Textures are a different resource type

            if (pCreateSurface->dwUsage & D3DUSAGE_PRIMARYSURFACE)
            {
                // If we aren't creating a primary flip chain, then we
                // don't have to do much here.
                
                if (pCreateSurface->dwSCnt == 1)
                {
                    pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_PRIMARYSURFACE;
                }
                else
                {
                    if (i == 0)
                    {
                        // This is the front buffer
                        pDDSurfaceLocal[i].ddsCaps.dwCaps |=
                            DDSCAPS_PRIMARYSURFACE |
                            DDSCAPS_VISIBLE |
                            DDSCAPS_FRONTBUFFER;
                    }
                    else
                    {
                        // This is a back buffer
                        pDDSurfaceLocal[i].ddsCaps.dwCaps |=
                            DDSCAPS_BACKBUFFER;
                    }

                    // All surfaces in the primary chain get these caps
                    pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_3DDEVICE;

                    // We also get a CreateEx handle for all surfaces in the
                    // chain, but not if we're running w/ a software driver.
                    if (((PDDDEVICEHANDLE)pCreateSurface->hDD)->pDD == NULL)
                    {
                        pDDSurfaceMore[i].dwSurfaceHandle = GetDX7SurfaceHandle(pCreateSurface->hDD);
                    }
                }
            }
            else if (pCreateSurface->dwUsage & D3DUSAGE_DEPTHSTENCIL)
            {
                DDASSERT(0 == (pCreateSurface->dwUsage & D3DUSAGE_DISCARD) );
                pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_ZBUFFER;
                pDDSurfaceMore[i].dwSurfaceHandle = GetDX7SurfaceHandle(pCreateSurface->hDD);
            }
            else
            {
                pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN;
            }
            break;
        case D3DRTYPE_VOLUME:
            // We don't create stand-alone volumes
            DDASSERT(FALSE);
            break;
        case D3DRTYPE_TEXTURE:
            DDASSERT(0 == (pCreateSurface->dwUsage & D3DUSAGE_DISCARD) );

            pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_TEXTURE;

            //mipmaps are only DDI-level mipmaps if they're more than one level
            if (pCreateSurface->dwSCnt>1)
                pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_MIPMAP;

            if (i > 0)
            {
                // Mark non-top levels as being a sub-level
                pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
            }

            if (pCreateSurface->dwUsage & D3DUSAGE_DYNAMIC)
            {
                pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_HINTDYNAMIC;
            }

            pDDSurfaceMore[i].dwSurfaceHandle = GetDX7SurfaceHandle(pCreateSurface->hDD);
            break;
        case D3DRTYPE_VOLUMETEXTURE:
            DDASSERT(0 == (pCreateSurface->dwUsage & D3DUSAGE_DISCARD) );

            pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_TEXTURE | DDSCAPS_MIPMAP;
            pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_VOLUME;
            pDDSurfaceMore[i].ddsCapsEx.dwCaps4 =
                MAKELONG((WORD)(pCreateSurface->pSList[i].cpDepth),0);

            if (i > 0)
            {
                // Mark non-top levels as being a sub-level
                pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
            }

            if (pCreateSurface->dwUsage & D3DUSAGE_DYNAMIC)
            {
                pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_HINTDYNAMIC;
            }

            pDDSurfaceMore[i].dwSurfaceHandle = GetDX7SurfaceHandle(pCreateSurface->hDD);
            break;
        case D3DRTYPE_CUBETEXTURE:
            DDASSERT(0 == (pCreateSurface->dwUsage & D3DUSAGE_DISCARD) );

            pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_TEXTURE | DDSCAPS_COMPLEX;
            pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_CUBEMAP;
            pDDSurfaceMore[i].dwSurfaceHandle = GetDX7SurfaceHandle(pCreateSurface->hDD);

            //cubemaps are only DDI-level mipmaps if they're more than one level
            if (pCreateSurface->dwSCnt>6)
                pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_MIPMAP;

            // DX8 only supports creation of all faces
            {
                DWORD dwOrderedFaces[6] = {
                                           DDSCAPS2_CUBEMAP_POSITIVEX,
                                           DDSCAPS2_CUBEMAP_NEGATIVEX,
                                           DDSCAPS2_CUBEMAP_POSITIVEY,
                                           DDSCAPS2_CUBEMAP_NEGATIVEY,
                                           DDSCAPS2_CUBEMAP_POSITIVEZ,
                                           DDSCAPS2_CUBEMAP_NEGATIVEZ
                };

                int MipLevels;

                MipLevels = pCreateSurface->dwSCnt/6; //since all faces are always present in DX8

                DDASSERT(MipLevels>=1);

                //the first n (where n is mip depth) faces are +x, etc.
               pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= dwOrderedFaces[i/MipLevels];

                //every MipLevels'th surface is a top-level face,
                if (i % MipLevels)
                {
                    // Mark non-top levels as being a sub-level
                    pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
                }

                if (pCreateSurface->dwUsage & D3DUSAGE_DYNAMIC)
                {
                    pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_HINTDYNAMIC;
                }
            }

            break;
        case D3DRTYPE_IMAGESURFACE:
            DDASSERT(0 == (pCreateSurface->dwUsage & D3DUSAGE_DISCARD) );
            // Image surfaces are marked as textures since they have the
            // greatest flexibility for formats. But they don't get
            // a CreateSurfaceEx handle since they are never passed to
            // a driver.
            pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_TEXTURE;
            break;

        case D3DRTYPE_COMMANDBUFFER:
            DDASSERT(0 == (pCreateSurface->dwUsage & D3DUSAGE_DISCARD) );

            pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_EXECUTEBUFFER;
            pDDSurfaceMore[i].dwSurfaceHandle = GetDX7SurfaceHandle(pCreateSurface->hDD);
            DDASSERT((pCreateSurface->dwUsage & D3DUSAGE_INTERNALBUFFER) == 0);
            pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_COMMANDBUFFER;
            pDDSurfaceGlobal[i].dwLinearSize  = pDDSurfaceGlobal[i].wWidth;
            break;
        case D3DRTYPE_VERTEXBUFFER:
            DDASSERT(0 == (pCreateSurface->dwUsage & D3DUSAGE_DISCARD) );

            pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_EXECUTEBUFFER;
            if (!(pCreateSurface->dwUsage & D3DUSAGE_INTERNALBUFFER))
            {
                pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_VERTEXBUFFER;
            }
            if (pDevice->DriverLevel >= 8)
            {
                if (pCreateSurface->dwUsage & D3DUSAGE_DYNAMIC)
                {
                    pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_HINTDYNAMIC;
                }
                else
                {
                    pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_HINTSTATIC;
                }
            }
            pDDSurfaceMore[i].dwSurfaceHandle = GetDX7SurfaceHandle(pCreateSurface->hDD);
            pDDSurfaceGlobal[i].dwLinearSize  = pDDSurfaceGlobal[i].wWidth;
            break;
        case D3DRTYPE_INDEXBUFFER:
            DDASSERT(0 == (pCreateSurface->dwUsage & D3DUSAGE_DISCARD) );

            pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_EXECUTEBUFFER;
            pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_INDEXBUFFER;
            if (pDevice->DriverLevel >= 8)
            {
                if (pCreateSurface->dwUsage & D3DUSAGE_DYNAMIC)
                {
                    pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_HINTDYNAMIC;
                }
                else
                {
                    pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_HINTSTATIC;
                }
            }
            pDDSurfaceMore[i].dwSurfaceHandle = GetDX7SurfaceHandle(pCreateSurface->hDD);
            pDDSurfaceGlobal[i].dwLinearSize  = pDDSurfaceGlobal[i].wWidth;
            break;
        }

        if (pCreateSurface->dwUsage & D3DUSAGE_RENDERTARGET)
        {
            pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_3DDEVICE;
            if (pDDSurfaceMore[i].dwSurfaceHandle == 0)
            {
                pDDSurfaceMore[i].dwSurfaceHandle = GetDX7SurfaceHandle(pCreateSurface->hDD);
            }
        }
        if (pCreateSurface->dwUsage & D3DUSAGE_DEPTHSTENCIL)
        {
            pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_ZBUFFER;
        }
        if (pDevice->DriverLevel >= 8)
        {
            if (pCreateSurface->dwUsage & D3DUSAGE_LOADONCE)
            {
                pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_OPAQUE;
            }
            if (pCreateSurface->dwUsage & D3DUSAGE_WRITEONLY)
            {
                pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_WRITEONLY;
            }        
            if (!(pCreateSurface->dwUsage & D3DUSAGE_LOCK) &&
                !(pCreateSurface->dwUsage & D3DUSAGE_LOADONCE))
            {
                pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_NOTUSERLOCKABLE;
            }
            if (pCreateSurface->dwUsage & D3DUSAGE_DISCARD)
            {
                DDASSERT(pCreateSurface->Type != D3DRTYPE_TEXTURE);
                DDASSERT(pCreateSurface->Type != D3DRTYPE_CUBETEXTURE);
                DDASSERT(pCreateSurface->Type != D3DRTYPE_VOLUMETEXTURE);
                DDASSERT(pCreateSurface->Type != D3DRTYPE_VOLUME);
                DDASSERT(pCreateSurface->Type != D3DRTYPE_VERTEXBUFFER);
                DDASSERT(pCreateSurface->Type != D3DRTYPE_INDEXBUFFER);

                pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_DISCARDBACKBUFFER;
            }
            if (pCreateSurface->dwUsage & D3DUSAGE_POINTS)
            {
                pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_POINTS;
            }
            if (pCreateSurface->dwUsage & D3DUSAGE_RTPATCHES)
            {
                pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_RTPATCHES;
            }
            if (pCreateSurface->dwUsage & D3DUSAGE_NPATCHES)
            {
                pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_NPATCHES;
            }
        }
        else // Pre-DX8 driver
        {
            // We allow LOADONCE through only for textures
            if (pCreateSurface->Type == D3DRTYPE_TEXTURE || 
                pCreateSurface->Type == D3DRTYPE_CUBETEXTURE || 
                pCreateSurface->Type == D3DRTYPE_VOLUMETEXTURE)
            {
                if (pCreateSurface->dwUsage & D3DUSAGE_LOADONCE)
                {
                    pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_OPAQUE;
                }
            }
            // We allow WRITEONLY through only for VBs
            if (pCreateSurface->Type == D3DRTYPE_VERTEXBUFFER)
            {
                if (pCreateSurface->dwUsage & D3DUSAGE_WRITEONLY)
                {
                    pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_WRITEONLY;
                } 
            }
        }

        switch (pCreateSurface->Pool)
        {
        case D3DPOOL_LOCALVIDMEM:
            pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
            break;
        case D3DPOOL_NONLOCALVIDMEM:
            pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_NONLOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
            break;
        case D3DPOOL_SYSTEMMEM:
            pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
            break;
        case D3DPOOL_MANAGED:
            pDDSurfaceLocal[i].dwFlags |= DDRAWISURF_DRIVERMANAGED;
            pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
            pDDSurfaceMore[i].ddsCapsEx.dwCaps2 |= DDSCAPS2_TEXTUREMANAGE;
            break;
        case D3DPOOL_DEFAULT:
            pCreateSurface->Pool = D3DPOOL_LOCALVIDMEM; 
            pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
            break;
        default:
            /* Unknown Pool?? */
            DDASSERT(FALSE);
            break;
        }
    }
}

/*****************************Private*Routine******************************\
* SelectAttachmentSurface
*
* Returns an index into the surface creation list that indicates which
* surface this surface should be attached to. For mipmap sublevels this is
* always the preceding surface. For cubemaps, each face attaches to the
* root face (element 0).
*
* History:
*  21-Mar-2000 -by- Jeff Noyle [jeffno]
* Wrote it.
\**************************************************************************/

#undef DPF_MODNAME
#define DPF_MODNAME "SelectAttachmentSurface"

UINT SelectAttachmentSurface(
    PD3D8_CREATESURFACEDATA pCreateSurface,
    UINT                    iThis)
{

    //We should never be called to find the attachment from the root face.
    DDASSERT( iThis > 0);

    if ((pCreateSurface->Type == D3DRTYPE_CUBETEXTURE) &&
        ((iThis % (pCreateSurface->dwSCnt/6)) == 0) //which means we're looking at a top-level face
        )
    {
        //... so we attach this face to the root
        return 0;
    }
    else
    {
        // nope its just a mip sublevel, so we attach to the previous
        return iThis-1;
    }
}


/*****************************Private*Routine******************************\
* CreateVidMemSurface
*
* History:
*  06-Dec-1999 -by- Scott MacDonald [smac]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "CreateVidMemSurface"


HRESULT
CreateVidMemSurface(
    PD3D8_CREATESURFACEDATA pCreateSurface,
    DD_SURFACE_LOCAL*       pDDSurfaceLocal,
    DD_SURFACE_GLOBAL*      pDDSurfaceGlobal,
    DD_SURFACE_MORE*        pDDSurfaceMore,
    HANDLE*                 phInSurface,
    HANDLE*                 phOutSurface,
    BOOL                    bIsLost
   )
{
    DDSURFACEDESC2          SurfaceDesc;
    DD_CREATESURFACEDATA    CreateData7;
    DWORD                   i;
    DWORD                   j;
    BOOL                    bRet;
    DDSURFHANDLE*           pSurf;
    DD_CANCREATESURFACEDATA CanCreateData;
    DEFERREDCREATE*         pDefCreate;

    if (DDSCAPS_EXECUTEBUFFER & pDDSurfaceLocal[0].ddsCaps.dwCaps)
    {
        if (!(DDDEVICE_SUPPORTD3DBUF & 
            ((PDDDEVICEHANDLE)pCreateSurface->hDD)->dwFlags)
           )
        {
            return  E_FAIL;
        }
    }
    // If the device is lost, we don't want to allocate vidmem or call the
    // kernel at this point (the surface will be released soon anyway).

    if (bIsLost)
    {
DeviceLost:
        DDASSERT(pCreateSurface->bReUse == FALSE);
        for (i = 0; i < pCreateSurface->dwSCnt; i++)
        {
            pSurf = (PDDSURFHANDLE) pCreateSurface->pSList[i].hKernelHandle;
            pDDSurfaceMore[i].dwSurfaceHandle = 0;

            // There is a chance that the app may call Lock at some point,
            // in which case we have to allocate a buffer that they can write
            // to.  Allocating the buffer now is a bit wasteful, but if we
            // allocate it at Lock time the allocation may fail and I'm
            // guessing that apps will handle create surface failures better
            // than they will Lock failures, so we will do the allocation now.

            pDDSurfaceGlobal[i].lPitch = pCreateSurface->pSList[i].cpWidth * 8;
            pDDSurfaceGlobal[i].dwLinearSize =
                pDDSurfaceGlobal[i].lPitch;

            if ((pCreateSurface->Type == D3DRTYPE_VOLUME) ||
                (pCreateSurface->Type == D3DRTYPE_VOLUMETEXTURE))
            {
                pSurf->lSlicePitch = pDDSurfaceGlobal[i].lPitch *
                    pCreateSurface->pSList[i].cpHeight;

                pDDSurfaceGlobal[i].fpVidMem = (ULONG_PTR)
                    MemAlloc(pSurf->lSlicePitch *
                    pCreateSurface->pSList[i].cpDepth);
            }
            else
            {
                pDDSurfaceGlobal[i].fpVidMem = (ULONG_PTR)
                    MemAlloc(pDDSurfaceGlobal[i].lPitch *
                    pCreateSurface->pSList[i].cpHeight);
            }

            if (pDDSurfaceGlobal[i].fpVidMem == (ULONG_PTR) NULL)
            {
                for (j = 0; j < i; j++)
                {
                    MemFree((void*)pDDSurfaceGlobal[j].fpVidMem);
                }

                return E_OUTOFMEMORY;
            }
            pSurf->dwFlags |= DDSURF_SYSMEMALLOCATED;
        }

        // If the surface is driver managed, we save the creation info so that 
        // we can retry the creation at reset time
        if (pDDSurfaceLocal[0].dwFlags & DDRAWISURF_DRIVERMANAGED)
        {
            pDefCreate = (PDEFERREDCREATE)MemAlloc(sizeof(DEFERREDCREATE));
            if (pDefCreate == NULL)
            {
                // Cleanup stuff that we allocated above
                for (i = 0; i < pCreateSurface->dwSCnt; ++i)
                {
                    MemFree((void*)pDDSurfaceGlobal[i].fpVidMem);
                    pSurf = (PDDSURFHANDLE) pCreateSurface->pSList[i].hKernelHandle;
                    pSurf->dwFlags &= ~DDSURF_SYSMEMALLOCATED;
                }
                return E_OUTOFMEMORY;
            }

            // Copy
            pDefCreate->CreateData = *pCreateSurface;

            pDefCreate->CreateData.pSList = (LPDDSURFACEINFO)MemAlloc(sizeof(DDSURFACEINFO) * pCreateSurface->dwSCnt);
            if (pDefCreate->CreateData.pSList == NULL)
            {
                // Cleanup stuff that we allocated above
                MemFree(pDefCreate);
                for (i = 0; i < pCreateSurface->dwSCnt; ++i)
                {
                    MemFree((void*)pDDSurfaceGlobal[i].fpVidMem);
                    pSurf = (PDDSURFHANDLE) pCreateSurface->pSList[i].hKernelHandle;
                    pSurf->dwFlags &= ~DDSURF_SYSMEMALLOCATED;
                }
                return E_OUTOFMEMORY;
            }

            // Copy
            CopyMemory(pDefCreate->CreateData.pSList, pCreateSurface->pSList, sizeof(DDSURFACEINFO) * pCreateSurface->dwSCnt);

            // Linkup
            pDefCreate->pNext = ((PDDDEVICEHANDLE)pCreateSurface->hDD)->pDeferList;
            ((PDDDEVICEHANDLE)pCreateSurface->hDD)->pDeferList = pDefCreate;

            // We need to release the cookies allocated in InitSurfaceStructures
            // because this is not an actual create. When we do the actual create, we
            // will be reallocating the cookies.
            for (i = 0; i < pCreateSurface->dwSCnt; ++i)
            {
                pSurf = (PDDSURFHANDLE) pCreateSurface->pSList[i].hKernelHandle;
                DDASSERT(pSurf->dwCookie != 0);
                ReleaseDX7SurfaceHandle(pSurf->pDevice, pSurf->dwCookie);
                pSurf->dwCookie = 0;
            }

            // *************************MEMORY LEAK WARNING*********************** //
            // The DEFERREDCREATE and DDSURFACEINFO allocations above will
            // not be cleaned up immediately if for some reason DdCreateSurface 
            // (ie the caller of this function) fails after this function returns
            // success. As of 3/2001, DdCreateSurface has no code path that can
            // fail after we return ok below.
            // ******************************************************************* //
        }

        return S_OK;
    }

    // First setup the surface desc

    RtlZeroMemory(&SurfaceDesc, sizeof(SurfaceDesc));
    SurfaceDesc.dwSize = sizeof(SurfaceDesc);
    SurfaceDesc.ddsCaps.dwCaps = pDDSurfaceLocal[0].ddsCaps.dwCaps;
    SurfaceDesc.ddsCaps.dwCaps2 = pDDSurfaceMore[0].ddsCapsEx.dwCaps2;
    SurfaceDesc.ddsCaps.dwCaps3 = pDDSurfaceMore[0].ddsCapsEx.dwCaps3;
    SurfaceDesc.ddsCaps.dwCaps4 = pDDSurfaceMore[0].ddsCapsEx.dwCaps4;
    SurfaceDesc.ddpfPixelFormat = pDDSurfaceGlobal[0].ddpfSurface;
    if ((pCreateSurface->Type == D3DRTYPE_TEXTURE) ||
        (pCreateSurface->Type == D3DRTYPE_VOLUMETEXTURE))
    {
        SurfaceDesc.dwMipMapCount = pCreateSurface->dwSCnt;
        if (SurfaceDesc.dwMipMapCount)
        {
            SurfaceDesc.dwFlags |= DDSD_MIPMAPCOUNT;
        }
    }
    else if (pCreateSurface->Type == D3DRTYPE_CUBETEXTURE)
    {
        if (pCreateSurface->dwSCnt > 6)
        {
            SurfaceDesc.dwMipMapCount = pCreateSurface->dwSCnt / 6;
            SurfaceDesc.dwFlags |= DDSD_MIPMAPCOUNT;
        }
    }
    else if (pCreateSurface->dwSCnt > 1)
    {
        SurfaceDesc.dwBackBufferCount = pCreateSurface->dwSCnt - 1;
        SurfaceDesc.dwFlags |= DDSD_BACKBUFFERCOUNT;
    }
    SurfaceDesc.dwHeight = pDDSurfaceGlobal[0].wHeight;
    SurfaceDesc.dwWidth = pDDSurfaceGlobal[0].wWidth;
    SurfaceDesc.dwFlags |= DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
    if (pDDSurfaceLocal[0].dwFlags & DDRAWISURF_HASPIXELFORMAT)
    {
        SurfaceDesc.dwFlags |= DDSD_PIXELFORMAT;
    }
    if (pCreateSurface->Type == D3DRTYPE_VERTEXBUFFER)
    {
        SurfaceDesc.dwFVF = pCreateSurface->dwFVF;
        SurfaceDesc.dwFlags |= DDSD_FVF;
    }
    if (SurfaceDesc.ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER)
    {
        SurfaceDesc.dwLinearSize = pCreateSurface->pSList[0].iPitch;
        SurfaceDesc.dwFlags |= DDSD_LINEARSIZE;
    }
    if (SurfaceDesc.ddsCaps.dwCaps2 & DDSCAPS2_VOLUME)
    {
        SurfaceDesc.dwDepth = pCreateSurface->pSList[0].cpDepth;
        SurfaceDesc.dwFlags |= DDSD_DEPTH;
    }

    if (SurfaceDesc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
    {
        // ATI Rage3 driver in Win2K still expects dwZbufferBitDepth
        // in the old place in DDSD, so put it there but probably not
        // set the bit in dwFlags as we don't advocate it.
        ((DDSURFACEDESC*)&SurfaceDesc)->dwZBufferBitDepth =
            SurfaceDesc.ddpfPixelFormat.dwZBufferBitDepth;
    }

    // We do not support texture stage in DX8
    DDASSERT((SurfaceDesc.dwFlags & DDSD_TEXTURESTAGE) == 0);
    DDASSERT(SurfaceDesc.dwTextureStage == 0);

    // Now call CanCreateSurface since this is where most drivers do the
    // majority of their caps checking.

    RtlZeroMemory(&CanCreateData, sizeof(CanCreateData));
    CanCreateData.lpDDSurfaceDesc = (DDSURFACEDESC*) &SurfaceDesc;

    if (!FormatCompatibleWithDisplayFormat(((PDDDEVICEHANDLE)pCreateSurface->hDD), pCreateSurface->Format))
    {
        CanCreateData.bIsDifferentPixelFormat = TRUE;
    }
    else
    {
        CanCreateData.bIsDifferentPixelFormat = FALSE;
    }

    if (SurfaceDesc.ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER)
    {
        bRet = OsThunkDdCanCreateD3DBuffer(DDHANDLE(pCreateSurface->hDD),
                                    &CanCreateData);
    }
    else
    {
        bRet = OsThunkDdCanCreateSurface(DDHANDLE(pCreateSurface->hDD),
                                    &CanCreateData);
    }
    if ( bRet )
    {
        if (CanCreateData.ddRVal != S_OK)
        {
            if (CanCreateData.ddRVal == DDERR_SURFACELOST)
            {
                if (!pCreateSurface->bReUse)
                {
                    goto DeviceLost;
                }
            }
            return CanCreateData.ddRVal;
        }
    }
    /*
     * if the driver didn't handle it, then fail any requests to create a
     * surface that differs in format from the primary surface, except for
     * z buffer and alpha
     */

    else
    {
        // On Win2K, due to broken kernel, when the device is lost, the kernel
        // returns DDHAL_DRIVER_NOT_HANDLED and the return code is DDERR_GENERIC.
        // When we detect this, we check for device lost ourselves.
        if (CanCreateData.ddRVal == DDERR_GENERIC && 
            CheckForDeviceLost (pCreateSurface->hDD))
        {
            if (!pCreateSurface->bReUse)
            {
                goto DeviceLost;
            }
            return DDERR_SURFACELOST;
        }
        if (!FormatCompatibleWithDisplayFormat(((PDDDEVICEHANDLE)pCreateSurface->hDD), pCreateSurface->Format)
            && !(SurfaceDesc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER|DDSCAPS_ALPHA|DDSCAPS_EXECUTEBUFFER)) )
        {
	    return DDERR_INVALIDPIXELFORMAT;
	}
    }


    // Calculate the surface pitch.  The driver may override this, but if we
    // don't initialize it and the driver doesn't explicitly specify it, then
    // the kernel may fail the allocation.

    if (!(SurfaceDesc.ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER))
    {
        for (i = 0; i < pCreateSurface->dwSCnt; i++)
        {
            if (SurfaceDesc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
            {
                pDDSurfaceGlobal[i].lPitch = ((PDDDEVICEHANDLE)pCreateSurface->hDD)->DisplayPitch;
            }
            else if ((pDDSurfaceLocal[0].dwFlags & DDRAWISURF_HASPIXELFORMAT) &&
                     (pDDSurfaceGlobal[0].ddpfSurface.dwRGBBitCount > 0))
            {
                pDDSurfaceGlobal[i].lPitch =
                    (pDDSurfaceGlobal[0].ddpfSurface.dwRGBBitCount / 8) *
                    pDDSurfaceGlobal[i].wWidth;

                // Assume that they need to be 8 byte aligned.

                pDDSurfaceGlobal[i].lPitch += 7;
                pDDSurfaceGlobal[i].lPitch &= 0xfffffff8;
            }
        }
    }

    // If the surface requires attachments, we need to set that up before the
    // CreateSurface call.

    if (pCreateSurface->dwSCnt > 1)
    {
        // First, create all of the surface objects

        for (i = 0; i < pCreateSurface->dwSCnt; i++)
        {
            phInSurface[i] = OsThunkDdCreateSurfaceObject(DDHANDLE(pCreateSurface->hDD),
                NULL,
                &pDDSurfaceLocal[i],
                &pDDSurfaceMore[i],
                &pDDSurfaceGlobal[i],
                FALSE);
            if (phInSurface[i] == NULL)
            {
                for (j = 0; j < i; j++)
                {
                    OsThunkDdDeleteSurfaceObject(phInSurface[j]);
                }
                // Looks like we are lost or something. Check it out.
                if (CheckForDeviceLost (pCreateSurface->hDD))
                {
                    if (!pCreateSurface->bReUse)
                    {
                        goto DeviceLost;
                    }
                    return DDERR_SURFACELOST;
                }
                return E_FAIL;
            }
        }

        // Now attach them all

        for (i = 1; i < pCreateSurface->dwSCnt; i++)
        {
            bRet = OsThunkDdAttachSurface(phInSurface[SelectAttachmentSurface(pCreateSurface,i)],
                                        phInSurface[i]);

            // smac:  handle error condition
        }

        // If it's the primary surface chain, I also need to attach the back
        // to the front (to avoid potential compatibility issues).

        if (pDDSurfaceLocal[0].ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
        {
            bRet = OsThunkDdAttachSurface(phInSurface[pCreateSurface->dwSCnt - 1],
                                        phInSurface[0]);
        }
    }

    // Preset an error in case the kernel can't write status
    // back for some reason.

    CreateData7.ddRVal = E_FAIL;
    CreateData7.dwSCnt = pCreateSurface->dwSCnt;

    if (SurfaceDesc.ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER)
    {
        bRet = OsThunkDdCreateD3DBuffer(DDHANDLE(pCreateSurface->hDD),
                           phInSurface,
                          (LPDDSURFACEDESC)&SurfaceDesc,
                          pDDSurfaceGlobal,
                          pDDSurfaceLocal,
                          pDDSurfaceMore,
                          (PDD_CREATESURFACEDATA) &CreateData7,
                          phOutSurface);
    }
    else
    {
        bRet = OsThunkDdCreateSurface(DDHANDLE(pCreateSurface->hDD),
                           phInSurface,
                          (LPDDSURFACEDESC)&SurfaceDesc,
                          pDDSurfaceGlobal,
                          pDDSurfaceLocal,
                          pDDSurfaceMore,
                          (PDD_CREATESURFACEDATA) &CreateData7,
                          phOutSurface);
    }

    if ( bRet && (CreateData7.ddRVal != S_OK))
    {
        if (pCreateSurface->dwSCnt > 1)
        {
            for (i = 0; i < pCreateSurface->dwSCnt; i++)
            {
                OsThunkDdDeleteSurfaceObject(phInSurface[i]);
            }
        }
        if (CreateData7.ddRVal == DDERR_SURFACELOST)
        {
            if (!pCreateSurface->bReUse)
            {
                goto DeviceLost;
            }
        }
        // Broken Win2K kernel fails with DDERR_OUTOFVIDEOMEMORY, so handle this case
        else if ((CreateData7.ddRVal == DDERR_OUTOFVIDEOMEMORY ||
                 CreateData7.ddRVal == DDERR_GENERIC) &&
                 CheckForDeviceLost (pCreateSurface->hDD))
        {
            if (!pCreateSurface->bReUse)
            {
                goto DeviceLost;
            }
            CreateData7.ddRVal = DDERR_SURFACELOST;
        }
        return CreateData7.ddRVal;
    }

    if (pDDSurfaceLocal[0].ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM)
    {
        pCreateSurface->Pool = D3DPOOL_NONLOCALVIDMEM;
        for (i = 0; i < pCreateSurface->dwSCnt; i++)
        {
            pSurf = (PDDSURFHANDLE) pCreateSurface->pSList[i].hKernelHandle;
            pSurf->Pool = D3DPOOL_NONLOCALVIDMEM;
        }
    }

    for (i = 0; i < pCreateSurface->dwSCnt; i++)
    {
        pSurf = (PDDSURFHANDLE) pCreateSurface->pSList[i].hKernelHandle;
        pSurf->hSurface = phOutSurface[i];
    }

    return CreateData7.ddRVal;
}

/*****************************Private*Routine******************************\
* CreateSysMemSurface
*
* History:
*  06-Dec-1999 -by- Scott MacDonald [smac]
* Wrote it.
\**************************************************************************/

#undef DPF_MODNAME
#define DPF_MODNAME "CreateSysMemSurface"

HRESULT
CreateSysMemSurface(
    PD3D8_CREATESURFACEDATA pCreateSurface,
    DD_SURFACE_LOCAL*       pDDSurfaceLocal,
    DD_SURFACE_GLOBAL*      pDDSurfaceGlobal,
    DD_SURFACE_MORE*        pDDSurfaceMore,
    BOOL                    bIsLost
   )
{
    DWORD           i;
    DWORD           j;
    HRESULT         hr;
    BOOL            bRet;
    DDSURFHANDLE*   pSurf;

    hr = S_OK;
    for (i = 0; i < pCreateSurface->dwSCnt; i++)
    {
        pDDSurfaceGlobal[i].fpVidMem = (ULONG_PTR)pCreateSurface->pSList[i].pbPixels;
        pDDSurfaceGlobal[i].lPitch = pCreateSurface->pSList[i].iPitch;
        if ((pCreateSurface->Type == D3DRTYPE_VOLUME) ||
            (pCreateSurface->Type == D3DRTYPE_VOLUMETEXTURE))
        {
            pDDSurfaceGlobal[i].dwBlockSizeY = pCreateSurface->pSList[i].iSlicePitch;
        }

        // Hack for NT; they don't support FourCC codes
        if (pDDSurfaceGlobal[i].ddpfSurface.dwFlags == DDPF_FOURCC)
        {
            if (pCreateSurface->Format == D3DFMT_UYVY ||
                pCreateSurface->Format == D3DFMT_YUY2)
            {
                pDDSurfaceGlobal[i].ddpfSurface.dwRGBBitCount = 16;
                // lie about pitch
                pDDSurfaceGlobal[i].lPitch = 
                    ((pDDSurfaceGlobal[i].wWidth*2 + 7) & ~7);
            }
            else if (pCreateSurface->Format == D3DFMT_DXT1 ||
                     pCreateSurface->Format == D3DFMT_DXT2 ||
                     pCreateSurface->Format == D3DFMT_DXT3 ||
                     pCreateSurface->Format == D3DFMT_DXT4 ||
                     pCreateSurface->Format == D3DFMT_DXT5)
            {
                DWORD blksize;
                DWORD realwidth  = pDDSurfaceGlobal[i].wWidth;
                DWORD realheight = pDDSurfaceGlobal[i].wHeight;
                WORD dx, dy;

                if (pCreateSurface->Format == D3DFMT_DXT1)
                {
                    blksize = 8;
                }
                else
                {
                    blksize = 16;
                }

                // HACK STOLEN FROM DX7 DDHEL
                // <kd> used the same logic as dx7 to avoid compat pain

                // The NT bug won't let us create this surface unless we lie.
                // We have to make up a width, height, pitch, and pixel size
                // that GDI will accept as valid.
                dx = (WORD)((realwidth  + 3) >> 2);   // number of 4x4 blocks in a row
                dy = (WORD)((realheight + 3) >> 2);   // number of 4x4 blocks in a column

                pDDSurfaceGlobal[i].wHeight = dy;                    // lie about height
                pDDSurfaceGlobal[i].lPitch = dx*blksize;             // lie about pitch
                pDDSurfaceGlobal[i].wWidth = (WORD)pDDSurfaceGlobal[i].lPitch;   // lie about width
                pDDSurfaceGlobal[i].ddpfSurface.dwRGBBitCount = 8;   // lie about pixel size
            }
        }

        // The presence of a software driver can make a sysmem surface act
        // like a vidmem surface, so we need to explicitly say that it's in sysmem

        pDDSurfaceLocal[i].ddsCaps.dwCaps &=
            ~(DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM);
        pDDSurfaceLocal[i].ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;

        pSurf = (PDDSURFHANDLE) pCreateSurface->pSList[i].hKernelHandle;
        pSurf->hSurface = OsThunkDdCreateSurfaceObject(DDHANDLE(pCreateSurface->hDD),
                NULL,
                &pDDSurfaceLocal[i],
                &pDDSurfaceMore[i],
                &pDDSurfaceGlobal[i],
                TRUE);

        if (pSurf->hSurface == NULL)
        {
            // Note that the main reason for this error is actually
            // out-of-memory; but it could also point at a bug
            // somewhere between the validation logic in kernel 
            // and the validation logic in our runtime,
            DPF_ERR("Kernel failed registration of sys-mem object; out of system-memory condition");
            hr = E_OUTOFMEMORY;
        }
    }

    // If we successfully created the handles, then we create any attachments
    // that we might require.

    if (SUCCEEDED(hr))
    {
        for (i = 1; i < pCreateSurface->dwSCnt; i++)
        {
            pSurf = (PDDSURFHANDLE) pCreateSurface->pSList[i].hKernelHandle;
            bRet = OsThunkDdAttachSurface(
                ((PDDSURFHANDLE)pCreateSurface->pSList[
                        SelectAttachmentSurface(pCreateSurface,i)
                        ].hKernelHandle)->hSurface,
                    pSurf->hSurface);

            // smac:  handle error condition
        }
    }

    // If we're still OK, then we should call CreateSurfaceEx

    if (SUCCEEDED(hr))
    {
        if (pDDSurfaceMore[0].dwSurfaceHandle != 0)
        {
            // If using a software driver, we need to call CreateSurfaceEx
            // in the software driver; otherwsie, we call the kernel

            if (!IS_SOFTWARE_DRIVER(pCreateSurface->hDD))
            {
                if (bIsLost)
                {
                    // We set defer on the top level so CreateSurfaceEx gets called on Reset
                    pSurf = (PDDSURFHANDLE) pCreateSurface->pSList[0].hKernelHandle;
                    pSurf->dwFlags |= DDSURF_DEFERCREATEEX;
                    return hr;
                }            
                hr = OsThunkDdCreateSurfaceEx(
                        DDHANDLE(pCreateSurface->hDD),
                        ((PDDSURFHANDLE)pCreateSurface->pSList[0].hKernelHandle)->hSurface,
                        pDDSurfaceMore[0].dwSurfaceHandle);
                if (FAILED(hr))
                {
                    if (hr == DDERR_SURFACELOST ||
                        CheckForDeviceLost (pCreateSurface->hDD)) // Due to broken Win2K implementation
                    {
                        // We set defer on the top level so CreateSurfaceEx gets called on Reset
                        pSurf = (PDDSURFHANDLE) pCreateSurface->pSList[0].hKernelHandle;
                        pSurf->dwFlags |= DDSURF_DEFERCREATEEX;
                        return S_OK;
                    }
                }
            }
        }
    }

    return hr;
}

BOOL IsWhistler()
{
    OSVERSIONINFOEX osvi;
    DWORDLONG       dwlConditionMask = 0;

    ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
    osvi.dwMajorVersion = 5;
    osvi.dwMinorVersion = 1;

    VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, 
        VER_GREATER_EQUAL );
    VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, 
        VER_GREATER_EQUAL );

    return VerifyVersionInfo(&osvi, 
                             VER_MAJORVERSION|VER_MINORVERSION,
                             dwlConditionMask);
}
// ResetUniqueness will cause runtime to think there is a device lost,
// have to do that only for whistler when fscreen app alt-tab away to
// desktop mode that is the same as the fullscreen, whistler 
void ResetUniqueness( HANDLE hDD )
{
    PDDDEVICEHANDLE pDeviceHandle = (PDDDEVICEHANDLE) hDD;
    if (pDeviceHandle->bIsWhistler)
        pDeviceHandle->DisplayUniqueness = 0;
}
/*****************************Private*Routine******************************\
* DdCreateSurface
*
* History:
*  2-Nov-1999 -by- Scott MacDonald [smac]
* Wrote it.
\**************************************************************************/

#undef DPF_MODNAME
#define DPF_MODNAME "DdCreateSurface"

HRESULT
APIENTRY
DdCreateSurface(
    PD3D8_CREATESURFACEDATA pCreateSurface
   )
{
    ULONG                       i;
    ULONG                       j;
    DDSURFACEDESC2              SurfaceDesc;
    HANDLE                      hInSurface;
    HANDLE                      hOutSurface;
    DD_SURFACE_LOCAL            SurfaceLocal;
    DD_SURFACE_GLOBAL           SurfaceGlobal;
    DD_SURFACE_MORE             SurfaceMore;
    DD_SURFACE_LOCAL*           pDDSurfaceLocal = NULL;
    DD_SURFACE_GLOBAL*          pDDSurfaceGlobal = NULL;
    DD_SURFACE_MORE*            pDDSurfaceMore = NULL;
    HANDLE*                     phInSurface = NULL;
    HANDLE*                     phOutSurface = NULL;
    HRESULT                     hr;
    BOOL                        bSysMemCreate = FALSE;
    PDDSURFHANDLE               pSurf;
    BOOL                        bIsLost = FALSE;
    DWORD                       dwNumToCreate;
    PDDDEVICEHANDLE             pDevice = (PDDDEVICEHANDLE) pCreateSurface->hDD;

    dwNumToCreate = pCreateSurface->dwSCnt;

    // If the device is lost, we don't want to actually allocate vidmem, but
    // we still need to support sysmem surfaces.  We also have to fake up
    // vidmem allocations since we only want to expose lost devices in a
    // couple of places.

    if (CheckForDeviceLost (pCreateSurface->hDD))
    {
        bIsLost = TRUE;
        if (pCreateSurface->bReUse)
        {
            return DDERR_SURFACELOST;
        }
    }

    // For every surface, convert to the kernel's surface data structure,
    // call the kernel, then convert back:

    hr = S_OK;

    // If we are only creating one, no need to allocate gobs of memory; otherwise, do it
    if (dwNumToCreate == 1)
    {
        RtlZeroMemory(&SurfaceLocal, sizeof(SurfaceLocal));
        RtlZeroMemory(&SurfaceGlobal, sizeof(SurfaceGlobal));
        RtlZeroMemory(&SurfaceMore, sizeof(SurfaceMore));
        hInSurface = NULL;
        hOutSurface = NULL;
        pDDSurfaceLocal  = &SurfaceLocal;
        pDDSurfaceGlobal  = &SurfaceGlobal;
        pDDSurfaceMore  = &SurfaceMore;
        phInSurface = &hInSurface;
        phOutSurface = &hOutSurface;
    }
    else
    {
        pDDSurfaceLocal = (DD_SURFACE_LOCAL*) MemAlloc(
            sizeof(DD_SURFACE_LOCAL) * dwNumToCreate);

        pDDSurfaceGlobal = (DD_SURFACE_GLOBAL*) MemAlloc(
            sizeof(DD_SURFACE_GLOBAL) * dwNumToCreate);

        pDDSurfaceMore = (DD_SURFACE_MORE*) MemAlloc(
            sizeof(DD_SURFACE_MORE) * dwNumToCreate);

        phInSurface = (HANDLE*) MemAlloc(sizeof(HANDLE) * dwNumToCreate);

        phOutSurface = (HANDLE*) MemAlloc(
            sizeof(HANDLE) * dwNumToCreate);

        if ((pDDSurfaceLocal == NULL) ||
            (pDDSurfaceGlobal == NULL) ||
            (pDDSurfaceMore == NULL) ||
            (phInSurface == NULL) ||
            (phOutSurface == NULL))
        {
            hr = E_OUTOFMEMORY;
            goto CleanupCreate;
        }
    }

    InitSurfaceStructures (pCreateSurface,
        pDDSurfaceLocal,
        pDDSurfaceGlobal,
        pDDSurfaceMore);

    // Allocate the internal surface structures for each surface in the chain
    // and initialize it if we are not reusing the surface
    if (!pCreateSurface->bReUse)
    {
        for (i = 0; i < dwNumToCreate; i++)
        {
            pSurf = (PDDSURFHANDLE) MemAlloc(sizeof(DDSURFHANDLE));
            if (pSurf == NULL)
            {
                hr = E_OUTOFMEMORY;
                goto CleanupCreate;
            }
            pSurf->Pool = pCreateSurface->Pool;
            pSurf->Format = pCreateSurface->Format;
            pSurf->Type = pCreateSurface->Type;

            // This is sort of a hack to save space.  For regular surfaces, we need
            // to know the height to handle the lost case, but for volume textures,
            // we really need to know the depth.  To save space, we will re-use the
            // same variable.

            if ((pSurf->Type == D3DRTYPE_VOLUME) ||
                (pSurf->Type == D3DRTYPE_VOLUMETEXTURE))
            {
                pSurf->dwHeight = pCreateSurface->pSList[i].cpDepth;
            }
            else
            {
                pSurf->dwHeight = pCreateSurface->pSList[i].cpHeight;
            }
            pCreateSurface->pSList[i].hKernelHandle = (HANDLE) pSurf;
            pSurf->pDevice = (PDDDEVICEHANDLE) pCreateSurface->hDD;

            // You may find it wasteful that we assign handles to each mipmap level,
            // even though we only call CreateSurfaceEx on the topmost level.  We need
            // to do this, however, since DX7 worked this way and it also call
            // CreateSurfaceEx fpVidMem = 0 at release time on each level of the mipmap.

            pSurf->dwCookie = pDDSurfaceMore[i].dwSurfaceHandle;

            // Now figure out if this is a sysmem surface, a software driver
            // surface, or a HAL surface.

            if (pSurf->Pool != D3DPOOL_SYSTEMMEM)
            {
                // If they are running w/ a software driver (refrast, RGB HEL, etc.),
                // we will not allow any surfaces to be created in video memory except
                // for the primary flipping chain. And also for surfaces marked
                // USAGE_OFFSCREENPLAIN (which are used for the cursors)

                if (IS_SOFTWARE_DRIVER(pCreateSurface->hDD) &&
                    !(pCreateSurface->dwUsage & D3DUSAGE_PRIMARYSURFACE) &&
                    !(pCreateSurface->dwUsage & D3DUSAGE_OFFSCREENPLAIN))
                {
                    pSurf->dwFlags |= DDSURF_SOFTWARE;
                }
                else
                {
                    pSurf->dwFlags |= DDSURF_HAL;
                }
            }

            if (pCreateSurface->bTreatAsVidMem == TRUE)
            {
                // For objects that should be treated as non-persistent
                // i.e. Reset fails unless these are all freed; we
                // set a flag here and check it in DoVidMemSurfacesExist()
                pSurf->dwFlags |= DDSURF_TREATASVIDMEM;
            }

            // If a software driver will see this surface (either because it
            // will create it, or because it's a sysmem surface that will need
            // to handle CreateEx), we need to build a heavyweight surface structure.

            if (IS_SOFTWARE_DRIVER(pCreateSurface->hDD))
            {
                if (!(pSurf->dwFlags & DDSURF_HAL) &&
                    (pSurf->dwCookie != 0))
                {
                    pSurf->pLcl = SwDDIBuildHeavyWeightSurface(
                                    pSurf->pDevice->pDD,
                                    pCreateSurface,
                                    &pDDSurfaceLocal[i],
                                    &pDDSurfaceGlobal[i],
                                    &pDDSurfaceMore[i],
                                    i);
                    if (pSurf->pLcl == NULL)
                    {
                        hr = E_OUTOFMEMORY;
                        goto CleanupCreate;
                    }
                }
            }
        }
    }
    else // fill in the new cookie
    {
        for (i = 0; i < dwNumToCreate; i++)
        {
            pSurf = (PDDSURFHANDLE) pCreateSurface->pSList[i].hKernelHandle;
            DDASSERT(pSurf->dwCookie == 0);
            pSurf->dwCookie = pDDSurfaceMore[i].dwSurfaceHandle;
        }
    }

    // Now create the actual surfaces

    pSurf = (PDDSURFHANDLE) pCreateSurface->pSList[0].hKernelHandle;
    if (pSurf->Pool == D3DPOOL_SYSTEMMEM)
    {
        hr = CreateSysMemSurface(
                pCreateSurface,
                pDDSurfaceLocal,
                pDDSurfaceGlobal,
                pDDSurfaceMore,
                bIsLost);
    }
    else if (pSurf->dwFlags & DDSURF_SOFTWARE)
    {
        // Call the software rasterizer if it can handle it.
        // This allows them to allocate the memory, etc., but
        // we still need to call the kernel to create an object

        hr = SwDDICreateSurface(pCreateSurface,
                                pDDSurfaceLocal,
                                pDDSurfaceGlobal,
                                pDDSurfaceMore);

        // We only need to get a kernel-handle
        // for back-buffers
        
        if (SUCCEEDED(hr) && (pCreateSurface->dwUsage & D3DUSAGE_BACKBUFFER))
        {
            hr = CreateSysMemSurface(pCreateSurface,
                                     pDDSurfaceLocal,
                                     pDDSurfaceGlobal,
                                     pDDSurfaceMore,
                                     bIsLost);

            if (FAILED(hr))
            {
                // we need to mark all the surfaces
                // as completely built so that
                // we free them correctly
                for (i = 0; i < dwNumToCreate; i++)
                {
                    pSurf = (PDDSURFHANDLE) pCreateSurface->pSList[i].hKernelHandle;

                    pSurf->dwFlags |= DDSURF_CREATECOMPLETE;
                }
            }
        }
    }
    else
    {
        hr = CreateVidMemSurface (pCreateSurface,
                                  pDDSurfaceLocal,
                                  pDDSurfaceGlobal,
                                  pDDSurfaceMore,
                                  phInSurface,
                                  phOutSurface,
                                  bIsLost);
    }
    if (FAILED(hr))
    {
        goto CleanupCreate;
    }

    // Everything worked so far, so now we just need to finish up.

    for(i = 0; i < dwNumToCreate; i++)
    {
        pSurf = (PDDSURFHANDLE) pCreateSurface->pSList[i].hKernelHandle;

        pSurf->dwFlags |= DDSURF_CREATECOMPLETE;
        if (!(pSurf->dwFlags & DDSURF_HAL))
        {
            // It's a sysmem surface - either explicit or a software driver
            pSurf->fpVidMem = (ULONG_PTR)pCreateSurface->pSList[i].pbPixels;
            pSurf->dwLinearSize = pCreateSurface->pSList[i].iPitch;
            pSurf->lPitch = pCreateSurface->pSList[i].iPitch;
            pSurf->lSlicePitch = pCreateSurface->pSList[i].iSlicePitch;
        }
        else
        {
            pSurf->fpVidMem = (ULONG_PTR)pDDSurfaceGlobal[i].fpVidMem;
            pSurf->dwLinearSize = pDDSurfaceGlobal[i].dwLinearSize;
            pCreateSurface->pSList[i].iPitch = pSurf->dwLinearSize;
            pSurf->lPitch = pDDSurfaceGlobal[i].lPitch;
            if ((pSurf->Type == D3DRTYPE_VOLUME) ||
                (pSurf->Type == D3DRTYPE_VOLUMETEXTURE))
            {
                pSurf->lSlicePitch = pDDSurfaceGlobal[i].dwBlockSizeY;
            }
            else
            {
                pSurf->lSlicePitch = 0;
            }
        }

        // If it's a software driver, we may need to attach surfaces

        if ((0==(pSurf->dwFlags & DDSURF_HAL)) &&
            (IS_SOFTWARE_DRIVER(pCreateSurface->hDD)) &&
            (i > 0))
        {
            // Cubes are created strangely... Each face is attached to the root,
            // and each mipsublevel is attached to its face

            DDASSERT(pCreateSurface->Type != D3DRTYPE_CUBETEXTURE || pCreateSurface->dwSCnt>=6);

            SwDDIAttachSurfaces (
                    ((PDDSURFHANDLE)pCreateSurface->pSList[
                            SelectAttachmentSurface(pCreateSurface,i)
                        ].hKernelHandle)->pLcl,
                    pSurf->pLcl);
        }
    }

    // If it's a software driver, we need to call CreateSurfaceEx after
    // all of the attachments are made.

    if ((IS_SOFTWARE_DRIVER(pCreateSurface->hDD)) &&
        (pSurf->dwCookie != 0))
    {
        SwDDICreateSurfaceEx (pDevice->pDD,
            ((PDDSURFHANDLE)pCreateSurface->pSList[0].hKernelHandle)->pLcl);
    }

    // Now save the surfaces in a linked list
    // If re-using, then we are already on the list so don't do anything
    if (!pCreateSurface->bReUse)
    {
        for (i = 0; i < dwNumToCreate; i++)
        {
            ((PDDSURFHANDLE)(pCreateSurface->pSList[i].hKernelHandle))->pNext =
                pDevice->pSurfList;
            ((PDDSURFHANDLE)(pCreateSurface->pSList[i].hKernelHandle))->pPrevious =
                NULL;
            if (pDevice->pSurfList != NULL)
            {
                pDevice->pSurfList->pPrevious = (PDDSURFHANDLE)(pCreateSurface->pSList[i].hKernelHandle);
            }
            pDevice->pSurfList = (PDDSURFHANDLE)(pCreateSurface->pSList[i].hKernelHandle);
        }
    }

    CleanupCreate:
    if (1 != dwNumToCreate)
    {
        if (pDDSurfaceLocal != NULL)
        {
            MemFree(pDDSurfaceLocal);
        }
        if (pDDSurfaceGlobal != NULL)
        {
            MemFree(pDDSurfaceGlobal);
        }
        if (pDDSurfaceMore != NULL)
        {
            MemFree(pDDSurfaceMore);
        }
        if (phInSurface != NULL)
        {
            MemFree(phInSurface);
        }
        if (phOutSurface != NULL)
        {
            MemFree(phOutSurface);
        }
    }

    if (FAILED(hr))
    {
        // Clean everything up

        for (i = 0; i < dwNumToCreate; i++)
        {
            pSurf = (PDDSURFHANDLE) pCreateSurface->pSList[i].hKernelHandle;
            if (pSurf != NULL)
            {
                FreeSurfaceObject(pSurf);
                // If we are reusing, then we need to keep the pSurf around
                // for a retry
                if (!pCreateSurface->bReUse)
                {
                    MemFree(pSurf);
                }
            }
            pCreateSurface->pSList[i].hKernelHandle   = NULL;
        }
    }

    return(MapLegacyResult(hr));
}


/******************************Public*Routine******************************\
*
* D3dContextCreate
*
* History:
*  Mon Jun 03 14:18:29 1996     -by-    Drew Bliss [drewb]
*   Created
*
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3dContextCreate"

DWORD WINAPI 
D3dContextCreate(PD3D8_CONTEXTCREATEDATA pCreateContext)
{
    PD3DCONTEXTHANDLE   pContext = NULL;
    BOOL                bIsLost = FALSE;
    DWORD               dwRet = DDHAL_DRIVER_HANDLED;

    // Don't call the driver if the device is lost

    pCreateContext->ddrval = S_OK;
    if (!CheckForDeviceLost (pCreateContext->hDD))
    {
        dwRet = OsThunkD3dContextCreate(DDHANDLE(pCreateContext->hDD),
            GetSurfHandle(pCreateContext->hSurface),
            GetSurfHandle(pCreateContext->hDDSZ),
            (D3DNTHAL_CONTEXTCREATEI *)pCreateContext);
        if (pCreateContext->ddrval == DDERR_SURFACELOST)
        {
            bIsLost = TRUE;
            pCreateContext->ddrval = S_OK;
            CheckForDeviceLost (pCreateContext->hDD);
        }
    }
    else
    {
        bIsLost = TRUE;
    }

    // We need to abstract the handle for a couple of reasons:
    // 1.  The context handle can change due to lost devices, and
    //     we'd prefer to abstract this from D3D.
    // 2.  We need to know the device that this handle belongs to
    //     so we can always check for device lost.

    if (pCreateContext->ddrval == S_OK)
    {
        pContext = (PD3DCONTEXTHANDLE) MemAlloc(sizeof(D3DCONTEXTHANDLE));
        if (pContext == NULL)
        {
            // smac: clean up

            pCreateContext->dwhContext = (ULONG_PTR) NULL;
            pCreateContext->ddrval = E_OUTOFMEMORY;
        }
        else
        {
            pContext->pDevice = pCreateContext->hDD;
            if (bIsLost)
            {
                pContext->dwFlags = D3DCONTEXT_DEFERCREATE;
                pContext->dwPID = pCreateContext->dwPID;
                pContext->hDeferHandle = (HANDLE)pCreateContext->dwhContext;
                pContext->pSurface = pCreateContext->hSurface;
                pContext->pDDSZ = pCreateContext->hDDSZ;
            }
            else
            {
                pContext->dwhContext = (HANDLE) pCreateContext->dwhContext;
            }
            pCreateContext->dwhContext = (ULONG_PTR) pContext;
        }
    }

    pCreateContext->ddrval = MapLegacyResult(pCreateContext->ddrval);

    return dwRet;
}

/******************************Public*Routine******************************\
*
* D3dContextDestroy
*
* History:
*  Mon Jun 03 14:18:29 1996     -by-    Drew Bliss [drewb]
*   Created
*
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3dContextDestroy"

DWORD WINAPI 
D3dContextDestroy(PD3D8_CONTEXTDESTROYDATA pDestroyContext)
{
    PD3DCONTEXTHANDLE pContext = (PD3DCONTEXTHANDLE) pDestroyContext->dwhContext;

    CheckForDeviceLost (pContext->pDevice);

    pDestroyContext->ddrval = S_OK;
    if (pContext->dwhContext)
    {
        pDestroyContext->dwhContext = (LONG_PTR) pContext->dwhContext;
        OsThunkD3dContextDestroy((LPD3DNTHAL_CONTEXTDESTROYDATA) pDestroyContext);
    }

    pContext->pDevice->pContext = NULL;
    MemFree(pContext);

    pDestroyContext->ddrval = MapLegacyResult(pDestroyContext->ddrval);

    return DDHAL_DRIVER_HANDLED;
}

/******************************Public*Routine******************************\
*
* D3dContextDestroyAll
*
* History:
*  Mon Jun 03 14:18:29 1996     -by-    Drew Bliss [drewb]
*   Created
*
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3dContextDestroyAll"

DWORD WINAPI 
D3dContextDestroyAll(PD3D8_CONTEXTDESTROYALLDATA pDestroyAllContext)
{
    OsThunkD3dContextDestroyAll((LPD3DNTHAL_CONTEXTDESTROYALLDATA) pDestroyAllContext);

    // smac:  Need to add code here to free all contexts for each device
    // the PID has?

    return DDHAL_DRIVER_HANDLED;
}

/******************************Public*Routine******************************\
*
* DdGetDriverState
*
* History:
*  Mon Jun 03 14:18:29 1996     -by-    Drew Bliss [drewb]
*   Created
*
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "DdGetDriverState"

DWORD WINAPI DdGetDriverState(PD3D8_GETDRIVERSTATEDATA pGetDriverState)
{
    PD3DCONTEXTHANDLE pContext = (PD3DCONTEXTHANDLE) pGetDriverState->dwhContext;
    DWORD       dwRet = DDHAL_DRIVER_HANDLED;
    ULONG_PTR   pTemp;

    pGetDriverState->ddRVal = E_FAIL;
    if (!CheckForDeviceLost (pContext->pDevice))
    {
        pTemp = pGetDriverState->dwhContext;
        pGetDriverState->dwhContext = (ULONG_PTR) pContext->dwhContext;
        dwRet = OsThunkDdGetDriverState ((DD_GETDRIVERSTATEDATA*)pGetDriverState);
        pGetDriverState->dwhContext = pTemp;
        if (pGetDriverState->ddRVal == DDERR_SURFACELOST)
        {
            pGetDriverState->ddRVal = E_FAIL;
        }
    }

    pGetDriverState->ddRVal = MapLegacyResult(pGetDriverState->ddRVal);

    return dwRet;
}

/******************************Public*Routine******************************\
*
* D3dValidateTextureStageState
*
* History:
*  Mon Jun 03 14:18:29 1996     -by-    Drew Bliss [drewb]
*   Created
*
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3dValidateTextureStageState"

DWORD WINAPI D3dValidateTextureStageState(PD3D8_VALIDATETEXTURESTAGESTATEDATA pValidate)
{
    PD3DCONTEXTHANDLE pContext = (PD3DCONTEXTHANDLE) pValidate->dwhContext;
    DWORD       dwRet = DDHAL_DRIVER_HANDLED;
    ULONG_PTR   pTemp;

    pValidate->ddrval = D3DERR_DEVICELOST;
    pValidate->dwNumPasses = 0;
    if (!CheckForDeviceLost (pContext->pDevice))
    {
        pTemp = pValidate->dwhContext;
        pValidate->dwhContext = (ULONG_PTR) pContext->dwhContext;
        dwRet = OsThunkD3dValidateTextureStageState((D3DNTHAL_VALIDATETEXTURESTAGESTATEDATA*)pValidate);
        pValidate->dwhContext = pTemp;
        if (pValidate->ddrval == DDERR_SURFACELOST)
        {
            pValidate->ddrval = D3DERR_DEVICELOST;
        }
    }

    return dwRet;
}

/******************************Public*Routine******************************\
*
* D3dDrawPrimitives2
*
* History:
*  Mon Jun 17 13:27:05 1996     -by-    Anantha Kancherla [anankan]
*   Created
*
\**************************************************************************/

#undef DPF_MODNAME
#define DPF_MODNAME "D3dDrawPrimitives2"

DWORD WINAPI D3dDrawPrimitives2(PD3D8_DRAWPRIMITIVES2DATA pdp2data)
{
    PD3DCONTEXTHANDLE pContext = (PD3DCONTEXTHANDLE) pdp2data->dwhContext;
    DWORD       dwRet = DDHAL_DRIVER_HANDLED;
    ULONG_PTR   pTemp;

    if (CheckForDeviceLost (pContext->pDevice))
    {
        goto DeviceLost;
    }

    pTemp = pdp2data->dwhContext;
    pdp2data->dwhContext = (ULONG_PTR) pContext->dwhContext;

    if (pdp2data->dwFlags & D3DHALDP2_USERMEMVERTICES)
    {
        dwRet = OsThunkD3dDrawPrimitives2 (
            GetSurfHandle(pdp2data->hDDCommands),
            NULL, // No DDraw surface, pass NULL handle
            (LPD3DNTHAL_DRAWPRIMITIVES2DATA)pdp2data,
            &((PDDSURFHANDLE)(pdp2data->hDDCommands))->fpVidMem,
            &((PDDSURFHANDLE)(pdp2data->hDDCommands))->dwLinearSize,
            NULL,
            NULL
           );
        if (dwRet == DDHAL_DRIVER_HANDLED)
        {
            if (pdp2data->ddrval == DDERR_SURFACELOST)
            {
                pdp2data->dwhContext = pTemp;
                goto DeviceLost;
            }
            else if ((pdp2data->ddrval != S_OK) && 
                (DDERR_WASSTILLDRAWING != pdp2data->ddrval) )
            {
                pContext->pDevice->dwFlags |= DDDEVICE_DP2ERROR;
            }
        }
        pdp2data->fpVidMem_CB = ((PDDSURFHANDLE)(pdp2data->hDDCommands))->fpVidMem;
        pdp2data->dwLinearSize_CB = ((PDDSURFHANDLE)(pdp2data->hDDCommands))->dwLinearSize;
        pdp2data->fpVidMem_VB = 0;
        pdp2data->dwLinearSize_VB = 0;
    }
    else
    {
        dwRet = OsThunkD3dDrawPrimitives2 (
            GetSurfHandle(pdp2data->hDDCommands),
            GetSurfHandle(pdp2data->hDDVertex),
            (LPD3DNTHAL_DRAWPRIMITIVES2DATA)pdp2data,
            &((PDDSURFHANDLE)(pdp2data->hDDCommands))->fpVidMem,
            &((PDDSURFHANDLE)(pdp2data->hDDCommands))->dwLinearSize,
            &((PDDSURFHANDLE)(pdp2data->hDDVertex))->fpVidMem,
            &((PDDSURFHANDLE)(pdp2data->hDDVertex))->dwLinearSize
            );
        if (dwRet == DDHAL_DRIVER_HANDLED)
        {
            if (pdp2data->ddrval == DDERR_SURFACELOST)
            {
                pdp2data->dwhContext = pTemp;
                goto DeviceLost;
            }
            else if ((pdp2data->ddrval != S_OK) &&
                (DDERR_WASSTILLDRAWING != pdp2data->ddrval) )
            {
                pContext->pDevice->dwFlags |= DDDEVICE_DP2ERROR;
            }
        }

        pdp2data->fpVidMem_CB = ((PDDSURFHANDLE)(pdp2data->hDDCommands))->fpVidMem;
        pdp2data->dwLinearSize_CB = ((PDDSURFHANDLE)(pdp2data->hDDCommands))->dwLinearSize;
        pdp2data->fpVidMem_VB = ((PDDSURFHANDLE)(pdp2data->hDDVertex))->fpVidMem;
        pdp2data->dwLinearSize_VB = ((PDDSURFHANDLE)(pdp2data->hDDVertex))->dwLinearSize;
    }
    pdp2data->dwhContext = pTemp;

    return dwRet;

DeviceLost:
    pdp2data->ddrval = S_OK;
    pdp2data->dwErrorOffset = 0;

    // Need to set these values to their original
    // state so that the FE doesn't get confused.
    pdp2data->fpVidMem_CB = ((PDDSURFHANDLE)(pdp2data->hDDCommands))->fpVidMem;
    pdp2data->dwLinearSize_CB = ((PDDSURFHANDLE)(pdp2data->hDDCommands))->dwLinearSize;
    if (pdp2data->dwFlags & D3DHALDP2_USERMEMVERTICES)
    {
        pdp2data->fpVidMem_VB       = 0;
        pdp2data->dwLinearSize_VB   = 0;
    }
    else
    {
        pdp2data->fpVidMem_VB = ((PDDSURFHANDLE)(pdp2data->hDDVertex))->fpVidMem;
        pdp2data->dwLinearSize_VB = ((PDDSURFHANDLE)(pdp2data->hDDVertex))->dwLinearSize;
    }

    // Don't map the legacy result because the runtime needs to handle the
    // WASSTILLDRAWING case.  The runtime will do this mapping for us.

    return DDHAL_DRIVER_HANDLED;
}

LPRGNDATA GetClipList(HWND hWnd)
{
    int APIENTRY GetRandomRgn(HDC hdc, HRGN hrgn, int iNum);
    int rc;
    HRESULT         ddrval = S_OK;
    DWORD           dwSize;
    DWORD           cbRealSize;
    HDC             hdc;
    HRGN            hrgn;
    LPRGNDATA       lpClipList;

    hdc = GetDC(hWnd);
    if (hdc == NULL)
    {
        DPF_ERR("GetDC failed. Unable to accelerate Present.");
        return NULL;
    }

    // Create the appropriate Region object
    hrgn = CreateRectRgn(0, 0, 0, 0);
    if (hrgn == NULL)
    {
        DPF_ERR("CreateRectRgn failed. Unable to accelerate Present.");
        ReleaseDC(hWnd, hdc);
        return NULL;
    }

    // Set the Region to the DC
    if (-1 == GetRandomRgn(hdc, hrgn, 4))
    {
        DPF_ERR("GetRandomRgn failed. Unable to accelerate Present.");
        ReleaseDC(hWnd, hdc);
        DeleteObject(hrgn);
        return NULL;
    }

    // Get the size
    dwSize = GetRegionData(hrgn, 0, NULL);

    if (0 == dwSize)
    {
        // Release allocations
        ReleaseDC(hWnd, hdc);
        DeleteObject(hrgn);
        return NULL;
    }
    do
    {
        lpClipList = (LPRGNDATA)MemAlloc(dwSize);
        if (NULL == lpClipList)
        {
            // Release allocations
            ReleaseDC(hWnd, hdc);
            DeleteObject(hrgn);
            return NULL;
        }
        // Get the window's region's REGIONDATA
        cbRealSize = GetRegionData(hrgn, dwSize, lpClipList);
        if (cbRealSize > dwSize)
        {
            MemFree(lpClipList);
            dwSize =  cbRealSize;   // make it bigger and try again
        }
        else
        {
            break;  // succeeded
        }
    }while(TRUE);

    ReleaseDC(hWnd, hdc);
    DeleteObject(hrgn);

    if (cbRealSize == 0)
    {
        DPF_ERR("GetRegionData failed. Unable to accelerate Present.");
        MemFree(lpClipList);
        return NULL;
    }
    return  lpClipList;
}

/*
 * ClipRgnToRect
 */
void ClipRgnToRect(LPRECT prect, LPRGNDATA prd)
{
    RECT        rect;
    int         i;
    int         n;
    LPRECTL     prectlD;
    LPRECTL     prectlS;


    if (prect == NULL || prd == NULL)
    {
        return;
    }

    // If the bounding rect of the region is exactly equal to
    // or inside of the Restricting rect then we know
    // we don't have to do any more work.
    //
    // In the common case, the rcBound will be the client
    // area of a window and so will the restricting rect.
    if (prect->top    <= prd->rdh.rcBound.top &&
        prect->bottom >= prd->rdh.rcBound.bottom &&
        prect->left   <= prd->rdh.rcBound.left &&
        prect->right  >= prd->rdh.rcBound.right)
    {
        return;
    }

    // If the bounding rect doesn't equal the prect then
    // we might have to do some clipping.
    rect = *prect;

    prectlD = (LPRECTL) prd->Buffer;
    prectlS = (LPRECTL) prd->Buffer;
    n = (int)prd->rdh.nCount;

    for (i=0; i<n; i++)
    {
        prectlD->left  = max(prectlS->left, rect.left);
        prectlD->right = min(prectlS->right, rect.right);
        prectlD->top   = max(prectlS->top, rect.top);
        prectlD->bottom= min(prectlS->bottom, rect.bottom);

        prectlS++;

        if ((prectlD->bottom - prectlD->top <= 0) ||
            (prectlD->right - prectlD->left <= 0))
        {
            prd->rdh.nCount--;  // dont count empty rect.
        }
        else
        {
            prectlD++;
        }
    }

    return;

} /* ClipRgnToRect */

/*
 * XformRect
 *
 * Transform a clipped rect in destination space to the corresponding clipped
 * rect in src space. So, if we're stretching from src to dest, this yields
 * the unstretched clipping rect in src space.
 *
 *  PARAMETERS:
 *      prcSrc - unclipped rect in the source space
 *      prcDest - unclipped rect in the destination space
 *      prcClippedDest - the rect we want to transform
 *      prcClippedSrc - the resulting rect in the source space.  return value.
 *      scale_x - 16.16 fixed point src/dest width ratio
 *      scale_y  - 16.16 fixed point src/dest height ratio
 *
 *  DESCRIPTION:
 *      Given an rect in source space and a rect in destination space, and a
 *      clipped rectangle in the destination space (prcClippedDest), return
 *      the rectangle in the source space (prcClippedSrc) that maps to
 *      prcClippedDest.
 *
 *      Use 16.16 fixed point math for more accuracy. (Shift left, do math,
 *      shift back (w/ round))
 *
 *  RETURNS:
 *      S_OK always.  prcClippedSrc is the mapped rectangle.
 *
 */
HRESULT XformRect(RECT * prcSrc, RECT * prcDest, RECT * prcClippedDest,
                  RECT * prcClippedSrc, DWORD scale_x, DWORD scale_y)
{
    /*
     * This first calculation is done with fixed point arithmetic (16.16).
     * The result is converted to (32.0) below. Scale back into source space
     */
    prcClippedSrc->left = (prcClippedDest->left - prcDest->left) * scale_x;
    prcClippedSrc->right = (prcClippedDest->right - prcDest->left) * scale_x;
    prcClippedSrc->top = (prcClippedDest->top - prcDest->top) * scale_y;
    prcClippedSrc->bottom = (prcClippedDest->bottom - prcDest->top) * scale_y;

    /*
     * now round (adding 0x8000 rounds) and translate (offset by the
     * src offset)
     */
    prcClippedSrc->left = (((DWORD)prcClippedSrc->left + 0x8000) >> 16) + prcSrc->left;
    prcClippedSrc->right = (((DWORD)prcClippedSrc->right + 0x8000) >> 16) + prcSrc->left;
    prcClippedSrc->top = (((DWORD)prcClippedSrc->top + 0x8000) >> 16) + prcSrc->top;
    prcClippedSrc->bottom = (((DWORD)prcClippedSrc->bottom + 0x8000) >> 16) + prcSrc->top;

    /*
     * Check for zero-sized source rect dimensions and bump if necessary
     */
    if (prcClippedSrc->left == prcClippedSrc->right)
    {
        if (prcClippedSrc->right == prcSrc->right)
        {
            (prcClippedSrc->left)--;
        }
        else
        {
            (prcClippedSrc->right)++;
        }

    }
    if (prcClippedSrc->top == prcClippedSrc->bottom)
    {
        if (prcClippedSrc->bottom == prcSrc->bottom)
        {
            (prcClippedSrc->top)--;
        }
        else
        {
            (prcClippedSrc->bottom)++;
        }

    }

    return S_OK;

} /* XformRect */

/*****************************Private*Routine******************************\
* DdBlt
*
* History:
*  3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
* 31-Mar-2000 -by- Kan Qiu [kanqiu]
* Made it handle clipping case
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "DdBlt"
#define SIZE_OF_A_CLIPLIST(lpRgn) \
        (sizeof(RGNDATAHEADER)+sizeof(RECTL)*lpRgn->rdh.nCount)

DWORD
WINAPI
DdBlt(
    PD3D8_BLTDATA pBlt
   )
{
    DDHAL_BLTDATA   bd;
    DWORD       ret = DDHAL_DRIVER_NOTHANDLED;
    PDDSURFHANDLE   pDstSurf = (PDDSURFHANDLE) pBlt->hDestSurface;
    PDDSURFHANDLE   pSrcSurf = (PDDSURFHANDLE) pBlt->hSrcSurface;
    PDDDEVICEHANDLE pDevice = (PDDDEVICEHANDLE) pBlt->hDD;
    DWORD   bltcaps;
    if (CheckForDeviceLost (pBlt->hDD))
    {
        // Some blts should fail, others should succeed:
        // persistant -> non persitant : OK
        // persistant -> persitant : FAIL
        // non persistant -> persistant : FAIL
        // non persistant -> non persistant : OK

        if (pDstSurf && ((pDstSurf->Pool == D3DPOOL_LOCALVIDMEM) ||
            (pDstSurf->Pool == D3DPOOL_NONLOCALVIDMEM))
           )
        {
            pBlt->ddRVal = S_OK;
        }
        else
        {
            pBlt->ddRVal = D3DERR_DEVICELOST;
        }
        return DDHAL_DRIVER_HANDLED;
    }
    ZeroMemory(&bd, sizeof bd);
    bd.ddRVal      = E_FAIL;  // always assume error

    // Just a colorfill?
#ifdef DEBUG
    if ((pSrcSurf == NULL) && pDstSurf)
    {
        do
        {
            bd.dwFlags     = pBlt->dwFlags & DDBLT_VALID;
            bd.IsClipped   = FALSE; // NT Kernel cannot handle it
            bd.bltFX       = pBlt->bltFX;
            bd.rDest       = pBlt->rDest;

            ret = OsThunkDdBlt(GetSurfHandle(pBlt->hDestSurface),
                       0,
                       (PDD_BLTDATA) &bd);
        
            if (DDHAL_DRIVER_NOTHANDLED == ret)
            {
                DPF_ERR("Driver failed color-fill blt. SWAPEFFECT_DISCARD not being enforced.");
            }
        } while (bd.ddRVal == DDERR_WASSTILLDRAWING);
 
        return S_OK;
    }
#endif 

    // Are we going to send this blt to the driver?
    if (!pDstSurf)
    {
        // NULL destination ? we are running SW driver w/o ddraw support
        // use GDI for blting
        goto gdiblt;                    
    }
    else if (IS_SOFTWARE_DRIVER_SURFACE(pSrcSurf))
    {
        if (!(pDevice->DDCaps & DDCAPS_CANBLTSYSMEM))
            goto gdiblt;            
        bltcaps = pDevice->SVBCaps;
    }
    else
    {
        bltcaps = pDevice->DDCaps;
    }
    if (!(bltcaps & DDCAPS_BLT))
        goto gdiblt;            
    
    //it is assumed that the format for a presented back buffer is OK and has
    //been validated by higher layers of the runtime. (e.g. if the back
    //buffer has alpha, or in the future is very different from front buffer format)
    if ((pDstSurf->Format == pSrcSurf->Format) ||
        (pBlt->dwFlags & DDBLT_WINDOWCLIP) ) //which means this is a presentation blt
    {
        //Yes, we're going to the driver...
        bd.rDest       = pBlt->rDest;
        bd.rSrc        = pBlt->rSrc;
        bd.dwFlags     = pBlt->dwFlags & DDBLT_VALID;
        bd.dwROPFlags  = pBlt->dwROPFlags;
        bd.IsClipped   = FALSE; // NT Kernel cannot handle it
        bd.bltFX       = pBlt->bltFX;

        // This is for Window Redirection support
        // (available on post-Windows 2000)
        // On Windows 2000, bd.Blt is ignored by win32k.sys
        if (pBlt->dwFlags & DDBLT_WINDOWCLIP)
        {
           bd.Blt      = (VOID*)(pBlt->hWnd);
        }

        // Mask DX8 flags from the OS
        if (pBlt->dwFlags & DDBLT_DX8ORHIGHER)
        {
            bd.dwFlags &= ~(DDBLT_WINDOWCLIP | DDBLT_COPYVSYNC | DDBLT_DX8ORHIGHER);
        }

        DPF(10,"pBlt->rDest %08lx %08lx %08lx %08lx",
            pBlt->rDest.top, pBlt->rDest.bottom,
            pBlt->rDest.left, pBlt->rDest.right);
        if ((pBlt->hWnd) && (DDBLT_WINDOWCLIP & pBlt->dwFlags))
        {
            RECTL   rOrigSrc=pBlt->rSrc;   // unclipped src rect
            LONG    SrcWidth = rOrigSrc.right - rOrigSrc.left;
            LONG    SrcHeight = rOrigSrc.bottom - rOrigSrc.top;
            RECT    rOrigDest;
            do
            {
                LPRGNDATA   prd;
                LPRECT      prect;
                DWORD       cnt;
                if (GetClientRect(pBlt->hWnd, &rOrigDest))
                {
                    POINT   pOrigDest;
                    if (rOrigDest.right > pBlt->rDest.right)
                        rOrigDest.right = pBlt->rDest.right;
                    if (rOrigDest.bottom > pBlt->rDest.bottom)
                        rOrigDest.bottom = pBlt->rDest.bottom;
                    if (0 < pBlt->rDest.left)
                        rOrigDest.left = pBlt->rDest.left;
                    if (0 < pBlt->rDest.top)
                        rOrigDest.top = pBlt->rDest.top;
                    if ((rOrigDest.right <= rOrigDest.left) ||
                        (rOrigDest.bottom <= rOrigDest.top)
                       )
                    {
                        pBlt->ddRVal = S_OK;
                        return DDHAL_DRIVER_HANDLED;
                    }
                        
                    pOrigDest.x = - pDevice->rcMonitor.left;
                    pOrigDest.y = - pDevice->rcMonitor.top;
                    if (!ClientToScreen(pBlt->hWnd, &pOrigDest))
                        DPF_ERR("ClientToScreen Failed on pOrigDest?");
                    if (!OffsetRect(&rOrigDest, pOrigDest.x, pOrigDest.y ))
                        DPF_ERR("OffsetRect Failed on rOrigDest?");
                    if (rOrigDest.bottom <= 0 || rOrigDest.right <= 0 ||
                        (rOrigDest.top + pDevice->rcMonitor.top >= pDevice->rcMonitor.bottom) ||
                        (rOrigDest.left + pDevice->rcMonitor.left >= pDevice->rcMonitor.right))
                    {
                        // client is completely outside device space
                        // means cross device blt is needed
                        goto gdiblt;
                    }
                }
                else
                {
                    DPF_ERR("GetClientRect Failed ?");
                    goto gdiblt;
                }
                if (   ( NULL == pDevice->pClipList ) 
                    || ( NULL == pDevice->pOrigClipList )
                    || ( pDevice->hLastWnd != pBlt->hWnd )
                    || (DDERR_VISRGNCHANGED == bd.ddRVal))
                {
                    DWORD   dwClipListSize;
                    if ( NULL != pDevice->pClipList )
                    {
                        MemFree(pDevice->pClipList);
                        pDevice->pClipList = NULL;
                    }    
                    if ( NULL != pDevice->pOrigClipList )
                    {
                        MemFree(pDevice->pOrigClipList);
                        pDevice->pOrigClipList = NULL;
                    }    
                    prd = GetClipList(pBlt->hWnd);
                    if (NULL == prd)
                        goto gdiblt;
                
                    prect=(LPRECT) &prd->Buffer[0];
                    for (cnt=0; cnt<prd->rdh.nCount; cnt++)
                    {
                        if ((prect[cnt].top < pDevice->rcMonitor.top) ||
                            (prect[cnt].left < pDevice->rcMonitor.left) ||
                            (prect[cnt].bottom > pDevice->rcMonitor.bottom) ||
                            (prect[cnt].right > pDevice->rcMonitor.right)
                          )
                        {
                            // do GDI blt if any rect is outside
                            MemFree (prd);
                            goto gdiblt;
                        }
                        if (!OffsetRect( &prect[cnt], - pDevice->rcMonitor.left, 
                            - pDevice->rcMonitor.top ))
                            DPF_ERR("OffsetRect Failed on prect[cnt]?");
                    }
                    dwClipListSize = SIZE_OF_A_CLIPLIST(prd);
                    pDevice->pOrigClipList = (LPRGNDATA)MemAlloc(dwClipListSize);
                    if (NULL != pDevice->pOrigClipList)
                    {
                        memcpy(pDevice->pOrigClipList, prd, dwClipListSize);
                        pDevice->hLastWnd = pBlt->hWnd;
                    }                
                }
                else
                {                    
                    prd = pDevice->pClipList;
                    memcpy(prd, pDevice->pOrigClipList,
                        SIZE_OF_A_CLIPLIST(pDevice->pOrigClipList));
                }
                DDASSERT( (0 == pDevice->pClipList) || ( prd == pDevice->pClipList) );
                DDASSERT( NULL != prd );

                // Clip the region to the rect before we go further
                ClipRgnToRect(&rOrigDest, prd );

                // Process each visible sub-rect separately
                if (prd->rdh.nCount > 0)
                {
                    int         x_offset;
                    int         y_offset;
                    DWORD       scale_x;
                    DWORD       scale_y;
                    BOOL        stretch_blt;
                    pDevice->pClipList = prd;

                    // precalculate a couple of variables
                    if ((rOrigDest.bottom - rOrigDest.top == SrcHeight) &&
                        (rOrigDest.right - rOrigDest.left == SrcWidth))
                    {
                        x_offset = rOrigSrc.left - rOrigDest.left;
                        y_offset = rOrigSrc.top - rOrigDest.top;
                        stretch_blt = FALSE;
                    }
                    else
                    {
                        if (!(bltcaps & DDCAPS_BLTSTRETCH))
                            goto gdiblt;
                        // scale_x and scale_y are fixed point variables scaled
                        // 16.16 (16 integer bits and 16 fractional bits)
                        scale_x = (SrcWidth << 16) /
                            (rOrigDest.right - rOrigDest.left);
                        scale_y = (SrcHeight << 16) /
                            (rOrigDest.bottom - rOrigDest.top);
                        stretch_blt = TRUE;
                    }

                    if (DDBLT_COPYVSYNC & pBlt->dwFlags)
                    {
                        DD_GETSCANLINEDATA   ScanData;
                        DWORD                msStartTime = GetTickCount();
                        DWORD                msCurrentTime;
                        DWORD                threshold=pBlt->threshold;

                        // Compute how many milliseconds there
                        // are per refresh. We round down.
                        msCurrentTime = msStartTime;                

                        // If the previous blt was just a few ms ago
                        // then we can make up the difference by yielding
                        if ((msCurrentTime - pBlt->msLastPresent) < threshold )
                        {
                            Sleep(threshold + pBlt->msLastPresent - msCurrentTime);
                            msCurrentTime = pBlt->msLastPresent + threshold;
                        }

                        threshold = ((PDDSURFHANDLE)pBlt->hDestSurface)->dwHeight/2;
                        while (DDHAL_DRIVER_HANDLED == 
                            OsThunkDdGetScanLine(DDHANDLE(pBlt->hDD),&ScanData))
                        {
                            if (DD_OK != ScanData.ddRVal)
                                break;

                            if ((LONG)ScanData.dwScanLine >= rOrigDest.bottom)
                                break;
                        
                            if ((LONG)(ScanData.dwScanLine + threshold/3) < rOrigDest.top)
                                break;

                            // just yield 1 ms instead of doing lengthy calculation which
                            // does not get me better result
                            if ((LONG)(ScanData.dwScanLine + threshold) < rOrigDest.bottom)
                            {
                                Sleep(1);
                            }
                            // If we've been spinning here for 30ms
                            // then blt anyway; probably something
                            // running in the background taking
                            // up CPU cycles
                            msCurrentTime = GetTickCount();
                            if ((msCurrentTime - msStartTime) > 30)
                            {
                                break;
                            }
                        }

                        // Remember the time of last blt
                        pBlt->msLastPresent = msCurrentTime;
                    }
                    //traverse the visible rect list and send each piece to
                    //the driver to blit
                    prect=(LPRECT) &prd->Buffer[0];

                    for (cnt=0;cnt<prd->rdh.nCount;cnt++)
                    {

                        // find out where on the src rect we need to get
                        // the data from.

                        bd.rDest.left = prect[cnt].left;
                        bd.rDest.right = prect[cnt].right;
                        bd.rDest.top = prect[cnt].top;
                        bd.rDest.bottom = prect[cnt].bottom;
                        if (!stretch_blt)
                        {
                            // no stretch
                            // one-to-one mapping from source to destination
                            bd.rSrc.left = bd.rDest.left + x_offset;
                            bd.rSrc.right = bd.rDest.right + x_offset;
                            bd.rSrc.top = bd.rDest.top + y_offset;
                            bd.rSrc.bottom = bd.rDest.bottom + y_offset;
                        }
                        else
                        {
                            // stretching
                            // linear mapping from source to destination
                            // calculate the source rect which transforms to the
                            // dest rect
                            XformRect((RECT *)&(rOrigSrc), &rOrigDest,
                                (RECT *)&(bd.rDest), (RECT *)&(bd.rSrc),
                                scale_x, scale_y);
                        }

                        // If mirror Blt, we must fix up source rect here!
                        if (bd.dwFlags & DDBLT_DDFX)
                        {
                            int temp;

                            if (bd.bltFX.dwDDFX & DDBLTFX_MIRRORLEFTRIGHT)
                            {
                                temp = bd.rSrc.left;
                                bd.rSrc.left = rOrigSrc.left +
                                    rOrigSrc.right - bd.rSrc.right;
                                bd.rSrc.right = rOrigSrc.left +
                                    rOrigSrc.right - temp;
                            }

                            if (bd.bltFX.dwDDFX & DDBLTFX_MIRRORUPDOWN)
                            {
                                temp = bd.rSrc.top;
                                bd.rSrc.top = rOrigSrc.top +
                                    rOrigSrc.bottom - bd.rSrc.bottom;
                                bd.rSrc.bottom = rOrigSrc.top +
                                    rOrigSrc.bottom - temp;
                            }
                        }

                        do
                        {
                            bd.ddRVal = E_FAIL;  // always assume error

                            if (bd.dwFlags & DDBLT_PRESENTATION)
                            {
                                if (cnt == prd->rdh.nCount-1)
                                {
                                    bd.dwFlags |= DDBLT_LAST_PRESENTATION;
                                }
                            }

                            ret = OsThunkDdBlt(GetSurfHandle(pBlt->hDestSurface),
                                       GetSurfHandle(pBlt->hSrcSurface),
                                       (PDD_BLTDATA) &bd);
                            if (DDHAL_DRIVER_NOTHANDLED == ret)
                            {
                                bd.ddRVal = E_FAIL;  // make it out of loop
                                break;
                            }
                            if (bd.ddRVal == DDERR_SURFACELOST)
                            {
                                bd.ddRVal = S_OK;
                                break;
                            }

                            /*
                             * NOTE: If clipping has introduced more than
                             * one rectangle we behave as if DDBLT_WAIT
                             * was specified on all rectangles after the
                             * first. This is necessary as the first
                             * rectangle will probably cause the accelerator
                             * to be busy. Hence, the attempt to blit the
                             * second rectangle will fail with
                             * DDERR_WASSTILLDRAWING. If we pass this to
                             * the application (rather than busy waiting)
                             * the application is likely to retry the blit
                             * (which will fail on the second rectangle again)
                             * and we have an application sitting in an
                             * infinite loop).
                             */
                        } while(  (DDERR_WASSTILLDRAWING == bd.ddRVal) &&
                                  ( (DDBLT_WAIT & pBlt->dwFlags) ||
                                    (1 < prd->rdh.nCount)
                                  )
                               );
                        if (FAILED(bd.ddRVal))
                            break;
                    }
                }
                else
                {
                    MemFree (prd);
                    pDevice->pClipList = NULL;
                    bd.ddRVal = S_OK;
                    ret = DDHAL_DRIVER_HANDLED;
                    break;  // all clipped, no need to blt!
                }
                if (DDERR_VISRGNCHANGED == bd.ddRVal)
                {
                    OsThunkDdResetVisrgn(GetSurfHandle(pBlt->hDestSurface),(HWND)0);
                    pDevice->hLastWnd = NULL;   // zero cached info for DdBlt
                }
            } while (DDERR_VISRGNCHANGED == bd.ddRVal);
        }
        else
        {
            DDASSERT( 0 == (bd.dwFlags & DDBLT_PRESENTATION));
            if ((bd.rDest.right - bd.rDest.left != bd.rSrc.right - bd.rSrc.left || 
                 bd.rDest.bottom - bd.rDest.top != bd.rSrc.bottom - bd.rSrc.top)
                 && !(bltcaps & DDCAPS_BLTSTRETCH)
               )
                goto gdiblt;

            do
            {
                bd.ddRVal = E_FAIL;  // always assume error
                ret = OsThunkDdBlt(GetSurfHandle(pBlt->hDestSurface),
                           GetSurfHandle(pBlt->hSrcSurface),
                           (PDD_BLTDATA) &bd);
                if (DDHAL_DRIVER_NOTHANDLED == ret)
                {
                    bd.ddRVal = E_FAIL;  // make it out of loop
                    break;
                }
                if (bd.ddRVal == DDERR_SURFACELOST)
                {
                    bd.ddRVal = S_OK;
                }
                if (DDERR_VISRGNCHANGED == bd.ddRVal)
                {
                    OsThunkDdResetVisrgn(GetSurfHandle(pBlt->hDestSurface),(HWND)0);
                    pDevice->hLastWnd = NULL;   // zero cached info for DdBlt
                }
            } while ( (DDERR_VISRGNCHANGED == bd.ddRVal) ||
                      ( (DDERR_WASSTILLDRAWING == bd.ddRVal) &&
                        (DDBLT_WAIT & pBlt->dwFlags)
                      )
                    );
        }
    }

gdiblt:
    if (FAILED(bd.ddRVal))
    {
        // !!! Just use GetDC on the DirectDraw surface for now, though this is
        // probably way too slow on drivers which do not support derived
        // surfaces. DirectDraw Blt support should be added soon.
        HDC hDCTarget;
        BOOL    bGetDCfromWnd = (pBlt->hWnd) && 
                    ((DDBLT_WINDOWCLIP & pBlt->dwFlags) || !pBlt->hDestSurface);
        if (bGetDCfromWnd)
            hDCTarget = GetDC(pBlt->hWnd);
        else
            hDCTarget = D3D8GetDC(pBlt->hDestSurface, NULL);
        if (hDCTarget != NULL)
        {
            HDC hDCSource = D3D8GetDC(pBlt->hSrcSurface, NULL);
            if (hDCSource != NULL)
            {
                LONG DestWidth=pBlt->rDest.right - pBlt->rDest.left;
                LONG DestHeight= pBlt->rDest.bottom - pBlt->rDest.top;
                LONG SrcWidth= pBlt->rSrc.right - pBlt->rSrc.left;
                LONG SrcHeight= pBlt->rSrc.bottom - pBlt->rSrc.top;
                if (DestWidth == SrcWidth && DestHeight == SrcHeight)
                {
                    if (BitBlt(
                        hDCTarget,
                        pBlt->rDest.left,
                        pBlt->rDest.top,
                        DestWidth,
                        DestHeight,
                        hDCSource,
                        pBlt->rSrc.left,
                        pBlt->rSrc.top,
                        SRCCOPY))
                    {
                        bd.ddRVal = S_OK;
                        ret = DDHAL_DRIVER_HANDLED;
                    }
                }
                else
                {
                    // COLORONCOLOR is not the default in NT
                    int saved = SetStretchBltMode(hDCTarget,COLORONCOLOR);
                    if (StretchBlt(
                        hDCTarget,
                        pBlt->rDest.left,
                        pBlt->rDest.top,
                        DestWidth,
                        DestHeight,
                        hDCSource,
                        pBlt->rSrc.left,
                        pBlt->rSrc.top,
                        SrcWidth,
                        SrcHeight,
                        SRCCOPY))
                    {
                        bd.ddRVal = S_OK;
                        ret = DDHAL_DRIVER_HANDLED;
                    }
                    // restore to previous mode
                    if (saved)
                        SetStretchBltMode(hDCTarget,saved);
                }
                D3D8ReleaseDC(pBlt->hSrcSurface, hDCSource);
            }
            if (bGetDCfromWnd)
                ReleaseDC(pBlt->hWnd, hDCTarget);
            else
                D3D8ReleaseDC(pBlt->hDestSurface, hDCTarget);
        }        
    }

    pBlt->ddRVal = MapLegacyResult(bd.ddRVal);

    // We only want to report DP2 errors  during the present call because
    // checking for it everywhere is too hard.
    if ((pBlt->ddRVal == DD_OK) &&
        (pDevice->dwFlags & DDDEVICE_DP2ERROR) &&
        (pBlt->dwFlags & DDBLT_WINDOWCLIP))
    {
        pDevice->dwFlags &= ~DDDEVICE_DP2ERROR;

        // We use a special error here to mean that the blt succeeded
        // but that that some DP2 failed since the last present
        pBlt->ddRVal = D3DERR_DEFERRED_DP2ERROR;
    }

    return ret;
}

/*****************************Private*Routine******************************\
* DdFlip
*
* History:
*  3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "DdFlip"

DWORD
APIENTRY
DdFlip(
    PD3D8_FLIPDATA pFlip
   )
{
    HANDLE          hSurfTargLeft=NULL;
    HANDLE          hSurfCurrLeft=NULL;
    DDHAL_FLIPDATA  FlipData;
    DWORD           dwRet;

    if (CheckForDeviceLost (pFlip->hDD))
    {
        pFlip->ddRVal = S_OK;
        return DDHAL_DRIVER_HANDLED;
    }

    FlipData.dwFlags = (pFlip->dwFlags  & ~DDFLIP_WAIT);
    FlipData.ddRVal = DDERR_GENERIC;
    if (pFlip->dwFlags & DDFLIP_STEREO)
    {
        hSurfTargLeft = GetSurfHandle(pFlip->hSurfTargLeft);
        hSurfCurrLeft = GetSurfHandle(pFlip->hSurfCurrLeft);
    }
    do
    {
        dwRet = OsThunkDdFlip(GetSurfHandle(pFlip->hSurfCurr),
                       GetSurfHandle(pFlip->hSurfTarg),
                       hSurfCurrLeft,
                       hSurfTargLeft,
                       (PDD_FLIPDATA) &FlipData);
        if (FlipData.ddRVal == DDERR_SURFACELOST)
        {
            FlipData.ddRVal = S_OK;
        }
    }while (DDERR_WASSTILLDRAWING == FlipData.ddRVal &&
        (DDFLIP_WAIT & pFlip->dwFlags));
    pFlip->ddRVal = MapLegacyResult(FlipData.ddRVal);

    // We only want to report DP2 errors  during the present call because
    // checking for it everywhere is too hard.
    if ((pFlip->ddRVal == DD_OK) &&
        (((DDDEVICEHANDLE*)pFlip->hDD)->dwFlags & DDDEVICE_DP2ERROR))
    {
        ((DDDEVICEHANDLE*)pFlip->hDD)->dwFlags &= ~DDDEVICE_DP2ERROR;

        // We use a special error here to mean that the flip succeeded
        // but that that some DP2 failed since the last present
        pFlip->ddRVal = D3DERR_DEFERRED_DP2ERROR;
    }

    return dwRet;
}

/*****************************Private*Routine******************************\
* DdLock
*
* History:
*  3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "DdLock"

HRESULT
APIENTRY
DdLock(
    PD3D8_LOCKDATA pLock
   )
{
    DD_LOCKDATA     LockData;
    PDDSURFHANDLE   pSurf;
    BOOL            bAdjustSlice = FALSE;

    pSurf = (PDDSURFHANDLE) pLock->hSurface;

    // If the device is lost, we need to fake up a buffer for
    // the app to write to.  We still allow software drivers
    // handle the Lock call, however. Further, we also allow
    // driver managed surfaces to go through.

    if (CheckForDeviceLost (pLock->hDD) &&
        !IS_SOFTWARE_DRIVER_SURFACE(pSurf) &&
        pSurf->Pool != D3DPOOL_MANAGED)
    {
        goto DeviceLost;
    }

    // We do make an exception for fake deferred creates
    // of driver managed surfaces. The driver doesn't know
    // about these deferred surfaces, so we don't call it.
    // ASSUMPTIONS: even if DDSURF_SYSMEMALLOCATED can be
    // set below, we expect it to be never set below for
    // **driver managed surfaces**. For these surfaces, we
    // assume that it will be set only in 
    // CreateVidMemSurface. This assumption is true as of
    // 3/2001.

    if ((pSurf->dwFlags & DDSURF_SYSMEMALLOCATED) != 0)
    {
        DDASSERT(pSurf->fpVidMem != (ULONG_PTR)NULL);
        goto DeviceLost;
    }

    // Mask off new flags
    LockData.dwFlags  = pLock->dwFlags;
    LockData.dwFlags &= (D3DLOCK_READONLY         |
                         D3DLOCK_DISCARD          |   
                         D3DLOCK_NOOVERWRITE      |
                         D3DLOCK_NOSYSLOCK);       
    // Always set lock_wait
    LockData.dwFlags |= DDLOCK_WAIT;
    // Also set equivalent DDLOCK flag for NO_DIRTY_UPDATE
    // if the driver understands it
    if ((pLock->dwFlags & D3DLOCK_NO_DIRTY_UPDATE) != 0)
    {
        LockData.dwFlags |= DDLOCK_NODIRTYUPDATE;
    }

    if(pLock->bHasRange)
    {
        LockData.bHasRect = TRUE;
        LockData.rArea.left = 0;
        LockData.rArea.right = 0;
        LockData.rArea.top = pLock->range.Offset;
        LockData.rArea.bottom = pLock->range.Offset + pLock->range.Size;
    }
    else
    {
        LockData.bHasRect = pLock->bHasRect;
        LockData.rArea = pLock->rArea;
    }

    if (pLock->bHasBox)
    {
        LockData.bHasRect = TRUE;
        LockData.rArea.left = pLock->box.Left;
        LockData.rArea.right = pLock->box.Right;
        LockData.rArea.top = pLock->box.Top;
        LockData.rArea.bottom = pLock->box.Bottom;

        // We cannot change the kernel for an OS before whistler, so we will
        // not pass the front/back to the driver.  For ref and for newer OSes,
        // we will stick the front/back into the high word of left/right

        if (IS_SOFTWARE_DRIVER_SURFACE(pSurf) ||
            ((((PDDDEVICEHANDLE)pLock->hDD)->bIsWhistler) &&
             (((PDDDEVICEHANDLE)pLock->hDD)->dwFlags & DDDEVICE_SUPPORTSUBVOLUMELOCK)))
        {
            LockData.dwFlags |= DDLOCK_HASVOLUMETEXTUREBOXRECT;
            LockData.rArea.left |= (pLock->box.Front << 16);
            LockData.rArea.right |= (pLock->box.Back << 16);
        }
        else
        {
            bAdjustSlice = TRUE;
        }
    }

    LockData.ddRVal = DDERR_WASSTILLDRAWING;

    if (IS_SOFTWARE_DRIVER_SURFACE(pSurf))
    {
        // This is a software driver, so we need to treat
        // it specially

        SwDDILock (pLock->hDD, pSurf, &LockData);
    }
    else
    {
        while ((LockData.ddRVal == DDERR_VISRGNCHANGED) ||
            (LockData.ddRVal == DDERR_WASSTILLDRAWING))
        {
            if ((pSurf->Type == D3DRTYPE_VERTEXBUFFER) ||
                (pSurf->Type == D3DRTYPE_COMMANDBUFFER)||
                (pSurf->Type == D3DRTYPE_INDEXBUFFER))
            {
                OsThunkDdLockD3D(pSurf->hSurface,
                                 &LockData);
            }
            else
            {
                OsThunkDdLock(pSurf->hSurface,
                                &LockData,
                                NULL);
            }

            if (LockData.ddRVal == DDERR_VISRGNCHANGED)
            {
                if (pLock->dwFlags & DDLOCK_FAILONVISRGNCHANGED)
                {
                    break;
                }
                else
                {
                    PDDDEVICEHANDLE pDevice = (PDDDEVICEHANDLE) pLock->hDD;
                    OsThunkDdResetVisrgn(pSurf->hSurface, (HWND)0);
                    pDevice->hLastWnd = NULL;   // zero cached info for DdBlt
                }
            }

            // In the past we would require DDLOCK_WAIT to
            // decide if we would spin or exit now we always wait
        }
        if (LockData.ddRVal == DDERR_SURFACELOST)
        {
            CheckForDeviceLost(pLock->hDD);
            goto DeviceLost;
        }
    }

    if (LockData.ddRVal == S_OK)
    {
        pLock->lpSurfData = LockData.lpSurfData;
        pLock->lPitch = pSurf->lPitch;

        if ((pSurf->Type == D3DRTYPE_VOLUME) ||
            (pSurf->Type == D3DRTYPE_VOLUMETEXTURE))
        {
            pLock->lSlicePitch = pSurf->lSlicePitch;

            if (bAdjustSlice)
            {
                ((BYTE*)pLock->lpSurfData) += (pLock->lSlicePitch * 
                                                pLock->box.Front);
            }
        }
        pSurf->LockRefCnt++;
    }

    return MapLegacyResult(LockData.ddRVal);

DeviceLost:
    // At the time the device is lost, fpVidMem is set to NULL
    // for all vidmem surfaces.  Therefore, if it is non-NULL
    // we are safe to use what we already have; otherwise, we
    // have to allocate our own.

    if (pSurf->fpVidMem == (ULONG_PTR) NULL)
    {
        if ((pSurf->Type == D3DRTYPE_VOLUME) ||
            (pSurf->Type == D3DRTYPE_VOLUMETEXTURE))
        {
            // For volume textures, dwHeight really contains the depth
            pSurf->fpVidMem = (ULONG_PTR) MemAlloc(pSurf->lSlicePitch * pSurf->dwHeight);
        }
        else
        {
            pSurf->fpVidMem = (ULONG_PTR) MemAlloc(pSurf->lPitch * pSurf->dwHeight);
        }
        if (pSurf->fpVidMem == (ULONG_PTR) NULL)
        {
            pLock->lpSurfData = (void*)pSurf->fpVidMem;
            return E_FAIL;
        }
        pSurf->dwFlags |= DDSURF_SYSMEMALLOCATED;
    }
    pLock->lpSurfData = (void*)pSurf->fpVidMem;
    pLock->lPitch = pSurf->lPitch;

    if ((pSurf->Type == D3DRTYPE_VOLUME) ||
        (pSurf->Type == D3DRTYPE_VOLUMETEXTURE))
    {
        pLock->lSlicePitch = pSurf->lSlicePitch;
    }
    pSurf->LockRefCnt++;

    return S_OK;
}

/*****************************Private*Routine******************************\
* DdUnlock
*
* History:
*  3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "DdUnlock"

HRESULT
APIENTRY
DdUnlock(
    PD3D8_UNLOCKDATA pUnlock
   )
{
    DD_UNLOCKDATA   UnlockData;
    PDDSURFHANDLE   pSurf;

    pSurf = (PDDSURFHANDLE) pUnlock->hSurface;

    if (pSurf->LockRefCnt > 0)
    {
        pSurf->LockRefCnt--;
    }
    if (CheckForDeviceLost (pUnlock->hDD) &&
        !IS_SOFTWARE_DRIVER_SURFACE(pSurf) &&
        pSurf->Pool != D3DPOOL_MANAGED)
    {
        return S_OK;
    }
    if ((pSurf->dwFlags & DDSURF_SYSMEMALLOCATED) != 0)
    {
        DDASSERT(pSurf->fpVidMem != (ULONG_PTR)NULL);
        return S_OK;
    }

    if (IS_SOFTWARE_DRIVER_SURFACE(pSurf))
    {
        // This is a software driver, so we need to treat
        // it specially

        SwDDIUnlock (pUnlock->hDD, pSurf, &UnlockData);
    }
    else
    {
        if ((GetSurfType(pUnlock->hSurface) == D3DRTYPE_VERTEXBUFFER) ||
            (GetSurfType(pUnlock->hSurface) == D3DRTYPE_COMMANDBUFFER) ||
            (GetSurfType(pUnlock->hSurface) == D3DRTYPE_INDEXBUFFER))
        {
            OsThunkDdUnlockD3D(GetSurfHandle(pUnlock->hSurface),
                             &UnlockData);
        }
        else
        {
            OsThunkDdUnlock(GetSurfHandle(pUnlock->hSurface),
                          &UnlockData);
        }
        if (UnlockData.ddRVal == DDERR_SURFACELOST)
        {
            UnlockData.ddRVal = S_OK;
        }
    }
    return MapLegacyResult(UnlockData.ddRVal);
}

/*****************************Private*Routine******************************\
* DdGetBltStatus
*
* History:
*  3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "DdGetBltStatus"

DWORD
APIENTRY
DdGetBltStatus(
    PD3D8_GETBLTSTATUSDATA pGetBltStatus
   )
{
    DDHAL_GETBLTSTATUSDATA  StatusData;
    DWORD dwRet;

    if (CheckForDeviceLost (pGetBltStatus->hDD))
    {
        pGetBltStatus->ddRVal = S_OK;
        return DDHAL_DRIVER_HANDLED;
    }

    StatusData.dwFlags = pGetBltStatus->dwFlags;
    dwRet = OsThunkDdGetBltStatus(GetSurfHandle(pGetBltStatus->hSurface),
                               (PDD_GETBLTSTATUSDATA) &StatusData);
    
    if (StatusData.ddRVal == DDERR_SURFACELOST)
    {
        StatusData.ddRVal = S_OK;
    }

    pGetBltStatus->ddRVal = MapLegacyResult(StatusData.ddRVal);

    return dwRet;
}

/*****************************Private*Routine******************************\
* DdGetFlipStatus
*
* History:
*  3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "DdGetFlipStatus"

DWORD
APIENTRY
DdGetFlipStatus(
    PD3D8_GETFLIPSTATUSDATA pGetFlipStatus
   )
{
    DDHAL_GETFLIPSTATUSDATA StatusData;
    DWORD dwRet;

    if (CheckForDeviceLost (pGetFlipStatus->hDD))
    {
        pGetFlipStatus->ddRVal = S_OK;
        return DDHAL_DRIVER_HANDLED;
    }

    StatusData.dwFlags = pGetFlipStatus->dwFlags;

    dwRet = OsThunkDdGetFlipStatus(GetSurfHandle(pGetFlipStatus->hSurface),
                                   (PDD_GETFLIPSTATUSDATA) &StatusData);

    if (StatusData.ddRVal == DDERR_SURFACELOST)
    {
        StatusData.ddRVal = S_OK;
    }

    pGetFlipStatus->ddRVal = MapLegacyResult(StatusData.ddRVal);

    return dwRet;
}

/*****************************Private*Routine******************************\
* DdWaitForVerticalBlank
*
* History:
*  3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "DdWaitForVerticalBlank"

DWORD
APIENTRY
DdWaitForVerticalBlank(
    PD3D8_WAITFORVERTICALBLANKDATA pWaitForVerticalBlank
   )
{
    DDHAL_WAITFORVERTICALBLANKDATA WaitData;
    DWORD dwRet;

    if (CheckForDeviceLost (pWaitForVerticalBlank->hDD))
    {
        goto DeviceLost;
    }

    WaitData.dwFlags    = pWaitForVerticalBlank->dwFlags;
    WaitData.hEvent     = 0;

    dwRet = OsThunkDdWaitForVerticalBlank(DDHANDLE(pWaitForVerticalBlank->hDD),
                (PDD_WAITFORVERTICALBLANKDATA) &WaitData);

    if (WaitData.ddRVal == DDERR_SURFACELOST)
    {
        goto DeviceLost;
    }

    pWaitForVerticalBlank->bIsInVB  = WaitData.bIsInVB;
    pWaitForVerticalBlank->ddRVal   = WaitData.ddRVal;

    if (WaitData.ddRVal == DDERR_VERTICALBLANKINPROGRESS)
    {
        pWaitForVerticalBlank->bIsInVB = TRUE;                   
    }
    else
    {
        pWaitForVerticalBlank->bIsInVB = FALSE;                   
    }
    pWaitForVerticalBlank->ddRVal = DD_OK;

    return dwRet;

DeviceLost:
    {
        static int LostTestVerticalBlank;

        pWaitForVerticalBlank->ddRVal = DD_OK;
        if (pWaitForVerticalBlank->dwFlags == DDWAITVB_I_TESTVB)
        {
            if (LostTestVerticalBlank > 0)
            {
                pWaitForVerticalBlank->bIsInVB = TRUE;
            }
            else
            {
                pWaitForVerticalBlank->bIsInVB = FALSE;
            }
            LostTestVerticalBlank = LostTestVerticalBlank == 0 ? 1 : 0;
        }
        else if (pWaitForVerticalBlank->dwFlags == DDWAITVB_BLOCKEND)
        {
            pWaitForVerticalBlank->bIsInVB = FALSE;
        }
        else
        {
            pWaitForVerticalBlank->bIsInVB = TRUE;
        }
    }
    return DDHAL_DRIVER_HANDLED;
}

/*****************************Private*Routine******************************\
* DdDestroySurface
*
* History:
*  3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "DdDestroySurface"

DWORD
APIENTRY
DdDestroySurface(
    PD3D8_DESTROYSURFACEDATA pDestroySurface
   )
{
    DWORD i;
    PDDSURFHANDLE pSurf = (PDDSURFHANDLE) pDestroySurface->hSurface;
    PDDDEVICEHANDLE pDevice = (PDDDEVICEHANDLE) pDestroySurface->hDD;
    PDEFERREDCREATE pDefCreate = pDevice->pDeferList;

    FreeSurfaceObject(pSurf);

    // Remove the surface from the linked list

    if (pDevice->pSurfList == pSurf)
    {
        pDevice->pSurfList = pSurf->pNext;
        if (pSurf->pNext != NULL)
        {
            pSurf->pNext->pPrevious = NULL;
        }
    }
    else
    {
        if (pSurf->pNext != NULL)
        {
            pSurf->pNext->pPrevious = pSurf->pPrevious;
        }
        pSurf->pPrevious->pNext = pSurf->pNext;
    }

    // If we allcoated the memory for this surface (due to a lost state),
    // then we should free it now.

    if (pSurf->dwFlags & DDSURF_SYSMEMALLOCATED)
    {
        MemFree((void*) pSurf->fpVidMem);
    }

    // If this surface pointer is cached in the context structure, we need
    // to remedy that.

    if (pSurf->pDevice->pContext != NULL)
    {
        if (pSurf->pDevice->pContext->pSurface == pSurf)
        {
            pSurf->pDevice->pContext->pSurface = NULL;
        }
        if (pSurf->pDevice->pContext->pDDSZ == pSurf)
        {
            pSurf->pDevice->pContext->pDDSZ = NULL;
        }
    }

    MemFree (pSurf);

    // We look in the defer list to see if any referenced surface
    // is being destroyed. If this is the case, then we need to
    // update the defer list and mark the surfaces as freed so
    // that we don't try and resurrect destroyed surfaces. Although
    // this appears slow, it is not too bad because a deferred list
    // will be present only if a mode switch happened. In this case,
    // it doesn't hurt if things are a little slow.

    while (pDefCreate != NULL)
    {
        for (i = 0; i < pDefCreate->CreateData.dwSCnt; i++)
        {
            if (pSurf == (PDDSURFHANDLE) pDefCreate->CreateData.pSList[i].hKernelHandle)
            {
                pDefCreate->CreateData.pSList[i].hKernelHandle = 0;
                break;
            }
        }
        pDefCreate = pDefCreate->pNext;
    }

    return (DDHAL_DRIVER_HANDLED);
}

#undef DPF_MODNAME
#define DPF_MODNAME "D3D8GetMode"

DWORD
APIENTRY
D3D8GetMode(
    HANDLE          Handle,
    char*           pDeviceName,
    D3DDISPLAYMODE* pMode,
    D3DFORMAT       Unknown16)
{
    DEVMODE     dm;
    HDC         hdc;

    memset (&dm, 0, sizeof(dm));
    dm.dmSize = sizeof(dm);
    if (EnumDisplaySettings(pDeviceName, ENUM_CURRENT_SETTINGS, &dm))
    {
        pMode->Width        = dm.dmPelsWidth;
        pMode->Height       = dm.dmPelsHeight;
        pMode->RefreshRate  = dm.dmDisplayFrequency;

        switch (dm.dmBitsPerPel)
        {
        case 8:
            pMode->Format = D3DFMT_P8;
            break;

        case 24:
            pMode->Format = D3DFMT_R8G8B8;
            break;

        case 32:
            pMode->Format = D3DFMT_X8R8G8B8;
            break;

        case 15:
        case 16:
            pMode->Format = D3DFMT_R5G6B5;
            hdc = DD_CreateDC(pDeviceName);
            if (hdc)
            {
                HBITMAP hbm;
                BITMAPINFO *pbmi;
                DWORD *pdwColors;

                if (pbmi = (BITMAPINFO*) MemAlloc(3 * sizeof (RGBQUAD) + sizeof (BITMAPINFO)))
                {
                    if (hbm = CreateCompatibleBitmap(hdc, 1, 1))
                    {
                        pbmi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);

                        if (GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS))
                        {
                            if (pbmi->bmiHeader.biCompression == BI_BITFIELDS)
                            {
                                GetDIBits(hdc, hbm, 0, pbmi->bmiHeader.biHeight,
                                    NULL, pbmi, DIB_RGB_COLORS);

                                pdwColors = (DWORD *) &pbmi->bmiColors[0];
                                if (pdwColors[1] == 0x3e0)
                                {
                                    pMode->Format = D3DFMT_X1R5G5B5;
                                }
                            }
                        }
                        DeleteObject(hbm);
                    }
                    MemFree(pbmi);
                }
                DD_DoneDC(hdc);
            }
            break;

        default:
            pMode->Format = D3DFMT_UNKNOWN;
            break;
        }
        return S_OK;
    }

    // I don't know in which cases we would ever hit this
    return D3DERR_DRIVERINTERNALERROR;
}

#undef DPF_MODNAME
#define DPF_MODNAME "D3D8SetMode"

DWORD
APIENTRY
D3D8SetMode(
    HANDLE          Handle,
    char*           pDeviceName,
    UINT            Width,
    UINT            Height,
    UINT            BPP,
    UINT            RefreshRate,
    BOOL            bRestore)
{
    HANDLE h = GetModuleHandle("USER32");
    LONG (WINAPI *pfnChangeDisplaySettingsExA)(LPCSTR,LPDEVMODEA,HWND,DWORD,LPVOID);
    DEVMODE dm, * pdm;
    PDDDEVICEHANDLE pDevice = (PDDDEVICEHANDLE) Handle;

    // Init the devmode properly:

    dm.dmSize               = sizeof(DEVMODE);
    EnumDisplaySettings (pDeviceName,0,&dm);

    dm.dmBitsPerPel         = BPP;
    dm.dmPelsWidth          = Width;
    dm.dmPelsHeight         = Height;
    dm.dmDisplayFrequency   = RefreshRate;
    dm.dmDisplayFlags       = 0;
    dm.dmFields             = DM_BITSPERPEL |
                              DM_PELSWIDTH |
                              DM_PELSHEIGHT |
                              DM_DISPLAYFREQUENCY;

    // Now tell the OS to do the mode change

    (FARPROC)pfnChangeDisplaySettingsExA = GetProcAddress(h,"ChangeDisplaySettingsExA");
    if (pfnChangeDisplaySettingsExA)
    {
        InformDriverToDeferFrees(pDevice);
        if (bRestore)
        {
            if ((*pfnChangeDisplaySettingsExA)(pDeviceName,
                NULL, NULL, CDS_FULLSCREEN, 0) == DISP_CHANGE_SUCCESSFUL)
            {
                return S_OK;
            }
        }
        else
        {
            if ((*pfnChangeDisplaySettingsExA)(pDeviceName,
                &dm, NULL, CDS_FULLSCREEN, 0) == DISP_CHANGE_SUCCESSFUL)
            {
                return S_OK;
            }
        }
        if (NumReadyDevices == NumDevices)
        {
            InformDriverFreeAGP(pDevice);
        }
    }

    return D3DERR_DRIVERINTERNALERROR;
}

/*****************************Private*Routine******************************\
* DdSetMode
*
* History:
*  29-Nov-1999 -by- Scott MacDonald [smac]
* Wrote it.
\**************************************************************************/

#undef DPF_MODNAME
#define DPF_MODNAME "DdSetMode"

DWORD
APIENTRY
DdSetMode(
    PD3D8_SETMODEDATA pSetMode
   )
{
    UINT    BPP;
    PDDDEVICEHANDLE pDeviceHandle = (PDDDEVICEHANDLE) pSetMode->hDD;

    // smac: How should lost devices behave?
    CheckForDeviceLost(pSetMode->hDD);

    pSetMode->ddRVal = D3DERR_DRIVERINTERNALERROR;

    switch (pSetMode->Format)
    {
    case D3DFMT_P8:
        BPP = 8;
        break;

    case D3DFMT_R5G6B5:
    case D3DFMT_X1R5G5B5:
        BPP = 16;
        break;

    case D3DFMT_R8G8B8:
        BPP = 24;
        break;

    case D3DFMT_A8R8G8B8:
    case D3DFMT_X8R8G8B8:
        BPP = 32;
        break;

    default:
        return DDHAL_DRIVER_HANDLED;
    }

    pSetMode->ddRVal = D3D8SetMode(pDeviceHandle,
                                   pDeviceHandle->szDeviceName,
                                   pSetMode->dwWidth,
                                   pSetMode->dwHeight,
                                   BPP,
                                   pSetMode->dwRefreshRate,
                                   pSetMode->bRestore);

    return DDHAL_DRIVER_HANDLED;
}

/*****************************Private*Routine******************************\
* DdGetScanLine
*
* History:
*  3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/

#undef DPF_MODNAME
#define DPF_MODNAME "DdGetScanLine"

DWORD
APIENTRY
DdGetScanLine(
    PD3D8_GETSCANLINEDATA pGetScanLine
   )
{
    DDHAL_GETSCANLINEDATA   ScanData;
    DWORD                   dwRet;

    if (CheckForDeviceLost(pGetScanLine->hDD))
    {
        goto DeviceLost;
    }

    dwRet = OsThunkDdGetScanLine(DDHANDLE(pGetScanLine->hDD),
                                 (PDD_GETSCANLINEDATA) &ScanData);

    if (ScanData.ddRVal == DDERR_SURFACELOST)
    {
        goto DeviceLost;
    }

    pGetScanLine->dwScanLine = ScanData.dwScanLine;
    if (ScanData.ddRVal == DDERR_VERTICALBLANKINPROGRESS)
    {
        pGetScanLine->bInVerticalBlank = TRUE;
        ScanData.ddRVal = S_OK;
    }
    else
    {
        pGetScanLine->bInVerticalBlank = FALSE;
    }
    pGetScanLine->ddRVal = MapLegacyResult(ScanData.ddRVal);

    return dwRet;

DeviceLost:
    {
        static int LostScanLine;

        // When lost, we want to mix up the return values in case somebody
        // calling us is waiting for these values to change

        pGetScanLine->ddRVal = DD_OK;
        if (LostScanLine == 0)
        {
            pGetScanLine->dwScanLine = 0;
            pGetScanLine->bInVerticalBlank = TRUE;
        }
        else 
        {
            pGetScanLine->dwScanLine = LostScanLine;
            pGetScanLine->bInVerticalBlank = FALSE;
        }
        if ((LostScanLine += 10) > 100)
        {
            LostScanLine = 0;
        }
    }
    return DDHAL_DRIVER_HANDLED;
}

/*****************************Private*Routine******************************\
* DdSetExclusiveMode
*
* History:
*  22-Apr-1998 -by- John Stephens [johnstep]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "DdSetExclusiveMode"

DWORD
APIENTRY
DdSetExclusiveMode(
    PD3D8_SETEXCLUSIVEMODEDATA pSetExclusiveMode
   )
{
    DDHAL_SETEXCLUSIVEMODEDATA  ExclusiveData;
    DWORD dwRet;

    // smac: How should lost devices behave?
    CheckForDeviceLost(pSetExclusiveMode->hDD);

    ZeroMemory(&ExclusiveData, sizeof(ExclusiveData));
    ExclusiveData.dwEnterExcl = pSetExclusiveMode->dwEnterExcl;

    dwRet = OsThunkDdSetExclusiveMode(
                DDHANDLE(pSetExclusiveMode->hDD),
                (PDD_SETEXCLUSIVEMODEDATA) &ExclusiveData);

    pSetExclusiveMode->ddRVal = MapLegacyResult(ExclusiveData.ddRVal);

    return dwRet;
}

/*****************************Private*Routine******************************\
* DdFlipToGDISurface
*
* History:
*  22-Apr-1998 -by- John Stephens [johnstep]
* Wrote it.
\**************************************************************************/

#undef DPF_MODNAME
#define DPF_MODNAME "DdFlipToGDISurface"

DWORD
APIENTRY
DdFlipToGDISurface(
    PD3D8_FLIPTOGDISURFACEDATA pFlipToGDISurface
   )
{
    DDHAL_FLIPTOGDISURFACEDATA  FlipData;
    DWORD dwRet;

    // smac: How should lost devices behave?
    CheckForDeviceLost(pFlipToGDISurface->hDD);

    FlipData.dwToGDI = pFlipToGDISurface->dwToGDI;
    FlipData.dwReserved = 0;
    FlipData.ddRVal = E_FAIL;
    dwRet = OsThunkDdFlipToGDISurface(
                DDHANDLE(pFlipToGDISurface->hDD),
                (PDD_FLIPTOGDISURFACEDATA) &FlipData);
    if (DDHAL_DRIVER_HANDLED == dwRet)
        pFlipToGDISurface->ddRVal = FlipData.ddRVal;

    pFlipToGDISurface->ddRVal = MapLegacyResult(pFlipToGDISurface->ddRVal);

    return dwRet;
}

/*****************************Private*Routine******************************\
* DdGetAvailDriverMemory
*
* History:
*  16-Feb-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/

#undef DPF_MODNAME
#define DPF_MODNAME "DdGetAvailDriverMemory"

DWORD
APIENTRY
DdGetAvailDriverMemory(
    PD3D8_GETAVAILDRIVERMEMORYDATA pGetAvailDriverMemory
   )
{
    DDHAL_GETAVAILDRIVERMEMORYDATA  MemoryData;
    DWORD dwRet;

    // smac: How should lost devices behave?
    CheckForDeviceLost(pGetAvailDriverMemory->hDD);

    pGetAvailDriverMemory->dwFree = 0;

    // Convert the pool to something that the driver can understand

    memset(&MemoryData, 0, sizeof(MemoryData));
    switch (pGetAvailDriverMemory->Pool)
    {
    case D3DPOOL_LOCALVIDMEM:
        MemoryData.DDSCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
        break;
    case D3DPOOL_DEFAULT:
        MemoryData.DDSCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
        break;
    case D3DPOOL_NONLOCALVIDMEM:
        MemoryData.DDSCaps.dwCaps |= DDSCAPS_NONLOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
        break;

    default:
        return DDHAL_DRIVER_HANDLED;
    }

    if (pGetAvailDriverMemory->dwUsage & D3DUSAGE_DEPTHSTENCIL)
    {
        MemoryData.DDSCaps.dwCaps |= DDSCAPS_ZBUFFER;
    }
    if (pGetAvailDriverMemory->dwUsage & D3DUSAGE_RENDERTARGET)
    {
        MemoryData.DDSCaps.dwCaps |= DDSCAPS_TEXTURE | DDSCAPS_3DDEVICE;
    }
    if (pGetAvailDriverMemory->dwUsage & D3DUSAGE_TEXTURE)
    {
        MemoryData.DDSCaps.dwCaps |= DDSCAPS_TEXTURE;
    }

    dwRet = OsThunkDdGetAvailDriverMemory(
                DDHANDLE(pGetAvailDriverMemory->hDD),
                (PDD_GETAVAILDRIVERMEMORYDATA) &MemoryData);

    pGetAvailDriverMemory->dwFree = MemoryData.dwFree;

    return dwRet;
}

/*****************************Private*Routine******************************\
* D3D8QueryDirectDrawObject
*
* History:
*  3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3D8QueryDirectDrawObject"


BOOL
APIENTRY
D3D8QueryDirectDrawObject(
    HANDLE                      hDD,
    PD3D8_DRIVERCAPS            pDriverCaps,
    PD3D8_CALLBACKS             pCallbacks,
    char*                       pDeviceName,
    HINSTANCE                   hLibrary,
    D3D8_GLOBALDRIVERDATA*      pGblDriverData,
    D3DHAL_D3DEXTENDEDCAPS*     pExtendedCaps,
    LPDDSURFACEDESC             pTextureFormats,
    LPDDPIXELFORMAT             pZStencilFormats,
    UINT*                       pcTextureFormats,
    UINT*                       pcZStencilFormats
   )
{
    PDDDEVICEHANDLE             pDevice = (PDDDEVICEHANDLE) hDD;
    DD_HALINFO                  HalInfo;
    DWORD                       adwCallBackFlags[3];
    DWORD                       dwFlags;
    VIDEOMEMORY*                pVideoMemoryList;
    VIDEOMEMORY*                pVideoMemory;
    DWORD                       dwNumHeaps;
    DWORD                       dwNumFourCC;
    D3DNTHAL_CALLBACKS          D3dCallbacks;
    D3DNTHAL_GLOBALDRIVERDATA   D3dDriverData;
    DD_D3DBUFCALLBACKS          D3dBufferCallbacks;
    DDSCAPSEX                   SurfCapsEx;
    DD_GETDRIVERINFODATA        GetDriverInfoData;
    DWORD                       dwSize;
    DD_MORESURFACECAPS *        pSurfCaps;
    DWORD                       dwRet;
    DWORD                       i;
    DD_MISCELLANEOUSCALLBACKS   MiscCallbacks;
    DD_MISCELLANEOUS2CALLBACKS  Misc2Callbacks;
    D3DNTHAL_CALLBACKS3         D3dCallbacks3;
    D3DDISPLAYMODE              Mode;
    UINT                        MaxZStencilFormats;
    UINT                        MaxTextureFormats;
    
    DDASSERT(pcTextureFormats);
    DDASSERT(pcZStencilFormats);

    MaxTextureFormats = *pcTextureFormats;
    MaxZStencilFormats = *pcZStencilFormats;
    *pcTextureFormats=0;
    *pcZStencilFormats=0;

    // memset the extended caps and global driver data
    ZeroMemory( pExtendedCaps, sizeof( *pExtendedCaps ) );
    ZeroMemory( pGblDriverData, sizeof( *pGblDriverData ) );

    // smac: How should lost devices behave?
    CheckForDeviceLost(hDD);

    // Get all of the neccesary caps
    // Note: do this memset before the Query, since the caller might (ok will) be
    // using a ptr internal to this struct to hold a reference to the

    memset(pDriverCaps, 0, sizeof(D3D8_DRIVERCAPS));

    // Behavior change: This code used to query for the supported texture format
    // list if the device is not software only and the caller supplied a non-NULL
    // buffer for the supported texture formats. Now, however, we never request
    // texture formats at this point. We only request them if we need to, that
    // is if the driver turns out to be a DirectX 7.0 driver or if it is a
    // DirectX 8.0 driver that doesn't support the new format querying mechanism.
    // This later clause is temporary only. Prior to RTM we will require
    // DirectX 8.0 drivers to support the new format querying mechanism.
    if (!OsThunkDdQueryDirectDrawObject(DDHANDLE(hDD),
                                      &HalInfo,
                                      &adwCallBackFlags[0],
                                      &D3dCallbacks,
                                      &D3dDriverData,
                                      &D3dBufferCallbacks,
                                      NULL,
                                      &dwNumHeaps,
                                      NULL,
                                      &dwNumFourCC,
                                      NULL))
    {
        return(FALSE);
    }
    if ((!(HalInfo.dwFlags & DDHALINFO_GETDRIVERINFO2)) &&
        (!(IS_SOFTWARE_DRIVER(pDevice)))                &&
        (NULL != pTextureFormats))
    {
        // This is not a DirectX 8.0 or higher level driver so query again to get
        // the texture formats (as we know we won't get them through the new DirectX 8.0
        // interfaces).
        if (!OsThunkDdQueryDirectDrawObject(DDHANDLE(hDD),
                                        &HalInfo,
                                        &adwCallBackFlags[0],
                                        &D3dCallbacks,
                                        &D3dDriverData,
                                        &D3dBufferCallbacks,
                                        pTextureFormats,
                                        &dwNumHeaps,
                                        NULL,
                                        &dwNumFourCC,
                                        NULL))
        {
            return(FALSE);
        }
    }

    if (!IS_SOFTWARE_DRIVER(pDevice))
    {
        // Initialize the texture format count from the driver data.
        // However, if this is a DX8 style driver this number will be
        // replaced by a format count reported by the new DX8 mechanism
        // code later in this function.
        *pcTextureFormats = D3dDriverData.dwNumTextureFormats;
    }

    // Display drivers can all render windowed
    if( (HalInfo.dwFlags & DDHALINFO_ISPRIMARYDISPLAY) ||
        IsVGADevice(pDeviceName))
    {
        HalInfo.ddCaps.dwCaps2 |= DDCAPS2_CANRENDERWINDOWED;
    }

    pDriverCaps->D3DCaps.Caps         = HalInfo.ddCaps.dwCaps;
    pDriverCaps->D3DCaps.Caps2        = HalInfo.ddCaps.dwCaps2;
    pDriverCaps->D3DCaps.Caps3        = HalInfo.ddCaps.dwSVCaps;
    pDriverCaps->SVBCaps              = HalInfo.ddCaps.dwSVBCaps;
    pDriverCaps->VSBCaps              = HalInfo.ddCaps.dwVSBCaps;
    pDriverCaps->SVBCaps2             = HalInfo.ddCaps.dwSVBCaps2;

    pDevice->DisplayPitch = HalInfo.vmiData.lDisplayPitch;

    // Get the extended surface caps

    SurfCapsEx.dwCaps2 = 0;
    SurfCapsEx.dwCaps3 = 0;
    SurfCapsEx.dwCaps4 = 0;

    memset(&GetDriverInfoData, 0, sizeof(GetDriverInfoData));
    GetDriverInfoData.dwSize = sizeof(GetDriverInfoData);

    GetDriverInfoData.guidInfo = GUID_DDMoreSurfaceCaps;
    dwSize = sizeof(DD_MORESURFACECAPS) + ((dwNumHeaps ? dwNumHeaps - 1 : 0) * sizeof(DDSCAPSEX) * 2);
    pSurfCaps = (DD_MORESURFACECAPS*) MemAlloc(dwSize);
    GetDriverInfoData.ddRVal = E_FAIL;
    if (pSurfCaps != NULL)
    {
        pSurfCaps->dwSize = dwSize;
        GetDriverInfoData.dwExpectedSize = dwSize;
        GetDriverInfoData.lpvData        = pSurfCaps;

        dwRet = OsThunkDdGetDriverInfo(DDHANDLE(hDD), &GetDriverInfoData);
        if ((dwRet == DDHAL_DRIVER_HANDLED) &&
            (GetDriverInfoData.ddRVal == S_OK))
        {
            SurfCapsEx = pSurfCaps->ddsCapsMore;
        }
        MemFree(pSurfCaps);
    }

    // If the driver supports the "GetDriverInfo2" usage of GetDriverInfo then
    // use that now to get the D3DCAPS8.
    if ((HalInfo.dwFlags & DDHALINFO_GETDRIVERINFO2) &&
        !IS_SOFTWARE_DRIVER(pDevice))
    {
        // This buffer is used to pass information down to the driver and get
        // information back from the driver. The GetDriverInfo2 header and
        // any additional information to pass to the driver is copied into this
        // buffer prior to calling GetDriverInfo2. After the call the information
        // returned by the driver is contained in this buffer. All information
        // passed to and from the driver must fit within a buffer of this size.
        DWORD                  buffer[MAX_GDI2_BUFFER_DWORD_SIZE];
        DD_GETDRIVERINFO2DATA* pgdi2;
        DD_GETFORMATCOUNTDATA* pgfcd;
        DD_GETFORMATDATA*      pgfd;
        DD_DXVERSION*          pDXVersion;
        int                    i;
        
        // Set up the DXVersion call
        memset(&buffer, 0, sizeof(buffer));
        pDXVersion = (DD_DXVERSION *)buffer;

        // Before we do anything else, we notify the
        // driver about the DX version information. We ignore
        // errors here.
        pDXVersion->gdi2.dwReserved     = sizeof(DD_STEREOMODE);
        pDXVersion->gdi2.dwMagic        = D3DGDI2_MAGIC;
        pDXVersion->gdi2.dwType         = D3DGDI2_TYPE_DXVERSION;
        pDXVersion->gdi2.dwExpectedSize = sizeof(DD_DXVERSION);
        pDXVersion->dwDXVersion         = DD_RUNTIME_VERSION;
        
        memset(&GetDriverInfoData, 0, sizeof(GetDriverInfoData));
        GetDriverInfoData.dwSize         = sizeof(GetDriverInfoData);
        GetDriverInfoData.guidInfo       = GUID_GetDriverInfo2;
        GetDriverInfoData.lpvData        = &buffer;
        GetDriverInfoData.dwExpectedSize = sizeof(DD_STEREOMODE);
        dwRet = OsThunkDdGetDriverInfo(DDHANDLE(hDD), &GetDriverInfoData);
        if (dwRet != DDHAL_DRIVER_HANDLED       || 
            GetDriverInfoData.ddRVal != S_OK)
        {
            // Errors are ignored here
            dwRet = DDHAL_DRIVER_HANDLED;
        }

        memset(&buffer, 0, sizeof(buffer));

        pgdi2 = (DD_GETDRIVERINFO2DATA*)&buffer;

        // sizeof(DD_STEREOMODE)? The GUID for GetDriverInfo2 is shared with
        // the stereo mode querying stuff. Therefore we need to pass down
        // the structure size (and the expected data size) as
        // sizeof(DD_STEREOMODE) even though we actually have a buffer (and
        // expect a size of sizeof(D3DCAPS8).
        pgdi2->dwReserved     = sizeof(DD_STEREOMODE);
        pgdi2->dwMagic        = D3DGDI2_MAGIC;
        pgdi2->dwType         = D3DGDI2_TYPE_GETD3DCAPS8;
        pgdi2->dwExpectedSize = sizeof(D3DCAPS8);

        memset(&GetDriverInfoData, 0, sizeof(GetDriverInfoData));
        GetDriverInfoData.dwSize         = sizeof(GetDriverInfoData);
        GetDriverInfoData.guidInfo       = GUID_GetDriverInfo2;
        GetDriverInfoData.lpvData        = &buffer;
        GetDriverInfoData.dwExpectedSize = sizeof(DD_STEREOMODE);
        dwRet = OsThunkDdGetDriverInfo(DDHANDLE(hDD), &GetDriverInfoData);
        if ((dwRet == DDHAL_DRIVER_HANDLED) && (GetDriverInfoData.ddRVal == S_OK))
        {
            // Looks like we got D3DCAPS8 back from the driver. Verify by means
            // of the dwActualSize field in GetDriverInfoData.
            if (sizeof(D3DCAPS8) != GetDriverInfoData.dwActualSize)
            {
                DPF(0, "Driver returned an data structure of incorrect size (!= sizeof(D3DCAPS8))");
                return(FALSE);
            }

            // All went well. Copy the caps data across
            memcpy(&pDriverCaps->D3DCaps, &buffer, sizeof(D3DCAPS8));

            // Drivers may not set the ddraw caps correctly, or they might not update them
            // across mode changes, so use the caps that we already have.
            pDriverCaps->D3DCaps.Caps = HalInfo.ddCaps.dwCaps;

            // Display drivers can all render windowed
            if( (HalInfo.dwFlags & DDHALINFO_ISPRIMARYDISPLAY) ||
                IsVGADevice(pDeviceName))
            {
                pDriverCaps->D3DCaps.Caps2 |= DDCAPS2_CANRENDERWINDOWED;
            }

            // Set the flag indicating that the DDI successfully reported DX8
            // style caps
            pDriverCaps->dwFlags |= DDIFLAG_D3DCAPS8;

            // See device can do sub volume lock for volume texture.
            if (pDriverCaps->D3DCaps.DevCaps & D3DDEVCAPS_SUBVOLUMELOCK)
            {
                pDevice->dwFlags |= DDDEVICE_SUPPORTSUBVOLUMELOCK;
            }
        }

        // If this is a DX8 driver it needs to report it supported texture formats to us
        // using GetDriverInfo2. This is done in two stages, one query to determine the
        // number of supported formats, and one to actually retrieve those formats
        // iteratively.

        // Step 1: Get the number of supported formats
        // Please see the description comments above for a description of why the
        // reserved field is set to sizeof(DD_STEREOMODE)
        memset(&buffer, 0, sizeof(buffer));

        pgfcd = (DD_GETFORMATCOUNTDATA*)&buffer;

        pgfcd->gdi2.dwReserved     = sizeof(DD_STEREOMODE);
        pgfcd->gdi2.dwMagic        = D3DGDI2_MAGIC;
        pgfcd->gdi2.dwType         = D3DGDI2_TYPE_GETFORMATCOUNT;
        pgfcd->gdi2.dwExpectedSize = sizeof(DD_GETFORMATCOUNTDATA);

        #if DBG
            // Ensure the driver actually sets the format count if it succeeds this call
            pgfcd->dwFormatCount    = BOGUS_FIELD_VALUE;
        #endif // DBG

        memset(&GetDriverInfoData, 0, sizeof(GetDriverInfoData));
        GetDriverInfoData.dwSize         = sizeof(GetDriverInfoData);
        GetDriverInfoData.guidInfo       = GUID_GetDriverInfo2;
        GetDriverInfoData.lpvData        = &buffer;
        GetDriverInfoData.dwExpectedSize = sizeof(DD_STEREOMODE);
        dwRet = OsThunkDdGetDriverInfo(DDHANDLE(hDD), &GetDriverInfoData);
        if ((dwRet == DDHAL_DRIVER_HANDLED) && (GetDriverInfoData.ddRVal == S_OK))
        {
            // Looks like we got a DD_GETFORMATCOUNTDATA back from the driver. Verify by means
            // of the dwActualSize field in GetDriverInfoData.
            if (sizeof(DD_GETFORMATCOUNTDATA) != GetDriverInfoData.dwActualSize)
            {
                DPF(0, "Driver returned an data structure of incorrect size (!= sizeof(DD_GETFORMATCOUNTDATA))");
                return(FALSE);
            }

            #ifdef DBG
                if (BOGUS_FIELD_VALUE == ((DD_GETFORMATCOUNTDATA*)&buffer)->dwFormatCount)
                {
                    DPF_ERR( "Driver succeeded GETFORMATCOUNT request but didn't set dwFormatCount. Driver error." );
                    return(FALSE);
                }
            #endif // DBG

            // All went well. Replace the number of supported texture formats the driver
            // reported to us with this new number. We don't use the legacy texture format
            // list if this new mechanism is supported
            
            *pcTextureFormats = ((DD_GETFORMATCOUNTDATA*)&buffer)->dwFormatCount;

            // Step2: Query for each of the surface formats in turn.
            // We only do this if the caller requested that we do by means of a non-NULL
            // texture format buffer
            if (NULL != pTextureFormats)
            {
                DWORD          c;
                DDSURFACEDESC* pOutFormat;

                // For simplicities sake we ask for a single format at a time. Not exactly
                // high-performance but this should not matter at this stage of the code.
                pOutFormat = pTextureFormats;
                *pcTextureFormats = min(MaxTextureFormats, *pcTextureFormats);
                for (c = 0; c < (*pcTextureFormats); ++c)
                {
                    // We reinitialize the entire request each time. We could probably
                    // optimize this but it doesn't seem worth it.
                    memset(&buffer, 0, sizeof(DD_GETFORMATDATA));

                    pgfd = (DD_GETFORMATDATA*)&buffer;

                    pgfd->gdi2.dwReserved     = sizeof(DD_STEREOMODE);
                    pgfd->gdi2.dwMagic        = D3DGDI2_MAGIC;
                    pgfd->gdi2.dwType         = D3DGDI2_TYPE_GETFORMAT;
                    pgfd->gdi2.dwExpectedSize = sizeof(DD_GETFORMATDATA);
                    pgfd->dwFormatIndex        = c;
                    #if DBG
                        // Ensure the driver actually sets the format count if it succeeds this call
                        pgfd->format.dwSize    = BOGUS_FIELD_VALUE;
                    #endif // DBG
 
                    memset(&GetDriverInfoData, 0, sizeof(GetDriverInfoData));
                    GetDriverInfoData.dwSize         = sizeof(GetDriverInfoData);
                    GetDriverInfoData.guidInfo       = GUID_GetDriverInfo2;
                    GetDriverInfoData.lpvData        = &buffer;
                    GetDriverInfoData.dwExpectedSize = sizeof(DD_STEREOMODE);
                    dwRet = OsThunkDdGetDriverInfo(DDHANDLE(hDD), &GetDriverInfoData);
                    if ((dwRet == DDHAL_DRIVER_HANDLED) && (GetDriverInfoData.ddRVal == S_OK))
                    {
                        // Looks like we got a DD_GETFORMATDATA back from the driver. Verify by means
                        // of the dwActualSize field in GetDriverInfoData.
                        if (sizeof(DD_GETFORMATDATA) != GetDriverInfoData.dwActualSize)
                        {
                            DPF(0, "Driver returned an data structure of incorrect size (!= sizeof(DD_GETFORMATDATA))");
                            return(FALSE);
                        }

                        DDASSERT(c == ((DD_GETFORMATDATA*)&buffer)->dwFormatIndex);

                        #ifdef DBG
                            if (BOGUS_FIELD_VALUE == (((DD_GETFORMATDATA*)&buffer)->format).dwSize)
                            {
                                DPF_ERR( "Driver succeeded GETFORMAT request but didn't set format. Driver error." );
                                return(FALSE);
                            }
                        #endif // DBG

                        // Looks like all went well. Initialize the surface description part of the format
                        // list and copy the pixel format we got from the driver across.
                        memset(pOutFormat, 0, sizeof(DDSURFACEDESC));
                        pOutFormat->dwSize  = sizeof(DDSURFACEDESC);
                        pOutFormat->dwFlags = DDSD_PIXELFORMAT;
                        memcpy(&pOutFormat->ddpfPixelFormat, &(((DD_GETFORMATDATA*)&buffer)->format), sizeof(DDPIXELFORMAT));

                        ++pOutFormat;
                    }
                }
            }
        }
        else
        {
            DPF(0, "Driver claims DX8 but fails call to GETFORMATCOUNT"             );
            DPF(0, "DX7 texture format list will be used but this will change soon" );
            DPF(0, "Fix driver to support DX8 style surface format reporting now"   );

            // This is a DirectX 8.0 level driver but it doesn't appear to support the
            // new DirectX 8.0 style format querying mechanism so query the kernel
            // again for the DirectX 7.0 style capabilities and use them instead.
            // Note, this is a temporary measure only, prior to the RTM of DirectX 8.0
            // this fallback will be removed and drivers will be required to support
            // the new DirectX 8.0 style format reporting mechanism
            if ((!IS_SOFTWARE_DRIVER(pDevice)) && (NULL != pTextureFormats))
            {
                if (!OsThunkDdQueryDirectDrawObject(DDHANDLE(hDD),
                        &HalInfo,
                        &adwCallBackFlags[0],
                        &D3dCallbacks,
                        &D3dDriverData,
                        &D3dBufferCallbacks,
                        pTextureFormats,
                        &dwNumHeaps,
                        NULL,
                        &dwNumFourCC,
                        NULL))
                {
                    return(FALSE);
                }
            }
        }
    }
    else if (D3dCallbacks.dwSize != 0 && D3dDriverData.dwSize != 0)
    {
        pGblDriverData->dwSize = D3dDriverData.dwSize;
        
        //watcha gonna do:
        DDASSERT(sizeof(pGblDriverData->hwCaps) == sizeof(D3dDriverData.hwCaps));
        memcpy(&pGblDriverData->hwCaps, &D3dDriverData.hwCaps, sizeof(pGblDriverData->hwCaps));
        
        pGblDriverData->dwNumVertices = D3dDriverData.dwNumVertices;
        pGblDriverData->dwNumClipVertices = D3dDriverData.dwNumClipVertices;
        
        // Get the D3D extended caps
        
        GetDriverInfoData.guidInfo       = GUID_D3DExtendedCaps;
        GetDriverInfoData.ddRVal         = E_FAIL;
        GetDriverInfoData.dwExpectedSize = sizeof(D3DHAL_D3DEXTENDEDCAPS);
        GetDriverInfoData.lpvData        = pExtendedCaps;
        dwRet = OsThunkDdGetDriverInfo(DDHANDLE(hDD), &GetDriverInfoData);
        if ((dwRet != DDHAL_DRIVER_HANDLED) ||
            (GetDriverInfoData.ddRVal != S_OK))
        {
            DPF_ERR( "Get EXTENDEDCAPS from the driver failed" );
            return FALSE;
        }
    }

    // Get the supported Z formats.  We only do this if we are not using a
    // software driver

    if (!IS_SOFTWARE_DRIVER(pDevice))
    {
        DWORD tempbuf[249];  // make this <1K bytes or GetDriverInfo() fails cuz it cant do its "expected size overwrite" test within its own 1K tempbuffer

        GetDriverInfoData.guidInfo       = GUID_ZPixelFormats;
        GetDriverInfoData.ddRVal         = E_FAIL;
        GetDriverInfoData.dwExpectedSize = sizeof(tempbuf);
        GetDriverInfoData.lpvData        = tempbuf;
        dwRet = OsThunkDdGetDriverInfo(DDHANDLE(hDD), &GetDriverInfoData);

        if ((dwRet != DDHAL_DRIVER_HANDLED) ||
            (GetDriverInfoData.ddRVal != S_OK) ||
            ((GetDriverInfoData.dwActualSize-sizeof(DWORD)) % sizeof(DDPIXELFORMAT) != 0) ||
            ((tempbuf[0]*sizeof(DDPIXELFORMAT)+sizeof(DWORD))>sizeof(tempbuf)))

        {
            // It could be that this is an old driver that doesn't support
            // stencil.  We might be able to get some info from the global
            // driver data.

            if (pGblDriverData->hwCaps.dwDeviceZBufferBitDepth & DDBD_16)
            {
                (*pcZStencilFormats)++;
                if (pZStencilFormats && 
                    (*pcZStencilFormats <= MaxZStencilFormats))
                {
                    pZStencilFormats->dwSize = sizeof(DDPIXELFORMAT);
                    pZStencilFormats->dwFlags = DDPF_ZBUFFER;
                    pZStencilFormats->dwZBufferBitDepth = 16;
                    pZStencilFormats->dwStencilBitDepth = 0;
                    pZStencilFormats->dwZBitMask = 0xffff;
                    pZStencilFormats->dwStencilBitMask = 0x0000;
                    pZStencilFormats++;
                }
            }
            if (pGblDriverData->hwCaps.dwDeviceZBufferBitDepth & DDBD_32)
            {
                (*pcZStencilFormats)++;
                if (pZStencilFormats &&
                    (*pcZStencilFormats <= MaxZStencilFormats))
                {
                    pZStencilFormats->dwSize = sizeof(DDPIXELFORMAT);
                    pZStencilFormats->dwFlags = DDPF_ZBUFFER;
                    pZStencilFormats->dwZBufferBitDepth = 32;
                    pZStencilFormats->dwStencilBitDepth = 0;
                    pZStencilFormats->dwZBitMask = 0xffffffff;
                    pZStencilFormats->dwStencilBitMask = 0x00000000;
                    pZStencilFormats++;
                }
            }
        }
        else
        {
            //We have a GetDriverInfo response to our Z format query. These are
            //DDPIXELFORMATs that we can copy back to our caller
            (*pcZStencilFormats) = tempbuf[0];
            if(pZStencilFormats)
            {
                MaxZStencilFormats = min(MaxZStencilFormats, tempbuf[0]);
                memcpy(pZStencilFormats, &tempbuf[1], MaxZStencilFormats * sizeof(DDPIXELFORMAT));
            }
        }
    }

    // Get info about the current mode

    D3D8GetMode (NULL, pDeviceName, &Mode, 0);

    pDevice->DisplayFormatWithAlpha = Mode.Format;
    pDevice->DisplayFormatWithoutAlpha = Mode.Format;
    if (Mode.Format == D3DFMT_X8R8G8B8)
    {
        if (HalInfo.vmiData.ddpfDisplay.dwFlags & DDPF_ALPHAPIXELS)
        {
            pDevice->DisplayFormatWithAlpha = D3DFMT_A8R8G8B8;
        }
    }
    if (Mode.Format == D3DFMT_X1R5G5B5)
    {
        if (HalInfo.vmiData.ddpfDisplay.dwFlags & DDPF_ALPHAPIXELS)
        {
            pDevice->DisplayFormatWithAlpha = D3DFMT_A1R5G5B5;
        }
    }

    pDriverCaps->DisplayWidth               = Mode.Width;
    pDriverCaps->DisplayHeight              = Mode.Height;
    pDriverCaps->DisplayFrequency           = Mode.RefreshRate;
    pDriverCaps->DisplayFormatWithoutAlpha  = Mode.Format;
    pDriverCaps->DisplayFormatWithAlpha     = pDevice->DisplayFormatWithAlpha;


    // Get the Miscellaneous callbacks
    GetDriverInfoData.guidInfo       = GUID_MiscellaneousCallbacks;
    GetDriverInfoData.ddRVal         = E_FAIL;
    GetDriverInfoData.dwExpectedSize = sizeof(DD_MISCELLANEOUSCALLBACKS);
    GetDriverInfoData.lpvData        = &MiscCallbacks;
    dwRet = OsThunkDdGetDriverInfo(DDHANDLE(hDD), &GetDriverInfoData);
    if ((dwRet != DDHAL_DRIVER_HANDLED) ||
        (GetDriverInfoData.ddRVal != S_OK))
    {
        memset (&MiscCallbacks, 0, sizeof(DD_MISCELLANEOUSCALLBACKS));
    }

    // Get the Miscellaneous2 callbacks
    GetDriverInfoData.guidInfo       = GUID_Miscellaneous2Callbacks;
    GetDriverInfoData.ddRVal         = E_FAIL;
    GetDriverInfoData.dwExpectedSize = sizeof(DD_MISCELLANEOUS2CALLBACKS);
    GetDriverInfoData.lpvData        = &Misc2Callbacks;
    dwRet = OsThunkDdGetDriverInfo(DDHANDLE(hDD), &GetDriverInfoData);
    if ((dwRet != DDHAL_DRIVER_HANDLED) ||
        (GetDriverInfoData.ddRVal != S_OK))
    {
        memset (&Misc2Callbacks, 0, sizeof(DD_MISCELLANEOUS2CALLBACKS));
    }

    // Get the D3Dcallbacks3 callbacks
    GetDriverInfoData.guidInfo       = GUID_D3DCallbacks3;
    GetDriverInfoData.ddRVal         = E_FAIL;
    GetDriverInfoData.dwExpectedSize = sizeof(D3DNTHAL_CALLBACKS3);
    GetDriverInfoData.lpvData        = &D3dCallbacks3;
    dwRet = OsThunkDdGetDriverInfo(DDHANDLE(hDD), &GetDriverInfoData);
    if ((dwRet != DDHAL_DRIVER_HANDLED) ||
        (GetDriverInfoData.ddRVal != S_OK))
    {
        memset (&D3dCallbacks3, 0, sizeof(D3DNTHAL_CALLBACKS3));
    }

    // Fill in the D3D8 Callback table
    RtlZeroMemory(pCallbacks, sizeof(*pCallbacks));
    pCallbacks->CreateSurface           = DdCreateSurface;
    pCallbacks->DestroySurface          = DdDestroySurface;
    pCallbacks->Lock                    = DdLock;
    pCallbacks->Unlock                  = DdUnlock;
    pCallbacks->Blt                     = DdBlt;
    pCallbacks->GetScanLine             = DdGetScanLine;
    pCallbacks->Flip                    = DdFlip;
    pCallbacks->WaitForVerticalBlank    = DdWaitForVerticalBlank;
    pCallbacks->GetBltStatus            = DdGetBltStatus;
    pCallbacks->GetFlipStatus           = DdGetFlipStatus;
    pCallbacks->SetMode                 = DdSetMode;
    pCallbacks->FlipToGDISurface        = DdFlipToGDISurface;
    pCallbacks->SetExclusiveMode        = DdSetExclusiveMode;
    pCallbacks->GetAvailDriverMemory    = DdGetAvailDriverMemory;

    if (D3dCallbacks.ContextCreate != NULL)
    {
        pCallbacks->CreateContext   = D3dContextCreate;
    }
    if (D3dCallbacks.ContextDestroy != NULL)
    {
        pCallbacks->ContextDestroy = D3dContextDestroy;
    }
    if (D3dCallbacks.ContextDestroyAll != NULL)
    {
        pCallbacks->ContextDestroyAll = D3dContextDestroyAll;
    }
    if (Misc2Callbacks.GetDriverState)
    {
        pCallbacks->GetDriverState = DdGetDriverState;
    }
    if (D3dCallbacks3.ValidateTextureStageState != NULL)
    {
        pCallbacks->ValidateTextureStageState = D3dValidateTextureStageState;
    }
    if (D3dCallbacks3.DrawPrimitives2 != NULL)
    {
        pCallbacks->DrawPrimitives2 = D3dDrawPrimitives2;
    }
    if (HalInfo.dwFlags & DDHALINFO_GETDRIVERINFO2)
    {
        pDevice->dwFlags |= DDDEVICE_GETDRIVERINFO2;
        if (!(pDevice->dwFlags & DDDEVICE_INITIALIZED))
        {
            // Since this is the first time we have seen this device, we need
            // to tell the driver that the runtime will send the propoer AGP
            // notification.
            InformDriverAGPWorkaroundAware((HANDLE) pDevice);
        }
    }
    pDevice->dwFlags |= DDDEVICE_INITIALIZED;

    if (FAILED(GetNTDeviceRect(pDeviceName,&pDevice->rcMonitor)))
    {
        SetRect(&pDevice->rcMonitor,0,0,
            GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
    }

    // What about HW cursor support? check Must be done before SoftwareRast
    // Caps Overrides

    if (0 == pDriverCaps->D3DCaps.MaxStreams)
    {
        // The hardware driver is DX7
        if (CanKnownDriverDoThis(pDevice, KNOWN_HWCURSOR))
        {
            pDriverCaps->D3DCaps.CursorCaps = D3DCURSORCAPS_COLOR; 
            pDriverCaps->KnownDriverFlags |= KNOWN_HWCURSOR;
            if (CanKnownDriverDoThis(pDevice, KNOWN_HWCURSORLOWRES))
            {
                pDriverCaps->D3DCaps.CursorCaps |= D3DCURSORCAPS_LOWRES; 
                pDriverCaps->KnownDriverFlags |= KNOWN_HWCURSORLOWRES;
            }
        }
    }
    // need to save a HAL copy in thunklayer, for example DdBlt needs caps
    pDevice->DDCaps = pDriverCaps->D3DCaps.Caps;
    pDevice->SVBCaps = pDriverCaps->SVBCaps;

    // If Refrast or the HEL has a hook, call it to let it change whatever it wants

    if (IS_SOFTWARE_DRIVER(pDevice))
    {
        *pcZStencilFormats = 0;

        SwDDIMungeCaps (
            hLibrary,
            hDD,
            pDriverCaps,
            pCallbacks,
            pTextureFormats,
            pcTextureFormats,
            pDevice->pSwInitFunction
            );
    }

    pDevice->DriverLevel = 0;
    if (pDriverCaps->D3DCaps.MaxStreams != 0)
    {
        pDevice->DriverLevel = 8;
    }
    else if (pCallbacks->DrawPrimitives2 != NULL)
    {
        pDevice->DriverLevel = 7;
    }

    // Determine what version of windows is running so we can know
    // what lock parameters to send.  Whistler is version 5.1.

    pDevice->bIsWhistler = IsWhistler();

    // If it's a pre-dx8 driver and they support cubemaps, we need to
    // specify whether they support mipped cubemaps or not.
    
    if (pDevice->DriverLevel < 8)
    {
        if (CanKnownDriverDoThis(pDevice, KNOWN_MIPPEDCUBEMAPS))
        {
            pDriverCaps->KnownDriverFlags |= KNOWN_MIPPEDCUBEMAPS;
        }

        // Does this driver have a Z/Stencil depth restriction?
        if (CanKnownDriverDoThis(pDevice, KNOWN_ZSTENCILDEPTH))
        {
            pDriverCaps->KnownDriverFlags |= KNOWN_ZSTENCILDEPTH;
        }

        // Does device have no driver known to over-queue windowed presentation blts?
        if (CanKnownDriverDoThis(pDevice, KNOWN_NOTAWINDOWEDBLTQUEUER))
        {
            pDriverCaps->KnownDriverFlags |= KNOWN_NOTAWINDOWEDBLTQUEUER;
        }

        // Does device support D3DFMT_D16_LOCKABLE
        if (CanKnownDriverDoThis(pDevice, KNOWN_D16_LOCKABLE))
        {
            pDriverCaps->KnownDriverFlags |= KNOWN_D16_LOCKABLE;
        }

        // Figure out what RT/Texture formats it supports
        if (CanKnownDriverDoThis(pDevice, KNOWN_CANMISMATCHRT))
        {
            pDriverCaps->KnownDriverFlags |= KNOWN_CANMISMATCHRT;
        }
        if (CanKnownDriverDoThis(pDevice, KNOWN_RTTEXTURE_X1R5G5B5))
        {
            pDriverCaps->KnownDriverFlags |= KNOWN_RTTEXTURE_X1R5G5B5;
        }
        if (CanKnownDriverDoThis(pDevice, KNOWN_RTTEXTURE_R5G6B5))
        {
            pDriverCaps->KnownDriverFlags |= KNOWN_RTTEXTURE_R5G6B5;
        }
        if (CanKnownDriverDoThis(pDevice, KNOWN_RTTEXTURE_X8R8G8B8))
        {
            pDriverCaps->KnownDriverFlags |= KNOWN_RTTEXTURE_X8R8G8B8;
        }
        if (CanKnownDriverDoThis(pDevice, KNOWN_RTTEXTURE_A8R8G8B8))
        {
            pDriverCaps->KnownDriverFlags |= KNOWN_RTTEXTURE_A8R8G8B8;
        }
        if (CanKnownDriverDoThis(pDevice, KNOWN_RTTEXTURE_A1R5G5B5))
        {
            pDriverCaps->KnownDriverFlags |= KNOWN_RTTEXTURE_A1R5G5B5;
        }
        if (CanKnownDriverDoThis(pDevice, KNOWN_RTTEXTURE_A4R4G4B4))
        {
            pDriverCaps->KnownDriverFlags |= KNOWN_RTTEXTURE_A4R4G4B4;
        }
    }

    if (NULL != HalInfo.lpD3DBufCallbacks )
    {
        pDevice->dwFlags |= DDDEVICE_SUPPORTD3DBUF;
    }
    else
    {
        pDevice->dwFlags &= ~DDDEVICE_SUPPORTD3DBUF;
    }
    return(TRUE);
}

//
// See NT bug 448720...
//
// AGP surfaces will be unlocked by the kernel mode in response to mode switches.
// App may still be writing to surface.
// Driver should therefore defer free of AGP memory until later.
// "Later" is defined as when the usermode determines the app is done writing and can tell
// the driver so.
//
// Drivers need to know that the runtime can do this so they can turn off any other workarounds
// they might have.
//

/*****************************Private*Routine******************************\
* GetDriverInfo2
*
* History:
*  06-Nov-2001  maxmcm      Wrote it
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "GetDriverInfo2"

DWORD
APIENTRY
GetDriverInfo2(
    DWORD* pdwDrvRet,
    HANDLE hDriver,
    DWORD dwType,
    DWORD dwSize,
    void* pBuffer)
{
    DD_GETDRIVERINFO2DATA*          pGDI2Data;
    DD_GETDRIVERINFODATA            GetDriverInfoData;
    DWORD                           dwRet;
    PDDDEVICEHANDLE                 pDevice;

    // In some cases (e.g. ProfileAdapter), it is possible that we can get
    // here with a NULL device, so we should check for that.
    pDevice = (PDDDEVICEHANDLE) hDriver;
    if (pDevice == NULL)
    {
        *pdwDrvRet = E_FAIL;
        return DDHAL_DRIVER_HANDLED;
    }

    // Don't call the driver if they don't support GETDRIVERINFO2
    if (!(pDevice->dwFlags & DDDEVICE_GETDRIVERINFO2))
    {
        *pdwDrvRet = E_FAIL;
        return DDHAL_DRIVER_HANDLED;
    }
       
    // Setup GetDriverInfo2 call
    pGDI2Data = (DD_GETDRIVERINFO2DATA*) pBuffer;

    memset(pGDI2Data, 0, sizeof(*pGDI2Data));
    pGDI2Data->dwReserved       = sizeof(DD_STEREOMODE);
    pGDI2Data->dwMagic          = D3DGDI2_MAGIC;
    pGDI2Data->dwType           = dwType;
    pGDI2Data->dwExpectedSize   = dwSize;

    memset(&GetDriverInfoData, 0, sizeof(GetDriverInfoData));
    GetDriverInfoData.dwSize         = sizeof(GetDriverInfoData);
    GetDriverInfoData.guidInfo       = GUID_GetDriverInfo2;
    GetDriverInfoData.lpvData        = pGDI2Data;
    GetDriverInfoData.dwExpectedSize = sizeof(DD_STEREOMODE);

    // Ask the driver for information
    dwRet = OsThunkDdGetDriverInfo(DDHANDLE(pDevice), &GetDriverInfoData);

    *pdwDrvRet = GetDriverInfoData.ddRVal;
    return dwRet;
}


void InformDriverAGPWorkaroundAware(HANDLE hDD)
{
    DDNT_DEFERRED_AGP_AWARE_DATA  aad;
    DWORD                       dwDrvRet;
    DWORD                       dwGDI2Ret;

    dwGDI2Ret = GetDriverInfo2(&dwDrvRet, hDD,
                                   _NT_D3DGDI2_TYPE_DEFERRED_AGP_AWARE,
                                   sizeof(aad), &aad);

    //drop the return code on the floor.... just a notification
}

void InformDriverFreeAGP(HANDLE hDD)
{
    DDNT_FREE_DEFERRED_AGP_DATA   fad;
    DWORD                       dwDrvRet;
    DWORD                       dwGDI2Ret;

    fad.dwProcessId = GetCurrentProcessId();

    dwGDI2Ret = GetDriverInfo2(&dwDrvRet, hDD,
                                   _NT_D3DGDI2_TYPE_FREE_DEFERRED_AGP,
                                   sizeof(fad), &fad);

    //drop the return code on the floor.... just a notification
}

void InformDriverToDeferFrees(HANDLE hDD)
{
    DDNT_FREE_DEFERRED_AGP_DATA   fad;
    DWORD                       dwDrvRet;
    DWORD                       dwGDI2Ret;

    fad.dwProcessId = GetCurrentProcessId();

    dwGDI2Ret = GetDriverInfo2(&dwDrvRet, hDD,
                                   _NT_D3DGDI2_TYPE_DEFER_AGP_FREES,
                                   sizeof(fad), &fad);

    //drop the return code on the floor.... just a notification
}

/*****************************Private*Routine******************************\
* D3D8CreateDirectDrawObject
*
* Calls GDI32 to get the global DirectDraw handle.
*
* History:
*  16-Nov-1999 -by- Scott MacDonald [smac]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3D8CreateDirectDrawObject"

VOID
APIENTRY
D3D8CreateDirectDrawObject(
    HDC             hdc,
    char*           szDeviceName,
    HANDLE*         phDD,
    D3DDEVTYPE      Type,
    HINSTANCE*      phLibrary,
    VOID*           pInitFunction
   )
{
    DDRAWI_DIRECTDRAW_GBL   ddg;
    PDDDEVICEHANDLE         pDeviceHandle;
    HKEY                    hKey = (HKEY) NULL;

    *phDD = NULL;
    ddg.hDD = 0;
    pDeviceHandle = NULL;
    DdCreateDirectDrawObject (&ddg, hdc);

    if (ddg.hDD != 0)
    {
        pDeviceHandle = MemAlloc (sizeof(DDDEVICEHANDLE));
        if (pDeviceHandle != NULL)
        {
            pDeviceHandle->hDD = (HANDLE)ddg.hDD;
            *phDD = (HANDLE) pDeviceHandle;
            lstrcpy (pDeviceHandle->szDeviceName, szDeviceName);
            pDeviceHandle->DisplayUniqueness =
                DdQueryDisplaySettingsUniqueness();
            pDeviceHandle->hLastWnd = NULL;
            pDeviceHandle->pClipList = NULL;
            pDeviceHandle->pOrigClipList = NULL;
            *phLibrary = NULL;
            pDeviceHandle->DeviceType = Type;
            if (Type == D3DDEVTYPE_REF)
            {
                *phLibrary = LoadLibrary (D3D8_REFRASTNAME);
                pDeviceHandle->pDD = SwDDICreateDirectDraw();
                if (pDeviceHandle->pDD == NULL)
                {
                    *phDD = NULL;
                }
                else
                {
                    pDeviceHandle->hLibrary = *phLibrary;
                }
            }
            else if (Type == D3DDEVTYPE_SW)
            {
                pDeviceHandle->pDD = SwDDICreateDirectDraw();
                if (pDeviceHandle->pDD == NULL)
                {
                    *phDD = NULL;
                }
                else
                {
                    pDeviceHandle->pSwInitFunction = pInitFunction;
                }
            }
        }
    }

    if (*phDD == NULL)
    {
        if (pDeviceHandle)
        {
            MemFree (pDeviceHandle);
        }

        if (ddg.hDD != 0)
        {
            OsThunkDdDeleteDirectDrawObject((HANDLE) ddg.hDD);
        }
    }
    else
    {
        // See if they want to explicitly enable/disable driver behavior
        if (!RegOpenKey(HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey))
        {
            DWORD   type;
            DWORD   value;
            DWORD   cb = sizeof(value);

            pDeviceHandle->ForceFlagsOn = 0;
            pDeviceHandle->ForceFlagsOff = 0;
#ifdef DEBUG
            if (!RegQueryValueEx(hKey, "ForceDriverFlagsOn", NULL, &type, (CONST LPBYTE)&value, &cb))
            {
                pDeviceHandle->ForceFlagsOn = value;
            }
            cb = sizeof(value);
#endif
            if (!RegQueryValueEx(hKey, "ForceDriverFlagsOff", NULL, &type, (CONST LPBYTE)&value, &cb))
            {
                pDeviceHandle->ForceFlagsOff = value;
            }
            RegCloseKey(hKey);
        }
        NumDevices++;
    }
}

/*****************************Private*Routine******************************\
* D3D8DeleteDirectDrawObject
*
* Note that all associated surface objects must be deleted before the
* DirectDrawObject can be deleted.
*
* History:
*  3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3D8DeleteDirectDrawObject"

VOID
APIENTRY
D3D8DeleteDirectDrawObject(
    HANDLE hDD
   )
{
    PDDDEVICEHANDLE pHandle = (PDDDEVICEHANDLE) hDD;
    PDEFERREDCREATE pTemp;

    NumDevices--;
    if (pHandle!= NULL)
    {
        PDEFERREDCREATE pDefCreate = pHandle->pDeferList;

        OsThunkDdDeleteDirectDrawObject(DDHANDLE(hDD));
        if (NULL != pHandle->SurfaceHandleList.dwList)
        {
            MemFree(pHandle->SurfaceHandleList.dwList);
        }
        if (NULL != pHandle->pDD)
        {
            if ( NULL != pHandle->pDD->lpGbl->lpDDCBtmp)
            {
                MemFree(pHandle->pDD->lpGbl->lpDDCBtmp);
            }
            MemFree(pHandle->pDD);
        }
        if (NULL != pHandle->pClipList)
        {
            MemFree(pHandle->pClipList);
        }
        if (NULL != pHandle->pOrigClipList)
        {
            MemFree(pHandle->pOrigClipList);
        }
#ifdef DEBUG
        // In debug print the types of objects
        // that weren't released
        if (pHandle->pSurfList != NULL)
        {
            PDDSURFHANDLE pSurf = pHandle->pSurfList;
            DPF_ERR("Not all objects were freed: the following indicate "
                    "the types of unfreed objects.");
            while (pSurf)
            {
                DebugPrintSurfaceInfo(pSurf);
                pSurf = pSurf->pNext;
            }
        }
#endif
        while (pDefCreate != NULL)
        {
            pTemp = pDefCreate->pNext;
            MemFree(pDefCreate->CreateData.pSList);
            MemFree(pDefCreate);
            pDefCreate = pTemp;
        }
        DDASSERT(pHandle->pSurfList == NULL);
        DDASSERT(pHandle->pContext == NULL);

        MemFree(hDD);
    }
}

/*****************************Private*Routine******************************\
* DdGetDC
*
* History:
*  3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3D8GetDC"

HDC
APIENTRY
D3D8GetDC(
    HANDLE                    hSurface,
    LPPALETTEENTRY            pPalette
   )
{
    if (CheckForDeviceLost((HANDLE)((PDDSURFHANDLE)hSurface)->pDevice))
    {
        return NULL;
    }
    return(OsThunkDdGetDC(GetSurfHandle(hSurface), pPalette));
}

/*****************************Private*Routine******************************\
* DdReleaseDC
*
* History:
*  3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3D8ReleaseDC"

BOOL
APIENTRY
D3D8ReleaseDC(
    HANDLE                  hSurface,
    HDC                     hdc
   )
{
    DDASSERT(hdc != NULL);

    return(OsThunkDdReleaseDC(GetSurfHandle(hSurface)));
}

/*****************************Private*Routine******************************\
* DdReenableDirectDrawObject
*
* History:
*  3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3D8ReenableDirectDrawObject"

BOOL
APIENTRY
D3D8ReenableDirectDrawObject(
    HANDLE                  hDD,
    BOOL*                   pbNewMode
   )
{
    BOOL    bRet;
    PDDDEVICEHANDLE pHandle = (PDDDEVICEHANDLE) hDD;

    bRet = OsThunkDdReenableDirectDrawObject(DDHANDLE(hDD),
                                           pbNewMode);

    if (!bRet && 
        ((pHandle->DeviceType == D3DDEVTYPE_REF) || 
            (pHandle->DeviceType == D3DDEVTYPE_SW)) &&
        !(pHandle->DDCaps & ~DDCAPS_NOHARDWARE))
    {
        bRet = TRUE;
    }

    return bRet;
}

/*****************************Private*Routine******************************\
* DdSetGammaRamp
*
* History:
*  18-Oct-1997 -by- smac
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3D8SetGammaRamp"

BOOL
APIENTRY
D3D8SetGammaRamp(
    HANDLE      hDD,
    HDC         hdc,
    LPVOID      lpGammaRamp
   )
{
    if (CheckForDeviceLost(hDD))
    {
        return TRUE;
    }

    return(OsThunkDdSetGammaRamp(DDHANDLE(hDD), hdc,
        lpGammaRamp));
}

/*****************************Private*Routine******************************\
* D3D8BuildModeTable
*
* History:
*  15-Dec-1999 -by- smac
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3D8BuildModeTable"

VOID
APIENTRY
D3D8BuildModeTable(
    char*               pszDevice,
    D3DDISPLAYMODE*     pModeTable,
    DWORD*              pNumEntries,
    D3DFORMAT           Unknown16,
    HANDLE              hProfile,
    BOOL                b16bppSupported,
    BOOL                b32bppSupported
   )
{
    int             i;
    int             j;
    DEVMODE         dm;
    D3DFORMAT       format;
    int             NumTempEntries = 0;
    DWORD           NumActualEntries = 0;

    dm.dmSize = sizeof(dm);
    for (i = 0; EnumDisplaySettings(pszDevice, i, &dm); ++i)
    {
        // Filter out all modes other than 15, 16 and 32bpp
        if ((dm.dmBitsPerPel != 15) &&
            (dm.dmBitsPerPel != 16) &&
            (dm.dmBitsPerPel != 32))
        {
            continue;
        }

        if (((dm.dmBitsPerPel == 15) ||
             (dm.dmBitsPerPel == 16)) &&
            !b16bppSupported)
        {
            continue;
        }
        else if ((dm.dmBitsPerPel == 32) &&
            !b32bppSupported)
        {
            continue;
        }
       
        // Make sure that we understand the format.

        if ((dm.dmBitsPerPel == 16) ||
            (dm.dmBitsPerPel == 15))
        {
            format = Unknown16;
        }
        else
        {
            DDASSERT(dm.dmBitsPerPel == 32);
            format = D3DFMT_X8R8G8B8;
        }

        if (pModeTable != NULL)
        {
            ///The caller must pass us a number
            DDASSERT( (*pNumEntries) );
            if ( NumActualEntries >= (*pNumEntries) )
            {
                //we exceeded the number of entries allocated for us.
                //tell the caller to re-query and try again.
                NumActualEntries = 0;
                break;
            }

            // Add the new mode.
            pModeTable[NumActualEntries].Width       = dm.dmPelsWidth;
            pModeTable[NumActualEntries].Height      = dm.dmPelsHeight;
            pModeTable[NumActualEntries].RefreshRate = dm.dmDisplayFrequency;
            pModeTable[NumActualEntries].Format      = format;
        }
         
        NumActualEntries++;

    }

    //The caller will either pass a NULL modelist pointer, in which case
    //it is expecting us to fill in the number of entries. If the modelist
    // is non-null, the caller expects us to fill the table but not
    // overwrite. If we find the table has grown, ask the caller to 
    // re-allocate by returning 0 modes.
    (*pNumEntries) = NumActualEntries;
}

/*****************************Private*Routine******************************\
* D3D8IsDeviceLost
*
* History:
*  15-Dec-1999 -by- smac
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3D8IsDeviceLost"

BOOL
APIENTRY
D3D8IsDeviceLost(
    HANDLE  hDD
   )
{
    return CheckForDeviceLost(hDD);
}

/*****************************Private*Routine******************************\
* D3D8CanRestoreNow
* 15-Dec-1999 -by- smac
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3D8CanRestoreNow"

BOOL
APIENTRY
D3D8CanRestoreNow(
    HANDLE  hDD
   )
{
    PDDDEVICEHANDLE pDeviceHandle = (PDDDEVICEHANDLE) hDD;
    BOOL            bNewMode;
    D3D8_DRIVERCAPS DriverData;
    D3D8_GLOBALDRIVERDATA D3DGlobalDriverData;
    D3DHAL_D3DEXTENDEDCAPS D3DExtendedCaps;
    D3D8_CALLBACKS  Callbacks;
    UINT            uiDummy;

    // If we aren't lost, then it's an easy call

    if (!CheckForDeviceLost(hDD))
    {
        return TRUE;
    }

    // Otherwise, we actually need to call the kernel and look at the caps

    memset(&DriverData, 0, sizeof(DriverData));
    memset(&D3DGlobalDriverData, 0, sizeof(D3DGlobalDriverData));
    memset(&D3DExtendedCaps, 0, sizeof(D3DExtendedCaps));
    memset(&Callbacks, 0, sizeof(Callbacks));
    if (!D3D8ReenableDirectDrawObject (hDD,&bNewMode) ||
        !D3D8QueryDirectDrawObject(hDD,
                                   &DriverData,
                                   &Callbacks,
                                   pDeviceHandle->szDeviceName,
                                   pDeviceHandle->hLibrary,
                                   &D3DGlobalDriverData,
                                   &D3DExtendedCaps,
                                   NULL,NULL,&uiDummy,&uiDummy))
    {
        return FALSE;
    }

    if (IS_SOFTWARE_DRIVER(hDD) ||
        ((DriverData.D3DCaps.Caps & DDCAPS_3D) &&
        (Callbacks.DrawPrimitives2 != NULL)))
    {
        return TRUE;
    }

    return FALSE;
}

/*****************************Private*Routine******************************\
* D3D8RestoreDevice
* 15-Dec-1999 -by- smac
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3D8RestoreDevice"

void
APIENTRY
D3D8RestoreDevice (
    HANDLE hDD
   )
{
    HRESULT hr;
    DWORD i, j, k;
    DWORD Width, Height, Depth;
    BYTE *SliceSrc, *SliceDst, *RowSrc, *RowDst;
    PDDDEVICEHANDLE pDeviceHandle = (PDDDEVICEHANDLE) hDD;
    PDDSURFHANDLE pSurf;
    PD3DCONTEXTHANDLE pContext = pDeviceHandle->pContext;
    PDEFERREDCREATE pDefCreate = pDeviceHandle->pDeferList;
    PDEFERREDCREATE *ppNext = &pDeviceHandle->pDeferList;
    PDEFERREDCREATE pTemp;
    D3D8_LOCKDATA LockData;
    D3D8_UNLOCKDATA UnlockData;
    ULONG_PTR pVidmem[32 * 6];

    // First, say that we aren't lost anymore

    pDeviceHandle->DisplayUniqueness =
        DdQueryDisplaySettingsUniqueness();
    pDeviceHandle->bDeviceLost = FALSE;
    pDeviceHandle->dwFlags &= ~DDDEVICE_DP2ERROR;

    // Now, check for any sysmem surfaces that were created while
    // the device was lost and call CreateSurfaceEx if they need it.

    pSurf = pDeviceHandle->pSurfList;

    while (pSurf != NULL)
    {
        if ((pSurf->dwCookie != 0) &&
            (pSurf->dwFlags & DDSURF_DEFERCREATEEX))
        {
            hr = OsThunkDdCreateSurfaceEx(
                    DDHANDLE(hDD),
                    pSurf->hSurface,
                    pSurf->dwCookie);
            if (SUCCEEDED(hr))
            {
                pSurf->dwFlags &= ~DDSURF_DEFERCREATEEX;
            }
            else
            {
                // TODO: Handle error condition
                DPF(0, "CreateSurfaceEx failed when resurrecting sysmem or D3D managed surfaces");
            }
        }
        pSurf = pSurf->pNext;
    }

    // Now, create the D3D context if we need to.

    if ((pContext != NULL) &&
        (pContext->dwFlags & D3DCONTEXT_DEFERCREATE))
    {
        D3D8_CONTEXTCREATEDATA  ContextData;

        memset(&ContextData, 0, sizeof(ContextData));
        ContextData.hDD = DDHANDLE(hDD);
        ContextData.dwPID = pContext->dwPID;
        ContextData.dwhContext = (ULONG_PTR) pContext->hDeferHandle;

        OsThunkD3dContextCreate(DDHANDLE(hDD),
            GetSurfHandle(pContext->pSurface),
            GetSurfHandle(pContext->pDDSZ),
            (D3DNTHAL_CONTEXTCREATEI *)&ContextData);

        if (SUCCEEDED(ContextData.ddrval))
        {
            pContext->dwhContext = (HANDLE) ContextData.dwhContext;
            pContext->dwFlags &= ~D3DCONTEXT_DEFERCREATE;
        }
        else
        {
            // TODO: Handle error condition
        }
    }

    // Finally resurrect our deferred driver managed surfaces (Gulp!)

    while (pDefCreate != NULL)
    {
        DDASSERT(pDefCreate->CreateData.dwSCnt <= 32 * 6);

        // First check if the deferred surface exists at all. The problem
        // is that DdDestroySurface could have been called. We could have
        // removed the surface from the deferred list in DdDestroySurface
        // but since DdDestroySurface is called piecemeal, it gets
        // very annoying. The removal is best done here.
        // ASSUMPTION: if pSList[0].hKernelHandle is NULL then
        // pSList[1,2,etc].hKernelHandle are also NULL. There is no
        // reason for this to be not the case as of 3/2001.

        if (pDefCreate->CreateData.pSList[0].hKernelHandle == NULL)
        {
            pTemp = pDefCreate->pNext;
            *ppNext = pTemp;
            MemFree(pDefCreate->CreateData.pSList);
            MemFree(pDefCreate);
            pDefCreate = pTemp;
            continue;
        }

        // Save off all the fpVidmems since they will be overwritten

        for (i = 0; i < pDefCreate->CreateData.dwSCnt; i++)
        {
            pSurf = (PDDSURFHANDLE) pDefCreate->CreateData.pSList[i].hKernelHandle;
            pVidmem[i] = pSurf->fpVidMem;
        }

        // Attempt to resurrect

        pDefCreate->CreateData.bReUse = TRUE;
        hr = DdCreateSurface(&pDefCreate->CreateData);
        if (SUCCEEDED(hr))
        {
            for (i = 0; i < pDefCreate->CreateData.dwSCnt; i++)
            {
                pSurf = (PDDSURFHANDLE) pDefCreate->CreateData.pSList[i].hKernelHandle;

                // Reset DDSURF_SYSMEMALLOCATED to keep DdLock below happy

                pSurf->dwFlags &= ~DDSURF_SYSMEMALLOCATED;

                // Lock and copy

                ZeroMemory(&LockData, sizeof(LockData));
                LockData.hDD = hDD;
                LockData.hSurface = pSurf;
                hr = DdLock(&LockData);
                if (SUCCEEDED(hr))
                {
                    SliceSrc = (BYTE*)pVidmem[i];
                    SliceDst = (BYTE*)LockData.lpSurfData;
                    Width = pDefCreate->CreateData.pSList[i].cpWidth;
                    Height = pDefCreate->CreateData.pSList[i].cpHeight;
                    Depth = pDefCreate->CreateData.pSList[i].cpDepth;
                    if (!(pDefCreate->CreateData.Type == D3DRTYPE_VOLUME ||
                        pDefCreate->CreateData.Type == D3DRTYPE_VOLUMETEXTURE))
                    {
                        Depth = 1;
                    }
                    for (j = 0; j < Depth; ++j)
                    {
                        RowSrc = SliceSrc;
                        RowDst = SliceDst;
                        for (k = 0; k < Height; ++k)
                        {
                            CopyMemory(RowDst, RowSrc, min(LockData.lPitch, (LONG)Width * 8));
                            RowSrc += Width * 8;
                            RowDst += LockData.lPitch;
                        }
                        SliceSrc += Width * Height * 8;
                        SliceDst += LockData.lSlicePitch;
                    }

                    ZeroMemory(&UnlockData, sizeof(UnlockData));
                    UnlockData.hDD = hDD;
                    UnlockData.hSurface = pSurf;
                    hr = DdUnlock(&UnlockData);
                    if (FAILED(hr))
                    {
                        // TODO: Handle/(ignore?) failure 
                        DPF(0,"Unlock failed when resurrecting driver managed surface.");
                    }
                }
                else
                {
                    // TODO: Handle/(ignore?) failure 
                    DPF(0,"Lock failed when resurrecting driver managed surface. Texture may go missing.");
                }

                // Free the temporary fpVidmem that we allocated in CreateVidmemSurface
            
                MemFree((VOID*)pVidmem[i]);
            }

            // Remove from list and freeup all memory
     
            pTemp = pDefCreate->pNext;
            *ppNext = pTemp;
            MemFree(pDefCreate->CreateData.pSList);
            MemFree(pDefCreate);
            pDefCreate = pTemp;
        }
        else
        {
            // We set ReUse to FALSE to indicate that we were not able to resurrect
            pDefCreate->CreateData.bReUse = FALSE;

            ppNext = &(pDefCreate->pNext);
            pDefCreate = pDefCreate->pNext;
        }
    }

    if (pDeviceHandle->pDeferList != NULL)
    {
        // TODO:
        // Ummm, we were not able to resurrect. This may be due to out of memory
        // or if a mode switch happened as we were trying to Reset (ACK!). The
        // former probably needs to be reported to the app. The latter is
        // probably harmless, because the app will eventually realize this and
        // try again.
        DPF(0,"Unable to resurrect all driver managed surfaces.");
    }
}
                     

/*****************************Private*Routine******************************\
* D3D8AreVidmemSurfaces
* 15-Dec-1999 -by- smac
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "D3D8DoVidmemSurfacesExist "

BOOL
APIENTRY
D3D8DoVidmemSurfacesExist (
    HANDLE hDD
   )
{
    PDDDEVICEHANDLE pDeviceHandle = (PDDDEVICEHANDLE) hDD;
    PDDSURFHANDLE pSurf;

    // Walk the list and return TRUE is we find any surfaces that are either
    // local or nonlocal vidmem.

    pSurf = pDeviceHandle->pSurfList;
    while (pSurf != NULL)
    {
        if ((pSurf->Pool == D3DPOOL_LOCALVIDMEM) ||
            (pSurf->Pool == D3DPOOL_NONLOCALVIDMEM) ||
            (pSurf->dwFlags & DDSURF_TREATASVIDMEM))
        {
#if DBG
            DPF(0,"The following D3DPOOL_DEFAULT surfaces/buffers/textures still exist");
            pSurf = pDeviceHandle->pSurfList;
            while (pSurf != NULL)
            {
                if ((pSurf->Pool == D3DPOOL_LOCALVIDMEM) ||
                    (pSurf->Pool == D3DPOOL_NONLOCALVIDMEM) ||
                    (pSurf->dwFlags & DDSURF_TREATASVIDMEM))
                {
                    DebugPrintSurfaceInfo(pSurf);
                }
                pSurf = pSurf->pNext;
            }
#endif

            return TRUE;
        }
        pSurf = pSurf->pNext;
    }

    // Is this the first time that the device has become ready?
    if (!(pDeviceHandle->dwFlags & DDDEVICE_READY) &&
        (pDeviceHandle->bDeviceLost))
    {
        pDeviceHandle->dwFlags |= DDDEVICE_READY;
        if (++NumReadyDevices == NumDevices)
        {
            InformDriverFreeAGP(pDeviceHandle);
        }
    }

    return FALSE;
}

#undef DPF_MODNAME
#define DPF_MODNAME "D3D8BeginProfile"

HANDLE
APIENTRY
D3D8BeginProfile(
    char*           pDeviceName)
{
    return NULL;
}
#undef DPF_MODNAME
#define DPF_MODNAME "D3D8EndProfile"

void
APIENTRY
D3D8EndProfile(
    HANDLE  Handle)
{
}

DWORD APIENTRY D3D8SetCooperativeLevel(
    HANDLE hDD,
    HWND hWnd,
    DWORD dwFlags )
{
    return S_OK;
}

BOOL APIENTRY D3D8IsDummySurface(
    HANDLE hSurface )
{
    return FALSE;
}

VOID APIENTRY D3D8LoseDevice(
    HANDLE hDD )
{
    PDDDEVICEHANDLE pDeviceHandle = (PDDDEVICEHANDLE) hDD;
    PDDSURFHANDLE   pSurf;

    if (!pDeviceHandle->bDeviceLost)
    {
        pDeviceHandle->bDeviceLost  = TRUE;
        pSurf = pDeviceHandle->pSurfList;
        while (pSurf != NULL)
        {
            if (IS_SURFACE_LOOSABLE(pSurf))
            {
                FreeSurfaceObject(pSurf);
                pSurf->fpVidMem = (ULONG_PTR) NULL;
            }
            pSurf = pSurf->pNext;
        }
    }
}

