/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ #include "plDXEnumerate.h" #include #include "hsGDDrawDllLoad.h" #include "hsG3DDeviceSelector.h" #include "hsUtils.h" //// Local Typedefs /////////////////////////////////////////////////////////// typedef LPDIRECT3D9 (WINAPI * Direct3DCreateProc)( UINT sdkVersion ); const UInt8 hsGDirect3DTnLEnumerate::kNumDisplayFormats = 6; const D3DFORMAT hsGDirect3DTnLEnumerate::kDisplayFormats[] = { D3DFMT_A1R5G5B5, D3DFMT_A2B10G10R10, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5, D3DFMT_X8R8G8B8, }; HRESULT hsGDirect3DTnLEnumerate::SelectFromDevMode(const hsG3DDeviceRecord* devRec, const hsG3DDeviceMode* devMode) { int i; for( i = 0; i < GetNumDrivers(); i++ ) { if( !stricmp(GetDriver(i)->fAdapterInfo.Description, devRec->GetDriverDesc()) ) { int j; for( j = 0; j < GetDriver(i)->fDevices.GetCount(); j++ ) { if( !stricmp(GetDriver(i)->fDevices[j].fStrName, devRec->GetDeviceDesc()) ) { SetCurrentDriver(GetDriver(i)); SetCurrentDevice(&GetDriver(i)->fDevices[j]); D3DEnum_SelectDefaultMode( devMode->GetWidth(), devMode->GetHeight(), devMode->GetColorDepth()); return false; } } } } char errStr[256]; sprintf(errStr, "Can't find requested device - %s:%s:%s:%s:%s", devRec->GetG3DDeviceTypeName(), devRec->GetDriverDesc(), devRec->GetDriverName(), devRec->GetDriverVersion(), devRec->GetDeviceDesc()); DWORD enumFlags = 0; int width = devMode->GetWidth(); int height = devMode->GetHeight(); int colorDepth = devMode->GetColorDepth(); // for a window, take whatever colordepth we can get. if( !colorDepth ) enumFlags |= D3DENUM_CANWINDOW; enumFlags |= D3DENUM_TNLHAL; #ifdef HS_ALLOW_D3D_REF_DRIVER enumFlags |= D3DENUM_REFERENCERAST; #endif D3DEnum_SelectDefaultDriver(enumFlags); // If we didn't get what we want, try for anything. if( !GetCurrentDriver() || !GetCurrentDevice() ) { enumFlags = colorDepth ? 0 : D3DENUM_CANWINDOW; D3DEnum_SelectDefaultDriver(enumFlags); } if( !GetCurrentDriver() || !GetCurrentDevice() ) D3DEnum_SelectDefaultDriver(0); if( !GetCurrentDriver() || !GetCurrentDevice() ) { if( !*GetEnumeErrorStr() ) SetEnumeErrorStr("Error finding device"); return true; } D3DEnum_SelectDefaultMode(width, height, colorDepth); if( !GetCurrentMode() ) { if( !*GetEnumeErrorStr() ) SetEnumeErrorStr("Error finding mode"); return true; } return false; } HRESULT hsGDirect3DTnLEnumerate::D3DEnum_SelectDefaultMode(int width, int height, int depth) { hsAssert(GetCurrentDriver() && GetCurrentDevice(), "Must have selected device already"); BOOL windowed = false; if (depth == 0) { // Legacy code writes out 0 bit depth to mean windowed windowed = true; depth = 32; } D3DEnum_DeviceInfo* device = GetCurrentDevice(); int i; for( i = 0; i < device->fModes.GetCount(); i++ ) { D3DEnum_ModeInfo* mode = &device->fModes[i]; if (mode->fWindowed != windowed) continue; if( depth ) { if( width < mode->fDDmode.Width ) continue; if( height < mode->fDDmode.Height ) continue; } if( depth < mode->fBitDepth ) continue; if( GetCurrentMode() ) { D3DEnum_ModeInfo* curMode = GetCurrentDriver()->fCurrentMode; if( depth ) { if( curMode->fDDmode.Width > mode->fDDmode.Width ) continue; if( curMode->fDDmode.Height > mode->fDDmode.Height ) continue; } if( curMode->fBitDepth > mode->fBitDepth ) continue; } SetCurrentMode(mode); } return S_OK; } //----------------------------------------------------------------------------- // Name: D3DEnum_SelectDefaultDriver() // Desc: Picks a default driver according to the passed in flags. //----------------------------------------------------------------------------- HRESULT hsGDirect3DTnLEnumerate::D3DEnum_SelectDefaultDriver( DWORD dwFlags ) { // If a specific driver was requested, perform that search here if( dwFlags & D3DENUM_MASK ) { int i; for( i = 0; i < fDrivers.GetCount(); i++ ) { D3DEnum_DriverInfo* pDriver = &fDrivers[i]; int j; for( j = 0; j < pDriver->fDevices.GetCount(); j++ ) { D3DEnum_DeviceInfo* pDevice = &pDriver->fDevices[j]; BOOL bFound = FALSE; if( pDevice->fDDType == D3DDEVTYPE_REF ) { if( dwFlags & D3DENUM_REFERENCERAST ) bFound = TRUE; } else if( pDevice->fDDType == D3DDEVTYPE_HAL && pDevice->fDDCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) { if( dwFlags & D3DENUM_TNLHAL ) bFound = TRUE; } else { #if !HS_BUILD_FOR_XBOX if( dwFlags & D3DENUM_CANWINDOW ) { if( (pDriver == &fDrivers[0]) &&( pDevice->fDDCaps.Caps2 & DDCAPS2_CANRENDERWINDOWED ) ) { if( ( pDevice->fDDCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) ^ !(dwFlags & D3DENUM_TNLHAL) ) bFound = TRUE; } } else #endif if( dwFlags & D3DENUM_PRIMARYHAL ) { if( pDriver == &fDrivers[0] ) bFound = TRUE; } else if( dwFlags & D3DENUM_SECONDARYHAL ) { if( pDriver != &fDrivers[0] ) bFound = TRUE; } } if( bFound ) { SetCurrentDriver(pDriver); SetCurrentDevice(pDevice); return S_OK; } } } return D3DENUMERR_NOTFOUND; } int i; for( i = 0; i < fDrivers.GetCount(); i++ ) { D3DEnum_DriverInfo* pDriver = &fDrivers[i]; int j; for( j = 0; j < pDriver->fDevices.GetCount(); j++ ) { D3DEnum_DeviceInfo* pDevice = &pDriver->fDevices[j]; if( !pDevice->fIsHardware ) continue; SetCurrentDriver(pDriver); SetCurrentDevice(pDevice); return S_OK; } } // No compatible devices were found. Return an error code return D3DENUMERR_NOCOMPATIBLEDEVICES; } //// Constructor ////////////////////////////////////////////////////////////// // // Inits the enumeration and builds our list of devices/whatever. hsGDirect3DTnLEnumerate::hsGDirect3DTnLEnumerate() { memset( &fEnumeErrorStr[0], 0x00, sizeof(fEnumeErrorStr) ); fCurrentDriver = NULL; // The selected DD driver fDrivers.Reset(); // List of DD drivers /// New DX Enumeration // Get a pointer to the creation function #if !HS_BUILD_FOR_XBOX if( hsGDDrawDllLoad::GetD3DDll() == nil ) { strcpy( fEnumeErrorStr, "Cannot load Direct3D driver!" ); return; } Direct3DCreateProc procPtr; procPtr = (Direct3DCreateProc)GetProcAddress( hsGDDrawDllLoad::GetD3DDll(), "Direct3DCreate9" ); if( procPtr == nil ) { strcpy( fEnumeErrorStr, "Cannot load D3D Create Proc!" ); return; } // Create a D3D object to use IDirect3D9 *pD3D = procPtr( D3D_SDK_VERSION ); #else IDirect3D9 *pD3D = Direct3DCreate9( D3D_SDK_VERSION ); #endif if( pD3D == nil ) { strcpy( fEnumeErrorStr, "Cannot load DirectX!" ); return; } /// Loop through the "adapters" (we don't call them drivers anymore) UINT iAdapter; for( iAdapter = 0; iAdapter < pD3D->GetAdapterCount(); iAdapter++ ) { D3DEnum_DriverInfo* newDriver = fDrivers.Push(); ZeroMemory( newDriver, sizeof( *newDriver ) ); // Copy data to a device info structure D3DADAPTER_IDENTIFIER9 adapterInfo; pD3D->GetAdapterIdentifier( iAdapter, 0, &adapterInfo ); pD3D->GetAdapterDisplayMode( iAdapter, &newDriver->fDesktopMode ); memcpy( &newDriver->fAdapterInfo, &adapterInfo, sizeof( adapterInfo ) ); strncpy( newDriver->fStrName, adapterInfo.Driver, 39 ); strncpy( newDriver->fStrDesc, adapterInfo.Description, 39 ); newDriver->fGuid = adapterInfo.DeviceIdentifier; newDriver->fMemory = 16 * 1024 * 1024; /// Simulate 16 MB /// Do the mode and device enumeration for this adapter IEnumAdapterDevices( pD3D, iAdapter, newDriver ); } // Cleanup pD3D->Release(); } //// IEnumAdapterDevices ////////////////////////////////////////////////////// // // DirectX: Enumerates all the modes for a given adapter, then using the // two faked modes for HAL and REF, attaches the modes to each "device" that // can support them. void hsGDirect3DTnLEnumerate::IEnumAdapterDevices( IDirect3D9 *pD3D, UINT iAdapter, D3DEnum_DriverInfo *drivInfo ) { // A bit backwards from DX8... First we have to go through our list of formats and check for validity. // Then we can enum through the modes for each format. const DWORD numDeviceTypes = 2; const TCHAR* strDeviceDescs[] = { "HAL", "REF" }; const D3DDEVTYPE deviceTypes[] = { D3DDEVTYPE_HAL, D3DDEVTYPE_REF }; BOOL *formatWorks = TRACKED_NEW BOOL[kNumDisplayFormats + 1]; // One for each format DWORD *behavior = TRACKED_NEW DWORD[kNumDisplayFormats + 1]; UINT iDevice; for (iDevice = 0; iDevice < numDeviceTypes; iDevice++) { D3DEnum_DeviceInfo *deviceInfo = drivInfo->fDevices.Push(); ZeroMemory(deviceInfo, sizeof(*deviceInfo)); pD3D->GetDeviceCaps(iAdapter, deviceTypes[iDevice], &deviceInfo->fDDCaps); strncpy(deviceInfo->fStrName, strDeviceDescs[iDevice], 39); deviceInfo->fDDType = deviceTypes[iDevice]; deviceInfo->fIsHardware = deviceInfo->fDDCaps.DevCaps & D3DDEVCAPS_HWRASTERIZATION; /// Loop through the formats, checking each against this device to see /// if it will work. If so, add all modes matching that format UInt8 iFormat; for (iFormat = 0; iFormat < kNumDisplayFormats + 1; iFormat++ ) { // the desktop format gets to be first, everything else is nudged over one. D3DFORMAT currFormat = (iFormat == 0 ? drivInfo->fDesktopMode.Format : kDisplayFormats[iFormat - 1]); formatWorks[iFormat] = FALSE; int bitDepth = IGetDXBitDepth(currFormat); if (bitDepth == 0) continue; // Don't like this mode, skip it /// Can it be used as a render target? if (FAILED(pD3D->CheckDeviceType(iAdapter, deviceTypes[iDevice], currFormat, currFormat, FALSE))) continue; // Nope--skip it if (deviceInfo->fDDCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) { /// Confirm that HW vertex processing works on this device if (deviceInfo->fDDCaps.DevCaps & D3DDEVCAPS_PUREDEVICE) { #if 0 behavior[iFormat] = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE; #else behavior[iFormat] = D3DCREATE_HARDWARE_VERTEXPROCESSING; #endif if (SUCCEEDED(IConfirmDevice(&deviceInfo->fDDCaps, behavior[iFormat], currFormat))) { formatWorks[iFormat] = TRUE; } } if (!formatWorks[iFormat]) { /// HW vertex & Pure didn't work--just try HW vertex behavior[iFormat] = D3DCREATE_HARDWARE_VERTEXPROCESSING; if (SUCCEEDED(IConfirmDevice(&deviceInfo->fDDCaps, behavior[iFormat], currFormat))) { formatWorks[iFormat] = TRUE; } } if (!formatWorks[iFormat]) { /// HW vertex didn't work--can we do mixed? behavior[iFormat] = D3DCREATE_MIXED_VERTEXPROCESSING; if (SUCCEEDED(IConfirmDevice(&deviceInfo->fDDCaps, behavior[iFormat], currFormat))) { formatWorks[iFormat] = TRUE; } } } if (!formatWorks[iFormat]) { /// Egads. Try SW vertex processing behavior[iFormat] = D3DCREATE_SOFTWARE_VERTEXPROCESSING; if (SUCCEEDED(IConfirmDevice(&deviceInfo->fDDCaps, behavior[iFormat], currFormat))) { formatWorks[iFormat] = TRUE; } } if (formatWorks[iFormat]) { /// Now go through all the modes. If a given mode has a format that works, /// add it to the device UINT numAdapterModes = pD3D->GetAdapterModeCount(iAdapter, currFormat); DWORD iMode; for (iMode = 0; iMode < numAdapterModes; iMode++) { // TODO: Check for modes that only differ by refresh rate and exclude duplicates. /// Get the mode attributes D3DDISPLAYMODE dispMode; pD3D->EnumAdapterModes(iAdapter, currFormat, iMode, &dispMode); { /// Add it to our driver's global mode list D3DEnum_ModeInfo *modeInfo = drivInfo->fModes.Push(); ZeroMemory( modeInfo, sizeof( *modeInfo ) ); modeInfo->fDDmode = dispMode; sprintf( modeInfo->fStrDesc, TEXT( "%ld x %ld x %ld" ), dispMode.Width, dispMode.Height, bitDepth ); modeInfo->fBitDepth = bitDepth; // Add it to the device modeInfo->fDDBehavior = behavior[ iFormat ]; IFindDepthFormats( pD3D, iAdapter, deviceInfo->fDDType, modeInfo ); IFindFSAATypes( pD3D, iAdapter, deviceInfo->fDDType, modeInfo ); ICheckCubicRenderTargets( pD3D, iAdapter, deviceInfo->fDDType, modeInfo ); deviceInfo->fModes.Append( *modeInfo ); // Special check for the desktop, which we know is the first entry, because we put it there. if (iFormat == 0) { /// Check if the device can window and/or is compatible with the desktop display mode deviceInfo->fCompatibleWithDesktop = TRUE; // As of DirectX 9, any device supports windowed mode //if (deviceInfo->fDDCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED) { deviceInfo->fCanWindow = TRUE; /// Add a fake mode to represent windowed. Silly, but here for legacy D3DEnum_ModeInfo *pModeInfo = drivInfo->fModes.Push(); ZeroMemory(pModeInfo, sizeof(*pModeInfo)); pModeInfo->fDDmode = dispMode; pModeInfo->fDDBehavior = behavior[iFormat]; pModeInfo->fBitDepth = bitDepth; sprintf(pModeInfo->fStrDesc, TEXT("Windowed")); pModeInfo->fWindowed = true; IFindDepthFormats(pD3D, iAdapter, deviceInfo->fDDType, pModeInfo); IFindFSAATypes(pD3D, iAdapter, deviceInfo->fDDType, pModeInfo); ICheckCubicRenderTargets(pD3D, iAdapter, deviceInfo->fDDType, pModeInfo); deviceInfo->fModes.Append( *pModeInfo ); } } } } } } } delete [] formatWorks; delete [] behavior; } //// IFindDepthFormats //////////////////////////////////////////////////////// // DirectX: Given a device and mode, find ALL available depth/stencil // formats and add them to the mode info struct. hsBool hsGDirect3DTnLEnumerate::IFindDepthFormats( IDirect3D9 *pD3D, UINT iAdapter, D3DDEVTYPE deviceType, D3DEnum_ModeInfo *modeInfo ) { #if HS_BUILD_FOR_XBOX D3DFORMAT formats[] = { D3DFMT_D16, D3DFMT_D24S8, D3DFMT_UNKNOWN }; #else D3DFORMAT formats[] = { D3DFMT_D16, D3DFMT_D24X8, D3DFMT_D32, D3DFMT_D15S1, D3DFMT_D24X4S4, D3DFMT_D24S8, D3DFMT_UNKNOWN }; #endif /// Try 'em for( int i = 0; formats[ i ] != D3DFMT_UNKNOWN; i++ ) { if( SUCCEEDED( pD3D->CheckDeviceFormat( iAdapter, deviceType, modeInfo->fDDmode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, formats[ i ] ) ) ) { if( SUCCEEDED( pD3D->CheckDepthStencilMatch( iAdapter, deviceType, modeInfo->fDDmode.Format, modeInfo->fDDmode.Format, formats[ i ] ) ) ) { modeInfo->fDepthFormats.Append( formats[ i ] ); } } } return( modeInfo->fDepthFormats.GetCount() > 0 ? true : false ); } //// IFindFSAATypes /////////////////////////////////////////////////////////// // DirectX: Given a device and mode, find ALL available multisample types // and add them to the mode info struct. hsBool hsGDirect3DTnLEnumerate::IFindFSAATypes( IDirect3D9 *pD3D, UINT iAdapter, D3DDEVTYPE deviceType, D3DEnum_ModeInfo *modeInfo ) { /// Try 'em for (int type = 2; type <= 16; type++) { if (SUCCEEDED(pD3D->CheckDeviceMultiSampleType(iAdapter, deviceType, modeInfo->fDDmode.Format, modeInfo->fWindowed ? TRUE : FALSE, (D3DMULTISAMPLE_TYPE)type, NULL))) { modeInfo->fFSAATypes.Append((D3DMULTISAMPLE_TYPE)type); } } return (modeInfo->fFSAATypes.GetCount() > 0 ? true : false); } //// ICheckCubicRenderTargets ///////////////////////////////////////////////// hsBool hsGDirect3DTnLEnumerate::ICheckCubicRenderTargets( IDirect3D9 *pD3D, UINT iAdapter, D3DDEVTYPE deviceType, D3DEnum_ModeInfo *modeInfo ) { if( SUCCEEDED( pD3D->CheckDeviceFormat( iAdapter, deviceType, modeInfo->fDDmode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_CUBETEXTURE, modeInfo->fDDmode.Format ) ) ) { modeInfo->fCanRenderToCubic = true; return true; } modeInfo->fCanRenderToCubic = false; return false; } //// IConfirmDevice /////////////////////////////////////////////////////////// // // Nice, encapsulated way of testing for specific caps on a particular device HRESULT hsGDirect3DTnLEnumerate::IConfirmDevice( D3DCAPS9* pCaps, DWORD dwBehavior, D3DFORMAT Format ) { short bits; bits = IGetDXBitDepth( Format ); if( bits == 16 || bits == 24 || bits == 32 ) return S_OK; return E_FAIL; } //----------------------------------------------------------------------------- // Name: ~hsGDirect3DTnLEnumerate() // Desc: //----------------------------------------------------------------------------- hsGDirect3DTnLEnumerate::~hsGDirect3DTnLEnumerate() { D3DEnum_FreeResources(); } //----------------------------------------------------------------------------- // Name: D3DEnum_FreeResources() // Desc: Frees all resources used for driver enumeration //----------------------------------------------------------------------------- VOID hsGDirect3DTnLEnumerate::D3DEnum_FreeResources() { } //----------------------------------------------------------------------------- // Name: SetEnumeErrorStr() // Desc: //----------------------------------------------------------------------------- void hsGDirect3DTnLEnumerate::SetEnumeErrorStr(const char* s) { hsStrncpy(fEnumeErrorStr, s, 128); } //// IGetDXBitDepth ////////////////////////////////////////////////////////// // // From a D3DFORMAT enumeration, return the bit depth associated with it. // Copied from hsGDirect3DDevice to prevent inclusion of that class in // the RenderMenu project (for some reason, VC can't figure out we're only // calling one static function!) short hsGDirect3DTnLEnumerate::IGetDXBitDepth( D3DFORMAT format ) { #define ReturnDepth(type, depth) if (format == type) return depth ReturnDepth(D3DFMT_UNKNOWN, 0); ReturnDepth(D3DFMT_A8R8G8B8, 32); ReturnDepth(D3DFMT_X8R8G8B8, 32); ReturnDepth(D3DFMT_R5G6B5, 16); ReturnDepth(D3DFMT_X1R5G5B5, 16); ReturnDepth(D3DFMT_A1R5G5B5, 16); // Supported by DX9, but we don't currently support it. Can add support if needed. //ReturnDepth(D3DFMT_A2B10G10R10, 32); // Unsupported translation format--return 0 return 0; } /////////////////////////////////////////////////////////////////////////////// //// Direct3D DeviceSelector Code /////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// //// IGetD3DCardInfo ///////////////////////////////////////////////////////// // Given two enum structs, strips out and produces the vendor ID, device ID // and the driver name. Returns true if processed, false otherwise. hsBool hsG3DDeviceSelector::IGetD3DCardInfo( hsG3DDeviceRecord &record, // In void *driverInfo, void *deviceInfo, DWORD *vendorID, DWORD *deviceID, // Out char **driverString, char **descString ) { D3DEnum_DriverInfo *driverD3DInfo = (D3DEnum_DriverInfo *)driverInfo; D3DEnum_DeviceInfo *deviceD3DInfo = (D3DEnum_DeviceInfo *)deviceInfo; D3DADAPTER_IDENTIFIER9 *adapterInfo; adapterInfo = &driverD3DInfo->fAdapterInfo; /// Print out to our demo data file plDemoDebugFile::Write( "DeviceSelector detected DX Direct3D device. Info:" ); plDemoDebugFile::Write( " Driver Description", (char *)adapterInfo->Description ); plDemoDebugFile::Write( " Driver Name", (char *)adapterInfo->Driver ); plDemoDebugFile::Write( " Vendor ID", (Int32)adapterInfo->VendorId ); plDemoDebugFile::Write( " Device ID", (Int32)adapterInfo->DeviceId ); plDemoDebugFile::Write( " Version", (char *)record.GetDriverVersion() ); plDemoDebugFile::Write( " Memory size (in MB)", record.GetMemoryBytes() / ( 1024 * 1024 ) ); plDemoDebugFile::Write( " Memory size (in bytes)", record.GetMemoryBytes() ); *vendorID = adapterInfo->VendorId; *deviceID = adapterInfo->DeviceId; *driverString = adapterInfo->Driver; *descString = adapterInfo->Description; return true; } //// IInitDirect3D //////////////////////////////////////////////////////////// hsBool hsG3DDeviceSelector::IInitDirect3D( void ) { if( hsGDDrawDllLoad::GetD3DDll() == nil ) { strcpy( fErrorString, "Cannot load Direct3D driver!" ); return false; } Direct3DCreateProc procPtr; procPtr = (Direct3DCreateProc)GetProcAddress( hsGDDrawDllLoad::GetD3DDll(), "Direct3DCreate9" ); if( procPtr == nil ) { strcpy( fErrorString, "Cannot load D3D Create Proc!" ); return false; } // Create a D3D object to use IDirect3D9 *pD3D = procPtr( D3D_SDK_VERSION ); if( pD3D == nil ) { strcpy( fErrorString, "Cannot load DirectX!" ); return false; } pD3D->Release(); fErrorString[ 0 ] = 0; return true; } //// ITryDirect3DTnL ////////////////////////////////////////////////////////// void hsG3DDeviceSelector::ITryDirect3DTnL(hsWinRef winRef) { hsGDirect3DTnLEnumerate d3dEnum; int i; for( i = 0; i < d3dEnum.GetNumDrivers(); i++ ) { ITryDirect3DTnLDriver(d3dEnum.GetDriver(i)); } } //// ITryDirect3DDriver /////////////////////////////////////////////////////// // // New DirectX Way void hsG3DDeviceSelector::ITryDirect3DTnLDriver(D3DEnum_DriverInfo* drivInfo) { hsG3DDeviceRecord devRec; devRec.Clear(); devRec.SetG3DDeviceType( kDevTypeDirect3DTnL ); devRec.SetDriverName( drivInfo->fAdapterInfo.Driver ); devRec.SetDriverDesc( drivInfo->fAdapterInfo.Description ); char buff[ 256 ]; sprintf( buff, "%d.%02d.%02d.%04d", HIWORD( drivInfo->fAdapterInfo.DriverVersion.u.HighPart ), LOWORD( drivInfo->fAdapterInfo.DriverVersion.u.HighPart ), HIWORD( drivInfo->fAdapterInfo.DriverVersion.u.LowPart ), LOWORD( drivInfo->fAdapterInfo.DriverVersion.u.LowPart ) ); devRec.SetDriverVersion(buff); devRec.SetMemoryBytes(drivInfo->fMemory); int i; for( i = 0; i < drivInfo->fDevices.GetCount(); i++ ) { /// 9.6.2000 mcn - Changed here so we can do fudging here, rather /// than passing all the messy driver data to the function hsG3DDeviceRecord currDevRec = devRec; /// Done first now, so we can alter the D3D type later ITryDirect3DTnLDevice( &drivInfo->fDevices[i], currDevRec ); /// Check the vendor ID to see if it's 3dfx (#0x121a). If it is, don't add it. /// (we don't support 3dfx D3D devices) -mcn /// 11.25.2000 mcn - Knew this was going to come back and bite me. Now we just /// append (3dfx) to the end of the device description, so that our latter test /// can throw it out or not, depending on whether we're "strong". if( drivInfo->fAdapterInfo.VendorId == 0x121a && ( currDevRec.GetG3DHALorHEL() == hsG3DDeviceSelector::kHHD3DHALDev || currDevRec.GetG3DHALorHEL() == hsG3DDeviceSelector::kHHD3DTnLHalDev ) ) { if( drivInfo->fAdapterInfo.DeviceId >= 0x00000009 ) { currDevRec.SetG3DHALorHEL( kHHD3D3dfxVoodoo5Dev ); plDemoDebugFile::Write( " Tagging device as a 3dfx Voodoo5 or above" ); } else { currDevRec.SetG3DHALorHEL( kHHD3D3dfxDev ); plDemoDebugFile::Write( " Tagging device as a non-V5 3dfx card" ); } } IFudgeDirectXDevice( currDevRec, (D3DEnum_DriverInfo *)drivInfo, (D3DEnum_DeviceInfo *)&drivInfo->fDevices[ i ] ); if( currDevRec.GetModes().GetCount() ) fRecords.Append( currDevRec ); } } //// ITryDirect3DTnLDevice //////////////////////////////////////////////////// // // New DirectX Way void hsG3DDeviceSelector::ITryDirect3DTnLDevice(D3DEnum_DeviceInfo* devInfo, hsG3DDeviceRecord& devRec) { devRec.SetDeviceDesc(devInfo->fStrName); if( devInfo->fDDType == D3DDEVTYPE_REF ) devRec.SetG3DHALorHEL( kHHD3DRefDev ); else if( devInfo->fDDType == D3DDEVTYPE_HAL ) { if( devInfo->fDDCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) { devRec.SetG3DHALorHEL( kHHD3DTnLHalDev ); devRec.SetCap( kCapsHWTransform ); } else devRec.SetG3DHALorHEL( kHHD3DHALDev ); } if( devInfo->fDDCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP ) devRec.SetCap( kCapsCubicTextures ); devRec.SetLayersAtOnce( devInfo->fDDCaps.MaxSimultaneousTextures ); if( devInfo->fDDCaps.TextureFilterCaps & D3DPTFILTERCAPS_MIPFLINEAR ) devRec.SetCap( kCapsMipmap ); if( devInfo->fDDCaps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP ) devRec.SetCap( kCapsCubicMipmap ); if( devInfo->fDDCaps.TextureCaps & D3DPTEXTURECAPS_PERSPECTIVE ) devRec.SetCap(kCapsPerspective); if( devInfo->fIsHardware ) devRec.SetCap( kCapsHardware ); if( devInfo->fDDCaps.RasterCaps & D3DPRASTERCAPS_DITHER ) devRec.SetCap(kCapsDither); if( devInfo->fDDCaps.RasterCaps & D3DPRASTERCAPS_WBUFFER ) devRec.SetCap(kCapsWBuffer); if( devInfo->fDDCaps.RasterCaps & D3DPRASTERCAPS_FOGTABLE ) { devRec.SetCap( kCapsFogLinear ); devRec.SetCap( kCapsFogExp ); devRec.SetCap( kCapsFogExp2 ); devRec.SetCap( kCapsPixelFog ); } else { devRec.SetCap( kCapsFogLinear ); } if( devInfo->fDDCaps.RasterCaps & D3DPRASTERCAPS_FOGRANGE ) devRec.SetCap( kCapsFogRange ); if( devInfo->fDDCaps.MaxAnisotropy <= 1 ) devRec.SetMaxAnisotropicSamples( 0 ); else devRec.SetMaxAnisotropicSamples( (UInt8)devInfo->fDDCaps.MaxAnisotropy ); if (D3DSHADER_VERSION_MAJOR(devInfo->fDDCaps.PixelShaderVersion) > 0) devRec.SetCap(kCapsPixelShader); /// Assume these by default devRec.SetCap( kCapsCompressTextures ); devRec.SetCap( kCapsDoesSmallTextures ); #if 1 // mf - want to leave this one off by default // if( devInfo->fCanAntialias ) // devRec.SetCap( kCapsAntiAlias ); #endif // mf - want to leave this one off by default hsG3DDeviceMode devMode; int i, j; const struct { D3DFORMAT fmt; UInt16 depth; } depths[] = { { D3DFMT_D16, 0x0010 }, { D3DFMT_D24X8, 0x0018 }, { D3DFMT_D32, 0x0020 }, { D3DFMT_D15S1, 0x010f }, { D3DFMT_D24X4S4, 0x0418 }, { D3DFMT_D24S8, 0x0818 }, { D3DFMT_UNKNOWN, 0 } }; for( i = 0; i < devInfo->fModes.GetCount(); i++ ) { D3DEnum_ModeInfo* modeInfo = &devInfo->fModes[i]; devMode.Clear(); devMode.SetWidth( modeInfo->fDDmode.Width ); devMode.SetHeight( modeInfo->fDDmode.Height ); devMode.SetColorDepth( modeInfo->fBitDepth ); if( modeInfo->fCanRenderToCubic ) devMode.SetCanRenderToCubics( true ); else devMode.SetCanRenderToCubics( false ); for( j = 0; depths[ j ].depth != 0; j++ ) { if( modeInfo->fDepthFormats.Find( depths[ j ].fmt ) != modeInfo->fDepthFormats.kMissingIndex ) devMode.AddZStencilDepth( depths[ j ].depth ); } for( j = 2; j <= 16; j++ ) { if( modeInfo->fFSAATypes.Find( (D3DMULTISAMPLE_TYPE)j ) != modeInfo->fFSAATypes.kMissingIndex ) devMode.AddFSAAType( j ); } devRec.GetModes().Append( devMode ); } }