D3D11/D3D12: backend info from the frontend's device only

The frontend picks the adapter and hands over its device, so the core no
longer loads dxgi.dll, creates DXGI factories, enumerates adapters or
creates throwaway D3D11/D3D12 devices to query AA modes and logic op
support at load. Until the device arrives the AA modes are the counts
every device has; the context reset fills them in from the real device
(D3D12 now too) and re-validates the MSAA setting against them.
This commit is contained in:
LibretroAdmin authored and libretroadmin committed 2026-11-07 15:18:33 +01:00
1 parent 73c3c0baee
commit 0bd8e77a4d
11 files changed
+39 -312

No files matched your search

+4 -33
View File
@@ -11,7 +11,6 @@
#include <vector>
#ifdef _WIN32
#include "Common/DynamicLibrary.h"
#include "VideoBackends/D3D/VideoBackend.h"
#include "VideoBackends/D3D/D3DGfx.h"
#include "VideoBackends/D3D/D3DVertexManager.h"
@@ -85,8 +84,6 @@ static unsigned s_gpu_fields;
static unsigned s_gpu_fields_seen;
#ifdef _WIN32
static Common::DynamicLibrary d3d11_library;
static Common::DynamicLibrary d3d12_library;
/* Direct3D 11 version 2: the interface, and the levels of its context
* lock this thread holds */
static retro_hw_render_interface_d3d11* s_d3d11_v2;
@@ -372,19 +369,6 @@ static void ContextResetD3D11(retro_hw_render_interface_d3d11* d3d, const Window
DX11::D3D::context = d3d->context;
DX11::D3D::feature_level = d3d->featureLevel;
if (!d3d11_library.IsOpen() && !d3d11_library.Open("d3d11.dll"))
{
d3d11_library.Close();
ERROR_LOG_FMT(VIDEO, "Failed to load D3D11 Libraries");
return;
}
if (!D3DCommon::LoadLibraries())
{
ERROR_LOG_FMT(VIDEO, "Failed to load the dxgi library");
return;
}
if (FAILED(DX11::D3D::device.As(&DX11::D3D::device1)))
{
WARN_LOG_FMT(VIDEO, "Missing Direct3D 11.1 support. Logical operations will not be supported.");
@@ -402,6 +386,7 @@ static void ContextResetD3D11(retro_hw_render_interface_d3d11* d3d, const Window
}
d3d11->FillD3DBackendInfo();
g_Config.VerifyValidity();
UpdateActiveConfig();
std::unique_ptr<DX11Output> output = std::make_unique<DX11Output>(
@@ -500,19 +485,6 @@ void ContextReset(void)
return;
}
if (!d3d12_library.IsOpen() && !d3d12_library.Open("d3d12.dll"))
{
d3d12_library.Close();
ERROR_LOG_FMT(VIDEO, "Failed to load D3D12 Libraries");
return;
}
if (!D3DCommon::LoadLibraries())
{
ERROR_LOG_FMT(VIDEO, "Failed to load the dxgi library");
return;
}
// Create D3D12 context with RetroArch's device and queue
ID3D12Device* ra_device = static_cast<ID3D12Device*>(d3d12->device);
ID3D12CommandQueue* ra_queue = static_cast<ID3D12CommandQueue*>(d3d12->queue);
@@ -523,6 +495,9 @@ void ContextReset(void)
return;
}
static_cast<DX12::VideoBackend*>(g_video_backend)->FillD3D12BackendInfo();
g_Config.VerifyValidity();
Microsoft::WRL::ComPtr<ID3D12Device1> device1;
if (FAILED(DX12::g_dx_context->GetDevice()->QueryInterface(IID_PPV_ARGS(&device1))))
{
@@ -674,8 +649,6 @@ void ContextDestroy(void)
case RETRO_HW_CONTEXT_D3D12:
#ifdef _WIN32
DX12::DXContext::Destroy();
D3DCommon::UnloadLibraries();
d3d12_library.Close();
#endif
break;
case RETRO_HW_CONTEXT_D3D11:
@@ -693,8 +666,6 @@ void ContextDestroy(void)
DX11::D3D::device1 = nullptr;
DX11::D3D::context = nullptr;
DX11::D3D::stateman.reset();
D3DCommon::UnloadLibraries();
d3d11_library.Close();
#endif
break;
case RETRO_HW_CONTEXT_VULKAN:
+7 -79
View File
@@ -7,7 +7,6 @@
#include <array>
#include "Common/CommonTypes.h"
#include "Common/DynamicLibrary.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Core/Config/GraphicsSettings.h"
@@ -20,21 +19,13 @@
namespace DX11
{
static Common::DynamicLibrary s_d3d11_library;
namespace D3D
{
ComPtr<IDXGIFactory> dxgi_factory;
ComPtr<ID3D11Device> device;
ComPtr<ID3D11Device1> device1;
ComPtr<ID3D11DeviceContext> context;
D3D_FEATURE_LEVEL feature_level;
constexpr std::array<D3D_FEATURE_LEVEL, 3> s_supported_feature_levels{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
void Destroy()
{
stateman.reset();
@@ -54,44 +45,13 @@ void Destroy()
else
NOTICE_LOG_FMT(VIDEO, "Successfully released all device references!");
dxgi_factory.Reset();
D3DCommon::UnloadLibraries();
s_d3d11_library.Close();
}
std::vector<u32> GetAAModes(u32 adapter_index)
std::vector<u32> GetAAModes()
{
// Use temporary device if we don't have one already.
Common::DynamicLibrary temp_lib;
ComPtr<ID3D11Device> temp_device = device;
D3D_FEATURE_LEVEL temp_feature_level = feature_level;
if (!temp_device)
{
ComPtr<IDXGIFactory> temp_dxgi_factory = D3DCommon::CreateDXGIFactory(false);
if (!temp_dxgi_factory)
return {};
ComPtr<IDXGIAdapter> adapter;
temp_dxgi_factory->EnumAdapters(adapter_index, &adapter);
PFN_D3D11_CREATE_DEVICE d3d11_create_device;
if (!temp_lib.Open("d3d11.dll") ||
!temp_lib.GetSymbol("D3D11CreateDevice", &d3d11_create_device))
{
return {};
}
HRESULT hr = d3d11_create_device(adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0,
s_supported_feature_levels.data(),
static_cast<UINT>(s_supported_feature_levels.size()),
D3D11_SDK_VERSION, &temp_device, &temp_feature_level, nullptr);
if (FAILED(hr))
return {};
}
// 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_feature_level == D3D_FEATURE_LEVEL_10_0)
if (feature_level == D3D_FEATURE_LEVEL_10_0)
return {};
const DXGI_FORMAT target_format =
@@ -101,7 +61,7 @@ std::vector<u32> GetAAModes(u32 adapter_index)
{
UINT quality_levels = 0;
if (SUCCEEDED(
temp_device->CheckMultisampleQualityLevels(target_format, samples, &quality_levels)) &&
device->CheckMultisampleQualityLevels(target_format, samples, &quality_levels)) &&
quality_levels > 0)
{
aa_modes.push_back(samples);
@@ -120,46 +80,14 @@ bool SupportsTextureFormat(DXGI_FORMAT format)
return (support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0;
}
bool SupportsLogicOp(u32 adapter_index)
bool SupportsLogicOp()
{
// Use temporary device if we don't have one already.
Common::DynamicLibrary temp_lib;
ComPtr<ID3D11Device1> temp_device1 = device1;
if (!device)
{
ComPtr<ID3D11Device> temp_device;
ComPtr<IDXGIFactory> temp_dxgi_factory = D3DCommon::CreateDXGIFactory(false);
if (!temp_dxgi_factory)
return false;
ComPtr<IDXGIAdapter> adapter;
temp_dxgi_factory->EnumAdapters(adapter_index, &adapter);
PFN_D3D11_CREATE_DEVICE d3d11_create_device;
if (!temp_lib.Open("d3d11.dll") ||
!temp_lib.GetSymbol("D3D11CreateDevice", &d3d11_create_device))
{
return false;
}
HRESULT hr = d3d11_create_device(adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0,
s_supported_feature_levels.data(),
static_cast<UINT>(s_supported_feature_levels.size()),
D3D11_SDK_VERSION, &temp_device, nullptr, nullptr);
if (FAILED(hr))
return false;
if (FAILED(temp_device.As(&temp_device1)))
return false;
}
if (!temp_device1)
if (!device1)
return false;
D3D11_FEATURE_DATA_D3D11_OPTIONS options{};
if (FAILED(temp_device1->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options,
sizeof(options))))
if (FAILED(device1->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options,
sizeof(options))))
{
return false;
}
+4 -5
View File
@@ -18,7 +18,6 @@ using Microsoft::WRL::ComPtr;
namespace D3D
{
extern ComPtr<IDXGIFactory> dxgi_factory;
extern ComPtr<ID3D11Device> device;
extern ComPtr<ID3D11Device1> device1;
extern ComPtr<ID3D11DeviceContext> context;
@@ -26,14 +25,14 @@ extern D3D_FEATURE_LEVEL feature_level;
void Destroy();
// Returns a list of supported AA modes for the current device.
std::vector<u32> GetAAModes(u32 adapter_index);
// The AA modes the frontend's device supports.
std::vector<u32> GetAAModes();
// Checks for support of the given texture format.
bool SupportsTextureFormat(DXGI_FORMAT format);
// Checks for logic op support.
bool SupportsLogicOp(u32 adapter_index);
// Logic op support on the frontend's device.
bool SupportsLogicOp();
} // namespace D3D
+8 -34
View File
@@ -37,39 +37,9 @@ std::string VideoBackend::GetDisplayName() const
return _trans("Direct3D 11");
}
std::optional<std::string> VideoBackend::GetWarningMessage() const
{
std::optional<std::string> result;
// If relevant, show a warning about partial DX11.1 support
// This is being called BEFORE FillBackendInfo is called for this backend,
// so query for logic op support manually
bool supportsLogicOp = false;
if (D3DCommon::LoadLibraries())
{
supportsLogicOp = D3D::SupportsLogicOp(g_Config.iAdapter);
D3DCommon::UnloadLibraries();
}
if (!supportsLogicOp)
{
result = _trans("The Direct3D 11 renderer requires support for features not supported by your "
"system configuration. You may still use this backend, but you will encounter "
"graphical artifacts in certain games.\n"
"\n"
"Do you really want to switch to Direct3D 11? If unsure, select 'No'.");
}
return result;
}
void VideoBackend::InitBackendInfo(const WindowSystemInfo& wsi)
{
if (!D3DCommon::LoadLibraries())
return;
FillBackendInfo();
D3DCommon::UnloadLibraries();
}
void VideoBackend::FillBackendInfo()
@@ -109,15 +79,19 @@ void VideoBackend::FillBackendInfo()
g_backend_info.bSupportsCoarseDerivatives = true;
g_backend_info.bSupportsTextureQueryLevels = true;
g_backend_info.bSupportsLodBiasInSampler = true;
g_backend_info.bSupportsLogicOp =
!Common::is_uwp() && D3D::SupportsLogicOp(g_Config.iAdapter);
g_backend_info.bSupportsLogicOp = !Common::is_uwp() && D3D::device1 && D3D::SupportsLogicOp();
g_backend_info.bSupportsSettingObjectNames = true;
g_backend_info.bSupportsPartialMultisampleResolve = true;
g_backend_info.bSupportsDynamicVertexLoader = false;
g_backend_info.bSupportsHDROutput = true;
g_backend_info.Adapters = D3DCommon::GetAdapterNames();
g_backend_info.AAModes = D3D::GetAAModes(g_Config.iAdapter);
// The frontend picks the adapter and hands over its device: until then,
// the counts every D3D11 device has, narrowed to the device's own after.
g_backend_info.Adapters.clear();
if (D3D::device)
g_backend_info.AAModes = D3D::GetAAModes();
else
g_backend_info.AAModes = {1, 2, 4, 8};
// Override optional features if we are actually booting.
if (D3D::device)
@@ -16,7 +16,6 @@ public:
std::string GetConfigName() const override;
std::string GetDisplayName() const override;
std::optional<std::string> GetWarningMessage() const override;
void InitBackendInfo(const WindowSystemInfo& wsi) override;
@@ -35,35 +35,9 @@ DXContext::~DXContext()
CloseHandle(m_fence_event);
}
std::vector<u32> DXContext::GetAAModes(u32 adapter_index)
std::vector<u32> DXContext::GetAAModes()
{
// Use a temporary device if we aren't booting.
Common::DynamicLibrary temp_lib;
ComPtr<ID3D12Device> temp_device = g_dx_context ? g_dx_context->m_device : nullptr;
if (!temp_device)
{
ComPtr<IDXGIFactory> temp_dxgi_factory = D3DCommon::CreateDXGIFactory(false);
if (!temp_dxgi_factory)
return {};
ComPtr<IDXGIAdapter> adapter;
HRESULT hr = temp_dxgi_factory->EnumAdapters(adapter_index, &adapter);
if (!SUCCEEDED(hr))
return {};
PFN_D3D12_CREATE_DEVICE d3d12_create_device;
if (!temp_lib.Open("d3d12.dll") ||
!temp_lib.GetSymbol("D3D12CreateDevice", &d3d12_create_device))
{
return {};
}
hr = d3d12_create_device(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&temp_device));
if (!SUCCEEDED(hr))
return {};
}
ID3D12Device* const device = m_device.Get();
const DXGI_FORMAT target_format =
D3DCommon::GetDXGIFormatForAbstractFormat(FramebufferManager::GetEFBColorFormat(), false);
std::vector<u32> aa_modes;
@@ -73,9 +47,8 @@ std::vector<u32> DXContext::GetAAModes(u32 adapter_index)
multisample_quality_levels.Format = target_format;
multisample_quality_levels.SampleCount = samples;
temp_device->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));
if (multisample_quality_levels.NumQualityLevels > 0)
aa_modes.push_back(samples);
@@ -110,7 +83,6 @@ void DXContext::Destroy()
s_d3d12_serialize_root_signature = nullptr;
s_d3d12_library.Close();
D3DCommon::UnloadLibraries();
}
bool DXContext::CreateFence()
@@ -495,12 +467,6 @@ bool DXContext::CreateWithExternalDevice(ID3D12Device* device, ID3D12CommandQueu
return false;
}
if (!D3DCommon::LoadLibraries())
{
s_d3d12_library.Close();
return false;
}
g_dx_context.reset(new DXContext());
device->AddRef();
@@ -509,14 +475,6 @@ bool DXContext::CreateWithExternalDevice(ID3D12Device* device, ID3D12CommandQueu
queue->AddRef();
g_dx_context->m_command_queue.Attach(queue);
g_dx_context->m_dxgi_factory = D3DCommon::CreateDXGIFactory(false);
if (!g_dx_context->m_dxgi_factory)
{
ERROR_LOG_FMT(VIDEO, "Failed to create DXGI factory");
Destroy();
return false;
}
if (!g_dx_context->CreateFence())
{
ERROR_LOG_FMT(VIDEO, "Failed to create fence");
@@ -51,12 +51,12 @@ public:
~DXContext();
// Returns a list of AA modes.
static std::vector<u32> GetAAModes(u32 adapter_index);
// The AA modes the frontend's device supports.
std::vector<u32> GetAAModes();
// Destroys active context.
static void Destroy();
IDXGIFactory* GetDXGIFactory() const { return m_dxgi_factory.Get(); }
ID3D12Device* GetDevice() const { return m_device.Get(); }
ID3D12CommandQueue* GetCommandQueue() const { return m_command_queue.Get(); }
@@ -172,7 +172,6 @@ private:
void MoveToNextCommandList();
void DestroyPendingResources(CommandListResources& cmdlist);
ComPtr<IDXGIFactory> m_dxgi_factory;
ComPtr<ID3D12Device> m_device;
ComPtr<ID3D12CommandQueue> m_command_queue;
@@ -37,11 +37,7 @@ std::string VideoBackend::GetDisplayName() const
void VideoBackend::InitBackendInfo(const WindowSystemInfo& wsi)
{
if (!D3DCommon::LoadLibraries())
return;
FillBackendInfo();
D3DCommon::UnloadLibraries();
}
void VideoBackend::FillBackendInfo()
@@ -77,8 +73,13 @@ void VideoBackend::FillBackendInfo()
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);
// The frontend picks the adapter and hands over its device: until then,
// the counts every D3D12 device has, narrowed to the device's own after.
g_backend_info.Adapters.clear();
if (g_dx_context)
g_backend_info.AAModes = g_dx_context->GetAAModes();
else
g_backend_info.AAModes = {1, 2, 4, 8};
g_backend_info.bSupportsShaderBinaries = true;
g_backend_info.bSupportsPipelineCacheData = true;
g_backend_info.bSupportsCoarseDerivatives = true;
@@ -21,6 +21,9 @@ public:
static constexpr const char* CONFIG_NAME = "D3D12";
// Again, from the frontend's device once the context has it.
void FillD3D12BackendInfo() { FillBackendInfo(); }
private:
void FillBackendInfo();
};
@@ -9,8 +9,6 @@
#include <wrl/client.h>
#include "Common/Assert.h"
#include "Common/DynamicLibrary.h"
#include "Common/HRWrap.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.h"
@@ -19,97 +17,6 @@
namespace D3DCommon
{
static Common::DynamicLibrary s_dxgi_library;
static bool s_libraries_loaded = false;
static HRESULT (*create_dxgi_factory)(REFIID riid, _COM_Outptr_ void** ppFactory);
static HRESULT (*create_dxgi_factory2)(UINT Flags, REFIID riid, void** ppFactory);
bool LoadLibraries()
{
if (s_libraries_loaded)
return true;
if (!s_dxgi_library.Open("dxgi.dll"))
{
PanicAlertFmtT("Failed to load dxgi.dll");
return false;
}
// Required symbols.
if (!s_dxgi_library.GetSymbol("CreateDXGIFactory", &create_dxgi_factory))
{
PanicAlertFmtT("Failed to find one or more D3D symbols");
s_dxgi_library.Close();
return false;
}
// Optional symbols.
s_dxgi_library.GetSymbol("CreateDXGIFactory2", &create_dxgi_factory2);
s_libraries_loaded = true;
return true;
}
void UnloadLibraries()
{
create_dxgi_factory = nullptr;
create_dxgi_factory2 = nullptr;
s_dxgi_library.Close();
s_libraries_loaded = false;
}
Microsoft::WRL::ComPtr<IDXGIFactory> CreateDXGIFactory(bool debug_device)
{
Microsoft::WRL::ComPtr<IDXGIFactory> factory;
// Use Win8.1 version if available.
if (create_dxgi_factory2 &&
SUCCEEDED(create_dxgi_factory2(debug_device ? DXGI_CREATE_FACTORY_DEBUG : 0,
IID_PPV_ARGS(&factory))))
{
return factory;
}
// Fallback to original version, without debug support.
HRESULT hr = create_dxgi_factory(IID_PPV_ARGS(&factory));
if (FAILED(hr))
{
PanicAlertFmt("CreateDXGIFactory() failed: {}", Common::HRWrap(hr));
return nullptr;
}
return factory;
}
std::vector<std::string> GetAdapterNames()
{
Microsoft::WRL::ComPtr<IDXGIFactory> factory;
HRESULT hr = E_FAIL;
if (create_dxgi_factory2)
hr = create_dxgi_factory2(0, IID_PPV_ARGS(&factory));
else if (create_dxgi_factory)
hr = create_dxgi_factory(IID_PPV_ARGS(&factory));
if (FAILED(hr))
return {};
std::vector<std::string> adapters;
Microsoft::WRL::ComPtr<IDXGIAdapter> adapter;
while (factory->EnumAdapters(static_cast<UINT>(adapters.size()), &adapter) !=
DXGI_ERROR_NOT_FOUND)
{
std::string name;
DXGI_ADAPTER_DESC desc;
if (SUCCEEDED(adapter->GetDesc(&desc)))
name = WStringToUTF8(desc.Description);
adapters.push_back(std::move(name));
}
return adapters;
}
DXGI_FORMAT GetDXGIFormatForAbstractFormat(AbstractTextureFormat format, bool typeless)
{
switch (format)
@@ -11,22 +11,10 @@
#include "Common/CommonTypes.h"
struct IDXGIFactory;
enum class AbstractTextureFormat : u32;
namespace D3DCommon
{
// Loading dxgi.dll
bool LoadLibraries();
void UnloadLibraries();
// Returns a list of D3D device names.
std::vector<std::string> GetAdapterNames();
// Helper function which creates a DXGI factory.
Microsoft::WRL::ComPtr<IDXGIFactory> CreateDXGIFactory(bool debug_device);
// Helpers for texture format conversion.
DXGI_FORMAT GetDXGIFormatForAbstractFormat(AbstractTextureFormat format, bool typeless);
DXGI_FORMAT GetSRVFormatForAbstractFormat(AbstractTextureFormat format);