diff --git a/Source/Core/VideoBackends/D3D/BoundingBox.cpp b/Source/Core/VideoBackends/D3D/BoundingBox.cpp index abbd7036a1..511bf5cf66 100644 --- a/Source/Core/VideoBackends/D3D/BoundingBox.cpp +++ b/Source/Core/VideoBackends/D3D/BoundingBox.cpp @@ -6,6 +6,7 @@ #include "Common/CommonTypes.h" #include "Common/MsgHandler.h" #include "VideoBackends/D3D/D3DState.h" +#include "VideoBackends/D3DCommon/Common.h" #include "VideoCommon/VideoConfig.h" namespace DX11 @@ -35,7 +36,7 @@ void BBox::Init() HRESULT hr; hr = D3D::device->CreateBuffer(&desc, &data, &s_bbox_buffer); CHECK(SUCCEEDED(hr), "Create BoundingBox Buffer."); - D3D::SetDebugObjectName(s_bbox_buffer, "BoundingBox Buffer"); + D3DCommon::SetDebugObjectName(s_bbox_buffer, "BoundingBox Buffer"); // Second to use as a staging buffer. desc.Usage = D3D11_USAGE_STAGING; @@ -43,7 +44,7 @@ void BBox::Init() desc.BindFlags = 0; hr = D3D::device->CreateBuffer(&desc, nullptr, &s_bbox_staging_buffer); CHECK(SUCCEEDED(hr), "Create BoundingBox Staging Buffer."); - D3D::SetDebugObjectName(s_bbox_staging_buffer, "BoundingBox Staging Buffer"); + D3DCommon::SetDebugObjectName(s_bbox_staging_buffer, "BoundingBox Staging Buffer"); // UAV is required to allow concurrent access. D3D11_UNORDERED_ACCESS_VIEW_DESC UAVdesc = {}; @@ -54,7 +55,7 @@ void BBox::Init() UAVdesc.Buffer.NumElements = 4; hr = D3D::device->CreateUnorderedAccessView(s_bbox_buffer, &UAVdesc, &s_bbox_uav); CHECK(SUCCEEDED(hr), "Create BoundingBox UAV."); - D3D::SetDebugObjectName(s_bbox_uav, "BoundingBox UAV"); + D3DCommon::SetDebugObjectName(s_bbox_uav, "BoundingBox UAV"); D3D::stateman->SetOMUAV(s_bbox_uav); } } diff --git a/Source/Core/VideoBackends/D3D/CMakeLists.txt b/Source/Core/VideoBackends/D3D/CMakeLists.txt index facd2b07e3..b80d9df818 100644 --- a/Source/Core/VideoBackends/D3D/CMakeLists.txt +++ b/Source/Core/VideoBackends/D3D/CMakeLists.txt @@ -26,4 +26,5 @@ target_link_libraries(videod3d PUBLIC common videocommon + videod3dcommon ) diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj b/Source/Core/VideoBackends/D3D/D3D.vcxproj index 5721e4d3ce..5fd3dbcbce 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj @@ -46,6 +46,7 @@ + @@ -57,6 +58,7 @@ + @@ -64,6 +66,9 @@ {3de9ee35-3e91-4f27-a014-2866ad8c3fe3} + + {dea96cf2-f237-4a1a-b32f-c916769efb50} + diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters index 4ca2cfa179..630e95a808 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters @@ -40,6 +40,9 @@ Render + + Render + @@ -70,5 +73,8 @@ Render + + Render + \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D/D3DBase.cpp b/Source/Core/VideoBackends/D3D/D3DBase.cpp index 9a86cd3c0c..4ab64a4784 100644 --- a/Source/Core/VideoBackends/D3D/D3DBase.cpp +++ b/Source/Core/VideoBackends/D3D/D3DBase.cpp @@ -5,6 +5,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/DynamicLibrary.h" #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" @@ -13,221 +14,31 @@ #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/DXTexture.h" +#include "VideoBackends/D3DCommon/Common.h" #include "VideoCommon/VideoConfig.h" namespace DX11 { -using D3DREFLECT = HRESULT(WINAPI*)(LPCVOID, SIZE_T, REFIID, void**); - -static HINSTANCE s_d3d_compiler_dll; -static int s_d3dcompiler_dll_ref; -static D3DREFLECT s_d3d_reflect; -pD3DCompile PD3DCompile = nullptr; - -CREATEDXGIFACTORY PCreateDXGIFactory = nullptr; -static HINSTANCE s_dxgi_dll; -static int s_dxgi_dll_ref; - -static D3D11CREATEDEVICE s_d3d11_create_device; -static HINSTANCE s_d3d_dll; -static int s_d3d_dll_ref; - +static Common::DynamicLibrary s_d3d11_library; namespace D3D { -ID3D11Device* device = nullptr; -ID3D11Device1* device1 = nullptr; -ID3D11DeviceContext* context = nullptr; -IDXGISwapChain1* swapchain = nullptr; +ComPtr dxgi_factory; +ComPtr device; +ComPtr device1; +ComPtr context; +D3D_FEATURE_LEVEL feature_level; -static IDXGIFactory2* s_dxgi_factory; -static ID3D11Debug* s_debug; -static D3D_FEATURE_LEVEL s_featlevel; -static std::unique_ptr s_swap_chain_texture; -static std::unique_ptr s_swap_chain_framebuffer; +static ComPtr s_debug; -static std::vector s_aa_modes; // supported AA modes of the current adapter - -static bool s_bgra_textures_supported; -static bool s_allow_tearing_supported; - -constexpr UINT NUM_SUPPORTED_FEATURE_LEVELS = 3; -constexpr D3D_FEATURE_LEVEL supported_feature_levels[NUM_SUPPORTED_FEATURE_LEVELS] = { +static constexpr D3D_FEATURE_LEVEL s_supported_feature_levels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_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; - } - - // Even though we use IDXGIFactory2 we use CreateDXGIFactory1 to create it to maintain - // compatibility with Windows 7 - PCreateDXGIFactory = (CREATEDXGIFACTORY)GetProcAddress(s_dxgi_dll, "CreateDXGIFactory1"); - if (PCreateDXGIFactory == nullptr) - MessageBoxA(nullptr, "GetProcAddress failed for CreateDXGIFactory1!", "Critical error", - MB_OK | MB_ICONERROR); - - return S_OK; -} - -HRESULT LoadD3D() -{ - if (s_d3d_dll_ref++ > 0) - return S_OK; - - if (s_d3d_dll) - return S_OK; - s_d3d_dll = LoadLibraryA("d3d11.dll"); - if (!s_d3d_dll) - { - MessageBoxA(nullptr, "Failed to load d3d11.dll", "Critical error", MB_OK | MB_ICONERROR); - --s_d3d_dll_ref; - return E_FAIL; - } - s_d3d11_create_device = (D3D11CREATEDEVICE)GetProcAddress(s_d3d_dll, "D3D11CreateDevice"); - if (s_d3d11_create_device == nullptr) - MessageBoxA(nullptr, "GetProcAddress failed for D3D11CreateDevice!", "Critical error", - MB_OK | MB_ICONERROR); - - return S_OK; -} - -HRESULT LoadD3DCompiler() -{ - if (s_d3dcompiler_dll_ref++ > 0) - return S_OK; - if (s_d3d_compiler_dll) - return S_OK; - - // The older version of the D3D compiler cannot compile our ubershaders without various - // graphical issues. D3DCOMPILER_DLL_A should point to d3dcompiler_47.dll, so if this fails - // to load, inform the user that they need to update their system. - s_d3d_compiler_dll = LoadLibraryA(D3DCOMPILER_DLL_A); - if (!s_d3d_compiler_dll) - { - PanicAlertT("Failed to load %s. If you are using Windows 7, try installing the " - "KB4019990 update package.", - D3DCOMPILER_DLL_A); - return E_FAIL; - } - - s_d3d_reflect = (D3DREFLECT)GetProcAddress(s_d3d_compiler_dll, "D3DReflect"); - if (s_d3d_reflect == nullptr) - MessageBoxA(nullptr, "GetProcAddress failed for D3DReflect!", "Critical error", - MB_OK | MB_ICONERROR); - PD3DCompile = (pD3DCompile)GetProcAddress(s_d3d_compiler_dll, "D3DCompile"); - if (PD3DCompile == 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; - PCreateDXGIFactory = nullptr; -} - -void UnloadD3D() -{ - if (!s_d3d_dll_ref) - return; - if (--s_d3d_dll_ref != 0) - return; - - if (s_d3d_dll) - FreeLibrary(s_d3d_dll); - s_d3d_dll = nullptr; - s_d3d11_create_device = nullptr; -} - -void UnloadD3DCompiler() -{ - if (!s_d3dcompiler_dll_ref) - return; - if (--s_d3dcompiler_dll_ref != 0) - return; - - if (s_d3d_compiler_dll) - FreeLibrary(s_d3d_compiler_dll); - s_d3d_compiler_dll = nullptr; - s_d3d_reflect = nullptr; -} - -std::vector EnumAAModes(IDXGIAdapter* adapter) -{ - std::vector _aa_modes; - - // NOTE: D3D 10.0 doesn't support multisampled resources which are bound as depth buffers AND - // shader resources. - // Thus, we can't have MSAA with 10.0 level hardware. - ID3D11Device* _device; - ID3D11DeviceContext* _context; - D3D_FEATURE_LEVEL feat_level; - HRESULT hr = s_d3d11_create_device(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, - supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, - D3D11_SDK_VERSION, &_device, &feat_level, &_context); - if (FAILED(hr) || feat_level == D3D_FEATURE_LEVEL_10_0) - { - DXGI_SAMPLE_DESC desc; - desc.Count = 1; - desc.Quality = 0; - _aa_modes.push_back(desc); - SAFE_RELEASE(_context); - SAFE_RELEASE(_device); - } - else - { - for (int samples = 0; samples < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; ++samples) - { - UINT quality_levels = 0; - _device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, samples, &quality_levels); - - DXGI_SAMPLE_DESC desc; - desc.Count = samples; - desc.Quality = 0; - - if (quality_levels > 0) - _aa_modes.push_back(desc); - } - _context->Release(); - _device->Release(); - } - return _aa_modes; -} - -D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter) -{ - D3D_FEATURE_LEVEL feat_level = D3D_FEATURE_LEVEL_9_1; - s_d3d11_create_device(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, supported_feature_levels, - NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, nullptr, &feat_level, - nullptr); - return feat_level; -} - -static bool SupportsS3TCTextures(ID3D11Device* dev) +static bool SupportsS3TCTextures() { UINT bc1_support, bc2_support, bc3_support; - if (FAILED(dev->CheckFormatSupport(DXGI_FORMAT_BC1_UNORM, &bc1_support)) || - FAILED(dev->CheckFormatSupport(DXGI_FORMAT_BC2_UNORM, &bc2_support)) || - FAILED(dev->CheckFormatSupport(DXGI_FORMAT_BC3_UNORM, &bc3_support))) + if (FAILED(device->CheckFormatSupport(DXGI_FORMAT_BC1_UNORM, &bc1_support)) || + FAILED(device->CheckFormatSupport(DXGI_FORMAT_BC2_UNORM, &bc2_support)) || + FAILED(device->CheckFormatSupport(DXGI_FORMAT_BC3_UNORM, &bc3_support))) { return false; } @@ -235,449 +46,202 @@ static bool SupportsS3TCTextures(ID3D11Device* dev) return ((bc1_support & bc2_support & bc3_support) & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0; } -static bool SupportsBPTCTextures(ID3D11Device* dev) +static bool SupportsBPTCTextures() { // Currently, we only care about BC7. This could be extended to BC6H in the future. UINT bc7_support; - if (FAILED(dev->CheckFormatSupport(DXGI_FORMAT_BC7_UNORM, &bc7_support))) + if (FAILED(device->CheckFormatSupport(DXGI_FORMAT_BC7_UNORM, &bc7_support))) return false; return (bc7_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0; } -static bool CreateSwapChainFramebuffer() +bool Create(u32 adapter_index, bool enable_debug_layer) { - ID3D11Texture2D* texture; - HRESULT hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&texture); - CHECK(SUCCEEDED(hr), "GetBuffer for swap chain failed with HRESULT %08X", hr); - if (FAILED(hr)) - return false; - - D3D11_TEXTURE2D_DESC desc; - texture->GetDesc(&desc); - - s_swap_chain_texture = std::make_unique( - TextureConfig(desc.Width, desc.Height, desc.MipLevels, desc.ArraySize, desc.SampleDesc.Count, - AbstractTextureFormat::RGBA8, AbstractTextureFlag_RenderTarget), - texture, nullptr, nullptr); - - ID3D11RenderTargetView* rtv; - CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(texture, D3D11_RTV_DIMENSION_TEXTURE2DARRAY, desc.Format, - 0, 0, desc.ArraySize); - hr = device->CreateRenderTargetView(texture, &rtv_desc, &rtv); - CHECK(SUCCEEDED(hr), "Create render target view for swap chain"); - if (FAILED(hr)) + PFN_D3D11_CREATE_DEVICE d3d11_create_device; + if (!s_d3d11_library.Open("d3d11.dll") || + !s_d3d11_library.GetSymbol("D3D11CreateDevice", &d3d11_create_device)) { - s_swap_chain_texture.reset(); + PanicAlertT("Failed to load d3d11.dll"); + s_d3d11_library.Close(); return false; } - SetDebugObjectName(texture, "backbuffer texture"); - SetDebugObjectName(rtv, "backbuffer render target view"); - s_swap_chain_framebuffer = std::make_unique( - s_swap_chain_texture.get(), nullptr, AbstractTextureFormat::RGBA8, - AbstractTextureFormat::Undefined, desc.Width, desc.Height, desc.ArraySize, - desc.SampleDesc.Count, rtv, nullptr, nullptr); - - return true; -} - -static bool CreateSwapChain(HWND hWnd) -{ - DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {}; - swap_chain_desc.BufferCount = 2; - swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swap_chain_desc.SampleDesc.Count = 1; - swap_chain_desc.SampleDesc.Quality = 0; - swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - swap_chain_desc.Scaling = DXGI_SCALING_STRETCH; - swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - swap_chain_desc.Stereo = g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer; - - // This flag is necessary if we want to use a flip-model swapchain without locking the framerate - swap_chain_desc.Flags = s_allow_tearing_supported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0; - - HRESULT hr = s_dxgi_factory->CreateSwapChainForHwnd(device, hWnd, &swap_chain_desc, nullptr, - nullptr, &swapchain); - if (FAILED(hr)) + if (!D3DCommon::LoadLibraries()) { - // Flip-model discard swapchains aren't supported on Windows 8, so here we fall back to - // a sequential swapchain - swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; - hr = s_dxgi_factory->CreateSwapChainForHwnd(device, hWnd, &swap_chain_desc, nullptr, nullptr, - &swapchain); - } - - if (FAILED(hr)) - { - // Flip-model swapchains aren't supported on Windows 7, so here we fall back to a legacy - // BitBlt-model swapchain - swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - hr = s_dxgi_factory->CreateSwapChainForHwnd(device, hWnd, &swap_chain_desc, nullptr, nullptr, - &swapchain); - } - - if (FAILED(hr)) - { - ERROR_LOG(VIDEO, "Failed to create swap chain with HRESULT %08X", hr); + s_d3d11_library.Close(); return false; } - if (!CreateSwapChainFramebuffer()) + dxgi_factory = D3DCommon::CreateDXGIFactory(enable_debug_layer); + if (!dxgi_factory) { - SAFE_RELEASE(swapchain); + PanicAlertT("Failed to create DXGI factory"); + D3DCommon::UnloadLibraries(); + s_d3d11_library.Close(); return false; } - return true; -} - -HRESULT Create(HWND wnd) -{ - HRESULT hr = LoadDXGI(); - if (SUCCEEDED(hr)) - hr = LoadD3D(); - if (SUCCEEDED(hr)) - hr = LoadD3DCompiler(); + ComPtr adapter; + HRESULT hr = dxgi_factory->EnumAdapters(adapter_index, &adapter); if (FAILED(hr)) { - UnloadDXGI(); - UnloadD3D(); - UnloadD3DCompiler(); - return hr; + WARN_LOG(VIDEO, "Adapter %u not found, using default", adapter_index); + adapter = nullptr; } - hr = PCreateDXGIFactory(__uuidof(IDXGIFactory2), (void**)&s_dxgi_factory); - if (FAILED(hr)) - MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 11 backend"), - MB_OK | MB_ICONERROR); - - IDXGIAdapter* adapter; - hr = s_dxgi_factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter); - if (FAILED(hr)) - { - // try using the first one - hr = s_dxgi_factory->EnumAdapters(0, &adapter); - if (FAILED(hr)) - MessageBox(wnd, _T("Failed to enumerate adapters"), _T("Dolphin Direct3D 11 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()) - { - Config::SetCurrent(Config::GFX_MSAA, UINT32_C(1)); - UpdateActiveConfig(); - } - - // Check support for allow tearing, we query the interface for backwards compatibility - UINT allow_tearing = FALSE; - IDXGIFactory5* factory5; - hr = s_dxgi_factory->QueryInterface(&factory5); - if (SUCCEEDED(hr)) - { - hr = factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing, - sizeof(allow_tearing)); - factory5->Release(); - } - s_allow_tearing_supported = SUCCEEDED(hr) && allow_tearing; - // Creating debug devices can sometimes fail if the user doesn't have the correct // version of the DirectX SDK. If it does, simply fallback to a non-debug device. - if (g_Config.bEnableValidationLayer) + if (enable_debug_layer) { - hr = s_d3d11_create_device(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_DEBUG, - supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, - D3D11_SDK_VERSION, &device, &s_featlevel, &context); + hr = d3d11_create_device(adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, + D3D11_CREATE_DEVICE_DEBUG, s_supported_feature_levels, + static_cast(ArraySize(s_supported_feature_levels)), + D3D11_SDK_VERSION, &device, &feature_level, &context); // Debugbreak on D3D error - if (SUCCEEDED(hr) && SUCCEEDED(device->QueryInterface(__uuidof(ID3D11Debug), (void**)&s_debug))) + if (SUCCEEDED(hr) && SUCCEEDED(device->QueryInterface(IID_PPV_ARGS(&s_debug)))) { - ID3D11InfoQueue* infoQueue = nullptr; - if (SUCCEEDED(s_debug->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&infoQueue))) + ComPtr info_queue; + if (SUCCEEDED(s_debug->QueryInterface(IID_PPV_ARGS(&info_queue)))) { - infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); - infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); + info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); + info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); D3D11_MESSAGE_ID hide[] = {D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS}; D3D11_INFO_QUEUE_FILTER filter = {}; filter.DenyList.NumIDs = sizeof(hide) / sizeof(D3D11_MESSAGE_ID); filter.DenyList.pIDList = hide; - infoQueue->AddStorageFilterEntries(&filter); - infoQueue->Release(); + info_queue->AddStorageFilterEntries(&filter); } } + else + { + WARN_LOG(VIDEO, "Debug layer requested but not available."); + } } - if (!g_Config.bEnableValidationLayer || FAILED(hr)) + if (!enable_debug_layer || FAILED(hr)) { - hr = s_d3d11_create_device(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, - supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, - D3D11_SDK_VERSION, &device, &s_featlevel, &context); + hr = d3d11_create_device(adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, + s_supported_feature_levels, + static_cast(ArraySize(s_supported_feature_levels)), + D3D11_SDK_VERSION, &device, &feature_level, &context); } - SAFE_RELEASE(adapter); - - if (FAILED(hr) || (wnd && !CreateSwapChain(wnd))) + if (FAILED(hr)) { - MessageBox( - wnd, - _T("Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0"), - _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR); - SAFE_RELEASE(device); - SAFE_RELEASE(context); - SAFE_RELEASE(s_dxgi_factory); - return E_FAIL; + PanicAlertT( + "Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0"); + D3DCommon::UnloadLibraries(); + return false; } - hr = device->QueryInterface(&device1); + hr = device->QueryInterface(IID_PPV_ARGS(&device1)); if (FAILED(hr)) { WARN_LOG(VIDEO, "Missing Direct3D 11.1 support. Logical operations will not be supported."); g_Config.backend_info.bSupportsLogicOp = false; } - // BGRA textures are easier to deal with in TextureCache, but might not be supported - UINT format_support; - device->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM, &format_support); - s_bgra_textures_supported = (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0; - g_Config.backend_info.bSupportsST3CTextures = SupportsS3TCTextures(device); - g_Config.backend_info.bSupportsBPTCTextures = SupportsBPTCTextures(device); + g_Config.backend_info.bSupportsST3CTextures = SupportsS3TCTextures(); + g_Config.backend_info.bSupportsBPTCTextures = SupportsBPTCTextures(); - // 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. - if (wnd) - { - hr = s_dxgi_factory->MakeWindowAssociation(wnd, DXGI_MWA_NO_WINDOW_CHANGES); - if (FAILED(hr)) - MessageBox(wnd, _T("Failed to associate the window"), _T("Dolphin Direct3D 11 backend"), - MB_OK | MB_ICONERROR); - } + // Features only supported with a FL11.0+ device. + const bool shader_model_5_supported = feature_level >= D3D_FEATURE_LEVEL_11_0; + g_Config.backend_info.bSupportsEarlyZ = shader_model_5_supported; + g_Config.backend_info.bSupportsBBox = shader_model_5_supported; + g_Config.backend_info.bSupportsFragmentStoresAndAtomics = shader_model_5_supported; + g_Config.backend_info.bSupportsGSInstancing = shader_model_5_supported; + g_Config.backend_info.bSupportsSSAA = shader_model_5_supported; - SetDebugObjectName(context, "device context"); - - stateman = new StateManager; - return S_OK; + stateman = new StateManager(); + return true; } -void Close() +void Destroy() { - // we can't release the swapchain while in fullscreen. - if (swapchain) - swapchain->SetFullscreenState(false, nullptr); + delete stateman; + stateman = nullptr; - // release all bound resources context->ClearState(); - s_swap_chain_framebuffer.reset(); - s_swap_chain_texture.reset(); - SAFE_RELEASE(swapchain); - SAFE_DELETE(stateman); - context->Flush(); // immediately destroy device objects + context->Flush(); - SAFE_RELEASE(context); - SAFE_RELEASE(device1); - ULONG references = device->Release(); + context.Reset(); + device1.Reset(); + auto remaining_references = device.Reset(); if (s_debug) { - --references; // the debug interface increases the refcount of the device, subtract that. - if (references) + --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->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL); } - SAFE_RELEASE(s_debug) + s_debug.Reset(); } - if (references) - { - ERROR_LOG(VIDEO, "Unreleased references: %i.", references); - } + if (remaining_references) + ERROR_LOG(VIDEO, "Unreleased references: %i.", remaining_references); else - { NOTICE_LOG(VIDEO, "Successfully released all device references!"); - } - device = nullptr; - // unload DLLs - UnloadD3D(); - UnloadDXGI(); + D3DCommon::UnloadLibraries(); + s_d3d11_library.Close(); } -const char* VertexShaderVersionString() +std::vector GetAAModes(u32 adapter_index) { - if (s_featlevel == D3D_FEATURE_LEVEL_11_0) - return "vs_5_0"; - else if (s_featlevel == D3D_FEATURE_LEVEL_10_1) - return "vs_4_1"; - else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ - return "vs_4_0"; -} - -const char* GeometryShaderVersionString() -{ - if (s_featlevel == D3D_FEATURE_LEVEL_11_0) - return "gs_5_0"; - else if (s_featlevel == D3D_FEATURE_LEVEL_10_1) - return "gs_4_1"; - else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ - return "gs_4_0"; -} - -const char* PixelShaderVersionString() -{ - if (s_featlevel == D3D_FEATURE_LEVEL_11_0) - return "ps_5_0"; - else if (s_featlevel == D3D_FEATURE_LEVEL_10_1) - return "ps_4_1"; - else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ - return "ps_4_0"; -} - -const char* ComputeShaderVersionString() -{ - if (s_featlevel == D3D_FEATURE_LEVEL_11_0) - return "cs_5_0"; - else if (s_featlevel == D3D_FEATURE_LEVEL_10_1) - return "cs_4_1"; - else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ - return "cs_4_0"; -} - -DXTexture* GetSwapChainTexture() -{ - return s_swap_chain_texture.get(); -} -DXFramebuffer* GetSwapChainFramebuffer() -{ - return s_swap_chain_framebuffer.get(); -} -bool BGRATexturesSupported() -{ - return s_bgra_textures_supported; -} - -bool AllowTearingSupported() -{ - return s_allow_tearing_supported; -} - -// Returns the maximum width/height of a texture. This value only depends upon the feature level in -// DX11 -u32 GetMaxTextureSize(D3D_FEATURE_LEVEL feature_level) -{ - switch (feature_level) + // Use temporary device if we don't have one already. + Common::DynamicLibrary temp_lib; + ComPtr temp_device = device; + if (!temp_device) { - case D3D_FEATURE_LEVEL_11_0: - return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + ComPtr temp_dxgi_factory = D3DCommon::CreateDXGIFactory(false); + if (!temp_dxgi_factory) + return {}; - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: - return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; + ComPtr adapter; + temp_dxgi_factory->EnumAdapters(adapter_index, &adapter); - case D3D_FEATURE_LEVEL_9_3: - return 4096; + PFN_D3D11_CREATE_DEVICE d3d11_create_device; + if (!temp_lib.Open("d3d11.dll") || + !temp_lib.GetSymbol("D3D11CreateDevice", &d3d11_create_device)) + { + return {}; + } - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: - return 2048; - - default: - return 0; + HRESULT hr = d3d11_create_device(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, + s_supported_feature_levels, + static_cast(ArraySize(s_supported_feature_levels)), + D3D11_SDK_VERSION, &temp_device, nullptr, nullptr); + if (FAILED(hr)) + return {}; } -} -void Reset(HWND new_wnd) -{ - s_swap_chain_framebuffer.reset(); - s_swap_chain_texture.reset(); + // NOTE: D3D 10.0 doesn't support multisampled resources which are bound as depth buffers AND + // shader resources. Thus, we can't have MSAA with 10.0 level hardware. + if (temp_device->GetFeatureLevel() == D3D_FEATURE_LEVEL_10_0) + return {}; - if (swapchain) + std::vector aa_modes; + for (u32 samples = 1; samples < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; ++samples) { - if (GetFullscreenState()) - swapchain->SetFullscreenState(FALSE, nullptr); - SAFE_RELEASE(swapchain); + UINT quality_levels = 0; + if (SUCCEEDED(temp_device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, samples, + &quality_levels)) && + quality_levels > 0) + { + aa_modes.push_back(samples); + } } - if (new_wnd) - CreateSwapChain(new_wnd); + return aa_modes; } - -void ResizeSwapChain() -{ - s_swap_chain_framebuffer.reset(); - s_swap_chain_texture.reset(); - const UINT swap_chain_flags = AllowTearingSupported() ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0; - swapchain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_R8G8B8A8_UNORM, swap_chain_flags); - if (!CreateSwapChainFramebuffer()) - { - PanicAlert("Failed to get swap chain textures"); - SAFE_RELEASE(swapchain); - } -} - -void Present() -{ - UINT present_flags = 0; - - // When using sync interval 0, it is recommended to always pass the tearing - // flag when it is supported, even when presenting in windowed mode. - // However, this flag cannot be used if the app is in fullscreen mode as a - // result of calling SetFullscreenState. - if (AllowTearingSupported() && !g_ActiveConfig.bVSyncActive && !GetFullscreenState()) - present_flags |= DXGI_PRESENT_ALLOW_TEARING; - - if (swapchain->IsTemporaryMonoSupported() && g_ActiveConfig.stereo_mode != StereoMode::QuadBuffer) - { - present_flags |= DXGI_PRESENT_STEREO_TEMPORARY_MONO; - } - - // TODO: Is 1 the correct value for vsyncing? - swapchain->Present(static_cast(g_ActiveConfig.bVSyncActive), present_flags); -} - -HRESULT SetFullscreenState(bool enable_fullscreen) -{ - return swapchain->SetFullscreenState(enable_fullscreen, nullptr); -} - -bool GetFullscreenState() -{ - BOOL state = FALSE; - swapchain->GetFullscreenState(&state, nullptr); - return !!state; -} - -void SetDebugObjectName(ID3D11DeviceChild* resource, const char* name) -{ -#if defined(_DEBUG) || defined(DEBUGFAST) - if (resource) - resource->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)(name ? strlen(name) : 0), name); -#endif -} - -std::string GetDebugObjectName(ID3D11DeviceChild* resource) -{ - std::string name; -#if defined(_DEBUG) || defined(DEBUGFAST) - if (resource) - { - UINT size = 0; - resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, nullptr); // get required size - name.resize(size); - resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, const_cast(name.data())); - } -#endif - return name; -} - } // namespace D3D } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/D3DBase.h b/Source/Core/VideoBackends/D3D/D3DBase.h index fedb2fe0c4..af8114b421 100644 --- a/Source/Core/VideoBackends/D3D/D3DBase.h +++ b/Source/Core/VideoBackends/D3D/D3DBase.h @@ -9,13 +9,12 @@ #include #include #include +#include #include "Common/Common.h" #include "Common/CommonTypes.h" #include "Common/MsgHandler.h" -namespace DX11 -{ #define SAFE_RELEASE(x) \ { \ if (x) \ @@ -38,61 +37,25 @@ namespace DX11 PanicAlert("%s failed in %s at line %d: " Message, __func__, __FILE__, __LINE__, __VA_ARGS__); \ } -class DXTexture; -class DXFramebuffer; +namespace DX11 +{ +using Microsoft::WRL::ComPtr; +class SwapChain; namespace D3D { -HRESULT LoadDXGI(); -HRESULT LoadD3D(); -HRESULT LoadD3DCompiler(); -void UnloadDXGI(); -void UnloadD3D(); -void UnloadD3DCompiler(); +extern ComPtr dxgi_factory; +extern ComPtr device; +extern ComPtr device1; +extern ComPtr context; +extern D3D_FEATURE_LEVEL feature_level; -D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter); -std::vector EnumAAModes(IDXGIAdapter* adapter); +bool Create(u32 adapter_index, bool enable_debug_layer); +void Destroy(); -HRESULT Create(HWND wnd); -void Close(); - -extern ID3D11Device* device; -extern ID3D11Device1* device1; -extern ID3D11DeviceContext* context; -extern IDXGISwapChain1* swapchain; - -void Reset(HWND new_wnd); -void ResizeSwapChain(); -void Present(); - -DXTexture* GetSwapChainTexture(); -DXFramebuffer* GetSwapChainFramebuffer(); -const char* PixelShaderVersionString(); -const char* GeometryShaderVersionString(); -const char* VertexShaderVersionString(); -const char* ComputeShaderVersionString(); -bool BGRATexturesSupported(); -bool AllowTearingSupported(); - -u32 GetMaxTextureSize(D3D_FEATURE_LEVEL feature_level); - -HRESULT SetFullscreenState(bool enable_fullscreen); -bool GetFullscreenState(); - -// This function will assign a name to the given resource. -// The DirectX debug layer will make it easier to identify resources that way, -// e.g. when listing up all resources who have unreleased references. -void SetDebugObjectName(ID3D11DeviceChild* resource, const char* name); -std::string GetDebugObjectName(ID3D11DeviceChild* resource); +// Returns a list of supported AA modes for the current device. +std::vector GetAAModes(u32 adapter_index); } // namespace D3D -typedef HRESULT(WINAPI* CREATEDXGIFACTORY)(REFIID, void**); -extern CREATEDXGIFACTORY PCreateDXGIFactory; -typedef HRESULT(WINAPI* D3D11CREATEDEVICE)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, - CONST D3D_FEATURE_LEVEL*, UINT, UINT, ID3D11Device**, - D3D_FEATURE_LEVEL*, ID3D11DeviceContext**); - -extern pD3DCompile PD3DCompile; - } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index 72528e51d6..174982f084 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -13,6 +13,7 @@ #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/DXTexture.h" +#include "VideoBackends/D3DCommon/Common.h" #include "VideoCommon/VideoConfig.h" namespace DX11 @@ -360,10 +361,7 @@ ID3D11SamplerState* StateCache::Get(SamplerState state) ID3D11SamplerState* res = nullptr; HRESULT hr = D3D::device->CreateSamplerState(&sampdc, &res); - if (FAILED(hr)) - PanicAlert("Fail %s %d\n", __FILE__, __LINE__); - - D3D::SetDebugObjectName(res, "sampler state used to emulate the GX pipeline"); + CHECK(SUCCEEDED(hr), "Creating D3D sampler state failed"); m_sampler.emplace(state.hex, res); return res; } @@ -400,7 +398,6 @@ ID3D11BlendState* StateCache::Get(BlendingState state) HRESULT hr = D3D::device1->CreateBlendState1(&desc, &res); if (SUCCEEDED(hr)) { - D3D::SetDebugObjectName(res, "blend state used to emulate the GX pipeline"); m_blend.emplace(state.hex, res); return res; } @@ -443,10 +440,7 @@ ID3D11BlendState* StateCache::Get(BlendingState state) ID3D11BlendState* res = nullptr; HRESULT hr = D3D::device->CreateBlendState(&desc, &res); - if (FAILED(hr)) - PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__); - - D3D::SetDebugObjectName(res, "blend state used to emulate the GX pipeline"); + CHECK(SUCCEEDED(hr), "Creating D3D blend state failed"); m_blend.emplace(state.hex, res); return res; } @@ -468,10 +462,7 @@ ID3D11RasterizerState* StateCache::Get(RasterizationState state) ID3D11RasterizerState* res = nullptr; HRESULT hr = D3D::device->CreateRasterizerState(&desc, &res); - if (FAILED(hr)) - PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__); - - D3D::SetDebugObjectName(res, "rasterizer state used to emulate the GX pipeline"); + CHECK(SUCCEEDED(hr), "Creating D3D rasterizer state failed"); m_raster.emplace(state.hex, res); return res; } @@ -515,13 +506,8 @@ ID3D11DepthStencilState* StateCache::Get(DepthState state) ID3D11DepthStencilState* res = nullptr; HRESULT hr = D3D::device->CreateDepthStencilState(&depthdc, &res); - if (SUCCEEDED(hr)) - D3D::SetDebugObjectName(res, "depth-stencil state used to emulate the GX pipeline"); - else - PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__); - + CHECK(SUCCEEDED(hr), "Creating D3D depth stencil state failed"); m_depth.emplace(state.hex, res); - return res; } diff --git a/Source/Core/VideoBackends/D3D/DXShader.cpp b/Source/Core/VideoBackends/D3D/DXShader.cpp index 18f9aa0d3d..96202558f6 100644 --- a/Source/Core/VideoBackends/D3D/DXShader.cpp +++ b/Source/Core/VideoBackends/D3D/DXShader.cpp @@ -2,22 +2,14 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include - -#include "Common/Assert.h" -#include "Common/FileUtil.h" -#include "Common/Logging/Log.h" -#include "Common/MsgHandler.h" -#include "Common/StringUtil.h" - -#include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/DXShader.h" -#include "VideoCommon/VideoConfig.h" +#include "Common/Assert.h" +#include "VideoBackends/D3D/D3DBase.h" namespace DX11 { DXShader::DXShader(ShaderStage stage, BinaryData bytecode, ID3D11DeviceChild* shader) - : AbstractShader(stage), m_bytecode(bytecode), m_shader(shader) + : D3DCommon::Shader(stage, std::move(bytecode)), m_shader(shader) { } @@ -50,16 +42,6 @@ ID3D11ComputeShader* DXShader::GetD3DComputeShader() const return static_cast(m_shader); } -bool DXShader::HasBinary() const -{ - return true; -} - -AbstractShader::BinaryData DXShader::GetBinary() const -{ - return m_bytecode; -} - std::unique_ptr DXShader::CreateFromBytecode(ShaderStage stage, BinaryData bytecode) { switch (stage) @@ -117,86 +99,4 @@ std::unique_ptr DXShader::CreateFromBytecode(ShaderStage stage, Binary return nullptr; } - -static const char* GetCompileTarget(ShaderStage stage) -{ - switch (stage) - { - case ShaderStage::Vertex: - return D3D::VertexShaderVersionString(); - case ShaderStage::Geometry: - return D3D::GeometryShaderVersionString(); - case ShaderStage::Pixel: - return D3D::PixelShaderVersionString(); - case ShaderStage::Compute: - return D3D::ComputeShaderVersionString(); - default: - return ""; - } -} - -bool DXShader::CompileShader(BinaryData* out_bytecode, ShaderStage stage, const char* source, - size_t length) -{ - static constexpr D3D_SHADER_MACRO macros[] = {{"API_D3D", "1"}, {nullptr, nullptr}}; - const UINT flags = g_ActiveConfig.bEnableValidationLayer ? - (D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION) : - (D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_SKIP_VALIDATION); - const char* target = GetCompileTarget(stage); - - ID3DBlob* code = nullptr; - ID3DBlob* errors = nullptr; - HRESULT hr = PD3DCompile(source, length, nullptr, macros, nullptr, "main", target, flags, 0, - &code, &errors); - if (FAILED(hr)) - { - static int num_failures = 0; - std::string filename = StringFromFormat( - "%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), target, num_failures++); - std::ofstream file; - File::OpenFStream(file, filename, std::ios_base::out); - file.write(source, length); - file << "\n"; - file.write(static_cast(errors->GetBufferPointer()), errors->GetBufferSize()); - file.close(); - - PanicAlert("Failed to compile %s:\nDebug info (%s):\n%s", filename.c_str(), target, - static_cast(errors->GetBufferPointer())); - errors->Release(); - return false; - } - - if (errors && errors->GetBufferSize() > 0) - { - WARN_LOG(VIDEO, "%s compilation succeeded with warnings:\n%s", target, - static_cast(errors->GetBufferPointer())); - } - SAFE_RELEASE(errors); - - out_bytecode->resize(code->GetBufferSize()); - std::memcpy(out_bytecode->data(), code->GetBufferPointer(), code->GetBufferSize()); - code->Release(); - return true; -} - -std::unique_ptr DXShader::CreateFromSource(ShaderStage stage, const char* source, - size_t length) -{ - BinaryData bytecode; - if (!CompileShader(&bytecode, stage, source, length)) - return nullptr; - - return CreateFromBytecode(stage, std::move(bytecode)); -} - -std::unique_ptr DXShader::CreateFromBinary(ShaderStage stage, const void* data, - size_t length) -{ - if (length == 0) - return nullptr; - - BinaryData bytecode(length); - std::memcpy(bytecode.data(), data, length); - return CreateFromBytecode(stage, std::move(bytecode)); -} } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/DXShader.h b/Source/Core/VideoBackends/D3D/DXShader.h index a86a993b80..f793bc786b 100644 --- a/Source/Core/VideoBackends/D3D/DXShader.h +++ b/Source/Core/VideoBackends/D3D/DXShader.h @@ -6,11 +6,11 @@ #include #include -#include "VideoCommon/AbstractShader.h" +#include "VideoBackends/D3DCommon/Shader.h" namespace DX11 { -class DXShader final : public AbstractShader +class DXShader final : public D3DCommon::Shader { public: DXShader(ShaderStage stage, BinaryData bytecode, ID3D11DeviceChild* shader); @@ -23,22 +23,10 @@ public: ID3D11PixelShader* GetD3DPixelShader() const; ID3D11ComputeShader* GetD3DComputeShader() const; - bool HasBinary() const override; - BinaryData GetBinary() const override; - - // Creates a new shader object. static std::unique_ptr CreateFromBytecode(ShaderStage stage, BinaryData bytecode); - static bool CompileShader(BinaryData* out_bytecode, ShaderStage stage, const char* source, - size_t length); - - static std::unique_ptr CreateFromBinary(ShaderStage stage, const void* data, - size_t length); - static std::unique_ptr CreateFromSource(ShaderStage stage, const char* source, - size_t length); private: ID3D11DeviceChild* m_shader; - BinaryData m_bytecode; }; } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/DXTexture.cpp b/Source/Core/VideoBackends/D3D/DXTexture.cpp index dc1c04991a..bedac90fb5 100644 --- a/Source/Core/VideoBackends/D3D/DXTexture.cpp +++ b/Source/Core/VideoBackends/D3D/DXTexture.cpp @@ -11,141 +11,27 @@ #include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/DXTexture.h" +#include "VideoBackends/D3DCommon/Common.h" namespace DX11 { -namespace -{ -DXGI_FORMAT GetDXGIFormatForHostFormat(AbstractTextureFormat format, bool typeless) -{ - switch (format) - { - case AbstractTextureFormat::DXT1: - return DXGI_FORMAT_BC1_UNORM; - case AbstractTextureFormat::DXT3: - return DXGI_FORMAT_BC2_UNORM; - case AbstractTextureFormat::DXT5: - return DXGI_FORMAT_BC3_UNORM; - case AbstractTextureFormat::BPTC: - return DXGI_FORMAT_BC7_UNORM; - case AbstractTextureFormat::RGBA8: - return typeless ? DXGI_FORMAT_R8G8B8A8_TYPELESS : DXGI_FORMAT_R8G8B8A8_UNORM; - case AbstractTextureFormat::BGRA8: - return typeless ? DXGI_FORMAT_B8G8R8A8_TYPELESS : DXGI_FORMAT_B8G8R8A8_UNORM; - case AbstractTextureFormat::R16: - return typeless ? DXGI_FORMAT_R16_TYPELESS : DXGI_FORMAT_R16_UNORM; - case AbstractTextureFormat::R32F: - return typeless ? DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_R32_FLOAT; - case AbstractTextureFormat::D16: - return DXGI_FORMAT_R16_TYPELESS; - case AbstractTextureFormat::D24_S8: - return DXGI_FORMAT_R24G8_TYPELESS; - case AbstractTextureFormat::D32F: - return DXGI_FORMAT_R32_TYPELESS; - case AbstractTextureFormat::D32F_S8: - return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; - default: - PanicAlert("Unhandled texture format."); - return DXGI_FORMAT_R8G8B8A8_UNORM; - } -} -DXGI_FORMAT GetSRVFormatForHostFormat(AbstractTextureFormat format) -{ - switch (format) - { - case AbstractTextureFormat::DXT1: - return DXGI_FORMAT_BC1_UNORM; - case AbstractTextureFormat::DXT3: - return DXGI_FORMAT_BC2_UNORM; - case AbstractTextureFormat::DXT5: - return DXGI_FORMAT_BC3_UNORM; - case AbstractTextureFormat::BPTC: - return DXGI_FORMAT_BC7_UNORM; - case AbstractTextureFormat::RGBA8: - return DXGI_FORMAT_R8G8B8A8_UNORM; - case AbstractTextureFormat::BGRA8: - return DXGI_FORMAT_B8G8R8A8_UNORM; - case AbstractTextureFormat::R16: - return DXGI_FORMAT_R16_UNORM; - case AbstractTextureFormat::R32F: - return DXGI_FORMAT_R32_FLOAT; - case AbstractTextureFormat::D16: - return DXGI_FORMAT_R16_UNORM; - case AbstractTextureFormat::D24_S8: - return DXGI_FORMAT_R24_UNORM_X8_TYPELESS; - case AbstractTextureFormat::D32F: - return DXGI_FORMAT_R32_FLOAT; - case AbstractTextureFormat::D32F_S8: - return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; - default: - PanicAlert("Unhandled SRV format"); - return DXGI_FORMAT_UNKNOWN; - } -} -DXGI_FORMAT GetRTVFormatForHostFormat(AbstractTextureFormat format, bool integer) -{ - switch (format) - { - case AbstractTextureFormat::RGBA8: - return integer ? DXGI_FORMAT_R8G8B8A8_UINT : DXGI_FORMAT_R8G8B8A8_UNORM; - case AbstractTextureFormat::BGRA8: - return DXGI_FORMAT_B8G8R8A8_UNORM; - case AbstractTextureFormat::R16: - return integer ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R16_UNORM; - case AbstractTextureFormat::R32F: - return DXGI_FORMAT_R32_FLOAT; - default: - PanicAlert("Unhandled RTV format"); - return DXGI_FORMAT_UNKNOWN; - } -} -DXGI_FORMAT GetDSVFormatForHostFormat(AbstractTextureFormat format) -{ - switch (format) - { - case AbstractTextureFormat::D16: - return DXGI_FORMAT_D16_UNORM; - case AbstractTextureFormat::D24_S8: - return DXGI_FORMAT_D24_UNORM_S8_UINT; - case AbstractTextureFormat::D32F: - return DXGI_FORMAT_D32_FLOAT; - case AbstractTextureFormat::D32F_S8: - return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; - default: - PanicAlert("Unhandled DSV format"); - return DXGI_FORMAT_UNKNOWN; - } -} -} // Anonymous namespace - -DXTexture::DXTexture(const TextureConfig& tex_config, ID3D11Texture2D* d3d_texture, - ID3D11ShaderResourceView* d3d_srv, ID3D11UnorderedAccessView* d3d_uav) - : AbstractTexture(tex_config), m_d3d_texture(d3d_texture), m_d3d_srv(d3d_srv), - m_d3d_uav(d3d_uav) +DXTexture::DXTexture(const TextureConfig& config, ID3D11Texture2D* texture) + : AbstractTexture(config), m_texture(texture) { } DXTexture::~DXTexture() { - if (m_d3d_uav) - m_d3d_uav->Release(); - - if (m_d3d_srv) - { - if (D3D::stateman->UnsetTexture(m_d3d_srv) != 0) - D3D::stateman->ApplyTextures(); - - m_d3d_srv->Release(); - } - m_d3d_texture->Release(); + if (m_srv && D3D::stateman->UnsetTexture(m_srv.Get()) != 0) + D3D::stateman->ApplyTextures(); } std::unique_ptr DXTexture::Create(const TextureConfig& config) { // Use typeless to create the texture when it's a render target, so we can alias it with an // integer format (for EFB). - const DXGI_FORMAT tex_format = GetDXGIFormatForHostFormat(config.format, config.IsRenderTarget()); - const DXGI_FORMAT srv_format = GetSRVFormatForHostFormat(config.format); + const DXGI_FORMAT tex_format = + D3DCommon::GetDXGIFormatForAbstractFormat(config.format, config.IsRenderTarget()); UINT bindflags = D3D11_BIND_SHADER_RESOURCE; if (config.IsRenderTarget()) bindflags |= IsDepthFormat(config.format) ? D3D11_BIND_DEPTH_STENCIL : D3D11_BIND_RENDER_TARGET; @@ -154,7 +40,7 @@ std::unique_ptr DXTexture::Create(const TextureConfig& config) CD3D11_TEXTURE2D_DESC desc(tex_format, config.width, config.height, config.layers, config.levels, bindflags, D3D11_USAGE_DEFAULT, 0, config.samples, 0, 0); - ID3D11Texture2D* d3d_texture; + ComPtr d3d_texture; HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, &d3d_texture); if (FAILED(hr)) { @@ -163,36 +49,69 @@ std::unique_ptr DXTexture::Create(const TextureConfig& config) return nullptr; } - ID3D11ShaderResourceView* d3d_srv; - const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(d3d_texture, - config.IsMultisampled() ? - D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY : - D3D11_SRV_DIMENSION_TEXTURE2DARRAY, - srv_format, 0, config.levels, 0, config.layers); - hr = D3D::device->CreateShaderResourceView(d3d_texture, &srv_desc, &d3d_srv); + std::unique_ptr tex(new DXTexture(config, d3d_texture.Get())); + if (!tex->CreateSRV() || (config.IsComputeImage() && !tex->CreateUAV())) + return nullptr; + + return tex; +} + +std::unique_ptr DXTexture::CreateAdopted(ID3D11Texture2D* texture) +{ + D3D11_TEXTURE2D_DESC desc; + texture->GetDesc(&desc); + + // Convert to our texture config format. + TextureConfig config(desc.Width, desc.Height, desc.MipLevels, desc.ArraySize, + desc.SampleDesc.Count, + D3DCommon::GetAbstractFormatForDXGIFormat(desc.Format), 0); + if (desc.BindFlags & D3D11_BIND_RENDER_TARGET) + config.flags |= AbstractTextureFlag_RenderTarget; + if (desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) + config.flags |= AbstractTextureFlag_ComputeImage; + + std::unique_ptr tex(new DXTexture(config, texture)); + if (desc.BindFlags & D3D11_BIND_SHADER_RESOURCE && !tex->CreateSRV()) + return nullptr; + if (desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS && !tex->CreateUAV()) + return nullptr; + + return tex; +} + +bool DXTexture::CreateSRV() +{ + const CD3D11_SHADER_RESOURCE_VIEW_DESC desc( + m_texture.Get(), + m_config.IsMultisampled() ? D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY : + D3D11_SRV_DIMENSION_TEXTURE2DARRAY, + D3DCommon::GetSRVFormatForAbstractFormat(m_config.format), 0, m_config.levels, 0, + m_config.layers); + HRESULT hr = D3D::device->CreateShaderResourceView(m_texture.Get(), &desc, &m_srv); if (FAILED(hr)) { - PanicAlert("Failed to create %ux%ux%u D3D SRV", config.width, config.height, config.layers); - d3d_texture->Release(); - return nullptr; + PanicAlert("Failed to create %ux%ux%u D3D SRV", m_config.width, m_config.height, + m_config.layers); + return false; } - ID3D11UnorderedAccessView* d3d_uav = nullptr; - if (config.IsComputeImage()) + return true; +} + +bool DXTexture::CreateUAV() +{ + const CD3D11_UNORDERED_ACCESS_VIEW_DESC desc( + m_texture.Get(), D3D11_UAV_DIMENSION_TEXTURE2DARRAY, + D3DCommon::GetSRVFormatForAbstractFormat(m_config.format), 0, 0, m_config.layers); + HRESULT hr = D3D::device->CreateUnorderedAccessView(m_texture.Get(), &desc, &m_uav); + if (FAILED(hr)) { - const CD3D11_UNORDERED_ACCESS_VIEW_DESC uav_desc( - d3d_texture, D3D11_UAV_DIMENSION_TEXTURE2DARRAY, srv_format, 0, 0, config.layers); - hr = D3D::device->CreateUnorderedAccessView(d3d_texture, &uav_desc, &d3d_uav); - if (FAILED(hr)) - { - PanicAlert("Failed to create %ux%ux%u D3D UAV", config.width, config.height, config.layers); - d3d_uav->Release(); - d3d_texture->Release(); - return nullptr; - } + PanicAlert("Failed to create %ux%ux%u D3D UAV", m_config.width, m_config.height, + m_config.layers); + return false; } - return std::make_unique(config, d3d_texture, d3d_srv, d3d_uav); + return true; } void DXTexture::CopyRectangleFromTexture(const AbstractTexture* src, @@ -213,8 +132,8 @@ void DXTexture::CopyRectangleFromTexture(const AbstractTexture* src, src_box.back = 1; D3D::context->CopySubresourceRegion( - m_d3d_texture, D3D11CalcSubresource(dst_level, dst_layer, m_config.levels), dst_rect.left, - dst_rect.top, 0, srcentry->m_d3d_texture, + m_texture.Get(), D3D11CalcSubresource(dst_level, dst_layer, m_config.levels), dst_rect.left, + dst_rect.top, 0, srcentry->m_texture.Get(), D3D11CalcSubresource(src_level, src_layer, srcentry->m_config.levels), &src_box); } @@ -228,16 +147,16 @@ void DXTexture::ResolveFromTexture(const AbstractTexture* src, const MathUtil::R rect.top + rect.GetHeight() <= static_cast(srcentry->m_config.height)); D3D::context->ResolveSubresource( - m_d3d_texture, D3D11CalcSubresource(level, layer, m_config.levels), srcentry->m_d3d_texture, - D3D11CalcSubresource(level, layer, srcentry->m_config.levels), - GetDXGIFormatForHostFormat(m_config.format, false)); + m_texture.Get(), D3D11CalcSubresource(level, layer, m_config.levels), + srcentry->m_texture.Get(), D3D11CalcSubresource(level, layer, srcentry->m_config.levels), + D3DCommon::GetDXGIFormatForAbstractFormat(m_config.format, false)); } void DXTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) { size_t src_pitch = CalculateStrideForFormat(m_config.format, row_length); - D3D::context->UpdateSubresource(m_d3d_texture, level, nullptr, buffer, + D3D::context->UpdateSubresource(m_texture.Get(), level, nullptr, buffer, static_cast(src_pitch), 0); } @@ -275,8 +194,8 @@ std::unique_ptr DXStagingTexture::Create(StagingTextureType ty cpu_flags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; } - CD3D11_TEXTURE2D_DESC desc(GetDXGIFormatForHostFormat(config.format, false), config.width, - config.height, 1, 1, 0, usage, cpu_flags); + CD3D11_TEXTURE2D_DESC desc(D3DCommon::GetDXGIFormatForAbstractFormat(config.format, false), + config.width, config.height, 1, 1, 0, usage, cpu_flags); ID3D11Texture2D* texture; HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, &texture); @@ -437,14 +356,15 @@ std::unique_ptr DXFramebuffer::Create(DXTexture* color_attachment CD3D11_RENDER_TARGET_VIEW_DESC desc( color_attachment->IsMultisampled() ? D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D11_RTV_DIMENSION_TEXTURE2DARRAY, - GetRTVFormatForHostFormat(color_attachment->GetFormat(), false), 0, 0, + D3DCommon::GetRTVFormatForAbstractFormat(color_attachment->GetFormat(), false), 0, 0, color_attachment->GetLayers()); HRESULT hr = D3D::device->CreateRenderTargetView(color_attachment->GetD3DTexture(), &desc, &rtv); CHECK(SUCCEEDED(hr), "Create render target view for framebuffer"); // Only create the integer RTV on Win8+. - DXGI_FORMAT integer_format = GetRTVFormatForHostFormat(color_attachment->GetFormat(), true); + DXGI_FORMAT integer_format = + D3DCommon::GetRTVFormatForAbstractFormat(color_attachment->GetFormat(), true); if (D3D::device1 && integer_format != desc.Format) { desc.Format = integer_format; @@ -460,7 +380,7 @@ std::unique_ptr DXFramebuffer::Create(DXTexture* color_attachment const CD3D11_DEPTH_STENCIL_VIEW_DESC desc( depth_attachment->GetConfig().IsMultisampled() ? D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D11_DSV_DIMENSION_TEXTURE2DARRAY, - GetDSVFormatForHostFormat(depth_attachment->GetFormat()), 0, 0, + D3DCommon::GetDSVFormatForAbstractFormat(depth_attachment->GetFormat()), 0, 0, depth_attachment->GetLayers(), 0); HRESULT hr = D3D::device->CreateDepthStencilView(depth_attachment->GetD3DTexture(), &desc, &dsv); diff --git a/Source/Core/VideoBackends/D3D/DXTexture.h b/Source/Core/VideoBackends/D3D/DXTexture.h index 0a4e0ace48..78a3abd411 100644 --- a/Source/Core/VideoBackends/D3D/DXTexture.h +++ b/Source/Core/VideoBackends/D3D/DXTexture.h @@ -17,11 +17,10 @@ namespace DX11 class DXTexture final : public AbstractTexture { public: - explicit DXTexture(const TextureConfig& tex_config, ID3D11Texture2D* d3d_texture, - ID3D11ShaderResourceView* d3d_srv, ID3D11UnorderedAccessView* d3d_uav); ~DXTexture(); static std::unique_ptr Create(const TextureConfig& config); + static std::unique_ptr CreateAdopted(ID3D11Texture2D* texture); void CopyRectangleFromTexture(const AbstractTexture* src, const MathUtil::Rectangle& src_rect, u32 src_layer, @@ -32,14 +31,19 @@ public: void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) override; - ID3D11Texture2D* GetD3DTexture() const { return m_d3d_texture; } - ID3D11ShaderResourceView* GetD3DSRV() const { return m_d3d_srv; } - ID3D11UnorderedAccessView* GetD3DUAV() const { return m_d3d_uav; } + ID3D11Texture2D* GetD3DTexture() const { return m_texture.Get(); } + ID3D11ShaderResourceView* GetD3DSRV() const { return m_srv.Get(); } + ID3D11UnorderedAccessView* GetD3DUAV() const { return m_uav.Get(); } private: - ID3D11Texture2D* m_d3d_texture; - ID3D11ShaderResourceView* m_d3d_srv; - ID3D11UnorderedAccessView* m_d3d_uav; + DXTexture(const TextureConfig& config, ID3D11Texture2D* texture); + + bool CreateSRV(); + bool CreateUAV(); + + ComPtr m_texture; + ComPtr m_srv; + ComPtr m_uav; }; class DXStagingTexture final : public AbstractStagingTexture diff --git a/Source/Core/VideoBackends/D3D/NativeVertexFormat.cpp b/Source/Core/VideoBackends/D3D/NativeVertexFormat.cpp index 4d3407ed04..05da306a2b 100644 --- a/Source/Core/VideoBackends/D3D/NativeVertexFormat.cpp +++ b/Source/Core/VideoBackends/D3D/NativeVertexFormat.cpp @@ -160,9 +160,7 @@ ID3D11InputLayout* D3DVertexFormat::GetInputLayout(const void* vs_bytecode, size HRESULT hr = D3D::device->CreateInputLayout(m_elems.data(), m_num_elems, vs_bytecode, vs_bytecode_size, &layout); - if (FAILED(hr)) - PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__); - DX11::D3D::SetDebugObjectName(m_layout, "input layout used to emulate the GX pipeline"); + CHECK(SUCCEEDED(hr), "Failed to create input layout"); // This method can be called from multiple threads, so ensure that only one thread sets the // cached input layout pointer. If another thread beats this thread, use the existing layout. diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index a172425e3f..1bfffb0638 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -26,6 +26,7 @@ #include "VideoBackends/D3D/DXPipeline.h" #include "VideoBackends/D3D/DXShader.h" #include "VideoBackends/D3D/DXTexture.h" +#include "VideoBackends/D3D/SwapChain.h" #include "VideoCommon/BPFunctions.h" #include "VideoCommon/FramebufferManager.h" @@ -48,11 +49,12 @@ typedef struct _Nv_Stereo_Image_Header #define NVSTEREO_IMAGE_SIGNATURE 0x4433564e -Renderer::Renderer(int backbuffer_width, int backbuffer_height, float backbuffer_scale) - : ::Renderer(backbuffer_width, backbuffer_height, backbuffer_scale, - AbstractTextureFormat::RGBA8) +Renderer::Renderer(std::unique_ptr swap_chain, float backbuffer_scale) + : ::Renderer(swap_chain ? swap_chain->GetWidth() : 0, swap_chain ? swap_chain->GetHeight() : 0, + backbuffer_scale, + swap_chain ? swap_chain->GetFormat() : AbstractTextureFormat::Undefined), + m_swap_chain(std::move(swap_chain)) { - m_last_fullscreen_state = D3D::GetFullscreenState(); } Renderer::~Renderer() = default; @@ -82,17 +84,13 @@ void Renderer::Create3DVisionTexture(int width, int height) ID3D11Texture2D* texture; HRESULT hr = D3D::device->CreateTexture2D(&texture_desc, &sys_data, &texture); CHECK(SUCCEEDED(hr), "Create 3D Vision Texture"); - m_3d_vision_texture = std::make_unique(TextureConfig(width * 2, height + 1, 1, 1, 1, - AbstractTextureFormat::RGBA8, - AbstractTextureFlag_RenderTarget), - texture, nullptr, nullptr); - m_3d_vision_framebuffer = - DXFramebuffer::Create(static_cast(m_3d_vision_texture.get()), nullptr); + m_3d_vision_texture = DXTexture::CreateAdopted(texture); + m_3d_vision_framebuffer = DXFramebuffer::Create(m_3d_vision_texture.get(), nullptr); } bool Renderer::IsHeadless() const { - return D3D::swapchain == nullptr; + return !m_swap_chain; } std::unique_ptr Renderer::CreateTexture(const TextureConfig& config) @@ -116,13 +114,17 @@ std::unique_ptr Renderer::CreateFramebuffer(AbstractTexture std::unique_ptr Renderer::CreateShaderFromSource(ShaderStage stage, const char* source, size_t length) { - return DXShader::CreateFromSource(stage, source, length); + DXShader::BinaryData bytecode; + if (!DXShader::CompileShader(D3D::feature_level, &bytecode, stage, source, length)) + return nullptr; + + return DXShader::CreateFromBytecode(stage, std::move(bytecode)); } std::unique_ptr Renderer::CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length) { - return DXShader::CreateFromBinary(stage, data, length); + return DXShader::CreateFromBytecode(stage, DXShader::CreateByteCode(data, length)); } std::unique_ptr Renderer::CreatePipeline(const AbstractPipelineConfig& config) @@ -196,64 +198,44 @@ void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groups_x, void Renderer::BindBackbuffer(const ClearColor& clear_color) { - CheckForSurfaceChange(); - CheckForSurfaceResize(); - SetAndClearFramebuffer(D3D::GetSwapChainFramebuffer(), clear_color); + CheckForSwapChainChanges(); + SetAndClearFramebuffer(m_swap_chain->GetFramebuffer(), clear_color); } void Renderer::PresentBackbuffer() { - D3D::Present(); + m_swap_chain->Present(); } void Renderer::OnConfigChanged(u32 bits) { + // Quad-buffer changes require swap chain recreation. + if (bits & CONFIG_CHANGE_BIT_STEREO_MODE && m_swap_chain) + m_swap_chain->SetStereo(SwapChain::WantsStereo()); } -void Renderer::CheckForSurfaceChange() +void Renderer::CheckForSwapChainChanges() { - if (!m_surface_changed.TestAndClear()) + const bool surface_changed = m_surface_changed.TestAndClear(); + const bool surface_resized = + m_surface_resized.TestAndClear() || m_swap_chain->CheckForFullscreenChange(); + if (!surface_changed && !surface_resized) return; - m_3d_vision_framebuffer.reset(); - m_3d_vision_texture.reset(); - - D3D::Reset(reinterpret_cast(m_new_surface_handle)); - m_new_surface_handle = nullptr; - - UpdateBackbufferSize(); -} - -void Renderer::CheckForSurfaceResize() -{ - const bool fullscreen_state = D3D::GetFullscreenState(); - const bool exclusive_fullscreen_changed = fullscreen_state != m_last_fullscreen_state; - if (!m_surface_resized.TestAndClear() && !exclusive_fullscreen_changed) - return; - - m_3d_vision_framebuffer.reset(); - m_3d_vision_texture.reset(); - - m_last_fullscreen_state = fullscreen_state; - if (D3D::swapchain) - D3D::ResizeSwapChain(); - UpdateBackbufferSize(); -} - -void Renderer::UpdateBackbufferSize() -{ - if (D3D::swapchain) + if (surface_changed) { - DXGI_SWAP_CHAIN_DESC1 desc = {}; - D3D::swapchain->GetDesc1(&desc); - m_backbuffer_width = std::max(desc.Width, 1u); - m_backbuffer_height = std::max(desc.Height, 1u); + m_swap_chain->ChangeSurface(m_new_surface_handle); + m_new_surface_handle = nullptr; } else { - m_backbuffer_width = 1; - m_backbuffer_height = 1; + m_swap_chain->ResizeSwapChain(); } + + m_backbuffer_width = m_swap_chain->GetWidth(); + m_backbuffer_height = m_swap_chain->GetHeight(); + m_3d_vision_framebuffer.reset(); + m_3d_vision_texture.reset(); } void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer) @@ -392,22 +374,23 @@ void Renderer::RenderXFBToScreen(const AbstractTexture* texture, const EFBRectan // Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should // recognize the signature and automatically include the right eye frame. - const CD3D11_BOX box(0, 0, 0, m_backbuffer_width, m_backbuffer_height, 1); - D3D::context->CopySubresourceRegion(D3D::GetSwapChainTexture()->GetD3DTexture(), 0, 0, 0, 0, + const CD3D11_BOX box(0, 0, 0, m_swap_chain->GetWidth(), m_swap_chain->GetHeight(), 1); + D3D::context->CopySubresourceRegion(m_swap_chain->GetTexture()->GetD3DTexture(), 0, 0, 0, 0, m_3d_vision_texture->GetD3DTexture(), 0, &box); // Restore render target to backbuffer - SetFramebuffer(D3D::GetSwapChainFramebuffer()); + SetFramebuffer(m_swap_chain->GetFramebuffer()); } void Renderer::SetFullscreen(bool enable_fullscreen) { - D3D::SetFullscreenState(enable_fullscreen); + if (m_swap_chain) + m_swap_chain->SetFullscreen(enable_fullscreen); } bool Renderer::IsFullscreen() const { - return D3D::GetFullscreenState(); + return m_swap_chain && m_swap_chain->GetFullscreen(); } } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/Render.h b/Source/Core/VideoBackends/D3D/Render.h index 0f9b38761e..551295a9d5 100644 --- a/Source/Core/VideoBackends/D3D/Render.h +++ b/Source/Core/VideoBackends/D3D/Render.h @@ -11,13 +11,14 @@ namespace DX11 { +class SwapChain; class DXTexture; class DXFramebuffer; class Renderer : public ::Renderer { public: - Renderer(int backbuffer_width, int backbuffer_height, float backbuffer_scale); + Renderer(std::unique_ptr swap_chain, float backbuffer_scale); ~Renderer() override; StateCache& GetStateCache() { return m_state_cache; } @@ -69,15 +70,12 @@ public: private: void Create3DVisionTexture(int width, int height); - void CheckForSurfaceChange(); - void CheckForSurfaceResize(); - void UpdateBackbufferSize(); + void CheckForSwapChainChanges(); StateCache m_state_cache; + std::unique_ptr m_swap_chain; std::unique_ptr m_3d_vision_texture; std::unique_ptr m_3d_vision_framebuffer; - - bool m_last_fullscreen_state = false; }; } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/SwapChain.cpp b/Source/Core/VideoBackends/D3D/SwapChain.cpp new file mode 100644 index 0000000000..d5ce3372c0 --- /dev/null +++ b/Source/Core/VideoBackends/D3D/SwapChain.cpp @@ -0,0 +1,52 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "VideoBackends/D3D/SwapChain.h" +#include "VideoBackends/D3D/DXTexture.h" + +namespace DX11 +{ +SwapChain::SwapChain(const WindowSystemInfo& wsi, IDXGIFactory2* dxgi_factory, + ID3D11Device* d3d_device) + : D3DCommon::SwapChain(wsi, dxgi_factory, d3d_device) +{ +} + +SwapChain::~SwapChain() = default; + +std::unique_ptr SwapChain::Create(const WindowSystemInfo& wsi) +{ + std::unique_ptr swap_chain = + std::make_unique(wsi, D3D::dxgi_factory.Get(), D3D::device.Get()); + if (!swap_chain->CreateSwapChain(WantsStereo())) + return nullptr; + + return swap_chain; +} + +bool SwapChain::CreateSwapChainBuffers() +{ + ComPtr texture; + HRESULT hr = m_swap_chain->GetBuffer(0, IID_PPV_ARGS(&texture)); + CHECK(SUCCEEDED(hr), "Get swap chain buffer"); + if (FAILED(hr)) + return false; + + m_texture = DXTexture::CreateAdopted(texture.Get()); + if (!m_texture) + return false; + + m_framebuffer = DXFramebuffer::Create(m_texture.get(), nullptr); + if (!m_framebuffer) + return false; + + return true; +} + +void SwapChain::DestroySwapChainBuffers() +{ + m_framebuffer.reset(); + m_texture.reset(); +} +} // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/SwapChain.h b/Source/Core/VideoBackends/D3D/SwapChain.h new file mode 100644 index 0000000000..1579459eb6 --- /dev/null +++ b/Source/Core/VideoBackends/D3D/SwapChain.h @@ -0,0 +1,44 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include + +#include "Common/CommonTypes.h" +#include "Common/WindowSystemInfo.h" +#include "VideoBackends/D3D/D3DBase.h" +#include "VideoBackends/D3DCommon/SwapChain.h" +#include "VideoCommon/TextureConfig.h" + +namespace DX11 +{ +class DXTexture; +class DXFramebuffer; + +class SwapChain : public D3DCommon::SwapChain +{ +public: + SwapChain(const WindowSystemInfo& wsi, IDXGIFactory2* dxgi_factory, ID3D11Device* d3d_device); + ~SwapChain(); + + static std::unique_ptr Create(const WindowSystemInfo& wsi); + + DXTexture* GetTexture() const { return m_texture.get(); } + DXFramebuffer* GetFramebuffer() const { return m_framebuffer.get(); } + +protected: + bool CreateSwapChainBuffers() override; + void DestroySwapChainBuffers() override; + +private: + // The runtime takes care of renaming the buffers. + std::unique_ptr m_texture; + std::unique_ptr m_framebuffer; +}; + +} // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/VertexManager.cpp b/Source/Core/VideoBackends/D3D/VertexManager.cpp index 479f601037..3027842426 100644 --- a/Source/Core/VideoBackends/D3D/VertexManager.cpp +++ b/Source/Core/VideoBackends/D3D/VertexManager.cpp @@ -14,6 +14,7 @@ #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/Render.h" +#include "VideoBackends/D3DCommon/Common.h" #include "VideoCommon/BoundingBox.h" #include "VideoCommon/GeometryShaderManager.h" @@ -34,8 +35,11 @@ static ID3D11Buffer* AllocateConstantBuffer(u32 size) D3D11_CPU_ACCESS_WRITE); ID3D11Buffer* cbuf; const HRESULT hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &cbuf); - CHECK(hr == S_OK, "shader constant buffer (size=%u)", cbsize); - D3D::SetDebugObjectName(cbuf, "constant buffer used to emulate the GX pipeline"); + CHECK(SUCCEEDED(hr), "shader constant buffer (size=%u)", cbsize); + if (FAILED(hr)) + return nullptr; + + D3DCommon::SetDebugObjectName(cbuf, "constant buffer"); return cbuf; } @@ -88,7 +92,8 @@ bool VertexManager::Initialize() { CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, nullptr, &m_buffers[i])), "Failed to create buffer."); - D3D::SetDebugObjectName(m_buffers[i], "Buffer of VertexManager"); + if (m_buffers[i]) + D3DCommon::SetDebugObjectName(m_buffers[i], "Buffer of VertexManager"); } m_vertex_constant_buffer = AllocateConstantBuffer(sizeof(VertexShaderConstants)); diff --git a/Source/Core/VideoBackends/D3D/VideoBackend.h b/Source/Core/VideoBackends/D3D/VideoBackend.h index e288dddb9a..0b4c61fc66 100644 --- a/Source/Core/VideoBackends/D3D/VideoBackend.h +++ b/Source/Core/VideoBackends/D3D/VideoBackend.h @@ -11,6 +11,7 @@ namespace DX11 { class VideoBackend : public VideoBackendBase { +public: bool Initialize(const WindowSystemInfo& wsi) override; void Shutdown() override; @@ -18,5 +19,8 @@ class VideoBackend : public VideoBackendBase std::string GetDisplayName() const override; void InitBackendInfo() override; + +private: + void FillBackendInfo(); }; } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/main.cpp b/Source/Core/VideoBackends/D3D/main.cpp index c9a5ab7091..a3c56dbc7e 100644 --- a/Source/Core/VideoBackends/D3D/main.cpp +++ b/Source/Core/VideoBackends/D3D/main.cpp @@ -14,8 +14,10 @@ #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/PerfQuery.h" #include "VideoBackends/D3D/Render.h" +#include "VideoBackends/D3D/SwapChain.h" #include "VideoBackends/D3D/VertexManager.h" #include "VideoBackends/D3D/VideoBackend.h" +#include "VideoBackends/D3DCommon/Common.h" #include "VideoCommon/FramebufferManager.h" #include "VideoCommon/ShaderCache.h" @@ -37,15 +39,15 @@ std::string VideoBackend::GetDisplayName() const void VideoBackend::InitBackendInfo() { - HRESULT hr = DX11::D3D::LoadDXGI(); - if (SUCCEEDED(hr)) - hr = DX11::D3D::LoadD3D(); - if (FAILED(hr)) - { - DX11::D3D::UnloadDXGI(); + if (!D3DCommon::LoadLibraries()) return; - } + FillBackendInfo(); + D3DCommon::UnloadLibraries(); +} + +void VideoBackend::FillBackendInfo() +{ g_Config.backend_info.api_type = APIType::D3D; g_Config.backend_info.MaxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; g_Config.backend_info.bUsesLowerLeftOrigin = false; @@ -73,82 +75,36 @@ void VideoBackend::InitBackendInfo() g_Config.backend_info.bSupportsBPTCTextures = false; g_Config.backend_info.bSupportsFramebufferFetch = false; g_Config.backend_info.bSupportsBackgroundCompiling = true; + g_Config.backend_info.bSupportsST3CTextures = true; + g_Config.backend_info.bSupportsBPTCTextures = true; + g_Config.backend_info.bSupportsEarlyZ = true; + g_Config.backend_info.bSupportsBBox = true; + g_Config.backend_info.bSupportsFragmentStoresAndAtomics = true; + g_Config.backend_info.bSupportsGSInstancing = true; + g_Config.backend_info.bSupportsSSAA = true; - IDXGIFactory2* factory; - IDXGIAdapter* ad; - hr = DX11::PCreateDXGIFactory(__uuidof(IDXGIFactory2), (void**)&factory); - if (FAILED(hr)) - PanicAlert("Failed to create IDXGIFactory object"); - - // adapters - g_Config.backend_info.Adapters.clear(); - g_Config.backend_info.AAModes.clear(); - while (factory->EnumAdapters((UINT)g_Config.backend_info.Adapters.size(), &ad) != - DXGI_ERROR_NOT_FOUND) - { - const size_t adapter_index = g_Config.backend_info.Adapters.size(); - - DXGI_ADAPTER_DESC desc; - ad->GetDesc(&desc); - - // TODO: These don't get updated on adapter change, yet - if (adapter_index == g_Config.iAdapter) - { - std::vector modes = DX11::D3D::EnumAAModes(ad); - // 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); - } - - D3D_FEATURE_LEVEL feature_level = D3D::GetFeatureLevel(ad); - bool shader_model_5_supported = feature_level >= D3D_FEATURE_LEVEL_11_0; - g_Config.backend_info.MaxTextureSize = D3D::GetMaxTextureSize(feature_level); - - // Requires the earlydepthstencil attribute (only available in shader model 5) - g_Config.backend_info.bSupportsEarlyZ = shader_model_5_supported; - - // Requires full UAV functionality (only available in shader model 5) - g_Config.backend_info.bSupportsBBox = - g_Config.backend_info.bSupportsFragmentStoresAndAtomics = shader_model_5_supported; - - // Requires the instance attribute (only available in shader model 5) - g_Config.backend_info.bSupportsGSInstancing = shader_model_5_supported; - - // Sample shading requires shader model 5 - g_Config.backend_info.bSupportsSSAA = shader_model_5_supported; - } - g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description)); - ad->Release(); - } - factory->Release(); - - DX11::D3D::UnloadDXGI(); - DX11::D3D::UnloadD3D(); + g_Config.backend_info.Adapters = D3DCommon::GetAdapterNames(); + g_Config.backend_info.AAModes = D3D::GetAAModes(g_Config.iAdapter); } bool VideoBackend::Initialize(const WindowSystemInfo& wsi) { + if (!D3D::Create(g_Config.iAdapter, g_Config.bEnableValidationLayer)) + return false; + + FillBackendInfo(); InitializeShared(); - if (FAILED(D3D::Create(reinterpret_cast(wsi.render_surface)))) + std::unique_ptr swap_chain; + if (wsi.render_surface && !(swap_chain = SwapChain::Create(wsi))) { - PanicAlert("Failed to create D3D device."); + PanicAlertT("Failed to create D3D swap chain"); + ShutdownShared(); + D3D::Destroy(); return false; } - int backbuffer_width = 1, backbuffer_height = 1; - if (D3D::swapchain) - { - DXGI_SWAP_CHAIN_DESC1 desc = {}; - D3D::swapchain->GetDesc1(&desc); - backbuffer_width = std::max(desc.Width, 1u); - backbuffer_height = std::max(desc.Height, 1u); - } - - // internal interfaces - g_renderer = - std::make_unique(backbuffer_width, backbuffer_height, wsi.render_surface_scale); + g_renderer = std::make_unique(std::move(swap_chain), wsi.render_surface_scale); g_vertex_manager = std::make_unique(); g_shader_cache = std::make_unique(); g_framebuffer_manager = std::make_unique(); @@ -158,6 +114,7 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi) !g_shader_cache->Initialize() || !g_framebuffer_manager->Initialize() || !g_texture_cache->Initialize()) { + Shutdown(); return false; } @@ -181,7 +138,6 @@ void VideoBackend::Shutdown() g_renderer.reset(); ShutdownShared(); - - D3D::Close(); + D3D::Destroy(); } } // namespace DX11