|
|
/*==========================================================================
* * Copyright (C) 1995-1999 Microsoft Corporation. All Rights Reserved. * * File: enum.cpp * Content Handles all of the enum functions for determing what device * you want before you go there. * * ***************************************************************************/ #include "ddrawpr.h"
#include <stdio.h>
#include "d3dobj.hpp"
#include "pixel.hpp"
#include "enum.hpp"
#include "d3di.hpp"
#include "fcache.hpp"
#include "swapchan.hpp"
#define D3DPMISCCAPS_DX7VALID \
(D3DPMISCCAPS_MASKZ | \ D3DPMISCCAPS_LINEPATTERNREP | \ D3DPMISCCAPS_CULLNONE | \ D3DPMISCCAPS_CULLCW | \ D3DPMISCCAPS_CULLCCW)
// Maps D3DMULTISAMPLE_TYPE into the bit to use for the flags.
// Maps each of the multisampling values (2 to 16) to the bits[1] to bits[15]
// of wBltMSTypes and wFlipMSTypes
#define DDI_MULTISAMPLE_TYPE(x) (1 << ((x)-1))
#ifdef WINNT
extern "C" BOOL IsWhistler(); #endif
void DXReleaseExclusiveModeMutex(void) { if (hExclusiveModeMutex) { BOOL bSucceed = ReleaseMutex(hExclusiveModeMutex); if (!bSucceed) { DWORD dwErr = GetLastError(); DPF_ERR("Release Exclusive Mode Mutex Failed."); DPF_ERR("Application attempts to leave exclusive mode on different thread than the device was created on. Dangerous!!"); DPF(0, "Mutex 0x%p could not be released. Extended Error = %d", hExclusiveModeMutex, dwErr); DXGASSERT(FALSE); } } } // DXReleaseExclusiveModeMutex
// DLL exposed Creation function
IDirect3D8 * WINAPI Direct3DCreate8(UINT SDKVersion) { // Turn off D3D8 interfaces on WOW64.
#ifndef _IA64_
#if _WIN32_WINNT >= 0x0501
typedef BOOL (WINAPI *PFN_ISWOW64PROC)( HANDLE hProcess, PBOOL Wow64Process ); HINSTANCE hInst = NULL; hInst = LoadLibrary( "kernel32.dll" ); if( hInst ) { PFN_ISWOW64PROC pfnIsWow64 = NULL; pfnIsWow64 = (PFN_ISWOW64PROC)GetProcAddress( (HMODULE)hInst, "IsWow64Process" ); // We assume that if this function is not available, then it is some OS where
// WOW64 does not exist (this means that pre-Release versions of XP are busted)
if( pfnIsWow64 ) { BOOL wow64Process; if (pfnIsWow64(GetCurrentProcess(), &wow64Process) && wow64Process) { DPF_ERR("DX8 D3D interfaces are not supported on WOW64"); return NULL; } } FreeLibrary( hInst ); } else { DPF_ERR("LoadLibrary failed. Quitting."); return NULL; } #endif // _WIN32_WINNT >= 0x0501
#endif // _IA64_
#ifndef DEBUG
// Check for debug-please registry key. If debug is required, then
// we delegate this call to the debug version, if it exists,,
HKEY hKey;
if (!RegOpenKey(HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey)) { DWORD type; DWORD value; DWORD cb = sizeof(value);
if (!RegQueryValueEx(hKey, "LoadDebugRuntime", NULL, &type, (CONST LPBYTE)&value, &cb)) {
if (value) { HINSTANCE hDebugDLL = LoadLibrary("d3d8d.dll"); if (hDebugDLL) { typedef IDirect3D8* (WINAPI * PDIRECT3DCREATE8)(UINT);
PDIRECT3DCREATE8 pDirect3DCreate8 = (PDIRECT3DCREATE8) GetProcAddress(hDebugDLL, "Direct3DCreate8");
if (pDirect3DCreate8) { return pDirect3DCreate8(SDKVersion); } } } } RegCloseKey(hKey); } #else
//If we are debug, then spew a string at level 2
DPF(2,"Direct3D8 Debug Runtime selected."); #endif
#ifndef DX_FINAL_RELEASE
// Time-bomb check.
{ #pragma message("BETA EXPIRATION TIME BOMB! Remove for final build!")
SYSTEMTIME st; GetSystemTime(&st);
if (st.wYear > DX_EXPIRE_YEAR || ((st.wYear == DX_EXPIRE_YEAR) && (MAKELONG(st.wDay, st.wMonth) > MAKELONG(DX_EXPIRE_DAY, DX_EXPIRE_MONTH))) ) { MessageBox(0, DX_EXPIRE_TEXT, TEXT("Microsoft Direct3D"), MB_OK | MB_TASKMODAL); } } #endif //DX_FINAL_RELEASE
#ifdef DEBUG
HKEY hKey; if (!RegOpenKey(HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey)) { DWORD type; DWORD value; DWORD cb = sizeof(value);
if (!RegQueryValueEx(hKey, "SDKVersion", NULL, &type, (CONST LPBYTE)&value, &cb)) { if (value) { SDKVersion = value; } } RegCloseKey(hKey); } #endif
if ((SDKVersion != D3D_SDK_VERSION_DX8) && ((SDKVersion < (D3D_SDK_VERSION)) || (SDKVersion >= (D3D_SDK_VERSION+100))) ) { char pbuf[256]; _snprintf(pbuf, 256, "\n" "D3D ERROR: This application compiled against improper D3D headers.\n" "The application is compiled with SDK version (%d) but the currently installed\n" "runtime supports versions from (%d).\n" "Please recompile with an up-to-date SDK.\n\n", SDKVersion, D3D_SDK_VERSION); OutputDebugString(pbuf); return NULL; }
IDirect3D8 *pEnum = new CEnum(SDKVersion); if (pEnum == NULL) { DPF_ERR("Creating D3D enumeration object failed; out of memory. Direct3DCreate fails and returns NULL."); } return pEnum; } // Direct3DCreate
//---------------------------------------------------------------------------
// CEnum methods
//---------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::AddRef"
STDMETHODIMP_(ULONG) CEnum::AddRef(void) { API_ENTER_NO_LOCK(this);
// InterlockedIncrement requires the memory
// to be aligned on DWORD boundary
DXGASSERT(((ULONG_PTR)(&m_cRef) & 3) == 0); InterlockedIncrement((LONG *)&m_cRef); return m_cRef; } // AddRef
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::Release"
STDMETHODIMP_(ULONG) CEnum::Release(void) { API_ENTER_NO_LOCK(this);
// InterlockedDecrement requires the memory
// to be aligned on DWORD boundary
DXGASSERT(((ULONG_PTR)(&m_cRef) & 3) == 0); InterlockedDecrement((LONG *)&m_cRef); if (m_cRef != 0) return m_cRef;
for (UINT i = 0; i < m_cAdapter; i++) { if (m_REFCaps[i].pGDD8SupportedFormatOps) MemFree(m_REFCaps[i].pGDD8SupportedFormatOps);
if (m_SwCaps[i].pGDD8SupportedFormatOps) MemFree(m_SwCaps[i].pGDD8SupportedFormatOps); if (m_AdapterInfo[i].HALCaps.pGDD8SupportedFormatOps) MemFree(m_AdapterInfo[i].HALCaps.pGDD8SupportedFormatOps); if (m_AdapterInfo[i].pModeTable) MemFree(m_AdapterInfo[i].pModeTable); } if (m_hGammaCalibrator) { FreeLibrary((HMODULE) m_hGammaCalibrator); }
delete this; return 0; } // Release
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::QueryInterface"
STDMETHODIMP CEnum::QueryInterface(REFIID riid, LPVOID FAR *ppv) { API_ENTER(this);
if (!VALID_PTR_PTR(ppv)) { DPF_ERR("Invalid pointer passed to QueryInterface for IDirect3D8 interface"); return D3DERR_INVALIDCALL; }
if (!VALID_PTR(&riid, sizeof(GUID))) { DPF_ERR("Invalid guid memory address to QueryInterface for IDirect3D8 interface"); return D3DERR_INVALIDCALL; }
if (riid == IID_IUnknown || riid == IID_IDirect3D8) { *ppv = static_cast<void*>(static_cast<IDirect3D8*>(this)); AddRef(); } else { DPF_ERR("Unsupported Interface identifier passed to QueryInterface for IDirect3D8 interface"); *ppv = NULL; return E_NOINTERFACE; } return S_OK; } // QueryInterface
// DisplayGUID - GUID used to enumerate secondary displays.
//
// {67685559-3106-11d0-B971-00AA00342F9F}
//
// we use this GUID and the next 32 for enumerating devices
// returned via EnumDisplayDevices
//
GUID DisplayGUID = {0x67685559,0x3106,0x11d0,{0xb9,0x71,0x0,0xaa,0x0,0x34,0x2f,0x9f}};
#undef DPF_MODNAME
#define DPF_MODNAME "::strToGUID"
/*
* strToGUID * * converts a string in the form xxxxxxxx-xxxx-xxxx-xx-xx-xx-xx-xx-xx-xx-xx * into a guid */ static BOOL strToGUID(LPSTR str, GUID * pguid) { int idx; LPSTR ptr; LPSTR next; DWORD data; DWORD mul; BYTE ch; BOOL done;
idx = 0; done = FALSE; while (!done) { /*
* find the end of the current run of digits */ ptr = str; while ((*str) != '-' && (*str) != 0) { str++; } if (*str == 0) { done = TRUE; } else { next = str+1; }
/*
* scan backwards from the end of the string to the beginning, * converting characters from hex chars to numbers as we go */ str--; mul = 1; data = 0; while (str >= ptr) { ch = *str; if (ch >= 'A' && ch <= 'F') { data += mul * (DWORD) (ch-'A'+10); } else if (ch >= 'a' && ch <= 'f') { data += mul * (DWORD) (ch-'a'+10); } else if (ch >= '0' && ch <= '9') { data += mul * (DWORD) (ch-'0'); } else { return FALSE; } mul *= 16; str--; }
/*
* stuff the current number into the guid */ switch(idx) { case 0: pguid->Data1 = data; break; case 1: pguid->Data2 = (WORD) data; break; case 2: pguid->Data3 = (WORD) data; break; default: pguid->Data4[ idx-3 ] = (BYTE) data; break; }
/*
* did we find all 11 numbers? */ idx++; if (idx == 11) { if (done) { return TRUE; } else { return FALSE; } } str = next; } return FALSE;
} /* strToGUID */
// REF, HAL
typedef struct _DEVICEREGISTRYDATA { UINT Size; UINT Cookie; FILETIME FileDate; GUID DriverGuid; D3D8_DRIVERCAPS DeviceCaps; UINT OffsetFormatOps; D3DFORMAT Unknown16; DWORD HALFlags; } DEVICEREGISTRYDATA;
inline UINT EXPECTED_CACHE_SIZE(UINT nFormatOps) { return sizeof(DEVICEREGISTRYDATA) + sizeof(DDSURFACEDESC) * nFormatOps; }
#define DDRAW_REGCAPS_KEY "Software\\Microsoft\\DirectDraw\\MostRecentDrivers"
#define VERSION_COOKIE 0x0083
#undef DPF_MODNAME
#define DPF_MODNAME "ReadCapsFromCache"
BOOL GetFileDate (char* Driver, FILETIME* pFileDate) { WIN32_FILE_ATTRIBUTE_DATA FA; char Name[MAX_PATH]; HMODULE h = GetModuleHandle("KERNEL32"); BOOL (WINAPI *pfnGetFileAttributesEx)(LPCSTR, GET_FILEEX_INFO_LEVELS, LPVOID);
pFileDate->dwLowDateTime = 0; pFileDate->dwHighDateTime = 0;
*((void **)&pfnGetFileAttributesEx) = GetProcAddress(h,"GetFileAttributesExA"); if (pfnGetFileAttributesEx != NULL) { GetSystemDirectory(Name, sizeof(Name) - (strlen(Driver) + 3)); lstrcat(Name,"\\"); lstrcat(Name, Driver);
if ((*pfnGetFileAttributesEx)(Name, GetFileExInfoStandard, &FA) != 0) { *pFileDate = FA.ftCreationTime; return TRUE; } } return FALSE; }
//If pCaps is NULL, then those data will not be returned.
BOOL ReadCapsFromCache(UINT iAdapter, D3D8_DRIVERCAPS *pCaps, UINT* pHALFlags, D3DFORMAT* pUnknown16, char* pDeviceName, BOOL bDisplayDriver) { D3DADAPTER_IDENTIFIER8 DI; DEVICEREGISTRYDATA* pData = NULL; UINT Size; FILETIME FileDate;
// Read the data from the registry
// Don't need WHQL level or driver name
GetAdapterInfo(pDeviceName, &DI, bDisplayDriver, TRUE, FALSE);
ReadFromCache(&DI, &Size, (BYTE**)&pData); if (pData == NULL) { return FALSE; }
// We have the data, now do a sanity check to make sure that it
// it makes sense
if (pData->Size != Size) { MemFree(pData); return FALSE; } if (Size != EXPECTED_CACHE_SIZE(pData->DeviceCaps.GDD8NumSupportedFormatOps)) { MemFree(pData); return FALSE; } if (pData->DriverGuid != DI.DeviceIdentifier) { MemFree(pData); return FALSE; } if (pData->Cookie != VERSION_COOKIE) { MemFree(pData); return FALSE; }
// Check the driver date to see if it changed
if (GetFileDate(DI.Driver, &FileDate)) { if ((FileDate.dwLowDateTime != pData->FileDate.dwLowDateTime) || (FileDate.dwHighDateTime != pData->FileDate.dwHighDateTime)) { MemFree(pData); return FALSE; } }
*pUnknown16 = pData->Unknown16; *pHALFlags = pData->HALFlags;
//Sometime we may not be asked to get the whole caps
if (!pCaps) { MemFree(pData); return TRUE; }
// Now that we have the data, we need to load it into a form that we
// can use.
memcpy(pCaps, &pData->DeviceCaps, sizeof(*pCaps));
//reuse size to calculate size of support format ops
Size = pData->DeviceCaps.GDD8NumSupportedFormatOps * sizeof(*(pData->DeviceCaps.pGDD8SupportedFormatOps));
pCaps->pGDD8SupportedFormatOps = (DDSURFACEDESC*) MemAlloc(Size);
if (pCaps->pGDD8SupportedFormatOps != NULL) { memcpy(pCaps->pGDD8SupportedFormatOps, ((BYTE*)pData) + pData->OffsetFormatOps, Size); } else { pCaps->GDD8NumSupportedFormatOps = 0; }
MemFree(pData);
return TRUE; } #undef DPF_MODNAME
#define DPF_MODNAME "WriteCapsToCache"
void WriteCapsToCache(UINT iAdapter, D3D8_DRIVERCAPS *pCaps, UINT HALFlags, D3DFORMAT Unknown16, char* pDeviceName, BOOL bDisplayDriver) { DEVICEREGISTRYDATA* pData; D3DADAPTER_IDENTIFIER8 DI; UINT Size; UINT Offset; FILETIME FileDate;
// Allocate the buffer and fill in all of the memory
Size = EXPECTED_CACHE_SIZE(pCaps->GDD8NumSupportedFormatOps);
pData = (DEVICEREGISTRYDATA*) MemAlloc(Size); if (pData == NULL) { return; }
// Don't need WHQL level or driver name
GetAdapterInfo(pDeviceName, &DI, bDisplayDriver, TRUE, FALSE); pData->DriverGuid = DI.DeviceIdentifier;
pData->Size = Size; pData->Cookie = VERSION_COOKIE; memcpy(&pData->DeviceCaps, pCaps, sizeof(*pCaps)); pData->Unknown16 = Unknown16; pData->HALFlags = HALFlags;
if (GetFileDate(DI.Driver, &FileDate)) { pData->FileDate = FileDate; }
Offset = sizeof(DEVICEREGISTRYDATA); pData->OffsetFormatOps = Offset; memcpy(((BYTE*)pData) + Offset, pCaps->pGDD8SupportedFormatOps, pCaps->GDD8NumSupportedFormatOps * sizeof(*(pCaps->pGDD8SupportedFormatOps)));
// Now save it
WriteToCache(&DI, Size, (BYTE*) pData);
MemFree(pData); }
HRESULT CopyDriverCaps(D3D8_DRIVERCAPS* pDriverCaps, D3D8_DEVICEDATA* pDeviceData, BOOL bForce) { HRESULT hr = D3DERR_INVALIDCALL;
// Do they report any D3D caps in this mode?
DWORD Size;
// If it's not at least a DX6 driver, we don't want to fill
// in any caps at all. Also, if it can't texture, then
// we don't to support it either.
BOOL bCanTexture = TRUE; BOOL bCanHandleFVF = TRUE; BOOL bHasGoodCaps = TRUE; if (!bForce) { if (pDeviceData->DriverData.D3DCaps.TextureCaps) { bCanTexture = TRUE; } else { DPF(0, "HAL Disabled: Device doesn't support texturing"); bCanTexture = FALSE; }
// Some DX6 drivers are not FVF aware; and we need to
// disable HAL for them.
if (pDeviceData->DriverData.D3DCaps.FVFCaps != 0) { bCanHandleFVF = TRUE; } else { DPF(0, "HAL Disabled: Device doesn't support FVF"); bCanHandleFVF = FALSE; }
if (pDeviceData->Callbacks.DrawPrimitives2 == NULL) { DPF(0, "HAL Disabled: Device doesn't support DX6 or higher"); }
// We dont want drivers that report bogus caps:
// pre-DX8 drivers that can do DX8 features.
if (pDeviceData->DriverData.D3DCaps.MaxStreams == 0) { D3DCAPS8& Caps = pDeviceData->DriverData.D3DCaps;
// Should have none of the following:
// 1) PointSprites.
// 2) VertexShaders.
// 3) PixelShaders.
// 4) Volume textures.
// 5) Indexed Vertex Blending.
// 6) Higher order primitives.
// 7) PureDevice
// 8) Perspective Color.
// 9) Color Write.
// 10) Newer texture caps.
if ((Caps.MaxPointSize != 0) || (Caps.VertexShaderVersion != D3DVS_VERSION(0,0)) || (Caps.PixelShaderVersion != D3DPS_VERSION(0,0)) || (Caps.MaxVolumeExtent != 0) || (Caps.MaxVertexBlendMatrixIndex != 0) || (Caps.MaxVertexIndex != 0xffff) || ((Caps.DevCaps & ~(D3DDEVCAPS_DX7VALID | D3DDEVCAPS_HWVERTEXBUFFER)) != 0) || ((Caps.RasterCaps & ~(D3DPRASTERCAPS_DX7VALID)) != 0) || ((Caps.PrimitiveMiscCaps & ~(D3DPMISCCAPS_DX7VALID)) != 0) || ((Caps.TextureCaps & ~(D3DPTEXTURECAPS_DX7VALID)) != 0) ) { DPF(0, "HAL Disabled: DX7 Device should not support DX8 features"); bHasGoodCaps = FALSE; } } else // We dont want drivers that report bogus caps:
// DX8 drivers should do DX8 features.
{ D3DCAPS8& Caps = pDeviceData->DriverData.D3DCaps; } }
// We require drivers to support DP2 (i.e. DX6+),
// texturing and proper FVF support in order to use a HAL
if ((pDeviceData->Callbacks.DrawPrimitives2 != NULL && bCanTexture && bCanHandleFVF && bHasGoodCaps) || bForce) { MemFree(pDriverCaps->pGDD8SupportedFormatOps); memcpy(pDriverCaps, &pDeviceData->DriverData, sizeof(pDeviceData->DriverData));
Size = sizeof(DDSURFACEDESC) * pDriverCaps->GDD8NumSupportedFormatOps; pDriverCaps->pGDD8SupportedFormatOps = (DDSURFACEDESC*) MemAlloc(Size);
if (pDriverCaps->pGDD8SupportedFormatOps != NULL) { memcpy(pDriverCaps->pGDD8SupportedFormatOps, pDeviceData->DriverData.pGDD8SupportedFormatOps, Size); } else { pDriverCaps->GDD8NumSupportedFormatOps = 0; }
hr = D3D_OK; } return hr; }
#undef DPF_MODNAME
#define DPF_MODNAME "AddSoftwareDevice"
HRESULT AddSoftwareDevice(D3DDEVTYPE DeviceType, D3D8_DRIVERCAPS* pSoftCaps, ADAPTERINFO* pAdapterInfo, VOID* pInitFunction) { HRESULT hr; PD3D8_DEVICEDATA pDeviceData;
hr = InternalDirectDrawCreate(&pDeviceData, pAdapterInfo, DeviceType, pInitFunction, pAdapterInfo->Unknown16, pAdapterInfo->HALCaps.pGDD8SupportedFormatOps, pAdapterInfo->HALCaps.GDD8NumSupportedFormatOps); if (SUCCEEDED(hr)) { hr = CopyDriverCaps(pSoftCaps, pDeviceData, FALSE);
InternalDirectDrawRelease(pDeviceData); } return hr; }
#undef DPF_MODNAME
#define DPF_MODNAME "CreateCoverWindow"
HWND CreateCoverWindow() { #define COVERWINDOWNAME "DxCoverWindow"
WNDCLASS windowClass = { 0, DefWindowProc, 0, 0, g_hModule, LoadIcon(NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW), (HBRUSH)(BLACK_BRUSH), NULL, COVERWINDOWNAME };
RegisterClass(&windowClass);
HWND hWindow = CreateWindowEx( WS_EX_TOPMOST, COVERWINDOWNAME, COVERWINDOWNAME, WS_POPUP, 0, 0, 100, 100, NULL, NULL, g_hModule, NULL);
return hWindow; }
HRESULT GetHALCapsInCurrentMode (PD3D8_DEVICEDATA pHalData, PADAPTERINFO pAdapterInfo, BOOL bForce, BOOL bFetchNewCaps) { HRESULT hr; DWORD i;
// Free the old stuff if we no longer care
if (bFetchNewCaps) { MemFree(pHalData->DriverData.pGDD8SupportedFormatOps); pHalData->DriverData.pGDD8SupportedFormatOps = NULL; pHalData->DriverData.GDD8NumSupportedFormatOps = 0;
MemFree(pAdapterInfo->HALCaps.pGDD8SupportedFormatOps); pAdapterInfo->HALCaps.pGDD8SupportedFormatOps = NULL; pAdapterInfo->HALCaps.GDD8NumSupportedFormatOps = 0;
// Set this to ensure that we actually get the caps
pHalData->DriverData.D3DCaps.DevCaps = 0; pHalData->DriverData.dwFlags &= ~DDIFLAG_D3DCAPS8;
FetchDirectDrawData(pHalData, NULL, pAdapterInfo->Unknown16, NULL, 0); }
// Do they report any D3D caps in this mode?
hr = CopyDriverCaps(&pAdapterInfo->HALCaps, pHalData, bForce);
return hr; }
#undef DPF_MODNAME
#define DPF_MODNAME "ProfileAdapter"
void ProfileAdapter( PADAPTERINFO pAdapterInfo, PD3D8_DEVICEDATA pHalData) { UINT i; IDirect3DDevice8* pDevice; D3DDISPLAYMODE OrigMode; UINT OrigBpp; HRESULT hr;
// We will be changing display modes, so first we want to save the current
// mode so we can return to it later.
D3D8GetMode (pHalData->hDD, pAdapterInfo->DeviceName, &OrigMode, D3DFMT_UNKNOWN);
MemFree(pAdapterInfo->HALCaps.pGDD8SupportedFormatOps); memset(&pAdapterInfo->HALCaps, 0, sizeof(D3D8_DRIVERCAPS));
OrigBpp = CPixel::ComputePixelStride(OrigMode.Format)*8;
//First gather what we need from 16bpp: Unknown16 format
if (16 != OrigBpp) { D3D8SetMode (pHalData->hDD, pAdapterInfo->DeviceName, 640, 480, 16, 0, FALSE); }
D3DDISPLAYMODE Mode; D3D8GetMode (pHalData->hDD, pAdapterInfo->DeviceName, &Mode, D3DFMT_UNKNOWN); pAdapterInfo->Unknown16 = Mode.Format;
// We need to change to 32bpp, because the above code guarenteed we are now in 16bpp
hr = D3D8SetMode (pHalData->hDD, pAdapterInfo->DeviceName, 640, 480, 32, 0, FALSE); if (SUCCEEDED(hr)) { hr = GetHALCapsInCurrentMode(pHalData, pAdapterInfo, FALSE, TRUE); }
if (FAILED(hr)) { // If they don't report caps in 32bpp mode (ala Voodoo 3), then go
// back to 16bpp mode and get the caps. If the device supports
// caps in any mode, we want to exit this function with the caps.
D3D8SetMode (pHalData->hDD, pAdapterInfo->DeviceName, 640, 480, 16, 0, FALSE);
hr = GetHALCapsInCurrentMode(pHalData, pAdapterInfo, FALSE, TRUE);
// If they don't report good D3D caps in any mode at all, we still need
// to return some caps, if only so we can support a SW driver.
if (FAILED(hr)) { GetHALCapsInCurrentMode(pHalData, pAdapterInfo, TRUE, TRUE); for (i = 0; i < pAdapterInfo->HALCaps.GDD8NumSupportedFormatOps; i++) { pAdapterInfo->HALCaps.pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwOperations &= D3DFORMAT_OP_DISPLAYMODE; } } }
//And now set back to original mode...
D3D8SetMode (pHalData->hDD, pAdapterInfo->DeviceName, OrigMode.Width, OrigMode.Height, OrigBpp, 0, TRUE); }
#undef DPF_MODNAME
#define DPF_MODNAME "GetRefCaps"
void CEnum::GetRefCaps(UINT iAdapter) { // If we've already got the caps once, there's ne need to get
// them again
if (m_REFCaps[iAdapter].GDD8NumSupportedFormatOps == 0) { AddSoftwareDevice(D3DDEVTYPE_REF, &m_REFCaps[iAdapter], &m_AdapterInfo[iAdapter], NULL); } }
void CEnum::GetSwCaps(UINT iAdapter) { // If we've already got the caps once, there's ne need to get
// them again
if (m_SwCaps[iAdapter].GDD8NumSupportedFormatOps == 0) { AddSoftwareDevice(D3DDEVTYPE_SW, &m_SwCaps[iAdapter], &m_AdapterInfo[iAdapter], m_pSwInitFunction); } }
// IsSupportedOp
// Runs the pixel format operation list looking to see if the
// selected format can support at least the requested operations.
#undef DPF_MODNAME
#define DPF_MODNAME "IsSupportedOp"
BOOL IsSupportedOp (D3DFORMAT Format, DDSURFACEDESC* pList, UINT NumElements, DWORD dwRequestedOps) { UINT i;
for (i = 0; i < NumElements; i++) { DDASSERT(pList[i].ddpfPixelFormat.dwFlags == DDPF_D3DFORMAT);
if (pList[i].ddpfPixelFormat.dwFourCC == (DWORD) Format && (pList[i].ddpfPixelFormat.dwOperations & dwRequestedOps) == dwRequestedOps) { return TRUE; } }
return FALSE; }
#undef DPF_MODNAME
#define DPF_MODNAME "IsInList"
BOOL IsInList (D3DFORMAT Format, D3DFORMAT* pList, UINT NumElements) { UINT i;
for (i = 0; i < NumElements; i++) { if (pList[i] == Format) { return TRUE; } }
return FALSE; }
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::MapDepthStencilFormat"
D3DFORMAT CEnum::MapDepthStencilFormat(UINT iAdapter, D3DDEVTYPE Type, D3DFORMAT Format) const { DXGASSERT(CPixel::IsMappedDepthFormat(D3DFMT_D24X8)); DXGASSERT(CPixel::IsMappedDepthFormat(D3DFMT_D15S1)); DXGASSERT(CPixel::IsMappedDepthFormat(D3DFMT_D24S8)); DXGASSERT(CPixel::IsMappedDepthFormat(D3DFMT_D16)); DXGASSERT(CPixel::IsMappedDepthFormat(D3DFMT_D24X4S4));
if (CPixel::IsMappedDepthFormat(Format)) { DDSURFACEDESC *pTextureList; UINT NumTextures;
switch (Type) { case D3DDEVTYPE_SW: pTextureList = m_SwCaps[iAdapter].pGDD8SupportedFormatOps; NumTextures = m_SwCaps[iAdapter].GDD8NumSupportedFormatOps; break;
case D3DDEVTYPE_HAL: NumTextures = m_AdapterInfo[iAdapter].HALCaps.GDD8NumSupportedFormatOps; pTextureList = m_AdapterInfo[iAdapter].HALCaps.pGDD8SupportedFormatOps; break;
case D3DDEVTYPE_REF: NumTextures = m_REFCaps[iAdapter].GDD8NumSupportedFormatOps; pTextureList = m_REFCaps[iAdapter].pGDD8SupportedFormatOps; break; }
// No operations are required; we just want to know
// if this format is listed in the table for any purpose
// at all
DWORD dwRequiredOperations = 0;
switch (Format) { case D3DFMT_D24X4S4: if (IsSupportedOp(D3DFMT_X4S4D24, pTextureList, NumTextures, dwRequiredOperations)) { return D3DFMT_X4S4D24; } break;
case D3DFMT_D24X8: if (IsSupportedOp(D3DFMT_X8D24, pTextureList, NumTextures, dwRequiredOperations)) { return D3DFMT_X8D24; } break;
case D3DFMT_D24S8: if (IsSupportedOp(D3DFMT_S8D24, pTextureList, NumTextures, dwRequiredOperations)) { return D3DFMT_S8D24; } break;
case D3DFMT_D16: if (IsSupportedOp(D3DFMT_D16, pTextureList, NumTextures, dwRequiredOperations)) { return D3DFMT_D16; } return D3DFMT_D16_LOCKABLE;
case D3DFMT_D15S1: if (IsSupportedOp(D3DFMT_S1D15, pTextureList, NumTextures, dwRequiredOperations)) { return D3DFMT_S1D15; } break;
default: // Unexpected format?
DXGASSERT(FALSE); break; } }
return Format; }
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::GetAdapterCaps"
HRESULT CEnum::GetAdapterCaps(UINT iAdapter, D3DDEVTYPE Type, D3D8_DRIVERCAPS** ppCaps) { *ppCaps = NULL; if (Type == D3DDEVTYPE_REF) { GetRefCaps (iAdapter); *ppCaps = &m_REFCaps[iAdapter]; if (m_REFCaps[iAdapter].GDD8NumSupportedFormatOps == 0) { DPF_ERR("The reference driver cannot be found. GetAdapterCaps fails."); return D3DERR_NOTAVAILABLE; } return D3D_OK; } else if (Type == D3DDEVTYPE_SW) { if (m_pSwInitFunction == NULL) { DPF_ERR("No SW device has been registered.. GetAdapterCaps fails."); return D3DERR_INVALIDCALL; } else { GetSwCaps(iAdapter); *ppCaps = &m_SwCaps[iAdapter]; if (m_SwCaps[iAdapter].GDD8NumSupportedFormatOps == 0) { DPF_ERR("The software driver cannot be loaded. GetAdapterCaps fails."); return D3DERR_NOTAVAILABLE; } return D3D_OK; } } else if (Type == D3DDEVTYPE_HAL) { DWORD i;
if (m_bDisableHAL) { DPF_ERR("HW device not available. GetAdapterCaps fails."); return D3DERR_NOTAVAILABLE; }
*ppCaps = &m_AdapterInfo[iAdapter].HALCaps; return D3D_OK; }
return D3DERR_INVALIDDEVICE; }
void GetDX8HALCaps(UINT iAdapter, PD3D8_DEVICEDATA pHalData, ADAPTERINFO * pAdapterInfo) { //DX7 or older drivers may need to be profiled to determine
//their 555/565 format and whether they support an alpha
//channel in 32bpp
D3DFORMAT CachedUnknown16 = D3DFMT_UNKNOWN; UINT CachedHALFlags = 0; D3DDISPLAYMODE Mode; BOOL bProfiled = FALSE; UINT i; HRESULT hr;
// If it's a DX8 driver, we hopefully don't need to profile at all.
pAdapterInfo->Unknown16 = D3DFMT_UNKNOWN; hr = GetHALCapsInCurrentMode(pHalData, pAdapterInfo, FALSE, FALSE); if (SUCCEEDED(hr)) { for (i = 0; i < pAdapterInfo->HALCaps.GDD8NumSupportedFormatOps; i++) { if (pAdapterInfo->HALCaps.pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_DISPLAYMODE) { switch (pAdapterInfo->HALCaps.pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwFourCC) { case D3DFMT_X1R5G5B5: case D3DFMT_R5G6B5: pAdapterInfo->Unknown16 = (D3DFORMAT) pAdapterInfo->HALCaps.pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwFourCC; break; } } }
if (pAdapterInfo->Unknown16 != D3DFMT_UNKNOWN) { // That wasn't hard
return; } }
// We are definately need to read stuff from the caps at some point,
// so why not now?
if (!ReadCapsFromCache(iAdapter, NULL, &CachedHALFlags, &CachedUnknown16, pAdapterInfo->DeviceName, pAdapterInfo->bIsDisplay)) { // There's nothing to read, so we need to re-profile
ProfileAdapter( pAdapterInfo, pHalData); bProfiled = TRUE; }
// If we profiled, then we already have everything that we need;
// otherwise, we have to go get it.
if (!bProfiled) { D3D8GetMode (pHalData->hDD, pAdapterInfo->DeviceName, &Mode, D3DFMT_UNKNOWN); if ((Mode.Format == D3DFMT_X1R5G5B5) || (Mode.Format == D3DFMT_R5G6B5)) { pAdapterInfo->Unknown16 = Mode.Format; } else { pAdapterInfo->Unknown16 = CachedUnknown16; }
HRESULT hCurrentModeIsSupported = GetHALCapsInCurrentMode(pHalData, pAdapterInfo, FALSE, TRUE);
if (FAILED(hCurrentModeIsSupported)) { // We assume that this will succeed because the call above already has
ReadCapsFromCache(iAdapter, &pAdapterInfo->HALCaps, &CachedHALFlags, &CachedUnknown16, pAdapterInfo->DeviceName, pAdapterInfo->bIsDisplay); DPF(0,"D3D not supported in current mode - reading caps from file"); } }
//We now have good caps. Write them out to the cache.
WriteCapsToCache(iAdapter, &pAdapterInfo->HALCaps, pAdapterInfo->HALFlags, pAdapterInfo->Unknown16, pAdapterInfo->DeviceName, pAdapterInfo->bIsDisplay); }
#ifdef WINNT
void FakeDirectDrawCreate (ADAPTERINFO * pAdapterInfo, int iAdapter) { HDC hdc; DDSURFACEDESC* pTextureList = NULL; BOOL bProfiled = FALSE; BOOL b32Supported; BOOL b16Supported; int NumOps; DWORD j; pTextureList = (DDSURFACEDESC *) MemAlloc (2 * sizeof (*pTextureList)); if (pTextureList != NULL) { hdc = DD_CreateDC(pAdapterInfo->DeviceName); if (hdc != NULL) { HANDLE hDD; HINSTANCE hLib;
D3D8CreateDirectDrawObject(hdc, pAdapterInfo->DeviceName, &hDD, D3DDEVTYPE_HAL, &hLib, NULL); if (hDD != NULL) { pAdapterInfo->bNoDDrawSupport = TRUE;
// Figure out the unknown 16 value
if (!ReadCapsFromCache(iAdapter, NULL, &(pAdapterInfo->HALFlags), &(pAdapterInfo->Unknown16), pAdapterInfo->DeviceName, pAdapterInfo->bIsDisplay)) { D3DDISPLAYMODE OrigMode; D3DDISPLAYMODE NewMode;
D3D8GetMode (hDD, pAdapterInfo->DeviceName, &OrigMode, D3DFMT_UNKNOWN);
if ((OrigMode.Format == D3DFMT_R5G6B5) || (OrigMode.Format == D3DFMT_X1R5G5B5)) { pAdapterInfo->Unknown16 = OrigMode.Format; } else { D3D8SetMode (hDD, pAdapterInfo->DeviceName, 640, 480, 16, 0, FALSE);
D3D8GetMode (hDD, pAdapterInfo->DeviceName, &NewMode, D3DFMT_UNKNOWN);
D3D8SetMode (hDD, pAdapterInfo->DeviceName, OrigMode.Width, OrigMode.Height, 0, 0, TRUE); pAdapterInfo->Unknown16 = NewMode.Format; } bProfiled = TRUE; }
// Build the mode table
while (1) { D3D8BuildModeTable( pAdapterInfo->DeviceName, NULL, &(pAdapterInfo->NumModes), pAdapterInfo->Unknown16, hDD, TRUE, TRUE); if (pAdapterInfo->NumModes) { pAdapterInfo->pModeTable = (D3DDISPLAYMODE*) MemAlloc (sizeof(D3DDISPLAYMODE) * pAdapterInfo->NumModes); if (pAdapterInfo->pModeTable != NULL) { D3D8BuildModeTable( pAdapterInfo->DeviceName, pAdapterInfo->pModeTable, &(pAdapterInfo->NumModes), pAdapterInfo->Unknown16, hDD, TRUE, TRUE);
//If D3D8BuildModeTable finds it needs more space for its table,
//it will return 0 to indicate we should try again.
if (0 == pAdapterInfo->NumModes) { MemFree(pAdapterInfo->pModeTable); pAdapterInfo->pModeTable = NULL; continue; } } else { pAdapterInfo->NumModes = 0; } } break; }//while(1)
// Now build a rudimentary op list based on what modes we support
b32Supported = b16Supported = FALSE; for (j = 0; j < pAdapterInfo->NumModes; j++) { if (pAdapterInfo->pModeTable[j].Format == D3DFMT_X8R8G8B8) { b32Supported = TRUE; } if (pAdapterInfo->pModeTable[j].Format == pAdapterInfo->Unknown16) { b16Supported = TRUE; } }
NumOps = 0; if (b16Supported) { pTextureList[NumOps].ddpfPixelFormat.dwFlags = DDPF_D3DFORMAT; pTextureList[NumOps].ddpfPixelFormat.dwFourCC = (DWORD) pAdapterInfo->Unknown16; pTextureList[NumOps].ddpfPixelFormat.dwOperations = D3DFORMAT_OP_DISPLAYMODE; pTextureList[NumOps].ddpfPixelFormat.dwPrivateFormatBitCount = 0; pTextureList[NumOps].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes = 0; pTextureList[NumOps].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes = 0; NumOps++; }
if (b32Supported) { pTextureList[NumOps].ddpfPixelFormat.dwFlags = DDPF_D3DFORMAT; pTextureList[NumOps].ddpfPixelFormat.dwFourCC = (DWORD) D3DFMT_X8R8G8B8; pTextureList[NumOps].ddpfPixelFormat.dwOperations = D3DFORMAT_OP_DISPLAYMODE; pTextureList[NumOps].ddpfPixelFormat.dwPrivateFormatBitCount = 0; pTextureList[NumOps].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes = 0; pTextureList[NumOps].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes = 0; NumOps++; }
pAdapterInfo->HALCaps.pGDD8SupportedFormatOps = pTextureList; pAdapterInfo->HALCaps.GDD8NumSupportedFormatOps = NumOps;
if (bProfiled) { WriteCapsToCache(iAdapter, &(pAdapterInfo->HALCaps), pAdapterInfo->HALFlags, pAdapterInfo->Unknown16, pAdapterInfo->DeviceName, pAdapterInfo->bIsDisplay); }
D3D8DeleteDirectDrawObject(hDD); } DD_DoneDC(hdc); } if (pAdapterInfo->HALCaps.pGDD8SupportedFormatOps == NULL) { MemFree(pTextureList); } } } #endif
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::CEnum"
CEnum::CEnum(UINT AppSdkVersion) : m_cRef(1), m_cAdapter(0), m_bHasExclusive(FALSE), m_AppSdkVersion(AppSdkVersion) { DWORD rc; DWORD keyidx; HKEY hkey; HKEY hsubkey; char keyname[256]; char desc[256]; char drvname[MAX_PATH]; DWORD cb; DWORD i; DWORD type; GUID guid; HDC hdc; DISPLAY_DEVICEA dd;
// Give our base class a pointer to ourselves
SetOwner(this);
// Initialize our critical section
EnableCriticalSection();
// Disable DPFs that occur during this phase
DPF_MUTE();
// WARNING: Must call DPF_UNMUTE before returning from
// this function.
for (i = 0; i < MAX_DX8_ADAPTERS; i++) m_pFullScreenDevice[i] = NULL;
ZeroMemory(m_AdapterInfo, sizeof(m_AdapterInfo));
// Always make the first entry reflect the primary device
ZeroMemory(&dd, sizeof(dd)); dd.cb = sizeof(dd); for (i = 0; xxxEnumDisplayDevicesA(NULL, i, &dd, 0); i++) { //
// skip drivers that are not hardware devices
//
if (dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) continue; //
// don't enumerate devices that are not attached
//
if (!(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) continue;
if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) { m_AdapterInfo[m_cAdapter].Guid = DisplayGUID; m_AdapterInfo[m_cAdapter].Guid.Data1 += i; lstrcpyn(m_AdapterInfo[m_cAdapter].DeviceName, dd.DeviceName, MAX_PATH); m_AdapterInfo[m_cAdapter].bIsPrimary = TRUE; m_AdapterInfo[m_cAdapter++].bIsDisplay = TRUE; } }
// Now get the info for the attached secondary devices
for (i = 0; xxxEnumDisplayDevicesA(NULL, i, &dd, 0); i++) { //
// skip drivers that are not hardware devices
//
if (dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) continue;
//
// don't enumerate devices that are not attached
//
if (!(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) continue;
if (!(dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) && (m_cAdapter < MAX_DX8_ADAPTERS)) { m_AdapterInfo[m_cAdapter].Guid = DisplayGUID; m_AdapterInfo[m_cAdapter].Guid.Data1 += i; lstrcpyn(m_AdapterInfo[m_cAdapter].DeviceName, dd.DeviceName, MAX_PATH); m_AdapterInfo[m_cAdapter].bIsPrimary = FALSE; m_AdapterInfo[m_cAdapter++].bIsDisplay = TRUE; } }
// Now get info for the passthrough devices listed under
// HKEY_LOCALMACHINE\Hardware\DirectDrawDrivers
if (RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_DDHW, &hkey) == 0) { keyidx = 0; while (!RegEnumKey(hkey, keyidx, keyname, sizeof(keyname))) { if (strToGUID(keyname, &guid)) { if (!RegOpenKey(hkey, keyname, &hsubkey)) { cb = sizeof(desc) - 1; if (!RegQueryValueEx(hsubkey, REGSTR_KEY_DDHW_DESCRIPTION, NULL, &type, (CONST LPBYTE)desc, &cb)) { if (type == REG_SZ) { desc[cb] = 0; cb = sizeof(drvname) - 1; if (!RegQueryValueEx(hsubkey, REGSTR_KEY_DDHW_DRIVERNAME, NULL, &type, (CONST LPBYTE)drvname, &cb)) { // It is possible that the registry is out
// of date, so we will try to create a DC.
// The problem is that the Voodoo 1 driver
// will suceed on a Voodoo 2, Banshee, or
// Voodoo 3 (and hang later), so we need to
// hack around it.
drvname[cb] = 0; if (Voodoo1GoodToGo(&guid)) { hdc = DD_CreateDC(drvname); } else { hdc = NULL; } if ((type == REG_SZ) && (hdc != NULL)) { if (m_cAdapter < MAX_DX8_ADAPTERS) { drvname[cb] = 0; m_AdapterInfo[m_cAdapter].Guid = guid; lstrcpyn(m_AdapterInfo[m_cAdapter].DeviceName, drvname, MAX_PATH); m_AdapterInfo[m_cAdapter].bIsPrimary = FALSE; m_AdapterInfo[m_cAdapter++].bIsDisplay = FALSE; } } if (hdc != NULL) { DD_DoneDC(hdc); } } } } RegCloseKey(hsubkey); } } keyidx++; } RegCloseKey(hkey); } DPF_UNMUTE();
// Now that we know about all of the devices, we need to build a mode
// table for each one
for (i = 0; i < m_cAdapter; i++) { HRESULT hr; D3DDISPLAYMODE Mode; DWORD j; BOOL b16bppSupported; BOOL b32bppSupported; PD3D8_DEVICEDATA pHalData;
hr = InternalDirectDrawCreate(&pHalData, &m_AdapterInfo[i], D3DDEVTYPE_HAL, NULL, D3DFMT_UNKNOWN, NULL, 0);
if (FAILED(hr)) { memset(&m_AdapterInfo[i].HALCaps, 0, sizeof(m_AdapterInfo[i].HALCaps));
// On Win2K, we want to enable sufficient functionality so that this
// adapter can at least run a sw driver. If it truly failed due to
// no ddraw support, we need to special case this and then build a
// rudimentary op list indicting that it works in the current mode.
#ifdef WINNT
FakeDirectDrawCreate(&m_AdapterInfo[i], i); #endif
} else { GetDX8HALCaps(i, pHalData, &m_AdapterInfo[i]);
b16bppSupported = b32bppSupported = FALSE; for (j = 0; j < m_AdapterInfo[i].HALCaps.GDD8NumSupportedFormatOps; j++) { if (m_AdapterInfo[i].HALCaps.pGDD8SupportedFormatOps[j].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_DISPLAYMODE) { switch(m_AdapterInfo[i].HALCaps.pGDD8SupportedFormatOps[j].ddpfPixelFormat.dwFourCC) { case D3DFMT_X1R5G5B5: case D3DFMT_R5G6B5: b16bppSupported = TRUE; break;
case D3DFMT_X8R8G8B8: b32bppSupported = TRUE; break; } } }
while (1) { D3D8BuildModeTable( m_AdapterInfo[i].DeviceName, NULL, &m_AdapterInfo[i].NumModes, m_AdapterInfo[i].Unknown16, pHalData->hDD, b16bppSupported, b32bppSupported); if (m_AdapterInfo[i].NumModes) { m_AdapterInfo[i].pModeTable = (D3DDISPLAYMODE*) MemAlloc (sizeof(D3DDISPLAYMODE) * m_AdapterInfo[i].NumModes); if (m_AdapterInfo[i].pModeTable != NULL) { D3D8BuildModeTable( m_AdapterInfo[i].DeviceName, m_AdapterInfo[i].pModeTable, &m_AdapterInfo[i].NumModes, m_AdapterInfo[i].Unknown16, pHalData->hDD, b16bppSupported, b32bppSupported);
//If D3D8BuildModeTable finds it needs more space for its table,
//it will return 0 to indicate we should try again.
if (0 == m_AdapterInfo[i].NumModes) { MemFree(m_AdapterInfo[i].pModeTable); m_AdapterInfo[i].pModeTable = NULL; continue; } } else { m_AdapterInfo[i].NumModes = 0; } } break; }//while(1)
// If this doesn't have a ddraw HAL, but guessed that it might
// support a 32bpp mode, go see if we were right.
if (b32bppSupported && (m_AdapterInfo[i].HALCaps.D3DCaps.DevCaps == 0) && (m_AdapterInfo[i].HALCaps.DisplayFormatWithoutAlpha != D3DFMT_X8R8G8B8)) { for (j = 0; j < m_AdapterInfo[i].NumModes; j++) { if (m_AdapterInfo[i].pModeTable[j].Format == D3DFMT_X8R8G8B8) { break; } } if (j >= m_AdapterInfo[i].NumModes) { // This card apparently does NOT support 32bpp so remove it
for (j = 0; j < m_AdapterInfo[i].HALCaps.GDD8NumSupportedFormatOps; j++) { if ((m_AdapterInfo[i].HALCaps.pGDD8SupportedFormatOps[j].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_DISPLAYMODE) && (m_AdapterInfo[i].HALCaps.pGDD8SupportedFormatOps[j].ddpfPixelFormat.dwFourCC == D3DFMT_X8R8G8B8)) { m_AdapterInfo[i].HALCaps.pGDD8SupportedFormatOps[j].ddpfPixelFormat.dwOperations &= ~D3DFORMAT_OP_DISPLAYMODE; } } } }
InternalDirectDrawRelease(pHalData); } }
m_hGammaCalibrator = NULL; m_pGammaCalibratorProc = NULL; m_bAttemptedGammaCalibrator= FALSE; m_bGammaCalibratorExists = FALSE;
// The first time through, we will also check to see if a gamma
// calibrator is registered. All we'll do here is read the registry
// key and if it's non-NULL, we'll assume that one exists.
{ HKEY hkey; if (!RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_DDRAW "\\" REGSTR_KEY_GAMMA_CALIBRATOR, &hkey)) { DWORD type; DWORD cb;
cb = sizeof(m_szGammaCalibrator); if (!RegQueryValueEx(hkey, REGSTR_VAL_GAMMA_CALIBRATOR, NULL, &type, m_szGammaCalibrator, &cb)) { if ((type == REG_SZ) && (m_szGammaCalibrator[0] != '\0')) { m_bGammaCalibratorExists = TRUE; } } RegCloseKey(hkey); } }
// Check to see if they disabled the D3DHAL in the registry
{ HKEY hKey; if (!RegOpenKey(HKEY_LOCAL_MACHINE, RESPATH_D3D "\\Drivers", &hKey)) { DWORD type; DWORD value; DWORD cb = sizeof(value);
if (!RegQueryValueEx(hKey, "SoftwareOnly", NULL, &type, (CONST LPBYTE)&value, &cb)) { if (value) { m_bDisableHAL = TRUE; } else { m_bDisableHAL = FALSE; } } RegCloseKey(hKey); } }
DXGASSERT(IsValid());
} // CEnum::CEnum
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::GetAdapterCount"
STDMETHODIMP_(UINT) CEnum::GetAdapterCount() { API_ENTER_RET(this, UINT);
return m_cAdapter; } // GetAdapterCount
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::GetAdapterIdentifier"
STDMETHODIMP CEnum::GetAdapterIdentifier( UINT iAdapter, DWORD dwFlags, D3DADAPTER_IDENTIFIER8 *pIdentifier) { API_ENTER(this);
if (!VALID_WRITEPTR(pIdentifier, sizeof(D3DADAPTER_IDENTIFIER8))) { DPF_ERR("Invalid pIdentifier parameter specified for GetAdapterIdentifier"); return D3DERR_INVALIDCALL; }
memset(pIdentifier, 0, sizeof(*pIdentifier));
if (dwFlags & ~VALID_D3DENUM_FLAGS) { DPF_ERR("Invalid flags specified. GetAdapterIdentifier fails."); return D3DERR_INVALIDCALL; }
if (iAdapter >= m_cAdapter) { DPF_ERR("Invalid Adapter number specified. GetAdapterIdentifier fails."); return D3DERR_INVALIDCALL; }
// Need driver name
GetAdapterInfo (m_AdapterInfo[iAdapter].DeviceName, pIdentifier, m_AdapterInfo[iAdapter].bIsDisplay, (dwFlags & D3DENUM_NO_WHQL_LEVEL) ? TRUE : FALSE, TRUE);
return D3D_OK; } // GetAdapterIdentifier
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::GetAdapterModeCount"
STDMETHODIMP_(UINT) CEnum::GetAdapterModeCount( UINT iAdapter) { API_ENTER_RET(this, UINT);
if (iAdapter >= m_cAdapter) { DPF_ERR("Invalid adapter specified. GetAdapterModeCount returns zero."); return 0; } return m_AdapterInfo[iAdapter].NumModes; } // GetAdapterModeCount
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::EnumAdapterModes"
STDMETHODIMP CEnum::EnumAdapterModes( UINT iAdapter, UINT iMode, D3DDISPLAYMODE* pMode) { API_ENTER(this);
if (iAdapter >= m_cAdapter) { DPF_ERR("Invalid adapter specified. EnumAdapterModes fails."); return D3DERR_INVALIDCALL; }
if (iMode >= m_AdapterInfo[iAdapter].NumModes) { DPF_ERR("Invalid mode number specified. EnumAdapterModes fails."); return D3DERR_INVALIDCALL; }
if (!VALID_WRITEPTR(pMode, sizeof(D3DDISPLAYMODE))) { DPF_ERR("Invalid pMode parameter specified for EnumAdapterModes"); return D3DERR_INVALIDCALL; }
*pMode = m_AdapterInfo[iAdapter].pModeTable[iMode];
return D3D_OK; } // EnumAdapterModes
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::GetAdapterMonitor"
HMONITOR CEnum::GetAdapterMonitor(UINT iAdapter) { API_ENTER_RET(this, HMONITOR);
if (iAdapter >= m_cAdapter) { DPF_ERR("Invalid adapter specified. GetAdapterMonitor returns NULL"); return NULL; }
return GetMonitorFromDeviceName((LPSTR)m_AdapterInfo[iAdapter].DeviceName); } // GetAdapterMonitor
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::CheckDeviceFormat"
STDMETHODIMP CEnum::CheckDeviceFormat( UINT iAdapter, D3DDEVTYPE DevType, D3DFORMAT DisplayFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) { API_ENTER(this);
D3D8_DRIVERCAPS* pAdapterCaps; HRESULT hr;
// Check parameters
if (iAdapter >= m_cAdapter) { DPF_ERR("Invalid adapter specified. CheckDeviceFormat fails"); return D3DERR_INVALIDCALL; }
// Check Device Type
if (DevType != D3DDEVTYPE_REF && DevType != D3DDEVTYPE_HAL && DevType != D3DDEVTYPE_SW) { DPF_ERR("Invalid device specified to CheckDeviceFormat"); return D3DERR_INVALIDCALL; }
if ((DisplayFormat == D3DFMT_UNKNOWN) || (CheckFormat == D3DFMT_UNKNOWN)) { DPF(0, "D3DFMT_UNKNOWN is not a valid format."); return D3DERR_INVALIDCALL; }
// Sanity check the input format
if ((DisplayFormat != D3DFMT_X8R8G8B8) && (DisplayFormat != D3DFMT_R5G6B5) && (DisplayFormat != D3DFMT_X1R5G5B5) && (DisplayFormat != D3DFMT_R8G8B8)) { DPF(1, "D3D Unsupported for the adapter format passed to CheckDeviceFormat"); return D3DERR_NOTAVAILABLE; }
//We infer the texture usage from type...
if (RType == D3DRTYPE_TEXTURE || RType == D3DRTYPE_CUBETEXTURE || RType == D3DRTYPE_VOLUMETEXTURE) { Usage |= D3DUSAGE_TEXTURE; }
// Surface should be either render targets or Z/Stencil
else if (RType == D3DRTYPE_SURFACE) { if (!(Usage & D3DUSAGE_DEPTHSTENCIL) && !(Usage & D3DUSAGE_RENDERTARGET)) { DPF_ERR("Must specify either D3DUSAGE_DEPTHSTENCIL or D3DUSAGE_RENDERTARGET for D3DRTYPE_SURFACE. CheckDeviceFormat fails."); return D3DERR_INVALIDCALL; } }
// Any attempt to query anything but an unknown Z/stencil
// or D16 value must fail (because we explicitly don't allow apps to
// know what the z/stencil format really is, except for D16).
if (Usage & D3DUSAGE_DEPTHSTENCIL) { if (!CPixel::IsEnumeratableZ(CheckFormat)) { DPF_ERR("Format is not in approved list for Z buffer formats. CheckDeviceFormats fails."); return D3DERR_INVALIDCALL; } }
// Parameter check for invalid usages and resource types
if ((RType != D3DRTYPE_SURFACE) && (RType != D3DRTYPE_VOLUME) && (RType != D3DRTYPE_TEXTURE) && (RType != D3DRTYPE_VOLUMETEXTURE) && (RType != D3DRTYPE_CUBETEXTURE)) { DPF_ERR("Invalid resource type specified. CheckDeviceFormat fails."); return D3DERR_INVALIDCALL; }
if (Usage & ~(D3DUSAGE_EXTERNAL | D3DUSAGE_LOCK | D3DUSAGE_TEXTURE | D3DUSAGE_BACKBUFFER | D3DUSAGE_INTERNALBUFFER | D3DUSAGE_OFFSCREENPLAIN | D3DUSAGE_PRIMARYSURFACE)) { DPF_ERR("Invalid usage flag specified. CheckDeviceFormat fails."); return D3DERR_INVALIDCALL; }
hr = GetAdapterCaps(iAdapter, DevType, &pAdapterCaps); if (FAILED(hr)) { return hr; }
// Check if USAGE_DYNAMIC is allowed
if ((Usage & D3DUSAGE_DYNAMIC) && (Usage & D3DUSAGE_TEXTURE)) { if (!(pAdapterCaps->D3DCaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES)) { DPF_ERR("Driver does not support dynamic textures."); return D3DERR_INVALIDCALL; } if (Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) { DPF_ERR("Dynamic textures cannot be rendertargets or depth/stencils."); return D3DERR_INVALIDCALL; } }
// Make sure that the specified display format is supported
if (!IsSupportedOp (DisplayFormat, pAdapterCaps->pGDD8SupportedFormatOps, pAdapterCaps->GDD8NumSupportedFormatOps, D3DFORMAT_OP_DISPLAYMODE |D3DFORMAT_OP_3DACCELERATION)) { return D3DERR_NOTAVAILABLE; }
//We now need to map the API desires to the set of capabilities that we
//allow drivers to express in their DX8 pixel format operation list.
DWORD dwRequiredOperations=0;
//We have three different texturing methodologies that the driver may
//support independently
switch(RType) { case D3DRTYPE_TEXTURE: dwRequiredOperations |= D3DFORMAT_OP_TEXTURE; break; case D3DRTYPE_VOLUMETEXTURE: dwRequiredOperations |= D3DFORMAT_OP_VOLUMETEXTURE; break; case D3DRTYPE_CUBETEXTURE: dwRequiredOperations |= D3DFORMAT_OP_CUBETEXTURE; break; }
// If it's a depth/stencil, make sure it's a format that the driver understands
CheckFormat = MapDepthStencilFormat(iAdapter, DevType, CheckFormat);
//Render targets may be the same format as the display, or they may
//be different
if (Usage & D3DUSAGE_RENDERTARGET) { if (DisplayFormat == CheckFormat) { // We have a special cap for the case when the offscreen is the
// same format as the display
dwRequiredOperations |= D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET; } else if ((CPixel::SuppressAlphaChannel(CheckFormat) != CheckFormat) && //offscreen has alpha
(CPixel::SuppressAlphaChannel(CheckFormat) == DisplayFormat)) //offscreen is same as display mod alpha
{ //We have a special cap for the case when the offscreen is the same
//format as the display modulo the alpha channel
//(such as X8R8G8B8 for the primary and A8R8G8B8 for the offscreen).
dwRequiredOperations |= D3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET; } else { dwRequiredOperations |= D3DFORMAT_OP_OFFSCREEN_RENDERTARGET; } }
//Some hardware doesn't support Z and color buffers of differing pixel depths.
//We only do this check on known z/stencil formats, since drivers are free
//to spoof unknown formats (they can't be locked).
// Now we know what we're being asked to do on this format...
// let's run through the driver's list and see if it can do it.
for(UINT i=0;i< pAdapterCaps->GDD8NumSupportedFormatOps; i++) { // We need a match for format, plus all the requested operation flags
if ((CheckFormat == (D3DFORMAT) pAdapterCaps->pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwFourCC) && (dwRequiredOperations == (dwRequiredOperations & pAdapterCaps->pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwOperations))) { return D3D_OK; } }
// We don't spew info here; because NotAvailable is a reasonable
// usage of the API; this doesn't reflect an app bug or an
// anomalous circumstance where a message would be useful
return D3DERR_NOTAVAILABLE; }
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::CheckDeviceType"
STDMETHODIMP CEnum::CheckDeviceType( UINT iAdapter, D3DDEVTYPE DevType, D3DFORMAT DisplayFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed) { API_ENTER(this);
D3D8_DRIVERCAPS* pAdapterCaps; HRESULT hr;
if (iAdapter >= m_cAdapter) { DPF_ERR("Invalid adapter specified. CheckDeviceType fails."); return D3DERR_INVALIDCALL; }
if (DevType != D3DDEVTYPE_REF && DevType != D3DDEVTYPE_HAL && DevType != D3DDEVTYPE_SW) { DPF_ERR("Invalid device specified to CheckDeviceType"); return D3DERR_INVALIDCALL; }
if ((DisplayFormat == D3DFMT_UNKNOWN) || (BackBufferFormat == D3DFMT_UNKNOWN)) { DPF(0, "D3DFMT_UNKNOWN is not a valid format."); return D3DERR_INVALIDCALL; }
// Force the backbuffer format to be one of the 16 or 32bpp formats (not
// 24bpp). We do this because DX8 shipped with a similar check in Reset,
// and we want to be consistent.
if ((BackBufferFormat != D3DFMT_X1R5G5B5) && (BackBufferFormat != D3DFMT_A1R5G5B5) && (BackBufferFormat != D3DFMT_R5G6B5) && (BackBufferFormat != D3DFMT_X8R8G8B8) && (BackBufferFormat != D3DFMT_A8R8G8B8)) { // We should return D3DDERR_INVALIDCALL, but we didn't ship that way for
// DX8 and we don't want to cause regressions, so NOTAVAILABLE is safer.
DPF(1, "Invalid backbuffer format specified"); return D3DERR_NOTAVAILABLE; }
// Sanity check the input format
if ((DisplayFormat != D3DFMT_X8R8G8B8) && (DisplayFormat != D3DFMT_R5G6B5) && (DisplayFormat != D3DFMT_X1R5G5B5) && (DisplayFormat != D3DFMT_R8G8B8)) { DPF(1, "D3D Unsupported for the adapter format passed to CheckDeviceType"); return D3DERR_NOTAVAILABLE; }
hr = GetAdapterCaps(iAdapter, DevType, &pAdapterCaps); if (FAILED(hr)) { return hr; }
// Is the display mode supported?
if (!IsSupportedOp (DisplayFormat, pAdapterCaps->pGDD8SupportedFormatOps, pAdapterCaps->GDD8NumSupportedFormatOps, D3DFORMAT_OP_DISPLAYMODE |D3DFORMAT_OP_3DACCELERATION)) { return D3DERR_NOTAVAILABLE; }
if (DisplayFormat != BackBufferFormat) { D3DFORMAT AlphaFormat = D3DFMT_UNKNOWN; UINT i;
// This is allowed only if the only difference is alpha.
switch (DisplayFormat) { case D3DFMT_X1R5G5B5: AlphaFormat = D3DFMT_A1R5G5B5; break;
case D3DFMT_X8R8G8B8: AlphaFormat = D3DFMT_A8R8G8B8; break; }
hr = D3DERR_NOTAVAILABLE; if (AlphaFormat == BackBufferFormat) { if (IsSupportedOp (AlphaFormat, pAdapterCaps->pGDD8SupportedFormatOps, pAdapterCaps->GDD8NumSupportedFormatOps, D3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET)) { hr = D3D_OK; } } } else { // For DX8, we force the backbuffer and display formats to match
// (minus alpha). This means that they should support a render target
// of the same format.
if (!IsSupportedOp (DisplayFormat, pAdapterCaps->pGDD8SupportedFormatOps, pAdapterCaps->GDD8NumSupportedFormatOps, D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET)) { return D3DERR_NOTAVAILABLE; } }
if (SUCCEEDED(hr)) { if (bWindowed && !(pAdapterCaps->D3DCaps.Caps2 & DDCAPS2_CANRENDERWINDOWED)) { hr = D3DERR_NOTAVAILABLE; } }
return hr; }
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::GetAdapterDisplayMode"
STDMETHODIMP CEnum::GetAdapterDisplayMode(UINT iAdapter, D3DDISPLAYMODE* pMode) { API_ENTER(this);
HANDLE h; HRESULT hr = D3D_OK;
if (iAdapter >= m_cAdapter) { DPF_ERR("Invalid adapter specified. GetAdapterDisplayMode fails"); return D3DERR_INVALIDCALL; }
if (!VALID_WRITEPTR(pMode, sizeof(D3DDISPLAYMODE))) { DPF_ERR("Invalid pMode parameter specified for GetAdapterDisplayMode"); return D3DERR_INVALIDCALL; }
if (m_AdapterInfo[iAdapter].bIsDisplay) { D3D8GetMode (NULL, m_AdapterInfo[iAdapter].DeviceName, pMode, m_AdapterInfo[iAdapter].Unknown16); } else { PD3D8_DEVICEDATA pDeviceData;
hr = InternalDirectDrawCreate(&pDeviceData, &m_AdapterInfo[iAdapter], D3DDEVTYPE_HAL, NULL, m_AdapterInfo[iAdapter].Unknown16, m_AdapterInfo[iAdapter].HALCaps.pGDD8SupportedFormatOps, m_AdapterInfo[iAdapter].HALCaps.GDD8NumSupportedFormatOps); if (SUCCEEDED(hr)) { D3D8GetMode (pDeviceData->hDD, m_AdapterInfo[iAdapter].DeviceName, pMode, D3DFMT_UNKNOWN); InternalDirectDrawRelease(pDeviceData); } }
return hr; }
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::EnumDeviceMultiSampleType"
STDMETHODIMP CEnum::CheckDeviceMultiSampleType( UINT iAdapter, D3DDEVTYPE DevType, D3DFORMAT RTFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE SampleType) { API_ENTER(this);
// Check parameters
if (iAdapter >= m_cAdapter) { DPF_ERR("Invalid adapter specified. CheckDeviceMultiSampleType fails."); return D3DERR_INVALIDCALL; }
// Check Device Type
if (DevType != D3DDEVTYPE_REF && DevType != D3DDEVTYPE_HAL && DevType != D3DDEVTYPE_SW) { DPF_ERR("Invalid device specified to CheckDeviceMultiSampleType"); return D3DERR_INVALIDCALL; }
if (RTFormat == D3DFMT_UNKNOWN) { DPF_ERR("D3DFMT_UNKNOWN is not a valid format. CheckDeviceMultiSampleType fails."); return D3DERR_INVALIDCALL; }
D3D8_DRIVERCAPS* pAdapterCaps; HRESULT hr;
hr = GetAdapterCaps(iAdapter, DevType, &pAdapterCaps); if (FAILED(hr)) { return hr; }
if (SampleType == D3DMULTISAMPLE_NONE) { return D3D_OK; } else if (SampleType == 1) { DPF_ERR("Invalid sample type specified. Only enumerated values are supported. CheckDeviceMultiSampleType fails."); return D3DERR_INVALIDCALL; } else if (SampleType > D3DMULTISAMPLE_16_SAMPLES) { DPF_ERR("Invalid sample type specified. CheckDeviceMultiSampleType fails."); return D3DERR_INVALIDCALL; }
// Treat Ref/SW Fullscreen the same as Windowed.
if (DevType == D3DDEVTYPE_REF || DevType == D3DDEVTYPE_SW) { Windowed = TRUE; }
// If it's a depth/stencil, make sure it's a format that the driver understands
RTFormat = MapDepthStencilFormat(iAdapter, DevType, RTFormat);
DDSURFACEDESC * pDX8SupportedFormatOperations = pAdapterCaps->pGDD8SupportedFormatOps;
// let's run through the driver's list and see if it can do it.
for (UINT i = 0; i < pAdapterCaps->GDD8NumSupportedFormatOps; i++) { //We need a match for format, plus all either blt or flip caps
if (RTFormat == (D3DFORMAT) pDX8SupportedFormatOperations[i].ddpfPixelFormat.dwFourCC) { // Found the format in question... do we have the MS caps?
WORD wMSOps = Windowed ? pDX8SupportedFormatOperations[i].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes : pDX8SupportedFormatOperations[i].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes;
// To determine the bit to use, we map the set of sample-types [2-16] to
// a particular (bit 1 to bit 15) of the WORD.
DXGASSERT(SampleType > 1); DXGASSERT(SampleType <= 16); if (wMSOps & DDI_MULTISAMPLE_TYPE(SampleType)) { return D3D_OK; } } }
return D3DERR_NOTAVAILABLE;
} // CheckDeviceMultiSampleType
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::CheckDepthStencilMatch"
STDMETHODIMP CEnum::CheckDepthStencilMatch(UINT iAdapter, D3DDEVTYPE DevType, D3DFORMAT AdapterFormat, D3DFORMAT RTFormat, D3DFORMAT DSFormat) { API_ENTER(this);
HRESULT hr;
// Check parameters
if (iAdapter >= m_cAdapter) { DPF_ERR("Invalid adapter specified. CheckDepthStencilMatch fails."); return D3DERR_INVALIDCALL; }
// Check Device Type
if (DevType != D3DDEVTYPE_REF && DevType != D3DDEVTYPE_HAL && DevType != D3DDEVTYPE_SW) { DPF_ERR("Invalid device specified to CheckDepthStencilMatch"); return D3DERR_INVALIDCALL; }
if ((AdapterFormat == D3DFMT_UNKNOWN) || (RTFormat == D3DFMT_UNKNOWN) || (DSFormat == D3DFMT_UNKNOWN)) { DPF_ERR("D3DFMT_UNKNOWN is not a valid format. CheckDepthStencilMatch fails."); return D3DERR_INVALIDCALL; }
D3D8_DRIVERCAPS *pAdapterCaps = NULL; hr = GetAdapterCaps(iAdapter, DevType, &pAdapterCaps); if (FAILED(hr)) { return hr; }
// Is the display mode supported?
if (!IsSupportedOp (AdapterFormat, pAdapterCaps->pGDD8SupportedFormatOps, pAdapterCaps->GDD8NumSupportedFormatOps, D3DFORMAT_OP_DISPLAYMODE |D3DFORMAT_OP_3DACCELERATION)) { return D3DERR_NOTAVAILABLE; }
DDSURFACEDESC * pDX8SupportedFormatOperations = pAdapterCaps->pGDD8SupportedFormatOps;
// Decide what we need to check
BOOL bCanDoRT = FALSE; BOOL bCanDoDS = FALSE; BOOL bMatchNeededForDS = FALSE;
// We only need to check for matching if the user is trying
// to use D3DFMT_D16 or has Stencil
if (DSFormat == D3DFMT_D16_LOCKABLE || CPixel::HasStencilBits(DSFormat)) { bMatchNeededForDS = TRUE; }
//In DX8.1 and beyond, we also make this function check D24X8 and D32, since all known parts that have restrictions
//also have this restriction
if (GetAppSdkVersion() > D3D_SDK_VERSION_DX8) { switch (DSFormat) { case D3DFMT_D24X8: case D3DFMT_D32: bMatchNeededForDS = TRUE; } }
DWORD dwRequiredZOps = D3DFORMAT_OP_ZSTENCIL;
// If it's a depth/stencil, make sure it's a format that the driver understands
DSFormat = MapDepthStencilFormat(iAdapter, DevType, DSFormat);
// let's run through the driver's list and see if this all
// works
for (UINT i = 0; i < pAdapterCaps->GDD8NumSupportedFormatOps; i++) { // See if it matches the RT format
if (RTFormat == (D3DFORMAT) pDX8SupportedFormatOperations[i].ddpfPixelFormat.dwFourCC) { // Found the RT Format, can we use as a render-target?
// we check the format that has the least constraints so that
// we are truly checking "For all possible RTs that I can make
// with this device, does the Z match it?" We'd like to say
// "No." if you couldn't make the RT at all in any circumstance.
if (D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET & pAdapterCaps->pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwOperations) { bCanDoRT = TRUE; }
}
// See if it matches the DS Format
if (DSFormat == (D3DFORMAT) pDX8SupportedFormatOperations[i].ddpfPixelFormat.dwFourCC) { // Found the DS format, can we use it as DS (and potentially lockable)?
// i.e. if ALL required bits are on in this FOL entry.
// Again, we check the formats that have the least constraints.
if (dwRequiredZOps == (dwRequiredZOps & pAdapterCaps->pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwOperations) ) { bCanDoDS = TRUE;
if (D3DFORMAT_OP_ZSTENCIL_WITH_ARBITRARY_COLOR_DEPTH & pAdapterCaps->pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwOperations) { bMatchNeededForDS = FALSE; } } } }
if (!bCanDoRT) { DPF_ERR("RenderTarget Format is not supported for this " "Adapter/DevType/AdapterFormat. This error can happen if the " "application has not successfully called CheckDeviceFormats on the " "specified Format prior to calling CheckDepthStencilMatch. The application " "is advised to call CheckDeviceFormats on this format first, because a " "success return from CheckDepthStencilMatch does not guarantee " "that the format is valid as a RenderTarget for all possible cases " "i.e. D3DRTYPE_TEXTURE or D3DRTYPE_SURFACE or D3DRTYPE_CUBETEXTURE."); return D3DERR_INVALIDCALL; } if (!bCanDoDS) { DPF_ERR("DepthStencil Format is not supported for this " "Adapter/DevType/AdapterFormat. This error can happen if the " "application has not successfully called CheckDeviceFormats on the " "specified Format prior to calling CheckDepthStencilMatch. The application " "is advised to call CheckDeviceFormats on this format first, because a " "success return from CheckDepthStencilMatch does not guarantee " "that the format is valid as a DepthStencil buffer for all possible cases " "i.e. D3DRTYPE_TEXTURE or D3DRTYPE_SURFACE or D3DRTYPE_CUBETEXTURE."); return D3DERR_INVALIDCALL; } if (bMatchNeededForDS) { // Check if the DS depth matches the RT depth
if (CPixel::ComputePixelStride(RTFormat) != CPixel::ComputePixelStride(DSFormat)) { DPF(1, "Specified DepthStencil Format can not be used with RenderTarget Format"); return D3DERR_NOTAVAILABLE; } }
// Otherwise, we now know that the both the RT and DS formats
// are valid and that they match if they need to.
DXGASSERT(bCanDoRT && bCanDoDS);
return S_OK; } // CheckDepthStencilMatch
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::FillInCaps"
void CEnum::FillInCaps (D3DCAPS8 *pCaps, const D3D8_DRIVERCAPS *pDriverCaps, D3DDEVTYPE Type, UINT AdapterOrdinal) const { memset(pCaps, 0, sizeof(D3DCAPS8));
//
// do 3D caps first so we can copy the struct and clear the (few) non-3D fields
//
if (pDriverCaps->dwFlags & DDIFLAG_D3DCAPS8) { // set 3D fields from caps8 struct from driver
*pCaps = pDriverCaps->D3DCaps;
if (Type == D3DDEVTYPE_HAL) { pCaps->DevCaps |= D3DDEVCAPS_HWRASTERIZATION; }
} else { // ASSERT here
DDASSERT(FALSE); }
//
// non-3D caps
//
pCaps->DeviceType = Type; pCaps->AdapterOrdinal = AdapterOrdinal;
pCaps->Caps = pDriverCaps->D3DCaps.Caps & (DDCAPS_READSCANLINE | DDCAPS_NOHARDWARE); pCaps->Caps2 = pDriverCaps->D3DCaps.Caps2 & (DDCAPS2_NO2DDURING3DSCENE | DDCAPS2_PRIMARYGAMMA | DDCAPS2_CANRENDERWINDOWED | DDCAPS2_STEREO | DDCAPS2_DYNAMICTEXTURES | #ifdef WINNT
(IsWhistler() ? DDCAPS2_CANMANAGERESOURCE : 0)); #else
DDCAPS2_CANMANAGERESOURCE); #endif
// Special case: gamma calibrator is loaded by the enumerator...
if (m_bGammaCalibratorExists) pCaps->Caps2 |= DDCAPS2_CANCALIBRATEGAMMA;
pCaps->Caps3 = pDriverCaps->D3DCaps.Caps3 & ~D3DCAPS3_RESERVED; //mask off the old stereo flags.
pCaps->PresentationIntervals = D3DPRESENT_INTERVAL_ONE; if (pDriverCaps->D3DCaps.Caps2 & DDCAPS2_FLIPINTERVAL) { pCaps->PresentationIntervals |= (D3DPRESENT_INTERVAL_TWO | D3DPRESENT_INTERVAL_THREE | D3DPRESENT_INTERVAL_FOUR); } if (pDriverCaps->D3DCaps.Caps2 & DDCAPS2_FLIPNOVSYNC) { pCaps->PresentationIntervals |= (D3DPRESENT_INTERVAL_IMMEDIATE); }
// Mask out the HW VB and IB caps
pCaps->DevCaps &= ~(D3DDEVCAPS_HWVERTEXBUFFER | D3DDEVCAPS_HWINDEXBUFFER);
// Clear internal caps
pCaps->PrimitiveMiscCaps &= ~D3DPMISCCAPS_FOGINFVF;
// Fix up the vertex fog cap.
if (pCaps->VertexProcessingCaps & D3DVTXPCAPS_RESERVED) { pCaps->RasterCaps |= D3DPRASTERCAPS_FOGVERTEX; pCaps->VertexProcessingCaps &= ~D3DVTXPCAPS_RESERVED; }
} // FillInCaps
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::GetDeviceCaps"
STDMETHODIMP CEnum::GetDeviceCaps( UINT iAdapter, D3DDEVTYPE Type, D3DCAPS8 *pCaps) { API_ENTER(this);
BOOL bValidRTFormat; D3DFORMAT Format; D3D8_DRIVERCAPS* pAdapterCaps; HRESULT hr; DWORD i;
if (iAdapter >= m_cAdapter) { DPF_ERR("Invalid adapter specified. GetDeviceCaps fails."); return D3DERR_INVALIDCALL; } if (!VALID_WRITEPTR(pCaps, sizeof(D3DCAPS8))) { DPF_ERR("Invalid pointer to D3DCAPS8 specified. GetDeviceCaps fails."); return D3DERR_INVALIDCALL; }
hr = GetAdapterCaps(iAdapter, Type, &pAdapterCaps); if (FAILED(hr)) { // No caps for this type of device
memset(pCaps, 0, sizeof(D3DCAPS8)); return hr; }
// Fail this call if the driver dosn't support any accelerated modes
for (i = 0; i < pAdapterCaps->GDD8NumSupportedFormatOps; i++) { if (pAdapterCaps->pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_3DACCELERATION) { break; } } if (i == pAdapterCaps->GDD8NumSupportedFormatOps) { // No caps for this type of device
memset(pCaps, 0, sizeof(D3DCAPS8)); return D3DERR_NOTAVAILABLE; }
FillInCaps (pCaps, pAdapterCaps, Type, iAdapter);
if (pCaps->MaxPointSize == 0) { pCaps->MaxPointSize = 1.0f; }
return D3D_OK; } // GetDeviceCaps
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::LoadAndCallGammaCalibrator"
void CEnum::LoadAndCallGammaCalibrator( D3DGAMMARAMP *pRamp, UCHAR * pDeviceName) { API_ENTER_VOID(this);
if (!m_bAttemptedGammaCalibrator) { m_bAttemptedGammaCalibrator = TRUE;
m_hGammaCalibrator = LoadLibrary((char*) m_szGammaCalibrator); if (m_hGammaCalibrator) { m_pGammaCalibratorProc = (LPDDGAMMACALIBRATORPROC) GetProcAddress(m_hGammaCalibrator, "CalibrateGammaRamp");
if (m_pGammaCalibratorProc == NULL) { FreeLibrary((HMODULE) m_hGammaCalibrator); m_hGammaCalibrator = NULL; } } }
if (m_pGammaCalibratorProc) { m_pGammaCalibratorProc((LPDDGAMMARAMP) pRamp, pDeviceName); } } // LoadAndCallGammaCalibrator
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::RegisterSoftwareDevice"
STDMETHODIMP CEnum::RegisterSoftwareDevice( void* pInitFunction) { HRESULT hr;
API_ENTER(this);
if (pInitFunction == NULL) { DPF_ERR("Invalid initialization function specified. RegisterSoftwareDevice fails."); return D3DERR_INVALIDCALL; } if (m_pSwInitFunction != NULL) { DPF_ERR("A software device is already registered."); return D3DERR_INVALIDCALL; } if (m_cAdapter == 0) { DPF_ERR("No display devices are available."); return D3DERR_NOTAVAILABLE; }
hr = AddSoftwareDevice(D3DDEVTYPE_SW, &m_SwCaps[0], &m_AdapterInfo[0], pInitFunction); if (SUCCEEDED(hr)) { m_pSwInitFunction = pInitFunction; }
if (FAILED(hr)) { DPF_ERR("RegisterSoftwareDevice fails"); }
return hr;
} // RegisterSoftwareDevice
#ifdef WINNT
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::FocusWindow"
HWND CEnum::ExclusiveOwnerWindow() { API_ENTER_RET(this, HWND); for (UINT iAdapter = 0; iAdapter < m_cAdapter; iAdapter++) { CBaseDevice *pDevice = m_pFullScreenDevice[iAdapter]; if (pDevice) { return pDevice->FocusWindow(); } } return NULL; } // FocusWindow
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::SetFullScreenDevice"
void CEnum::SetFullScreenDevice(UINT iAdapter, CBaseDevice *pDevice) { API_ENTER_VOID(this);
if (m_pFullScreenDevice[iAdapter] != pDevice) { DDASSERT(NULL == m_pFullScreenDevice[iAdapter] || NULL == pDevice); m_pFullScreenDevice[iAdapter] = pDevice; if (NULL == pDevice && NULL == ExclusiveOwnerWindow() && m_bHasExclusive) { m_bHasExclusive = FALSE; DXReleaseExclusiveModeMutex(); } } } // SetFullScreenDevice
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::CheckExclusiveMode"
BOOL CEnum::CheckExclusiveMode( CBaseDevice* pDevice, LPBOOL pbThisDeviceOwnsExclusive, BOOL bKeepMutex) { DWORD dwWaitResult; BOOL bExclusiveExists=FALSE;
WaitForSingleObject(hCheckExclusiveModeMutex, INFINITE);
dwWaitResult = WaitForSingleObject(hExclusiveModeMutex, 0);
if (dwWaitResult == WAIT_OBJECT_0) { /*
* OK, so this process now owns the exclusive mode object, * Have we taken the Mutex already ? */ if (m_bHasExclusive) { bExclusiveExists = TRUE; bKeepMutex = FALSE; } else { bExclusiveExists = FALSE; } if (pbThisDeviceOwnsExclusive && pDevice) { if (bExclusiveExists && (pDevice == m_pFullScreenDevice[pDevice->AdapterIndex()] || NULL == m_pFullScreenDevice[pDevice->AdapterIndex()]) && pDevice->FocusWindow() == ExclusiveOwnerWindow() ) { *pbThisDeviceOwnsExclusive = TRUE; } else { *pbThisDeviceOwnsExclusive = FALSE; } } /*
* Undo the temporary ref we just took on the mutex to check its state, if we're not actually * taking ownership. We are not taking ownership if we already have ownership. This means this routine * doesn't allow more than one ref on the exclusive mode mutex. */ if (!bKeepMutex) { ReleaseMutex(hExclusiveModeMutex); } else { m_bHasExclusive = TRUE; } } else if (dwWaitResult == WAIT_TIMEOUT) { bExclusiveExists = TRUE; if (pbThisDeviceOwnsExclusive) *pbThisDeviceOwnsExclusive = FALSE; } else if (dwWaitResult == WAIT_ABANDONED) { /*
* Some other thread lost exclusive mode. We have now picked it up. */ bExclusiveExists = FALSE; if (pbThisDeviceOwnsExclusive) *pbThisDeviceOwnsExclusive = FALSE; /*
* Undo the temporary ref we just took on the mutex to check its state, if we're not actually * taking ownership. */ if (!bKeepMutex) { ReleaseMutex(hExclusiveModeMutex); } else { m_bHasExclusive = TRUE; } }
ReleaseMutex(hCheckExclusiveModeMutex);
return bExclusiveExists; } // CheckExclusiveMode
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::DoneExclusiveMode"
/*
* DoneExclusiveMode */ void CEnum::DoneExclusiveMode() { UINT iAdapter; for (iAdapter=0;iAdapter < m_cAdapter;iAdapter++) { CBaseDevice* pDevice = m_pFullScreenDevice[iAdapter]; if (pDevice) { pDevice->SwapChain()->DoneExclusiveMode(TRUE); } } m_bHasExclusive = FALSE;
DXReleaseExclusiveModeMutex();
} /* DoneExclusiveMode */
#undef DPF_MODNAME
#define DPF_MODNAME "CEnum::StartExclusiveMode"
/*
* StartExclusiveMode */ void CEnum::StartExclusiveMode() { UINT iAdapter; for (iAdapter=0;iAdapter<m_cAdapter;iAdapter++) { CBaseDevice* pDevice = m_pFullScreenDevice[iAdapter]; if (pDevice) { pDevice->SwapChain()->StartExclusiveMode(TRUE); } } } /* StartExclusiveMode */
#endif // WINNT
// End of file : enum.cpp
|