D3D12: Cleanup startup/shutdown process

Sorts out references that cause some modules to be kept around after
backend shutdown.

Should also solve the issue with errors being thrown due to the config
being loaded after device creation, leading to the incorrect device being
used in a multi-adapter system.
This commit is contained in:
Stenzek 2016-03-07 00:36:37 +10:00
parent 4269abdc3e
commit 9bff187547
4 changed files with 145 additions and 212 deletions

View File

@ -14,6 +14,7 @@
#include "VideoBackends/D3D12/D3DDescriptorHeapManager.h"
#include "VideoBackends/D3D12/D3DState.h"
#include "VideoBackends/D3D12/D3DTexture.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/VideoConfig.h"
static const unsigned int SWAP_CHAIN_BUFFER_COUNT = 4;
@ -72,18 +73,12 @@ 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)
@ -233,108 +228,29 @@ void UnloadD3DCompiler()
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\nPlease 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> EnumAAModes(ID3D12Device* device)
{
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)
{
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;
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));
device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &multisample_quality_levels, sizeof(multisample_quality_levels));
DXGI_SAMPLE_DESC desc;
desc.Count = samples;
desc.Quality = 0;
DXGI_SAMPLE_DESC desc;
desc.Count = samples;
desc.Quality = 0;
if (multisample_quality_levels.NumQualityLevels > 0)
{
aa_modes.push_back(desc);
}
}
device12->Release();
if (multisample_quality_levels.NumQualityLevels > 0)
aa_modes.push_back(desc);
}
return aa_modes;
}
D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter)
{
return D3D_FEATURE_LEVEL_11_0;
}
HRESULT Create(HWND wnd)
{
hWnd = wnd;
@ -346,17 +262,21 @@ HRESULT Create(HWND wnd)
s_yres = client.bottom - client.top;
hr = LoadDXGI();
if (SUCCEEDED(hr))
hr = LoadD3D();
if (SUCCEEDED(hr))
hr = LoadD3DCompiler();
if (FAILED(hr))
return hr;
hr = LoadD3D();
if (FAILED(hr))
{
UnloadDXGI();
return hr;
}
hr = LoadD3DCompiler();
if (FAILED(hr))
{
UnloadD3D();
UnloadD3DCompiler();
UnloadDXGI();
return hr;
}
@ -364,7 +284,13 @@ HRESULT Create(HWND wnd)
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);
UnloadD3DCompiler();
UnloadD3D();
UnloadDXGI();
return hr;
}
hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter);
if (FAILED(hr))
@ -372,20 +298,13 @@ HRESULT Create(HWND wnd)
// 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();
UnloadD3DCompiler();
UnloadD3D();
UnloadDXGI();
return hr;
}
}
DXGI_SWAP_CHAIN_DESC swap_chain_desc = {};
@ -405,74 +324,70 @@ HRESULT Create(HWND wnd)
#if defined(_DEBUG) || defined(DEBUGFAST) || defined(USE_D3D12_DEBUG_LAYER)
// Enabling the debug layer will fail if the Graphics Tools feature is not installed.
ID3D12Debug* debug_controller;
hr = d3d12_get_debug_interface(IID_PPV_ARGS(&debug_controller));
if (SUCCEEDED(hr))
{
ID3D12Debug* debug_controller;
hr = d3d12_get_debug_interface(IID_PPV_ARGS(&debug_controller));
if (SUCCEEDED(hr))
{
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);
}
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);
}
#endif
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;
}
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;
}
}
hr = d3d12_create_device(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device12));
if (FAILED(hr))
{
MessageBox(wnd, _T("Failed to initialize Direct3D.\nMake 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;
adapter->Release();
UnloadD3DCompiler();
UnloadD3D();
UnloadDXGI();
return hr;
}
// Ensure that the chosen AA mode is supported by the device.
std::vector<DXGI_SAMPLE_DESC> aa_modes = EnumAAModes(device12);
if (std::find_if(
aa_modes.begin(),
aa_modes.end(),
[](const DXGI_SAMPLE_DESC& desc) {return desc.Count == g_Config.iMultisamples; }
) == aa_modes.end())
{
g_Config.iMultisamples = 1;
UpdateActiveConfig();
}
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)));
CheckHR(factory->CreateSwapChain(command_queue, &swap_chain_desc, &s_swap_chain));
s_current_back_buf = 0;
// 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;
}
ID3D12InfoQueue* info_queue = nullptr;
@ -505,9 +420,6 @@ HRESULT Create(HWND wnd)
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();
@ -545,6 +457,14 @@ HRESULT Create(HWND wnd)
QueryPerformanceFrequency(&s_qpc_frequency);
// Render the device name.
DXGI_ADAPTER_DESC adapter_desc;
CheckHR(adapter->GetDesc(&adapter_desc));
OSD::AddMessage(StringFromFormat("Using D3D Adapter: %s.", UTF16ToUTF8(adapter_desc.Description).c_str()));
SAFE_RELEASE(factory);
SAFE_RELEASE(adapter);
return S_OK;
}
@ -757,9 +677,9 @@ void Close()
current_command_list = nullptr;
// unload DLLs
UnloadDXGI();
UnloadD3DCompiler();
UnloadD3D();
UnloadDXGI();
}
const std::string VertexShaderVersionString()

View File

