// EnumD3D.cpp: implementation of the CEnumD3D class. // ////////////////////////////////////////////////////////////////////// #include "EnumD3D.h" #include #include "GMMemory.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// D3DAdapterInfo CEnumD3D::m_Adapters[10]; DWORD CEnumD3D::m_dwNumAdapters; DWORD CEnumD3D::m_dwAdapter; BOOL CEnumD3D::m_bWindowed; LPDIRECT3D8 CEnumD3D::m_pD3D; BOOL CEnumD3D::m_bUseDepthBuffer; long CEnumD3D::m_dwMinDepthBits; long CEnumD3D::m_dwMinStencilBits; long CEnumD3D::m_nAdapter; long CEnumD3D::m_nDevice; long CEnumD3D::m_nMode; TCHAR CEnumD3D::m_strSoundCard[64]; TCHAR CEnumD3D::m_strSoundCardDrv[64]; int SortModesCallback( const VOID* arg1, const VOID* arg2 ) { D3DDISPLAYMODE* p1 = (D3DDISPLAYMODE*)arg1; D3DDISPLAYMODE* p2 = (D3DDISPLAYMODE*)arg2; if( p1->Format > p2->Format ) return -1; if( p1->Format < p2->Format ) return +1; if( p1->Width < p2->Width ) return -1; if( p1->Width > p2->Width ) return +1; if( p1->Height < p2->Height ) return -1; if( p1->Height > p2->Height ) return +1; return 0; } VOID EnumSound(); BOOL CALLBACK DSoundEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext ); CEnumD3D::CEnumD3D() { m_bUseDepthBuffer=true; m_nAdapter=m_nDevice=m_nMode=0; } CEnumD3D::~CEnumD3D() { } HRESULT CEnumD3D::Enum() { m_pD3D=Direct3DCreate8(D3D_SDK_VERSION); const DWORD dwNumDeviceTypes = 2; const TCHAR* strDeviceDescs[] = { "HAL", "REF" }; const D3DDEVTYPE DeviceTypes[] = { D3DDEVTYPE_HAL, D3DDEVTYPE_REF }; BOOL bHALExists = FALSE; BOOL bHALIsWindowedCompatible = FALSE; BOOL bHALIsDesktopCompatible = FALSE; BOOL bHALIsSampleCompatible = FALSE; // Loop through all the adapters on the system (usually, there's just one // unless more than one graphics card is present). m_dwNumAdapters=0; for( UINT iAdapter = 0; iAdapter < m_pD3D->GetAdapterCount(); iAdapter++ ) { // Fill in adapter info D3DAdapterInfo* pAdapter = &m_Adapters[m_dwNumAdapters]; m_pD3D->GetAdapterIdentifier( iAdapter, 0, &pAdapter->d3dAdapterIdentifier ); m_pD3D->GetAdapterDisplayMode( iAdapter, &pAdapter->d3ddmDesktop ); pAdapter->dwNumDevices = 0; pAdapter->dwCurrentDevice = 0; // Enumerate all display modes on this adapter CD3DDISPLAYMODE modes[100]; D3DFORMAT formats[20]; DWORD dwNumFormats = 0; DWORD dwNumModes = 0; DWORD dwNumAdapterModes = m_pD3D->GetAdapterModeCount( iAdapter ); // Add the adapter's current desktop format to the list of formats formats[dwNumFormats++] = pAdapter->d3ddmDesktop.Format; DWORD dwRefreshCount = 0; ZeroMemory(&modes[0].RefreshRate, sizeof(modes[0].RefreshRate)); for( UINT iMode = 0; iMode < dwNumAdapterModes; iMode++ ) { // Get the display mode attributes D3DDISPLAYMODE DisplayMode; m_pD3D->EnumAdapterModes( iAdapter, iMode, &DisplayMode ); // Filter out low-resolution modes if( DisplayMode.Width < 640 || DisplayMode.Height < 400 ) continue; // Check if the mode already exists (to filter out refresh rates) DWORD m=0L; for( ; mdevices[pAdapter->dwNumDevices]; pDevice->DeviceType = DeviceTypes[iDevice]; m_pD3D->GetDeviceCaps( iAdapter, DeviceTypes[iDevice], &pDevice->d3dCaps ); pDevice->strDesc = strDeviceDescs[iDevice]; pDevice->dwNumModes = 0; pDevice->dwCurrentMode = 0; pDevice->bCanDoWindowed = FALSE; pDevice->bWindowed = FALSE; pDevice->MultiSampleType = D3DMULTISAMPLE_NONE; // Examine each format supported by the adapter to see if it will // work with this device and meets the needs of the application. BOOL bFormatConfirmed[20]; DWORD dwBehavior[20]; D3DFORMAT fmtDepthStencil[20]; for( DWORD f=0; fCheckDeviceType( iAdapter, pDevice->DeviceType, formats[f], formats[f], FALSE ) ) ) continue; if( pDevice->DeviceType == D3DDEVTYPE_HAL ) { // This system has a HAL device bHALExists = TRUE; if( pDevice->d3dCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED ) { // HAL can run in a window for some mode bHALIsWindowedCompatible = TRUE; if( f == 0 ) { // HAL can run in a window for the current desktop mode bHALIsDesktopCompatible = TRUE; } } } // Confirm the device/format for HW vertex processing if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT ) { if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_PUREDEVICE ) { /* dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE; */ dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING; if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f], formats[f] ) ) ) bFormatConfirmed[f] = FALSE; } if ( FALSE == bFormatConfirmed[f] ) { dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING; if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f], formats[f] ) ) ) bFormatConfirmed[f] = TRUE; } if ( FALSE == bFormatConfirmed[f] ) { dwBehavior[f] = D3DCREATE_MIXED_VERTEXPROCESSING; if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f], formats[f] ) ) ) bFormatConfirmed[f] = TRUE; } } // Confirm the device/format for SW vertex processing if( FALSE == bFormatConfirmed[f] ) { dwBehavior[f] = D3DCREATE_SOFTWARE_VERTEXPROCESSING; if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f], formats[f] ) ) ) bFormatConfirmed[f] = TRUE; } // Find a suitable depth/stencil buffer format for this device/format if( bFormatConfirmed[f]) { if( !FindDepthStencilFormat( iAdapter, pDevice->DeviceType, formats[f], &fmtDepthStencil[f] ) ) { bFormatConfirmed[f] = FALSE; } } } // Add all enumerated display modes with confirmed formats to the // device's list of valid modes DWORD m=0L; for( ; mmodes[pDevice->dwNumModes].Width = modes[m].Width; pDevice->modes[pDevice->dwNumModes].Height = modes[m].Height; pDevice->modes[pDevice->dwNumModes].Format = modes[m].Format; pDevice->modes[pDevice->dwNumModes].dwBehavior = dwBehavior[f]; pDevice->modes[pDevice->dwNumModes].DepthStencilFormat = fmtDepthStencil[f]; for( DWORD r = 0; r < 50; ++r ) { pDevice->modes[pDevice->dwNumModes].dwRefresh[r] = modes[m].RefreshRate[r]; } pDevice->dwNumModes++; if( pDevice->DeviceType == D3DDEVTYPE_HAL ) bHALIsSampleCompatible = TRUE; } } } } // Select any 640x480 mode for default (but prefer a 16-bit mode) for( m=0; mdwNumModes; m++ ) { if( pDevice->modes[m].Width==640 && pDevice->modes[m].Height==480 ) { pDevice->dwCurrentMode = m; if( pDevice->modes[m].Format == D3DFMT_R5G6B5 || pDevice->modes[m].Format == D3DFMT_X1R5G5B5 || pDevice->modes[m].Format == D3DFMT_A1R5G5B5 ) { break; } } } // Check if the device is compatible with the desktop display mode // (which was added initially as formats[0]) if( bFormatConfirmed[0] && (pDevice->d3dCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED) ) { pDevice->bCanDoWindowed = TRUE; pDevice->bWindowed = TRUE; } // If valid modes were found, keep this device if( pDevice->dwNumModes > 0 ) pAdapter->dwNumDevices++; } // If valid devices were found, keep this adapter if( pAdapter->dwNumDevices > 0 ) m_dwNumAdapters++; } // Return an error if no compatible devices were found if( 0L == m_dwNumAdapters ) return S_OK; // Pick a default device that can render into a window // (This code assumes that the HAL device comes before the REF // device in the device array). m_pD3D->Release(); EnumSound(); for( DWORD a=0; aCheckDeviceFormat( iAdapter, DeviceType, TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D16 ) ) ) { if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType, TargetFormat, TargetFormat, D3DFMT_D16 ) ) ) { *pDepthStencilFormat = D3DFMT_D16; return TRUE; } } } if( m_dwMinDepthBits <= 15 && m_dwMinStencilBits <= 1 ) { if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType, TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D15S1 ) ) ) { if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType, TargetFormat, TargetFormat, D3DFMT_D15S1 ) ) ) { *pDepthStencilFormat = D3DFMT_D15S1; return TRUE; } } } if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits == 0 ) { if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType, TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X8 ) ) ) { if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType, TargetFormat, TargetFormat, D3DFMT_D24X8 ) ) ) { *pDepthStencilFormat = D3DFMT_D24X8; return TRUE; } } } if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 8 ) { if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType, TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24S8 ) ) ) { if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType, TargetFormat, TargetFormat, D3DFMT_D24S8 ) ) ) { *pDepthStencilFormat = D3DFMT_D24S8; return TRUE; } } } if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 4 ) { if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType, TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X4S4 ) ) ) { if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType, TargetFormat, TargetFormat, D3DFMT_D24X4S4 ) ) ) { *pDepthStencilFormat = D3DFMT_D24X4S4; return TRUE; } } } if( m_dwMinDepthBits <= 32 && m_dwMinStencilBits == 0 ) { if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType, TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D32 ) ) ) { if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType, TargetFormat, TargetFormat, D3DFMT_D32 ) ) ) { *pDepthStencilFormat = D3DFMT_D32; return TRUE; } } } return FALSE; } HRESULT CEnumD3D::ConfirmDevice(D3DCAPS8 *, DWORD, D3DFORMAT) { return S_OK; } VOID EnumSound() { LPDIRECTSOUND8 pDS; if( FAILED(DirectSoundCreate8(NULL, &pDS, NULL)) ) { return; } if (FAILED(DirectSoundEnumerate((LPDSENUMCALLBACK)DSoundEnumProc, NULL))) { if( pDS ) { pDS->Release(); pDS = NULL; } return; } if( pDS ) { pDS->Release(); pDS = NULL; } } BOOL CALLBACK DSoundEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext ) { HWND hCombo = (HWND)lpContext; LPGUID lpTemp = NULL; if (lpGUID != NULL) // NULL only for "Primary Sound Driver". { strcpy( CEnumD3D::m_strSoundCard, lpszDesc ); strcpy( CEnumD3D::m_strSoundCardDrv, lpszDrvName ); } return(TRUE); }