#include "stdafx.h" #if 0 //----------------------------------------------------------------------------- // File: D3DEnum.cpp // // Desc: Functions to enumerate DDraw/D3D drivers, devices, and modes. // // Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved //----------------------------------------------------------------------------- #define STRICT #include #include #include #include "D3DEnum.h" #include "D3DUtil.h" // For DEBUG_MSG #include "D3DRes.h" // For dialog controls //----------------------------------------------------------------------------- // Global data for the enumerator functions //----------------------------------------------------------------------------- static HRESULT (*g_fnAppConfirmFn)(DDCAPS*, D3DDEVICEDESC7*) = NULL; static D3DEnum_DeviceInfo g_pDeviceList[20]; static DWORD g_dwNumDevicesEnumerated = 0L; static DWORD g_dwNumDevices = 0L; //----------------------------------------------------------------------------- // Name: SortModesCallback() // Desc: Callback function for sorting display modes. //----------------------------------------------------------------------------- int SortModesCallback(const VOID* arg1, const VOID* arg2) { DDSURFACEDESC2* p1 = (DDSURFACEDESC2*)arg1; DDSURFACEDESC2* p2 = (DDSURFACEDESC2*)arg2; if (p1->dwWidth < p2->dwWidth) return -1; if (p1->dwWidth > p2->dwWidth) return +1; if (p1->dwHeight < p2->dwHeight) return -1; if (p1->dwHeight > p2->dwHeight) return +1; if (p1->ddpfPixelFormat.dwRGBBitCount < p2->ddpfPixelFormat.dwRGBBitCount) return -1; if (p1->ddpfPixelFormat.dwRGBBitCount > p2->ddpfPixelFormat.dwRGBBitCount) return +1; return 0; } //----------------------------------------------------------------------------- // Name: ModeEnumCallback() // Desc: Callback function for enumerating display modes. //----------------------------------------------------------------------------- static HRESULT WINAPI ModeEnumCallback(DDSURFACEDESC2* pddsd, VOID* pParentInfo) { D3DEnum_DeviceInfo* pDevice = (D3DEnum_DeviceInfo*)pParentInfo; // Reallocate storage for the modes DDSURFACEDESC2* pddsdNewModes = new DDSURFACEDESC2[pDevice->dwNumModes+1]; memcpy(pddsdNewModes, pDevice->pddsdModes, pDevice->dwNumModes * sizeof(DDSURFACEDESC2)); delete pDevice->pddsdModes; pDevice->pddsdModes = pddsdNewModes; // Add the new mode pDevice->pddsdModes[pDevice->dwNumModes++] = (*pddsd); return DDENUMRET_OK; } //----------------------------------------------------------------------------- // Name: DeviceEnumCallback() // Desc: Callback function for enumerating devices //----------------------------------------------------------------------------- static HRESULT WINAPI DeviceEnumCallback(TCHAR* strDesc, TCHAR* strName, D3DDEVICEDESC7* pDesc, VOID* pParentInfo) { // Keep track of # of devices that were enumerated g_dwNumDevicesEnumerated++; D3DEnum_DeviceInfo* pDriverInfo = (D3DEnum_DeviceInfo*)pParentInfo; D3DEnum_DeviceInfo* pDeviceInfo = &g_pDeviceList[g_dwNumDevices]; ZeroMemory(pDeviceInfo, sizeof(D3DEnum_DeviceInfo)); // Select either the HAL or HEL device desc: pDeviceInfo->bHardware = pDesc->dwDevCaps & D3DDEVCAPS_HWRASTERIZATION; memcpy(&pDeviceInfo->ddDeviceDesc, pDesc, sizeof(D3DDEVICEDESC7)); // Set up device info for this device pDeviceInfo->bDesktopCompatible = pDriverInfo->bDesktopCompatible; pDeviceInfo->ddDriverCaps = pDriverInfo->ddDriverCaps; pDeviceInfo->ddHELCaps = pDriverInfo->ddHELCaps; pDeviceInfo->guidDevice = pDesc->deviceGUID; pDeviceInfo->pDeviceGUID = &pDeviceInfo->guidDevice; pDeviceInfo->pddsdModes = new DDSURFACEDESC2[pDriverInfo->dwNumModes]; // Copy the driver GUID and description for the device if (pDriverInfo->pDriverGUID) { pDeviceInfo->guidDriver = pDriverInfo->guidDriver; pDeviceInfo->pDriverGUID = &pDeviceInfo->guidDriver; lstrcpyn(pDeviceInfo->strDesc, pDriverInfo->strDesc, 39); } else { pDeviceInfo->pDriverGUID = NULL; lstrcpyn(pDeviceInfo->strDesc, strName, 39); } // Avoid duplicates: only enum HW devices for secondary DDraw drivers. if (NULL != pDeviceInfo->pDriverGUID && FALSE == pDeviceInfo->bHardware) return D3DENUMRET_OK; // Give the app a chance to accept or reject this device. if (g_fnAppConfirmFn) if (FAILED(g_fnAppConfirmFn(&pDeviceInfo->ddDriverCaps, &pDeviceInfo->ddDeviceDesc))) return D3DENUMRET_OK; // Build list of supported modes for the device for(DWORD i=0; idwNumModes; i++) { DDSURFACEDESC2 ddsdMode = pDriverInfo->pddsdModes[i]; DWORD dwRenderDepths = pDeviceInfo->ddDeviceDesc.dwDeviceRenderBitDepth; DWORD dwDepth = ddsdMode.ddpfPixelFormat.dwRGBBitCount; // Accept modes that are compatable with the device if (((dwDepth == 32) && (dwRenderDepths & DDBD_32)) || ((dwDepth == 24) && (dwRenderDepths & DDBD_24)) || ((dwDepth == 16) && (dwRenderDepths & DDBD_16))) { // Copy compatible modes to the list of device-supported modes pDeviceInfo->pddsdModes[pDeviceInfo->dwNumModes++] = ddsdMode; // Record whether the device has any stereo modes if (ddsdMode.ddsCaps.dwCaps2 & DDSCAPS2_STEREOSURFACELEFT) pDeviceInfo->bStereoCompatible = TRUE; } } // Bail if the device has no supported modes if (0 == pDeviceInfo->dwNumModes) return D3DENUMRET_OK; // Find a 640x480x16 mode for the default fullscreen mode for(i=0; idwNumModes; i++) { if ((pDeviceInfo->pddsdModes[i].dwWidth == 640) && (pDeviceInfo->pddsdModes[i].dwHeight == 480) && (pDeviceInfo->pddsdModes[i].ddpfPixelFormat.dwRGBBitCount == 16)) { pDeviceInfo->ddsdFullscreenMode = pDeviceInfo->pddsdModes[i]; pDeviceInfo->dwCurrentMode = i; } } // Select whether the device is initially windowed pDeviceInfo->bWindowed = pDeviceInfo->bDesktopCompatible; // Accept the device and return g_dwNumDevices++; return D3DENUMRET_OK; } //----------------------------------------------------------------------------- // Name: DriverEnumCallback() // Desc: Callback function for enumerating drivers. //----------------------------------------------------------------------------- static BOOL WINAPI DriverEnumCallback(GUID* pGUID, TCHAR* strDesc, TCHAR* strName, VOID*, HMONITOR) { D3DEnum_DeviceInfo d3dDeviceInfo; LPDIRECTDRAW7 pDD; LPDIRECT3D7 pD3D; HRESULT hr; // Use the GUID to create the DirectDraw object hr = DirectDrawCreateEx(pGUID, (VOID**)&pDD, IID_IDirectDraw7, NULL); if (FAILED(hr)) { DEBUG_MSG(_T("Can't create DDraw during enumeration!")); return D3DENUMRET_OK; } // Create a D3D object, to enumerate the d3d devices hr = pDD->QueryInterface(IID_IDirect3D7, (VOID**)&pD3D); if (FAILED(hr)) { pDD->Release(); DEBUG_MSG(_T("Can't query IDirect3D7 during enumeration!")); return D3DENUMRET_OK; } // Copy data to a device info structure ZeroMemory(&d3dDeviceInfo, sizeof(d3dDeviceInfo)); lstrcpyn(d3dDeviceInfo.strDesc, strDesc, 39); d3dDeviceInfo.ddDriverCaps.dwSize = sizeof(DDCAPS); d3dDeviceInfo.ddHELCaps.dwSize = sizeof(DDCAPS); pDD->GetCaps(&d3dDeviceInfo.ddDriverCaps, &d3dDeviceInfo.ddHELCaps); if (pGUID) { d3dDeviceInfo.guidDriver = (*pGUID); d3dDeviceInfo.pDriverGUID = &d3dDeviceInfo.guidDriver; } // Record whether the device can render into a desktop window if (d3dDeviceInfo.ddDriverCaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED) if (NULL == d3dDeviceInfo.pDriverGUID) d3dDeviceInfo.bDesktopCompatible = TRUE; // Enumerate the fullscreen display modes. pDD->EnumDisplayModes(0, NULL, &d3dDeviceInfo, ModeEnumCallback); // Sort list of display modes qsort(d3dDeviceInfo.pddsdModes, d3dDeviceInfo.dwNumModes, sizeof(DDSURFACEDESC2), SortModesCallback); // Now, enumerate all the 3D devices pD3D->EnumDevices(DeviceEnumCallback, &d3dDeviceInfo); // Clean up and return SAFE_DELETE(d3dDeviceInfo.pddsdModes); pD3D->Release(); pDD->Release(); return DDENUMRET_OK; } //----------------------------------------------------------------------------- // Name: D3DEnum_EnumerateDevices() // Desc: Enumerates all drivers, devices, and modes. The callback function is // called each device, to confirm that the device supports the feature // set required by the app. //----------------------------------------------------------------------------- HRESULT D3DEnum_EnumerateDevices(HRESULT (*AppConfirmFn)(DDCAPS*, D3DDEVICEDESC7*)) { // Store the device enumeration callback function g_fnAppConfirmFn = AppConfirmFn; // Enumerate drivers, devices, and modes DirectDrawEnumerateEx(DriverEnumCallback, NULL, DDENUM_ATTACHEDSECONDARYDEVICES | DDENUM_DETACHEDSECONDARYDEVICES | DDENUM_NONDISPLAYDEVICES); // Make sure devices were actually enumerated if (0 == g_dwNumDevicesEnumerated) { DEBUG_MSG(_T("No devices and/or modes were enumerated!")); return D3DENUMERR_ENUMERATIONFAILED; } if (0 == g_dwNumDevices) { DEBUG_MSG(_T("No enumerated devices were accepted!")); DEBUG_MSG(_T("Try enabling the D3D Reference Rasterizer.")); return D3DENUMERR_SUGGESTREFRAST; } return S_OK; } //----------------------------------------------------------------------------- // Name: D3DEnum_FreeResources() // Desc: Cleans up any memory allocated during device enumeration //----------------------------------------------------------------------------- VOID D3DEnum_FreeResources() { for(DWORD i=0; ibDesktopCompatible) bWindowed = FALSE; // Add a list of devices to the device combo box for(DWORD device = 0; device < dwNumDevices; device++) { D3DEnum_DeviceInfo* pDevice = &pDeviceList[device]; // Add device name to the combo box DWORD dwItem = ComboBox_AddString(hwndDevice, pDevice->strDesc); // Set the remaining UI states for the current device if (pDevice == pCurrentDevice) { // Set the combobox selection on the current device ComboBox_SetCurSel(hwndDevice, dwItem); // Enable/set the fullscreen checkbox, as appropriate if (hwndWindowed) { EnableWindow(hwndWindowed, pDevice->bDesktopCompatible); Button_SetCheck(hwndWindowed, bWindowed); } // Enable/set the stereo checkbox, as appropriate if (hwndStereo) { EnableWindow(hwndStereo, pDevice->bStereoCompatible && !bWindowed); Button_SetCheck(hwndStereo, bStereo); } // Enable/set the fullscreen modes combo, as appropriate EnableWindow(hwndMode, !bWindowed); EnableWindow(hwndFullscreenText, !bWindowed); // Build the list of fullscreen modes for(DWORD mode = 0; mode < pDevice->dwNumModes; mode++) { DDSURFACEDESC2* pddsdMode = &pDevice->pddsdModes[mode]; // Skip non-stereo modes, if the device is in stereo mode if (0 == (pddsdMode->ddsCaps.dwCaps2&DDSCAPS2_STEREOSURFACELEFT)) if (bStereo) continue; TCHAR strMode[80]; wsprintf(strMode, _T("%ld x %ld x %ld"), pddsdMode->dwWidth, pddsdMode->dwHeight, pddsdMode->ddpfPixelFormat.dwRGBBitCount); // Add mode desc to the combo box DWORD dwItem = ComboBox_AddString(hwndMode, strMode); // Set the item data to identify this mode ComboBox_SetItemData(hwndMode, dwItem, mode); // Set the combobox selection on the current mode if (mode == dwCurrentMode) ComboBox_SetCurSel(hwndMode, dwItem); // Since not all modes support stereo, select a default mode in // case none was chosen yet. if (bStereo && (CB_ERR == ComboBox_GetCurSel(hwndMode))) ComboBox_SetCurSel(hwndMode, dwItem); } } } } //----------------------------------------------------------------------------- // Name: ChangeDeviceProc() // Desc: Windows message handling function for the device select dialog //----------------------------------------------------------------------------- static BOOL CALLBACK ChangeDeviceProc(HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { static D3DEnum_DeviceInfo** ppDeviceArg; static D3DEnum_DeviceInfo* pCurrentDevice; static DWORD dwCurrentMode; static BOOL bCurrentWindowed; static BOOL bCurrentStereo; // Get access to the enumerated device list D3DEnum_DeviceInfo* pDeviceList; DWORD dwNumDevices; D3DEnum_GetDevices(&pDeviceList, &dwNumDevices); // Handle the initialization message if (WM_INITDIALOG == uiMsg) { // Get the app's current device, passed in as an lParam argument ppDeviceArg = (D3DEnum_DeviceInfo**)lParam; if (NULL == ppDeviceArg) return FALSE; // Setup temp storage pointers for dialog pCurrentDevice = (*ppDeviceArg); dwCurrentMode = pCurrentDevice->dwCurrentMode; bCurrentWindowed = pCurrentDevice->bWindowed; bCurrentStereo = pCurrentDevice->bStereo; UpdateDialogControls(hDlg, pCurrentDevice, dwCurrentMode, bCurrentWindowed, bCurrentStereo); return TRUE; } else if (WM_COMMAND == uiMsg) { HWND hwndDevice = GetDlgItem(hDlg, IDC_DEVICE_COMBO); HWND hwndMode = GetDlgItem(hDlg, IDC_MODE_COMBO); HWND hwndWindowed = GetDlgItem(hDlg, IDC_WINDOWED_CHECKBOX); HWND hwndStereo = GetDlgItem(hDlg, IDC_STEREO_CHECKBOX); // Get current UI state DWORD dwDevice = ComboBox_GetCurSel(hwndDevice); DWORD dwModeItem = ComboBox_GetCurSel(hwndMode); DWORD dwMode = ComboBox_GetItemData(hwndMode, dwModeItem); BOOL bWindowed = hwndWindowed ? Button_GetCheck(hwndWindowed) : 0; BOOL bStereo = hwndStereo ? Button_GetCheck(hwndStereo) : 0; D3DEnum_DeviceInfo* pDevice = &pDeviceList[dwDevice]; if (IDOK == LOWORD(wParam)) { // Handle the case when the user hits the OK button. Check if any // of the options were changed if (pDevice != pCurrentDevice || dwMode != dwCurrentMode || bWindowed != bCurrentWindowed || bStereo != bCurrentStereo) { // Return the newly selected device and its new properties (*ppDeviceArg) = pDevice; pDevice->bWindowed = bWindowed; pDevice->bStereo = bStereo; pDevice->dwCurrentMode = dwMode; pDevice->ddsdFullscreenMode = pDevice->pddsdModes[dwMode]; EndDialog(hDlg, IDOK); } else EndDialog(hDlg, IDCANCEL); return TRUE; } else if (IDCANCEL == LOWORD(wParam)) { // Handle the case when the user hits the Cancel button EndDialog(hDlg, IDCANCEL); return TRUE; } else if (CBN_SELENDOK == HIWORD(wParam)) { if (LOWORD(wParam) == IDC_DEVICE_COMBO) { // Handle the case when the user chooses the device combo dwMode = pDeviceList[dwDevice].dwCurrentMode; bWindowed = pDeviceList[dwDevice].bWindowed; bStereo = pDeviceList[dwDevice].bStereo; } } // Keep the UI current UpdateDialogControls(hDlg, &pDeviceList[dwDevice], dwMode, bWindowed, bStereo); return TRUE; } return FALSE; } //----------------------------------------------------------------------------- // Name: D3DEnum_UserChangeDevice() // Desc: Pops up a dialog which allows the user to select a new device. //----------------------------------------------------------------------------- HRESULT D3DEnum_UserChangeDevice(D3DEnum_DeviceInfo** ppDevice) { if (IDOK == DialogBoxParam((HINSTANCE)GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_CHANGEDEVICE), GetForegroundWindow(), ChangeDeviceProc, (LPARAM)ppDevice)) return S_OK; return E_FAIL; } //----------------------------------------------------------------------------- // Name: D3DEnum_SelectDefaultDevice() // Desc: Pick a default device, preferably hardware and desktop compatible. //----------------------------------------------------------------------------- HRESULT D3DEnum_SelectDefaultDevice(D3DEnum_DeviceInfo** ppDevice, DWORD dwFlags) { // Check arguments if (NULL == ppDevice) return E_INVALIDARG; // Get access to the enumerated device list D3DEnum_DeviceInfo* pDeviceList; DWORD dwNumDevices; D3DEnum_GetDevices(&pDeviceList, &dwNumDevices); // Look for windowable software, hardware, and hardware TnL devices D3DEnum_DeviceInfo* pRefRastDevice = NULL; D3DEnum_DeviceInfo* pSoftwareDevice = NULL; D3DEnum_DeviceInfo* pHardwareDevice = NULL; D3DEnum_DeviceInfo* pHardwareTnLDevice = NULL; for(DWORD i=0; ibWindowed = TRUE; return S_OK; } #endif