1155 lines
44 KiB
C++

//--------------------------------------------------------------------------------------
// File: DXUTDevice11.cpp
//
// Enumerates D3D adapters, devices, modes, etc.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#include "DXUT.h"
#undef min // use __min instead
#undef max // use __max instead
//--------------------------------------------------------------------------------------
// Forward declarations
//--------------------------------------------------------------------------------------
extern void DXUTGetCallbackD3D11DeviceAcceptable( LPDXUTCALLBACKISD3D11DEVICEACCEPTABLE* ppCallbackIsDeviceAcceptable, void** ppUserContext );
static int __cdecl SortModesCallback( const void* arg1, const void* arg2 );
CD3D11Enumeration* g_pDXUTD3D11Enumeration = NULL;
HRESULT WINAPI DXUTCreateD3D11Enumeration()
{
if( g_pDXUTD3D11Enumeration == NULL )
{
g_pDXUTD3D11Enumeration = new CD3D11Enumeration();
if( NULL == g_pDXUTD3D11Enumeration )
return E_OUTOFMEMORY;
}
return S_OK;
}
void WINAPI DXUTDestroyD3D11Enumeration()
{
SAFE_DELETE( g_pDXUTD3D11Enumeration );
}
class DXUTMemoryHelperD3D11Enum
{
public:
DXUTMemoryHelperD3D11Enum()
{
DXUTCreateD3D11Enumeration();
}
~DXUTMemoryHelperD3D11Enum()
{
DXUTDestroyD3D11Enumeration();
}
};
//--------------------------------------------------------------------------------------
CD3D11Enumeration* WINAPI DXUTGetD3D11Enumeration( bool bForceEnumerate, bool bEnumerateAllAdapterFormats, D3D_FEATURE_LEVEL forceFL )
{
// Using an static class with accessor function to allow control of the construction order
static DXUTMemoryHelperD3D11Enum d3d11enumMemory;
if( g_pDXUTD3D11Enumeration && ( !g_pDXUTD3D11Enumeration->HasEnumerated() || bForceEnumerate ) )
{
g_pDXUTD3D11Enumeration->SetEnumerateAllAdapterFormats( bEnumerateAllAdapterFormats );
LPDXUTCALLBACKISD3D11DEVICEACCEPTABLE pCallbackIsDeviceAcceptable;
void* pUserContext;
DXUTGetCallbackD3D11DeviceAcceptable( &pCallbackIsDeviceAcceptable, &pUserContext );
g_pDXUTD3D11Enumeration->SetForceFeatureLevel(forceFL);
g_pDXUTD3D11Enumeration->Enumerate( pCallbackIsDeviceAcceptable, pUserContext );
}
return g_pDXUTD3D11Enumeration;
}
//--------------------------------------------------------------------------------------
CD3D11Enumeration::CD3D11Enumeration()
{
m_bHasEnumerated = false;
m_IsD3D11DeviceAcceptableFunc = NULL;
m_pIsD3D11DeviceAcceptableFuncUserContext = NULL;
m_nMinWidth = 640;
m_nMinHeight = 480;
m_nMaxWidth = UINT_MAX;
m_nMaxHeight = UINT_MAX;
m_bEnumerateAllAdapterFormats = false;
m_nRefreshMin = 0;
m_nRefreshMax = UINT_MAX;
ResetPossibleDepthStencilFormats();
}
//--------------------------------------------------------------------------------------
CD3D11Enumeration::~CD3D11Enumeration()
{
ClearAdapterInfoList();
}
//--------------------------------------------------------------------------------------
// Enumerate for each adapter all of the supported display modes,
// device types, adapter formats, back buffer formats, window/full screen support,
// depth stencil formats, multisampling types/qualities, and presentations intervals.
//
// For each combination of device type (HAL/REF), adapter format, back buffer format, and
// IsWindowed it will call the app's ConfirmDevice callback. This allows the app
// to reject or allow that combination based on its caps/etc. It also allows the
// app to change the BehaviorFlags. The BehaviorFlags defaults non-pure HWVP
// if supported otherwise it will default to SWVP, however the app can change this
// through the ConfirmDevice callback.
//--------------------------------------------------------------------------------------
HRESULT CD3D11Enumeration::Enumerate( LPDXUTCALLBACKISD3D11DEVICEACCEPTABLE IsD3D11DeviceAcceptableFunc,
void* pIsD3D11DeviceAcceptableFuncUserContext )
{
CDXUTPerfEventGenerator eventGenerator( DXUT_PERFEVENTCOLOR, L"DXUT D3D11 Enumeration" );
HRESULT hr;
IDXGIFactory1* pFactory = DXUTGetDXGIFactory();
if( pFactory == NULL )
return E_FAIL;
m_bHasEnumerated = true;
m_IsD3D11DeviceAcceptableFunc = IsD3D11DeviceAcceptableFunc;
m_pIsD3D11DeviceAcceptableFuncUserContext = pIsD3D11DeviceAcceptableFuncUserContext;
ClearAdapterInfoList();
for( int index = 0; ; ++index )
{
IDXGIAdapter* pAdapter = NULL;
hr = pFactory->EnumAdapters( index, &pAdapter );
if( FAILED( hr ) ) // DXGIERR_NOT_FOUND is expected when the end of the list is hit
break;
CD3D11EnumAdapterInfo* pAdapterInfo = new CD3D11EnumAdapterInfo;
if( !pAdapterInfo )
{
SAFE_RELEASE( pAdapter );
return E_OUTOFMEMORY;
}
ZeroMemory( pAdapterInfo, sizeof( CD3D11EnumAdapterInfo ) );
pAdapterInfo->AdapterOrdinal = index;
pAdapter->GetDesc( &pAdapterInfo->AdapterDesc );
pAdapterInfo->m_pAdapter = pAdapter;
// Enumerate the device driver types on the adapter.
hr = EnumerateDevices( pAdapterInfo );
if( FAILED( hr ) )
{
delete pAdapterInfo;
continue;
}
hr = EnumerateOutputs( pAdapterInfo );
if( FAILED( hr ) || pAdapterInfo->outputInfoList.GetSize() <= 0 )
{
delete pAdapterInfo;
continue;
}
// Get info for each devicecombo on this device
if( FAILED( hr = EnumerateDeviceCombos( pFactory, pAdapterInfo ) ) )
{
delete pAdapterInfo;
continue;
}
hr = m_AdapterInfoList.Add( pAdapterInfo );
if( FAILED( hr ) )
{
delete pAdapterInfo;
return hr;
}
}
// If we did not get an adapter then we should still enumerate WARP and Ref.
if (m_AdapterInfoList.GetSize() == 0) {
CD3D11EnumAdapterInfo* pAdapterInfo = new CD3D11EnumAdapterInfo;
if( !pAdapterInfo )
{
return E_OUTOFMEMORY;
}
ZeroMemory( pAdapterInfo, sizeof( CD3D11EnumAdapterInfo ) );
pAdapterInfo->bAdapterUnavailable = true;
hr = EnumerateDevices( pAdapterInfo );
// Get info for each devicecombo on this device
if( FAILED( hr = EnumerateDeviceCombosNoAdapter( pAdapterInfo ) ) )
{
delete pAdapterInfo;
}
if (!FAILED(hr)) hr = m_AdapterInfoList.Add( pAdapterInfo );
}
//
// Check for 2 or more adapters with the same name. Append the name
// with some instance number if that's the case to help distinguish
// them.
//
bool bUniqueDesc = true;
CD3D11EnumAdapterInfo* pAdapterInfo;
for( int i = 0; i < m_AdapterInfoList.GetSize(); i++ )
{
CD3D11EnumAdapterInfo* pAdapterInfo1 = m_AdapterInfoList.GetAt( i );
for( int j = i + 1; j < m_AdapterInfoList.GetSize(); j++ )
{
CD3D11EnumAdapterInfo* pAdapterInfo2 = m_AdapterInfoList.GetAt( j );
if( wcsncmp( pAdapterInfo1->AdapterDesc.Description,
pAdapterInfo2->AdapterDesc.Description, DXGI_MAX_DEVICE_IDENTIFIER_STRING ) == 0 )
{
bUniqueDesc = false;
break;
}
}
if( !bUniqueDesc )
break;
}
for( int i = 0; i < m_AdapterInfoList.GetSize(); i++ )
{
pAdapterInfo = m_AdapterInfoList.GetAt( i );
wcscpy_s( pAdapterInfo->szUniqueDescription, 100, pAdapterInfo->AdapterDesc.Description );
if( !bUniqueDesc )
{
WCHAR sz[100];
swprintf_s( sz, 100, L" (#%d)", pAdapterInfo->AdapterOrdinal );
wcscat_s( pAdapterInfo->szUniqueDescription, DXGI_MAX_DEVICE_IDENTIFIER_STRING, sz );
}
}
return S_OK;
}
//--------------------------------------------------------------------------------------
HRESULT CD3D11Enumeration::EnumerateOutputs( CD3D11EnumAdapterInfo* pAdapterInfo )
{
HRESULT hr;
IDXGIOutput* pOutput;
for( int iOutput = 0; ; ++iOutput )
{
pOutput = NULL;
hr = pAdapterInfo->m_pAdapter->EnumOutputs( iOutput, &pOutput );
if( DXGI_ERROR_NOT_FOUND == hr )
{
return S_OK;
}
else if( FAILED( hr ) )
{
return hr; //Something bad happened.
}
else //Success!
{
CD3D11EnumOutputInfo* pOutputInfo = new CD3D11EnumOutputInfo;
if( !pOutputInfo )
{
SAFE_RELEASE( pOutput );
return E_OUTOFMEMORY;
}
ZeroMemory( pOutputInfo, sizeof( CD3D11EnumOutputInfo ) );
pOutput->GetDesc( &pOutputInfo->Desc );
pOutputInfo->Output = iOutput;
pOutputInfo->m_pOutput = pOutput;
EnumerateDisplayModes( pOutputInfo );
if( pOutputInfo->displayModeList.GetSize() <= 0 )
{
// If this output has no valid display mode, do not save it.
delete pOutputInfo;
continue;
}
hr = pAdapterInfo->outputInfoList.Add( pOutputInfo );
if( FAILED( hr ) )
{
delete pOutputInfo;
return hr;
}
}
}
}
//--------------------------------------------------------------------------------------
HRESULT CD3D11Enumeration::EnumerateDisplayModes( CD3D11EnumOutputInfo* pOutputInfo )
{
HRESULT hr = S_OK;
DXGI_FORMAT allowedAdapterFormatArray[] =
{
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, //This is DXUT's preferred mode
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_R16G16B16A16_FLOAT,
DXGI_FORMAT_R10G10B10A2_UNORM
};
int allowedAdapterFormatArrayCount = sizeof( allowedAdapterFormatArray ) / sizeof( allowedAdapterFormatArray[0] );
// Swap perferred modes for apps running in linear space
DXGI_FORMAT RemoteMode = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
if( !DXUTIsInGammaCorrectMode() )
{
allowedAdapterFormatArray[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
allowedAdapterFormatArray[1] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
RemoteMode = DXGI_FORMAT_R8G8B8A8_UNORM;
}
// The fast path only enumerates R8G8B8A8_UNORM_SRGB modes
if( !m_bEnumerateAllAdapterFormats )
allowedAdapterFormatArrayCount = 1;
for( int f = 0; f < allowedAdapterFormatArrayCount; ++f )
{
// Fast-path: Try to grab at least 512 modes.
// This is to avoid calling GetDisplayModeList more times than necessary.
// GetDisplayModeList is an expensive call.
UINT NumModes = 512;
DXGI_MODE_DESC* pDesc = new DXGI_MODE_DESC[ NumModes ];
assert( pDesc );
if( !pDesc )
return E_OUTOFMEMORY;
hr = pOutputInfo->m_pOutput->GetDisplayModeList( allowedAdapterFormatArray[f],
DXGI_ENUM_MODES_SCALING,
&NumModes,
pDesc );
if( DXGI_ERROR_NOT_FOUND == hr )
{
SAFE_DELETE_ARRAY( pDesc );
NumModes = 0;
break;
}
else if( MAKE_DXGI_HRESULT( 34 ) == hr && RemoteMode == allowedAdapterFormatArray[f] )
{
// DXGI cannot enumerate display modes over a remote session. Therefore, create a fake display
// mode for the current screen resolution for the remote session.
if( 0 != GetSystemMetrics( 0x1000 ) ) // SM_REMOTESESSION
{
DEVMODE DevMode;
DevMode.dmSize = sizeof( DEVMODE );
if( EnumDisplaySettings( NULL, ENUM_CURRENT_SETTINGS, &DevMode ) )
{
NumModes = 1;
pDesc[0].Width = DevMode.dmPelsWidth;
pDesc[0].Height = DevMode.dmPelsHeight;
pDesc[0].Format = DXGI_FORMAT_R8G8B8A8_UNORM;
pDesc[0].RefreshRate.Numerator = 60;
pDesc[0].RefreshRate.Denominator = 1;
pDesc[0].ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
pDesc[0].Scaling = DXGI_MODE_SCALING_CENTERED;
hr = S_OK;
}
}
}
else if( DXGI_ERROR_MORE_DATA == hr )
{
// Slow path. There were more than 512 modes.
SAFE_DELETE_ARRAY( pDesc );
hr = pOutputInfo->m_pOutput->GetDisplayModeList( allowedAdapterFormatArray[f],
DXGI_ENUM_MODES_SCALING,
&NumModes,
NULL );
if( FAILED( hr ) )
{
NumModes = 0;
break;
}
pDesc = new DXGI_MODE_DESC[ NumModes ];
assert( pDesc );
if( !pDesc )
return E_OUTOFMEMORY;
hr = pOutputInfo->m_pOutput->GetDisplayModeList( allowedAdapterFormatArray[f],
DXGI_ENUM_MODES_SCALING,
&NumModes,
pDesc );
if( FAILED( hr ) )
{
SAFE_DELETE_ARRAY( pDesc );
NumModes = 0;
break;
}
}
if( 0 == NumModes && 0 == f )
{
// No R8G8B8A8_UNORM_SRGB modes!
// Abort the fast-path if we're on it
allowedAdapterFormatArrayCount = sizeof( allowedAdapterFormatArray ) / sizeof
( allowedAdapterFormatArray[0] );
SAFE_DELETE_ARRAY( pDesc );
continue;
}
if( SUCCEEDED( hr ) )
{
for( UINT m = 0; m < NumModes; m++ )
{
pOutputInfo->displayModeList.Add( pDesc[m] );
}
}
SAFE_DELETE_ARRAY( pDesc );
}
return hr;
}
//--------------------------------------------------------------------------------------
HRESULT CD3D11Enumeration::EnumerateDevices( CD3D11EnumAdapterInfo* pAdapterInfo )
{
HRESULT hr;
DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
const D3D_DRIVER_TYPE devTypeArray[] =
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE
};
const UINT devTypeArrayCount = sizeof( devTypeArray ) / sizeof( devTypeArray[0] );
// Enumerate each Direct3D device type
for( UINT iDeviceType = 0; iDeviceType < devTypeArrayCount; iDeviceType++ )
{
CD3D11EnumDeviceInfo* pDeviceInfo = new CD3D11EnumDeviceInfo;
if( pDeviceInfo == NULL )
return E_OUTOFMEMORY;
// Fill struct w/ AdapterOrdinal and D3DX10_DRIVER_TYPE
pDeviceInfo->AdapterOrdinal = pAdapterInfo->AdapterOrdinal;
pDeviceInfo->DeviceType = devTypeArray[iDeviceType];
D3D_FEATURE_LEVEL FeatureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1
};
UINT NumFeatureLevels = ARRAYSIZE( FeatureLevels );
// Call D3D11CreateDevice to ensure that this is a D3D11 device.
ID3D11Device* pd3dDevice = NULL;
ID3D11DeviceContext* pd3dDeviceContext = NULL;
IDXGIAdapter* pAdapter = NULL;
//if( devTypeArray[iDeviceType] == D3D_DRIVER_TYPE_HARDWARE )
// pAdapter = pAdapterInfo->m_pAdapter;
hr = DXUT_Dynamic_D3D11CreateDevice( pAdapter,
devTypeArray[iDeviceType],
( HMODULE )0,
0,
FeatureLevels,
NumFeatureLevels,
D3D11_SDK_VERSION,
&pd3dDevice,
&pDeviceInfo->MaxLevel,
&pd3dDeviceContext );
if( FAILED( hr ) || pDeviceInfo->MaxLevel < deviceSettings.MinimumFeatureLevel)
{
delete pDeviceInfo;
continue;
}
if (g_forceFL == 0 || g_forceFL == pDeviceInfo->MaxLevel) {
pDeviceInfo->SelectedLevel = pDeviceInfo->MaxLevel;
}
else if (g_forceFL > pDeviceInfo->MaxLevel) {
delete pDeviceInfo;
SAFE_RELEASE( pd3dDevice );
SAFE_RELEASE( pd3dDeviceContext );
continue;
} else {
// A device was created with a higher feature level that the user-specified feature level.
SAFE_RELEASE( pd3dDevice );
SAFE_RELEASE( pd3dDeviceContext );
D3D_FEATURE_LEVEL rtFL;
hr = DXUT_Dynamic_D3D11CreateDevice( pAdapter,
devTypeArray[iDeviceType],
( HMODULE )0,
0,
&g_forceFL,
1,
D3D11_SDK_VERSION,
&pd3dDevice,
&rtFL,
&pd3dDeviceContext );
if( !FAILED( hr ) && rtFL == g_forceFL ) {
pDeviceInfo->SelectedLevel = g_forceFL;
}else {
delete pDeviceInfo;
SAFE_RELEASE( pd3dDevice );
SAFE_RELEASE( pd3dDeviceContext );
continue;
}
}
IDXGIDevice1* pDXGIDev = NULL;
hr = pd3dDevice->QueryInterface( __uuidof( IDXGIDevice1 ), ( LPVOID* )&pDXGIDev );
if( SUCCEEDED( hr ) && pDXGIDev )
{
SAFE_RELEASE( pAdapterInfo->m_pAdapter );
pDXGIDev->GetAdapter( &pAdapterInfo->m_pAdapter );
}
SAFE_RELEASE( pDXGIDev );
D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS ho;
pd3dDevice->CheckFeatureSupport(D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, &ho, sizeof(ho));
pDeviceInfo->ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x = ho.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x;
SAFE_RELEASE( pd3dDeviceContext );
SAFE_RELEASE( pd3dDevice );
pAdapterInfo->deviceInfoList.Add( pDeviceInfo );
}
return S_OK;
}
HRESULT CD3D11Enumeration::EnumerateDeviceCombosNoAdapter( CD3D11EnumAdapterInfo* pAdapterInfo )
{
// Iterate through each combination of device driver type, output,
// adapter format, and backbuffer format to build the adapter's device combo list.
//
for( int device = 0; device < pAdapterInfo->deviceInfoList.GetSize(); ++device )
{
CD3D11EnumDeviceInfo* pDeviceInfo = pAdapterInfo->deviceInfoList.GetAt( device );
DXGI_FORMAT BufferFormatArray[] =
{
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, //This is DXUT's preferred mode
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_R16G16B16A16_FLOAT,
DXGI_FORMAT_R10G10B10A2_UNORM
};
const UINT BufferFormatArrayCount = sizeof( BufferFormatArray ) / sizeof
( BufferFormatArray[0] );
// Swap perferred modes for apps running in linear space
if( !DXUTIsInGammaCorrectMode() )
{
BufferFormatArray[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
BufferFormatArray[1] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
}
for( UINT iBufferFormat = 0; iBufferFormat < BufferFormatArrayCount; iBufferFormat++ )
{
DXGI_FORMAT BufferFormat = BufferFormatArray[iBufferFormat];
// determine if there are any modes for this particular format
// If an application callback function has been provided, make sure this device
// is acceptable to the app.
if( m_IsD3D11DeviceAcceptableFunc != NULL )
{
if( !m_IsD3D11DeviceAcceptableFunc( pAdapterInfo,
0,
pDeviceInfo,
BufferFormat,
TRUE,
m_pIsD3D11DeviceAcceptableFuncUserContext ) )
continue;
}
// At this point, we have an adapter/device/backbufferformat/iswindowed
// DeviceCombo that is supported by the system. We still
// need to find one or more suitable depth/stencil buffer format,
// multisample type, and present interval.
CD3D11EnumDeviceSettingsCombo* pDeviceCombo = new CD3D11EnumDeviceSettingsCombo;
if( pDeviceCombo == NULL )
return E_OUTOFMEMORY;
pDeviceCombo->AdapterOrdinal = pDeviceInfo->AdapterOrdinal;
pDeviceCombo->DeviceType = pDeviceInfo->DeviceType;
pDeviceCombo->BackBufferFormat = BufferFormat;
pDeviceCombo->Windowed = TRUE;
pDeviceCombo->Output = 0;
pDeviceCombo->pAdapterInfo = pAdapterInfo;
pDeviceCombo->pDeviceInfo = pDeviceInfo;
pDeviceCombo->pOutputInfo = NULL;
BuildMultiSampleQualityList( BufferFormat, pDeviceCombo );
if( FAILED( pAdapterInfo->deviceSettingsComboList.Add( pDeviceCombo ) ) )
delete pDeviceCombo;
}
}
return S_OK;
}
//--------------------------------------------------------------------------------------
HRESULT CD3D11Enumeration::EnumerateDeviceCombos( IDXGIFactory1* pFactory, CD3D11EnumAdapterInfo* pAdapterInfo )
{
// Iterate through each combination of device driver type, output,
// adapter format, and backbuffer format to build the adapter's device combo list.
//
for( int output = 0; output < pAdapterInfo->outputInfoList.GetSize(); ++output )
{
CD3D11EnumOutputInfo* pOutputInfo = pAdapterInfo->outputInfoList.GetAt( output );
for( int device = 0; device < pAdapterInfo->deviceInfoList.GetSize(); ++device )
{
CD3D11EnumDeviceInfo* pDeviceInfo = pAdapterInfo->deviceInfoList.GetAt( device );
DXGI_FORMAT backBufferFormatArray[] =
{
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, //This is DXUT's preferred mode
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_R16G16B16A16_FLOAT,
DXGI_FORMAT_R10G10B10A2_UNORM
};
const UINT backBufferFormatArrayCount = sizeof( backBufferFormatArray ) / sizeof
( backBufferFormatArray[0] );
// Swap perferred modes for apps running in linear space
if( !DXUTIsInGammaCorrectMode() )
{
backBufferFormatArray[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
backBufferFormatArray[1] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
}
for( UINT iBackBufferFormat = 0; iBackBufferFormat < backBufferFormatArrayCount; iBackBufferFormat++ )
{
DXGI_FORMAT backBufferFormat = backBufferFormatArray[iBackBufferFormat];
for( int nWindowed = 0; nWindowed < 2; nWindowed++ )
{
if( !nWindowed && pOutputInfo->displayModeList.GetSize() == 0 )
continue;
// determine if there are any modes for this particular format
UINT iModes = 0;
for( int i = 0; i < pOutputInfo->displayModeList.GetSize(); i++ )
{
if( backBufferFormat == pOutputInfo->displayModeList.GetAt( i ).Format )
iModes ++;
}
if( 0 == iModes )
continue;
// If an application callback function has been provided, make sure this device
// is acceptable to the app.
if( m_IsD3D11DeviceAcceptableFunc != NULL )
{
if( !m_IsD3D11DeviceAcceptableFunc( pAdapterInfo, output,
pDeviceInfo, backBufferFormat,
FALSE != nWindowed,
m_pIsD3D11DeviceAcceptableFuncUserContext ) )
continue;
}
// At this point, we have an adapter/device/backbufferformat/iswindowed
// DeviceCombo that is supported by the system. We still
// need to find one or more suitable depth/stencil buffer format,
// multisample type, and present interval.
CD3D11EnumDeviceSettingsCombo* pDeviceCombo = new CD3D11EnumDeviceSettingsCombo;
if( pDeviceCombo == NULL )
return E_OUTOFMEMORY;
pDeviceCombo->AdapterOrdinal = pDeviceInfo->AdapterOrdinal;
pDeviceCombo->DeviceType = pDeviceInfo->DeviceType;
pDeviceCombo->BackBufferFormat = backBufferFormat;
pDeviceCombo->Windowed = ( nWindowed != 0 );
pDeviceCombo->Output = pOutputInfo->Output;
pDeviceCombo->pAdapterInfo = pAdapterInfo;
pDeviceCombo->pDeviceInfo = pDeviceInfo;
pDeviceCombo->pOutputInfo = pOutputInfo;
BuildMultiSampleQualityList( backBufferFormat, pDeviceCombo );
if( FAILED( pAdapterInfo->deviceSettingsComboList.Add( pDeviceCombo ) ) )
delete pDeviceCombo;
}
}
}
}
return S_OK;
}
//--------------------------------------------------------------------------------------
// Release all the allocated CD3D11EnumAdapterInfo objects and empty the list
//--------------------------------------------------------------------------------------
void CD3D11Enumeration::ClearAdapterInfoList()
{
CD3D11EnumAdapterInfo* pAdapterInfo;
for( int i = 0; i < m_AdapterInfoList.GetSize(); i++ )
{
pAdapterInfo = m_AdapterInfoList.GetAt( i );
delete pAdapterInfo;
}
m_AdapterInfoList.RemoveAll();
}
//--------------------------------------------------------------------------------------
void CD3D11Enumeration::ResetPossibleDepthStencilFormats()
{
m_DepthStencilPossibleList.RemoveAll();
m_DepthStencilPossibleList.Add( DXGI_FORMAT_D32_FLOAT_S8X24_UINT );
m_DepthStencilPossibleList.Add( DXGI_FORMAT_D32_FLOAT );
m_DepthStencilPossibleList.Add( DXGI_FORMAT_D24_UNORM_S8_UINT );
m_DepthStencilPossibleList.Add( DXGI_FORMAT_D16_UNORM );
}
//--------------------------------------------------------------------------------------
void CD3D11Enumeration::SetEnumerateAllAdapterFormats( bool bEnumerateAllAdapterFormats )
{
m_bEnumerateAllAdapterFormats = bEnumerateAllAdapterFormats;
}
//--------------------------------------------------------------------------------------
void CD3D11Enumeration::BuildMultiSampleQualityList( DXGI_FORMAT fmt, CD3D11EnumDeviceSettingsCombo* pDeviceCombo )
{
ID3D11Device* pd3dDevice = NULL;
ID3D11DeviceContext* pd3dDeviceContext = NULL;
IDXGIAdapter* pAdapter = NULL;
//if( pDeviceCombo->DeviceType == D3D_DRIVER_TYPE_HARDWARE )
// DXUTGetDXGIFactory()->EnumAdapters( pDeviceCombo->pAdapterInfo->AdapterOrdinal, &pAdapter );
//DXGI_ADAPTER_DESC dad;
//pAdapter->GetDesc(&dad);
D3D_FEATURE_LEVEL *FeatureLevels = &(pDeviceCombo->pDeviceInfo->SelectedLevel);
D3D_FEATURE_LEVEL returnedFeatureLevel;
UINT NumFeatureLevels = 1;
HRESULT hr = DXUT_Dynamic_D3D11CreateDevice( pAdapter,
pDeviceCombo->DeviceType,
( HMODULE )0,
0,
FeatureLevels,
NumFeatureLevels,
D3D11_SDK_VERSION,
&pd3dDevice,
&returnedFeatureLevel,
&pd3dDeviceContext ) ;
if( FAILED( hr)) return;
if (returnedFeatureLevel != pDeviceCombo->pDeviceInfo->SelectedLevel) return;
for( int i = 1; i <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; ++i )
{
UINT Quality;
if( SUCCEEDED( pd3dDevice->CheckMultisampleQualityLevels( fmt, i, &Quality ) ) && Quality > 0 )
{
//From D3D10 docs: When multisampling a texture, the number of quality levels available for an adapter is dependent on the texture
//format used and the number of samples requested. The maximum sample count is defined by
//D3D10_MAX_MULTISAMPLE_SAMPLE_COUNT in d3d10.h. If the returned value of pNumQualityLevels is 0,
//the format and sample count combination is not supported for the installed adapter.
if (Quality != 0) {
pDeviceCombo->multiSampleCountList.Add( i );
pDeviceCombo->multiSampleQualityList.Add( Quality );
}
}
}
SAFE_RELEASE( pAdapter );
SAFE_RELEASE( pd3dDevice );
SAFE_RELEASE (pd3dDeviceContext);
}
//--------------------------------------------------------------------------------------
// Call GetAdapterInfoList() after Enumerate() to get a STL vector of
// CD3D11EnumAdapterInfo*
//--------------------------------------------------------------------------------------
CGrowableArray <CD3D11EnumAdapterInfo*>* CD3D11Enumeration::GetAdapterInfoList()
{
return &m_AdapterInfoList;
}
//--------------------------------------------------------------------------------------
CD3D11EnumAdapterInfo* CD3D11Enumeration::GetAdapterInfo( UINT AdapterOrdinal )
{
for( int iAdapter = 0; iAdapter < m_AdapterInfoList.GetSize(); iAdapter++ )
{
CD3D11EnumAdapterInfo* pAdapterInfo = m_AdapterInfoList.GetAt( iAdapter );
if( pAdapterInfo->AdapterOrdinal == AdapterOrdinal )
return pAdapterInfo;
}
return NULL;
}
//--------------------------------------------------------------------------------------
CD3D11EnumDeviceInfo* CD3D11Enumeration::GetDeviceInfo( UINT AdapterOrdinal, D3D_DRIVER_TYPE DeviceType )
{
CD3D11EnumAdapterInfo* pAdapterInfo = GetAdapterInfo( AdapterOrdinal );
if( pAdapterInfo )
{
for( int iDeviceInfo = 0; iDeviceInfo < pAdapterInfo->deviceInfoList.GetSize(); iDeviceInfo++ )
{
CD3D11EnumDeviceInfo* pDeviceInfo = pAdapterInfo->deviceInfoList.GetAt( iDeviceInfo );
if( pDeviceInfo->DeviceType == DeviceType )
return pDeviceInfo;
}
}
return NULL;
}
//--------------------------------------------------------------------------------------
CD3D11EnumOutputInfo* CD3D11Enumeration::GetOutputInfo( UINT AdapterOrdinal, UINT Output )
{
CD3D11EnumAdapterInfo* pAdapterInfo = GetAdapterInfo( AdapterOrdinal );
if( pAdapterInfo && pAdapterInfo->outputInfoList.GetSize() > int( Output ) )
{
return pAdapterInfo->outputInfoList.GetAt( Output );
}
return NULL;
}
//--------------------------------------------------------------------------------------
CD3D11EnumDeviceSettingsCombo* CD3D11Enumeration::GetDeviceSettingsCombo( UINT AdapterOrdinal,
D3D_DRIVER_TYPE DeviceType, UINT Output,
DXGI_FORMAT BackBufferFormat, BOOL Windowed )
{
CD3D11EnumAdapterInfo* pAdapterInfo = GetAdapterInfo( AdapterOrdinal );
if( pAdapterInfo )
{
for( int iDeviceCombo = 0; iDeviceCombo < pAdapterInfo->deviceSettingsComboList.GetSize(); iDeviceCombo++ )
{
CD3D11EnumDeviceSettingsCombo* pDeviceSettingsCombo = pAdapterInfo->deviceSettingsComboList.GetAt(
iDeviceCombo );
if( pDeviceSettingsCombo->BackBufferFormat == BackBufferFormat &&
pDeviceSettingsCombo->Windowed == Windowed )
return pDeviceSettingsCombo;
}
}
return NULL;
}
//--------------------------------------------------------------------------------------
CD3D11EnumOutputInfo::~CD3D11EnumOutputInfo( void )
{
SAFE_RELEASE( m_pOutput );
displayModeList.RemoveAll();
}
//--------------------------------------------------------------------------------------
CD3D11EnumDeviceInfo::~CD3D11EnumDeviceInfo()
{
}
//--------------------------------------------------------------------------------------
CD3D11EnumAdapterInfo::~CD3D11EnumAdapterInfo( void )
{
for( int i = 0; i < outputInfoList.GetSize(); i++ )
{
CD3D11EnumOutputInfo* pOutputInfo = outputInfoList.GetAt( i );
delete pOutputInfo;
}
outputInfoList.RemoveAll();
for( int i = 0; i < deviceInfoList.GetSize(); ++i )
{
CD3D11EnumDeviceInfo* pDeviceInfo = deviceInfoList.GetAt( i );
delete pDeviceInfo;
}
deviceInfoList.RemoveAll();
for( int i = 0; i < deviceSettingsComboList.GetSize(); ++i )
{
CD3D11EnumDeviceSettingsCombo* pDeviceCombo = deviceSettingsComboList.GetAt( i );
delete pDeviceCombo;
}
deviceSettingsComboList.RemoveAll();
SAFE_RELEASE( m_pAdapter );
}
//--------------------------------------------------------------------------------------
// Returns the number of color channel bits in the specified DXGI_FORMAT
//--------------------------------------------------------------------------------------
UINT WINAPI DXUTGetDXGIColorChannelBits( DXGI_FORMAT fmt )
{
switch( fmt )
{
case DXGI_FORMAT_R32G32B32A32_TYPELESS:
case DXGI_FORMAT_R32G32B32A32_FLOAT:
case DXGI_FORMAT_R32G32B32A32_UINT:
case DXGI_FORMAT_R32G32B32A32_SINT:
case DXGI_FORMAT_R32G32B32_TYPELESS:
case DXGI_FORMAT_R32G32B32_FLOAT:
case DXGI_FORMAT_R32G32B32_UINT:
case DXGI_FORMAT_R32G32B32_SINT:
return 32;
case DXGI_FORMAT_R16G16B16A16_TYPELESS:
case DXGI_FORMAT_R16G16B16A16_FLOAT:
case DXGI_FORMAT_R16G16B16A16_UNORM:
case DXGI_FORMAT_R16G16B16A16_UINT:
case DXGI_FORMAT_R16G16B16A16_SNORM:
case DXGI_FORMAT_R16G16B16A16_SINT:
return 16;
case DXGI_FORMAT_R10G10B10A2_TYPELESS:
case DXGI_FORMAT_R10G10B10A2_UNORM:
case DXGI_FORMAT_R10G10B10A2_UINT:
return 10;
case DXGI_FORMAT_R8G8B8A8_TYPELESS:
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
case DXGI_FORMAT_R8G8B8A8_UINT:
case DXGI_FORMAT_R8G8B8A8_SNORM:
case DXGI_FORMAT_R8G8B8A8_SINT:
return 8;
case DXGI_FORMAT_B5G6R5_UNORM:
case DXGI_FORMAT_B5G5R5A1_UNORM:
return 5;
default:
return 0;
}
}
//--------------------------------------------------------------------------------------
// Returns a ranking number that describes how closely this device
// combo matches the optimal combo based on the match options and the optimal device settings
//--------------------------------------------------------------------------------------
float DXUTRankD3D11DeviceCombo( CD3D11EnumDeviceSettingsCombo* pDeviceSettingsCombo,
DXUTD3D11DeviceSettings* pOptimalDeviceSettings,
DXGI_MODE_DESC* pAdapterDisplayMode,
int &bestModeIndex,
int &bestMSAAIndex
)
{
float fCurRanking = 0.0f;
// Arbitrary weights. Gives preference to the ordinal, device type, and windowed
const float fAdapterOrdinalWeight = 1000.0f;
const float fAdapterOutputWeight = 500.0f;
const float fDeviceTypeWeight = 100.0f;
const float fWARPOverRefWeight = 80.0f;
const float fWindowWeight = 10.0f;
const float fResolutionWeight = 1.0f;
const float fBackBufferFormatWeight = 1.0f;
const float fMultiSampleWeight = 1.0f;
const float fRefreshRateWeight = 1.0f;
//---------------------
// Adapter ordinal
//---------------------
if( pDeviceSettingsCombo->AdapterOrdinal == pOptimalDeviceSettings->AdapterOrdinal )
fCurRanking += fAdapterOrdinalWeight;
//---------------------
// Adapter ordinal
//---------------------
if( pDeviceSettingsCombo->Output == pOptimalDeviceSettings->Output )
fCurRanking += fAdapterOutputWeight;
//---------------------
// Device type
//---------------------
if( pDeviceSettingsCombo->DeviceType == pOptimalDeviceSettings->DriverType )
fCurRanking += fDeviceTypeWeight;
else if (pDeviceSettingsCombo->DeviceType == D3D_DRIVER_TYPE_WARP && pOptimalDeviceSettings->DriverType == D3D_DRIVER_TYPE_HARDWARE) {
fCurRanking += fWARPOverRefWeight;
}
// Slightly prefer HAL
if( pDeviceSettingsCombo->DeviceType == D3DDEVTYPE_HAL )
fCurRanking += 0.1f;
//---------------------
// Windowed
//---------------------
if( pDeviceSettingsCombo->Windowed == pOptimalDeviceSettings->sd.Windowed )
fCurRanking += fWindowWeight;
//---------------------
// Resolution
//---------------------
bool bResolutionFound = false;
unsigned int best = 0xffffffff;
bestModeIndex=0;
for( int idm = 0; pDeviceSettingsCombo->pOutputInfo != NULL && idm < pDeviceSettingsCombo->pOutputInfo->displayModeList.GetSize() && !bResolutionFound; idm++ )
{
DXGI_MODE_DESC displayMode = pDeviceSettingsCombo->pOutputInfo->displayModeList.GetAt( idm );
if( displayMode.Width == pOptimalDeviceSettings->sd.BufferDesc.Width &&
displayMode.Height == pOptimalDeviceSettings->sd.BufferDesc.Height )
bResolutionFound = true;
unsigned int current =
(UINT) abs ((int)displayMode.Width - (int)pOptimalDeviceSettings->sd.BufferDesc.Width) +
(UINT) abs ((int)displayMode.Height - (int)pOptimalDeviceSettings->sd.BufferDesc.Height );
if (current < best) {
best = current;
bestModeIndex= idm;
}
}
if( bResolutionFound )
fCurRanking += fResolutionWeight;
//---------------------
// Back buffer format
//---------------------
if( pDeviceSettingsCombo->BackBufferFormat == pOptimalDeviceSettings->sd.BufferDesc.Format )
{
fCurRanking += fBackBufferFormatWeight;
}
else
{
int nBitDepthDelta = abs( ( long )DXUTGetDXGIColorChannelBits( pDeviceSettingsCombo->BackBufferFormat ) -
( long )DXUTGetDXGIColorChannelBits(
pOptimalDeviceSettings->sd.BufferDesc.Format ) );
float fScale = __max( 0.9f - ( float )nBitDepthDelta * 0.2f, 0.0f );
fCurRanking += fScale * fBackBufferFormatWeight;
}
//---------------------
// Back buffer count
//---------------------
// No caps for the back buffer count
//---------------------
// Multisample
//---------------------
bool bMultiSampleFound = false;
bestMSAAIndex = 0;
for( int i = 0; i < pDeviceSettingsCombo->multiSampleCountList.GetSize(); i++ )
{
UINT Count = pDeviceSettingsCombo->multiSampleCountList.GetAt( i );
if( Count == pOptimalDeviceSettings->sd.SampleDesc.Count )
{
bestMSAAIndex = i;
bMultiSampleFound = true;
break;
}
}
if( bMultiSampleFound )
fCurRanking += fMultiSampleWeight;
//---------------------
// Swap effect
//---------------------
// No caps for swap effects
//---------------------
// Depth stencil
//---------------------
// No caps for swap effects
//---------------------
// Present flags
//---------------------
// No caps for the present flags
//---------------------
// Refresh rate
//---------------------
bool bRefreshFound = false;
for( int idm = 0; pDeviceSettingsCombo->pOutputInfo != NULL && idm < pDeviceSettingsCombo->pOutputInfo->displayModeList.GetSize(); idm++ )
{
DXGI_MODE_DESC displayMode = pDeviceSettingsCombo->pOutputInfo->displayModeList.GetAt( idm );
if( fabs( float( displayMode.RefreshRate.Numerator ) / displayMode.RefreshRate.Denominator -
float( pOptimalDeviceSettings->sd.BufferDesc.RefreshRate.Numerator ) /
pOptimalDeviceSettings->sd.BufferDesc.RefreshRate.Denominator ) < 0.1f )
bRefreshFound = true;
}
if( bRefreshFound )
fCurRanking += fRefreshRateWeight;
//---------------------
// Present interval
//---------------------
// No caps for the present flags
return fCurRanking;
}
//--------------------------------------------------------------------------------------
// Returns the DXGI_MODE_DESC struct for a given adapter and output
//--------------------------------------------------------------------------------------
HRESULT WINAPI DXUTGetD3D11AdapterDisplayMode( UINT AdapterOrdinal, UINT nOutput, DXGI_MODE_DESC* pModeDesc )
{
if( !pModeDesc )
return E_INVALIDARG;
CD3D11Enumeration* pD3DEnum = DXUTGetD3D11Enumeration();
CD3D11EnumOutputInfo* pOutputInfo = pD3DEnum->GetOutputInfo( AdapterOrdinal, nOutput );
if( pOutputInfo )
{
pModeDesc->Width = 640;
pModeDesc->Height = 480;
pModeDesc->RefreshRate.Numerator = 60;
pModeDesc->RefreshRate.Denominator = 1;
pModeDesc->Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
pModeDesc->Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
pModeDesc->ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
DXGI_OUTPUT_DESC Desc;
pOutputInfo->m_pOutput->GetDesc( &Desc );
pModeDesc->Width = Desc.DesktopCoordinates.right - Desc.DesktopCoordinates.left;
pModeDesc->Height = Desc.DesktopCoordinates.bottom - Desc.DesktopCoordinates.top;
}
// TODO: verify this is needed
if( pModeDesc->Format == DXGI_FORMAT_B8G8R8A8_UNORM )
pModeDesc->Format = DXGI_FORMAT_R8G8B8A8_UNORM;
return S_OK;
}