/////////////////////////////////////////////////////////////////////////////// // // ## ###### // ###### ### // ## ############### Shark 3D Engine (www.shark3d.com) // ########## # # # // ######## Copyright (c) 1996-2006 Spinor GmbH. // ######### # # # All rights reserved. // ## ########## // ## // /////////////////////////////////////////////////////////////////////////////// //@cpp #include "drv_d3d9_enum.h" #include "drv_d3d9_env.h" #include "drv_d3d9_util.h" #include "sys/core/sys_util.h" #include "util/cont/util_arrayalgo.h" /////////////////////////////////////////////////////////////////////////////// static const D3DFORMAT drv_d3d9_AdapterFmtArray[] = { D3DFMT_R5G6B5, D3DFMT_X1R5G5B5, D3DFMT_X8R8G8B8, D3DFMT_A2R10G10B10, //fullscreen only }; static const D3DFORMAT drv_d3d9_BackBufFmtArray[] = { D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5, D3DFMT_A1R5G5B5, D3DFMT_A2R10G10B10, }; static const D3DFORMAT drv_d3d9_DepthStencilFmtArray[] = { D3DFMT_D24S8, D3DFMT_D24X4S4, D3DFMT_D15S1, D3DFMT_D24FS8, D3DFMT_D32, D3DFMT_D24X8, D3DFMT_D16, D3DFMT_D16_LOCKABLE, D3DFMT_D32F_LOCKABLE, }; static const D3DFORMAT drv_d3d9_DepthFmtArray[] = { D3DFMT_D32, D3DFMT_D24X8, D3DFMT_D16, D3DFMT_D16_LOCKABLE, D3DFMT_D32F_LOCKABLE, }; /////////////////////////////////////////////////////////////////////////////// int s3d_CDrvD3d9EnumEntry::Compare( const s3d_CDrvD3d9EnumEntry &e) const { if(m_Adapter < e.m_Adapter) return -1; if(m_Adapter > e.m_Adapter) return 1; int KeyFmtA = KeyOfFmt(m_AdapterFmt); int KeyFmtB = KeyOfFmt(e.m_AdapterFmt); if(KeyFmtA < KeyFmtB) return -1; if(KeyFmtA > KeyFmtB) return 1; const s3d_CDrvGfxEnumEntry *GfxEnumEntryA = &m_GfxEnumEntry; const s3d_CDrvGfxEnumEntry *GfxEnumEntryB = &e.m_GfxEnumEntry; if(GfxEnumEntryA->m_Width < GfxEnumEntryB->m_Width) return -1; if(GfxEnumEntryA->m_Width > GfxEnumEntryB->m_Width) return 1; if(GfxEnumEntryA->m_Height < GfxEnumEntryB->m_Height) return -1; if(GfxEnumEntryA->m_Height > GfxEnumEntryB->m_Height) return 1; if(GfxEnumEntryA->m_Depth < GfxEnumEntryB->m_Depth) return -1; if(GfxEnumEntryA->m_Depth > GfxEnumEntryB->m_Depth) return 1; if(GfxEnumEntryA->m_Freq < GfxEnumEntryB->m_Freq) return -1; if(GfxEnumEntryA->m_Freq > GfxEnumEntryB->m_Freq) return 1; return 0; } bool s3d_CDrvD3d9EnumEntry::operator==( const s3d_CDrvD3d9EnumEntry &e) const { return Compare(e) == 0; } bool s3d_CDrvD3d9EnumEntry::operator<( const s3d_CDrvD3d9EnumEntry &e) const { return Compare(e) < 0; } int s3d_CDrvD3d9EnumEntry::KeyOfFmt(D3DFORMAT Fmt) { switch(Fmt) { case D3DFMT_R5G6B5: return 1; case D3DFMT_A1R5G5B5: return 2; case D3DFMT_X1R5G5B5: return 3; case D3DFMT_A8R8G8B8: return 4; case D3DFMT_X8R8G8B8: return 5; case D3DFMT_A2R10G10B10: return 6; } return -1; } /////////////////////////////////////////////////////////////////////////////// int s3d_CDrvD3d9EnumRef::Compare( const s3d_CDrvD3d9EnumEntry &Entry, const s3d_CDrvD3d9EnumRef &Ref) { if(Entry.m_Adapter < Ref.m_Adapter) return -1; if(Entry.m_Adapter > Ref.m_Adapter) return 1; if(!Ref.m_Fullscreen && Ref.m_AdapterFmt == D3DFMT_A2R10G10B10) { S3D_SYS_ASSERT(0); return -1; } int KeyFmtA = s3d_CDrvD3d9EnumEntry::KeyOfFmt(Entry.m_AdapterFmt); int KeyFmtB = s3d_CDrvD3d9EnumEntry::KeyOfFmt(Ref.m_AdapterFmt); if(KeyFmtA < KeyFmtB) return -1; if(KeyFmtA > KeyFmtB) return 1; const s3d_CDrvGfxEnumEntry *GfxEnumEntry = &Entry.m_GfxEnumEntry; if(GfxEnumEntry->m_Depth < Ref.m_Depth) return -1; if(GfxEnumEntry->m_Depth > Ref.m_Depth) return 1; if(Ref.m_Fullscreen) { if(GfxEnumEntry->m_Width < Ref.m_Width) return -1; if(GfxEnumEntry->m_Width > Ref.m_Width) return 1; if(GfxEnumEntry->m_Height < Ref.m_Height) return -1; if(GfxEnumEntry->m_Height > Ref.m_Height) return 1; if(Ref.m_Freq != 0) { if(GfxEnumEntry->m_Freq < Ref.m_Freq) return -1; if(GfxEnumEntry->m_Freq > Ref.m_Freq) return 1; } } return 0; } /////////////////////////////////////////////////////////////////////////////// bool s3d_CDrvD3d9Enum::Enumerate( s3d_CUtilMsgHandler *MsgHandler, s3d_CUtilStr_cr Info, s3d_CUtilMemPool *MemPool, s3d_CDrvD3d9Param *D3dParam, LPDIRECT3D9 D3d, bool Fullscreen, bool NoStencil) { if(!D3d) return false; s3d_CDrvD3d9Env Env; Env.Init(MsgHandler, D3dParam); m_ModeArray.Reset(); m_AdapterFmtArray.Reset(); D3DDEVTYPE DevType = D3DDEVTYPE_HAL; if(D3dParam->m_RefDriver) DevType = D3DDEVTYPE_REF; UINT AdapterCnt = D3d->GetAdapterCount(); UINT iAdapter; for(iAdapter = 0; iAdapter < AdapterCnt; iAdapter++) { s3d_CUtilStr Device = s3d_CUtilStrUtil::StrOfIntps(iAdapter); D3DADAPTER_IDENTIFIER9 AdapterIdentifier; /* Flags can be set to either 0 or D3DENUM_WHQL_LEVEL. If D3DENUM_WHQL_LEVEL is specified, this call can connect to the Internet to download new Microsoft Windows Hardware Quality Labs (WHQL) certificates. */ HRESULT Result; DWORD Flags = 0; S3D_DRV_D3D9_CALLCHECK( &Env, Result, D3d->GetAdapterIdentifier( iAdapter, Flags, &AdapterIdentifier)); if(FAILED(Result)) continue; D3DCAPS9 Caps; S3D_DRV_D3D9_CALLCHECK( &Env, Result, D3d->GetDeviceCaps( iAdapter, DevType, &Caps)); if(FAILED(Result)) continue; if(!CheckRequirements(Caps)) continue; s3d_CSysIntps AdapterFmtCnt = S3D_SYS_ARRAYCNTS( drv_d3d9_AdapterFmtArray); s3d_CSysIntps iAdapterFmt; for(iAdapterFmt = 0; iAdapterFmt < AdapterFmtCnt; iAdapterFmt++) { D3DFORMAT AdapterFmt = drv_d3d9_AdapterFmtArray[iAdapterFmt]; s3d_CUtilStrBuf Desc; Desc.Append(AdapterIdentifier.Description); Desc.Append("@"); Desc.Append(AdapterIdentifier.DeviceName); Desc.Append("@"); Desc.Append(s3d_CDrvD3d9Util::StrOfFmt(AdapterFmt)); UINT ModeCnt = D3d->GetAdapterModeCount(iAdapter, AdapterFmt); UINT iMode; for(iMode = 0; iMode < ModeCnt; iMode++) { D3DDISPLAYMODE AdapterMode; S3D_DRV_D3D9_HRESCALL( &Env, Result, D3d->EnumAdapterModes( iAdapter, AdapterFmt, iMode, &AdapterMode)); if(FAILED(Result)) continue; s3d_CDrvD3d9EnumEntry EnumEntry; EnumEntry.m_Adapter = iAdapter; EnumEntry.m_AdapterFmt = AdapterMode.Format; EnumEntry.m_GfxEnumEntry.m_Device = Device; EnumEntry.m_GfxEnumEntry.m_Width = AdapterMode.Width; EnumEntry.m_GfxEnumEntry.m_Height = AdapterMode.Height; EnumEntry.m_GfxEnumEntry.m_Freq = AdapterMode.RefreshRate; EnumEntry.m_GfxEnumEntry.m_Depth = 0; EnumEntry.m_GfxEnumEntry.m_Desc = Desc; switch(AdapterFmt) { case D3DFMT_R5G6B5: case D3DFMT_X1R5G5B5: EnumEntry.m_GfxEnumEntry.m_Depth = 16; break; case D3DFMT_A2R10G10B10: case D3DFMT_X8R8G8B8: EnumEntry.m_GfxEnumEntry.m_Depth = 32; break; } m_ModeArray.InsertBack(EnumEntry); } } } s3d_UtilArraySortDefault(m_ModeArray); s3d_UtilArraySortedDeleteDuplicatesDefault(m_ModeArray); m_ModeArray.Compactify(); if(m_ModeArray.IsEmpty()) return false; // Collect all adapters w/ their formats s3d_CUtilArray AdapterFmtArray; D3DFORMAT LastFmt = D3DFMT_UNKNOWN; int LastAdapter = -1; s3d_CSysIntps nMode = m_ModeArray.GetCnt(); s3d_CSysIntps iMode; for(iMode = 0; iMode < nMode; iMode++) { s3d_CDrvD3d9EnumEntry EnumEntry = m_ModeArray.RefAtRaw(iMode); if(EnumEntry.m_AdapterFmt == LastFmt && EnumEntry.m_Adapter == LastAdapter) continue; LastFmt = EnumEntry.m_AdapterFmt; LastAdapter = EnumEntry.m_Adapter; // Collect all supported adapters formats s3d_CDrvD3d9FmtArray FmtArray; FmtArray = AdapterFmtArray.RefAtDefault(LastAdapter, FmtArray); FmtArray.InsertBack(LastFmt); AdapterFmtArray.SetAtGrow(LastAdapter, FmtArray); } // Find matching back- and depthstencil buffer formats combinations // for each adapter format. s3d_CSysIntps nAdapter = AdapterFmtArray.GetCnt(); for(iAdapter = 0; iAdapter < UINT(nAdapter); iAdapter++) { s3d_CDrvD3d9FmtMap BackBufFmtMap; s3d_CDrvD3d9FmtMap DepthFmtMap; s3d_CDrvD3d9FmtArray FmtArray = AdapterFmtArray.RefAtRaw(iAdapter); s3d_CSysIntps nFmt = FmtArray.GetCnt(); s3d_CSysIntps iFmt; for(iFmt = 0; iFmt < nFmt; iFmt++) { D3DFORMAT AdapterFmt = FmtArray.RefAtRaw(iFmt); // Search for allowed backbuffer formats. s3d_CDrvD3d9FmtArray BackBufFmtArray; s3d_CSysIntps FmtCnt = S3D_SYS_ARRAYCNTS(drv_d3d9_BackBufFmtArray); s3d_CSysIntps iFmt; for(iFmt = 0; iFmt < FmtCnt; iFmt++) { D3DFORMAT BackBufFmt = drv_d3d9_BackBufFmtArray[iFmt]; HRESULT Result; S3D_DRV_D3D9_HRESCALL( &Env, Result, D3d->CheckDeviceType( iAdapter, DevType, AdapterFmt, BackBufFmt, !Fullscreen)); if(FAILED(Result)) continue; if(!Fullscreen) { // e.g. R5G6B5 <-> X8R8G8B8 S3D_DRV_D3D9_HRESCALL( &Env, Result, D3d->CheckDeviceFormatConversion( iAdapter, DevType, AdapterFmt, BackBufFmt)); if(FAILED(Result)) continue; } BackBufFmtArray.InsertBack(BackBufFmt); // Search for depth stencil buffer formats that are compatible // w/ found backbuffer format. s3d_CDrvD3d9FmtArray DepthFmtArray; s3d_CSysIntps EnumFmtDepthCnt = S3D_SYS_ARRAYCNTS( drv_d3d9_DepthStencilFmtArray); const D3DFORMAT *EnumDepthFmtArray = drv_d3d9_DepthStencilFmtArray; if(NoStencil) { EnumFmtDepthCnt = S3D_SYS_ARRAYCNTS( drv_d3d9_DepthFmtArray); EnumDepthFmtArray = drv_d3d9_DepthFmtArray; } s3d_CSysIntps iEnumFmtDepthCnt; for(iEnumFmtDepthCnt = 0; iEnumFmtDepthCnt < EnumFmtDepthCnt; iEnumFmtDepthCnt++) { D3DFORMAT DepthFmt = EnumDepthFmtArray[iEnumFmtDepthCnt]; HRESULT Result; S3D_DRV_D3D9_HRESCALL( &Env, Result, D3d->CheckDeviceFormat( iAdapter, DevType, AdapterFmt, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, DepthFmt)); if(FAILED(Result)) continue; S3D_DRV_D3D9_HRESCALL( &Env, Result, D3d->CheckDepthStencilMatch( iAdapter, DevType, AdapterFmt, BackBufFmt, DepthFmt)); if(FAILED(Result)) continue; DepthFmtArray.InsertBack(DepthFmt); } DepthFmtMap.SetAt(BackBufFmt, DepthFmtArray); } BackBufFmtMap.SetAt(AdapterFmt, BackBufFmtArray); } s3d_CDrvD3d9EnumAdapterFmt AdapterFmt; AdapterFmt.m_BackBufFmtMap = BackBufFmtMap; AdapterFmt.m_DepthFmtMap = DepthFmtMap; m_AdapterFmtArray.InsertBack(AdapterFmt); } return m_AdapterFmtArray.GetCnt() > 0; } void s3d_CDrvD3d9Enum::CollectEntries( s3d_CUtilArray &EnumArray) { s3d_CSysIntps nMode = m_ModeArray.GetCnt(); s3d_CSysIntps iMode; for(iMode = 0; iMode < nMode; iMode++) { s3d_CDrvD3d9EnumEntry EnumEntry = m_ModeArray.GetAt(iMode); EnumArray.InsertBack(EnumEntry.m_GfxEnumEntry); } } bool s3d_CDrvD3d9Enum::SearchEntry( s3d_CDrvD3d9EnumEntry &EnumEntry, UINT Adapter, int Prop, int Width, int Height, int Depth, int Frequency, bool Fullscreen) { s3d_CDrvD3d9EnumRef EnumRef; EnumRef.m_Adapter = Adapter; EnumRef.m_AdapterFmt = D3DFMT_UNKNOWN; EnumRef.m_Width = Width; EnumRef.m_Height = Height; EnumRef.m_Depth = Depth; EnumRef.m_Freq = Frequency; EnumRef.m_Fullscreen = Fullscreen; s3d_CSysIntps Pos = -1; if(Depth > 16) { EnumRef.m_AdapterFmt = D3DFMT_X8R8G8B8; Pos = s3d_UtilArraySortedGetEqual(m_ModeArray, EnumRef); if(Pos < 0 && Fullscreen) { EnumRef.m_AdapterFmt = D3DFMT_A2R10G10B10; Pos = s3d_UtilArraySortedGetEqual(m_ModeArray, EnumRef); } } else { EnumRef.m_AdapterFmt = D3DFMT_R5G6B5; Pos = s3d_UtilArraySortedGetEqual(m_ModeArray, EnumRef); if(Pos < 0) { EnumRef.m_AdapterFmt = D3DFMT_X1R5G5B5; Pos = s3d_UtilArraySortedGetEqual(m_ModeArray, EnumRef); } } if(Pos < 0) return false; EnumEntry = m_ModeArray.GetAt(Pos); return true; } void s3d_CDrvD3d9Enum::GetBufferFmts( int Depth, D3DFORMAT &BackBufFmt, D3DFORMAT &DepthStencilFmt, const s3d_CDrvD3d9EnumEntry &EnumEntry) { BackBufFmt = D3DFMT_UNKNOWN; DepthStencilFmt = D3DFMT_UNKNOWN; s3d_CDrvD3d9EnumAdapterFmt EnumAdapterFmt = m_AdapterFmtArray.GetAtDefault(EnumEntry.m_Adapter); s3d_CDrvD3d9FmtArray BackBufFmtArray; EnumAdapterFmt.m_BackBufFmtMap.GetAtInto( EnumEntry.m_AdapterFmt, BackBufFmtArray); s3d_CSysIntps nBackBufFmt = BackBufFmtArray.GetCnt(); s3d_CSysIntps iBackBufFmt; for(iBackBufFmt = 0; iBackBufFmt < nBackBufFmt; iBackBufFmt++) { BackBufFmt = BackBufFmtArray.GetAtDefault(iBackBufFmt, D3DFMT_UNKNOWN); if(Depth == s3d_CDrvD3d9Util::ColBitsOfFmt(BackBufFmt)) break; } s3d_CDrvD3d9FmtArray DepthStencilFmtArray; EnumAdapterFmt.m_DepthFmtMap.GetAtInto(BackBufFmt, DepthStencilFmtArray); DepthStencilFmt = DepthStencilFmtArray.GetAtDefault(0, D3DFMT_UNKNOWN); } /////////////////////////////////////////////////////////////////////////////// bool s3d_CDrvD3d9Enum::CheckRequirements(const D3DCAPS9 &Caps) { return true; } ///////////////////////////////////////////////////////////////////////////////