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

2968 lines
89 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1995-1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: enum.cpp
  6. * Content Handles all of the enum functions for determing what device
  7. * you want before you go there.
  8. *
  9. *
  10. ***************************************************************************/
  11. #include "ddrawpr.h"
  12. #include <stdio.h>
  13. #include "d3dobj.hpp"
  14. #include "pixel.hpp"
  15. #include "enum.hpp"
  16. #include "d3di.hpp"
  17. #include "fcache.hpp"
  18. #include "swapchan.hpp"
  19. #define D3DPMISCCAPS_DX7VALID \
  20. (D3DPMISCCAPS_MASKZ | \
  21. D3DPMISCCAPS_LINEPATTERNREP | \
  22. D3DPMISCCAPS_CULLNONE | \
  23. D3DPMISCCAPS_CULLCW | \
  24. D3DPMISCCAPS_CULLCCW)
  25. // Maps D3DMULTISAMPLE_TYPE into the bit to use for the flags.
  26. // Maps each of the multisampling values (2 to 16) to the bits[1] to bits[15]
  27. // of wBltMSTypes and wFlipMSTypes
  28. #define DDI_MULTISAMPLE_TYPE(x) (1 << ((x)-1))
  29. #ifdef WINNT
  30. extern "C" BOOL IsWhistler();
  31. #endif
  32. void DXReleaseExclusiveModeMutex(void)
  33. {
  34. if (hExclusiveModeMutex)
  35. {
  36. BOOL bSucceed = ReleaseMutex(hExclusiveModeMutex);
  37. if (!bSucceed)
  38. {
  39. DWORD dwErr = GetLastError();
  40. DPF_ERR("Release Exclusive Mode Mutex Failed.");
  41. DPF_ERR("Application attempts to leave exclusive mode on different thread than the device was created on. Dangerous!!");
  42. DPF(0, "Mutex 0x%p could not be released. Extended Error = %d",
  43. hExclusiveModeMutex, dwErr);
  44. DXGASSERT(FALSE);
  45. }
  46. }
  47. } // DXReleaseExclusiveModeMutex
  48. // DLL exposed Creation function
  49. IDirect3D8 * WINAPI Direct3DCreate8(UINT SDKVersion)
  50. {
  51. // Turn off D3D8 interfaces on WOW64.
  52. #ifndef _IA64_
  53. #if _WIN32_WINNT >= 0x0501
  54. typedef BOOL (WINAPI *PFN_ISWOW64PROC)( HANDLE hProcess,
  55. PBOOL Wow64Process );
  56. HINSTANCE hInst = NULL;
  57. hInst = LoadLibrary( "kernel32.dll" );
  58. if( hInst )
  59. {
  60. PFN_ISWOW64PROC pfnIsWow64 = NULL;
  61. pfnIsWow64 = (PFN_ISWOW64PROC)GetProcAddress( (HMODULE)hInst, "IsWow64Process" );
  62. // We assume that if this function is not available, then it is some OS where
  63. // WOW64 does not exist (this means that pre-Release versions of XP are busted)
  64. if( pfnIsWow64 )
  65. {
  66. BOOL wow64Process;
  67. if (pfnIsWow64(GetCurrentProcess(), &wow64Process) && wow64Process)
  68. {
  69. DPF_ERR("DX8 D3D interfaces are not supported on WOW64");
  70. return NULL;
  71. }
  72. }
  73. FreeLibrary( hInst );
  74. }
  75. else
  76. {
  77. DPF_ERR("LoadLibrary failed. Quitting.");
  78. return NULL;
  79. }
  80. #endif // _WIN32_WINNT >= 0x0501
  81. #endif // _IA64_
  82. #ifndef DEBUG
  83. // Check for debug-please registry key. If debug is required, then
  84. // we delegate this call to the debug version, if it exists,,
  85. HKEY hKey;
  86. if (!RegOpenKey(HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey))
  87. {
  88. DWORD type;
  89. DWORD value;
  90. DWORD cb = sizeof(value);
  91. if (!RegQueryValueEx(hKey, "LoadDebugRuntime", NULL, &type, (CONST LPBYTE)&value, &cb))
  92. {
  93. if (value)
  94. {
  95. HINSTANCE hDebugDLL = LoadLibrary("d3d8d.dll");
  96. if (hDebugDLL)
  97. {
  98. typedef IDirect3D8* (WINAPI * PDIRECT3DCREATE8)(UINT);
  99. PDIRECT3DCREATE8 pDirect3DCreate8 =
  100. (PDIRECT3DCREATE8) GetProcAddress(hDebugDLL, "Direct3DCreate8");
  101. if (pDirect3DCreate8)
  102. {
  103. return pDirect3DCreate8(SDKVersion);
  104. }
  105. }
  106. }
  107. }
  108. RegCloseKey(hKey);
  109. }
  110. #else
  111. //If we are debug, then spew a string at level 2
  112. DPF(2,"Direct3D8 Debug Runtime selected.");
  113. #endif
  114. #ifndef DX_FINAL_RELEASE
  115. // Time-bomb check.
  116. {
  117. #pragma message("BETA EXPIRATION TIME BOMB! Remove for final build!")
  118. SYSTEMTIME st;
  119. GetSystemTime(&st);
  120. if (st.wYear > DX_EXPIRE_YEAR ||
  121. ((st.wYear == DX_EXPIRE_YEAR) && (MAKELONG(st.wDay, st.wMonth) > MAKELONG(DX_EXPIRE_DAY, DX_EXPIRE_MONTH)))
  122. )
  123. {
  124. MessageBox(0, DX_EXPIRE_TEXT,
  125. TEXT("Microsoft Direct3D"), MB_OK | MB_TASKMODAL);
  126. }
  127. }
  128. #endif //DX_FINAL_RELEASE
  129. #ifdef DEBUG
  130. HKEY hKey;
  131. if (!RegOpenKey(HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey))
  132. {
  133. DWORD type;
  134. DWORD value;
  135. DWORD cb = sizeof(value);
  136. if (!RegQueryValueEx(hKey, "SDKVersion", NULL, &type, (CONST LPBYTE)&value, &cb))
  137. {
  138. if (value)
  139. {
  140. SDKVersion = value;
  141. }
  142. }
  143. RegCloseKey(hKey);
  144. }
  145. #endif
  146. if ((SDKVersion != D3D_SDK_VERSION_DX8) &&
  147. ((SDKVersion < (D3D_SDK_VERSION)) || (SDKVersion >= (D3D_SDK_VERSION+100))) )
  148. {
  149. char pbuf[256];
  150. _snprintf(pbuf, 256,
  151. "\n"
  152. "D3D ERROR: This application compiled against improper D3D headers.\n"
  153. "The application is compiled with SDK version (%d) but the currently installed\n"
  154. "runtime supports versions from (%d).\n"
  155. "Please recompile with an up-to-date SDK.\n\n",
  156. SDKVersion, D3D_SDK_VERSION);
  157. OutputDebugString(pbuf);
  158. return NULL;
  159. }
  160. IDirect3D8 *pEnum = new CEnum(SDKVersion);
  161. if (pEnum == NULL)
  162. {
  163. DPF_ERR("Creating D3D enumeration object failed; out of memory. Direct3DCreate fails and returns NULL.");
  164. }
  165. return pEnum;
  166. } // Direct3DCreate
  167. //---------------------------------------------------------------------------
  168. // CEnum methods
  169. //---------------------------------------------------------------------------
  170. #undef DPF_MODNAME
  171. #define DPF_MODNAME "CEnum::AddRef"
  172. STDMETHODIMP_(ULONG) CEnum::AddRef(void)
  173. {
  174. API_ENTER_NO_LOCK(this);
  175. // InterlockedIncrement requires the memory
  176. // to be aligned on DWORD boundary
  177. DXGASSERT(((ULONG_PTR)(&m_cRef) & 3) == 0);
  178. InterlockedIncrement((LONG *)&m_cRef);
  179. return m_cRef;
  180. } // AddRef
  181. #undef DPF_MODNAME
  182. #define DPF_MODNAME "CEnum::Release"
  183. STDMETHODIMP_(ULONG) CEnum::Release(void)
  184. {
  185. API_ENTER_NO_LOCK(this);
  186. // InterlockedDecrement requires the memory
  187. // to be aligned on DWORD boundary
  188. DXGASSERT(((ULONG_PTR)(&m_cRef) & 3) == 0);
  189. InterlockedDecrement((LONG *)&m_cRef);
  190. if (m_cRef != 0)
  191. return m_cRef;
  192. for (UINT i = 0; i < m_cAdapter; i++)
  193. {
  194. if (m_REFCaps[i].pGDD8SupportedFormatOps)
  195. MemFree(m_REFCaps[i].pGDD8SupportedFormatOps);
  196. if (m_SwCaps[i].pGDD8SupportedFormatOps)
  197. MemFree(m_SwCaps[i].pGDD8SupportedFormatOps);
  198. if (m_AdapterInfo[i].HALCaps.pGDD8SupportedFormatOps)
  199. MemFree(m_AdapterInfo[i].HALCaps.pGDD8SupportedFormatOps);
  200. if (m_AdapterInfo[i].pModeTable)
  201. MemFree(m_AdapterInfo[i].pModeTable);
  202. }
  203. if (m_hGammaCalibrator)
  204. {
  205. FreeLibrary((HMODULE) m_hGammaCalibrator);
  206. }
  207. delete this;
  208. return 0;
  209. } // Release
  210. #undef DPF_MODNAME
  211. #define DPF_MODNAME "CEnum::QueryInterface"
  212. STDMETHODIMP CEnum::QueryInterface(REFIID riid, LPVOID FAR *ppv)
  213. {
  214. API_ENTER(this);
  215. if (!VALID_PTR_PTR(ppv))
  216. {
  217. DPF_ERR("Invalid pointer passed to QueryInterface for IDirect3D8 interface");
  218. return D3DERR_INVALIDCALL;
  219. }
  220. if (!VALID_PTR(&riid, sizeof(GUID)))
  221. {
  222. DPF_ERR("Invalid guid memory address to QueryInterface for IDirect3D8 interface");
  223. return D3DERR_INVALIDCALL;
  224. }
  225. if (riid == IID_IUnknown || riid == IID_IDirect3D8)
  226. {
  227. *ppv = static_cast<void*>(static_cast<IDirect3D8*>(this));
  228. AddRef();
  229. }
  230. else
  231. {
  232. DPF_ERR("Unsupported Interface identifier passed to QueryInterface for IDirect3D8 interface");
  233. *ppv = NULL;
  234. return E_NOINTERFACE;
  235. }
  236. return S_OK;
  237. } // QueryInterface
  238. // DisplayGUID - GUID used to enumerate secondary displays.
  239. //
  240. // {67685559-3106-11d0-B971-00AA00342F9F}
  241. //
  242. // we use this GUID and the next 32 for enumerating devices
  243. // returned via EnumDisplayDevices
  244. //
  245. GUID DisplayGUID =
  246. {0x67685559,0x3106,0x11d0,{0xb9,0x71,0x0,0xaa,0x0,0x34,0x2f,0x9f}};
  247. #undef DPF_MODNAME
  248. #define DPF_MODNAME "::strToGUID"
  249. /*
  250. * strToGUID
  251. *
  252. * converts a string in the form xxxxxxxx-xxxx-xxxx-xx-xx-xx-xx-xx-xx-xx-xx
  253. * into a guid
  254. */
  255. static BOOL strToGUID(LPSTR str, GUID * pguid)
  256. {
  257. int idx;
  258. LPSTR ptr;
  259. LPSTR next;
  260. DWORD data;
  261. DWORD mul;
  262. BYTE ch;
  263. BOOL done;
  264. idx = 0;
  265. done = FALSE;
  266. while (!done)
  267. {
  268. /*
  269. * find the end of the current run of digits
  270. */
  271. ptr = str;
  272. while ((*str) != '-' && (*str) != 0)
  273. {
  274. str++;
  275. }
  276. if (*str == 0)
  277. {
  278. done = TRUE;
  279. }
  280. else
  281. {
  282. next = str+1;
  283. }
  284. /*
  285. * scan backwards from the end of the string to the beginning,
  286. * converting characters from hex chars to numbers as we go
  287. */
  288. str--;
  289. mul = 1;
  290. data = 0;
  291. while (str >= ptr)
  292. {
  293. ch = *str;
  294. if (ch >= 'A' && ch <= 'F')
  295. {
  296. data += mul * (DWORD) (ch-'A'+10);
  297. }
  298. else if (ch >= 'a' && ch <= 'f')
  299. {
  300. data += mul * (DWORD) (ch-'a'+10);
  301. }
  302. else if (ch >= '0' && ch <= '9')
  303. {
  304. data += mul * (DWORD) (ch-'0');
  305. }
  306. else
  307. {
  308. return FALSE;
  309. }
  310. mul *= 16;
  311. str--;
  312. }
  313. /*
  314. * stuff the current number into the guid
  315. */
  316. switch(idx)
  317. {
  318. case 0:
  319. pguid->Data1 = data;
  320. break;
  321. case 1:
  322. pguid->Data2 = (WORD) data;
  323. break;
  324. case 2:
  325. pguid->Data3 = (WORD) data;
  326. break;
  327. default:
  328. pguid->Data4[ idx-3 ] = (BYTE) data;
  329. break;
  330. }
  331. /*
  332. * did we find all 11 numbers?
  333. */
  334. idx++;
  335. if (idx == 11)
  336. {
  337. if (done)
  338. {
  339. return TRUE;
  340. }
  341. else
  342. {
  343. return FALSE;
  344. }
  345. }
  346. str = next;
  347. }
  348. return FALSE;
  349. } /* strToGUID */
  350. // REF, HAL
  351. typedef struct _DEVICEREGISTRYDATA
  352. {
  353. UINT Size;
  354. UINT Cookie;
  355. FILETIME FileDate;
  356. GUID DriverGuid;
  357. D3D8_DRIVERCAPS DeviceCaps;
  358. UINT OffsetFormatOps;
  359. D3DFORMAT Unknown16;
  360. DWORD HALFlags;
  361. } DEVICEREGISTRYDATA;
  362. inline UINT EXPECTED_CACHE_SIZE(UINT nFormatOps)
  363. {
  364. return sizeof(DEVICEREGISTRYDATA) + sizeof(DDSURFACEDESC) * nFormatOps;
  365. }
  366. #define DDRAW_REGCAPS_KEY "Software\\Microsoft\\DirectDraw\\MostRecentDrivers"
  367. #define VERSION_COOKIE 0x0083
  368. #undef DPF_MODNAME
  369. #define DPF_MODNAME "ReadCapsFromCache"
  370. BOOL GetFileDate (char* Driver, FILETIME* pFileDate)
  371. {
  372. WIN32_FILE_ATTRIBUTE_DATA FA;
  373. char Name[MAX_PATH];
  374. HMODULE h = GetModuleHandle("KERNEL32");
  375. BOOL (WINAPI *pfnGetFileAttributesEx)(LPCSTR, GET_FILEEX_INFO_LEVELS, LPVOID);
  376. pFileDate->dwLowDateTime = 0;
  377. pFileDate->dwHighDateTime = 0;
  378. *((void **)&pfnGetFileAttributesEx) = GetProcAddress(h,"GetFileAttributesExA");
  379. if (pfnGetFileAttributesEx != NULL)
  380. {
  381. GetSystemDirectory(Name, sizeof(Name) - (strlen(Driver) + 3));
  382. lstrcat(Name,"\\");
  383. lstrcat(Name, Driver);
  384. if ((*pfnGetFileAttributesEx)(Name, GetFileExInfoStandard, &FA) != 0)
  385. {
  386. *pFileDate = FA.ftCreationTime;
  387. return TRUE;
  388. }
  389. }
  390. return FALSE;
  391. }
  392. //If pCaps is NULL, then those data will not be returned.
  393. BOOL ReadCapsFromCache(UINT iAdapter,
  394. D3D8_DRIVERCAPS *pCaps,
  395. UINT* pHALFlags,
  396. D3DFORMAT* pUnknown16,
  397. char* pDeviceName,
  398. BOOL bDisplayDriver)
  399. {
  400. D3DADAPTER_IDENTIFIER8 DI;
  401. DEVICEREGISTRYDATA* pData = NULL;
  402. UINT Size;
  403. FILETIME FileDate;
  404. // Read the data from the registry
  405. // Don't need WHQL level or driver name
  406. GetAdapterInfo(pDeviceName, &DI, bDisplayDriver, TRUE, FALSE);
  407. ReadFromCache(&DI, &Size, (BYTE**)&pData);
  408. if (pData == NULL)
  409. {
  410. return FALSE;
  411. }
  412. // We have the data, now do a sanity check to make sure that it
  413. // it makes sense
  414. if (pData->Size != Size)
  415. {
  416. MemFree(pData);
  417. return FALSE;
  418. }
  419. if (Size != EXPECTED_CACHE_SIZE(pData->DeviceCaps.GDD8NumSupportedFormatOps))
  420. {
  421. MemFree(pData);
  422. return FALSE;
  423. }
  424. if (pData->DriverGuid != DI.DeviceIdentifier)
  425. {
  426. MemFree(pData);
  427. return FALSE;
  428. }
  429. if (pData->Cookie != VERSION_COOKIE)
  430. {
  431. MemFree(pData);
  432. return FALSE;
  433. }
  434. // Check the driver date to see if it changed
  435. if (GetFileDate(DI.Driver, &FileDate))
  436. {
  437. if ((FileDate.dwLowDateTime != pData->FileDate.dwLowDateTime) ||
  438. (FileDate.dwHighDateTime != pData->FileDate.dwHighDateTime))
  439. {
  440. MemFree(pData);
  441. return FALSE;
  442. }
  443. }
  444. *pUnknown16 = pData->Unknown16;
  445. *pHALFlags = pData->HALFlags;
  446. //Sometime we may not be asked to get the whole caps
  447. if (!pCaps)
  448. {
  449. MemFree(pData);
  450. return TRUE;
  451. }
  452. // Now that we have the data, we need to load it into a form that we
  453. // can use.
  454. memcpy(pCaps, &pData->DeviceCaps, sizeof(*pCaps));
  455. //reuse size to calculate size of support format ops
  456. Size = pData->DeviceCaps.GDD8NumSupportedFormatOps
  457. * sizeof(*(pData->DeviceCaps.pGDD8SupportedFormatOps));
  458. pCaps->pGDD8SupportedFormatOps = (DDSURFACEDESC*) MemAlloc(Size);
  459. if (pCaps->pGDD8SupportedFormatOps != NULL)
  460. {
  461. memcpy(pCaps->pGDD8SupportedFormatOps,
  462. ((BYTE*)pData) + pData->OffsetFormatOps,
  463. Size);
  464. }
  465. else
  466. {
  467. pCaps->GDD8NumSupportedFormatOps = 0;
  468. }
  469. MemFree(pData);
  470. return TRUE;
  471. }
  472. #undef DPF_MODNAME
  473. #define DPF_MODNAME "WriteCapsToCache"
  474. void WriteCapsToCache(UINT iAdapter,
  475. D3D8_DRIVERCAPS *pCaps,
  476. UINT HALFlags,
  477. D3DFORMAT Unknown16,
  478. char* pDeviceName,
  479. BOOL bDisplayDriver)
  480. {
  481. DEVICEREGISTRYDATA* pData;
  482. D3DADAPTER_IDENTIFIER8 DI;
  483. UINT Size;
  484. UINT Offset;
  485. FILETIME FileDate;
  486. // Allocate the buffer and fill in all of the memory
  487. Size = EXPECTED_CACHE_SIZE(pCaps->GDD8NumSupportedFormatOps);
  488. pData = (DEVICEREGISTRYDATA*) MemAlloc(Size);
  489. if (pData == NULL)
  490. {
  491. return;
  492. }
  493. // Don't need WHQL level or driver name
  494. GetAdapterInfo(pDeviceName, &DI, bDisplayDriver, TRUE, FALSE);
  495. pData->DriverGuid = DI.DeviceIdentifier;
  496. pData->Size = Size;
  497. pData->Cookie = VERSION_COOKIE;
  498. memcpy(&pData->DeviceCaps, pCaps, sizeof(*pCaps));
  499. pData->Unknown16 = Unknown16;
  500. pData->HALFlags = HALFlags;
  501. if (GetFileDate(DI.Driver, &FileDate))
  502. {
  503. pData->FileDate = FileDate;
  504. }
  505. Offset = sizeof(DEVICEREGISTRYDATA);
  506. pData->OffsetFormatOps = Offset;
  507. memcpy(((BYTE*)pData) + Offset,
  508. pCaps->pGDD8SupportedFormatOps,
  509. pCaps->GDD8NumSupportedFormatOps *
  510. sizeof(*(pCaps->pGDD8SupportedFormatOps)));
  511. // Now save it
  512. WriteToCache(&DI, Size, (BYTE*) pData);
  513. MemFree(pData);
  514. }
  515. HRESULT CopyDriverCaps(D3D8_DRIVERCAPS* pDriverCaps, D3D8_DEVICEDATA* pDeviceData, BOOL bForce)
  516. {
  517. HRESULT hr = D3DERR_INVALIDCALL;
  518. // Do they report any D3D caps in this mode?
  519. DWORD Size;
  520. // If it's not at least a DX6 driver, we don't want to fill
  521. // in any caps at all. Also, if it can't texture, then
  522. // we don't to support it either.
  523. BOOL bCanTexture = TRUE;
  524. BOOL bCanHandleFVF = TRUE;
  525. BOOL bHasGoodCaps = TRUE;
  526. if (!bForce)
  527. {
  528. if (pDeviceData->DriverData.D3DCaps.TextureCaps)
  529. {
  530. bCanTexture = TRUE;
  531. }
  532. else
  533. {
  534. DPF(0, "HAL Disabled: Device doesn't support texturing");
  535. bCanTexture = FALSE;
  536. }
  537. // Some DX6 drivers are not FVF aware; and we need to
  538. // disable HAL for them.
  539. if (pDeviceData->DriverData.D3DCaps.FVFCaps != 0)
  540. {
  541. bCanHandleFVF = TRUE;
  542. }
  543. else
  544. {
  545. DPF(0, "HAL Disabled: Device doesn't support FVF");
  546. bCanHandleFVF = FALSE;
  547. }
  548. if (pDeviceData->Callbacks.DrawPrimitives2 == NULL)
  549. {
  550. DPF(0, "HAL Disabled: Device doesn't support DX6 or higher");
  551. }
  552. // We dont want drivers that report bogus caps:
  553. // pre-DX8 drivers that can do DX8 features.
  554. if (pDeviceData->DriverData.D3DCaps.MaxStreams == 0)
  555. {
  556. D3DCAPS8& Caps = pDeviceData->DriverData.D3DCaps;
  557. // Should have none of the following:
  558. // 1) PointSprites.
  559. // 2) VertexShaders.
  560. // 3) PixelShaders.
  561. // 4) Volume textures.
  562. // 5) Indexed Vertex Blending.
  563. // 6) Higher order primitives.
  564. // 7) PureDevice
  565. // 8) Perspective Color.
  566. // 9) Color Write.
  567. // 10) Newer texture caps.
  568. if ((Caps.MaxPointSize != 0) ||
  569. (Caps.VertexShaderVersion != D3DVS_VERSION(0,0)) ||
  570. (Caps.PixelShaderVersion != D3DPS_VERSION(0,0)) ||
  571. (Caps.MaxVolumeExtent != 0) ||
  572. (Caps.MaxVertexBlendMatrixIndex != 0) ||
  573. (Caps.MaxVertexIndex != 0xffff) ||
  574. ((Caps.DevCaps & ~(D3DDEVCAPS_DX7VALID | D3DDEVCAPS_HWVERTEXBUFFER)) != 0) ||
  575. ((Caps.RasterCaps & ~(D3DPRASTERCAPS_DX7VALID)) != 0) ||
  576. ((Caps.PrimitiveMiscCaps & ~(D3DPMISCCAPS_DX7VALID)) != 0) ||
  577. ((Caps.TextureCaps & ~(D3DPTEXTURECAPS_DX7VALID)) != 0)
  578. )
  579. {
  580. DPF(0, "HAL Disabled: DX7 Device should not support DX8 features");
  581. bHasGoodCaps = FALSE;
  582. }
  583. }
  584. else
  585. // We dont want drivers that report bogus caps:
  586. // DX8 drivers should do DX8 features.
  587. {
  588. D3DCAPS8& Caps = pDeviceData->DriverData.D3DCaps;
  589. }
  590. }
  591. // We require drivers to support DP2 (i.e. DX6+),
  592. // texturing and proper FVF support in order to use a HAL
  593. if ((pDeviceData->Callbacks.DrawPrimitives2 != NULL &&
  594. bCanTexture &&
  595. bCanHandleFVF &&
  596. bHasGoodCaps) ||
  597. bForce)
  598. {
  599. MemFree(pDriverCaps->pGDD8SupportedFormatOps);
  600. memcpy(pDriverCaps,
  601. &pDeviceData->DriverData, sizeof(pDeviceData->DriverData));
  602. Size = sizeof(DDSURFACEDESC) *
  603. pDriverCaps->GDD8NumSupportedFormatOps;
  604. pDriverCaps->pGDD8SupportedFormatOps =
  605. (DDSURFACEDESC*) MemAlloc(Size);
  606. if (pDriverCaps->pGDD8SupportedFormatOps != NULL)
  607. {
  608. memcpy(pDriverCaps->pGDD8SupportedFormatOps,
  609. pDeviceData->DriverData.pGDD8SupportedFormatOps,
  610. Size);
  611. }
  612. else
  613. {
  614. pDriverCaps->GDD8NumSupportedFormatOps = 0;
  615. }
  616. hr = D3D_OK;
  617. }
  618. return hr;
  619. }
  620. #undef DPF_MODNAME
  621. #define DPF_MODNAME "AddSoftwareDevice"
  622. HRESULT AddSoftwareDevice(D3DDEVTYPE DeviceType,
  623. D3D8_DRIVERCAPS* pSoftCaps,
  624. ADAPTERINFO* pAdapterInfo,
  625. VOID* pInitFunction)
  626. {
  627. HRESULT hr;
  628. PD3D8_DEVICEDATA pDeviceData;
  629. hr = InternalDirectDrawCreate(&pDeviceData,
  630. pAdapterInfo,
  631. DeviceType,
  632. pInitFunction,
  633. pAdapterInfo->Unknown16,
  634. pAdapterInfo->HALCaps.pGDD8SupportedFormatOps,
  635. pAdapterInfo->HALCaps.GDD8NumSupportedFormatOps);
  636. if (SUCCEEDED(hr))
  637. {
  638. hr = CopyDriverCaps(pSoftCaps, pDeviceData, FALSE);
  639. InternalDirectDrawRelease(pDeviceData);
  640. }
  641. return hr;
  642. }
  643. #undef DPF_MODNAME
  644. #define DPF_MODNAME "CreateCoverWindow"
  645. HWND CreateCoverWindow()
  646. {
  647. #define COVERWINDOWNAME "DxCoverWindow"
  648. WNDCLASS windowClass =
  649. {
  650. 0,
  651. DefWindowProc,
  652. 0,
  653. 0,
  654. g_hModule,
  655. LoadIcon(NULL, IDI_APPLICATION),
  656. LoadCursor(NULL, IDC_ARROW),
  657. (HBRUSH)(BLACK_BRUSH),
  658. NULL,
  659. COVERWINDOWNAME
  660. };
  661. RegisterClass(&windowClass);
  662. HWND hWindow = CreateWindowEx(
  663. WS_EX_TOPMOST,
  664. COVERWINDOWNAME,
  665. COVERWINDOWNAME,
  666. WS_POPUP,
  667. 0,
  668. 0,
  669. 100,
  670. 100,
  671. NULL,
  672. NULL,
  673. g_hModule,
  674. NULL);
  675. return hWindow;
  676. }
  677. HRESULT GetHALCapsInCurrentMode (PD3D8_DEVICEDATA pHalData, PADAPTERINFO pAdapterInfo, BOOL bForce, BOOL bFetchNewCaps)
  678. {
  679. HRESULT hr;
  680. DWORD i;
  681. // Free the old stuff if we no longer care
  682. if (bFetchNewCaps)
  683. {
  684. MemFree(pHalData->DriverData.pGDD8SupportedFormatOps);
  685. pHalData->DriverData.pGDD8SupportedFormatOps = NULL;
  686. pHalData->DriverData.GDD8NumSupportedFormatOps = 0;
  687. MemFree(pAdapterInfo->HALCaps.pGDD8SupportedFormatOps);
  688. pAdapterInfo->HALCaps.pGDD8SupportedFormatOps = NULL;
  689. pAdapterInfo->HALCaps.GDD8NumSupportedFormatOps = 0;
  690. // Set this to ensure that we actually get the caps
  691. pHalData->DriverData.D3DCaps.DevCaps = 0;
  692. pHalData->DriverData.dwFlags &= ~DDIFLAG_D3DCAPS8;
  693. FetchDirectDrawData(pHalData,
  694. NULL,
  695. pAdapterInfo->Unknown16,
  696. NULL,
  697. 0);
  698. }
  699. // Do they report any D3D caps in this mode?
  700. hr = CopyDriverCaps(&pAdapterInfo->HALCaps, pHalData, bForce);
  701. return hr;
  702. }
  703. #undef DPF_MODNAME
  704. #define DPF_MODNAME "ProfileAdapter"
  705. void ProfileAdapter(
  706. PADAPTERINFO pAdapterInfo,
  707. PD3D8_DEVICEDATA pHalData)
  708. {
  709. UINT i;
  710. IDirect3DDevice8* pDevice;
  711. D3DDISPLAYMODE OrigMode;
  712. UINT OrigBpp;
  713. HRESULT hr;
  714. // We will be changing display modes, so first we want to save the current
  715. // mode so we can return to it later.
  716. D3D8GetMode (pHalData->hDD, pAdapterInfo->DeviceName, &OrigMode, D3DFMT_UNKNOWN);
  717. MemFree(pAdapterInfo->HALCaps.pGDD8SupportedFormatOps);
  718. memset(&pAdapterInfo->HALCaps, 0, sizeof(D3D8_DRIVERCAPS));
  719. OrigBpp = CPixel::ComputePixelStride(OrigMode.Format)*8;
  720. //First gather what we need from 16bpp: Unknown16 format
  721. if (16 != OrigBpp)
  722. {
  723. D3D8SetMode (pHalData->hDD,
  724. pAdapterInfo->DeviceName,
  725. 640,
  726. 480,
  727. 16,
  728. 0,
  729. FALSE);
  730. }
  731. D3DDISPLAYMODE Mode;
  732. D3D8GetMode (pHalData->hDD, pAdapterInfo->DeviceName, &Mode, D3DFMT_UNKNOWN);
  733. pAdapterInfo->Unknown16 = Mode.Format;
  734. // We need to change to 32bpp, because the above code guarenteed we are now in 16bpp
  735. hr = D3D8SetMode (pHalData->hDD,
  736. pAdapterInfo->DeviceName,
  737. 640,
  738. 480,
  739. 32,
  740. 0,
  741. FALSE);
  742. if (SUCCEEDED(hr))
  743. {
  744. hr = GetHALCapsInCurrentMode(pHalData, pAdapterInfo, FALSE, TRUE);
  745. }
  746. if (FAILED(hr))
  747. {
  748. // If they don't report caps in 32bpp mode (ala Voodoo 3), then go
  749. // back to 16bpp mode and get the caps. If the device supports
  750. // caps in any mode, we want to exit this function with the caps.
  751. D3D8SetMode (pHalData->hDD,
  752. pAdapterInfo->DeviceName,
  753. 640,
  754. 480,
  755. 16,
  756. 0,
  757. FALSE);
  758. hr = GetHALCapsInCurrentMode(pHalData, pAdapterInfo, FALSE, TRUE);
  759. // If they don't report good D3D caps in any mode at all, we still need
  760. // to return some caps, if only so we can support a SW driver.
  761. if (FAILED(hr))
  762. {
  763. GetHALCapsInCurrentMode(pHalData, pAdapterInfo, TRUE, TRUE);
  764. for (i = 0; i < pAdapterInfo->HALCaps.GDD8NumSupportedFormatOps; i++)
  765. {
  766. pAdapterInfo->HALCaps.pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwOperations &= D3DFORMAT_OP_DISPLAYMODE;
  767. }
  768. }
  769. }
  770. //And now set back to original mode...
  771. D3D8SetMode (pHalData->hDD,
  772. pAdapterInfo->DeviceName,
  773. OrigMode.Width,
  774. OrigMode.Height,
  775. OrigBpp,
  776. 0,
  777. TRUE);
  778. }
  779. #undef DPF_MODNAME
  780. #define DPF_MODNAME "GetRefCaps"
  781. void CEnum::GetRefCaps(UINT iAdapter)
  782. {
  783. // If we've already got the caps once, there's ne need to get
  784. // them again
  785. if (m_REFCaps[iAdapter].GDD8NumSupportedFormatOps == 0)
  786. {
  787. AddSoftwareDevice(D3DDEVTYPE_REF,
  788. &m_REFCaps[iAdapter],
  789. &m_AdapterInfo[iAdapter],
  790. NULL);
  791. }
  792. }
  793. void CEnum::GetSwCaps(UINT iAdapter)
  794. {
  795. // If we've already got the caps once, there's ne need to get
  796. // them again
  797. if (m_SwCaps[iAdapter].GDD8NumSupportedFormatOps == 0)
  798. {
  799. AddSoftwareDevice(D3DDEVTYPE_SW,
  800. &m_SwCaps[iAdapter],
  801. &m_AdapterInfo[iAdapter],
  802. m_pSwInitFunction);
  803. }
  804. }
  805. // IsSupportedOp
  806. // Runs the pixel format operation list looking to see if the
  807. // selected format can support at least the requested operations.
  808. #undef DPF_MODNAME
  809. #define DPF_MODNAME "IsSupportedOp"
  810. BOOL IsSupportedOp (D3DFORMAT Format,
  811. DDSURFACEDESC* pList,
  812. UINT NumElements,
  813. DWORD dwRequestedOps)
  814. {
  815. UINT i;
  816. for (i = 0; i < NumElements; i++)
  817. {
  818. DDASSERT(pList[i].ddpfPixelFormat.dwFlags == DDPF_D3DFORMAT);
  819. if (pList[i].ddpfPixelFormat.dwFourCC == (DWORD) Format &&
  820. (pList[i].ddpfPixelFormat.dwOperations & dwRequestedOps) == dwRequestedOps)
  821. {
  822. return TRUE;
  823. }
  824. }
  825. return FALSE;
  826. }
  827. #undef DPF_MODNAME
  828. #define DPF_MODNAME "IsInList"
  829. BOOL IsInList (D3DFORMAT Format,
  830. D3DFORMAT* pList,
  831. UINT NumElements)
  832. {
  833. UINT i;
  834. for (i = 0; i < NumElements; i++)
  835. {
  836. if (pList[i] == Format)
  837. {
  838. return TRUE;
  839. }
  840. }
  841. return FALSE;
  842. }
  843. #undef DPF_MODNAME
  844. #define DPF_MODNAME "CEnum::MapDepthStencilFormat"
  845. D3DFORMAT CEnum::MapDepthStencilFormat(UINT iAdapter,
  846. D3DDEVTYPE Type,
  847. D3DFORMAT Format) const
  848. {
  849. DXGASSERT(CPixel::IsMappedDepthFormat(D3DFMT_D24X8));
  850. DXGASSERT(CPixel::IsMappedDepthFormat(D3DFMT_D15S1));
  851. DXGASSERT(CPixel::IsMappedDepthFormat(D3DFMT_D24S8));
  852. DXGASSERT(CPixel::IsMappedDepthFormat(D3DFMT_D16));
  853. DXGASSERT(CPixel::IsMappedDepthFormat(D3DFMT_D24X4S4));
  854. if (CPixel::IsMappedDepthFormat(Format))
  855. {
  856. DDSURFACEDESC *pTextureList;
  857. UINT NumTextures;
  858. switch (Type)
  859. {
  860. case D3DDEVTYPE_SW:
  861. pTextureList = m_SwCaps[iAdapter].pGDD8SupportedFormatOps;
  862. NumTextures = m_SwCaps[iAdapter].GDD8NumSupportedFormatOps;
  863. break;
  864. case D3DDEVTYPE_HAL:
  865. NumTextures = m_AdapterInfo[iAdapter].HALCaps.GDD8NumSupportedFormatOps;
  866. pTextureList = m_AdapterInfo[iAdapter].HALCaps.pGDD8SupportedFormatOps;
  867. break;
  868. case D3DDEVTYPE_REF:
  869. NumTextures = m_REFCaps[iAdapter].GDD8NumSupportedFormatOps;
  870. pTextureList = m_REFCaps[iAdapter].pGDD8SupportedFormatOps;
  871. break;
  872. }
  873. // No operations are required; we just want to know
  874. // if this format is listed in the table for any purpose
  875. // at all
  876. DWORD dwRequiredOperations = 0;
  877. switch (Format)
  878. {
  879. case D3DFMT_D24X4S4:
  880. if (IsSupportedOp(D3DFMT_X4S4D24, pTextureList, NumTextures, dwRequiredOperations))
  881. {
  882. return D3DFMT_X4S4D24;
  883. }
  884. break;
  885. case D3DFMT_D24X8:
  886. if (IsSupportedOp(D3DFMT_X8D24, pTextureList, NumTextures, dwRequiredOperations))
  887. {
  888. return D3DFMT_X8D24;
  889. }
  890. break;
  891. case D3DFMT_D24S8:
  892. if (IsSupportedOp(D3DFMT_S8D24, pTextureList, NumTextures, dwRequiredOperations))
  893. {
  894. return D3DFMT_S8D24;
  895. }
  896. break;
  897. case D3DFMT_D16:
  898. if (IsSupportedOp(D3DFMT_D16, pTextureList, NumTextures, dwRequiredOperations))
  899. {
  900. return D3DFMT_D16;
  901. }
  902. return D3DFMT_D16_LOCKABLE;
  903. case D3DFMT_D15S1:
  904. if (IsSupportedOp(D3DFMT_S1D15, pTextureList, NumTextures, dwRequiredOperations))
  905. {
  906. return D3DFMT_S1D15;
  907. }
  908. break;
  909. default:
  910. // Unexpected format?
  911. DXGASSERT(FALSE);
  912. break;
  913. }
  914. }
  915. return Format;
  916. }
  917. #undef DPF_MODNAME
  918. #define DPF_MODNAME "CEnum::GetAdapterCaps"
  919. HRESULT CEnum::GetAdapterCaps(UINT iAdapter,
  920. D3DDEVTYPE Type,
  921. D3D8_DRIVERCAPS** ppCaps)
  922. {
  923. *ppCaps = NULL;
  924. if (Type == D3DDEVTYPE_REF)
  925. {
  926. GetRefCaps (iAdapter);
  927. *ppCaps = &m_REFCaps[iAdapter];
  928. if (m_REFCaps[iAdapter].GDD8NumSupportedFormatOps == 0)
  929. {
  930. DPF_ERR("The reference driver cannot be found. GetAdapterCaps fails.");
  931. return D3DERR_NOTAVAILABLE;
  932. }
  933. return D3D_OK;
  934. }
  935. else if (Type == D3DDEVTYPE_SW)
  936. {
  937. if (m_pSwInitFunction == NULL)
  938. {
  939. DPF_ERR("No SW device has been registered.. GetAdapterCaps fails.");
  940. return D3DERR_INVALIDCALL;
  941. }
  942. else
  943. {
  944. GetSwCaps(iAdapter);
  945. *ppCaps = &m_SwCaps[iAdapter];
  946. if (m_SwCaps[iAdapter].GDD8NumSupportedFormatOps == 0)
  947. {
  948. DPF_ERR("The software driver cannot be loaded. GetAdapterCaps fails.");
  949. return D3DERR_NOTAVAILABLE;
  950. }
  951. return D3D_OK;
  952. }
  953. }
  954. else if (Type == D3DDEVTYPE_HAL)
  955. {
  956. DWORD i;
  957. if (m_bDisableHAL)
  958. {
  959. DPF_ERR("HW device not available. GetAdapterCaps fails.");
  960. return D3DERR_NOTAVAILABLE;
  961. }
  962. *ppCaps = &m_AdapterInfo[iAdapter].HALCaps;
  963. return D3D_OK;
  964. }
  965. return D3DERR_INVALIDDEVICE;
  966. }
  967. void GetDX8HALCaps(UINT iAdapter, PD3D8_DEVICEDATA pHalData, ADAPTERINFO * pAdapterInfo)
  968. {
  969. //DX7 or older drivers may need to be profiled to determine
  970. //their 555/565 format and whether they support an alpha
  971. //channel in 32bpp
  972. D3DFORMAT CachedUnknown16 = D3DFMT_UNKNOWN;
  973. UINT CachedHALFlags = 0;
  974. D3DDISPLAYMODE Mode;
  975. BOOL bProfiled = FALSE;
  976. UINT i;
  977. HRESULT hr;
  978. // If it's a DX8 driver, we hopefully don't need to profile at all.
  979. pAdapterInfo->Unknown16 = D3DFMT_UNKNOWN;
  980. hr = GetHALCapsInCurrentMode(pHalData, pAdapterInfo, FALSE, FALSE);
  981. if (SUCCEEDED(hr))
  982. {
  983. for (i = 0; i < pAdapterInfo->HALCaps.GDD8NumSupportedFormatOps; i++)
  984. {
  985. if (pAdapterInfo->HALCaps.pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_DISPLAYMODE)
  986. {
  987. switch (pAdapterInfo->HALCaps.pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwFourCC)
  988. {
  989. case D3DFMT_X1R5G5B5:
  990. case D3DFMT_R5G6B5:
  991. pAdapterInfo->Unknown16 = (D3DFORMAT) pAdapterInfo->HALCaps.pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwFourCC;
  992. break;
  993. }
  994. }
  995. }
  996. if (pAdapterInfo->Unknown16 != D3DFMT_UNKNOWN)
  997. {
  998. // That wasn't hard
  999. return;
  1000. }
  1001. }
  1002. // We are definately need to read stuff from the caps at some point,
  1003. // so why not now?
  1004. if (!ReadCapsFromCache(iAdapter,
  1005. NULL,
  1006. &CachedHALFlags,
  1007. &CachedUnknown16,
  1008. pAdapterInfo->DeviceName,
  1009. pAdapterInfo->bIsDisplay))
  1010. {
  1011. // There's nothing to read, so we need to re-profile
  1012. ProfileAdapter(
  1013. pAdapterInfo,
  1014. pHalData);
  1015. bProfiled = TRUE;
  1016. }
  1017. // If we profiled, then we already have everything that we need;
  1018. // otherwise, we have to go get it.
  1019. if (!bProfiled)
  1020. {
  1021. D3D8GetMode (pHalData->hDD, pAdapterInfo->DeviceName, &Mode, D3DFMT_UNKNOWN);
  1022. if ((Mode.Format == D3DFMT_X1R5G5B5) ||
  1023. (Mode.Format == D3DFMT_R5G6B5))
  1024. {
  1025. pAdapterInfo->Unknown16 = Mode.Format;
  1026. }
  1027. else
  1028. {
  1029. pAdapterInfo->Unknown16 = CachedUnknown16;
  1030. }
  1031. HRESULT hCurrentModeIsSupported = GetHALCapsInCurrentMode(pHalData, pAdapterInfo, FALSE, TRUE);
  1032. if (FAILED(hCurrentModeIsSupported))
  1033. {
  1034. // We assume that this will succeed because the call above already has
  1035. ReadCapsFromCache(iAdapter,
  1036. &pAdapterInfo->HALCaps,
  1037. &CachedHALFlags,
  1038. &CachedUnknown16,
  1039. pAdapterInfo->DeviceName,
  1040. pAdapterInfo->bIsDisplay);
  1041. DPF(0,"D3D not supported in current mode - reading caps from file");
  1042. }
  1043. }
  1044. //We now have good caps. Write them out to the cache.
  1045. WriteCapsToCache(iAdapter,
  1046. &pAdapterInfo->HALCaps,
  1047. pAdapterInfo->HALFlags,
  1048. pAdapterInfo->Unknown16,
  1049. pAdapterInfo->DeviceName,
  1050. pAdapterInfo->bIsDisplay);
  1051. }
  1052. #ifdef WINNT
  1053. void FakeDirectDrawCreate (ADAPTERINFO * pAdapterInfo, int iAdapter)
  1054. {
  1055. HDC hdc;
  1056. DDSURFACEDESC* pTextureList = NULL;
  1057. BOOL bProfiled = FALSE;
  1058. BOOL b32Supported;
  1059. BOOL b16Supported;
  1060. int NumOps;
  1061. DWORD j;
  1062. pTextureList = (DDSURFACEDESC *) MemAlloc (2 * sizeof (*pTextureList));
  1063. if (pTextureList != NULL)
  1064. {
  1065. hdc = DD_CreateDC(pAdapterInfo->DeviceName);
  1066. if (hdc != NULL)
  1067. {
  1068. HANDLE hDD;
  1069. HINSTANCE hLib;
  1070. D3D8CreateDirectDrawObject(hdc,
  1071. pAdapterInfo->DeviceName,
  1072. &hDD,
  1073. D3DDEVTYPE_HAL,
  1074. &hLib,
  1075. NULL);
  1076. if (hDD != NULL)
  1077. {
  1078. pAdapterInfo->bNoDDrawSupport = TRUE;
  1079. // Figure out the unknown 16 value
  1080. if (!ReadCapsFromCache(iAdapter,
  1081. NULL,
  1082. &(pAdapterInfo->HALFlags),
  1083. &(pAdapterInfo->Unknown16),
  1084. pAdapterInfo->DeviceName,
  1085. pAdapterInfo->bIsDisplay))
  1086. {
  1087. D3DDISPLAYMODE OrigMode;
  1088. D3DDISPLAYMODE NewMode;
  1089. D3D8GetMode (hDD,
  1090. pAdapterInfo->DeviceName,
  1091. &OrigMode,
  1092. D3DFMT_UNKNOWN);
  1093. if ((OrigMode.Format == D3DFMT_R5G6B5) ||
  1094. (OrigMode.Format == D3DFMT_X1R5G5B5))
  1095. {
  1096. pAdapterInfo->Unknown16 = OrigMode.Format;
  1097. }
  1098. else
  1099. {
  1100. D3D8SetMode (hDD,
  1101. pAdapterInfo->DeviceName,
  1102. 640,
  1103. 480,
  1104. 16,
  1105. 0,
  1106. FALSE);
  1107. D3D8GetMode (hDD,
  1108. pAdapterInfo->DeviceName,
  1109. &NewMode,
  1110. D3DFMT_UNKNOWN);
  1111. D3D8SetMode (hDD,
  1112. pAdapterInfo->DeviceName,
  1113. OrigMode.Width,
  1114. OrigMode.Height,
  1115. 0,
  1116. 0,
  1117. TRUE);
  1118. pAdapterInfo->Unknown16 = NewMode.Format;
  1119. }
  1120. bProfiled = TRUE;
  1121. }
  1122. // Build the mode table
  1123. while (1)
  1124. {
  1125. D3D8BuildModeTable(
  1126. pAdapterInfo->DeviceName,
  1127. NULL,
  1128. &(pAdapterInfo->NumModes),
  1129. pAdapterInfo->Unknown16,
  1130. hDD,
  1131. TRUE,
  1132. TRUE);
  1133. if (pAdapterInfo->NumModes)
  1134. {
  1135. pAdapterInfo->pModeTable = (D3DDISPLAYMODE*)
  1136. MemAlloc (sizeof(D3DDISPLAYMODE) * pAdapterInfo->NumModes);
  1137. if (pAdapterInfo->pModeTable != NULL)
  1138. {
  1139. D3D8BuildModeTable(
  1140. pAdapterInfo->DeviceName,
  1141. pAdapterInfo->pModeTable,
  1142. &(pAdapterInfo->NumModes),
  1143. pAdapterInfo->Unknown16,
  1144. hDD,
  1145. TRUE,
  1146. TRUE);
  1147. //If D3D8BuildModeTable finds it needs more space for its table,
  1148. //it will return 0 to indicate we should try again.
  1149. if (0 == pAdapterInfo->NumModes)
  1150. {
  1151. MemFree(pAdapterInfo->pModeTable);
  1152. pAdapterInfo->pModeTable = NULL;
  1153. continue;
  1154. }
  1155. }
  1156. else
  1157. {
  1158. pAdapterInfo->NumModes = 0;
  1159. }
  1160. }
  1161. break;
  1162. }//while(1)
  1163. // Now build a rudimentary op list based on what modes we support
  1164. b32Supported = b16Supported = FALSE;
  1165. for (j = 0; j < pAdapterInfo->NumModes; j++)
  1166. {
  1167. if (pAdapterInfo->pModeTable[j].Format == D3DFMT_X8R8G8B8)
  1168. {
  1169. b32Supported = TRUE;
  1170. }
  1171. if (pAdapterInfo->pModeTable[j].Format == pAdapterInfo->Unknown16)
  1172. {
  1173. b16Supported = TRUE;
  1174. }
  1175. }
  1176. NumOps = 0;
  1177. if (b16Supported)
  1178. {
  1179. pTextureList[NumOps].ddpfPixelFormat.dwFlags = DDPF_D3DFORMAT;
  1180. pTextureList[NumOps].ddpfPixelFormat.dwFourCC = (DWORD) pAdapterInfo->Unknown16;
  1181. pTextureList[NumOps].ddpfPixelFormat.dwOperations = D3DFORMAT_OP_DISPLAYMODE;
  1182. pTextureList[NumOps].ddpfPixelFormat.dwPrivateFormatBitCount = 0;
  1183. pTextureList[NumOps].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes = 0;
  1184. pTextureList[NumOps].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes = 0;
  1185. NumOps++;
  1186. }
  1187. if (b32Supported)
  1188. {
  1189. pTextureList[NumOps].ddpfPixelFormat.dwFlags = DDPF_D3DFORMAT;
  1190. pTextureList[NumOps].ddpfPixelFormat.dwFourCC = (DWORD) D3DFMT_X8R8G8B8;
  1191. pTextureList[NumOps].ddpfPixelFormat.dwOperations = D3DFORMAT_OP_DISPLAYMODE;
  1192. pTextureList[NumOps].ddpfPixelFormat.dwPrivateFormatBitCount = 0;
  1193. pTextureList[NumOps].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes = 0;
  1194. pTextureList[NumOps].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes = 0;
  1195. NumOps++;
  1196. }
  1197. pAdapterInfo->HALCaps.pGDD8SupportedFormatOps = pTextureList;
  1198. pAdapterInfo->HALCaps.GDD8NumSupportedFormatOps = NumOps;
  1199. if (bProfiled)
  1200. {
  1201. WriteCapsToCache(iAdapter,
  1202. &(pAdapterInfo->HALCaps),
  1203. pAdapterInfo->HALFlags,
  1204. pAdapterInfo->Unknown16,
  1205. pAdapterInfo->DeviceName,
  1206. pAdapterInfo->bIsDisplay);
  1207. }
  1208. D3D8DeleteDirectDrawObject(hDD);
  1209. }
  1210. DD_DoneDC(hdc);
  1211. }
  1212. if (pAdapterInfo->HALCaps.pGDD8SupportedFormatOps == NULL)
  1213. {
  1214. MemFree(pTextureList);
  1215. }
  1216. }
  1217. }
  1218. #endif
  1219. #undef DPF_MODNAME
  1220. #define DPF_MODNAME "CEnum::CEnum"
  1221. CEnum::CEnum(UINT AppSdkVersion)
  1222. :
  1223. m_cRef(1),
  1224. m_cAdapter(0),
  1225. m_bHasExclusive(FALSE),
  1226. m_AppSdkVersion(AppSdkVersion)
  1227. {
  1228. DWORD rc;
  1229. DWORD keyidx;
  1230. HKEY hkey;
  1231. HKEY hsubkey;
  1232. char keyname[256];
  1233. char desc[256];
  1234. char drvname[MAX_PATH];
  1235. DWORD cb;
  1236. DWORD i;
  1237. DWORD type;
  1238. GUID guid;
  1239. HDC hdc;
  1240. DISPLAY_DEVICEA dd;
  1241. // Give our base class a pointer to ourselves
  1242. SetOwner(this);
  1243. // Initialize our critical section
  1244. EnableCriticalSection();
  1245. // Disable DPFs that occur during this phase
  1246. DPF_MUTE();
  1247. // WARNING: Must call DPF_UNMUTE before returning from
  1248. // this function.
  1249. for (i = 0; i < MAX_DX8_ADAPTERS; i++)
  1250. m_pFullScreenDevice[i] = NULL;
  1251. ZeroMemory(m_AdapterInfo, sizeof(m_AdapterInfo));
  1252. // Always make the first entry reflect the primary device
  1253. ZeroMemory(&dd, sizeof(dd));
  1254. dd.cb = sizeof(dd);
  1255. for (i = 0; xxxEnumDisplayDevicesA(NULL, i, &dd, 0); i++)
  1256. {
  1257. //
  1258. // skip drivers that are not hardware devices
  1259. //
  1260. if (dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)
  1261. continue;
  1262. //
  1263. // don't enumerate devices that are not attached
  1264. //
  1265. if (!(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
  1266. continue;
  1267. if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
  1268. {
  1269. m_AdapterInfo[m_cAdapter].Guid = DisplayGUID;
  1270. m_AdapterInfo[m_cAdapter].Guid.Data1 += i;
  1271. lstrcpyn(m_AdapterInfo[m_cAdapter].DeviceName, dd.DeviceName, MAX_PATH);
  1272. m_AdapterInfo[m_cAdapter].bIsPrimary = TRUE;
  1273. m_AdapterInfo[m_cAdapter++].bIsDisplay = TRUE;
  1274. }
  1275. }
  1276. // Now get the info for the attached secondary devices
  1277. for (i = 0; xxxEnumDisplayDevicesA(NULL, i, &dd, 0); i++)
  1278. {
  1279. //
  1280. // skip drivers that are not hardware devices
  1281. //
  1282. if (dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)
  1283. continue;
  1284. //
  1285. // don't enumerate devices that are not attached
  1286. //
  1287. if (!(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
  1288. continue;
  1289. if (!(dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) &&
  1290. (m_cAdapter < MAX_DX8_ADAPTERS))
  1291. {
  1292. m_AdapterInfo[m_cAdapter].Guid = DisplayGUID;
  1293. m_AdapterInfo[m_cAdapter].Guid.Data1 += i;
  1294. lstrcpyn(m_AdapterInfo[m_cAdapter].DeviceName, dd.DeviceName, MAX_PATH);
  1295. m_AdapterInfo[m_cAdapter].bIsPrimary = FALSE;
  1296. m_AdapterInfo[m_cAdapter++].bIsDisplay = TRUE;
  1297. }
  1298. }
  1299. // Now get info for the passthrough devices listed under
  1300. // HKEY_LOCALMACHINE\Hardware\DirectDrawDrivers
  1301. if (RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_DDHW, &hkey) == 0)
  1302. {
  1303. keyidx = 0;
  1304. while (!RegEnumKey(hkey, keyidx, keyname, sizeof(keyname)))
  1305. {
  1306. if (strToGUID(keyname, &guid))
  1307. {
  1308. if (!RegOpenKey(hkey, keyname, &hsubkey))
  1309. {
  1310. cb = sizeof(desc) - 1;
  1311. if (!RegQueryValueEx(hsubkey, REGSTR_KEY_DDHW_DESCRIPTION, NULL, &type,
  1312. (CONST LPBYTE)desc, &cb))
  1313. {
  1314. if (type == REG_SZ)
  1315. {
  1316. desc[cb] = 0;
  1317. cb = sizeof(drvname) - 1;
  1318. if (!RegQueryValueEx(hsubkey, REGSTR_KEY_DDHW_DRIVERNAME, NULL, &type,
  1319. (CONST LPBYTE)drvname, &cb))
  1320. {
  1321. // It is possible that the registry is out
  1322. // of date, so we will try to create a DC.
  1323. // The problem is that the Voodoo 1 driver
  1324. // will suceed on a Voodoo 2, Banshee, or
  1325. // Voodoo 3 (and hang later), so we need to
  1326. // hack around it.
  1327. drvname[cb] = 0;
  1328. if (Voodoo1GoodToGo(&guid))
  1329. {
  1330. hdc = DD_CreateDC(drvname);
  1331. }
  1332. else
  1333. {
  1334. hdc = NULL;
  1335. }
  1336. if ((type == REG_SZ) &&
  1337. (hdc != NULL))
  1338. {
  1339. if (m_cAdapter < MAX_DX8_ADAPTERS)
  1340. {
  1341. drvname[cb] = 0;
  1342. m_AdapterInfo[m_cAdapter].Guid = guid;
  1343. lstrcpyn(m_AdapterInfo[m_cAdapter].DeviceName, drvname, MAX_PATH);
  1344. m_AdapterInfo[m_cAdapter].bIsPrimary = FALSE;
  1345. m_AdapterInfo[m_cAdapter++].bIsDisplay = FALSE;
  1346. }
  1347. }
  1348. if (hdc != NULL)
  1349. {
  1350. DD_DoneDC(hdc);
  1351. }
  1352. }
  1353. }
  1354. }
  1355. RegCloseKey(hsubkey);
  1356. }
  1357. }
  1358. keyidx++;
  1359. }
  1360. RegCloseKey(hkey);
  1361. }
  1362. DPF_UNMUTE();
  1363. // Now that we know about all of the devices, we need to build a mode
  1364. // table for each one
  1365. for (i = 0; i < m_cAdapter; i++)
  1366. {
  1367. HRESULT hr;
  1368. D3DDISPLAYMODE Mode;
  1369. DWORD j;
  1370. BOOL b16bppSupported;
  1371. BOOL b32bppSupported;
  1372. PD3D8_DEVICEDATA pHalData;
  1373. hr = InternalDirectDrawCreate(&pHalData,
  1374. &m_AdapterInfo[i],
  1375. D3DDEVTYPE_HAL,
  1376. NULL,
  1377. D3DFMT_UNKNOWN,
  1378. NULL,
  1379. 0);
  1380. if (FAILED(hr))
  1381. {
  1382. memset(&m_AdapterInfo[i].HALCaps, 0, sizeof(m_AdapterInfo[i].HALCaps));
  1383. // On Win2K, we want to enable sufficient functionality so that this
  1384. // adapter can at least run a sw driver. If it truly failed due to
  1385. // no ddraw support, we need to special case this and then build a
  1386. // rudimentary op list indicting that it works in the current mode.
  1387. #ifdef WINNT
  1388. FakeDirectDrawCreate(&m_AdapterInfo[i], i);
  1389. #endif
  1390. }
  1391. else
  1392. {
  1393. GetDX8HALCaps(i, pHalData, &m_AdapterInfo[i]);
  1394. b16bppSupported = b32bppSupported = FALSE;
  1395. for (j = 0; j < m_AdapterInfo[i].HALCaps.GDD8NumSupportedFormatOps; j++)
  1396. {
  1397. if (m_AdapterInfo[i].HALCaps.pGDD8SupportedFormatOps[j].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_DISPLAYMODE)
  1398. {
  1399. switch(m_AdapterInfo[i].HALCaps.pGDD8SupportedFormatOps[j].ddpfPixelFormat.dwFourCC)
  1400. {
  1401. case D3DFMT_X1R5G5B5:
  1402. case D3DFMT_R5G6B5:
  1403. b16bppSupported = TRUE;
  1404. break;
  1405. case D3DFMT_X8R8G8B8:
  1406. b32bppSupported = TRUE;
  1407. break;
  1408. }
  1409. }
  1410. }
  1411. while (1)
  1412. {
  1413. D3D8BuildModeTable(
  1414. m_AdapterInfo[i].DeviceName,
  1415. NULL,
  1416. &m_AdapterInfo[i].NumModes,
  1417. m_AdapterInfo[i].Unknown16,
  1418. pHalData->hDD,
  1419. b16bppSupported,
  1420. b32bppSupported);
  1421. if (m_AdapterInfo[i].NumModes)
  1422. {
  1423. m_AdapterInfo[i].pModeTable = (D3DDISPLAYMODE*)
  1424. MemAlloc (sizeof(D3DDISPLAYMODE) * m_AdapterInfo[i].NumModes);
  1425. if (m_AdapterInfo[i].pModeTable != NULL)
  1426. {
  1427. D3D8BuildModeTable(
  1428. m_AdapterInfo[i].DeviceName,
  1429. m_AdapterInfo[i].pModeTable,
  1430. &m_AdapterInfo[i].NumModes,
  1431. m_AdapterInfo[i].Unknown16,
  1432. pHalData->hDD,
  1433. b16bppSupported,
  1434. b32bppSupported);
  1435. //If D3D8BuildModeTable finds it needs more space for its table,
  1436. //it will return 0 to indicate we should try again.
  1437. if (0 == m_AdapterInfo[i].NumModes)
  1438. {
  1439. MemFree(m_AdapterInfo[i].pModeTable);
  1440. m_AdapterInfo[i].pModeTable = NULL;
  1441. continue;
  1442. }
  1443. }
  1444. else
  1445. {
  1446. m_AdapterInfo[i].NumModes = 0;
  1447. }
  1448. }
  1449. break;
  1450. }//while(1)
  1451. // If this doesn't have a ddraw HAL, but guessed that it might
  1452. // support a 32bpp mode, go see if we were right.
  1453. if (b32bppSupported &&
  1454. (m_AdapterInfo[i].HALCaps.D3DCaps.DevCaps == 0) &&
  1455. (m_AdapterInfo[i].HALCaps.DisplayFormatWithoutAlpha != D3DFMT_X8R8G8B8))
  1456. {
  1457. for (j = 0; j < m_AdapterInfo[i].NumModes; j++)
  1458. {
  1459. if (m_AdapterInfo[i].pModeTable[j].Format == D3DFMT_X8R8G8B8)
  1460. {
  1461. break;
  1462. }
  1463. }
  1464. if (j >= m_AdapterInfo[i].NumModes)
  1465. {
  1466. // This card apparently does NOT support 32bpp so remove it
  1467. for (j = 0; j < m_AdapterInfo[i].HALCaps.GDD8NumSupportedFormatOps; j++)
  1468. {
  1469. if ((m_AdapterInfo[i].HALCaps.pGDD8SupportedFormatOps[j].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_DISPLAYMODE) &&
  1470. (m_AdapterInfo[i].HALCaps.pGDD8SupportedFormatOps[j].ddpfPixelFormat.dwFourCC == D3DFMT_X8R8G8B8))
  1471. {
  1472. m_AdapterInfo[i].HALCaps.pGDD8SupportedFormatOps[j].ddpfPixelFormat.dwOperations &= ~D3DFORMAT_OP_DISPLAYMODE;
  1473. }
  1474. }
  1475. }
  1476. }
  1477. InternalDirectDrawRelease(pHalData);
  1478. }
  1479. }
  1480. m_hGammaCalibrator = NULL;
  1481. m_pGammaCalibratorProc = NULL;
  1482. m_bAttemptedGammaCalibrator= FALSE;
  1483. m_bGammaCalibratorExists = FALSE;
  1484. // The first time through, we will also check to see if a gamma
  1485. // calibrator is registered. All we'll do here is read the registry
  1486. // key and if it's non-NULL, we'll assume that one exists.
  1487. {
  1488. HKEY hkey;
  1489. if (!RegOpenKey(HKEY_LOCAL_MACHINE,
  1490. REGSTR_PATH_DDRAW "\\" REGSTR_KEY_GAMMA_CALIBRATOR, &hkey))
  1491. {
  1492. DWORD type;
  1493. DWORD cb;
  1494. cb = sizeof(m_szGammaCalibrator);
  1495. if (!RegQueryValueEx(hkey, REGSTR_VAL_GAMMA_CALIBRATOR,
  1496. NULL, &type, m_szGammaCalibrator, &cb))
  1497. {
  1498. if ((type == REG_SZ) &&
  1499. (m_szGammaCalibrator[0] != '\0'))
  1500. {
  1501. m_bGammaCalibratorExists = TRUE;
  1502. }
  1503. }
  1504. RegCloseKey(hkey);
  1505. }
  1506. }
  1507. // Check to see if they disabled the D3DHAL in the registry
  1508. {
  1509. HKEY hKey;
  1510. if (!RegOpenKey(HKEY_LOCAL_MACHINE, RESPATH_D3D "\\Drivers", &hKey))
  1511. {
  1512. DWORD type;
  1513. DWORD value;
  1514. DWORD cb = sizeof(value);
  1515. if (!RegQueryValueEx(hKey, "SoftwareOnly", NULL, &type, (CONST LPBYTE)&value, &cb))
  1516. {
  1517. if (value)
  1518. {
  1519. m_bDisableHAL = TRUE;
  1520. }
  1521. else
  1522. {
  1523. m_bDisableHAL = FALSE;
  1524. }
  1525. }
  1526. RegCloseKey(hKey);
  1527. }
  1528. }
  1529. DXGASSERT(IsValid());
  1530. } // CEnum::CEnum
  1531. #undef DPF_MODNAME
  1532. #define DPF_MODNAME "CEnum::GetAdapterCount"
  1533. STDMETHODIMP_(UINT) CEnum::GetAdapterCount()
  1534. {
  1535. API_ENTER_RET(this, UINT);
  1536. return m_cAdapter;
  1537. } // GetAdapterCount
  1538. #undef DPF_MODNAME
  1539. #define DPF_MODNAME "CEnum::GetAdapterIdentifier"
  1540. STDMETHODIMP CEnum::GetAdapterIdentifier(
  1541. UINT iAdapter,
  1542. DWORD dwFlags,
  1543. D3DADAPTER_IDENTIFIER8 *pIdentifier)
  1544. {
  1545. API_ENTER(this);
  1546. if (!VALID_WRITEPTR(pIdentifier, sizeof(D3DADAPTER_IDENTIFIER8)))
  1547. {
  1548. DPF_ERR("Invalid pIdentifier parameter specified for GetAdapterIdentifier");
  1549. return D3DERR_INVALIDCALL;
  1550. }
  1551. memset(pIdentifier, 0, sizeof(*pIdentifier));
  1552. if (dwFlags & ~VALID_D3DENUM_FLAGS)
  1553. {
  1554. DPF_ERR("Invalid flags specified. GetAdapterIdentifier fails.");
  1555. return D3DERR_INVALIDCALL;
  1556. }
  1557. if (iAdapter >= m_cAdapter)
  1558. {
  1559. DPF_ERR("Invalid Adapter number specified. GetAdapterIdentifier fails.");
  1560. return D3DERR_INVALIDCALL;
  1561. }
  1562. // Need driver name
  1563. GetAdapterInfo (m_AdapterInfo[iAdapter].DeviceName,
  1564. pIdentifier,
  1565. m_AdapterInfo[iAdapter].bIsDisplay,
  1566. (dwFlags & D3DENUM_NO_WHQL_LEVEL) ? TRUE : FALSE,
  1567. TRUE);
  1568. return D3D_OK;
  1569. } // GetAdapterIdentifier
  1570. #undef DPF_MODNAME
  1571. #define DPF_MODNAME "CEnum::GetAdapterModeCount"
  1572. STDMETHODIMP_(UINT) CEnum::GetAdapterModeCount(
  1573. UINT iAdapter)
  1574. {
  1575. API_ENTER_RET(this, UINT);
  1576. if (iAdapter >= m_cAdapter)
  1577. {
  1578. DPF_ERR("Invalid adapter specified. GetAdapterModeCount returns zero.");
  1579. return 0;
  1580. }
  1581. return m_AdapterInfo[iAdapter].NumModes;
  1582. } // GetAdapterModeCount
  1583. #undef DPF_MODNAME
  1584. #define DPF_MODNAME "CEnum::EnumAdapterModes"
  1585. STDMETHODIMP CEnum::EnumAdapterModes(
  1586. UINT iAdapter,
  1587. UINT iMode,
  1588. D3DDISPLAYMODE* pMode)
  1589. {
  1590. API_ENTER(this);
  1591. if (iAdapter >= m_cAdapter)
  1592. {
  1593. DPF_ERR("Invalid adapter specified. EnumAdapterModes fails.");
  1594. return D3DERR_INVALIDCALL;
  1595. }
  1596. if (iMode >= m_AdapterInfo[iAdapter].NumModes)
  1597. {
  1598. DPF_ERR("Invalid mode number specified. EnumAdapterModes fails.");
  1599. return D3DERR_INVALIDCALL;
  1600. }
  1601. if (!VALID_WRITEPTR(pMode, sizeof(D3DDISPLAYMODE)))
  1602. {
  1603. DPF_ERR("Invalid pMode parameter specified for EnumAdapterModes");
  1604. return D3DERR_INVALIDCALL;
  1605. }
  1606. *pMode = m_AdapterInfo[iAdapter].pModeTable[iMode];
  1607. return D3D_OK;
  1608. } // EnumAdapterModes
  1609. #undef DPF_MODNAME
  1610. #define DPF_MODNAME "CEnum::GetAdapterMonitor"
  1611. HMONITOR CEnum::GetAdapterMonitor(UINT iAdapter)
  1612. {
  1613. API_ENTER_RET(this, HMONITOR);
  1614. if (iAdapter >= m_cAdapter)
  1615. {
  1616. DPF_ERR("Invalid adapter specified. GetAdapterMonitor returns NULL");
  1617. return NULL;
  1618. }
  1619. return GetMonitorFromDeviceName((LPSTR)m_AdapterInfo[iAdapter].DeviceName);
  1620. } // GetAdapterMonitor
  1621. #undef DPF_MODNAME
  1622. #define DPF_MODNAME "CEnum::CheckDeviceFormat"
  1623. STDMETHODIMP CEnum::CheckDeviceFormat(
  1624. UINT iAdapter,
  1625. D3DDEVTYPE DevType,
  1626. D3DFORMAT DisplayFormat,
  1627. DWORD Usage,
  1628. D3DRESOURCETYPE RType,
  1629. D3DFORMAT CheckFormat)
  1630. {
  1631. API_ENTER(this);
  1632. D3D8_DRIVERCAPS* pAdapterCaps;
  1633. HRESULT hr;
  1634. // Check parameters
  1635. if (iAdapter >= m_cAdapter)
  1636. {
  1637. DPF_ERR("Invalid adapter specified. CheckDeviceFormat fails");
  1638. return D3DERR_INVALIDCALL;
  1639. }
  1640. // Check Device Type
  1641. if (DevType != D3DDEVTYPE_REF &&
  1642. DevType != D3DDEVTYPE_HAL &&
  1643. DevType != D3DDEVTYPE_SW)
  1644. {
  1645. DPF_ERR("Invalid device specified to CheckDeviceFormat");
  1646. return D3DERR_INVALIDCALL;
  1647. }
  1648. if ((DisplayFormat == D3DFMT_UNKNOWN) ||
  1649. (CheckFormat == D3DFMT_UNKNOWN))
  1650. {
  1651. DPF(0, "D3DFMT_UNKNOWN is not a valid format.");
  1652. return D3DERR_INVALIDCALL;
  1653. }
  1654. // Sanity check the input format
  1655. if ((DisplayFormat != D3DFMT_X8R8G8B8) &&
  1656. (DisplayFormat != D3DFMT_R5G6B5) &&
  1657. (DisplayFormat != D3DFMT_X1R5G5B5) &&
  1658. (DisplayFormat != D3DFMT_R8G8B8))
  1659. {
  1660. DPF(1, "D3D Unsupported for the adapter format passed to CheckDeviceFormat");
  1661. return D3DERR_NOTAVAILABLE;
  1662. }
  1663. //We infer the texture usage from type...
  1664. if (RType == D3DRTYPE_TEXTURE ||
  1665. RType == D3DRTYPE_CUBETEXTURE ||
  1666. RType == D3DRTYPE_VOLUMETEXTURE)
  1667. {
  1668. Usage |= D3DUSAGE_TEXTURE;
  1669. }
  1670. // Surface should be either render targets or Z/Stencil
  1671. else if (RType == D3DRTYPE_SURFACE)
  1672. {
  1673. if (!(Usage & D3DUSAGE_DEPTHSTENCIL) &&
  1674. !(Usage & D3DUSAGE_RENDERTARGET))
  1675. {
  1676. DPF_ERR("Must specify either D3DUSAGE_DEPTHSTENCIL or D3DUSAGE_RENDERTARGET for D3DRTYPE_SURFACE. CheckDeviceFormat fails.");
  1677. return D3DERR_INVALIDCALL;
  1678. }
  1679. }
  1680. // Any attempt to query anything but an unknown Z/stencil
  1681. // or D16 value must fail (because we explicitly don't allow apps to
  1682. // know what the z/stencil format really is, except for D16).
  1683. if (Usage & D3DUSAGE_DEPTHSTENCIL)
  1684. {
  1685. if (!CPixel::IsEnumeratableZ(CheckFormat))
  1686. {
  1687. DPF_ERR("Format is not in approved list for Z buffer formats. CheckDeviceFormats fails.");
  1688. return D3DERR_INVALIDCALL;
  1689. }
  1690. }
  1691. // Parameter check for invalid usages and resource types
  1692. if ((RType != D3DRTYPE_SURFACE) &&
  1693. (RType != D3DRTYPE_VOLUME) &&
  1694. (RType != D3DRTYPE_TEXTURE) &&
  1695. (RType != D3DRTYPE_VOLUMETEXTURE) &&
  1696. (RType != D3DRTYPE_CUBETEXTURE))
  1697. {
  1698. DPF_ERR("Invalid resource type specified. CheckDeviceFormat fails.");
  1699. return D3DERR_INVALIDCALL;
  1700. }
  1701. if (Usage & ~(D3DUSAGE_EXTERNAL |
  1702. D3DUSAGE_LOCK |
  1703. D3DUSAGE_TEXTURE |
  1704. D3DUSAGE_BACKBUFFER |
  1705. D3DUSAGE_INTERNALBUFFER |
  1706. D3DUSAGE_OFFSCREENPLAIN |
  1707. D3DUSAGE_PRIMARYSURFACE))
  1708. {
  1709. DPF_ERR("Invalid usage flag specified. CheckDeviceFormat fails.");
  1710. return D3DERR_INVALIDCALL;
  1711. }
  1712. hr = GetAdapterCaps(iAdapter,
  1713. DevType,
  1714. &pAdapterCaps);
  1715. if (FAILED(hr))
  1716. {
  1717. return hr;
  1718. }
  1719. // Check if USAGE_DYNAMIC is allowed
  1720. if ((Usage & D3DUSAGE_DYNAMIC) && (Usage & D3DUSAGE_TEXTURE))
  1721. {
  1722. if (!(pAdapterCaps->D3DCaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES))
  1723. {
  1724. DPF_ERR("Driver does not support dynamic textures.");
  1725. return D3DERR_INVALIDCALL;
  1726. }
  1727. if (Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL))
  1728. {
  1729. DPF_ERR("Dynamic textures cannot be rendertargets or depth/stencils.");
  1730. return D3DERR_INVALIDCALL;
  1731. }
  1732. }
  1733. // Make sure that the specified display format is supported
  1734. if (!IsSupportedOp (DisplayFormat,
  1735. pAdapterCaps->pGDD8SupportedFormatOps,
  1736. pAdapterCaps->GDD8NumSupportedFormatOps,
  1737. D3DFORMAT_OP_DISPLAYMODE |D3DFORMAT_OP_3DACCELERATION))
  1738. {
  1739. return D3DERR_NOTAVAILABLE;
  1740. }
  1741. //We now need to map the API desires to the set of capabilities that we
  1742. //allow drivers to express in their DX8 pixel format operation list.
  1743. DWORD dwRequiredOperations=0;
  1744. //We have three different texturing methodologies that the driver may
  1745. //support independently
  1746. switch(RType)
  1747. {
  1748. case D3DRTYPE_TEXTURE:
  1749. dwRequiredOperations |= D3DFORMAT_OP_TEXTURE;
  1750. break;
  1751. case D3DRTYPE_VOLUMETEXTURE:
  1752. dwRequiredOperations |= D3DFORMAT_OP_VOLUMETEXTURE;
  1753. break;
  1754. case D3DRTYPE_CUBETEXTURE:
  1755. dwRequiredOperations |= D3DFORMAT_OP_CUBETEXTURE;
  1756. break;
  1757. }
  1758. // If it's a depth/stencil, make sure it's a format that the driver understands
  1759. CheckFormat = MapDepthStencilFormat(iAdapter,
  1760. DevType,
  1761. CheckFormat);
  1762. //Render targets may be the same format as the display, or they may
  1763. //be different
  1764. if (Usage & D3DUSAGE_RENDERTARGET)
  1765. {
  1766. if (DisplayFormat == CheckFormat)
  1767. {
  1768. // We have a special cap for the case when the offscreen is the
  1769. // same format as the display
  1770. dwRequiredOperations |= D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET;
  1771. }
  1772. else if ((CPixel::SuppressAlphaChannel(CheckFormat) != CheckFormat) && //offscreen has alpha
  1773. (CPixel::SuppressAlphaChannel(CheckFormat) == DisplayFormat)) //offscreen is same as display mod alpha
  1774. {
  1775. //We have a special cap for the case when the offscreen is the same
  1776. //format as the display modulo the alpha channel
  1777. //(such as X8R8G8B8 for the primary and A8R8G8B8 for the offscreen).
  1778. dwRequiredOperations |= D3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET;
  1779. }
  1780. else
  1781. {
  1782. dwRequiredOperations |= D3DFORMAT_OP_OFFSCREEN_RENDERTARGET;
  1783. }
  1784. }
  1785. //Some hardware doesn't support Z and color buffers of differing pixel depths.
  1786. //We only do this check on known z/stencil formats, since drivers are free
  1787. //to spoof unknown formats (they can't be locked).
  1788. // Now we know what we're being asked to do on this format...
  1789. // let's run through the driver's list and see if it can do it.
  1790. for(UINT i=0;i< pAdapterCaps->GDD8NumSupportedFormatOps; i++)
  1791. {
  1792. // We need a match for format, plus all the requested operation flags
  1793. if ((CheckFormat ==
  1794. (D3DFORMAT) pAdapterCaps->pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwFourCC) &&
  1795. (dwRequiredOperations == (dwRequiredOperations &
  1796. pAdapterCaps->pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwOperations)))
  1797. {
  1798. return D3D_OK;
  1799. }
  1800. }
  1801. // We don't spew info here; because NotAvailable is a reasonable
  1802. // usage of the API; this doesn't reflect an app bug or an
  1803. // anomalous circumstance where a message would be useful
  1804. return D3DERR_NOTAVAILABLE;
  1805. }
  1806. #undef DPF_MODNAME
  1807. #define DPF_MODNAME "CEnum::CheckDeviceType"
  1808. STDMETHODIMP CEnum::CheckDeviceType(
  1809. UINT iAdapter,
  1810. D3DDEVTYPE DevType,
  1811. D3DFORMAT DisplayFormat,
  1812. D3DFORMAT BackBufferFormat,
  1813. BOOL bWindowed)
  1814. {
  1815. API_ENTER(this);
  1816. D3D8_DRIVERCAPS* pAdapterCaps;
  1817. HRESULT hr;
  1818. if (iAdapter >= m_cAdapter)
  1819. {
  1820. DPF_ERR("Invalid adapter specified. CheckDeviceType fails.");
  1821. return D3DERR_INVALIDCALL;
  1822. }
  1823. if (DevType != D3DDEVTYPE_REF &&
  1824. DevType != D3DDEVTYPE_HAL &&
  1825. DevType != D3DDEVTYPE_SW)
  1826. {
  1827. DPF_ERR("Invalid device specified to CheckDeviceType");
  1828. return D3DERR_INVALIDCALL;
  1829. }
  1830. if ((DisplayFormat == D3DFMT_UNKNOWN) ||
  1831. (BackBufferFormat == D3DFMT_UNKNOWN))
  1832. {
  1833. DPF(0, "D3DFMT_UNKNOWN is not a valid format.");
  1834. return D3DERR_INVALIDCALL;
  1835. }
  1836. // Force the backbuffer format to be one of the 16 or 32bpp formats (not
  1837. // 24bpp). We do this because DX8 shipped with a similar check in Reset,
  1838. // and we want to be consistent.
  1839. if ((BackBufferFormat != D3DFMT_X1R5G5B5) &&
  1840. (BackBufferFormat != D3DFMT_A1R5G5B5) &&
  1841. (BackBufferFormat != D3DFMT_R5G6B5) &&
  1842. (BackBufferFormat != D3DFMT_X8R8G8B8) &&
  1843. (BackBufferFormat != D3DFMT_A8R8G8B8))
  1844. {
  1845. // We should return D3DDERR_INVALIDCALL, but we didn't ship that way for
  1846. // DX8 and we don't want to cause regressions, so NOTAVAILABLE is safer.
  1847. DPF(1, "Invalid backbuffer format specified");
  1848. return D3DERR_NOTAVAILABLE;
  1849. }
  1850. // Sanity check the input format
  1851. if ((DisplayFormat != D3DFMT_X8R8G8B8) &&
  1852. (DisplayFormat != D3DFMT_R5G6B5) &&
  1853. (DisplayFormat != D3DFMT_X1R5G5B5) &&
  1854. (DisplayFormat != D3DFMT_R8G8B8))
  1855. {
  1856. DPF(1, "D3D Unsupported for the adapter format passed to CheckDeviceType");
  1857. return D3DERR_NOTAVAILABLE;
  1858. }
  1859. hr = GetAdapterCaps(iAdapter,
  1860. DevType,
  1861. &pAdapterCaps);
  1862. if (FAILED(hr))
  1863. {
  1864. return hr;
  1865. }
  1866. // Is the display mode supported?
  1867. if (!IsSupportedOp (DisplayFormat,
  1868. pAdapterCaps->pGDD8SupportedFormatOps,
  1869. pAdapterCaps->GDD8NumSupportedFormatOps,
  1870. D3DFORMAT_OP_DISPLAYMODE |D3DFORMAT_OP_3DACCELERATION))
  1871. {
  1872. return D3DERR_NOTAVAILABLE;
  1873. }
  1874. if (DisplayFormat != BackBufferFormat)
  1875. {
  1876. D3DFORMAT AlphaFormat = D3DFMT_UNKNOWN;
  1877. UINT i;
  1878. // This is allowed only if the only difference is alpha.
  1879. switch (DisplayFormat)
  1880. {
  1881. case D3DFMT_X1R5G5B5:
  1882. AlphaFormat = D3DFMT_A1R5G5B5;
  1883. break;
  1884. case D3DFMT_X8R8G8B8:
  1885. AlphaFormat = D3DFMT_A8R8G8B8;
  1886. break;
  1887. }
  1888. hr = D3DERR_NOTAVAILABLE;
  1889. if (AlphaFormat == BackBufferFormat)
  1890. {
  1891. if (IsSupportedOp (AlphaFormat,
  1892. pAdapterCaps->pGDD8SupportedFormatOps,
  1893. pAdapterCaps->GDD8NumSupportedFormatOps,
  1894. D3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET))
  1895. {
  1896. hr = D3D_OK;
  1897. }
  1898. }
  1899. }
  1900. else
  1901. {
  1902. // For DX8, we force the backbuffer and display formats to match
  1903. // (minus alpha). This means that they should support a render target
  1904. // of the same format.
  1905. if (!IsSupportedOp (DisplayFormat,
  1906. pAdapterCaps->pGDD8SupportedFormatOps,
  1907. pAdapterCaps->GDD8NumSupportedFormatOps,
  1908. D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET))
  1909. {
  1910. return D3DERR_NOTAVAILABLE;
  1911. }
  1912. }
  1913. if (SUCCEEDED(hr))
  1914. {
  1915. if (bWindowed &&
  1916. !(pAdapterCaps->D3DCaps.Caps2 & DDCAPS2_CANRENDERWINDOWED))
  1917. {
  1918. hr = D3DERR_NOTAVAILABLE;
  1919. }
  1920. }
  1921. return hr;
  1922. }
  1923. #undef DPF_MODNAME
  1924. #define DPF_MODNAME "CEnum::GetAdapterDisplayMode"
  1925. STDMETHODIMP CEnum::GetAdapterDisplayMode(UINT iAdapter, D3DDISPLAYMODE* pMode)
  1926. {
  1927. API_ENTER(this);
  1928. HANDLE h;
  1929. HRESULT hr = D3D_OK;
  1930. if (iAdapter >= m_cAdapter)
  1931. {
  1932. DPF_ERR("Invalid adapter specified. GetAdapterDisplayMode fails");
  1933. return D3DERR_INVALIDCALL;
  1934. }
  1935. if (!VALID_WRITEPTR(pMode, sizeof(D3DDISPLAYMODE)))
  1936. {
  1937. DPF_ERR("Invalid pMode parameter specified for GetAdapterDisplayMode");
  1938. return D3DERR_INVALIDCALL;
  1939. }
  1940. if (m_AdapterInfo[iAdapter].bIsDisplay)
  1941. {
  1942. D3D8GetMode (NULL, m_AdapterInfo[iAdapter].DeviceName, pMode, m_AdapterInfo[iAdapter].Unknown16);
  1943. }
  1944. else
  1945. {
  1946. PD3D8_DEVICEDATA pDeviceData;
  1947. hr = InternalDirectDrawCreate(&pDeviceData,
  1948. &m_AdapterInfo[iAdapter],
  1949. D3DDEVTYPE_HAL,
  1950. NULL,
  1951. m_AdapterInfo[iAdapter].Unknown16,
  1952. m_AdapterInfo[iAdapter].HALCaps.pGDD8SupportedFormatOps,
  1953. m_AdapterInfo[iAdapter].HALCaps.GDD8NumSupportedFormatOps);
  1954. if (SUCCEEDED(hr))
  1955. {
  1956. D3D8GetMode (pDeviceData->hDD, m_AdapterInfo[iAdapter].DeviceName, pMode, D3DFMT_UNKNOWN);
  1957. InternalDirectDrawRelease(pDeviceData);
  1958. }
  1959. }
  1960. return hr;
  1961. }
  1962. #undef DPF_MODNAME
  1963. #define DPF_MODNAME "CEnum::EnumDeviceMultiSampleType"
  1964. STDMETHODIMP CEnum::CheckDeviceMultiSampleType(
  1965. UINT iAdapter,
  1966. D3DDEVTYPE DevType,
  1967. D3DFORMAT RTFormat,
  1968. BOOL Windowed,
  1969. D3DMULTISAMPLE_TYPE SampleType)
  1970. {
  1971. API_ENTER(this);
  1972. // Check parameters
  1973. if (iAdapter >= m_cAdapter)
  1974. {
  1975. DPF_ERR("Invalid adapter specified. CheckDeviceMultiSampleType fails.");
  1976. return D3DERR_INVALIDCALL;
  1977. }
  1978. // Check Device Type
  1979. if (DevType != D3DDEVTYPE_REF &&
  1980. DevType != D3DDEVTYPE_HAL &&
  1981. DevType != D3DDEVTYPE_SW)
  1982. {
  1983. DPF_ERR("Invalid device specified to CheckDeviceMultiSampleType");
  1984. return D3DERR_INVALIDCALL;
  1985. }
  1986. if (RTFormat == D3DFMT_UNKNOWN)
  1987. {
  1988. DPF_ERR("D3DFMT_UNKNOWN is not a valid format. CheckDeviceMultiSampleType fails.");
  1989. return D3DERR_INVALIDCALL;
  1990. }
  1991. D3D8_DRIVERCAPS* pAdapterCaps;
  1992. HRESULT hr;
  1993. hr = GetAdapterCaps(iAdapter,
  1994. DevType,
  1995. &pAdapterCaps);
  1996. if (FAILED(hr))
  1997. {
  1998. return hr;
  1999. }
  2000. if (SampleType == D3DMULTISAMPLE_NONE)
  2001. {
  2002. return D3D_OK;
  2003. }
  2004. else if (SampleType == 1)
  2005. {
  2006. DPF_ERR("Invalid sample type specified. Only enumerated values are supported. CheckDeviceMultiSampleType fails.");
  2007. return D3DERR_INVALIDCALL;
  2008. }
  2009. else if (SampleType > D3DMULTISAMPLE_16_SAMPLES)
  2010. {
  2011. DPF_ERR("Invalid sample type specified. CheckDeviceMultiSampleType fails.");
  2012. return D3DERR_INVALIDCALL;
  2013. }
  2014. // Treat Ref/SW Fullscreen the same as Windowed.
  2015. if (DevType == D3DDEVTYPE_REF ||
  2016. DevType == D3DDEVTYPE_SW)
  2017. {
  2018. Windowed = TRUE;
  2019. }
  2020. // If it's a depth/stencil, make sure it's a format that the driver understands
  2021. RTFormat = MapDepthStencilFormat(iAdapter,
  2022. DevType,
  2023. RTFormat);
  2024. DDSURFACEDESC * pDX8SupportedFormatOperations =
  2025. pAdapterCaps->pGDD8SupportedFormatOps;
  2026. // let's run through the driver's list and see if it can do it.
  2027. for (UINT i = 0; i < pAdapterCaps->GDD8NumSupportedFormatOps; i++)
  2028. {
  2029. //We need a match for format, plus all either blt or flip caps
  2030. if (RTFormat == (D3DFORMAT) pDX8SupportedFormatOperations[i].ddpfPixelFormat.dwFourCC)
  2031. {
  2032. // Found the format in question... do we have the MS caps?
  2033. WORD wMSOps = Windowed ?
  2034. pDX8SupportedFormatOperations[i].ddpfPixelFormat.MultiSampleCaps.wBltMSTypes :
  2035. pDX8SupportedFormatOperations[i].ddpfPixelFormat.MultiSampleCaps.wFlipMSTypes;
  2036. // To determine the bit to use, we map the set of sample-types [2-16] to
  2037. // a particular (bit 1 to bit 15) of the WORD.
  2038. DXGASSERT(SampleType > 1);
  2039. DXGASSERT(SampleType <= 16);
  2040. if (wMSOps & DDI_MULTISAMPLE_TYPE(SampleType))
  2041. {
  2042. return D3D_OK;
  2043. }
  2044. }
  2045. }
  2046. return D3DERR_NOTAVAILABLE;
  2047. } // CheckDeviceMultiSampleType
  2048. #undef DPF_MODNAME
  2049. #define DPF_MODNAME "CEnum::CheckDepthStencilMatch"
  2050. STDMETHODIMP CEnum::CheckDepthStencilMatch(UINT iAdapter,
  2051. D3DDEVTYPE DevType,
  2052. D3DFORMAT AdapterFormat,
  2053. D3DFORMAT RTFormat,
  2054. D3DFORMAT DSFormat)
  2055. {
  2056. API_ENTER(this);
  2057. HRESULT hr;
  2058. // Check parameters
  2059. if (iAdapter >= m_cAdapter)
  2060. {
  2061. DPF_ERR("Invalid adapter specified. CheckDepthStencilMatch fails.");
  2062. return D3DERR_INVALIDCALL;
  2063. }
  2064. // Check Device Type
  2065. if (DevType != D3DDEVTYPE_REF &&
  2066. DevType != D3DDEVTYPE_HAL &&
  2067. DevType != D3DDEVTYPE_SW)
  2068. {
  2069. DPF_ERR("Invalid device specified to CheckDepthStencilMatch");
  2070. return D3DERR_INVALIDCALL;
  2071. }
  2072. if ((AdapterFormat == D3DFMT_UNKNOWN) ||
  2073. (RTFormat == D3DFMT_UNKNOWN) ||
  2074. (DSFormat == D3DFMT_UNKNOWN))
  2075. {
  2076. DPF_ERR("D3DFMT_UNKNOWN is not a valid format. CheckDepthStencilMatch fails.");
  2077. return D3DERR_INVALIDCALL;
  2078. }
  2079. D3D8_DRIVERCAPS *pAdapterCaps = NULL;
  2080. hr = GetAdapterCaps(iAdapter,
  2081. DevType,
  2082. &pAdapterCaps);
  2083. if (FAILED(hr))
  2084. {
  2085. return hr;
  2086. }
  2087. // Is the display mode supported?
  2088. if (!IsSupportedOp (AdapterFormat,
  2089. pAdapterCaps->pGDD8SupportedFormatOps,
  2090. pAdapterCaps->GDD8NumSupportedFormatOps,
  2091. D3DFORMAT_OP_DISPLAYMODE |D3DFORMAT_OP_3DACCELERATION))
  2092. {
  2093. return D3DERR_NOTAVAILABLE;
  2094. }
  2095. DDSURFACEDESC * pDX8SupportedFormatOperations =
  2096. pAdapterCaps->pGDD8SupportedFormatOps;
  2097. // Decide what we need to check
  2098. BOOL bCanDoRT = FALSE;
  2099. BOOL bCanDoDS = FALSE;
  2100. BOOL bMatchNeededForDS = FALSE;
  2101. // We only need to check for matching if the user is trying
  2102. // to use D3DFMT_D16 or has Stencil
  2103. if (DSFormat == D3DFMT_D16_LOCKABLE ||
  2104. CPixel::HasStencilBits(DSFormat))
  2105. {
  2106. bMatchNeededForDS = TRUE;
  2107. }
  2108. //In DX8.1 and beyond, we also make this function check D24X8 and D32, since all known parts that have restrictions
  2109. //also have this restriction
  2110. if (GetAppSdkVersion() > D3D_SDK_VERSION_DX8)
  2111. {
  2112. switch (DSFormat)
  2113. {
  2114. case D3DFMT_D24X8:
  2115. case D3DFMT_D32:
  2116. bMatchNeededForDS = TRUE;
  2117. }
  2118. }
  2119. DWORD dwRequiredZOps = D3DFORMAT_OP_ZSTENCIL;
  2120. // If it's a depth/stencil, make sure it's a format that the driver understands
  2121. DSFormat = MapDepthStencilFormat(iAdapter,
  2122. DevType,
  2123. DSFormat);
  2124. // let's run through the driver's list and see if this all
  2125. // works
  2126. for (UINT i = 0; i < pAdapterCaps->GDD8NumSupportedFormatOps; i++)
  2127. {
  2128. // See if it matches the RT format
  2129. if (RTFormat == (D3DFORMAT) pDX8SupportedFormatOperations[i].ddpfPixelFormat.dwFourCC)
  2130. {
  2131. // Found the RT Format, can we use as a render-target?
  2132. // we check the format that has the least constraints so that
  2133. // we are truly checking "For all possible RTs that I can make
  2134. // with this device, does the Z match it?" We'd like to say
  2135. // "No." if you couldn't make the RT at all in any circumstance.
  2136. if (D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET &
  2137. pAdapterCaps->pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwOperations)
  2138. {
  2139. bCanDoRT = TRUE;
  2140. }
  2141. }
  2142. // See if it matches the DS Format
  2143. if (DSFormat == (D3DFORMAT) pDX8SupportedFormatOperations[i].ddpfPixelFormat.dwFourCC)
  2144. {
  2145. // Found the DS format, can we use it as DS (and potentially lockable)?
  2146. // i.e. if ALL required bits are on in this FOL entry.
  2147. // Again, we check the formats that have the least constraints.
  2148. if (dwRequiredZOps ==
  2149. (dwRequiredZOps & pAdapterCaps->pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwOperations) )
  2150. {
  2151. bCanDoDS = TRUE;
  2152. if (D3DFORMAT_OP_ZSTENCIL_WITH_ARBITRARY_COLOR_DEPTH &
  2153. pAdapterCaps->pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwOperations)
  2154. {
  2155. bMatchNeededForDS = FALSE;
  2156. }
  2157. }
  2158. }
  2159. }
  2160. if (!bCanDoRT)
  2161. {
  2162. DPF_ERR("RenderTarget Format is not supported for this "
  2163. "Adapter/DevType/AdapterFormat. This error can happen if the "
  2164. "application has not successfully called CheckDeviceFormats on the "
  2165. "specified Format prior to calling CheckDepthStencilMatch. The application "
  2166. "is advised to call CheckDeviceFormats on this format first, because a "
  2167. "success return from CheckDepthStencilMatch does not guarantee "
  2168. "that the format is valid as a RenderTarget for all possible cases "
  2169. "i.e. D3DRTYPE_TEXTURE or D3DRTYPE_SURFACE or D3DRTYPE_CUBETEXTURE.");
  2170. return D3DERR_INVALIDCALL;
  2171. }
  2172. if (!bCanDoDS)
  2173. {
  2174. DPF_ERR("DepthStencil Format is not supported for this "
  2175. "Adapter/DevType/AdapterFormat. This error can happen if the "
  2176. "application has not successfully called CheckDeviceFormats on the "
  2177. "specified Format prior to calling CheckDepthStencilMatch. The application "
  2178. "is advised to call CheckDeviceFormats on this format first, because a "
  2179. "success return from CheckDepthStencilMatch does not guarantee "
  2180. "that the format is valid as a DepthStencil buffer for all possible cases "
  2181. "i.e. D3DRTYPE_TEXTURE or D3DRTYPE_SURFACE or D3DRTYPE_CUBETEXTURE.");
  2182. return D3DERR_INVALIDCALL;
  2183. }
  2184. if (bMatchNeededForDS)
  2185. {
  2186. // Check if the DS depth matches the RT depth
  2187. if (CPixel::ComputePixelStride(RTFormat) !=
  2188. CPixel::ComputePixelStride(DSFormat))
  2189. {
  2190. DPF(1, "Specified DepthStencil Format can not be used with RenderTarget Format");
  2191. return D3DERR_NOTAVAILABLE;
  2192. }
  2193. }
  2194. // Otherwise, we now know that the both the RT and DS formats
  2195. // are valid and that they match if they need to.
  2196. DXGASSERT(bCanDoRT && bCanDoDS);
  2197. return S_OK;
  2198. } // CheckDepthStencilMatch
  2199. #undef DPF_MODNAME
  2200. #define DPF_MODNAME "CEnum::FillInCaps"
  2201. void CEnum::FillInCaps (D3DCAPS8 *pCaps,
  2202. const D3D8_DRIVERCAPS *pDriverCaps,
  2203. D3DDEVTYPE Type,
  2204. UINT AdapterOrdinal) const
  2205. {
  2206. memset(pCaps, 0, sizeof(D3DCAPS8));
  2207. //
  2208. // do 3D caps first so we can copy the struct and clear the (few) non-3D fields
  2209. //
  2210. if (pDriverCaps->dwFlags & DDIFLAG_D3DCAPS8)
  2211. {
  2212. // set 3D fields from caps8 struct from driver
  2213. *pCaps = pDriverCaps->D3DCaps;
  2214. if (Type == D3DDEVTYPE_HAL)
  2215. {
  2216. pCaps->DevCaps |= D3DDEVCAPS_HWRASTERIZATION;
  2217. }
  2218. }
  2219. else
  2220. {
  2221. // ASSERT here
  2222. DDASSERT(FALSE);
  2223. }
  2224. //
  2225. // non-3D caps
  2226. //
  2227. pCaps->DeviceType = Type;
  2228. pCaps->AdapterOrdinal = AdapterOrdinal;
  2229. pCaps->Caps = pDriverCaps->D3DCaps.Caps &
  2230. (DDCAPS_READSCANLINE |
  2231. DDCAPS_NOHARDWARE);
  2232. pCaps->Caps2 = pDriverCaps->D3DCaps.Caps2 &
  2233. (DDCAPS2_NO2DDURING3DSCENE |
  2234. DDCAPS2_PRIMARYGAMMA |
  2235. DDCAPS2_CANRENDERWINDOWED |
  2236. DDCAPS2_STEREO |
  2237. DDCAPS2_DYNAMICTEXTURES |
  2238. #ifdef WINNT
  2239. (IsWhistler() ? DDCAPS2_CANMANAGERESOURCE : 0));
  2240. #else
  2241. DDCAPS2_CANMANAGERESOURCE);
  2242. #endif
  2243. // Special case: gamma calibrator is loaded by the enumerator...
  2244. if (m_bGammaCalibratorExists)
  2245. pCaps->Caps2 |= DDCAPS2_CANCALIBRATEGAMMA;
  2246. pCaps->Caps3 = pDriverCaps->D3DCaps.Caps3 & ~D3DCAPS3_RESERVED; //mask off the old stereo flags.
  2247. pCaps->PresentationIntervals = D3DPRESENT_INTERVAL_ONE;
  2248. if (pDriverCaps->D3DCaps.Caps2 & DDCAPS2_FLIPINTERVAL)
  2249. {
  2250. pCaps->PresentationIntervals |=
  2251. (D3DPRESENT_INTERVAL_TWO |
  2252. D3DPRESENT_INTERVAL_THREE |
  2253. D3DPRESENT_INTERVAL_FOUR);
  2254. }
  2255. if (pDriverCaps->D3DCaps.Caps2 & DDCAPS2_FLIPNOVSYNC)
  2256. {
  2257. pCaps->PresentationIntervals |=
  2258. (D3DPRESENT_INTERVAL_IMMEDIATE);
  2259. }
  2260. // Mask out the HW VB and IB caps
  2261. pCaps->DevCaps &= ~(D3DDEVCAPS_HWVERTEXBUFFER | D3DDEVCAPS_HWINDEXBUFFER);
  2262. // Clear internal caps
  2263. pCaps->PrimitiveMiscCaps &= ~D3DPMISCCAPS_FOGINFVF;
  2264. // Fix up the vertex fog cap.
  2265. if (pCaps->VertexProcessingCaps & D3DVTXPCAPS_RESERVED)
  2266. {
  2267. pCaps->RasterCaps |= D3DPRASTERCAPS_FOGVERTEX;
  2268. pCaps->VertexProcessingCaps &= ~D3DVTXPCAPS_RESERVED;
  2269. }
  2270. } // FillInCaps
  2271. #undef DPF_MODNAME
  2272. #define DPF_MODNAME "CEnum::GetDeviceCaps"
  2273. STDMETHODIMP CEnum::GetDeviceCaps(
  2274. UINT iAdapter,
  2275. D3DDEVTYPE Type,
  2276. D3DCAPS8 *pCaps)
  2277. {
  2278. API_ENTER(this);
  2279. BOOL bValidRTFormat;
  2280. D3DFORMAT Format;
  2281. D3D8_DRIVERCAPS* pAdapterCaps;
  2282. HRESULT hr;
  2283. DWORD i;
  2284. if (iAdapter >= m_cAdapter)
  2285. {
  2286. DPF_ERR("Invalid adapter specified. GetDeviceCaps fails.");
  2287. return D3DERR_INVALIDCALL;
  2288. }
  2289. if (!VALID_WRITEPTR(pCaps, sizeof(D3DCAPS8)))
  2290. {
  2291. DPF_ERR("Invalid pointer to D3DCAPS8 specified. GetDeviceCaps fails.");
  2292. return D3DERR_INVALIDCALL;
  2293. }
  2294. hr = GetAdapterCaps(iAdapter,
  2295. Type,
  2296. &pAdapterCaps);
  2297. if (FAILED(hr))
  2298. {
  2299. // No caps for this type of device
  2300. memset(pCaps, 0, sizeof(D3DCAPS8));
  2301. return hr;
  2302. }
  2303. // Fail this call if the driver dosn't support any accelerated modes
  2304. for (i = 0; i < pAdapterCaps->GDD8NumSupportedFormatOps; i++)
  2305. {
  2306. if (pAdapterCaps->pGDD8SupportedFormatOps[i].ddpfPixelFormat.dwOperations & D3DFORMAT_OP_3DACCELERATION)
  2307. {
  2308. break;
  2309. }
  2310. }
  2311. if (i == pAdapterCaps->GDD8NumSupportedFormatOps)
  2312. {
  2313. // No caps for this type of device
  2314. memset(pCaps, 0, sizeof(D3DCAPS8));
  2315. return D3DERR_NOTAVAILABLE;
  2316. }
  2317. FillInCaps (pCaps,
  2318. pAdapterCaps,
  2319. Type,
  2320. iAdapter);
  2321. if (pCaps->MaxPointSize == 0)
  2322. {
  2323. pCaps->MaxPointSize = 1.0f;
  2324. }
  2325. return D3D_OK;
  2326. } // GetDeviceCaps
  2327. #undef DPF_MODNAME
  2328. #define DPF_MODNAME "CEnum::LoadAndCallGammaCalibrator"
  2329. void CEnum::LoadAndCallGammaCalibrator(
  2330. D3DGAMMARAMP *pRamp,
  2331. UCHAR * pDeviceName)
  2332. {
  2333. API_ENTER_VOID(this);
  2334. if (!m_bAttemptedGammaCalibrator)
  2335. {
  2336. m_bAttemptedGammaCalibrator = TRUE;
  2337. m_hGammaCalibrator = LoadLibrary((char*) m_szGammaCalibrator);
  2338. if (m_hGammaCalibrator)
  2339. {
  2340. m_pGammaCalibratorProc = (LPDDGAMMACALIBRATORPROC)
  2341. GetProcAddress(m_hGammaCalibrator, "CalibrateGammaRamp");
  2342. if (m_pGammaCalibratorProc == NULL)
  2343. {
  2344. FreeLibrary((HMODULE) m_hGammaCalibrator);
  2345. m_hGammaCalibrator = NULL;
  2346. }
  2347. }
  2348. }
  2349. if (m_pGammaCalibratorProc)
  2350. {
  2351. m_pGammaCalibratorProc((LPDDGAMMARAMP) pRamp, pDeviceName);
  2352. }
  2353. } // LoadAndCallGammaCalibrator
  2354. #undef DPF_MODNAME
  2355. #define DPF_MODNAME "CEnum::RegisterSoftwareDevice"
  2356. STDMETHODIMP CEnum::RegisterSoftwareDevice(
  2357. void* pInitFunction)
  2358. {
  2359. HRESULT hr;
  2360. API_ENTER(this);
  2361. if (pInitFunction == NULL)
  2362. {
  2363. DPF_ERR("Invalid initialization function specified. RegisterSoftwareDevice fails.");
  2364. return D3DERR_INVALIDCALL;
  2365. }
  2366. if (m_pSwInitFunction != NULL)
  2367. {
  2368. DPF_ERR("A software device is already registered.");
  2369. return D3DERR_INVALIDCALL;
  2370. }
  2371. if (m_cAdapter == 0)
  2372. {
  2373. DPF_ERR("No display devices are available.");
  2374. return D3DERR_NOTAVAILABLE;
  2375. }
  2376. hr = AddSoftwareDevice(D3DDEVTYPE_SW, &m_SwCaps[0], &m_AdapterInfo[0], pInitFunction);
  2377. if (SUCCEEDED(hr))
  2378. {
  2379. m_pSwInitFunction = pInitFunction;
  2380. }
  2381. if (FAILED(hr))
  2382. {
  2383. DPF_ERR("RegisterSoftwareDevice fails");
  2384. }
  2385. return hr;
  2386. } // RegisterSoftwareDevice
  2387. #ifdef WINNT
  2388. #undef DPF_MODNAME
  2389. #define DPF_MODNAME "CEnum::FocusWindow"
  2390. HWND CEnum::ExclusiveOwnerWindow()
  2391. {
  2392. API_ENTER_RET(this, HWND);
  2393. for (UINT iAdapter = 0; iAdapter < m_cAdapter; iAdapter++)
  2394. {
  2395. CBaseDevice *pDevice = m_pFullScreenDevice[iAdapter];
  2396. if (pDevice)
  2397. {
  2398. return pDevice->FocusWindow();
  2399. }
  2400. }
  2401. return NULL;
  2402. } // FocusWindow
  2403. #undef DPF_MODNAME
  2404. #define DPF_MODNAME "CEnum::SetFullScreenDevice"
  2405. void CEnum::SetFullScreenDevice(UINT iAdapter,
  2406. CBaseDevice *pDevice)
  2407. {
  2408. API_ENTER_VOID(this);
  2409. if (m_pFullScreenDevice[iAdapter] != pDevice)
  2410. {
  2411. DDASSERT(NULL == m_pFullScreenDevice[iAdapter] || NULL == pDevice);
  2412. m_pFullScreenDevice[iAdapter] = pDevice;
  2413. if (NULL == pDevice && NULL == ExclusiveOwnerWindow() && m_bHasExclusive)
  2414. {
  2415. m_bHasExclusive = FALSE;
  2416. DXReleaseExclusiveModeMutex();
  2417. }
  2418. }
  2419. } // SetFullScreenDevice
  2420. #undef DPF_MODNAME
  2421. #define DPF_MODNAME "CEnum::CheckExclusiveMode"
  2422. BOOL CEnum::CheckExclusiveMode(
  2423. CBaseDevice* pDevice,
  2424. LPBOOL pbThisDeviceOwnsExclusive,
  2425. BOOL bKeepMutex)
  2426. {
  2427. DWORD dwWaitResult;
  2428. BOOL bExclusiveExists=FALSE;
  2429. WaitForSingleObject(hCheckExclusiveModeMutex, INFINITE);
  2430. dwWaitResult = WaitForSingleObject(hExclusiveModeMutex, 0);
  2431. if (dwWaitResult == WAIT_OBJECT_0)
  2432. {
  2433. /*
  2434. * OK, so this process now owns the exclusive mode object,
  2435. * Have we taken the Mutex already ?
  2436. */
  2437. if (m_bHasExclusive)
  2438. {
  2439. bExclusiveExists = TRUE;
  2440. bKeepMutex = FALSE;
  2441. }
  2442. else
  2443. {
  2444. bExclusiveExists = FALSE;
  2445. }
  2446. if (pbThisDeviceOwnsExclusive && pDevice)
  2447. {
  2448. if (bExclusiveExists &&
  2449. (pDevice == m_pFullScreenDevice[pDevice->AdapterIndex()]
  2450. || NULL == m_pFullScreenDevice[pDevice->AdapterIndex()]) &&
  2451. pDevice->FocusWindow() == ExclusiveOwnerWindow()
  2452. )
  2453. {
  2454. *pbThisDeviceOwnsExclusive = TRUE;
  2455. }
  2456. else
  2457. {
  2458. *pbThisDeviceOwnsExclusive = FALSE;
  2459. }
  2460. }
  2461. /*
  2462. * Undo the temporary ref we just took on the mutex to check its state, if we're not actually
  2463. * taking ownership. We are not taking ownership if we already have ownership. This means this routine
  2464. * doesn't allow more than one ref on the exclusive mode mutex.
  2465. */
  2466. if (!bKeepMutex)
  2467. {
  2468. ReleaseMutex(hExclusiveModeMutex);
  2469. }
  2470. else
  2471. {
  2472. m_bHasExclusive = TRUE;
  2473. }
  2474. }
  2475. else if (dwWaitResult == WAIT_TIMEOUT)
  2476. {
  2477. bExclusiveExists = TRUE;
  2478. if (pbThisDeviceOwnsExclusive)
  2479. *pbThisDeviceOwnsExclusive = FALSE;
  2480. }
  2481. else if (dwWaitResult == WAIT_ABANDONED)
  2482. {
  2483. /*
  2484. * Some other thread lost exclusive mode. We have now picked it up.
  2485. */
  2486. bExclusiveExists = FALSE;
  2487. if (pbThisDeviceOwnsExclusive)
  2488. *pbThisDeviceOwnsExclusive = FALSE;
  2489. /*
  2490. * Undo the temporary ref we just took on the mutex to check its state, if we're not actually
  2491. * taking ownership.
  2492. */
  2493. if (!bKeepMutex)
  2494. {
  2495. ReleaseMutex(hExclusiveModeMutex);
  2496. }
  2497. else
  2498. {
  2499. m_bHasExclusive = TRUE;
  2500. }
  2501. }
  2502. ReleaseMutex(hCheckExclusiveModeMutex);
  2503. return bExclusiveExists;
  2504. } // CheckExclusiveMode
  2505. #undef DPF_MODNAME
  2506. #define DPF_MODNAME "CEnum::DoneExclusiveMode"
  2507. /*
  2508. * DoneExclusiveMode
  2509. */
  2510. void
  2511. CEnum::DoneExclusiveMode()
  2512. {
  2513. UINT iAdapter;
  2514. for (iAdapter=0;iAdapter < m_cAdapter;iAdapter++)
  2515. {
  2516. CBaseDevice* pDevice = m_pFullScreenDevice[iAdapter];
  2517. if (pDevice)
  2518. {
  2519. pDevice->SwapChain()->DoneExclusiveMode(TRUE);
  2520. }
  2521. }
  2522. m_bHasExclusive = FALSE;
  2523. DXReleaseExclusiveModeMutex();
  2524. } /* DoneExclusiveMode */
  2525. #undef DPF_MODNAME
  2526. #define DPF_MODNAME "CEnum::StartExclusiveMode"
  2527. /*
  2528. * StartExclusiveMode
  2529. */
  2530. void
  2531. CEnum::StartExclusiveMode()
  2532. {
  2533. UINT iAdapter;
  2534. for (iAdapter=0;iAdapter<m_cAdapter;iAdapter++)
  2535. {
  2536. CBaseDevice* pDevice = m_pFullScreenDevice[iAdapter];
  2537. if (pDevice)
  2538. {
  2539. pDevice->SwapChain()->StartExclusiveMode(TRUE);
  2540. }
  2541. }
  2542. } /* StartExclusiveMode */
  2543. #endif // WINNT
  2544. // End of file : enum.cpp