/*========================================================================== * * 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