2016-01-08 03:40:35 +00:00
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
# include <algorithm>
2016-02-16 06:21:22 +00:00
# include <memory>
2016-01-08 03:40:35 +00:00
# include "Common/CommonTypes.h"
# include "Common/MsgHandler.h"
# include "Common/StringUtil.h"
# include "Common/Logging/Log.h"
# include "VideoBackends/D3D12/D3DBase.h"
# include "VideoBackends/D3D12/D3DCommandListManager.h"
# include "VideoBackends/D3D12/D3DDescriptorHeapManager.h"
# include "VideoBackends/D3D12/D3DState.h"
# include "VideoBackends/D3D12/D3DTexture.h"
# include "VideoCommon/VideoConfig.h"
static const unsigned int SWAP_CHAIN_BUFFER_COUNT = 4 ;
namespace DX12
{
// d3dcompiler_*.dll exports
static HINSTANCE s_d3d_compiler_dll = nullptr ;
static int s_d3d_compiler_dll_ref = 0 ;
D3DREFLECT d3d_reflect = nullptr ;
D3DCREATEBLOB d3d_create_blob = nullptr ;
pD3DCompile d3d_compile = nullptr ;
// dxgi.dll exports
static HINSTANCE s_dxgi_dll = nullptr ;
static int s_dxgi_dll_ref = 0 ;
CREATEDXGIFACTORY create_dxgi_factory = nullptr ;
// d3d12.dll exports
static HINSTANCE s_d3d12_dll = nullptr ;
static int s_d3d12_dll_ref = 0 ;
D3D12CREATEDEVICE d3d12_create_device = nullptr ;
D3D12SERIALIZEROOTSIGNATURE d3d12_serialize_root_signature = nullptr ;
D3D12GETDEBUGINTERFACE d3d12_get_debug_interface = nullptr ;
namespace D3D
{
// Begin extern'd variables.
ID3D12Device * device12 = nullptr ;
ID3D12CommandQueue * command_queue = nullptr ;
2016-02-16 06:21:22 +00:00
std : : unique_ptr < D3DCommandListManager > command_list_mgr ;
2016-01-08 03:40:35 +00:00
ID3D12GraphicsCommandList * current_command_list = nullptr ;
ID3D12RootSignature * default_root_signature = nullptr ;
D3D12_CPU_DESCRIPTOR_HANDLE null_srv_cpu = { } ;
D3D12_CPU_DESCRIPTOR_HANDLE null_srv_cpu_shadow = { } ;
unsigned int resource_descriptor_size = 0 ;
unsigned int sampler_descriptor_size = 0 ;
2016-02-16 06:21:22 +00:00
std : : unique_ptr < D3DDescriptorHeapManager > gpu_descriptor_heap_mgr ;
std : : unique_ptr < D3DDescriptorHeapManager > sampler_descriptor_heap_mgr ;
std : : unique_ptr < D3DDescriptorHeapManager > dsv_descriptor_heap_mgr ;
std : : unique_ptr < D3DDescriptorHeapManager > rtv_descriptor_heap_mgr ;
2016-01-08 03:40:35 +00:00
std : : array < ID3D12DescriptorHeap * , 2 > gpu_descriptor_heaps ;
HWND hWnd ;
// End extern'd variables.
static IDXGISwapChain * s_swap_chain = nullptr ;
static unsigned int s_monitor_refresh_rate = 0 ;
static LARGE_INTEGER s_qpc_frequency ;
static ID3D12DebugDevice * s_debug_device12 = nullptr ;
static D3D_FEATURE_LEVEL s_feat_level ;
static D3DTexture2D * s_backbuf [ SWAP_CHAIN_BUFFER_COUNT ] ;
static unsigned int s_current_back_buf = 0 ;
static unsigned int s_xres = 0 ;
static unsigned int s_yres = 0 ;
static bool s_frame_in_progress = false ;
static std : : vector < DXGI_SAMPLE_DESC > s_aa_modes ; // supported AA modes of the current adapter
static const D3D_FEATURE_LEVEL s_supported_feature_levels [ ] = {
D3D_FEATURE_LEVEL_11_0
} ;
HRESULT LoadDXGI ( )
{
if ( s_dxgi_dll_ref + + > 0 )
return S_OK ;
if ( s_dxgi_dll )
return S_OK ;
s_dxgi_dll = LoadLibraryA ( " dxgi.dll " ) ;
if ( ! s_dxgi_dll )
{
MessageBoxA ( nullptr , " Failed to load dxgi.dll " , " Critical error " , MB_OK | MB_ICONERROR ) ;
- - s_dxgi_dll_ref ;
return E_FAIL ;
}
create_dxgi_factory = ( CREATEDXGIFACTORY ) GetProcAddress ( s_dxgi_dll , " CreateDXGIFactory " ) ;
if ( create_dxgi_factory = = nullptr )
MessageBoxA ( nullptr , " GetProcAddress failed for CreateDXGIFactory! " , " Critical error " , MB_OK | MB_ICONERROR ) ;
return S_OK ;
}
HRESULT LoadD3D ( )
{
if ( s_d3d12_dll_ref + + > 0 )
return S_OK ;
s_d3d12_dll = LoadLibraryA ( " d3d12.dll " ) ;
if ( ! s_d3d12_dll )
{
MessageBoxA ( nullptr , " Failed to load d3d12.dll " , " Critical error " , MB_OK | MB_ICONERROR ) ;
- - s_d3d12_dll_ref ;
return E_FAIL ;
}
d3d12_create_device = ( D3D12CREATEDEVICE ) GetProcAddress ( s_d3d12_dll , " D3D12CreateDevice " ) ;
if ( d3d12_create_device = = nullptr )
{
MessageBoxA ( nullptr , " GetProcAddress failed for D3D12CreateDevice! " , " Critical error " , MB_OK | MB_ICONERROR ) ;
return E_FAIL ;
}
d3d12_serialize_root_signature = ( D3D12SERIALIZEROOTSIGNATURE ) GetProcAddress ( s_d3d12_dll , " D3D12SerializeRootSignature " ) ;
if ( d3d12_serialize_root_signature = = nullptr )
{
MessageBoxA ( nullptr , " GetProcAddress failed for D3D12SerializeRootSignature! " , " Critical error " , MB_OK | MB_ICONERROR ) ;
return E_FAIL ;
}
d3d12_get_debug_interface = ( D3D12GETDEBUGINTERFACE ) GetProcAddress ( s_d3d12_dll , " D3D12GetDebugInterface " ) ;
if ( d3d12_get_debug_interface = = nullptr )
{
MessageBoxA ( nullptr , " GetProcAddress failed for D3D12GetDebugInterface! " , " Critical error " , MB_OK | MB_ICONERROR ) ;
return E_FAIL ;
}
return S_OK ;
}
HRESULT LoadD3DCompiler ( )
{
if ( s_d3d_compiler_dll_ref + + > 0 )
return S_OK ;
if ( s_d3d_compiler_dll )
return S_OK ;
// try to load D3DCompiler first to check whether we have proper runtime support
// try to use the dll the backend was compiled against first - don't bother about debug runtimes
s_d3d_compiler_dll = LoadLibraryA ( D3DCOMPILER_DLL_A ) ;
if ( ! s_d3d_compiler_dll )
{
// if that fails, use the dll which should be available in every SDK which officially supports DX12.
s_d3d_compiler_dll = LoadLibraryA ( " D3DCompiler_42.dll " ) ;
if ( ! s_d3d_compiler_dll )
{
MessageBoxA ( nullptr , " Failed to load D3DCompiler_42.dll, update your DX12 runtime, please " , " Critical error " , MB_OK | MB_ICONERROR ) ;
return E_FAIL ;
}
else
{
NOTICE_LOG ( VIDEO , " Successfully loaded D3DCompiler_42.dll. If you're having trouble, try updating your DX runtime first. " ) ;
}
}
d3d_reflect = ( D3DREFLECT ) GetProcAddress ( s_d3d_compiler_dll , " D3DReflect " ) ;
if ( d3d_reflect = = nullptr )
MessageBoxA ( nullptr , " GetProcAddress failed for D3DReflect! " , " Critical error " , MB_OK | MB_ICONERROR ) ;
d3d_create_blob = ( D3DCREATEBLOB ) GetProcAddress ( s_d3d_compiler_dll , " D3DCreateBlob " ) ;
if ( d3d_create_blob = = nullptr )
MessageBoxA ( nullptr , " GetProcAddress failed for D3DCreateBlob! " , " Critical error " , MB_OK | MB_ICONERROR ) ;
d3d_compile = ( pD3DCompile ) GetProcAddress ( s_d3d_compiler_dll , " D3DCompile " ) ;
if ( d3d_compile = = nullptr )
MessageBoxA ( nullptr , " GetProcAddress failed for D3DCompile! " , " Critical error " , MB_OK | MB_ICONERROR ) ;
return S_OK ;
}
void UnloadDXGI ( )
{
if ( ! s_dxgi_dll_ref )
return ;
if ( - - s_dxgi_dll_ref ! = 0 )
return ;
if ( s_dxgi_dll )
FreeLibrary ( s_dxgi_dll ) ;
s_dxgi_dll = nullptr ;
create_dxgi_factory = nullptr ;
}
void UnloadD3D ( )
{
if ( ! s_d3d12_dll_ref )
return ;
if ( - - s_d3d12_dll_ref ! = 0 )
return ;
if ( s_d3d12_dll )
FreeLibrary ( s_d3d12_dll ) ;
s_d3d12_dll = nullptr ;
d3d12_create_device = nullptr ;
d3d12_serialize_root_signature = nullptr ;
}
void UnloadD3DCompiler ( )
{
if ( ! s_d3d_compiler_dll_ref )
return ;
if ( - - s_d3d_compiler_dll_ref ! = 0 )
return ;
if ( s_d3d_compiler_dll )
FreeLibrary ( s_d3d_compiler_dll ) ;
s_d3d_compiler_dll = nullptr ;
d3d_compile = nullptr ;
d3d_create_blob = nullptr ;
d3d_reflect = nullptr ;
}
bool AlertUserIfSelectedAdapterDoesNotSupportD3D12 ( )
{
HRESULT hr = LoadDXGI ( ) ;
if ( SUCCEEDED ( hr ) )
{
hr = LoadD3D ( ) ;
}
if ( FAILED ( hr ) )
{
// LoadDXGI / LoadD3D display a specific error message,
// no need to do that here.
return false ;
}
IDXGIFactory * factory = nullptr ;
IDXGIAdapter * adapter = nullptr ;
ID3D12Device * device = nullptr ;
if ( SUCCEEDED ( hr ) )
{
hr = create_dxgi_factory ( __uuidof ( IDXGIFactory ) , ( void * * ) & factory ) ;
}
if ( SUCCEEDED ( hr ) )
{
hr = factory - > EnumAdapters ( g_ActiveConfig . iAdapter , & adapter ) ;
}
if ( SUCCEEDED ( hr ) )
{
hr = d3d12_create_device ( adapter , D3D_FEATURE_LEVEL_11_0 , IID_PPV_ARGS ( & device ) ) ;
SAFE_RELEASE ( device ) ;
SAFE_RELEASE ( adapter ) ;
SAFE_RELEASE ( factory ) ;
if ( FAILED ( hr ) )
{
UnloadD3D ( ) ;
UnloadDXGI ( ) ;
MessageBoxA ( nullptr , " Failed to create a D3D12 device on the selected adapter. \n \n Please make sure it supports Direct3D 12, and that your graphics drivers are up-to-date. " , " Critical error " , MB_OK | MB_ICONERROR ) ;
return false ;
}
// If succeeded, leave DXGI and D3D libraries loaded since we'll use them in Create().
return true ;
}
// DXGI failed to create factory/enumerate adapter. This should be very uncommon.
MessageBoxA ( nullptr , " Failed to create enumerate selected adapter. Please select a different graphics adapter. " , " Critical error " , MB_OK | MB_ICONERROR ) ;
SAFE_RELEASE ( adapter ) ;
SAFE_RELEASE ( factory ) ;
UnloadD3D ( ) ;
UnloadDXGI ( ) ;
return false ;
}
std : : vector < DXGI_SAMPLE_DESC > EnumAAModes ( IDXGIAdapter * adapter )
{
std : : vector < DXGI_SAMPLE_DESC > aa_modes ;
bool d3d12_supported = AlertUserIfSelectedAdapterDoesNotSupportD3D12 ( ) ;
if ( ! d3d12_supported )
return aa_modes ;
ID3D12Device * device12 = nullptr ;
d3d12_create_device ( adapter , D3D_FEATURE_LEVEL_11_0 , IID_PPV_ARGS ( & device12 ) ) ;
if ( device12 )
{
for ( int samples = 0 ; samples < D3D12_MAX_MULTISAMPLE_SAMPLE_COUNT ; + + samples )
{
D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS multisample_quality_levels = { } ;
multisample_quality_levels . Format = DXGI_FORMAT_R8G8B8A8_UNORM ;
multisample_quality_levels . SampleCount = samples ;
device12 - > CheckFeatureSupport ( D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS , & multisample_quality_levels , sizeof ( multisample_quality_levels ) ) ;
DXGI_SAMPLE_DESC desc ;
desc . Count = samples ;
desc . Quality = 0 ;
if ( multisample_quality_levels . NumQualityLevels > 0 )
{
aa_modes . push_back ( desc ) ;
}
}
device12 - > Release ( ) ;
}
return aa_modes ;
}
D3D_FEATURE_LEVEL GetFeatureLevel ( IDXGIAdapter * adapter )
{
return D3D_FEATURE_LEVEL_11_0 ;
}
HRESULT Create ( HWND wnd )
{
hWnd = wnd ;
HRESULT hr ;
RECT client ;
GetClientRect ( hWnd , & client ) ;
s_xres = client . right - client . left ;
s_yres = client . bottom - client . top ;
hr = LoadDXGI ( ) ;
if ( SUCCEEDED ( hr ) )
hr = LoadD3D ( ) ;
if ( SUCCEEDED ( hr ) )
hr = LoadD3DCompiler ( ) ;
if ( FAILED ( hr ) )
{
UnloadDXGI ( ) ;
UnloadD3D ( ) ;
UnloadD3DCompiler ( ) ;
return hr ;
}
IDXGIFactory * factory ;
IDXGIAdapter * adapter ;
hr = create_dxgi_factory ( __uuidof ( IDXGIFactory ) , ( void * * ) & factory ) ;
if ( FAILED ( hr ) )
MessageBox ( wnd , _T ( " Failed to create IDXGIFactory object " ) , _T ( " Dolphin Direct3D 12 backend " ) , MB_OK | MB_ICONERROR ) ;
hr = factory - > EnumAdapters ( g_ActiveConfig . iAdapter , & adapter ) ;
if ( FAILED ( hr ) )
{
// try using the first one
hr = factory - > EnumAdapters ( 0 , & adapter ) ;
if ( FAILED ( hr ) )
MessageBox ( wnd , _T ( " Failed to enumerate adapters " ) , _T ( " Dolphin Direct3D 12 backend " ) , MB_OK | MB_ICONERROR ) ;
}
// get supported AA modes
s_aa_modes = EnumAAModes ( adapter ) ;
if ( std : : find_if (
s_aa_modes . begin ( ) ,
s_aa_modes . end ( ) ,
[ ] ( const DXGI_SAMPLE_DESC & desc ) { return desc . Count = = g_Config . iMultisamples ; }
) = = s_aa_modes . end ( ) )
{
g_Config . iMultisamples = 1 ;
UpdateActiveConfig ( ) ;
}
DXGI_SWAP_CHAIN_DESC swap_chain_desc = { } ;
swap_chain_desc . BufferCount = SWAP_CHAIN_BUFFER_COUNT ;
swap_chain_desc . BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT ;
swap_chain_desc . OutputWindow = wnd ;
swap_chain_desc . SampleDesc . Count = 1 ;
swap_chain_desc . SampleDesc . Quality = 0 ;
swap_chain_desc . Windowed = true ;
swap_chain_desc . SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL ;
swap_chain_desc . Flags = 0 ;
swap_chain_desc . BufferDesc . Width = s_xres ;
swap_chain_desc . BufferDesc . Height = s_yres ;
swap_chain_desc . BufferDesc . Format = DXGI_FORMAT_R8G8B8A8_UNORM ;
swap_chain_desc . BufferDesc . Scaling = DXGI_MODE_SCALING_UNSPECIFIED ;
2016-02-17 03:39:12 +00:00
# if defined(_DEBUG) || defined(DEBUGFAST) || defined(USE_D3D12_DEBUG_LAYER)
// Enabling the debug layer will fail if the Graphics Tools feature is not installed.
if ( SUCCEEDED ( hr ) )
2016-01-08 03:40:35 +00:00
{
2016-02-17 03:39:12 +00:00
ID3D12Debug * debug_controller ;
hr = d3d12_get_debug_interface ( IID_PPV_ARGS ( & debug_controller ) ) ;
2016-01-08 03:40:35 +00:00
if ( SUCCEEDED ( hr ) )
{
2016-02-17 03:39:12 +00:00
debug_controller - > EnableDebugLayer ( ) ;
debug_controller - > Release ( ) ;
}
else
{
MessageBox ( wnd , _T ( " WARNING: Failed to enable D3D12 debug layer, please ensure the Graphics Tools feature is installed. " ) , _T ( " Dolphin Direct3D 12 backend " ) , MB_OK | MB_ICONERROR ) ;
2016-01-08 03:40:35 +00:00
}
}
# endif
2016-02-17 03:39:12 +00:00
if ( SUCCEEDED ( hr ) )
{
hr = d3d12_create_device ( adapter , D3D_FEATURE_LEVEL_11_0 , IID_PPV_ARGS ( & device12 ) ) ;
s_feat_level = D3D_FEATURE_LEVEL_11_0 ;
2016-01-08 03:40:35 +00:00
}
if ( SUCCEEDED ( hr ) )
{
D3D12_COMMAND_QUEUE_DESC command_queue_desc = {
D3D12_COMMAND_LIST_TYPE_DIRECT , // D3D12_COMMAND_LIST_TYPE Type;
0 , // INT Priority;
D3D12_COMMAND_QUEUE_FLAG_NONE , // D3D12_COMMAND_QUEUE_FLAG Flags;
0 // UINT NodeMask;
} ;
CheckHR ( device12 - > CreateCommandQueue ( & command_queue_desc , IID_PPV_ARGS ( & command_queue ) ) ) ;
IDXGIFactory * factory = nullptr ;
adapter - > GetParent ( IID_PPV_ARGS ( & factory ) ) ;
CheckHR ( factory - > CreateSwapChain ( command_queue , & swap_chain_desc , & s_swap_chain ) ) ;
s_current_back_buf = 0 ;
factory - > Release ( ) ;
}
if ( SUCCEEDED ( hr ) )
{
// Query the monitor refresh rate, to ensure proper Present throttling behavior.
DEVMODE dev_mode ;
memset ( & dev_mode , 0 , sizeof ( DEVMODE ) ) ;
dev_mode . dmSize = sizeof ( DEVMODE ) ;
dev_mode . dmDriverExtra = 0 ;
if ( EnumDisplaySettings ( NULL , ENUM_CURRENT_SETTINGS , & dev_mode ) = = 0 )
{
// If EnumDisplaySettings fails, assume monitor refresh rate of 60 Hz.
s_monitor_refresh_rate = 60 ;
}
else
{
s_monitor_refresh_rate = dev_mode . dmDisplayFrequency ;
}
}
if ( FAILED ( hr ) )
{
MessageBox ( wnd , _T ( " Failed to initialize Direct3D. \n Make sure your video card supports Direct3D 12 and your drivers are up-to-date. " ) , _T ( " Dolphin Direct3D 12 backend " ) , MB_OK | MB_ICONERROR ) ;
SAFE_RELEASE ( s_swap_chain ) ;
return E_FAIL ;
}
ID3D12InfoQueue * info_queue = nullptr ;
if ( SUCCEEDED ( device12 - > QueryInterface ( & info_queue ) ) )
{
CheckHR ( info_queue - > SetBreakOnSeverity ( D3D12_MESSAGE_SEVERITY_ERROR , TRUE ) ) ;
CheckHR ( info_queue - > SetBreakOnSeverity ( D3D12_MESSAGE_SEVERITY_WARNING , TRUE ) ) ;
D3D12_INFO_QUEUE_FILTER filter = { } ;
D3D12_MESSAGE_ID id_list [ ] = {
D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_DEPTHSTENCILVIEW_NOT_SET , // Benign.
D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_RENDERTARGETVIEW_NOT_SET , // Benign.
D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_TYPE_MISMATCH , // Benign.
D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE , // Benign.
} ;
filter . DenyList . NumIDs = ARRAYSIZE ( id_list ) ;
filter . DenyList . pIDList = id_list ;
info_queue - > PushStorageFilter ( & filter ) ;
info_queue - > Release ( ) ;
// Used at Close time to report live objects.
CheckHR ( device12 - > QueryInterface ( & s_debug_device12 ) ) ;
}
// prevent DXGI from responding to Alt+Enter, unfortunately DXGI_MWA_NO_ALT_ENTER
// does not work so we disable all monitoring of window messages. However this
// may make it more difficult for DXGI to handle display mode changes.
hr = factory - > MakeWindowAssociation ( wnd , DXGI_MWA_NO_WINDOW_CHANGES ) ;
if ( FAILED ( hr ) )
MessageBox ( wnd , _T ( " Failed to associate the window " ) , _T ( " Dolphin Direct3D 12 backend " ) , MB_OK | MB_ICONERROR ) ;
SAFE_RELEASE ( factory ) ;
SAFE_RELEASE ( adapter )
CreateDescriptorHeaps ( ) ;
CreateRootSignatures ( ) ;
2016-02-16 06:21:22 +00:00
command_list_mgr = std : : make_unique < D3DCommandListManager > (
2016-01-08 03:40:35 +00:00
D3D12_COMMAND_LIST_TYPE_DIRECT ,
device12 ,
command_queue
) ;
command_list_mgr - > GetCommandList ( & current_command_list ) ;
command_list_mgr - > SetInitialCommandListState ( ) ;
for ( UINT i = 0 ; i < SWAP_CHAIN_BUFFER_COUNT ; i + + )
{
ID3D12Resource * buf12 = nullptr ;
hr = s_swap_chain - > GetBuffer ( i , IID_PPV_ARGS ( & buf12 ) ) ;
CHECK ( SUCCEEDED ( hr ) , " Retrieve back buffer texture " ) ;
s_backbuf [ i ] = new D3DTexture2D ( buf12 ,
D3D11_BIND_RENDER_TARGET ,
DXGI_FORMAT_UNKNOWN ,
DXGI_FORMAT_UNKNOWN ,
DXGI_FORMAT_UNKNOWN ,
false ,
D3D12_RESOURCE_STATE_PRESENT // Swap Chain back buffers start out in D3D12_RESOURCE_STATE_PRESENT.
) ;
SAFE_RELEASE ( buf12 ) ;
SetDebugObjectName12 ( s_backbuf [ i ] - > GetTex12 ( ) , " backbuffer texture " ) ;
}
s_backbuf [ s_current_back_buf ] - > TransitionToResourceState ( current_command_list , D3D12_RESOURCE_STATE_RENDER_TARGET ) ;
current_command_list - > OMSetRenderTargets ( 1 , & s_backbuf [ s_current_back_buf ] - > GetRTV12 ( ) , FALSE , nullptr ) ;
QueryPerformanceFrequency ( & s_qpc_frequency ) ;
return S_OK ;
}
void CreateDescriptorHeaps ( )
{
// Create D3D12 GPU and CPU descriptor heaps.
{
D3D12_DESCRIPTOR_HEAP_DESC gpu_descriptor_heap_desc = { } ;
gpu_descriptor_heap_desc . Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE ;
gpu_descriptor_heap_desc . NumDescriptors = 500000 ;
gpu_descriptor_heap_desc . Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ;
2016-02-16 06:21:22 +00:00
gpu_descriptor_heap_mgr = std : : make_unique < D3DDescriptorHeapManager > ( & gpu_descriptor_heap_desc , device12 , 50000 ) ;
2016-01-08 03:40:35 +00:00
gpu_descriptor_heaps [ 0 ] = gpu_descriptor_heap_mgr - > GetDescriptorHeap ( ) ;
D3D12_CPU_DESCRIPTOR_HANDLE descriptor_heap_cpu_base = gpu_descriptor_heap_mgr - > GetDescriptorHeap ( ) - > GetCPUDescriptorHandleForHeapStart ( ) ;
resource_descriptor_size = device12 - > GetDescriptorHandleIncrementSize ( D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ) ;
sampler_descriptor_size = device12 - > GetDescriptorHandleIncrementSize ( D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER ) ;
D3D12_GPU_DESCRIPTOR_HANDLE null_srv_gpu = { } ;
gpu_descriptor_heap_mgr - > Allocate ( & null_srv_cpu , & null_srv_gpu , & null_srv_cpu_shadow ) ;
D3D12_SHADER_RESOURCE_VIEW_DESC null_srv_desc = { } ;
null_srv_desc . Format = DXGI_FORMAT_R8G8B8A8_UNORM ;
null_srv_desc . ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D ;
null_srv_desc . Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING ;
device12 - > CreateShaderResourceView ( NULL , & null_srv_desc , null_srv_cpu ) ;
for ( UINT i = 0 ; i < 500000 ; i + + )
{
// D3D12TODO: Make paving of descriptor heap optional.
D3D12_CPU_DESCRIPTOR_HANDLE destination_descriptor = { } ;
destination_descriptor . ptr = descriptor_heap_cpu_base . ptr + i * resource_descriptor_size ;
device12 - > CreateShaderResourceView ( NULL , & null_srv_desc , destination_descriptor ) ;
}
}
{
D3D12_DESCRIPTOR_HEAP_DESC sampler_descriptor_heap_desc = { } ;
sampler_descriptor_heap_desc . Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE ;
sampler_descriptor_heap_desc . NumDescriptors = 2000 ;
sampler_descriptor_heap_desc . Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER ;
2016-02-16 06:21:22 +00:00
sampler_descriptor_heap_mgr = std : : make_unique < D3DDescriptorHeapManager > ( & sampler_descriptor_heap_desc , device12 ) ;
2016-01-08 03:40:35 +00:00
gpu_descriptor_heaps [ 1 ] = sampler_descriptor_heap_mgr - > GetDescriptorHeap ( ) ;
}
{
D3D12_DESCRIPTOR_HEAP_DESC dsv_descriptor_heap_desc = { } ;
dsv_descriptor_heap_desc . Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE ;
dsv_descriptor_heap_desc . NumDescriptors = 2000 ;
dsv_descriptor_heap_desc . Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV ;
2016-02-16 06:21:22 +00:00
dsv_descriptor_heap_mgr = std : : make_unique < D3DDescriptorHeapManager > ( & dsv_descriptor_heap_desc , device12 ) ;
2016-01-08 03:40:35 +00:00
}
{
// D3D12TODO: Temporary workaround.. really need to properly suballocate out of render target heap.
D3D12_DESCRIPTOR_HEAP_DESC rtv_descriptor_heap_desc = { } ;
rtv_descriptor_heap_desc . Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE ;
rtv_descriptor_heap_desc . NumDescriptors = 1000000 ;
rtv_descriptor_heap_desc . Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV ;
2016-02-16 06:21:22 +00:00
rtv_descriptor_heap_mgr = std : : make_unique < D3DDescriptorHeapManager > ( & rtv_descriptor_heap_desc , device12 ) ;
2016-01-08 03:40:35 +00:00
}
}
void CreateRootSignatures ( )
{
D3D12_DESCRIPTOR_RANGE desc_range_srv = {
D3D12_DESCRIPTOR_RANGE_TYPE_SRV , // D3D12_DESCRIPTOR_RANGE_TYPE RangeType;
8 , // UINT NumDescriptors;
0 , // UINT BaseShaderRegister;
0 , // UINT RegisterSpace;
D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND // UINT OffsetInDescriptorsFromTableStart;
} ;
D3D12_DESCRIPTOR_RANGE desc_range_sampler = {
D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER , // D3D12_DESCRIPTOR_RANGE_TYPE RangeType;
8 , // UINT NumDescriptors;
0 , // UINT BaseShaderRegister;
0 , // UINT RegisterSpace;
D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND // UINT OffsetInDescriptorsFromTableStart;
} ;
D3D12_ROOT_PARAMETER root_parameters [ 6 ] ;
root_parameters [ DESCRIPTOR_TABLE_PS_SRV ] . ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE ;
root_parameters [ DESCRIPTOR_TABLE_PS_SRV ] . DescriptorTable . NumDescriptorRanges = 1 ;
root_parameters [ DESCRIPTOR_TABLE_PS_SRV ] . DescriptorTable . pDescriptorRanges = & desc_range_srv ;
root_parameters [ DESCRIPTOR_TABLE_PS_SRV ] . ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL ;
root_parameters [ DESCRIPTOR_TABLE_PS_SAMPLER ] . ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE ;
root_parameters [ DESCRIPTOR_TABLE_PS_SAMPLER ] . DescriptorTable . NumDescriptorRanges = 1 ;
root_parameters [ DESCRIPTOR_TABLE_PS_SAMPLER ] . DescriptorTable . pDescriptorRanges = & desc_range_sampler ;
root_parameters [ DESCRIPTOR_TABLE_PS_SAMPLER ] . ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL ;
root_parameters [ DESCRIPTOR_TABLE_GS_CBV ] . ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV ;
root_parameters [ DESCRIPTOR_TABLE_GS_CBV ] . Descriptor . RegisterSpace = 0 ;
root_parameters [ DESCRIPTOR_TABLE_GS_CBV ] . Descriptor . ShaderRegister = 0 ;
root_parameters [ DESCRIPTOR_TABLE_GS_CBV ] . ShaderVisibility = D3D12_SHADER_VISIBILITY_GEOMETRY ;
root_parameters [ DESCRIPTOR_TABLE_VS_CBV ] . ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV ;
root_parameters [ DESCRIPTOR_TABLE_VS_CBV ] . Descriptor . RegisterSpace = 0 ;
root_parameters [ DESCRIPTOR_TABLE_VS_CBV ] . Descriptor . ShaderRegister = 0 ;
root_parameters [ DESCRIPTOR_TABLE_VS_CBV ] . ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX ;
root_parameters [ DESCRIPTOR_TABLE_PS_CBVONE ] . ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV ;
root_parameters [ DESCRIPTOR_TABLE_PS_CBVONE ] . Descriptor . RegisterSpace = 0 ;
root_parameters [ DESCRIPTOR_TABLE_PS_CBVONE ] . Descriptor . ShaderRegister = 0 ;
root_parameters [ DESCRIPTOR_TABLE_PS_CBVONE ] . ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL ;
root_parameters [ DESCRIPTOR_TABLE_PS_CBVTWO ] . ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV ;
root_parameters [ DESCRIPTOR_TABLE_PS_CBVTWO ] . Descriptor . RegisterSpace = 0 ;
root_parameters [ DESCRIPTOR_TABLE_PS_CBVTWO ] . Descriptor . ShaderRegister = 1 ;
root_parameters [ DESCRIPTOR_TABLE_PS_CBVTWO ] . ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL ;
// D3D12TODO: Add bounding box UAV to root signature.
D3D12_ROOT_SIGNATURE_DESC root_signature_desc = { } ;
root_signature_desc . pParameters = root_parameters ;
root_signature_desc . Flags =
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS ;
root_signature_desc . NumParameters = ARRAYSIZE ( root_parameters ) ;
ID3DBlob * text_root_signature_blob ;
ID3DBlob * text_root_signature_error_blob ;
CheckHR ( d3d12_serialize_root_signature ( & root_signature_desc , D3D_ROOT_SIGNATURE_VERSION_1 , & text_root_signature_blob , & text_root_signature_error_blob ) ) ;
CheckHR ( D3D : : device12 - > CreateRootSignature ( 0 , text_root_signature_blob - > GetBufferPointer ( ) , text_root_signature_blob - > GetBufferSize ( ) , IID_PPV_ARGS ( & default_root_signature ) ) ) ;
}
void WaitForOutstandingRenderingToComplete ( )
{
2016-02-17 04:57:57 +00:00
command_list_mgr - > ExecuteQueuedWork ( true ) ;
2016-01-08 03:40:35 +00:00
}
void Close ( )
{
// we can't release the swapchain while in fullscreen.
s_swap_chain - > SetFullscreenState ( false , nullptr ) ;
// Release all back buffer references
for ( UINT i = 0 ; i < ARRAYSIZE ( s_backbuf ) ; i + + )
{
SAFE_RELEASE ( s_backbuf [ i ] ) ;
}
D3D : : CleanupPersistentD3DTextureResources ( ) ;
SAFE_RELEASE ( s_swap_chain ) ;
2016-02-16 06:21:22 +00:00
command_list_mgr . reset ( ) ;
2016-01-08 03:40:35 +00:00
command_queue - > Release ( ) ;
default_root_signature - > Release ( ) ;
2016-02-16 06:21:22 +00:00
gpu_descriptor_heap_mgr . reset ( ) ;
sampler_descriptor_heap_mgr . reset ( ) ;
rtv_descriptor_heap_mgr . reset ( ) ;
dsv_descriptor_heap_mgr . reset ( ) ;
2016-01-08 03:40:35 +00:00
ULONG remaining_references = device12 - > Release ( ) ;
if ( ( ! s_debug_device12 & & remaining_references ) | | ( s_debug_device12 & & remaining_references > 1 ) )
{
ERROR_LOG ( VIDEO , " Unreleased D3D12 references: %i. " , remaining_references ) ;
}
else
{
NOTICE_LOG ( VIDEO , " Successfully released all D3D12 device references! " ) ;
}
# if defined(_DEBUG) || defined(DEBUGFAST)
if ( s_debug_device12 )
{
- - remaining_references ; // the debug interface increases the refcount of the device, subtract that.
if ( remaining_references )
{
// print out alive objects, but only if we actually have pending references
// note this will also print out internal live objects to the debug console
s_debug_device12 - > ReportLiveDeviceObjects ( D3D12_RLDO_DETAIL ) ;
}
SAFE_RELEASE ( s_debug_device12 ) ;
}
# endif
device12 = nullptr ;
current_command_list = nullptr ;
// unload DLLs
UnloadDXGI ( ) ;
UnloadD3DCompiler ( ) ;
UnloadD3D ( ) ;
}
const std : : string VertexShaderVersionString ( )
{
return " vs_5_0 " ;
}
const std : : string GeometryShaderVersionString ( )
{
return " gs_5_0 " ;
}
const std : : string PixelShaderVersionString ( )
{
return " ps_5_0 " ;
}
D3DTexture2D * & GetBackBuffer ( )
{
return s_backbuf [ s_current_back_buf ] ;
}
unsigned int GetBackBufferWidth ( )
{
return s_xres ;
}
unsigned int GetBackBufferHeight ( )
{
return s_yres ;
}
// Returns the maximum width/height of a texture.
unsigned int GetMaxTextureSize ( )
{
return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION ;
}
void Reset ( )
{
// release all back buffer references
for ( UINT i = 0 ; i < ARRAYSIZE ( s_backbuf ) ; i + + )
{
SAFE_RELEASE ( s_backbuf [ i ] ) ;
}
2016-02-17 04:57:57 +00:00
// Block until all commands have finished.
// This will also final-release all pending resources (including the backbuffer above)
command_list_mgr - > ExecuteQueuedWork ( true ) ;
2016-01-08 03:40:35 +00:00
// resize swapchain buffers
RECT client ;
GetClientRect ( hWnd , & client ) ;
s_xres = client . right - client . left ;
s_yres = client . bottom - client . top ;
CheckHR ( s_swap_chain - > ResizeBuffers ( SWAP_CHAIN_BUFFER_COUNT , s_xres , s_yres , DXGI_FORMAT_R8G8B8A8_UNORM , 0 ) ) ;
// recreate back buffer textures
HRESULT hr = S_OK ;
for ( UINT i = 0 ; i < SWAP_CHAIN_BUFFER_COUNT ; i + + )
{
ID3D12Resource * buf12 = nullptr ;
hr = s_swap_chain - > GetBuffer ( i , IID_PPV_ARGS ( & buf12 ) ) ;
CHECK ( SUCCEEDED ( hr ) , " Retrieve back buffer texture " ) ;
s_backbuf [ i ] = new D3DTexture2D ( buf12 ,
D3D11_BIND_RENDER_TARGET ,
DXGI_FORMAT_UNKNOWN ,
DXGI_FORMAT_UNKNOWN ,
DXGI_FORMAT_UNKNOWN ,
false ,
D3D12_RESOURCE_STATE_PRESENT
) ;
SAFE_RELEASE ( buf12 ) ;
SetDebugObjectName12 ( s_backbuf [ i ] - > GetTex12 ( ) , " backbuffer texture " ) ;
}
// The 'about-to-be-presented' back buffer index is always set back to '0' upon ResizeBuffers, just like
// creating a new swap chain.
s_current_back_buf = 0 ;
s_backbuf [ s_current_back_buf ] - > TransitionToResourceState ( current_command_list , D3D12_RESOURCE_STATE_RENDER_TARGET ) ;
}
bool BeginFrame ( )
{
if ( s_frame_in_progress )
{
PanicAlert ( " BeginFrame called although a frame is already in progress " ) ;
return false ;
}
s_frame_in_progress = true ;
return ( device12 ! = nullptr ) ;
}
void EndFrame ( )
{
if ( ! s_frame_in_progress )
{
PanicAlert ( " EndFrame called although no frame is in progress " ) ;
return ;
}
s_frame_in_progress = false ;
}
void Present ( )
{
// The Present function contains logic to ensure we never Present faster than Windows can
// send to the monitor. If we Present too fast, the Present call will start to block, and we'll be
// throttled - obviously not desired if vsync is disabled and the emulated CPU speed is > 100%.
// The throttling logic ensures that we don't Present more than twice in a given monitor vsync.
// This is accomplished through timing data - there is a programmatic way to determine if a
// Present call will block, however after investigation that is not feasible here (without invasive
// workarounds), due to the fact this method does not actually call Present - we just queue a Present
// command for the background thread to dispatch.
// The monitor refresh rate is determined in Create().
static LARGE_INTEGER s_last_present_qpc ;
LARGE_INTEGER current_qpc ;
QueryPerformanceCounter ( & current_qpc ) ;
const double time_elapsed_since_last_present = static_cast < double > ( current_qpc . QuadPart - s_last_present_qpc . QuadPart ) / s_qpc_frequency . QuadPart ;
unsigned int present_flags = 0 ;
if ( g_ActiveConfig . IsVSync ( ) = = false & &
time_elapsed_since_last_present < ( 1.0 / static_cast < double > ( s_monitor_refresh_rate ) ) / 2.0
)
{
present_flags = DXGI_PRESENT_TEST ; // Causes Present to be a no-op.
}
else
{
s_last_present_qpc = current_qpc ;
s_backbuf [ s_current_back_buf ] - > TransitionToResourceState ( current_command_list , D3D12_RESOURCE_STATE_PRESENT ) ;
s_current_back_buf = ( s_current_back_buf + 1 ) % SWAP_CHAIN_BUFFER_COUNT ;
}
command_list_mgr - > ExecuteQueuedWorkAndPresent ( s_swap_chain , g_ActiveConfig . IsVSync ( ) ? 1 : 0 , present_flags ) ;
command_list_mgr - > m_cpu_access_last_frame = command_list_mgr - > m_cpu_access_this_frame ;
command_list_mgr - > m_cpu_access_this_frame = false ;
command_list_mgr - > m_draws_since_last_execution = 0 ;
}
HRESULT SetFullscreenState ( bool enable_fullscreen )
{
return S_OK ;
}
HRESULT GetFullscreenState ( bool * fullscreen_state )
{
// Fullscreen exclusive intentionally not supported in DX12 backend. No performance
// difference between it and windowed full-screen due to usage of a FLIP swap chain.
* fullscreen_state = false ;
return S_OK ;
}
} // namespace D3D
} // namespace DX12