@ -65,9 +65,7 @@ void UnloadDXGI();
void UnloadD3D();
void UnloadD3DCompiler();
std::vector<DXGI_SAMPLE_DESC> EnumAAModes(IDXGIAdapter* adapter);
bool AlertUserIfSelectedAdapterDoesNotSupportD3D12();
std::vector<DXGI_SAMPLE_DESC> EnumAAModes(ID3D12Device* device);
HRESULT Create(HWND wnd);
@ -148,6 +146,8 @@ using CREATEDXGIFACTORY = HRESULT(WINAPI*)(REFIID, void**);
extern CREATEDXGIFACTORY create_dxgi_factory;
using D3D12CREATEDEVICE = HRESULT(WINAPI*)(IUnknown*, D3D_FEATURE_LEVEL, REFIID, void**);
extern D3D12CREATEDEVICE d3d12_create_device;
using D3D12SERIALIZEROOTSIGNATURE = HRESULT(WINAPI*)(const D3D12_ROOT_SIGNATURE_DESC* pRootSignature, D3D_ROOT_SIGNATURE_VERSION Version, ID3DBlob** ppBlob, ID3DBlob** ppErrorBlob);
using D3D12GETDEBUGINTERFACE = HRESULT(WINAPI*)(REFIID riid, void** ppvDebug);

View File

@ -224,8 +224,6 @@ Renderer::Renderer(void*& window_handle)
return;
}
D3D::Create((HWND)window_handle);
s_backbuffer_width = D3D::GetBackBufferWidth();
s_backbuffer_height = D3D::GetBackBufferHeight();
@ -283,7 +281,6 @@ Renderer::~Renderer()
D3D::EndFrame();
D3D::WaitForOutstandingRenderingToComplete();
TeardownDeviceObjects();
D3D::Close();
}
void Renderer::RenderText(const std::string& text, int left, int top, u32 color)

View File

@ -65,11 +65,14 @@ std::string VideoBackend::GetDisplayName() const
void InitBackendInfo()
{
HRESULT hr = DX12::D3D::LoadDXGI();
if (SUCCEEDED(hr)) hr = DX12::D3D::LoadD3D();
HRESULT hr = D3D::LoadDXGI();
if (FAILED(hr))
return;
hr = D3D::LoadD3D();
if (FAILED(hr))
{
DX12::D3D::UnloadDXGI();
D3D::UnloadDXGI();
return;
}
@ -86,9 +89,14 @@ void InitBackendInfo()
IDXGIFactory* factory;
IDXGIAdapter* ad;
hr = DX12::create_dxgi_factory(__uuidof(IDXGIFactory), (void**)&factory);
hr = create_dxgi_factory(__uuidof(IDXGIFactory), (void**)&factory);
if (FAILED(hr))
{
PanicAlert("Failed to create IDXGIFactory object");
D3D::UnloadD3D();
D3D::UnloadDXGI();
return;
}
// adapters
g_Config.backend_info.Adapters.clear();
@ -103,26 +111,34 @@ void InitBackendInfo()
// TODO: These don't get updated on adapter change, yet
if (adapter_index == g_Config.iAdapter)
{
std::string samples;
std::vector<DXGI_SAMPLE_DESC> modes = DX12::D3D::EnumAAModes(ad);
// First iteration will be 1. This equals no AA.
for (unsigned int i = 0; i < modes.size(); ++i)
ID3D12Device* temp_device;
hr = d3d12_create_device(ad, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&temp_device));
if (SUCCEEDED(hr))
{
g_Config.backend_info.AAModes.push_back(modes[i].Count);
std::string samples;
std::vector<DXGI_SAMPLE_DESC> modes = D3D::EnumAAModes(temp_device);
// First iteration will be 1. This equals no AA.
for (unsigned int i = 0; i < modes.size(); ++i)
{
g_Config.backend_info.AAModes.push_back(modes[i].Count);
}
// Requires the earlydepthstencil attribute (only available in shader model 5)
g_Config.backend_info.bSupportsEarlyZ = true;
// Requires full UAV functionality (only available in shader model 5)
g_Config.backend_info.bSupportsBBox = true;
// Requires the instance attribute (only available in shader model 5)
g_Config.backend_info.bSupportsGSInstancing = true;
// Sample shading requires shader model 5
g_Config.backend_info.bSupportsSSAA = true;
temp_device->Release();
}
// Requires the earlydepthstencil attribute (only available in shader model 5)
g_Config.backend_info.bSupportsEarlyZ = true;
// Requires full UAV functionality (only available in shader model 5)
g_Config.backend_info.bSupportsBBox = true;
// Requires the instance attribute (only available in shader model 5)
g_Config.backend_info.bSupportsGSInstancing = true;
// Sample shading requires shader model 5
g_Config.backend_info.bSupportsSSAA = true;
}
g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description));
ad->Release();
}
@ -132,8 +148,8 @@ void InitBackendInfo()
g_Config.backend_info.PPShaders.clear();
g_Config.backend_info.AnaglyphShaders.clear();
DX12::D3D::UnloadDXGI();
DX12::D3D::UnloadD3D();
D3D::UnloadD3D();
D3D::UnloadDXGI();
}
void VideoBackend::ShowConfig(void *hParent)
@ -144,11 +160,6 @@ void VideoBackend::ShowConfig(void *hParent)
bool VideoBackend::Initialize(void *window_handle)
{
bool d3d12_supported = D3D::AlertUserIfSelectedAdapterDoesNotSupportD3D12();
if (!d3d12_supported)
return false;
if (window_handle == nullptr)
return false;
@ -167,6 +178,9 @@ bool VideoBackend::Initialize(void *window_handle)
g_Config.VerifyValidity();
UpdateActiveConfig();
if (FAILED(D3D::Create((HWND)window_handle)))
return false;
m_window_handle = window_handle;
m_initialized = true;
@ -235,6 +249,8 @@ void VideoBackend::Shutdown()
g_vertex_manager.reset();
g_texture_cache.reset();
g_renderer.reset();
D3D::Close();
}
}