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.

609 lines
21 KiB

  1. #include "stdafx.h"
  2. #if 0
  3. //-----------------------------------------------------------------------------
  4. // File: D3DEnum.cpp
  5. //
  6. // Desc: Functions to enumerate DDraw/D3D drivers, devices, and modes.
  7. //
  8. // Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved
  9. //-----------------------------------------------------------------------------
  10. #define STRICT
  11. #include <windowsx.h>
  12. #include <stdio.h>
  13. #include <tchar.h>
  14. #include "D3DEnum.h"
  15. #include "D3DUtil.h" // For DEBUG_MSG
  16. #include "D3DRes.h" // For dialog controls
  17. //-----------------------------------------------------------------------------
  18. // Global data for the enumerator functions
  19. //-----------------------------------------------------------------------------
  20. static HRESULT (*g_fnAppConfirmFn)(DDCAPS*, D3DDEVICEDESC7*) = NULL;
  21. static D3DEnum_DeviceInfo g_pDeviceList[20];
  22. static DWORD g_dwNumDevicesEnumerated = 0L;
  23. static DWORD g_dwNumDevices = 0L;
  24. //-----------------------------------------------------------------------------
  25. // Name: SortModesCallback()
  26. // Desc: Callback function for sorting display modes.
  27. //-----------------------------------------------------------------------------
  28. int SortModesCallback(const VOID* arg1, const VOID* arg2)
  29. {
  30. DDSURFACEDESC2* p1 = (DDSURFACEDESC2*)arg1;
  31. DDSURFACEDESC2* p2 = (DDSURFACEDESC2*)arg2;
  32. if (p1->dwWidth < p2->dwWidth)
  33. return -1;
  34. if (p1->dwWidth > p2->dwWidth)
  35. return +1;
  36. if (p1->dwHeight < p2->dwHeight)
  37. return -1;
  38. if (p1->dwHeight > p2->dwHeight)
  39. return +1;
  40. if (p1->ddpfPixelFormat.dwRGBBitCount < p2->ddpfPixelFormat.dwRGBBitCount)
  41. return -1;
  42. if (p1->ddpfPixelFormat.dwRGBBitCount > p2->ddpfPixelFormat.dwRGBBitCount)
  43. return +1;
  44. return 0;
  45. }
  46. //-----------------------------------------------------------------------------
  47. // Name: ModeEnumCallback()
  48. // Desc: Callback function for enumerating display modes.
  49. //-----------------------------------------------------------------------------
  50. static HRESULT WINAPI ModeEnumCallback(DDSURFACEDESC2* pddsd,
  51. VOID* pParentInfo)
  52. {
  53. D3DEnum_DeviceInfo* pDevice = (D3DEnum_DeviceInfo*)pParentInfo;
  54. // Reallocate storage for the modes
  55. DDSURFACEDESC2* pddsdNewModes = new DDSURFACEDESC2[pDevice->dwNumModes+1];
  56. memcpy(pddsdNewModes, pDevice->pddsdModes,
  57. pDevice->dwNumModes * sizeof(DDSURFACEDESC2));
  58. delete pDevice->pddsdModes;
  59. pDevice->pddsdModes = pddsdNewModes;
  60. // Add the new mode
  61. pDevice->pddsdModes[pDevice->dwNumModes++] = (*pddsd);
  62. return DDENUMRET_OK;
  63. }
  64. //-----------------------------------------------------------------------------
  65. // Name: DeviceEnumCallback()
  66. // Desc: Callback function for enumerating devices
  67. //-----------------------------------------------------------------------------
  68. static HRESULT WINAPI DeviceEnumCallback(TCHAR* strDesc, TCHAR* strName,
  69. D3DDEVICEDESC7* pDesc,
  70. VOID* pParentInfo)
  71. {
  72. // Keep track of # of devices that were enumerated
  73. g_dwNumDevicesEnumerated++;
  74. D3DEnum_DeviceInfo* pDriverInfo = (D3DEnum_DeviceInfo*)pParentInfo;
  75. D3DEnum_DeviceInfo* pDeviceInfo = &g_pDeviceList[g_dwNumDevices];
  76. ZeroMemory(pDeviceInfo, sizeof(D3DEnum_DeviceInfo));
  77. // Select either the HAL or HEL device desc:
  78. pDeviceInfo->bHardware = pDesc->dwDevCaps & D3DDEVCAPS_HWRASTERIZATION;
  79. memcpy(&pDeviceInfo->ddDeviceDesc, pDesc, sizeof(D3DDEVICEDESC7));
  80. // Set up device info for this device
  81. pDeviceInfo->bDesktopCompatible = pDriverInfo->bDesktopCompatible;
  82. pDeviceInfo->ddDriverCaps = pDriverInfo->ddDriverCaps;
  83. pDeviceInfo->ddHELCaps = pDriverInfo->ddHELCaps;
  84. pDeviceInfo->guidDevice = pDesc->deviceGUID;
  85. pDeviceInfo->pDeviceGUID = &pDeviceInfo->guidDevice;
  86. pDeviceInfo->pddsdModes = new DDSURFACEDESC2[pDriverInfo->dwNumModes];
  87. // Copy the driver GUID and description for the device
  88. if (pDriverInfo->pDriverGUID)
  89. {
  90. pDeviceInfo->guidDriver = pDriverInfo->guidDriver;
  91. pDeviceInfo->pDriverGUID = &pDeviceInfo->guidDriver;
  92. lstrcpyn(pDeviceInfo->strDesc, pDriverInfo->strDesc, 39);
  93. }
  94. else
  95. {
  96. pDeviceInfo->pDriverGUID = NULL;
  97. lstrcpyn(pDeviceInfo->strDesc, strName, 39);
  98. }
  99. // Avoid duplicates: only enum HW devices for secondary DDraw drivers.
  100. if (NULL != pDeviceInfo->pDriverGUID && FALSE == pDeviceInfo->bHardware)
  101. return D3DENUMRET_OK;
  102. // Give the app a chance to accept or reject this device.
  103. if (g_fnAppConfirmFn)
  104. if (FAILED(g_fnAppConfirmFn(&pDeviceInfo->ddDriverCaps,
  105. &pDeviceInfo->ddDeviceDesc)))
  106. return D3DENUMRET_OK;
  107. // Build list of supported modes for the device
  108. for(DWORD i=0; i<pDriverInfo->dwNumModes; i++)
  109. {
  110. DDSURFACEDESC2 ddsdMode = pDriverInfo->pddsdModes[i];
  111. DWORD dwRenderDepths = pDeviceInfo->ddDeviceDesc.dwDeviceRenderBitDepth;
  112. DWORD dwDepth = ddsdMode.ddpfPixelFormat.dwRGBBitCount;
  113. // Accept modes that are compatable with the device
  114. if (((dwDepth == 32) && (dwRenderDepths & DDBD_32)) ||
  115. ((dwDepth == 24) && (dwRenderDepths & DDBD_24)) ||
  116. ((dwDepth == 16) && (dwRenderDepths & DDBD_16)))
  117. {
  118. // Copy compatible modes to the list of device-supported modes
  119. pDeviceInfo->pddsdModes[pDeviceInfo->dwNumModes++] = ddsdMode;
  120. // Record whether the device has any stereo modes
  121. if (ddsdMode.ddsCaps.dwCaps2 & DDSCAPS2_STEREOSURFACELEFT)
  122. pDeviceInfo->bStereoCompatible = TRUE;
  123. }
  124. }
  125. // Bail if the device has no supported modes
  126. if (0 == pDeviceInfo->dwNumModes)
  127. return D3DENUMRET_OK;
  128. // Find a 640x480x16 mode for the default fullscreen mode
  129. for(i=0; i<pDeviceInfo->dwNumModes; i++)
  130. {
  131. if ((pDeviceInfo->pddsdModes[i].dwWidth == 640) &&
  132. (pDeviceInfo->pddsdModes[i].dwHeight == 480) &&
  133. (pDeviceInfo->pddsdModes[i].ddpfPixelFormat.dwRGBBitCount == 16))
  134. {
  135. pDeviceInfo->ddsdFullscreenMode = pDeviceInfo->pddsdModes[i];
  136. pDeviceInfo->dwCurrentMode = i;
  137. }
  138. }
  139. // Select whether the device is initially windowed
  140. pDeviceInfo->bWindowed = pDeviceInfo->bDesktopCompatible;
  141. // Accept the device and return
  142. g_dwNumDevices++;
  143. return D3DENUMRET_OK;
  144. }
  145. //-----------------------------------------------------------------------------
  146. // Name: DriverEnumCallback()
  147. // Desc: Callback function for enumerating drivers.
  148. //-----------------------------------------------------------------------------
  149. static BOOL WINAPI DriverEnumCallback(GUID* pGUID, TCHAR* strDesc,
  150. TCHAR* strName, VOID*, HMONITOR)
  151. {
  152. D3DEnum_DeviceInfo d3dDeviceInfo;
  153. LPDIRECTDRAW7 pDD;
  154. LPDIRECT3D7 pD3D;
  155. HRESULT hr;
  156. // Use the GUID to create the DirectDraw object
  157. hr = DirectDrawCreateEx(pGUID, (VOID**)&pDD, IID_IDirectDraw7, NULL);
  158. if (FAILED(hr))
  159. {
  160. DEBUG_MSG(_T("Can't create DDraw during enumeration!"));
  161. return D3DENUMRET_OK;
  162. }
  163. // Create a D3D object, to enumerate the d3d devices
  164. hr = pDD->QueryInterface(IID_IDirect3D7, (VOID**)&pD3D);
  165. if (FAILED(hr))
  166. {
  167. pDD->Release();
  168. DEBUG_MSG(_T("Can't query IDirect3D7 during enumeration!"));
  169. return D3DENUMRET_OK;
  170. }
  171. // Copy data to a device info structure
  172. ZeroMemory(&d3dDeviceInfo, sizeof(d3dDeviceInfo));
  173. lstrcpyn(d3dDeviceInfo.strDesc, strDesc, 39);
  174. d3dDeviceInfo.ddDriverCaps.dwSize = sizeof(DDCAPS);
  175. d3dDeviceInfo.ddHELCaps.dwSize = sizeof(DDCAPS);
  176. pDD->GetCaps(&d3dDeviceInfo.ddDriverCaps, &d3dDeviceInfo.ddHELCaps);
  177. if (pGUID)
  178. {
  179. d3dDeviceInfo.guidDriver = (*pGUID);
  180. d3dDeviceInfo.pDriverGUID = &d3dDeviceInfo.guidDriver;
  181. }
  182. // Record whether the device can render into a desktop window
  183. if (d3dDeviceInfo.ddDriverCaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED)
  184. if (NULL == d3dDeviceInfo.pDriverGUID)
  185. d3dDeviceInfo.bDesktopCompatible = TRUE;
  186. // Enumerate the fullscreen display modes.
  187. pDD->EnumDisplayModes(0, NULL, &d3dDeviceInfo, ModeEnumCallback);
  188. // Sort list of display modes
  189. qsort(d3dDeviceInfo.pddsdModes, d3dDeviceInfo.dwNumModes,
  190. sizeof(DDSURFACEDESC2), SortModesCallback);
  191. // Now, enumerate all the 3D devices
  192. pD3D->EnumDevices(DeviceEnumCallback, &d3dDeviceInfo);
  193. // Clean up and return
  194. SAFE_DELETE(d3dDeviceInfo.pddsdModes);
  195. pD3D->Release();
  196. pDD->Release();
  197. return DDENUMRET_OK;
  198. }
  199. //-----------------------------------------------------------------------------
  200. // Name: D3DEnum_EnumerateDevices()
  201. // Desc: Enumerates all drivers, devices, and modes. The callback function is
  202. // called each device, to confirm that the device supports the feature
  203. // set required by the app.
  204. //-----------------------------------------------------------------------------
  205. HRESULT D3DEnum_EnumerateDevices(HRESULT (*AppConfirmFn)(DDCAPS*, D3DDEVICEDESC7*))
  206. {
  207. // Store the device enumeration callback function
  208. g_fnAppConfirmFn = AppConfirmFn;
  209. // Enumerate drivers, devices, and modes
  210. DirectDrawEnumerateEx(DriverEnumCallback, NULL,
  211. DDENUM_ATTACHEDSECONDARYDEVICES |
  212. DDENUM_DETACHEDSECONDARYDEVICES |
  213. DDENUM_NONDISPLAYDEVICES);
  214. // Make sure devices were actually enumerated
  215. if (0 == g_dwNumDevicesEnumerated)
  216. {
  217. DEBUG_MSG(_T("No devices and/or modes were enumerated!"));
  218. return D3DENUMERR_ENUMERATIONFAILED;
  219. }
  220. if (0 == g_dwNumDevices)
  221. {
  222. DEBUG_MSG(_T("No enumerated devices were accepted!"));
  223. DEBUG_MSG(_T("Try enabling the D3D Reference Rasterizer."));
  224. return D3DENUMERR_SUGGESTREFRAST;
  225. }
  226. return S_OK;
  227. }
  228. //-----------------------------------------------------------------------------
  229. // Name: D3DEnum_FreeResources()
  230. // Desc: Cleans up any memory allocated during device enumeration
  231. //-----------------------------------------------------------------------------
  232. VOID D3DEnum_FreeResources()
  233. {
  234. for(DWORD i=0; i<g_dwNumDevices; i++)
  235. {
  236. SAFE_DELETE(g_pDeviceList[i].pddsdModes);
  237. }
  238. }
  239. //-----------------------------------------------------------------------------
  240. // Name: D3DEnum_GetDevices()
  241. // Desc: Returns a ptr to the array of D3DEnum_DeviceInfo structures.
  242. //-----------------------------------------------------------------------------
  243. VOID D3DEnum_GetDevices(D3DEnum_DeviceInfo** ppDevices, DWORD* pdwCount)
  244. {
  245. if (ppDevices)
  246. (*ppDevices) = g_pDeviceList;
  247. if (pdwCount)
  248. (*pdwCount) = g_dwNumDevices;
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Name: UpdateDialogControls()
  252. // Desc: Builds the list of devices and modes for the combo boxes in the device
  253. // select dialog box.
  254. //-----------------------------------------------------------------------------
  255. static VOID UpdateDialogControls(HWND hDlg, D3DEnum_DeviceInfo* pCurrentDevice,
  256. DWORD dwCurrentMode, BOOL bWindowed,
  257. BOOL bStereo)
  258. {
  259. // Get access to the enumerated device list
  260. D3DEnum_DeviceInfo* pDeviceList;
  261. DWORD dwNumDevices;
  262. D3DEnum_GetDevices(&pDeviceList, &dwNumDevices);
  263. // Access to UI controls
  264. HWND hwndDevice = GetDlgItem(hDlg, IDC_DEVICE_COMBO);
  265. HWND hwndMode = GetDlgItem(hDlg, IDC_MODE_COMBO);
  266. HWND hwndWindowed = GetDlgItem(hDlg, IDC_WINDOWED_CHECKBOX);
  267. HWND hwndStereo = GetDlgItem(hDlg, IDC_STEREO_CHECKBOX);
  268. HWND hwndFullscreenText = GetDlgItem(hDlg, IDC_FULLSCREEN_TEXT);
  269. // Reset the content in each of the combo boxes
  270. ComboBox_ResetContent(hwndDevice);
  271. ComboBox_ResetContent(hwndMode);
  272. // Don't let non-GDI devices be windowed
  273. if (FALSE == pCurrentDevice->bDesktopCompatible)
  274. bWindowed = FALSE;
  275. // Add a list of devices to the device combo box
  276. for(DWORD device = 0; device < dwNumDevices; device++)
  277. {
  278. D3DEnum_DeviceInfo* pDevice = &pDeviceList[device];
  279. // Add device name to the combo box
  280. DWORD dwItem = ComboBox_AddString(hwndDevice, pDevice->strDesc);
  281. // Set the remaining UI states for the current device
  282. if (pDevice == pCurrentDevice)
  283. {
  284. // Set the combobox selection on the current device
  285. ComboBox_SetCurSel(hwndDevice, dwItem);
  286. // Enable/set the fullscreen checkbox, as appropriate
  287. if (hwndWindowed)
  288. {
  289. EnableWindow(hwndWindowed, pDevice->bDesktopCompatible);
  290. Button_SetCheck(hwndWindowed, bWindowed);
  291. }
  292. // Enable/set the stereo checkbox, as appropriate
  293. if (hwndStereo)
  294. {
  295. EnableWindow(hwndStereo, pDevice->bStereoCompatible && !bWindowed);
  296. Button_SetCheck(hwndStereo, bStereo);
  297. }
  298. // Enable/set the fullscreen modes combo, as appropriate
  299. EnableWindow(hwndMode, !bWindowed);
  300. EnableWindow(hwndFullscreenText, !bWindowed);
  301. // Build the list of fullscreen modes
  302. for(DWORD mode = 0; mode < pDevice->dwNumModes; mode++)
  303. {
  304. DDSURFACEDESC2* pddsdMode = &pDevice->pddsdModes[mode];
  305. // Skip non-stereo modes, if the device is in stereo mode
  306. if (0 == (pddsdMode->ddsCaps.dwCaps2&DDSCAPS2_STEREOSURFACELEFT))
  307. if (bStereo)
  308. continue;
  309. TCHAR strMode[80];
  310. wsprintf(strMode, _T("%ld x %ld x %ld"),
  311. pddsdMode->dwWidth, pddsdMode->dwHeight,
  312. pddsdMode->ddpfPixelFormat.dwRGBBitCount);
  313. // Add mode desc to the combo box
  314. DWORD dwItem = ComboBox_AddString(hwndMode, strMode);
  315. // Set the item data to identify this mode
  316. ComboBox_SetItemData(hwndMode, dwItem, mode);
  317. // Set the combobox selection on the current mode
  318. if (mode == dwCurrentMode)
  319. ComboBox_SetCurSel(hwndMode, dwItem);
  320. // Since not all modes support stereo, select a default mode in
  321. // case none was chosen yet.
  322. if (bStereo && (CB_ERR == ComboBox_GetCurSel(hwndMode)))
  323. ComboBox_SetCurSel(hwndMode, dwItem);
  324. }
  325. }
  326. }
  327. }
  328. //-----------------------------------------------------------------------------
  329. // Name: ChangeDeviceProc()
  330. // Desc: Windows message handling function for the device select dialog
  331. //-----------------------------------------------------------------------------
  332. static BOOL CALLBACK ChangeDeviceProc(HWND hDlg, UINT uiMsg, WPARAM wParam,
  333. LPARAM lParam)
  334. {
  335. static D3DEnum_DeviceInfo** ppDeviceArg;
  336. static D3DEnum_DeviceInfo* pCurrentDevice;
  337. static DWORD dwCurrentMode;
  338. static BOOL bCurrentWindowed;
  339. static BOOL bCurrentStereo;
  340. // Get access to the enumerated device list
  341. D3DEnum_DeviceInfo* pDeviceList;
  342. DWORD dwNumDevices;
  343. D3DEnum_GetDevices(&pDeviceList, &dwNumDevices);
  344. // Handle the initialization message
  345. if (WM_INITDIALOG == uiMsg)
  346. {
  347. // Get the app's current device, passed in as an lParam argument
  348. ppDeviceArg = (D3DEnum_DeviceInfo**)lParam;
  349. if (NULL == ppDeviceArg)
  350. return FALSE;
  351. // Setup temp storage pointers for dialog
  352. pCurrentDevice = (*ppDeviceArg);
  353. dwCurrentMode = pCurrentDevice->dwCurrentMode;
  354. bCurrentWindowed = pCurrentDevice->bWindowed;
  355. bCurrentStereo = pCurrentDevice->bStereo;
  356. UpdateDialogControls(hDlg, pCurrentDevice, dwCurrentMode,
  357. bCurrentWindowed, bCurrentStereo);
  358. return TRUE;
  359. }
  360. else if (WM_COMMAND == uiMsg)
  361. {
  362. HWND hwndDevice = GetDlgItem(hDlg, IDC_DEVICE_COMBO);
  363. HWND hwndMode = GetDlgItem(hDlg, IDC_MODE_COMBO);
  364. HWND hwndWindowed = GetDlgItem(hDlg, IDC_WINDOWED_CHECKBOX);
  365. HWND hwndStereo = GetDlgItem(hDlg, IDC_STEREO_CHECKBOX);
  366. // Get current UI state
  367. DWORD dwDevice = ComboBox_GetCurSel(hwndDevice);
  368. DWORD dwModeItem = ComboBox_GetCurSel(hwndMode);
  369. DWORD dwMode = ComboBox_GetItemData(hwndMode, dwModeItem);
  370. BOOL bWindowed = hwndWindowed ? Button_GetCheck(hwndWindowed) : 0;
  371. BOOL bStereo = hwndStereo ? Button_GetCheck(hwndStereo) : 0;
  372. D3DEnum_DeviceInfo* pDevice = &pDeviceList[dwDevice];
  373. if (IDOK == LOWORD(wParam))
  374. {
  375. // Handle the case when the user hits the OK button. Check if any
  376. // of the options were changed
  377. if (pDevice != pCurrentDevice || dwMode != dwCurrentMode ||
  378. bWindowed != bCurrentWindowed || bStereo != bCurrentStereo)
  379. {
  380. // Return the newly selected device and its new properties
  381. (*ppDeviceArg) = pDevice;
  382. pDevice->bWindowed = bWindowed;
  383. pDevice->bStereo = bStereo;
  384. pDevice->dwCurrentMode = dwMode;
  385. pDevice->ddsdFullscreenMode = pDevice->pddsdModes[dwMode];
  386. EndDialog(hDlg, IDOK);
  387. }
  388. else
  389. EndDialog(hDlg, IDCANCEL);
  390. return TRUE;
  391. }
  392. else if (IDCANCEL == LOWORD(wParam))
  393. {
  394. // Handle the case when the user hits the Cancel button
  395. EndDialog(hDlg, IDCANCEL);
  396. return TRUE;
  397. }
  398. else if (CBN_SELENDOK == HIWORD(wParam))
  399. {
  400. if (LOWORD(wParam) == IDC_DEVICE_COMBO)
  401. {
  402. // Handle the case when the user chooses the device combo
  403. dwMode = pDeviceList[dwDevice].dwCurrentMode;
  404. bWindowed = pDeviceList[dwDevice].bWindowed;
  405. bStereo = pDeviceList[dwDevice].bStereo;
  406. }
  407. }
  408. // Keep the UI current
  409. UpdateDialogControls(hDlg, &pDeviceList[dwDevice], dwMode, bWindowed, bStereo);
  410. return TRUE;
  411. }
  412. return FALSE;
  413. }
  414. //-----------------------------------------------------------------------------
  415. // Name: D3DEnum_UserChangeDevice()
  416. // Desc: Pops up a dialog which allows the user to select a new device.
  417. //-----------------------------------------------------------------------------
  418. HRESULT D3DEnum_UserChangeDevice(D3DEnum_DeviceInfo** ppDevice)
  419. {
  420. if (IDOK == DialogBoxParam((HINSTANCE)GetModuleHandle(NULL),
  421. MAKEINTRESOURCE(IDD_CHANGEDEVICE),
  422. GetForegroundWindow(),
  423. ChangeDeviceProc, (LPARAM)ppDevice))
  424. return S_OK;
  425. return E_FAIL;
  426. }
  427. //-----------------------------------------------------------------------------
  428. // Name: D3DEnum_SelectDefaultDevice()
  429. // Desc: Pick a default device, preferably hardware and desktop compatible.
  430. //-----------------------------------------------------------------------------
  431. HRESULT D3DEnum_SelectDefaultDevice(D3DEnum_DeviceInfo** ppDevice,
  432. DWORD dwFlags)
  433. {
  434. // Check arguments
  435. if (NULL == ppDevice)
  436. return E_INVALIDARG;
  437. // Get access to the enumerated device list
  438. D3DEnum_DeviceInfo* pDeviceList;
  439. DWORD dwNumDevices;
  440. D3DEnum_GetDevices(&pDeviceList, &dwNumDevices);
  441. // Look for windowable software, hardware, and hardware TnL devices
  442. D3DEnum_DeviceInfo* pRefRastDevice = NULL;
  443. D3DEnum_DeviceInfo* pSoftwareDevice = NULL;
  444. D3DEnum_DeviceInfo* pHardwareDevice = NULL;
  445. D3DEnum_DeviceInfo* pHardwareTnLDevice = NULL;
  446. for(DWORD i=0; i<dwNumDevices; i++)
  447. {
  448. if (pDeviceList[i].bDesktopCompatible)
  449. {
  450. if (pDeviceList[i].bHardware)
  451. {
  452. if ((*pDeviceList[i].pDeviceGUID) == IID_IDirect3DTnLHalDevice)
  453. pHardwareTnLDevice = &pDeviceList[i];
  454. else
  455. pHardwareDevice = &pDeviceList[i];
  456. }
  457. else
  458. {
  459. if ((*pDeviceList[i].pDeviceGUID) == IID_IDirect3DRefDevice)
  460. pRefRastDevice = &pDeviceList[i];
  461. else
  462. pSoftwareDevice = &pDeviceList[i];
  463. }
  464. }
  465. }
  466. // Prefer a hardware TnL device first, then a non-TnL hardware device, and
  467. // finally, a software device.
  468. if (0 == (dwFlags & D3DENUM_SOFTWAREONLY) && pHardwareTnLDevice)
  469. (*ppDevice) = pHardwareTnLDevice;
  470. else if (0 == (dwFlags & D3DENUM_SOFTWAREONLY) && pHardwareDevice)
  471. (*ppDevice) = pHardwareDevice;
  472. else if (pSoftwareDevice)
  473. (*ppDevice) = pSoftwareDevice;
  474. else if (pRefRastDevice)
  475. (*ppDevice) = pRefRastDevice;
  476. else
  477. return D3DENUMERR_NOCOMPATIBLEDEVICES;
  478. // Set the windowed state of the newly selected device
  479. (*ppDevice)->bWindowed = TRUE;
  480. return S_OK;
  481. }
  482. #endif