summaryrefslogtreecommitdiff
path: root/Runtime/GfxDevice/d3d/D3D9Enumeration.cpp
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-08-14 22:50:43 +0800
committerchai <chaifix@163.com>2019-08-14 22:50:43 +0800
commit15740faf9fe9fe4be08965098bbf2947e096aeeb (patch)
treea730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/GfxDevice/d3d/D3D9Enumeration.cpp
+Unity Runtime codeHEADmaster
Diffstat (limited to 'Runtime/GfxDevice/d3d/D3D9Enumeration.cpp')
-rw-r--r--Runtime/GfxDevice/d3d/D3D9Enumeration.cpp344
1 files changed, 344 insertions, 0 deletions
diff --git a/Runtime/GfxDevice/d3d/D3D9Enumeration.cpp b/Runtime/GfxDevice/d3d/D3D9Enumeration.cpp
new file mode 100644
index 0000000..b78433e
--- /dev/null
+++ b/Runtime/GfxDevice/d3d/D3D9Enumeration.cpp
@@ -0,0 +1,344 @@
+#include "UnityPrefix.h"
+#include "D3D9Enumeration.h"
+#include "D3D9Utils.h"
+#include "Runtime/GfxDevice/VramLimits.h"
+
+// ---------------------------------------------------------------------------
+
+
+const int kMinDisplayWidth = 512;
+const int kMinDisplayHeight = 384;
+const int kMinColorBits = 4;
+const int kMinAlphaBits = 0;
+
+extern D3DDEVTYPE g_D3DDevType;
+extern DWORD g_D3DAdapter;
+
+// ---------------------------------------------------------------------------
+
+static int GetFormatColorBits( D3DFORMAT fmt ) {
+ switch( fmt ) {
+ case D3DFMT_A2B10G10R10:
+ case D3DFMT_A2R10G10B10: return 10;
+ case D3DFMT_R8G8B8:
+ case D3DFMT_A8R8G8B8:
+ case D3DFMT_X8R8G8B8: return 8;
+ case D3DFMT_R5G6B5:
+ case D3DFMT_X1R5G5B5:
+ case D3DFMT_A1R5G5B5: return 5;
+ case D3DFMT_A4R4G4B4:
+ case D3DFMT_X4R4G4B4: return 4;
+ case D3DFMT_R3G3B2:
+ case D3DFMT_A8R3G3B2: return 2;
+ default: return 0;
+ }
+}
+
+static int GetFormatAlphaBits( D3DFORMAT fmt ) {
+ switch( fmt ) {
+ case D3DFMT_R8G8B8:
+ case D3DFMT_X8R8G8B8:
+ case D3DFMT_R5G6B5:
+ case D3DFMT_X1R5G5B5:
+ case D3DFMT_R3G3B2:
+ case D3DFMT_X4R4G4B4: return 0;
+ case D3DFMT_A8R8G8B8:
+ case D3DFMT_A8R3G3B2: return 8;
+ case D3DFMT_A1R5G5B5: return 1;
+ case D3DFMT_A4R4G4B4: return 4;
+ case D3DFMT_A2B10G10R10:
+ case D3DFMT_A2R10G10B10: return 2;
+ default: return 0;
+ }
+}
+
+int GetFormatDepthBits( D3DFORMAT fmt ) {
+ switch( fmt ) {
+ case D3DFMT_D16: return 16;
+ case D3DFMT_D15S1: return 15;
+ case D3DFMT_D24X8:
+ case D3DFMT_D24S8:
+ case D3DFMT_D24X4S4: return 24;
+ case D3DFMT_D32: return 32;
+ default: return 0;
+ }
+}
+
+static D3DFORMAT ConvertToAlphaFormat( D3DFORMAT fmt )
+{
+ if( fmt == D3DFMT_X8R8G8B8 )
+ fmt = D3DFMT_A8R8G8B8;
+ else if( fmt == D3DFMT_X4R4G4B4 )
+ fmt = D3DFMT_A4R4G4B4;
+ else if( fmt == D3DFMT_X1R5G5B5 )
+ fmt = D3DFMT_A1R5G5B5;
+ return fmt;
+}
+
+// -----------------------------------------------------------------------------
+
+
+static UInt32 buildVertexProcessings( const D3DCAPS9& caps )
+{
+ UInt32 result = 0;
+
+ // TODO: check vertex shader version
+
+ DWORD devCaps = caps.DevCaps;
+ if( devCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) {
+ if( devCaps & D3DDEVCAPS_PUREDEVICE ) {
+ result |= (1<<kVPPureHardware);
+ }
+ result |= (1<<kVPHardware);
+ result |= (1<<kVPMixed);
+ }
+
+ result |= (1<<kVPSoftware);
+
+ return result;
+}
+
+
+static void buildDepthStencilFormats( IDirect3D9& d3d, D3DDeviceCombo& devCombo )
+{
+ const D3DFORMAT dsFormats[] = {
+ D3DFMT_D24S8, D3DFMT_D24X8, D3DFMT_D24X4S4, D3DFMT_D16, D3DFMT_D15S1, D3DFMT_D32,
+ };
+ const int dsFormatCount = sizeof(dsFormats) / sizeof(dsFormats[0]);
+
+ for( int idsf = 0; idsf < dsFormatCount; ++idsf ) {
+ D3DFORMAT format = dsFormats[idsf];
+ if( SUCCEEDED( d3d.CheckDeviceFormat( g_D3DAdapter, g_D3DDevType, devCombo.adapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, format ) ) )
+ {
+ if( SUCCEEDED( d3d.CheckDepthStencilMatch( g_D3DAdapter, g_D3DDevType, devCombo.adapterFormat, devCombo.backBufferFormat, format ) ) )
+ {
+ devCombo.depthStencilFormats.push_back( format );
+ }
+ }
+ }
+}
+
+
+static void buildMultiSampleTypes( IDirect3D9& d3d, D3DDeviceCombo& devCombo )
+{
+ const size_t kMaxSamples = 16;
+ devCombo.multiSampleTypes.reserve( kMaxSamples );
+ devCombo.multiSampleTypes.push_back( D3DMULTISAMPLE_NONE );
+
+ for( int samples = 2; samples <= kMaxSamples; ++samples ) {
+ D3DMULTISAMPLE_TYPE msType = GetD3DMultiSampleType( samples );
+ DWORD msQuality;
+ if( SUCCEEDED( d3d.CheckDeviceMultiSampleType( g_D3DAdapter, g_D3DDevType, devCombo.backBufferFormat, devCombo.isWindowed, msType, NULL ) ) )
+ devCombo.multiSampleTypes.push_back( samples );
+ }
+}
+
+
+static void buildConflicts( IDirect3D9& d3d, D3DDeviceCombo& devCombo )
+{
+ for( size_t ids = 0; ids < devCombo.depthStencilFormats.size(); ++ids ) {
+ D3DFORMAT format = (D3DFORMAT)devCombo.depthStencilFormats[ids];
+ for( size_t ims = 0; ims < devCombo.multiSampleTypes.size(); ++ims ) {
+ D3DMULTISAMPLE_TYPE msType = (D3DMULTISAMPLE_TYPE)devCombo.multiSampleTypes[ims];
+ if( FAILED( d3d.CheckDeviceMultiSampleType(
+ g_D3DAdapter, g_D3DDevType,
+ format, devCombo.isWindowed, msType, NULL ) ) )
+ {
+ D3DDeviceCombo::MultiSampleConflict conflict;
+ conflict.format = format;
+ conflict.type = msType;
+ devCombo.conflicts.push_back( conflict );
+ }
+ }
+ }
+}
+
+
+static bool enumerateDeviceCombos( IDirect3D9& d3d, const D3DCAPS9& caps, const DwordVector& adapterFormats, D3DDeviceComboVector& outCombos )
+{
+ const D3DFORMAT bbufferFormats[] = {
+ D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_A2R10G10B10,
+ D3DFMT_R5G6B5, D3DFMT_A1R5G5B5, D3DFMT_X1R5G5B5
+ };
+ const int bbufferFormatCount = sizeof(bbufferFormats) / sizeof(bbufferFormats[0]);
+
+ bool isWindowedArray[] = { false, true };
+
+ // see which adapter formats are supported by this device
+ for( size_t iaf = 0; iaf < adapterFormats.size(); ++iaf )
+ {
+ D3DFORMAT format = (D3DFORMAT)adapterFormats[iaf];
+ for( int ibbf = 0; ibbf < bbufferFormatCount; ibbf++ )
+ {
+ D3DFORMAT bbufferFormat = bbufferFormats[ibbf];
+ if( GetFormatAlphaBits(bbufferFormat) < kMinAlphaBits )
+ continue;
+ for( int iiw = 0; iiw < 2; ++iiw ) {
+ bool isWindowed = isWindowedArray[iiw];
+ if( FAILED( d3d.CheckDeviceType( g_D3DAdapter, g_D3DDevType, format, bbufferFormat, isWindowed ) ) )
+ continue;
+
+ // Here, we have an adapter format / backbuffer format/ windowed
+ // combo that is supported by the system. We still need to find one or
+ // more suitable depth/stencil buffer format, multisample type,
+ // vertex processing type, and vsync.
+ D3DDeviceCombo devCombo;
+
+ devCombo.adapterFormat = format;
+ devCombo.backBufferFormat = bbufferFormat;
+ devCombo.isWindowed = isWindowed;
+ devCombo.presentationIntervals = caps.PresentationIntervals;
+
+ buildDepthStencilFormats( d3d, devCombo );
+ if( devCombo.depthStencilFormats.empty() )
+ continue;
+
+ buildMultiSampleTypes( d3d, devCombo );
+ if( devCombo.multiSampleTypes.empty() )
+ continue;
+
+ buildConflicts( d3d, devCombo );
+
+ outCombos.push_back( devCombo );
+ }
+ }
+ }
+
+ return !outCombos.empty();
+}
+
+
+bool D3D9FormatCaps::Enumerate( IDirect3D9& d3d )
+{
+ AssertIf( !m_Combos.empty() );
+ HRESULT hr;
+
+ const D3DFORMAT allowedFormats[] = {
+ D3DFMT_X8R8G8B8, D3DFMT_X1R5G5B5, D3DFMT_R5G6B5, D3DFMT_A2R10G10B10
+ };
+ const int allowedFormatCount = sizeof(allowedFormats) / sizeof(allowedFormats[0]);
+
+ m_AdapterFormatForChecks = D3DFMT_UNKNOWN;
+
+ // build a list of all display adapter formats
+ DwordVector adapterFormatList; // D3DFORMAT
+
+ for( size_t ifmt = 0; ifmt < allowedFormatCount; ++ifmt )
+ {
+ D3DFORMAT format = allowedFormats[ifmt];
+ int modeCount = d3d.GetAdapterModeCount( g_D3DAdapter, format );
+ for( int mode = 0; mode < modeCount; ++mode ) {
+ D3DDISPLAYMODE dm;
+ d3d.EnumAdapterModes( g_D3DAdapter, format, mode, &dm );
+ if( dm.Width < (UINT)kMinDisplayWidth || dm.Height < (UINT)kMinDisplayHeight || GetFormatColorBits(dm.Format) < kMinColorBits )
+ continue;
+ // adapterInfo->displayModes.push_back( dm );
+ if( std::find(adapterFormatList.begin(),adapterFormatList.end(),dm.Format) == adapterFormatList.end() ) {
+ adapterFormatList.push_back( dm.Format );
+ if( m_AdapterFormatForChecks == D3DFMT_UNKNOWN )
+ m_AdapterFormatForChecks = format;
+ }
+ }
+ }
+
+ if( m_AdapterFormatForChecks == D3DFMT_UNKNOWN ) // for some reason no format was selected for checks, use default
+ m_AdapterFormatForChecks = allowedFormats[0];
+
+ // get info for device on this adapter
+ D3DCAPS9 caps;
+ if( FAILED( d3d.GetDeviceCaps( g_D3DAdapter, g_D3DDevType, &caps ) ) )
+ return false;
+
+ // find suitable vertex processing modes (if any)
+ m_VertexProcessings = buildVertexProcessings( caps );
+ AssertIf( !m_VertexProcessings );
+
+ // get info for each device combo on this device
+ if( !enumerateDeviceCombos( d3d, caps, adapterFormatList, m_Combos ) )
+ return false;
+
+ return true;
+}
+
+
+void D3D9FormatCaps::FindBestPresentationParams( int width, int height, D3DFORMAT desktopMode, bool windowed, int vBlankCount, int multiSample, D3DPRESENT_PARAMETERS& outParams ) const
+{
+ const D3DDeviceCombo* bestCombo = NULL;
+ int bestScore = -1;
+
+ for( size_t idc = 0; idc < m_Combos.size(); ++idc )
+ {
+ const D3DDeviceCombo& devCombo = m_Combos[idc];
+ if( windowed && !devCombo.isWindowed )
+ continue;
+ if( !windowed && devCombo.isWindowed )
+ continue;
+ if( windowed )
+ {
+ if( devCombo.adapterFormat != desktopMode )
+ continue;
+ }
+
+ int score = 0;
+
+ bool matchesBB = (devCombo.backBufferFormat == ConvertToAlphaFormat(devCombo.adapterFormat));
+ bool matchesDesktop = (devCombo.adapterFormat == desktopMode);
+
+ if( matchesBB )
+ score += 1;
+ if( matchesDesktop )
+ score += 1;
+ if( GetFormatAlphaBits(devCombo.backBufferFormat) > 0 )
+ score += 1;
+
+ if( score > bestScore )
+ {
+ bestScore = score;
+ bestCombo = &devCombo;
+ }
+ }
+
+ if( !bestCombo )
+ {
+ // This can happen if we're debugging force-16BPP modes on a 32BPP desktop, and so on
+ outParams.BackBufferFormat = desktopMode;
+ outParams.AutoDepthStencilFormat = D3DFMT_D16;
+ outParams.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
+ outParams.MultiSampleType = D3DMULTISAMPLE_NONE;
+ outParams.MultiSampleQuality = 0;
+ return;
+ }
+
+ outParams.BackBufferFormat = bestCombo->backBufferFormat;
+ outParams.AutoDepthStencilFormat = (D3DFORMAT)bestCombo->depthStencilFormats[0];
+
+ // No support for intervals above 1 in windowed mode (case 497116)
+ if (windowed && vBlankCount > 1)
+ vBlankCount = 1;
+
+ // best possible vsync parameter (if device doesn't support 2 fall back to 1)
+ DWORD intervals = bestCombo->presentationIntervals;
+ outParams.PresentationInterval = ( vBlankCount >= 2 ) && ( intervals & D3DPRESENT_INTERVAL_TWO ) ? D3DPRESENT_INTERVAL_TWO :
+ ( vBlankCount >= 1 ) && ( intervals & D3DPRESENT_INTERVAL_ONE ) ? D3DPRESENT_INTERVAL_ONE :
+ ( vBlankCount == 0 ) && ( intervals & D3DPRESENT_INTERVAL_IMMEDIATE ) ? D3DPRESENT_INTERVAL_IMMEDIATE :
+ D3DPRESENT_INTERVAL_DEFAULT;
+
+ // Here we already know backbuffer, depth buffer formats and so on, so we can also clamp used FSAA to sane VRAM limits.
+ int backbufferBPP = GetBPPFromD3DFormat(outParams.BackBufferFormat)/8;
+ int frontbufferBPP = GetBPPFromD3DFormat(desktopMode)/8;
+ int depthBPP = GetBPPFromD3DFormat(outParams.AutoDepthStencilFormat)/8;
+ multiSample = ChooseSuitableFSAALevel( width, height, backbufferBPP, frontbufferBPP, depthBPP, multiSample );
+
+ // Find out best matched multi sample type.
+ int msIdx = 0;
+ if( multiSample > 1 )
+ {
+ while( msIdx < bestCombo->multiSampleTypes.size() && bestCombo->multiSampleTypes[msIdx] <= multiSample )
+ ++msIdx;
+ --msIdx;
+ AssertIf( msIdx < 0 );
+ }
+ outParams.MultiSampleType = GetD3DMultiSampleType(bestCombo->multiSampleTypes[msIdx]);
+ outParams.MultiSampleQuality = 0;
+}
+