2969 lines
89 KiB
C++
2969 lines
89 KiB
C++
/*==========================================================================
|
|
*
|
|
* 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
|