Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2169 lines
82 KiB

/*==========================================================================
*
* Copyright (C) 1994-1995 Microsoft Corporation. All Rights Reserved.
*
* File: ddcreate.c
* Content: DirectDraw create object.
* History:
* Date By Reason
* ==== == ======
* 31-dec-94 craige initial implementation
* 13-jan-95 craige re-worked to updated spec + ongoing work
* 21-jan-95 craige made 32-bit + ongoing work
* 13-feb-94 craige allow 32-bit callbacks
* 21-feb-95 craige disconnect anyone who forgot to do it themselves
* 27-feb-95 craige new sync. macros
* 06-mar-95 craige HEL integration
* 08-mar-95 craige new APIs
* 11-mar-95 craige palette stuff
* 15-mar-95 craige more HEL integration
* 19-mar-95 craige use HRESULTs, process termination cleanup fixes
* 27-mar-95 craige linear or rectangular vidmem
* 28-mar-95 craige removed Get/SetColorKey, added FlipToGDISurface
* 29-mar-95 craige reorg to only call driver once per creation, and
* to allow driver to load us first
* 01-apr-95 craige happy fun joy updated header file
* 06-apr-95 craige fill in free video memory
* 09-apr-95 craige fixed deadlock situation with a process having a lock
* on the primary surface while another process starts
* 12-apr-95 craige bug when driver object freed (extra leave csect)
* 13-apr-95 craige EricEng's little contribution to our being late
* 15-apr-95 craige fail load if no DD components present
* 06-may-95 craige use driver-level csects only
* 09-may-95 craige escape call to get 32-bit DLL
* 12-may-95 craige added DirectDrawEnumerate; use GUIDs in DirectDrawCreate
* 14-may-95 craige call DoneExclusiveMode during CurrentProcessCleanup
* 15-may-95 craige restore display mode on a per-process basis
* 19-may-95 craige memory leak on mode change
* 23-may-95 craige added Flush, GetBatchLimit, SetBatchLimit
* 24-may-95 craige plugged another memory leak; allow fourcc codes &
* number of vmem heaps to change
* 26-may-95 craige somebody freed the vmem heaps and then tried to
* free the surfaces!
* 28-may-95 craige unicode support; make sure blt means at least srccopy
* 05-jun-95 craige removed GetVersion, FreeAllSurfaces, DefWindowProc;
* change GarbageCollect to Compact
* 06-jun-95 craige call RestoreDisplayMode
* 07-jun-95 craige removed DCLIST
* 12-jun-95 craige new process list stuff
* 16-jun-95 craige new surface structure
* 18-jun-95 craige specify pitch for rectangular memory; deadlock
* with MemAlloc16 if we don't take the DLL lock
* 25-jun-95 craige one ddraw mutex
* 26-jun-95 craige reorganized surface structure
* 27-jun-95 craige replaced batch limit/flush stuff with BltBatch
* 28-jun-95 craige ENTER_DDRAW at very start of fns
* 02-jul-95 craige new registry format
* 03-jul-95 craige YEEHAW: new driver struct; SEH
* 06-jul-95 craige RemoveFromDriverList was screwing up links
* 07-jul-95 craige added pdevice stuff
* 08-jul-95 craige call InvalidateAllSurfaces
* 10-jul-95 craige support SetOverlayPosition
* 11-jul-95 craige validate pdevice is from a dibeng mini driver;
* fail aggregation calls; one ddraw object/process
* 13-jul-95 craige ENTER_DDRAW is now the win16 lock; need to
* leave Win16 lock while doing ExtEscape calls
* 14-jul-95 craige allow driver to specify heap is already allocated
* 15-jul-95 craige invalid HDC set in emulation only
* 18-jul-95 craige need to initialize dwPreferredMode
* 20-jul-95 craige internal reorg to prevent thunking during modeset
* 20-jul-95 toddla zero DDHALINFO before thunking in case nobody home.
* 22-jul-95 craige emulation only needs to initialize correctly
* 29-jul-95 toddla added DEBUG code to clear driver caps
* 31-jul-95 toddla added DD_HAL_VERSION
* 31-jul-95 craige set DDCAPS_BANKSWITCHED
* 01-aug-95 toddla added dwPDevice to DDRAWI_DIRECTDRAW_GBL
* 10-aug-95 craige validate alignment fields
* 13-aug-95 craige check DD_HAL_VERSION & set DDCAPS2_CERTIFIED
* 21-aug-95 craige mode X support
* 27-aug-95 craige bug 738: use GUID instead of IID
* 05-sep-95 craige bug 814
* 08-sep-95 craige bug 845: reset driver callbacks every time
* 09-sep-95 craige bug 949: don't allow ddraw to run in 4bpp
* bug 951: NULL out fn tables at reset
* 10-sep-95 toddla dont allow DirectDrawCreate to work for < 8bpp mode.
* 10-sep-95 toddla added Message box when DirectDrawCreate fails
* 20-sep-95 craige made primary display desc. a string resource
* 21-sep-95 craige bug 1215: let ddraw16 know about certified for modex
* 21-nov-95 colinmc made Direct3D a queryable interface off DirectDraw
* 27-nov-95 colinmc new member to return available vram of a given type
* (defined by DDSCAPS)
* 05-dec-95 colinmc changed DDSCAPS_TEXTUREMAP => DDSCAPS_TEXTURE for
* consitency with Direct3D
* 09-dec-95 colinmc execute buffer support
* 15-dec-95 colinmc fixed bug setting HAL up for execute buffers
* 25-dec-95 craige added InternalDirectDrawCreate for ClassFactory work
* 31-dec-95 craige more ClassFactory work
* 04-jan-96 kylej add driver interface structures
* 22-jan-96 jeffno NT driver conversation in createSurface.
* Since vidmem ptrs can legally be 0 for kernel, added
* DDRAWISURFACEGBL_ISGDISURFACE and use that to find gdi
* 02-feb-96 kylej Move HAL function pointers to local object
* 28-feb-96 kylej Change DDHALINFO structure
* 02-mar-96 colinmc Repulsive hack to support interim drivers
* 06-mar-96 kylej init HEL even with non-display drivers
* 13-mar-96 craige Bug 7528: hw that doesn't have modex
* 13-mar-96 jeffno Dynamic mode switch support for NT
* Register process IDs with NT kernel stuff
* 16-mar-96 colinmc Callback tables now initialized in dllmain
* 18-mar-96 colinmc Bug 13545: Independent clippers cleanup
* 22-mar-96 colinmc Bug 13316: uninitialized interfaces
* 23-mar-96 colinmc Bug 12252: Direct3D not cleaned up properly on crash
* 14-apr-96 colinmc Bug 17736: No driver notification of flip to GDI
* 16-apr-96 colinmc Bug 17921: Remove interim driver support
* 19-apr-96 colinmc Bug 18059: New caps bit to indicate that driver
* can't interleave 2D and 3D operations during scene
* rendering
* 11-may-96 colinmc Bug 22293: Now validate GUID passed to DirectDraw
* Create in retail as well as debug
* 16-may-96 colinmc Bug 23215: Not checking for a mode index of -1
* on driver initialization
* 27-may-96 kylej Bug 24595: Set Certified bit after call to
* FakeDDCreateDriverObject.
* 26-jun-96 colinmc Bug 2041: DirectDraw needs time bomb
* 22-jul-96 colinmc Work Item: Minimal stackable driver support
* 23-aug-96 craige registry entries for sw only and modex only
* 31-aug-96 colinmc Removed erroneous time bomb
* 03-sep-96 craige App compatibilty stuff
* 01-oct-96 ketand added GetAvailVidMem entrypoint for driver callbacks
* 05-sep-96 colinmc Work Item: Removing the restriction on taking Win16
* lock on VRAM surfaces (not including the primary)
* 10-oct-96 colinmc Refinements of the Win16 locking stuff
* 12-oct-96 colinmc Improvements to Win16 locking code to reduce virtual
* memory usage
* 15-oct-96 toddla support multimonitor
* 09-nov-96 colinmc Fixed problem with old and new drivers not working
* with DirectDraw
* 17-nov-96 colinmc Added ability to use PrintScrn key to snapshot
* DirectDraw applications.
* 08-dec-96 colinmc Initial AGP support
* 21-jan-97 ketand Added a rectMonitor to lpDD_gbl to allow for correct clipping
* on multi-monitor systems.
* 25-jan-97 nwilt Instance GUID in GetDriverInfo struct
* Query for D3DCallbacks2 w/no deps on D3D
* 27-jan-97 colinmc Fixed problem with multi-mon on emulated displays
* 27-jan-97 ketand Multi-mon. Remove bad globals; pass them explicitly. Fix ATTENTIONs.
* 29-jan-97 smac Removed old ring 0 code
* 30-jan-97 colinmc Work item 4125: Add time bomb for beta
* 30-jan-97 jeffno Allow surfaces wider than the primary
* 30-jan-97 ketand Only enumerate secondaries for multi-mon systems.
* 01-feb-97 colinmc Bug 5457: Fixed Win16 lock problem causing hang
* with mutliple AMovie instances on old cards
* 07-feb-97 ketand Zero DisplayDevice struct between calls to EnumDisplayDevices.
* Fix memory leak w.r.t. GetAndValidateNewHalInfo
* 24-feb-97 ketand Update Rects whenever a display change occurs.
* 24-feb-97 ketand Add a dwContext to GetDriverInfoData
* 03-mar-97 smac Added kernel mode interface
* 03-mar-97 jeffno Work item: Extended surface memory alignment
* 08-mar-97 colinmc Added support for DMA style AGP usage
* 11-mar-97 jeffno Asynchronous DMA support
* 11-mar-97 nwilt Fail driver create if driver exports some DrawPrimitive
* exports without exporting all of them.
* 13-mar-97 colinmc Bug 6533: Pass uncached flag to VMM correctly
* 20-mar-97 nwilt #6625 and D3D extended caps
* 24-mar-97 jeffno Optimized Surfaces
* 13-may-97 colinmc AGP support on OSR 2.1 systems
* 26-may-97 nwilt Fail driver create if driver sets D3DDEVCAPS_DRAWPRIMTLVERTEX
* without exporting the callbacks.
* 31-jul-97 jvanaken Bug 7093: Ensure unique HDC for each process/driver pair
* in a multimonitor system.
* 16-sep-97 jeffno DirectDrawEnumerateEx
* 30-sep-97 jeffno IDirectDraw4
* 31-oct-97 johnstep Persistent-content surfaces for Windows 9x
* 05-nov-97 jvanaken Support for master sprite list in SetSpriteDisplayList
*
***************************************************************************/
extern "C" {
#include "ddrawpr.h"
#ifdef WINNT
#include "ddrawgdi.h"
#define BUILD_DDDDK
#include "d3dhal.h"
#endif
#ifdef WIN95
#include "d3dhal.h"
#endif
} // extern C
#include "pixel.hpp"
#ifdef DEBUG
#define static
#endif
#undef DPF_MODNAME
#define DPF_MODNAME "DirectDrawObjectCreate"
#define DISPLAY_STR "display"
#define D3DFORMAT_OP_BACKBUFFER 0x00000020L
char g_szPrimaryDisplay[MAX_DRIVER_NAME] = "";
void getPrimaryDisplayName(void);
#ifndef WIN16_SEPARATE
#ifdef WIN95
CRITICAL_SECTION ddcCS = {0};
#define ENTER_CSDDC() EnterCriticalSection(&ddcCS)
#define LEAVE_CSDDC() LeaveCriticalSection(&ddcCS)
#else
#define ENTER_CSDDC()
#define LEAVE_CSDDC()
#endif
#else
#define ENTER_CSDDC()
#define LEAVE_CSDDC()
#endif
/*
* DISPLAY_DEVICEA
*
* define a local copy of the structures and constants needed
* to call EnumDisplayDevices
*
*/
#ifndef DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001
#define DISPLAY_DEVICE_MULTI_DRIVER 0x00000002
#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004
#define DISPLAY_DEVICE_MIRRORING_DRIVER 0x00000008
#define DISPLAY_DEVICE_VGA 0x00000010
typedef struct {
DWORD cb;
CHAR DeviceName[MAX_DRIVER_NAME];
CHAR DeviceString[128];
DWORD StateFlags;
} DISPLAY_DEVICEA;
#endif
#undef DPF_MODNAME
#define DPF_MODNAME "MakeDX8Caps"
void
MakeDX8Caps( D3DCAPS8 *pCaps8,
const D3D8_GLOBALDRIVERDATA* pGblDrvData,
const D3DHAL_D3DEXTENDEDCAPS* pExtCaps )
{
// we shouldn't memset pCaps8 as members like Caps, Caps2, Caps3 (dwSVCaps) and
// CursorCaps are already set by Thunk layer
pCaps8->DevCaps = pGblDrvData->hwCaps.dwDevCaps;
pCaps8->PrimitiveMiscCaps = pGblDrvData->hwCaps.dpcTriCaps.dwMiscCaps;
pCaps8->RasterCaps = pGblDrvData->hwCaps.dpcTriCaps.dwRasterCaps;
pCaps8->ZCmpCaps = pGblDrvData->hwCaps.dpcTriCaps.dwZCmpCaps;
pCaps8->SrcBlendCaps = pGblDrvData->hwCaps.dpcTriCaps.dwSrcBlendCaps;
pCaps8->DestBlendCaps = pGblDrvData->hwCaps.dpcTriCaps.dwDestBlendCaps;
pCaps8->AlphaCmpCaps = pGblDrvData->hwCaps.dpcTriCaps.dwAlphaCmpCaps;
pCaps8->ShadeCaps = pGblDrvData->hwCaps.dpcTriCaps.dwShadeCaps;
pCaps8->TextureCaps = pGblDrvData->hwCaps.dpcTriCaps.dwTextureCaps;
pCaps8->TextureFilterCaps = pGblDrvData->hwCaps.dpcTriCaps.dwTextureFilterCaps;
// Adjust the texture filter caps for the legacy drivers that
// set only the legacy texture filter caps and not the newer ones.
if ((pCaps8->TextureFilterCaps & (D3DPTFILTERCAPS_MINFPOINT |
D3DPTFILTERCAPS_MAGFPOINT |
D3DPTFILTERCAPS_MIPFPOINT |
D3DPTFILTERCAPS_MINFLINEAR |
D3DPTFILTERCAPS_MAGFLINEAR |
D3DPTFILTERCAPS_MIPFLINEAR)) == 0)
{
if (pCaps8->TextureFilterCaps & D3DPTFILTERCAPS_NEAREST)
{
pCaps8->TextureFilterCaps |= (D3DPTFILTERCAPS_MINFPOINT |
D3DPTFILTERCAPS_MAGFPOINT);
}
if (pCaps8->TextureFilterCaps & D3DPTFILTERCAPS_LINEAR)
{
pCaps8->TextureFilterCaps |= (D3DPTFILTERCAPS_MINFLINEAR |
D3DPTFILTERCAPS_MAGFLINEAR);
}
if (pCaps8->TextureFilterCaps & D3DPTFILTERCAPS_MIPNEAREST)
{
pCaps8->TextureFilterCaps |= (D3DPTFILTERCAPS_MINFPOINT |
D3DPTFILTERCAPS_MAGFPOINT |
D3DPTFILTERCAPS_MIPFPOINT);
}
if (pCaps8->TextureFilterCaps & D3DPTFILTERCAPS_MIPLINEAR)
{
pCaps8->TextureFilterCaps |= (D3DPTFILTERCAPS_MINFLINEAR |
D3DPTFILTERCAPS_MAGFLINEAR |
D3DPTFILTERCAPS_MIPFPOINT);
}
if (pCaps8->TextureFilterCaps & D3DPTFILTERCAPS_LINEARMIPNEAREST)
{
pCaps8->TextureFilterCaps |= (D3DPTFILTERCAPS_MINFPOINT |
D3DPTFILTERCAPS_MAGFPOINT |
D3DPTFILTERCAPS_MIPFLINEAR);
}
if (pCaps8->TextureFilterCaps & D3DPTFILTERCAPS_LINEARMIPLINEAR)
{
pCaps8->TextureFilterCaps |= (D3DPTFILTERCAPS_MINFLINEAR |
D3DPTFILTERCAPS_MAGFLINEAR |
D3DPTFILTERCAPS_MIPFLINEAR);
}
}
pCaps8->TextureAddressCaps = pGblDrvData->hwCaps.dpcTriCaps.dwTextureAddressCaps;
// Set the cube-texture filter caps only if the device supports
// cubemaps.
if (pCaps8->TextureCaps & D3DPTEXTURECAPS_CUBEMAP)
{
pCaps8->CubeTextureFilterCaps = pGblDrvData->hwCaps.dpcTriCaps.dwTextureFilterCaps;
}
const D3DPRIMCAPS* pTC = &pGblDrvData->hwCaps.dpcTriCaps;
const D3DPRIMCAPS* pLC = &pGblDrvData->hwCaps.dpcLineCaps;
if (pLC->dwTextureCaps) pCaps8->LineCaps |= D3DLINECAPS_TEXTURE ;
if (pLC->dwZCmpCaps == pTC->dwZCmpCaps)
pCaps8->LineCaps |= D3DLINECAPS_ZTEST;
if ( (pLC->dwSrcBlendCaps == pTC->dwSrcBlendCaps) &&
(pLC->dwDestBlendCaps == pTC->dwDestBlendCaps) )
pCaps8->LineCaps |= D3DLINECAPS_BLEND;
if (pLC->dwAlphaCmpCaps == pTC->dwAlphaCmpCaps)
pCaps8->LineCaps |= D3DLINECAPS_ALPHACMP;
if (pLC->dwRasterCaps & (D3DPRASTERCAPS_FOGVERTEX|D3DPRASTERCAPS_FOGTABLE))
pCaps8->LineCaps |= D3DLINECAPS_FOG;
if( pExtCaps->dwMaxTextureWidth == 0 )
pCaps8->MaxTextureWidth = 256;
else
pCaps8->MaxTextureWidth = pExtCaps->dwMaxTextureWidth;
if( pExtCaps->dwMaxTextureHeight == 0 )
pCaps8->MaxTextureHeight = 256;
else
pCaps8->MaxTextureHeight = pExtCaps->dwMaxTextureHeight;
pCaps8->MaxTextureRepeat = pExtCaps->dwMaxTextureRepeat;
pCaps8->MaxTextureAspectRatio = pExtCaps->dwMaxTextureAspectRatio;
pCaps8->MaxAnisotropy = pExtCaps->dwMaxAnisotropy;
pCaps8->MaxVertexW = pExtCaps->dvMaxVertexW;
pCaps8->GuardBandLeft = pExtCaps->dvGuardBandLeft;
pCaps8->GuardBandTop = pExtCaps->dvGuardBandTop;
pCaps8->GuardBandRight = pExtCaps->dvGuardBandRight;
pCaps8->GuardBandBottom = pExtCaps->dvGuardBandBottom;
pCaps8->ExtentsAdjust = pExtCaps->dvExtentsAdjust;
pCaps8->StencilCaps = pExtCaps->dwStencilCaps;
pCaps8->FVFCaps = pExtCaps->dwFVFCaps;
pCaps8->TextureOpCaps = pExtCaps->dwTextureOpCaps;
pCaps8->MaxTextureBlendStages = pExtCaps->wMaxTextureBlendStages;
pCaps8->MaxSimultaneousTextures = pExtCaps->wMaxSimultaneousTextures;
pCaps8->VertexProcessingCaps = pExtCaps->dwVertexProcessingCaps;
pCaps8->MaxActiveLights = pExtCaps->dwMaxActiveLights;
pCaps8->MaxUserClipPlanes = pExtCaps->wMaxUserClipPlanes;
pCaps8->MaxVertexBlendMatrices = pExtCaps->wMaxVertexBlendMatrices;
if (pCaps8->MaxVertexBlendMatrices == 1)
pCaps8->MaxVertexBlendMatrices = 0;
//
// Stuff in the DX8 caps that cannot be reported by the pre DX8 drivers
//
pCaps8->MaxPointSize = 0;
pCaps8->MaxPrimitiveCount = 0xffff;
pCaps8->MaxVertexIndex = 0xffff;
pCaps8->MaxStreams = 0;
pCaps8->MaxStreamStride = 255;
pCaps8->MaxVertexBlendMatrixIndex = 0;
pCaps8->MaxVolumeExtent = 0;
// Format is 8.8 in bottom of DWORD
pCaps8->VertexShaderVersion = D3DVS_VERSION(0,0);
pCaps8->MaxVertexShaderConst = 0;
pCaps8->PixelShaderVersion = D3DPS_VERSION(0,0);
pCaps8->MaxPixelShaderValue = 1.0f;
} // MakeDX8Caps
/*
* xxxEnumDisplayDevices
*
* wrapper around the new Win32 API EnumDisplayDevices
* uses GetProcAddress() so we run on Win95.
*
* this function exists in NT 4.0 and Win97 (Memphis) but not Win95
*
*/
BOOL xxxEnumDisplayDevicesA(LPVOID lpUnused, DWORD iDevice, DISPLAY_DEVICEA *pdd, DWORD dwFlags)
{
HMODULE h = GetModuleHandle("USER32");
BOOL (WINAPI *pfnEnumDisplayDevices)(LPVOID, DWORD, DISPLAY_DEVICEA *, DWORD);
*((void **)&pfnEnumDisplayDevices) = GetProcAddress(h,"EnumDisplayDevicesA");
//
// NT 4.0 had a EnumDisplayDevicesA but it does not have the same
// number of params, so ignore it unless a GetMonitorInfoA exists too.
//
if (GetProcAddress(h,"GetMonitorInfoA") == NULL)
pfnEnumDisplayDevices = NULL;
if (pfnEnumDisplayDevices)
{
return (*pfnEnumDisplayDevices)(lpUnused, iDevice, pdd, dwFlags);
}
//else we emulate the function for 95, NT4:
if (iDevice > 0)
return FALSE;
pdd->StateFlags = DISPLAY_DEVICE_PRIMARY_DEVICE;
lstrcpy(pdd->DeviceName, DISPLAY_STR);
LoadString(g_hModule, IDS_PRIMARYDISPLAY, pdd->DeviceString, sizeof(pdd->DeviceString));
return TRUE;
}
// Multi-monitor defines; these are wrong in the TRANGO tree;
// so I need to define them here explicitly. When we move to
// something that matches Memphis/NT5 then we can remove these
#undef SM_XVIRTUALSCREEN
#undef SM_YVIRTUALSCREEN
#undef SM_CXVIRTUALSCREEN
#undef SM_CYVIRTUALSCREEN
#undef SM_CMONITORS
#define SM_XVIRTUALSCREEN 76
#define SM_YVIRTUALSCREEN 77
#define SM_CXVIRTUALSCREEN 78
#define SM_CYVIRTUALSCREEN 79
#define SM_CMONITORS 80
#ifndef ENUM_CURRENT_SETTINGS
#define ENUM_CURRENT_SETTINGS ((DWORD)-1)
#endif
#ifdef WINNT
// This function gets the device rect by calling GetMonitorInfo.
// On Win98, we got this by calling EnumDisplaySettings, but this
// doesn't work on NT5 and reading the documentation, it never
// indicates that it should work, so we'll just do it the documented
// way.
HRESULT GetNTDeviceRect(LPSTR pDriverName, LPRECT lpRect)
{
MONITORINFO MonInfo;
HMONITOR hMon;
MonInfo.cbSize = sizeof(MONITORINFO);
if (_stricmp(pDriverName, DISPLAY_STR) == 0)
{
hMon = GetMonitorFromDeviceName(g_szPrimaryDisplay);
}
else
{
hMon = GetMonitorFromDeviceName(pDriverName);
}
if (hMon != NULL)
{
if (GetMonitorInfo(hMon, &MonInfo) != 0)
{
CopyMemory(lpRect, &MonInfo.rcMonitor, sizeof(RECT));
return S_OK;
}
}
return E_FAIL;
}
#endif
/*
* IsVGADevice()
*
* determine if the passed device name is a VGA
*
*/
BOOL IsVGADevice(LPSTR szDevice)
{
//
// assume "DISPLAY" and "DISPLAY1" are VGA devices
//
if ((_stricmp(szDevice, DISPLAY_STR) == 0) ||
((szDevice[0] == '\\') &&
(szDevice[1] == '\\') &&
(szDevice[2] == '.')))
{
return TRUE;
}
return FALSE;
}
/*
* This function is currently only used in NT
*/
#ifdef WINNT
BOOL GetDDStereoMode(LPDDRAWI_DIRECTDRAW_GBL pdrv,
DWORD dwWidth,
DWORD dwHeight,
DWORD dwBpp,
DWORD dwRefreshRate)
{
DDHAL_GETDRIVERINFODATA gdidata;
HRESULT hres;
DDSTEREOMODE ddStereoMode;
DDASSERT(pdrv != NULL);
/*
* If driver does not support GetDriverInfo callback, it also
* has no extended capabilities to report, so we're done.
*/
if (!VALIDEX_CODE_PTR (pdrv->pGetDriverInfo))
{
return FALSE;
}
/*
* The mode can't be stereo if the driver doesn't support it...
*/
if (0 == (pdrv->ddCaps.dwCaps2 & DDCAPS2_STEREO))
{
return FALSE;
}
ZeroMemory(&ddStereoMode, sizeof(DDSTEREOMODE));
ddStereoMode.dwSize=sizeof(DDSTEREOMODE);
ddStereoMode.dwWidth=dwWidth;
ddStereoMode.dwHeight=dwHeight;
ddStereoMode.dwBpp=dwBpp;
ddStereoMode.dwRefreshRate=dwRefreshRate;
ddStereoMode.bSupported = TRUE;
/*
* Get the actual driver data
*/
memset(&gdidata, 0, sizeof(gdidata));
gdidata.dwSize = sizeof(gdidata);
gdidata.dwFlags = 0;
gdidata.guidInfo = GUID_DDStereoMode;
gdidata.dwExpectedSize = sizeof(DDSTEREOMODE);
gdidata.lpvData = &ddStereoMode;
gdidata.ddRVal = E_FAIL;
// Pass a context variable so that the driver
// knows which instance of itself to use
// w.r.t. this function. These are different
// values on Win95 and NT.
#ifdef WIN95
gdidata.dwContext = pdrv->dwReserved3;
#else
gdidata.dwContext = pdrv->hDD;
#endif
return TRUE;
} /* GetDDStereoMode */
#endif //WINNT
/*
* doneDC
*/
void DD_DoneDC(HDC hdc_dd)
{
if (hdc_dd != NULL)
{
DPF(5, "DeleteDC 0x%x", hdc_dd);
DeleteDC(hdc_dd);
hdc_dd = NULL;
}
} /* doneDC */
#undef DPF_MODNAME
#define DPF_MODNAME "DirectDrawCreate"
/*
* createDC
*
* create a new DC given a device name.
* doneDC() should be called to free DC
*
* the following are valid for device names:
*
* DISPLAY - the main display device via CreateDC("DISPLAY", ...)
* this is the normal case.
*
* foobar - the foobar.drv via CreateDC("foobar", ...)
* used for secondary displays listed in the registry
*
* \\.\DisplayX - display device X via CreateDC(NULL,"\\.\DisplayX",...)
* used on Memphis and NT5 for secondary displays
*
*/
HDC DD_CreateDC(LPSTR pdrvname)
{
HDC hdc;
UINT u;
DDASSERT(pdrvname != NULL);
#ifdef DEBUG
if (pdrvname[0] == 0)
{
DPF(3, "createDC() empty string!!!");
DebugBreak();
return NULL;
}
#endif
#if defined(NT_FIX) || defined(WIN95)
u = SetErrorMode(SEM_NOOPENFILEERRORBOX);
#endif
#ifdef WINNT
/*
* Note that DirectDraw refers to the driver for the primary monitor
* in a multimon system as "display", but NT uses "display" to refer
* to the desktop as a whole. To handle this mismatch, we store
* NT's name for the primary monitor's driver in g_szPrimaryDisplay
* and substitute this name in place of "display" in our calls to NT.
*/
if (GetSystemMetrics(SM_CMONITORS) > 1)
{
if ((_stricmp(pdrvname, DISPLAY_STR) == 0))
{
if (g_szPrimaryDisplay[0] == '\0')
{
getPrimaryDisplayName();
}
pdrvname = g_szPrimaryDisplay;
}
}
#endif //WINNT
DPF(5, "createDC(%s)", pdrvname);
if (pdrvname[0] == '\\' && pdrvname[1] == '\\' && pdrvname[2] == '.')
hdc = CreateDC(NULL, pdrvname, NULL, NULL);
else
hdc = CreateDC(pdrvname, NULL, NULL, NULL);
#if defined(NT_FIX) || defined(WIN95) //fix this error mode stuff
SetErrorMode(u);
#endif
if (hdc == NULL)
{
DPF(3, "createDC(%s) FAILED!", pdrvname);
}
return hdc;
} /* createDC */
/*****************************Private*Routine******************************\
* DdConvertFromOldFormat
*
* History:
* 13-Nov-1999 -by- Scott MacDonald [smac]
* Wrote it.
\**************************************************************************/
#undef DPF_MODNAME
#define DPF_MODNAME "ConvertFromOldFormat"
void ConvertFromOldFormat(LPDDPIXELFORMAT pOldFormat, D3DFORMAT *pNewFormat)
{
*pNewFormat = D3DFMT_UNKNOWN;
if (pOldFormat->dwFlags & DDPF_FOURCC)
{
*pNewFormat = (D3DFORMAT) pOldFormat->dwFourCC;
}
else if (pOldFormat->dwFlags == DDPF_RGB)
{
switch (pOldFormat->dwRGBBitCount)
{
case 8:
if ((pOldFormat->dwRBitMask == 0x000000e0) &&
(pOldFormat->dwGBitMask == 0x0000001c) &&
(pOldFormat->dwBBitMask == 0x00000003))
{
*pNewFormat = D3DFMT_R3G3B2;
}
else
{
*pNewFormat = D3DFMT_P8;
}
break;
case 16:
if ((pOldFormat->dwRBitMask == 0x0000f800) &&
(pOldFormat->dwGBitMask == 0x000007e0) &&
(pOldFormat->dwBBitMask == 0x0000001f))
{
*pNewFormat = D3DFMT_R5G6B5;
}
else if ((pOldFormat->dwRBitMask == 0x00007c00) &&
(pOldFormat->dwGBitMask == 0x000003e0) &&
(pOldFormat->dwBBitMask == 0x0000001f))
{
*pNewFormat = D3DFMT_X1R5G5B5;
}
else if ((pOldFormat->dwRBitMask == 0x00000f00) &&
(pOldFormat->dwGBitMask == 0x000000f0) &&
(pOldFormat->dwBBitMask == 0x0000000f))
{
*pNewFormat = D3DFMT_X4R4G4B4;
}
break;
case 24:
if ((pOldFormat->dwRBitMask == 0x00ff0000) &&
(pOldFormat->dwGBitMask == 0x0000ff00) &&
(pOldFormat->dwBBitMask == 0x000000ff))
{
*pNewFormat = D3DFMT_R8G8B8;
}
break;
case 32:
if ((pOldFormat->dwRBitMask == 0x00ff0000) &&
(pOldFormat->dwGBitMask == 0x0000ff00) &&
(pOldFormat->dwBBitMask == 0x000000ff))
{
*pNewFormat = D3DFMT_X8R8G8B8;
}
break;
}
}
else if (pOldFormat->dwFlags == (DDPF_RGB | DDPF_ALPHAPIXELS))
{
switch (pOldFormat->dwRGBBitCount)
{
case 16:
if ((pOldFormat->dwRGBAlphaBitMask == 0x0000FF00) &&
(pOldFormat->dwRBitMask == 0x000000e0) &&
(pOldFormat->dwGBitMask == 0x0000001c) &&
(pOldFormat->dwBBitMask == 0x00000003))
{
*pNewFormat = D3DFMT_A8R3G3B2;
}
else if ((pOldFormat->dwRGBAlphaBitMask == 0x0000f000) &&
(pOldFormat->dwRBitMask == 0x00000f00) &&
(pOldFormat->dwGBitMask == 0x000000f0) &&
(pOldFormat->dwBBitMask == 0x0000000f))
{
*pNewFormat = D3DFMT_A4R4G4B4;
}
else if ((pOldFormat->dwRGBAlphaBitMask == 0x0000FF00) &&
(pOldFormat->dwRBitMask == 0x00000f00) &&
(pOldFormat->dwGBitMask == 0x000000f0) &&
(pOldFormat->dwBBitMask == 0x0000000f))
{
*pNewFormat = D3DFMT_A4R4G4B4;
}
else if ((pOldFormat->dwRGBAlphaBitMask == 0x00008000) &&
(pOldFormat->dwRBitMask == 0x00007c00) &&
(pOldFormat->dwGBitMask == 0x000003e0) &&
(pOldFormat->dwBBitMask == 0x0000001f))
{
*pNewFormat = D3DFMT_A1R5G5B5;
}
break;
case 32:
if ((pOldFormat->dwRGBAlphaBitMask == 0xff000000) &&
(pOldFormat->dwRBitMask == 0x00ff0000) &&
(pOldFormat->dwGBitMask == 0x0000ff00) &&
(pOldFormat->dwBBitMask == 0x000000ff))
{
*pNewFormat = D3DFMT_A8R8G8B8;
}
break;
}
}
#if 0
// We don't convert the old representation of A8 to
// the new format because there are some existing DX7 drivers
// that expose the old format but don't implement it correctly
// or completely. We've seen Blt failures, and Rendering failures.
// So this becomes a DX8+ only feature; in which case
// we will get a new-style format from the driver.
// MB43799
else if (pOldFormat->dwFlags == DDPF_ALPHA)
{
if (pOldFormat->dwAlphaBitDepth == 8)
{
*pNewFormat = D3DFMT_A8;
}
}
#endif
else if (pOldFormat->dwFlags & (DDPF_PALETTEINDEXED8 | DDPF_RGB))
{
switch (pOldFormat->dwRGBBitCount)
{
case 8:
if (pOldFormat->dwFlags == (DDPF_PALETTEINDEXED8 | DDPF_RGB))
{
*pNewFormat = D3DFMT_P8;
}
break;
case 16:
if (pOldFormat->dwFlags == (DDPF_PALETTEINDEXED8 |
DDPF_RGB |
DDPF_ALPHAPIXELS) &&
pOldFormat->dwRGBAlphaBitMask == 0xFF00)
{
*pNewFormat = D3DFMT_A8P8;
}
break;
}
}
else if (pOldFormat->dwFlags == DDPF_ZBUFFER)
{
switch (pOldFormat->dwZBufferBitDepth)
{
case 32:
if (pOldFormat->dwZBitMask == 0xffffffff)
{
*pNewFormat = D3DFMT_D32;
}
else if (pOldFormat->dwZBitMask == 0x00FFFFFF)
{
*pNewFormat = D3DFMT_X8D24;
}
else if (pOldFormat->dwZBitMask == 0xFFFFFF00)
{
*pNewFormat = D3DFMT_D24X8;
}
break;
case 16:
if (pOldFormat->dwZBitMask == 0xffff)
{
*pNewFormat = D3DFMT_D16_LOCKABLE;
}
break;
}
}
else if (pOldFormat->dwFlags == (DDPF_ZBUFFER | DDPF_STENCILBUFFER))
{
switch (pOldFormat->dwZBufferBitDepth)
{
case 32:
if ((pOldFormat->dwZBitMask == 0xffffff00) &&
(pOldFormat->dwStencilBitMask == 0x000000ff) &&
(pOldFormat->dwStencilBitDepth == 8))
{
*pNewFormat = D3DFMT_D24S8;
}
else if ((pOldFormat->dwZBitMask == 0x00ffffff) &&
(pOldFormat->dwStencilBitMask == 0xff000000) &&
(pOldFormat->dwStencilBitDepth == 8))
{
*pNewFormat = D3DFMT_S8D24;
}
else if ((pOldFormat->dwZBitMask == 0xffffff00) &&
(pOldFormat->dwStencilBitMask == 0x0000000f) &&
(pOldFormat->dwStencilBitDepth == 4))
{
*pNewFormat = D3DFMT_D24X4S4;
}
else if ((pOldFormat->dwZBitMask == 0x00ffffff) &&
(pOldFormat->dwStencilBitMask == 0x0f000000) &&
(pOldFormat->dwStencilBitDepth == 4))
{
*pNewFormat = D3DFMT_X4S4D24;
}
break;
case 16:
if ((pOldFormat->dwZBitMask == 0xfffe) &&
(pOldFormat->dwStencilBitMask == 0x0001) &&
(pOldFormat->dwStencilBitDepth == 1))
{
*pNewFormat = D3DFMT_D15S1;
}
else if ((pOldFormat->dwZBitMask == 0x7fff) &&
(pOldFormat->dwStencilBitMask == 0x8000) &&
(pOldFormat->dwStencilBitDepth == 1))
{
*pNewFormat = D3DFMT_S1D15;
}
break;
}
}
else if (pOldFormat->dwFlags == DDPF_LUMINANCE)
{
switch (pOldFormat->dwLuminanceBitCount)
{
case 8:
if (pOldFormat->dwLuminanceBitMask == 0xFF)
{
*pNewFormat = D3DFMT_L8;
}
break;
}
}
else if (pOldFormat->dwFlags == (DDPF_LUMINANCE | DDPF_ALPHAPIXELS))
{
switch (pOldFormat->dwLuminanceBitCount)
{
case 8:
if (pOldFormat->dwLuminanceBitMask == 0x0F &&
pOldFormat->dwLuminanceAlphaBitMask == 0xF0)
{
*pNewFormat = D3DFMT_A4L4;
}
case 16:
if (pOldFormat->dwLuminanceBitMask == 0x00FF &&
pOldFormat->dwLuminanceAlphaBitMask == 0xFF00)
{
*pNewFormat = D3DFMT_A8L8;
}
break;
}
}
else if (pOldFormat->dwFlags == DDPF_BUMPDUDV)
{
switch (pOldFormat->dwBumpBitCount)
{
case 16:
if (pOldFormat->dwBumpDuBitMask == 0xFF &&
pOldFormat->dwBumpDvBitMask == 0xFF00)
{
*pNewFormat = D3DFMT_V8U8;
}
break;
}
}
else if (pOldFormat->dwFlags == (DDPF_BUMPDUDV | DDPF_BUMPLUMINANCE))
{
switch (pOldFormat->dwBumpBitCount)
{
case 16:
if (pOldFormat->dwBumpDuBitMask == 0x001F &&
pOldFormat->dwBumpDvBitMask == 0x03E0 &&
pOldFormat->dwBumpLuminanceBitMask == 0xFC00)
{
*pNewFormat = D3DFMT_L6V5U5;
}
break;
case 32:
if (pOldFormat->dwBumpDuBitMask == 0x0000FF &&
pOldFormat->dwBumpDvBitMask == 0x00FF00 &&
pOldFormat->dwBumpLuminanceBitMask == 0xFF0000)
{
*pNewFormat = D3DFMT_X8L8V8U8;
}
break;
}
}
}
/*
* FetchDirectDrawData
*
* Go get new HAL info...
*/
void FetchDirectDrawData(
PD3D8_DEVICEDATA pBaseData,
void* pInitFunction,
D3DFORMAT Unknown16,
DDSURFACEDESC* pHalOpList,
DWORD NumHalOps)
{
BOOL bNewMode;
BOOL bRetVal;
UINT i=0;
BOOL bAlreadyAnOpList = FALSE;
LPDDPIXELFORMAT pZStencilFormatList=0;
DDSURFACEDESC *pTextureList=0;
D3D8_GLOBALDRIVERDATA D3DGlobalDriverData;
D3DHAL_D3DEXTENDEDCAPS D3DExtendedCaps;
BOOL bBackbuffersExist = FALSE;
BOOL bReset = FALSE;
ZeroMemory( &D3DGlobalDriverData, sizeof(D3DGlobalDriverData) );
ZeroMemory( &D3DExtendedCaps, sizeof(D3DExtendedCaps) );
if (pBaseData->hDD == NULL)
{
#ifdef WINNT
D3D8CreateDirectDrawObject(pBaseData->hDC,
pBaseData->DriverName,
&pBaseData->hDD,
pBaseData->DeviceType,
&pBaseData->hLibrary,
pInitFunction);
#else
D3D8CreateDirectDrawObject(&pBaseData->Guid,
pBaseData->DriverName,
&pBaseData->hDD,
pBaseData->DeviceType,
&pBaseData->hLibrary,
pInitFunction);
#endif
if (pBaseData->hDD == NULL)
{
#ifdef WINNT
DPF(1, "****DirectDraw/Direct3D DRIVER DISABLING ERROR****:NT Kernel mode would not create driver object... Failing over to emulation");
#endif
goto ErrorExit;
}
}
else
{
// If we already have 3D caps, then we are resetting
if ((pBaseData->DriverData.dwFlags & DDIFLAG_D3DCAPS8) &&
(pBaseData->DriverData.D3DCaps.DevCaps != 0))
{
bReset = TRUE;
}
}
// Now we can get the driver info...
// The first call returns the amount of space we need to allocate for the
// texture and z/stencil lists
UINT cTextureFormats;
UINT cZStencilFormats;
if (bReset)
{
// If we are ressting, we do not want to rebuild all of the caps, the
// format list, etc., but we still need to call the thunk layer because
// on NT this resets the kernel.
D3D8_DRIVERCAPS TempData;
D3D8_CALLBACKS TempCallbacks;
if (!D3D8ReenableDirectDrawObject(pBaseData->hDD,&bNewMode) ||
!D3D8QueryDirectDrawObject(pBaseData->hDD,
&TempData,
&TempCallbacks,
pBaseData->DriverName,
pBaseData->hLibrary,
&D3DGlobalDriverData,
&D3DExtendedCaps,
NULL,
NULL,
&cTextureFormats,
&cZStencilFormats))
{
goto ErrorExit;
}
pBaseData->DriverData.DisplayWidth = TempData.DisplayWidth;
pBaseData->DriverData.DisplayHeight = TempData.DisplayHeight;
pBaseData->DriverData.DisplayFormatWithAlpha = TempData.DisplayFormatWithAlpha;
pBaseData->DriverData.DisplayFormatWithoutAlpha = TempData.DisplayFormatWithoutAlpha;
pBaseData->DriverData.DisplayFrequency = TempData.DisplayFrequency;
}
else
{
MemFree (pBaseData->DriverData.pGDD8SupportedFormatOps);
pBaseData->DriverData.pGDD8SupportedFormatOps = NULL;
if (!D3D8ReenableDirectDrawObject(pBaseData->hDD,&bNewMode) ||
!D3D8QueryDirectDrawObject(pBaseData->hDD,
&pBaseData->DriverData,
&pBaseData->Callbacks,
pBaseData->DriverName,
pBaseData->hLibrary,
&D3DGlobalDriverData,
&D3DExtendedCaps,
NULL,
NULL,
&cTextureFormats,
&cZStencilFormats))
{
DPF(1, "****Direct3D DRIVER DISABLING ERROR****:First call to DdQueryDirectDrawObject failed!");
D3D8DeleteDirectDrawObject(pBaseData->hDD);
pBaseData->hDD = NULL;
goto ErrorExit;
}
// First we make space for the formats
// let's do memalloc for pTextureList just once, 3 extra for possible backbuffers
// 3 extra for D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET
pTextureList = (DDSURFACEDESC *) MemAlloc ((cTextureFormats+ cZStencilFormats + 6) * sizeof (*pTextureList));
if (pTextureList == NULL)
{
DPF_ERR("****Direct3D DRIVER DISABLING ERROR****:Unable to allocate memory for texture formats!");
D3D8DeleteDirectDrawObject(pBaseData->hDD);
pBaseData->hDD = NULL;
goto ErrorExit;
}
if (cZStencilFormats > 0)
{
pZStencilFormatList = (DDPIXELFORMAT *) MemAlloc (cZStencilFormats * sizeof (*pZStencilFormatList));
if (pZStencilFormatList == NULL)
{
DPF_ERR("****Direct3D DRIVER DISABLING ERROR****:Unable to allocate memory for Z/Stencil formats!");
D3D8DeleteDirectDrawObject(pBaseData->hDD);
pBaseData->hDD = NULL;
goto ErrorExit;
}
}
//Now that we've allocated space for the texture and z/stencil lists, we can go get em.
if (!D3D8QueryDirectDrawObject(pBaseData->hDD,
&pBaseData->DriverData,
&pBaseData->Callbacks,
pBaseData->DriverName,
pBaseData->hLibrary,
&D3DGlobalDriverData,
&D3DExtendedCaps,
pTextureList,
pZStencilFormatList,
&cTextureFormats,
&cZStencilFormats))
{
DPF_ERR("****Direct3D DRIVER DISABLING ERROR****:Second call to DdQueryDirectDrawObject failed!");
D3D8DeleteDirectDrawObject(pBaseData->hDD);
pBaseData->hDD = NULL;
goto ErrorExit;
}
// If no D3DCAPS8 was reported by the thunk layer, then the driver
// must be a pre-DX8 driver. We must sew together the
// D3DGlobalDriverData and the ExtendedCaps (which have to be reported).
// Note: The thunk layer already has plugged in the DDraw Caps such
// as the Caps, Caps2 and Caps3 (dwSVCaps).
if( (pBaseData->DriverData.dwFlags & DDIFLAG_D3DCAPS8) == 0 )
{
MakeDX8Caps( &pBaseData->DriverData.D3DCaps,
&D3DGlobalDriverData,
&D3DExtendedCaps );
pBaseData->DriverData.dwFlags |= DDIFLAG_D3DCAPS8;
}
else
{
// They reported the DX8 caps.
// Internally we check MaxPointSize if it is zero or not
// to determine if PointSprites are supported or not. So if a DX8 driver said 1.0
// set it to Zero
if (pBaseData->DriverData.D3DCaps.MaxPointSize == 1.0)
{
pBaseData->DriverData.D3DCaps.MaxPointSize = 0;
}
}
// There are some legacy caps that are reported by the drivers that
// we dont want the applications to see. Should weed them out here.
pBaseData->DriverData.D3DCaps.PrimitiveMiscCaps &= ~(D3DPMISCCAPS_MASKPLANES |
D3DPMISCCAPS_CONFORMANT);
pBaseData->DriverData.D3DCaps.DevCaps &= ~(D3DDEVCAPS_FLOATTLVERTEX |
D3DDEVCAPS_SORTINCREASINGZ | D3DDEVCAPS_SORTDECREASINGZ |
D3DDEVCAPS_SORTEXACT);
pBaseData->DriverData.D3DCaps.TextureCaps &= ~(D3DPTEXTURECAPS_TRANSPARENCY |
D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_COLORKEYBLEND);
pBaseData->DriverData.D3DCaps.VertexProcessingCaps &= ~(D3DVTXPCAPS_VERTEXFOG);
pBaseData->DriverData.D3DCaps.RasterCaps &= ~(D3DPRASTERCAPS_SUBPIXEL |
D3DPRASTERCAPS_SUBPIXELX | D3DPRASTERCAPS_STIPPLE |
D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT |
D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT |
D3DPRASTERCAPS_TRANSLUCENTSORTINDEPENDENT);
pBaseData->DriverData.D3DCaps.ShadeCaps &= ~(D3DPSHADECAPS_COLORFLATMONO |
D3DPSHADECAPS_COLORFLATRGB | D3DPSHADECAPS_COLORGOURAUDMONO |
D3DPSHADECAPS_COLORPHONGMONO | D3DPSHADECAPS_COLORPHONGRGB |
D3DPSHADECAPS_SPECULARFLATMONO | D3DPSHADECAPS_SPECULARFLATRGB |
D3DPSHADECAPS_SPECULARGOURAUDMONO | D3DPSHADECAPS_SPECULARPHONGMONO |
D3DPSHADECAPS_SPECULARPHONGRGB | D3DPSHADECAPS_ALPHAFLATBLEND |
D3DPSHADECAPS_ALPHAFLATSTIPPLED | D3DPSHADECAPS_ALPHAGOURAUDSTIPPLED |
D3DPSHADECAPS_ALPHAPHONGBLEND | D3DPSHADECAPS_ALPHAPHONGSTIPPLED |
D3DPSHADECAPS_FOGFLAT | D3DPSHADECAPS_FOGPHONG);
// Now we generate the list of supported ops from the texture format
// list and z/stencil list.
//
// A DX7 or older driver will return to us a simple list of pixel formats.
// We will take this list and convert it into a list of supported
// texture formats in the DX8 style. To that we will append any
// z/stencil formats.
//
// First step in generating supported op lists: see if the list is
// already a DX8 style format list. If it is (i.e. if any
// entries are DDPF_D3DFORMAT, then all we need to do is
// yank out the old-style entries (drivers are allowed to
// keep both so they can run against old runtimes).
for (i = 0; i < cTextureFormats; i++)
{
if (pTextureList[i].ddpfPixelFormat.dwFlags == DDPF_D3DFORMAT)
{
bAlreadyAnOpList = TRUE;
break;
}
}
if (bAlreadyAnOpList)
{
// mmmmm.... dx8 driver. We'll ignore its Z/stencil list because
// such a driver is supposed to put additional op entries in the
// "texture" list (i.e. the op list) for its z/stencil formats
// Now all we have to do is ZAP all the old-style entries.
for (i = 0; i < (INT)cTextureFormats; i++)
{
if (pTextureList[i].ddpfPixelFormat.dwFlags != DDPF_D3DFORMAT && i < (INT)cTextureFormats)
{
// ha! zap that evil old-style entry!
// (scroll the remainder of the list down
// to squish this entry)
DDASSERT(cTextureFormats > 0); //after all, we're in a for loop.
if (i < (INT)(cTextureFormats - 1))
{
memcpy(pTextureList + i,
pTextureList + i + 1,
sizeof(*pTextureList)*(cTextureFormats - i - 1));
}
cTextureFormats--;
i--;
}
}
// TODO: Remove this as soon as we think that drivers have caught up to
// our OP LIST changes.
for (i = 0; i < cTextureFormats; i++)
{
if (pTextureList[i].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_BACKBUFFER)
{
pTextureList[i].ddpfPixelFormat.dwOperations &= ~D3DFORMAT_OP_BACKBUFFER;
pTextureList[i].ddpfPixelFormat.dwOperations |= D3DFORMAT_OP_3DACCELERATION;
if (pBaseData->DeviceType == D3DDEVTYPE_HAL)
{
pTextureList[i].ddpfPixelFormat.dwOperations |= D3DFORMAT_OP_DISPLAYMODE;
}
}
}
// If it's a SW driver, we've got a lot of extra work to do.
if ((pBaseData->DeviceType == D3DDEVTYPE_REF) ||
(pBaseData->DeviceType == D3DDEVTYPE_SW))
{
// First, make sure that the SW driver didn't erroneuously report any
// D3DFORMAT_OP_DISPLAYMODE entries.
for (i = 0; i < cTextureFormats; i++)
{
if (pTextureList[i].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_DISPLAYMODE)
{
DPF_ERR("*****The SW driver is disabled because it claims to support D3DFORMAT_OP_DISPLAYMODE*****");
D3D8DeleteDirectDrawObject(pBaseData->hDD);
pBaseData->hDD = NULL;
goto ErrorExit;
}
}
// Now for the hard part. The HAL reports which display modes
// it can support, and the SW driver reports which display
// modes it can accelerate. We need to prune the SW list so
// that it matches the HW list.
for (i = 0; i < cTextureFormats; i++)
{
if (pTextureList[i].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_3DACCELERATION)
{
// Does the HAL support this mode?
if (IsSupportedOp ((D3DFORMAT) pTextureList[i].ddpfPixelFormat.dwFourCC,
pHalOpList,
NumHalOps,
D3DFORMAT_OP_DISPLAYMODE))
{
pTextureList[i].ddpfPixelFormat.dwOperations |= D3DFORMAT_OP_DISPLAYMODE;
}
else
{
pTextureList[i].ddpfPixelFormat.dwOperations &= ~D3DFORMAT_OP_3DACCELERATION;
}
}
}
}
// since we found one op-style entry, we shouldn't have
// killed them all
DDASSERT(cTextureFormats);
}
else
{
// Hmmm.. yucky non DX8 driver! Better go through its texture list
// and turn it into an op list
INT i;
for(i=0; i< (INT)cTextureFormats; i++)
{
// we proved this above:
DDASSERT(pTextureList[i].ddpfPixelFormat.dwFlags != DDPF_D3DFORMAT);
D3DFORMAT NewFormat;
ConvertFromOldFormat(&pTextureList[i].ddpfPixelFormat, &NewFormat );
if (NewFormat != D3DFMT_UNKNOWN) // we succeeded the conversion
{
pTextureList[i].ddpfPixelFormat.dwFourCC = (DWORD) NewFormat;
pTextureList[i].ddpfPixelFormat.dwFlags = DDPF_D3DFORMAT;
pTextureList[i].ddpfPixelFormat.dwOperations = D3DFORMAT_OP_TEXTURE;
if (pBaseData->DriverData.D3DCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP)
{
// It is assumed that any texture format works for cubes
pTextureList[i].ddpfPixelFormat.dwOperations |=
D3DFORMAT_OP_CUBETEXTURE;
if (NewFormat == D3DFMT_X1R5G5B5 ||
NewFormat == D3DFMT_R5G6B5 ||
NewFormat == D3DFMT_A8R8G8B8 ||
NewFormat == D3DFMT_X8R8G8B8)
{
// For these three formats, we assume
// all cube-map hw supports rendering to them.
//
// Testing indicates that these formats don't work
// well if they are in bitdepth other than the primary;
// so we only specify that the RT aspect of these
// formats work if they are basically the same
// as the primary.
pTextureList[i].ddpfPixelFormat.dwOperations |=
D3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET;
}
}
// If they can support render target textures, add those flags in now
DWORD RTBit = D3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET;
if (pBaseData->DriverData.KnownDriverFlags & KNOWN_CANMISMATCHRT)
{
RTBit = D3DFORMAT_OP_OFFSCREEN_RENDERTARGET;
}
if ((NewFormat == D3DFMT_X1R5G5B5) &&
(pBaseData->DriverData.KnownDriverFlags & KNOWN_RTTEXTURE_X1R5G5B5))
{
pTextureList[i].ddpfPixelFormat.dwOperations |= RTBit;
}
else if ((NewFormat == D3DFMT_R5G6B5) &&
(pBaseData->DriverData.KnownDriverFlags & KNOWN_RTTEXTURE_R5G6B5))
{
pTextureList[i].ddpfPixelFormat.dwOperations |= RTBit;
}
else if ((NewFormat == D3DFMT_X8R8G8B8) &&
(pBaseData->DriverData.KnownDriverFlags & KNOWN_RTTEXTURE_X8R8G8B8))
{
pTextureList[i].ddpfPixelFormat.dwOperations |= RTBit;
}
else if ((NewFormat == D3DFMT_A8R8G8B8) &&
(pBaseData->DriverData.KnownDriverFlags & KNOWN_RTTEXTURE_A8R8G8B8))
{
pTextureList[i].ddpfPixelFormat.dwOperations |= RTBit;
}
else if ((NewFormat == D3DFMT_A1R5G5B5) &&
(pBaseData->DriverData.KnownDriverFlags & KNOWN_RTTEXTURE_A1R5G5B5))
{
pTextureList[i].ddpfPixelFormat.dwOperations |= RTBit;
}
else if ((NewFormat == D3DFMT_A4R4G4B4) &&
(pBaseData->DriverData.KnownDriverFlags & KNOWN_RTTEXTURE_A4R4G4B4))
{
pTextureList[i].ddpfPixelFormat.dwOperations |= RTBit;
}
pTextureList[i].ddpfPixelFormat.dwPrivateFormatBitCount = 0;
pTextureList[i].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes = 0;
pTextureList[i].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes = 0;
}
else
{
DPF(3,"This driver exposes an unrecognized DX7- style texture format");
// and we eat it up:
// (scroll the remainder of the list down to
// squish this entry)
DDASSERT(cTextureFormats>0); //after all, we're in a for loop.
if (i < (INT)(cTextureFormats - 1))
{
memcpy(pTextureList + i,
pTextureList + i + 1,
sizeof(*pTextureList)*(cTextureFormats - i - 1));
}
cTextureFormats--;
i--;
}
}
//And laboriously tack on the z/stencil formats. Phew.
for (i = 0; i < (INT)cZStencilFormats; i++)
{
DDASSERT(pZStencilFormatList);
//we proved this above:
DDASSERT(pZStencilFormatList[i].dwFlags != DDPF_D3DFORMAT);
D3DFORMAT NewFormat;
ConvertFromOldFormat(&pZStencilFormatList[i], &NewFormat);
if (NewFormat != D3DFMT_UNKNOWN) //we succeeded the conversion
{
// Room for these elements was allocated above...
pTextureList[cTextureFormats].ddpfPixelFormat.dwFlags = DDPF_D3DFORMAT;
pTextureList[cTextureFormats].ddpfPixelFormat.dwFourCC = (DWORD) NewFormat;
pTextureList[cTextureFormats].ddpfPixelFormat.dwOperations = D3DFORMAT_OP_ZSTENCIL;
pTextureList[cTextureFormats].ddpfPixelFormat.dwPrivateFormatBitCount = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes = 0;
// See if part is "known good" i.e. it can mix-and-match
// ZBuffer and RT formats
if (pBaseData->DriverData.KnownDriverFlags & KNOWN_ZSTENCILDEPTH)
{
pTextureList[cTextureFormats].ddpfPixelFormat.dwOperations
|= D3DFORMAT_OP_ZSTENCIL_WITH_ARBITRARY_COLOR_DEPTH;
}
// If part successfully supports lockable 16-bit zbuffer tests
// then we allow D16_LOCKABLE through; else we only expose D3DFMT_D16
if (NewFormat == D3DFMT_D16_LOCKABLE)
{
if (!(pBaseData->DriverData.KnownDriverFlags & KNOWN_D16_LOCKABLE))
{
pTextureList[cTextureFormats].ddpfPixelFormat.dwFourCC = (DWORD) D3DFMT_D16;
}
}
cTextureFormats++;
}
else
{
DPF(3,"This driver exposes an unrecognized DX6 style Z/Stencil format");
}
}
// Now we need to add in off-screen render target formats for this Non-DX8 driver.
// DX8 doesn't allow back buffers to be used as textures, so we add
// a whole new entry to the op list for each supported back buffer
// format (i.e. don't go searching for any existing texturable format
// entry that matches and OR in the RT op).
//
//If the format is a back-buffer format, we assume it can be rendered when in the same
//display mode. Note the presence of this entry in the format op list doesn't imply
//necessarily that the device can render in that depth. CheckDeviceFormat could still
//fail for modes of that format... This gives us license to blindly add the formats
//here before we really know what set of back buffer formats the device can do.
//(Note only display devices are given this boost, since voodoos don't run windowed)
if (pBaseData->dwFlags & DD_DISPLAYDRV)
{
pTextureList[cTextureFormats].ddpfPixelFormat.dwFlags = DDPF_D3DFORMAT;
pTextureList[cTextureFormats].ddpfPixelFormat.dwFourCC = (DWORD) Unknown16;
pTextureList[cTextureFormats].ddpfPixelFormat.dwOperations = D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET;
pTextureList[cTextureFormats].ddpfPixelFormat.dwPrivateFormatBitCount = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes = 0;
cTextureFormats ++;
pTextureList[cTextureFormats].ddpfPixelFormat.dwFlags = DDPF_D3DFORMAT;
pTextureList[cTextureFormats].ddpfPixelFormat.dwFourCC = (DWORD) D3DFMT_X8R8G8B8;
pTextureList[cTextureFormats].ddpfPixelFormat.dwOperations = D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET;
pTextureList[cTextureFormats].ddpfPixelFormat.dwPrivateFormatBitCount = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes = 0;
cTextureFormats ++;
}
else
{
// Voodood 2 hack - The V2 doesn't really support offscreen
// render targets, but we need to add a 565 RT anyway or else
// our op list won't create the device.
// CONSIDER: Adding an internal OP flag indicating that this format
// should NOT succeed in a call to CreateRenderTarget.
pTextureList[cTextureFormats].ddpfPixelFormat.dwFlags = DDPF_D3DFORMAT;
pTextureList[cTextureFormats].ddpfPixelFormat.dwFourCC = (DWORD) Unknown16;
pTextureList[cTextureFormats].ddpfPixelFormat.dwOperations = D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET;
pTextureList[cTextureFormats].ddpfPixelFormat.dwPrivateFormatBitCount = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes = 0;
cTextureFormats ++;
}
// Now add in the supported display modes
if (D3DGlobalDriverData.hwCaps.dwDeviceRenderBitDepth & DDBD_16)
{
pTextureList[cTextureFormats].ddpfPixelFormat.dwFlags = DDPF_D3DFORMAT;
pTextureList[cTextureFormats].ddpfPixelFormat.dwFourCC = (DWORD) Unknown16;
pTextureList[cTextureFormats].ddpfPixelFormat.dwOperations = D3DFORMAT_OP_DISPLAYMODE|D3DFORMAT_OP_3DACCELERATION;
pTextureList[cTextureFormats].ddpfPixelFormat.dwPrivateFormatBitCount = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes = 0;
cTextureFormats++;
}
if (D3DGlobalDriverData.hwCaps.dwDeviceRenderBitDepth & DDBD_24)
{
pTextureList[cTextureFormats].ddpfPixelFormat.dwFlags = DDPF_D3DFORMAT;
pTextureList[cTextureFormats].ddpfPixelFormat.dwFourCC = (DWORD) D3DFMT_R8G8B8;
pTextureList[cTextureFormats].ddpfPixelFormat.dwOperations = D3DFORMAT_OP_DISPLAYMODE|D3DFORMAT_OP_3DACCELERATION;
pTextureList[cTextureFormats].ddpfPixelFormat.dwPrivateFormatBitCount = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes = 0;
cTextureFormats++;
}
if (D3DGlobalDriverData.hwCaps.dwDeviceRenderBitDepth & DDBD_32)
{
pTextureList[cTextureFormats].ddpfPixelFormat.dwFlags = DDPF_D3DFORMAT;
pTextureList[cTextureFormats].ddpfPixelFormat.dwFourCC = (DWORD) D3DFMT_X8R8G8B8;
pTextureList[cTextureFormats].ddpfPixelFormat.dwOperations = D3DFORMAT_OP_DISPLAYMODE|D3DFORMAT_OP_3DACCELERATION;
pTextureList[cTextureFormats].ddpfPixelFormat.dwPrivateFormatBitCount = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes = 0;
cTextureFormats++;
}
// This is a hack for those really, really old drivers that don't
// support any D3D at all. We will fill in 16 and 32bpp modes, but remove
// the 32bpp mode later if we can't find it in the mode table.
if ((D3DGlobalDriverData.hwCaps.dwDeviceRenderBitDepth == 0)
#ifdef WIN95
&& (pBaseData->DriverData.D3DCaps.Caps & DDCAPS_BLT)
&& !(pBaseData->DriverData.D3DCaps.Caps & DDCAPS_NOHARDWARE)
#endif
)
{
pTextureList[cTextureFormats].ddpfPixelFormat.dwFlags = DDPF_D3DFORMAT;
pTextureList[cTextureFormats].ddpfPixelFormat.dwFourCC = (DWORD) Unknown16;
pTextureList[cTextureFormats].ddpfPixelFormat.dwOperations = D3DFORMAT_OP_DISPLAYMODE;
pTextureList[cTextureFormats].ddpfPixelFormat.dwPrivateFormatBitCount = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes = 0;
cTextureFormats++;
pTextureList[cTextureFormats].ddpfPixelFormat.dwFlags = DDPF_D3DFORMAT;
pTextureList[cTextureFormats].ddpfPixelFormat.dwFourCC = (DWORD) D3DFMT_X8R8G8B8;
pTextureList[cTextureFormats].ddpfPixelFormat.dwOperations = D3DFORMAT_OP_DISPLAYMODE;
pTextureList[cTextureFormats].ddpfPixelFormat.dwPrivateFormatBitCount = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes = 0;
pTextureList[cTextureFormats].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes = 0;
cTextureFormats++;
}
}
// As a final pass we infer operations as necessary. If we have an
// general operation that implies other specific operations; then we
// turn on the bits of those specific operations. This is better
// than relying on the driver to get everything right; because it lets us
// add more specific operations in future releases without breaking
// old releases.
for (i = 0; i < cTextureFormats; i++)
{
DWORD *pdwOperations = &(pTextureList[i].ddpfPixelFormat.dwOperations);
// Off-screen RT means truly mode-independent
if ((*pdwOperations) & D3DFORMAT_OP_OFFSCREEN_RENDERTARGET)
{
(*pdwOperations) |= D3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET;
(*pdwOperations) |= D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET;
}
// Same except for alpha means exact same is good too
if ((*pdwOperations) & D3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET)
{
(*pdwOperations) |= D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET;
}
// Color Independent Z implies that forced Z matching is ok too.
if ((*pdwOperations) & D3DFORMAT_OP_ZSTENCIL_WITH_ARBITRARY_COLOR_DEPTH)
{
(*pdwOperations) |= D3DFORMAT_OP_ZSTENCIL;
}
}
// Now we make a final pass to verify that they driver did gave us an
// OP list that makes sense. The OP list rules are:
//
// 1. Only One Endian-ness for any DS format is allowed i.e. D15S1 OR
// S1D15, not both independent of other bits.
// 2. A list should only include D3DFORMAT_OP_DISPLAYMODE for exactly
// one 16bpp format (i.e. shouldn’t enumerate 5:5:5 and 5:6:5).
// 3. A list should not any alpha formats with D3DFORMAT_OP_DISPLAYMODE
// or D3DFORMAT_OP_3DACCEL set.
// 4. Make sure no mode has OP_3DACCEL set that doesn’t also have
// OP_DISPLAYMODE set.
//
// We also register IHV formats with CPixel.
//
BOOL BadOpList = FALSE;
for (i = 0; i < cTextureFormats; i++)
{
if ((pTextureList[i].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_PIXELSIZE) &&
pTextureList[i].ddpfPixelFormat.dwPrivateFormatBitCount != 0)
{
CPixel::Register((D3DFORMAT)pTextureList[i].ddpfPixelFormat.dwFourCC, pTextureList[i].ddpfPixelFormat.dwPrivateFormatBitCount);
}
if ((pTextureList[i].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_3DACCELERATION) &&
!(pTextureList[i].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_DISPLAYMODE))
{
DPF_ERR("***Driver disabled because it reported a format with D3DFORMAT_OP_3DACCELERATION without D3DFORMAT_OP_DISPLAYMODE");
BadOpList = TRUE;
}
if ((pTextureList[i].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_3DACCELERATION) &&
((pTextureList[i].ddpfPixelFormat.dwFourCC == (DWORD) D3DFMT_A8R8G8B8) ||
(pTextureList[i].ddpfPixelFormat.dwFourCC == (DWORD) D3DFMT_A1R5G5B5)))
{
DPF_ERR("***Driver disabled because it reported an alpha format with D3DFORMAT_OP_3DACCELERATION");
BadOpList = TRUE;
}
if ((pTextureList[i].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_DISPLAYMODE) &&
(pTextureList[i].ddpfPixelFormat.dwFourCC == (DWORD) D3DFMT_R5G6B5))
{
if (IsSupportedOp (D3DFMT_X1R5G5B5, pTextureList, cTextureFormats, D3DFORMAT_OP_DISPLAYMODE))
{
DPF_ERR("***Driver disabled because it reported both D3DFMT_R5G6B5 and D3DFMT_X1R5G5B5 as a display mode");
BadOpList = TRUE;
}
}
if (pTextureList[i].ddpfPixelFormat.dwFourCC == (DWORD) D3DFMT_D15S1)
{
if (IsSupportedOp (D3DFMT_S1D15, pTextureList, cTextureFormats, 0))
{
DPF_ERR("***Driver disabled because it reported both D3DFMT_D15S1 and D3DFMT_S1D15");
BadOpList = TRUE;
}
}
else if (pTextureList[i].ddpfPixelFormat.dwFourCC == (DWORD) D3DFMT_D24S8)
{
if (IsSupportedOp (D3DFMT_S8D24, pTextureList, cTextureFormats, 0))
{
DPF_ERR("***Driver disabled because it reported both D3DFMT_D24S8 and D3DFMT_S8D24");
BadOpList = TRUE;
}
}
else if (pTextureList[i].ddpfPixelFormat.dwFourCC == (DWORD) D3DFMT_D24X8)
{
if (IsSupportedOp (D3DFMT_X8D24, pTextureList, cTextureFormats, 0))
{
DPF_ERR("***Driver disabled because it reported both D3DFMT_D24X8 and D3DFMT_X8D24");
BadOpList = TRUE;
}
}
else if (pTextureList[i].ddpfPixelFormat.dwFourCC == (DWORD) D3DFMT_D24X4S4)
{
if (IsSupportedOp (D3DFMT_X4S4D24, pTextureList, cTextureFormats, 0))
{
DPF_ERR("***Driver disabled because it reported both D3DFMT_D24X4S4 and D3DFMT_X4S4D24");
BadOpList = TRUE;
}
}
}
if (BadOpList)
{
D3D8DeleteDirectDrawObject(pBaseData->hDD);
pBaseData->hDD = NULL;
goto ErrorExit;
}
// and now we assign the texture list to its place in the driver data
pBaseData->DriverData.pGDD8SupportedFormatOps = pTextureList;
if (pTextureList != NULL)
{
pTextureList = NULL; //so it won't be freed later
pBaseData->DriverData.GDD8NumSupportedFormatOps = cTextureFormats;
}
else
{
pBaseData->DriverData.GDD8NumSupportedFormatOps = 0;
}
if (!(pBaseData->DriverData.D3DCaps.Caps2 & DDCAPS2_NONLOCALVIDMEM))
{
if (pBaseData->DriverData.D3DCaps.DevCaps & D3DDEVCAPS_TEXTURENONLOCALVIDMEM)
{ //some drivers(Riva128 on PCI) incorrectly sets D3DDEVCAPS_TEXTURENONLOCALVIDMEM
DPF(1, "driver set D3DDEVCAPS_TEXTURENONLOCALVIDMEM w/o DDCAPS2_NONLOCALVIDMEM:turning off D3DDEVCAPS_TEXTURENONLOCALVIDMEM");
pBaseData->DriverData.D3DCaps.DevCaps &= ~D3DDEVCAPS_TEXTURENONLOCALVIDMEM;
}
}
// For pre-DX8, we have some munging of caps that is necessary
if (pBaseData->DriverData.D3DCaps.MaxStreams == 0)
{
DWORD *pdwTextureCaps = &pBaseData->DriverData.D3DCaps.TextureCaps;
if (*pdwTextureCaps & D3DPTEXTURECAPS_CUBEMAP)
{
if (pBaseData->DriverData.KnownDriverFlags & KNOWN_MIPPEDCUBEMAPS)
{
*pdwTextureCaps |= D3DPTEXTURECAPS_MIPCUBEMAP;
}
else
{
// Turn off Mip filter flags since this is card doesnt support a mipped cubemap.
pBaseData->DriverData.D3DCaps.CubeTextureFilterCaps &= ~(D3DPTFILTERCAPS_MIPFPOINT |
D3DPTFILTERCAPS_MIPFLINEAR);
}
// Also we need to specify that cube-maps must
// be power-of-two
*pdwTextureCaps |= D3DPTEXTURECAPS_CUBEMAP_POW2;
}
// We need to determine the part can support mipmaps...
if (pBaseData->DriverData.D3DCaps.TextureFilterCaps &
(D3DPTFILTERCAPS_MIPNEAREST |
D3DPTFILTERCAPS_MIPLINEAR |
D3DPTFILTERCAPS_LINEARMIPNEAREST |
D3DPTFILTERCAPS_LINEARMIPLINEAR |
D3DPTFILTERCAPS_MIPFPOINT |
D3DPTFILTERCAPS_MIPFLINEAR))
{
*pdwTextureCaps |= D3DPTEXTURECAPS_MIPMAP;
}
else
{
DPF(3, "Device doesn't support mip-maps");
}
}
// We disable driver-management for pre-dx8 parts because
// the semantics for driver-management are now different
// for dx8; and hence we can't use old driver's logic.
pBaseData->DriverData.D3DCaps.Caps2 &= ~DDCAPS2_CANMANAGETEXTURE;
// For HW that needs separate banks of texture memory; we
// disable multi-texturing. This is done because we don't want to
// have an API that puts the burden on the application to specifically
// code for this case.
if (pBaseData->DriverData.D3DCaps.DevCaps & D3DDEVCAPS_SEPARATETEXTUREMEMORIES)
{
pBaseData->DriverData.D3DCaps.MaxSimultaneousTextures = 1;
// Turn off this flag.
pBaseData->DriverData.D3DCaps.DevCaps &= ~D3DDEVCAPS_SEPARATETEXTUREMEMORIES;
}
}
ErrorExit:
if (NULL != pTextureList)
MemFree(pTextureList);
// It was only temporary, having now been merged into the supported op list.
if (NULL != pZStencilFormatList)
MemFree(pZStencilFormatList);
return;
} /* FetchDirectDrawData */
/*
* DirectDrawSupported
*/
BOOL DirectDrawSupported(void)
{
HDC hdc;
unsigned u;
hdc = GetDC(NULL);
u = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
ReleaseDC(NULL, hdc);
if (u < 8)
{
return FALSE;
}
return TRUE;
} /* DirectDrawSupported */
// Utility function that tells us if there is more than
// one display device in the system. (We count all devices,
// regardless of whether they are attached to the desktop.)
BOOL IsMultiMonitor(void)
{
int i, n;
// Each loop below enumerates one display device.
for (i = 0, n = 0; ; i++)
{
DISPLAY_DEVICEA dd;
// Zero the memory of the DISPLAY_DEVICE struct between calls to
// EnumDisplayDevices
ZeroMemory(&dd, sizeof(dd));
dd.cb = sizeof(dd);
if (!xxxEnumDisplayDevicesA(NULL, i, &dd, 0))
{
break; // no more devices to enumerate
}
if (dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)
{
continue; // not a real hardware display driver
}
// We're just trying to count the number of display devices in the
// system and see if there is more than one.
if (++n > 1)
{
return TRUE; // multiple display devices
}
}
return FALSE; // single display device
}
BOOL fDoesGDI(HDC hdc)
{
//
// the 3Dfx driver always return 1 to every thing
// verify GetNearest() color works.
//
BOOL b = GetNearestColor(hdc, 0x000000) == 0x000000 &&
GetNearestColor(hdc, 0xFFFFFF) == 0xFFFFFF;
if (b)
{
DPF(3,"Driver is a GDI driver");
}
return b;
}
/*
* Functions to dynamically link against exports we need in user32 on
* older OSes
*/
//These statics will be per-process, cuz it's outside the shared section
typedef BOOL (WINAPI * LPENUMMONITORS) (HDC, LPRECT, MONITORENUMPROC, LPARAM);
typedef BOOL (WINAPI * LPGETMONINFO) (HMONITOR, MONITORINFO *);
typedef BOOL (WINAPI * LPISDEBUG) (void);
static LPISDEBUG pIsDebuggerPresent = 0;
static LPENUMMONITORS pEnumMonitors = 0;
static LPGETMONINFO pGetMonitorInfo = 0;
static BOOL bTriedToGetProcAlready = FALSE;
BOOL DynamicLinkToOS(void)
{
if (1) //!pEnumMonitors)
{
HMODULE hUser32;
HMODULE hKernel32;
if (0) //bTriedToGetProcAlready)
return FALSE;
bTriedToGetProcAlready = TRUE;
hUser32 = GetModuleHandle(TEXT("USER32"));
pEnumMonitors = (LPENUMMONITORS) GetProcAddress(hUser32,"EnumDisplayMonitors");
pGetMonitorInfo = (LPGETMONINFO) GetProcAddress(hUser32,"GetMonitorInfoA");
hKernel32 = GetModuleHandle(TEXT("KERNEL32"));
pIsDebuggerPresent = (LPISDEBUG) GetProcAddress(hKernel32,"IsDebuggerPresent");
if (!pEnumMonitors || !pGetMonitorInfo || !pIsDebuggerPresent)
{
DPF(3,"Failed to get proc addresses");
return FALSE;
}
}
DDASSERT(pEnumMonitors);
DDASSERT(pGetMonitorInfo);
DDASSERT(pEnumMonitors);
return TRUE;
}
BOOL InternalGetMonitorInfo(HMONITOR hMon, MONITORINFO *lpInfo)
{
DynamicLinkToOS();
if (!pGetMonitorInfo)
return FALSE;
return pGetMonitorInfo(hMon, lpInfo);
}
typedef struct
{
LPSTR pName;
HMONITOR hMon;
} CALLBACKSTRUCT, * LPCALLBACKSTRUCT;
BOOL InternalEnumMonitors(MONITORENUMPROC proc, LPCALLBACKSTRUCT lp)
{
DynamicLinkToOS();
if (!pEnumMonitors)
return FALSE;
pEnumMonitors(NULL,NULL,proc,(LPARAM)lp);
return TRUE;
}
/*
* InternalIsDebuggerPresent
* A little helper so that this runtime runs against older OSes
*/
BOOL InternalIsDebuggerPresent(void)
{
DynamicLinkToOS();
if (!pIsDebuggerPresent)
return FALSE;
return pIsDebuggerPresent();
}
//
// getPrimaryDisplayName
//
void getPrimaryDisplayName(void)
{
DISPLAY_DEVICE dd;
int i;
ZeroMemory(&dd, sizeof dd);
dd.cb = sizeof dd;
for (i = 0; xxxEnumDisplayDevicesA(NULL, i, &dd, 0); ++i)
{
if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
{
lstrcpyn(g_szPrimaryDisplay, dd.DeviceName, sizeof g_szPrimaryDisplay);
return;
}
}
lstrcpy(g_szPrimaryDisplay, DISPLAY_STR);
}
/*
* InternalDirectDrawCreate
*/
HRESULT InternalDirectDrawCreate(
PD3D8_DEVICEDATA* ppBaseData,
PADAPTERINFO pDeviceInfo,
D3DDEVTYPE DeviceType,
VOID* pInitFunction,
D3DFORMAT Unknown16,
DDSURFACEDESC* pHalOpList,
DWORD NumHalOps)
{
int rc;
HDC hdc_dd;
HKEY hkey;
ULONG_PTR hDD;
PD3D8_DEVICEDATA pBaseData;
*ppBaseData = (PD3D8_DEVICEDATA) NULL;
/*
* check for < 8 bpp and disallow.
*/
if (!DirectDrawSupported())
{
DPF_ERR("DDraw and Direct3D are not supported in less than 8bpp modes. Creating Device fails.");
return D3DERR_NOTAVAILABLE;
}
ENTER_CSDDC();
hdc_dd = NULL;
hDD = 0;
//
// Get the primary display name, which will usually be something like
// \\.\Display1 and in some cases may be \\.\Display1\Unit0. We only
// do this one time, and store it globally. On Win98, the global name
// will be shared between all processes, and on NT5, each process will
// have its own copy. Also, note that the primary device name may change
// on NT5; we need to look into this.
//
if (g_szPrimaryDisplay[0] == '\0')
{
getPrimaryDisplayName();
}
// Create the object and get all of the data.
hdc_dd = DD_CreateDC(pDeviceInfo->DeviceName);
if (hdc_dd == NULL)
{
DPF_ERR("Could not create driver, CreateDC failed! Creating Device fails.");
LEAVE_CSDDC();
return E_OUTOFMEMORY;
}
// Create the driver object
pBaseData = (PD3D8_DEVICEDATA) MemAlloc (sizeof (D3D8_DEVICEDATA));
if (pBaseData == NULL)
{
DPF_ERR("Insufficient system memory! Creating Device fails. ");
DD_DoneDC(hdc_dd);
LEAVE_CSDDC();
return E_OUTOFMEMORY;
}
ZeroMemory( pBaseData, sizeof(D3D8_DEVICEDATA) );
strcpy(pBaseData->DriverName, pDeviceInfo->DeviceName);
pBaseData->hDC = hdc_dd;
pBaseData->Guid = pDeviceInfo->Guid;
pBaseData->DeviceType = DeviceType;
// Even if it's not a display driver, it may still be a GDI driver
if (hdc_dd != NULL)
{
if (pDeviceInfo->bIsDisplay)
{
pBaseData->dwFlags |= DD_DISPLAYDRV;
}
else if (fDoesGDI(hdc_dd))
{
pBaseData->dwFlags |= DD_GDIDRV;
}
}
// Get all of the driver caps and callbacks
FetchDirectDrawData(pBaseData,
pInitFunction,
Unknown16,
pHalOpList,
NumHalOps);
if (pBaseData->hDD == NULL)
{
DDASSERT(NULL == pBaseData->DriverData.pGDD8SupportedFormatOps);
DD_DoneDC(hdc_dd);
MemFree(pBaseData);
LEAVE_CSDDC();
return D3DERR_NOTAVAILABLE;
}
*ppBaseData = pBaseData;
LEAVE_CSDDC();
return S_OK;
} /* InternalDirectDrawCreate */
/*
* InternalDirectDrawRelease
*/
HRESULT InternalDirectDrawRelease(PD3D8_DEVICEDATA pBaseData)
{
D3D8DeleteDirectDrawObject(pBaseData->hDD);
DD_DoneDC(pBaseData->hDC);
MemFree(pBaseData->DriverData.pGDD8SupportedFormatOps);
MemFree(pBaseData);
return S_OK;
} /* InternalDirectDrawRelease */
BOOL CALLBACK MonitorEnumProc(HMONITOR hMon, HDC hdc, LPRECT lpr, LPARAM lParam)
{
MONITORINFOEX mix;
MONITORINFO mi;
LPCALLBACKSTRUCT lpcb = (LPCALLBACKSTRUCT) lParam;
mi.cbSize = sizeof(mi);
if (!InternalGetMonitorInfo(hMon,&mi))
return FALSE;
mix.cbSize = sizeof(mix);
if (!InternalGetMonitorInfo(hMon,(MONITORINFO*) &mix))
return FALSE;
if (!strcmp(lpcb->pName,(LPSTR)mix.szDevice))
{
//Found it!!
lpcb->hMon = hMon;
return FALSE;
}
return TRUE;
}
/*
* GetMonitorFromDeviceName
*/
HMONITOR GetMonitorFromDeviceName(LPSTR szName)
{
CALLBACKSTRUCT cbs;
cbs.pName = szName;
cbs.hMon = NULL;
if (!InternalEnumMonitors(MonitorEnumProc, &cbs))
return NULL;
return cbs.hMon;
}
/*
* these are exported... temp. hack for non-Win95
*/
#ifndef WIN95
void DDAPI thk3216_ThunkData32(void)
{
}
void DDAPI thk1632_ThunkData32(void)
{
}
DWORD DDAPI DDGetPID(void)
{
return 0;
}
int DDAPI DDGetRequest(void)
{
return 0;
}
BOOL DDAPI DDGetDCInfo(LPSTR fname)
{
return 0;
}
#ifdef POSTPONED
BOOL DDAPI DD32_HandleExternalModeChange(LPDEVMODE pModeInfo)
{
return FALSE;
}
#endif
#endif