// Copyright 2016 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "VideoBackends/D3D12/VideoBackend.h" #include #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "Core/ConfigManager.h" #include "VideoBackends/D3D12/Common.h" #include "VideoBackends/D3D12/D3D12BoundingBox.h" #include "VideoBackends/D3D12/D3D12Gfx.h" #include "VideoBackends/D3D12/D3D12PerfQuery.h" #include "VideoBackends/D3D12/D3D12SwapChain.h" #include "VideoBackends/D3D12/D3D12VertexManager.h" #include "VideoBackends/D3D12/DX12Context.h" #ifdef ENABLE_VR #include "VideoBackends/D3D12/D3D12OpenXR.h" #endif #include "VideoCommon/FramebufferManager.h" #include "VideoCommon/ShaderCache.h" #include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" #ifdef ENABLE_VR #include "VideoCommon/VR/OpenXRManager.h" #endif namespace DX12 { std::string VideoBackend::GetConfigName() const { return CONFIG_NAME; } std::string VideoBackend::GetDisplayName() const { return "Direct3D 12"; } void VideoBackend::InitBackendInfo(const WindowSystemInfo& wsi) { if (!D3DCommon::LoadLibraries()) return; FillBackendInfo(); D3DCommon::UnloadLibraries(); } void VideoBackend::FillBackendInfo() { g_backend_info.api_type = APIType::D3D; g_backend_info.bUsesLowerLeftOrigin = false; g_backend_info.bSupportsExclusiveFullscreen = true; g_backend_info.bSupportsDualSourceBlend = true; g_backend_info.bSupportsPrimitiveRestart = true; g_backend_info.bSupportsGeometryShaders = true; g_backend_info.bSupports3DVision = false; g_backend_info.bSupportsEarlyZ = true; g_backend_info.bSupportsBindingLayout = false; g_backend_info.bSupportsBBox = true; g_backend_info.bSupportsGSInstancing = true; g_backend_info.bSupportsPaletteConversion = true; g_backend_info.bSupportsPostProcessing = true; g_backend_info.bSupportsClipControl = true; g_backend_info.bSupportsSSAA = true; g_backend_info.bSupportsFragmentStoresAndAtomics = true; g_backend_info.bSupportsDepthClamp = true; g_backend_info.bSupportsReversedDepthRange = false; g_backend_info.bSupportsComputeShaders = true; g_backend_info.bSupportsLogicOp = true; g_backend_info.bSupportsMultithreading = false; g_backend_info.bSupportsGPUTextureDecoding = true; g_backend_info.bSupportsST3CTextures = false; g_backend_info.bSupportsCopyToVram = true; g_backend_info.bSupportsBitfield = false; g_backend_info.bSupportsDynamicSamplerIndexing = false; g_backend_info.bSupportsBPTCTextures = false; g_backend_info.bSupportsFramebufferFetch = false; g_backend_info.bSupportsBackgroundCompiling = true; g_backend_info.bSupportsLargePoints = false; g_backend_info.bSupportsDepthReadback = true; g_backend_info.bSupportsPartialDepthCopies = false; g_backend_info.Adapters = D3DCommon::GetAdapterNames(); g_backend_info.AAModes = DXContext::GetAAModes(g_Config.iAdapter); g_backend_info.bSupportsShaderBinaries = true; g_backend_info.bSupportsPipelineCacheData = true; g_backend_info.bSupportsCoarseDerivatives = true; g_backend_info.bSupportsTextureQueryLevels = true; g_backend_info.bSupportsLodBiasInSampler = true; g_backend_info.bSupportsSettingObjectNames = true; g_backend_info.bSupportsPartialMultisampleResolve = true; g_backend_info.bSupportsDynamicVertexLoader = true; g_backend_info.bSupportsVSLinePointExpand = true; g_backend_info.bSupportsHDROutput = true; // We can only check texture support once we have a device. if (g_dx_context) { g_backend_info.bSupportsST3CTextures = g_dx_context->SupportsTextureFormat(DXGI_FORMAT_BC1_UNORM) && g_dx_context->SupportsTextureFormat(DXGI_FORMAT_BC2_UNORM) && g_dx_context->SupportsTextureFormat(DXGI_FORMAT_BC3_UNORM); g_backend_info.bSupportsBPTCTextures = g_dx_context->SupportsTextureFormat(DXGI_FORMAT_BC7_UNORM); } } bool VideoBackend::Initialize(const WindowSystemInfo& wsi) { if (!DXContext::Create(g_Config.iAdapter, g_Config.bEnableValidationLayer)) { PanicAlertFmtT("Failed to create D3D12 context"); return false; } FillBackendInfo(); UpdateActiveConfig(); if (!g_dx_context->CreateGlobalResources()) { PanicAlertFmtT("Failed to create D3D12 global resources"); DXContext::Destroy(); ShutdownShared(); return false; } #ifdef ENABLE_VR INFO_LOG_FMT(VIDEO, "VR: stereo_mode={} (session_active={}, flat={})", static_cast(g_ActiveConfig.stereo_mode), g_ActiveConfig.VRSessionActive() ? "YES" : "NO", g_ActiveConfig.vr_flat_screen ? "YES" : "NO"); if (g_ActiveConfig.VRSessionActive()) { auto openxr = std::make_unique(); if (!openxr->Initialize()) { WARN_LOG_FMT(VIDEO, "OpenXR initialization failed; continuing without VR."); } else { DX12::g_openxr_d3d12 = std::move(openxr); } } #endif std::unique_ptr swap_chain; if (wsi.render_surface && !(swap_chain = SwapChain::Create(wsi))) { PanicAlertFmtT("Failed to create D3D swap chain"); #ifdef ENABLE_VR DX12::g_openxr_d3d12.reset(); VR::g_openxr.reset(); #endif DXContext::Destroy(); ShutdownShared(); return false; } // Create main wrapper instances. auto gfx = std::make_unique(std::move(swap_chain), wsi.render_surface_scale); auto vertex_manager = std::make_unique(); auto perf_query = std::make_unique(); auto bounding_box = std::make_unique(); return InitializeShared(std::move(gfx), std::move(vertex_manager), std::move(perf_query), std::move(bounding_box)); } void VideoBackend::Shutdown() { // Keep the debug runtime happy... if (g_gfx) Gfx::GetInstance()->ExecuteCommandList(true); #ifdef ENABLE_VR // Shut down VR before the D3D12 context is destroyed. // g_openxr_d3d12 first (releases the DXTexture/DXFramebuffer wrappers and waits for the // GPU so the deferred references on the runtime-owned textures are dropped), then // g_openxr (calls xrDestroySession/Instance — releases the runtime's D3D12 refs). DX12::g_openxr_d3d12.reset(); VR::g_openxr.reset(); #endif ShutdownShared(); DXContext::Destroy(); } } // namespace DX12