GS: Unify D3D device creation paths

Also makes Vulkan the device for Intel Arc GPUs.
This commit is contained in:
Stenzek 2023-04-01 15:47:02 +10:00 committed by refractionpcsx2
parent 8989b69ce8
commit fcbc027abc
11 changed files with 408 additions and 539 deletions

View File

@ -125,7 +125,7 @@ bool Context::SupportsTextureFormat(DXGI_FORMAT format)
(support.Support1 & required) == required; (support.Support1 & required) == required;
} }
bool Context::Create(IDXGIFactory* dxgi_factory, u32 adapter_index, bool enable_debug_layer) bool Context::Create(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer)
{ {
pxAssertRel(!g_d3d12_context, "No context exists"); pxAssertRel(!g_d3d12_context, "No context exists");
@ -133,7 +133,7 @@ bool Context::Create(IDXGIFactory* dxgi_factory, u32 adapter_index, bool enable_
return false; return false;
g_d3d12_context.reset(new Context()); g_d3d12_context.reset(new Context());
if (!g_d3d12_context->CreateDevice(dxgi_factory, adapter_index, enable_debug_layer) || if (!g_d3d12_context->CreateDevice(dxgi_factory, adapter, enable_debug_layer) ||
!g_d3d12_context->CreateCommandQueue() || !g_d3d12_context->CreateAllocator() || !g_d3d12_context->CreateCommandQueue() || !g_d3d12_context->CreateAllocator() ||
!g_d3d12_context->CreateFence() || !g_d3d12_context->CreateDescriptorHeaps() || !g_d3d12_context->CreateFence() || !g_d3d12_context->CreateDescriptorHeaps() ||
!g_d3d12_context->CreateCommandLists() || !g_d3d12_context->CreateTimestampQuery() || !g_d3d12_context->CreateCommandLists() || !g_d3d12_context->CreateTimestampQuery() ||
@ -166,31 +166,9 @@ u32 Context::GetAdapterVendorID() const
return desc.VendorId; return desc.VendorId;
} }
bool Context::CreateDevice(IDXGIFactory* dxgi_factory, u32 adapter_index, bool enable_debug_layer) bool Context::CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer)
{ {
ComPtr<IDXGIAdapter> adapter; HRESULT hr;
HRESULT hr = dxgi_factory->EnumAdapters(adapter_index, &adapter);
if (FAILED(hr))
{
Console.Error("Adapter %u not found, using default", adapter_index);
adapter = nullptr;
}
else
{
DXGI_ADAPTER_DESC adapter_desc;
if (SUCCEEDED(adapter->GetDesc(&adapter_desc)))
{
char adapter_name_buffer[128];
const int name_length = WideCharToMultiByte(CP_UTF8, 0, adapter_desc.Description,
static_cast<int>(std::wcslen(adapter_desc.Description)),
adapter_name_buffer, std::size(adapter_name_buffer), 0, nullptr);
if (name_length >= 0)
{
adapter_name_buffer[name_length] = 0;
Console.WriteLn("D3D Adapter: %s", adapter_name_buffer);
}
}
}
// Enabling the debug layer will fail if the Graphics Tools feature is not installed. // Enabling the debug layer will fail if the Graphics Tools feature is not installed.
if (enable_debug_layer) if (enable_debug_layer)
@ -208,18 +186,14 @@ bool Context::CreateDevice(IDXGIFactory* dxgi_factory, u32 adapter_index, bool e
} }
// Create the actual device. // Create the actual device.
hr = s_d3d12_create_device(adapter.get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device)); hr = s_d3d12_create_device(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
if (FAILED(hr)) if (FAILED(hr))
return false; return false;
// get adapter // get adapter
ComPtr<IDXGIFactory4> dxgi_factory4; const LUID luid(m_device->GetAdapterLuid());
if (SUCCEEDED(dxgi_factory->QueryInterface<IDXGIFactory4>(dxgi_factory4.put()))) if (FAILED(dxgi_factory->EnumAdapterByLuid(luid, IID_PPV_ARGS(m_adapter.put()))))
{ Console.Error("Failed to get lookup adapter by device LUID");
const LUID luid(m_device->GetAdapterLuid());
if (FAILED(dxgi_factory4->EnumAdapterByLuid(luid, IID_PPV_ARGS(m_adapter.put()))))
Console.Error("Failed to get lookup adapter by device LUID");
}
if (enable_debug_layer) if (enable_debug_layer)
{ {

View File

@ -22,6 +22,7 @@
#include <array> #include <array>
#include <d3d12.h> #include <d3d12.h>
#include <dxgi1_5.h>
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <wil/com.h> #include <wil/com.h>
@ -60,7 +61,7 @@ namespace D3D12
~Context(); ~Context();
/// Creates new device and context. /// Creates new device and context.
static bool Create(IDXGIFactory* dxgi_factory, u32 adapter_index, bool enable_debug_layer); static bool Create(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer);
/// Destroys active context. /// Destroys active context.
static void Destroy(); static void Destroy();
@ -167,7 +168,7 @@ namespace D3D12
Context(); Context();
bool CreateDevice(IDXGIFactory* dxgi_factory, u32 adapter_index, bool enable_debug_layer); bool CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer);
bool CreateCommandQueue(); bool CreateCommandQueue();
bool CreateAllocator(); bool CreateAllocator();
bool CreateFence(); bool CreateFence();

View File

@ -36,8 +36,8 @@
class D3D11HostDisplayTexture : public HostDisplayTexture class D3D11HostDisplayTexture : public HostDisplayTexture
{ {
public: public:
D3D11HostDisplayTexture(wil::com_ptr_nothrow<ID3D11Texture2D> texture, D3D11HostDisplayTexture(wil::com_ptr_nothrow<ID3D11Texture2D> texture, wil::com_ptr_nothrow<ID3D11ShaderResourceView> srv, u32 width,
wil::com_ptr_nothrow<ID3D11ShaderResourceView> srv, u32 width, u32 height, bool dynamic) u32 height, bool dynamic)
: m_texture(std::move(texture)) : m_texture(std::move(texture))
, m_srv(std::move(srv)) , m_srv(std::move(srv))
, m_width(width) , m_width(width)
@ -103,19 +103,18 @@ bool D3D11HostDisplay::HasSurface() const
return static_cast<bool>(m_swap_chain); return static_cast<bool>(m_swap_chain);
} }
std::unique_ptr<HostDisplayTexture> D3D11HostDisplay::CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic /* = false */) std::unique_ptr<HostDisplayTexture> D3D11HostDisplay::CreateTexture(
u32 width, u32 height, const void* data, u32 data_stride, bool dynamic /* = false */)
{ {
const CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, width, height, 1u, 1u, const CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, width, height, 1u, 1u, D3D11_BIND_SHADER_RESOURCE,
D3D11_BIND_SHADER_RESOURCE, dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT, dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT, dynamic ? D3D11_CPU_ACCESS_WRITE : 0, 1, 0, 0);
dynamic ? D3D11_CPU_ACCESS_WRITE : 0, 1, 0, 0);
const D3D11_SUBRESOURCE_DATA srd{data, data_stride, data_stride * height}; const D3D11_SUBRESOURCE_DATA srd{data, data_stride, data_stride * height};
ComPtr<ID3D11Texture2D> texture; ComPtr<ID3D11Texture2D> texture;
HRESULT hr = m_device->CreateTexture2D(&desc, data ? &srd : nullptr, texture.addressof()); HRESULT hr = m_device->CreateTexture2D(&desc, data ? &srd : nullptr, texture.addressof());
if (FAILED(hr)) if (FAILED(hr))
return {}; return {};
const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(D3D11_SRV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 1, 0, const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(D3D11_SRV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 1, 0, 1);
1);
ComPtr<ID3D11ShaderResourceView> srv; ComPtr<ID3D11ShaderResourceView> srv;
hr = m_device->CreateShaderResourceView(texture.get(), &srv_desc, srv.addressof()); hr = m_device->CreateShaderResourceView(texture.get(), &srv_desc, srv.addressof());
if (FAILED(hr)) if (FAILED(hr))
@ -124,14 +123,15 @@ std::unique_ptr<HostDisplayTexture> D3D11HostDisplay::CreateTexture(u32 width, u
return std::make_unique<D3D11HostDisplayTexture>(std::move(texture), std::move(srv), width, height, dynamic); return std::make_unique<D3D11HostDisplayTexture>(std::move(texture), std::move(srv), width, height, dynamic);
} }
void D3D11HostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data, u32 texture_data_stride) void D3D11HostDisplay::UpdateTexture(
HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data, u32 texture_data_stride)
{ {
D3D11HostDisplayTexture* d3d11_texture = static_cast<D3D11HostDisplayTexture*>(texture); D3D11HostDisplayTexture* d3d11_texture = static_cast<D3D11HostDisplayTexture*>(texture);
if (!d3d11_texture->IsDynamic()) if (!d3d11_texture->IsDynamic())
{ {
const CD3D11_BOX dst_box(x, y, 0, x + width, y + height, 1); const CD3D11_BOX dst_box(x, y, 0, x + width, y + height, 1);
m_context->UpdateSubresource(d3d11_texture->GetD3DTexture(), 0, &dst_box, texture_data, texture_data_stride, m_context->UpdateSubresource(
texture_data_stride * height); d3d11_texture->GetD3DTexture(), 0, &dst_box, texture_data, texture_data_stride, texture_data_stride * height);
} }
else else
{ {
@ -167,10 +167,9 @@ bool D3D11HostDisplay::GetHostRefreshRate(float* refresh_rate)
if (SUCCEEDED(m_swap_chain->GetDesc(&desc)) && desc.BufferDesc.RefreshRate.Numerator > 0 && if (SUCCEEDED(m_swap_chain->GetDesc(&desc)) && desc.BufferDesc.RefreshRate.Numerator > 0 &&
desc.BufferDesc.RefreshRate.Denominator > 0) desc.BufferDesc.RefreshRate.Denominator > 0)
{ {
DevCon.WriteLn("using fs rr: %u %u", desc.BufferDesc.RefreshRate.Numerator, DevCon.WriteLn("using fs rr: %u %u", desc.BufferDesc.RefreshRate.Numerator, desc.BufferDesc.RefreshRate.Denominator);
desc.BufferDesc.RefreshRate.Denominator); *refresh_rate =
*refresh_rate = static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) / static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) / static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
return true; return true;
} }
} }
@ -189,52 +188,21 @@ bool D3D11HostDisplay::CreateDevice(const WindowInfo& wi, VsyncMode vsync)
if (EmuConfig.GS.UseDebugDevice) if (EmuConfig.GS.UseDebugDevice)
create_flags |= D3D11_CREATE_DEVICE_DEBUG; create_flags |= D3D11_CREATE_DEVICE_DEBUG;
ComPtr<IDXGIFactory> temp_dxgi_factory; m_dxgi_factory = D3D::CreateFactory(EmuConfig.GS.UseDebugDevice);
HRESULT hr = CreateDXGIFactory(IID_PPV_ARGS(temp_dxgi_factory.put())); if (!m_dxgi_factory)
if (FAILED(hr))
{
Console.Error("Failed to create DXGI factory: 0x%08X", hr);
return false; return false;
}
u32 adapter_index; ComPtr<IDXGIAdapter1> dxgi_adapter = D3D::GetAdapterByName(m_dxgi_factory.get(), EmuConfig.GS.Adapter);
if (!EmuConfig.GS.Adapter.empty())
{
AdapterAndModeList adapter_info(GetAdapterAndModeList(temp_dxgi_factory.get()));
for (adapter_index = 0; adapter_index < static_cast<u32>(adapter_info.adapter_names.size()); adapter_index++)
{
if (EmuConfig.GS.Adapter == adapter_info.adapter_names[adapter_index])
break;
}
if (adapter_index == static_cast<u32>(adapter_info.adapter_names.size()))
{
Console.Warning("Could not find adapter '%s', using first (%s)", EmuConfig.GS.Adapter.c_str(),
adapter_info.adapter_names[0].c_str());
adapter_index = 0;
}
}
else
{
Console.WriteLn("No adapter selected, using first.");
adapter_index = 0;
}
ComPtr<IDXGIAdapter> dxgi_adapter;
hr = temp_dxgi_factory->EnumAdapters(adapter_index, dxgi_adapter.put());
if (FAILED(hr))
Console.Warning("Failed to enumerate adapter %u, using default", adapter_index);
static constexpr std::array<D3D_FEATURE_LEVEL, 3> requested_feature_levels = { static constexpr std::array<D3D_FEATURE_LEVEL, 3> requested_feature_levels = {
{D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0}}; {D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0}};
hr = HRESULT hr = D3D11CreateDevice(dxgi_adapter.get(), dxgi_adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, nullptr,
D3D11CreateDevice(dxgi_adapter.get(), dxgi_adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, nullptr, create_flags, requested_feature_levels.data(), static_cast<UINT>(requested_feature_levels.size()), D3D11_SDK_VERSION,
create_flags, requested_feature_levels.data(), static_cast<UINT>(requested_feature_levels.size()), m_device.put(), nullptr, m_context.put());
D3D11_SDK_VERSION, m_device.put(), nullptr, m_context.put());
// we re-grab these later, see below // we re-grab these later, see below
dxgi_adapter.reset(); dxgi_adapter.reset();
temp_dxgi_factory.reset();
if (FAILED(hr)) if (FAILED(hr))
{ {
@ -252,39 +220,15 @@ bool D3D11HostDisplay::CreateDevice(const WindowInfo& wi, VsyncMode vsync)
} }
} }
// we need the specific factory for the device, otherwise MakeWindowAssociation() is flaky.
ComPtr<IDXGIDevice> dxgi_device; ComPtr<IDXGIDevice> dxgi_device;
if (!m_device.try_query_to(&dxgi_device) || FAILED(dxgi_device->GetParent(IID_PPV_ARGS(dxgi_adapter.put()))) || if (m_device.try_query_to(&dxgi_device) && SUCCEEDED(dxgi_device->GetParent(IID_PPV_ARGS(dxgi_adapter.put()))))
FAILED(dxgi_adapter->GetParent(IID_PPV_ARGS(m_dxgi_factory.put())))) Console.WriteLn(fmt::format("D3D Adapter: {}", D3D::GetAdapterName(dxgi_adapter.get())));
{ else
Console.Warning("Failed to get parent adapter/device/factory"); Console.Error("Failed to obtain D3D adapter name.");
return false;
}
DXGI_ADAPTER_DESC adapter_desc; BOOL allow_tearing_supported = false;
if (SUCCEEDED(dxgi_adapter->GetDesc(&adapter_desc))) hr = m_dxgi_factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported, sizeof(allow_tearing_supported));
{ m_allow_tearing_supported = (SUCCEEDED(hr) && allow_tearing_supported == TRUE);
char adapter_name_buffer[128];
const int name_length =
WideCharToMultiByte(CP_UTF8, 0, adapter_desc.Description, static_cast<int>(std::wcslen(adapter_desc.Description)),
adapter_name_buffer, sizeof(adapter_name_buffer), 0, nullptr);
if (name_length >= 0)
{
adapter_name_buffer[name_length] = 0;
Console.WriteLn("D3D Adapter: %s", adapter_name_buffer);
}
}
m_allow_tearing_supported = false;
ComPtr<IDXGIFactory5> dxgi_factory5;
if (m_dxgi_factory.try_query_to(&dxgi_factory5))
{
BOOL allow_tearing_supported = false;
hr = dxgi_factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported,
sizeof(allow_tearing_supported));
if (SUCCEEDED(hr))
m_allow_tearing_supported = (allow_tearing_supported == TRUE);
}
m_window_info = wi; m_window_info = wi;
m_vsync_mode = vsync; m_vsync_mode = vsync;
@ -323,33 +267,36 @@ bool D3D11HostDisplay::CreateSwapChain(const DXGI_MODE_DESC* fullscreen_mode)
const u32 width = static_cast<u32>(client_rc.right - client_rc.left); const u32 width = static_cast<u32>(client_rc.right - client_rc.left);
const u32 height = static_cast<u32>(client_rc.bottom - client_rc.top); const u32 height = static_cast<u32>(client_rc.bottom - client_rc.top);
DXGI_SWAP_CHAIN_DESC swap_chain_desc = {}; DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {};
swap_chain_desc.BufferDesc.Width = width; swap_chain_desc.Width = width;
swap_chain_desc.BufferDesc.Height = height; swap_chain_desc.Height = height;
swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swap_chain_desc.SampleDesc.Count = 1; swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.BufferCount = 3; swap_chain_desc.BufferCount = 3;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.OutputWindow = window_hwnd;
swap_chain_desc.Windowed = TRUE;
swap_chain_desc.SwapEffect = m_using_flip_model_swap_chain ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD; swap_chain_desc.SwapEffect = m_using_flip_model_swap_chain ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
m_using_allow_tearing = (m_allow_tearing_supported && m_using_flip_model_swap_chain && !fullscreen_mode); m_using_allow_tearing = (m_allow_tearing_supported && m_using_flip_model_swap_chain && !fullscreen_mode);
if (m_using_allow_tearing) if (m_using_allow_tearing)
swap_chain_desc.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; swap_chain_desc.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
DXGI_SWAP_CHAIN_FULLSCREEN_DESC fs_desc = {};
if (fullscreen_mode) if (fullscreen_mode)
{ {
swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
swap_chain_desc.Windowed = FALSE; swap_chain_desc.Width = fullscreen_mode->Width;
swap_chain_desc.BufferDesc = *fullscreen_mode; swap_chain_desc.Height = fullscreen_mode->Height;
fs_desc.RefreshRate = fullscreen_mode->RefreshRate;
fs_desc.ScanlineOrdering = fullscreen_mode->ScanlineOrdering;
fs_desc.Scaling = fullscreen_mode->Scaling;
fs_desc.Windowed = FALSE;
} }
Console.WriteLn("Creating a %dx%d %s %s swap chain", swap_chain_desc.BufferDesc.Width, Console.WriteLn("Creating a %dx%d %s %s swap chain", swap_chain_desc.Width, swap_chain_desc.Height,
swap_chain_desc.BufferDesc.Height, m_using_flip_model_swap_chain ? "flip-discard" : "discard", m_using_flip_model_swap_chain ? "flip-discard" : "discard", fullscreen_mode ? "full-screen" : "windowed");
swap_chain_desc.Windowed ? "windowed" : "full-screen");
HRESULT hr = m_dxgi_factory->CreateSwapChain(m_device.get(), &swap_chain_desc, m_swap_chain.put()); HRESULT hr = m_dxgi_factory->CreateSwapChainForHwnd(
m_device.get(), window_hwnd, &swap_chain_desc, fullscreen_mode ? &fs_desc : nullptr, nullptr, m_swap_chain.put());
if (FAILED(hr) && m_using_flip_model_swap_chain) if (FAILED(hr) && m_using_flip_model_swap_chain)
{ {
Console.Warning("Failed to create a flip-discard swap chain, trying discard."); Console.Warning("Failed to create a flip-discard swap chain, trying discard.");
@ -358,22 +305,18 @@ bool D3D11HostDisplay::CreateSwapChain(const DXGI_MODE_DESC* fullscreen_mode)
m_using_flip_model_swap_chain = false; m_using_flip_model_swap_chain = false;
m_using_allow_tearing = false; m_using_allow_tearing = false;
hr = m_dxgi_factory->CreateSwapChain(m_device.get(), &swap_chain_desc, m_swap_chain.put()); hr = m_dxgi_factory->CreateSwapChainForHwnd(
m_device.get(), window_hwnd, &swap_chain_desc, fullscreen_mode ? &fs_desc : nullptr, nullptr, m_swap_chain.put());
if (FAILED(hr)) if (FAILED(hr))
{ {
Console.Error("CreateSwapChain failed: 0x%08X", hr); Console.Error("CreateSwapChainForHwnd failed: 0x%08X", hr);
return false; return false;
} }
} }
ComPtr<IDXGIFactory> dxgi_factory; hr = m_dxgi_factory->MakeWindowAssociation(window_hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
hr = m_swap_chain->GetParent(IID_PPV_ARGS(dxgi_factory.put())); if (FAILED(hr))
if (SUCCEEDED(hr)) Console.Warning("MakeWindowAssociation() to disable ALT+ENTER failed");
{
hr = dxgi_factory->MakeWindowAssociation(swap_chain_desc.OutputWindow, DXGI_MWA_NO_WINDOW_CHANGES);
if (FAILED(hr))
Console.Warning("MakeWindowAssociation() to disable ALT+ENTER failed");
}
return CreateSwapChainRTV(); return CreateSwapChainRTV();
} }
@ -391,8 +334,7 @@ bool D3D11HostDisplay::CreateSwapChainRTV()
D3D11_TEXTURE2D_DESC backbuffer_desc; D3D11_TEXTURE2D_DESC backbuffer_desc;
backbuffer->GetDesc(&backbuffer_desc); backbuffer->GetDesc(&backbuffer_desc);
CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(D3D11_RTV_DIMENSION_TEXTURE2D, backbuffer_desc.Format, 0, 0, CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(D3D11_RTV_DIMENSION_TEXTURE2D, backbuffer_desc.Format, 0, 0, backbuffer_desc.ArraySize);
backbuffer_desc.ArraySize);
hr = m_device->CreateRenderTargetView(backbuffer.get(), &rtv_desc, m_swap_chain_rtv.put()); hr = m_device->CreateRenderTargetView(backbuffer.get(), &rtv_desc, m_swap_chain_rtv.put());
if (FAILED(hr)) if (FAILED(hr))
{ {
@ -408,11 +350,10 @@ bool D3D11HostDisplay::CreateSwapChainRTV()
{ {
BOOL fullscreen = FALSE; BOOL fullscreen = FALSE;
DXGI_SWAP_CHAIN_DESC desc; DXGI_SWAP_CHAIN_DESC desc;
if (SUCCEEDED(m_swap_chain->GetFullscreenState(&fullscreen, nullptr)) && fullscreen && if (SUCCEEDED(m_swap_chain->GetFullscreenState(&fullscreen, nullptr)) && fullscreen && SUCCEEDED(m_swap_chain->GetDesc(&desc)))
SUCCEEDED(m_swap_chain->GetDesc(&desc)))
{ {
m_window_info.surface_refresh_rate = static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) / m_window_info.surface_refresh_rate =
static_cast<float>(desc.BufferDesc.RefreshRate.Denominator); static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) / static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
} }
else else
{ {
@ -501,8 +442,7 @@ void D3D11HostDisplay::ResizeWindow(s32 new_window_width, s32 new_window_height,
m_swap_chain_rtv.reset(); m_swap_chain_rtv.reset();
HRESULT hr = m_swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, HRESULT hr = m_swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, m_using_allow_tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0);
m_using_allow_tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0);
if (FAILED(hr)) if (FAILED(hr))
Console.Error("ResizeBuffers() failed: 0x%08X", hr); Console.Error("ResizeBuffers() failed: 0x%08X", hr);
@ -681,7 +621,8 @@ void D3D11HostDisplay::PopTimestampQuery()
while (m_waiting_timestamp_queries > 0) while (m_waiting_timestamp_queries > 0)
{ {
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjoint; D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjoint;
const HRESULT disjoint_hr = m_context->GetData(m_timestamp_queries[m_read_timestamp_query][0].get(), &disjoint, sizeof(disjoint), D3D11_ASYNC_GETDATA_DONOTFLUSH); const HRESULT disjoint_hr = m_context->GetData(
m_timestamp_queries[m_read_timestamp_query][0].get(), &disjoint, sizeof(disjoint), D3D11_ASYNC_GETDATA_DONOTFLUSH);
if (disjoint_hr != S_OK) if (disjoint_hr != S_OK)
break; break;
@ -696,11 +637,14 @@ void D3D11HostDisplay::PopTimestampQuery()
else else
{ {
u64 start = 0, end = 0; u64 start = 0, end = 0;
const HRESULT start_hr = m_context->GetData(m_timestamp_queries[m_read_timestamp_query][1].get(), &start, sizeof(start), D3D11_ASYNC_GETDATA_DONOTFLUSH); const HRESULT start_hr = m_context->GetData(
const HRESULT end_hr = m_context->GetData(m_timestamp_queries[m_read_timestamp_query][2].get(), &end, sizeof(end), D3D11_ASYNC_GETDATA_DONOTFLUSH); m_timestamp_queries[m_read_timestamp_query][1].get(), &start, sizeof(start), D3D11_ASYNC_GETDATA_DONOTFLUSH);
const HRESULT end_hr =
m_context->GetData(m_timestamp_queries[m_read_timestamp_query][2].get(), &end, sizeof(end), D3D11_ASYNC_GETDATA_DONOTFLUSH);
if (start_hr == S_OK && end_hr == S_OK) if (start_hr == S_OK && end_hr == S_OK)
{ {
m_accumulated_gpu_time += static_cast<float>(static_cast<double>(end - start) / (static_cast<double>(disjoint.Frequency) / 1000.0)); m_accumulated_gpu_time +=
static_cast<float>(static_cast<double>(end - start) / (static_cast<double>(disjoint.Frequency) / 1000.0));
m_read_timestamp_query = (m_read_timestamp_query + 1) % NUM_TIMESTAMP_QUERIES; m_read_timestamp_query = (m_read_timestamp_query + 1) % NUM_TIMESTAMP_QUERIES;
m_waiting_timestamp_queries--; m_waiting_timestamp_queries--;
} }
@ -753,77 +697,38 @@ float D3D11HostDisplay::GetAndResetAccumulatedGPUTime()
HostDisplay::AdapterAndModeList D3D11HostDisplay::StaticGetAdapterAndModeList() HostDisplay::AdapterAndModeList D3D11HostDisplay::StaticGetAdapterAndModeList()
{ {
ComPtr<IDXGIFactory> dxgi_factory; auto factory = D3D::CreateFactory(false);
const HRESULT hr = CreateDXGIFactory(IID_PPV_ARGS(dxgi_factory.put())); if (!factory)
if (FAILED(hr))
return {}; return {};
return GetAdapterAndModeList(dxgi_factory.get()); return GetAdapterAndModeList(factory.get());
} }
HostDisplay::AdapterAndModeList D3D11HostDisplay::GetAdapterAndModeList(IDXGIFactory* dxgi_factory) HostDisplay::AdapterAndModeList D3D11HostDisplay::GetAdapterAndModeList(IDXGIFactory5* dxgi_factory)
{ {
AdapterAndModeList adapter_info; AdapterAndModeList adapter_info;
ComPtr<IDXGIAdapter> current_adapter; adapter_info.adapter_names = D3D::GetAdapterNames(dxgi_factory);
while (SUCCEEDED(dxgi_factory->EnumAdapters(static_cast<UINT>(adapter_info.adapter_names.size()),
current_adapter.put())))
{
DXGI_ADAPTER_DESC adapter_desc;
std::string adapter_name;
if (SUCCEEDED(current_adapter->GetDesc(&adapter_desc)))
{
char adapter_name_buffer[128];
const int name_length = WideCharToMultiByte(CP_UTF8, 0, adapter_desc.Description,
static_cast<int>(std::wcslen(adapter_desc.Description)),
adapter_name_buffer, sizeof(adapter_name_buffer), 0, nullptr);
if (name_length >= 0)
adapter_name.assign(adapter_name_buffer, static_cast<size_t>(name_length));
else
adapter_name.assign("(Unknown)");
}
else
{
adapter_name.assign("(Unknown)");
}
if (adapter_info.fullscreen_modes.empty()) auto adapter = D3D::GetChosenOrFirstAdapter(dxgi_factory, EmuConfig.GS.Adapter);
if (adapter)
{
ComPtr<IDXGIOutput> output;
if (SUCCEEDED(adapter->EnumOutputs(0, &output)))
{ {
ComPtr<IDXGIOutput> output; UINT num_modes = 0;
if (SUCCEEDED(current_adapter->EnumOutputs(0, &output))) if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, nullptr)))
{ {
UINT num_modes = 0; std::vector<DXGI_MODE_DESC> modes(num_modes);
if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, nullptr))) if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, modes.data())))
{ {
std::vector<DXGI_MODE_DESC> modes(num_modes); for (const DXGI_MODE_DESC& mode : modes)
if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, modes.data())))
{ {
for (const DXGI_MODE_DESC& mode : modes) adapter_info.fullscreen_modes.push_back(GetFullscreenModeString(mode.Width, mode.Height,
{ static_cast<float>(mode.RefreshRate.Numerator) / static_cast<float>(mode.RefreshRate.Denominator)));
adapter_info.fullscreen_modes.push_back(GetFullscreenModeString(
mode.Width, mode.Height,
static_cast<float>(mode.RefreshRate.Numerator) / static_cast<float>(mode.RefreshRate.Denominator)));
}
} }
} }
} }
} }
// handle duplicate adapter names
if (std::any_of(adapter_info.adapter_names.begin(), adapter_info.adapter_names.end(),
[&adapter_name](const std::string& other) { return (adapter_name == other); }))
{
std::string original_adapter_name = std::move(adapter_name);
u32 current_extra = 2;
do
{
adapter_name = StringUtil::StdStringFromFormat("%s (%u)", original_adapter_name.c_str(), current_extra);
current_extra++;
} while (std::any_of(adapter_info.adapter_names.begin(), adapter_info.adapter_names.end(),
[&adapter_name](const std::string& other) { return (adapter_name == other); }));
}
adapter_info.adapter_names.push_back(std::move(adapter_name));
} }
return adapter_info; return adapter_info;
@ -833,4 +738,3 @@ HostDisplay::AdapterAndModeList D3D11HostDisplay::GetAdapterAndModeList()
{ {
return GetAdapterAndModeList(m_dxgi_factory.get()); return GetAdapterAndModeList(m_dxgi_factory.get());
} }

View File

@ -20,7 +20,7 @@
#include "common/WindowInfo.h" #include "common/WindowInfo.h"
#include <array> #include <array>
#include <d3d11.h> #include <d3d11.h>
#include <dxgi.h> #include <dxgi1_5.h>
#include <memory> #include <memory>
#include <string> #include <string>
#include <string_view> #include <string_view>
@ -77,7 +77,7 @@ protected:
static constexpr u32 DISPLAY_CONSTANT_BUFFER_SIZE = 16; static constexpr u32 DISPLAY_CONSTANT_BUFFER_SIZE = 16;
static constexpr u8 NUM_TIMESTAMP_QUERIES = 5; static constexpr u8 NUM_TIMESTAMP_QUERIES = 5;
static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory); static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory5* dxgi_factory);
bool CreateImGuiContext() override; bool CreateImGuiContext() override;
void DestroyImGuiContext() override; void DestroyImGuiContext() override;
@ -94,8 +94,8 @@ protected:
ComPtr<ID3D11Device> m_device; ComPtr<ID3D11Device> m_device;
ComPtr<ID3D11DeviceContext> m_context; ComPtr<ID3D11DeviceContext> m_context;
ComPtr<IDXGIFactory> m_dxgi_factory; ComPtr<IDXGIFactory5> m_dxgi_factory;
ComPtr<IDXGISwapChain> m_swap_chain; ComPtr<IDXGISwapChain1> m_swap_chain;
ComPtr<ID3D11RenderTargetView> m_swap_chain_rtv; ComPtr<ID3D11RenderTargetView> m_swap_chain_rtv;
bool m_allow_tearing_supported = false; bool m_allow_tearing_supported = false;

View File

@ -122,10 +122,9 @@ bool D3D12HostDisplay::GetHostRefreshRate(float* refresh_rate)
if (SUCCEEDED(m_swap_chain->GetDesc(&desc)) && desc.BufferDesc.RefreshRate.Numerator > 0 && if (SUCCEEDED(m_swap_chain->GetDesc(&desc)) && desc.BufferDesc.RefreshRate.Numerator > 0 &&
desc.BufferDesc.RefreshRate.Denominator > 0) desc.BufferDesc.RefreshRate.Denominator > 0)
{ {
DevCon.WriteLn("using fs rr: %u %u", desc.BufferDesc.RefreshRate.Numerator, DevCon.WriteLn("using fs rr: %u %u", desc.BufferDesc.RefreshRate.Numerator, desc.BufferDesc.RefreshRate.Denominator);
desc.BufferDesc.RefreshRate.Denominator); *refresh_rate =
*refresh_rate = static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) / static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) / static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
return true; return true;
} }
} }
@ -140,56 +139,19 @@ void D3D12HostDisplay::SetVSync(VsyncMode mode)
bool D3D12HostDisplay::CreateDevice(const WindowInfo& wi, VsyncMode vsync) bool D3D12HostDisplay::CreateDevice(const WindowInfo& wi, VsyncMode vsync)
{ {
ComPtr<IDXGIFactory> temp_dxgi_factory; m_dxgi_factory = D3D::CreateFactory(EmuConfig.GS.UseDebugDevice);
HRESULT hr = CreateDXGIFactory(IID_PPV_ARGS(temp_dxgi_factory.put())); if (!m_dxgi_factory)
if (FAILED(hr))
{
Console.Error("Failed to create DXGI factory: 0x%08X", hr);
return false;
}
u32 adapter_index;
if (!EmuConfig.GS.Adapter.empty())
{
AdapterAndModeList adapter_info(GetAdapterAndModeList(temp_dxgi_factory.get()));
for (adapter_index = 0; adapter_index < static_cast<u32>(adapter_info.adapter_names.size()); adapter_index++)
{
if (EmuConfig.GS.Adapter == adapter_info.adapter_names[adapter_index])
break;
}
if (adapter_index == static_cast<u32>(adapter_info.adapter_names.size()))
{
Console.Warning("Could not find adapter '%s', using first (%s)", EmuConfig.GS.Adapter.c_str(), adapter_info.adapter_names[0].c_str());
adapter_index = 0;
}
}
else
{
Console.WriteLn("No adapter selected, using first.");
adapter_index = 0;
}
if (!D3D12::Context::Create(temp_dxgi_factory.get(), adapter_index, EmuConfig.GS.UseDebugDevice))
return false; return false;
if (FAILED(hr)) ComPtr<IDXGIAdapter1> dxgi_adapter = D3D::GetAdapterByName(m_dxgi_factory.get(), EmuConfig.GS.Adapter);
{
Console.Error("Failed to create D3D device: 0x%08X", hr); if (!D3D12::Context::Create(m_dxgi_factory.get(), dxgi_adapter.get(), EmuConfig.GS.UseDebugDevice))
return false; return false;
}
m_dxgi_factory = std::move(temp_dxgi_factory); BOOL allow_tearing_supported = false;
HRESULT hr =
m_allow_tearing_supported = false; m_dxgi_factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported, sizeof(allow_tearing_supported));
ComPtr<IDXGIFactory5> dxgi_factory5(m_dxgi_factory.try_query<IDXGIFactory5>()); m_allow_tearing_supported = (SUCCEEDED(hr) && allow_tearing_supported == TRUE);
if (dxgi_factory5)
{
BOOL allow_tearing_supported = false;
hr = dxgi_factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported,
sizeof(allow_tearing_supported));
if (SUCCEEDED(hr))
m_allow_tearing_supported = (allow_tearing_supported == TRUE);
}
m_window_info = wi; m_window_info = wi;
m_vsync_mode = vsync; m_vsync_mode = vsync;
@ -226,40 +188,43 @@ bool D3D12HostDisplay::CreateSwapChain(const DXGI_MODE_DESC* fullscreen_mode)
const u32 width = static_cast<u32>(client_rc.right - client_rc.left); const u32 width = static_cast<u32>(client_rc.right - client_rc.left);
const u32 height = static_cast<u32>(client_rc.bottom - client_rc.top); const u32 height = static_cast<u32>(client_rc.bottom - client_rc.top);
DXGI_SWAP_CHAIN_DESC swap_chain_desc = {}; DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {};
swap_chain_desc.BufferDesc.Width = width; swap_chain_desc.Width = width;
swap_chain_desc.BufferDesc.Height = height; swap_chain_desc.Height = height;
swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swap_chain_desc.SampleDesc.Count = 1; swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.BufferCount = 3; swap_chain_desc.BufferCount = 3;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.OutputWindow = window_hwnd;
swap_chain_desc.Windowed = TRUE;
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
m_using_allow_tearing = (m_allow_tearing_supported && !fullscreen_mode); m_using_allow_tearing = (m_allow_tearing_supported && !fullscreen_mode);
if (m_using_allow_tearing) if (m_using_allow_tearing)
swap_chain_desc.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; swap_chain_desc.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
DXGI_SWAP_CHAIN_FULLSCREEN_DESC fs_desc = {};
if (fullscreen_mode) if (fullscreen_mode)
{ {
swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
swap_chain_desc.Windowed = FALSE; swap_chain_desc.Width = fullscreen_mode->Width;
swap_chain_desc.BufferDesc = *fullscreen_mode; swap_chain_desc.Height = fullscreen_mode->Height;
fs_desc.RefreshRate = fullscreen_mode->RefreshRate;
fs_desc.ScanlineOrdering = fullscreen_mode->ScanlineOrdering;
fs_desc.Scaling = fullscreen_mode->Scaling;
fs_desc.Windowed = FALSE;
} }
DevCon.WriteLn("Creating a %dx%d %s swap chain", swap_chain_desc.BufferDesc.Width, swap_chain_desc.BufferDesc.Height, DevCon.WriteLn(
swap_chain_desc.Windowed ? "windowed" : "full-screen"); "Creating a %dx%d %s swap chain", swap_chain_desc.Width, swap_chain_desc.Height, fullscreen_mode ? "full-screen" : "windowed");
HRESULT hr = HRESULT hr = m_dxgi_factory->CreateSwapChainForHwnd(g_d3d12_context->GetCommandQueue(), window_hwnd, &swap_chain_desc,
m_dxgi_factory->CreateSwapChain(g_d3d12_context->GetCommandQueue(), &swap_chain_desc, m_swap_chain.put()); fullscreen_mode ? &fs_desc : nullptr, nullptr, m_swap_chain.put());
if (FAILED(hr)) if (FAILED(hr))
{ {
Console.Error("CreateSwapChain failed: 0x%08X", hr); Console.Error("CreateSwapChainForHwnd failed: 0x%08X", hr);
return false; return false;
} }
hr = m_dxgi_factory->MakeWindowAssociation(swap_chain_desc.OutputWindow, DXGI_MWA_NO_WINDOW_CHANGES); hr = m_dxgi_factory->MakeWindowAssociation(window_hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
if (FAILED(hr)) if (FAILED(hr))
Console.Warning("MakeWindowAssociation() to disable ALT+ENTER failed"); Console.Warning("MakeWindowAssociation() to disable ALT+ENTER failed");
@ -301,11 +266,10 @@ bool D3D12HostDisplay::CreateSwapChainRTV()
{ {
BOOL fullscreen = FALSE; BOOL fullscreen = FALSE;
DXGI_SWAP_CHAIN_DESC desc; DXGI_SWAP_CHAIN_DESC desc;
if (SUCCEEDED(m_swap_chain->GetFullscreenState(&fullscreen, nullptr)) && fullscreen && if (SUCCEEDED(m_swap_chain->GetFullscreenState(&fullscreen, nullptr)) && fullscreen && SUCCEEDED(m_swap_chain->GetDesc(&desc)))
SUCCEEDED(m_swap_chain->GetDesc(&desc)))
{ {
m_window_info.surface_refresh_rate = static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) / m_window_info.surface_refresh_rate =
static_cast<float>(desc.BufferDesc.RefreshRate.Denominator); static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) / static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
} }
else else
{ {
@ -402,8 +366,7 @@ void D3D12HostDisplay::ResizeWindow(s32 new_window_width, s32 new_window_height,
DestroySwapChainRTVs(); DestroySwapChainRTVs();
HRESULT hr = m_swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, HRESULT hr = m_swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, m_using_allow_tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0);
m_using_allow_tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0);
if (FAILED(hr)) if (FAILED(hr))
Console.Error("ResizeBuffers() failed: 0x%08X", hr); Console.Error("ResizeBuffers() failed: 0x%08X", hr);
@ -529,7 +492,8 @@ HostDisplay::PresentResult D3D12HostDisplay::BeginPresent(bool frame_skip)
cmdlist->ClearRenderTargetView(swap_chain_buf.GetWriteDescriptor(), clear_color.data(), 0, nullptr); cmdlist->ClearRenderTargetView(swap_chain_buf.GetWriteDescriptor(), clear_color.data(), 0, nullptr);
cmdlist->OMSetRenderTargets(1, &swap_chain_buf.GetWriteDescriptor().cpu_handle, FALSE, nullptr); cmdlist->OMSetRenderTargets(1, &swap_chain_buf.GetWriteDescriptor().cpu_handle, FALSE, nullptr);
const D3D12_VIEWPORT vp{0.0f, 0.0f, static_cast<float>(m_window_info.surface_width), static_cast<float>(m_window_info.surface_height), 0.0f, 1.0f}; const D3D12_VIEWPORT vp{
0.0f, 0.0f, static_cast<float>(m_window_info.surface_width), static_cast<float>(m_window_info.surface_height), 0.0f, 1.0f};
const D3D12_RECT scissor{0, 0, static_cast<LONG>(m_window_info.surface_width), static_cast<LONG>(m_window_info.surface_height)}; const D3D12_RECT scissor{0, 0, static_cast<LONG>(m_window_info.surface_width), static_cast<LONG>(m_window_info.surface_height)};
cmdlist->RSSetViewports(1, &vp); cmdlist->RSSetViewports(1, &vp);
cmdlist->RSSetScissorRects(1, &scissor); cmdlist->RSSetScissorRects(1, &scissor);
@ -571,77 +535,38 @@ float D3D12HostDisplay::GetAndResetAccumulatedGPUTime()
HostDisplay::AdapterAndModeList D3D12HostDisplay::StaticGetAdapterAndModeList() HostDisplay::AdapterAndModeList D3D12HostDisplay::StaticGetAdapterAndModeList()
{ {
ComPtr<IDXGIFactory> dxgi_factory; auto factory = D3D::CreateFactory(false);
const HRESULT hr = CreateDXGIFactory(IID_PPV_ARGS(dxgi_factory.put())); if (!factory)
if (FAILED(hr))
return {}; return {};
return GetAdapterAndModeList(dxgi_factory.get()); return GetAdapterAndModeList(factory.get());
} }
HostDisplay::AdapterAndModeList D3D12HostDisplay::GetAdapterAndModeList(IDXGIFactory* dxgi_factory) HostDisplay::AdapterAndModeList D3D12HostDisplay::GetAdapterAndModeList(IDXGIFactory5* dxgi_factory)
{ {
AdapterAndModeList adapter_info; AdapterAndModeList adapter_info;
ComPtr<IDXGIAdapter> current_adapter; adapter_info.adapter_names = D3D::GetAdapterNames(dxgi_factory);
while (SUCCEEDED(dxgi_factory->EnumAdapters(static_cast<UINT>(adapter_info.adapter_names.size()),
current_adapter.put())))
{
DXGI_ADAPTER_DESC adapter_desc;
std::string adapter_name;
if (SUCCEEDED(current_adapter->GetDesc(&adapter_desc)))
{
char adapter_name_buffer[128];
const int name_length = WideCharToMultiByte(CP_UTF8, 0, adapter_desc.Description,
static_cast<int>(std::wcslen(adapter_desc.Description)),
adapter_name_buffer, std::size(adapter_name_buffer), 0, nullptr);
if (name_length >= 0)
adapter_name.assign(adapter_name_buffer, static_cast<size_t>(name_length));
else
adapter_name.assign("(Unknown)");
}
else
{
adapter_name.assign("(Unknown)");
}
if (adapter_info.fullscreen_modes.empty()) auto adapter = D3D::GetChosenOrFirstAdapter(dxgi_factory, EmuConfig.GS.Adapter);
if (adapter)
{
ComPtr<IDXGIOutput> output;
if (SUCCEEDED(adapter->EnumOutputs(0, &output)))
{ {
ComPtr<IDXGIOutput> output; UINT num_modes = 0;
if (SUCCEEDED(current_adapter->EnumOutputs(0, &output))) if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, nullptr)))
{ {
UINT num_modes = 0; std::vector<DXGI_MODE_DESC> modes(num_modes);
if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, nullptr))) if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, modes.data())))
{ {
std::vector<DXGI_MODE_DESC> modes(num_modes); for (const DXGI_MODE_DESC& mode : modes)
if (SUCCEEDED(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, modes.data())))
{ {
for (const DXGI_MODE_DESC& mode : modes) adapter_info.fullscreen_modes.push_back(GetFullscreenModeString(mode.Width, mode.Height,
{ static_cast<float>(mode.RefreshRate.Numerator) / static_cast<float>(mode.RefreshRate.Denominator)));
adapter_info.fullscreen_modes.push_back(StringUtil::StdStringFromFormat(
"%u x %u @ %f hz", mode.Width, mode.Height,
static_cast<float>(mode.RefreshRate.Numerator) / static_cast<float>(mode.RefreshRate.Denominator)));
}
} }
} }
} }
} }
// handle duplicate adapter names
if (std::any_of(adapter_info.adapter_names.begin(), adapter_info.adapter_names.end(),
[&adapter_name](const std::string& other) { return (adapter_name == other); }))
{
std::string original_adapter_name = std::move(adapter_name);
u32 current_extra = 2;
do
{
adapter_name = StringUtil::StdStringFromFormat("%s (%u)", original_adapter_name.c_str(), current_extra);
current_extra++;
} while (std::any_of(adapter_info.adapter_names.begin(), adapter_info.adapter_names.end(),
[&adapter_name](const std::string& other) { return (adapter_name == other); }));
}
adapter_info.adapter_names.push_back(std::move(adapter_name));
} }
return adapter_info; return adapter_info;

View File

@ -25,7 +25,7 @@
#include "HostDisplay.h" #include "HostDisplay.h"
#include <d3d12.h> #include <d3d12.h>
#include <dxgi.h> #include <dxgi1_5.h>
#include <memory> #include <memory>
#include <string> #include <string>
#include <string_view> #include <string_view>
@ -80,7 +80,7 @@ public:
static AdapterAndModeList StaticGetAdapterAndModeList(); static AdapterAndModeList StaticGetAdapterAndModeList();
protected: protected:
static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory); static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory5* dxgi_factory);
bool CreateImGuiContext() override; bool CreateImGuiContext() override;
void DestroyImGuiContext() override; void DestroyImGuiContext() override;
@ -90,8 +90,8 @@ protected:
bool CreateSwapChainRTV(); bool CreateSwapChainRTV();
void DestroySwapChainRTVs(); void DestroySwapChainRTVs();
ComPtr<IDXGIFactory> m_dxgi_factory; ComPtr<IDXGIFactory5> m_dxgi_factory;
ComPtr<IDXGISwapChain> m_swap_chain; ComPtr<IDXGISwapChain1> m_swap_chain;
std::vector<D3D12::Texture> m_swap_chain_buffers; std::vector<D3D12::Texture> m_swap_chain_buffers;
u32 m_current_swap_chain_buffer = 0; u32 m_current_swap_chain_buffer = 0;

View File

@ -129,24 +129,6 @@ void GSclose()
static RenderAPI GetAPIForRenderer(GSRendererType renderer) static RenderAPI GetAPIForRenderer(GSRendererType renderer)
{ {
#if defined(_WIN32)
// On Windows, we use DX11 for software, since it's always available.
constexpr RenderAPI default_api = RenderAPI::D3D11;
#elif defined(__APPLE__)
// For Macs, default to Metal.
constexpr RenderAPI default_api = RenderAPI::Metal;
#else
// For Linux, default to OpenGL (because of hardware compatibility), if we
// have it, otherwise Vulkan (if we have it).
#if defined(ENABLE_OPENGL)
constexpr RenderAPI default_api = RenderAPI::OpenGL;
#elif defined(ENABLE_VULKAN)
constexpr RenderAPI default_api = RenderAPI::Vulkan;
#else
constexpr RenderAPI default_api = RenderAPI::None;
#endif
#endif
switch (renderer) switch (renderer)
{ {
case GSRendererType::OGL: case GSRendererType::OGL:
@ -169,7 +151,7 @@ static RenderAPI GetAPIForRenderer(GSRendererType renderer)
#endif #endif
default: default:
return default_api; return GetAPIForRenderer(GSUtil::GetPreferredRenderer());
} }
} }

View File

@ -203,25 +203,14 @@ GSRendererType GSUtil::GetPreferredRenderer()
// Mac: Prefer Metal hardware. // Mac: Prefer Metal hardware.
return GSRendererType::Metal; return GSRendererType::Metal;
#elif defined(_WIN32) #elif defined(_WIN32)
const u8 preferred = D3D::ShouldPreferRenderer(); // Use D3D device info to select renderer.
#if defined(ENABLE_VULKAN) return D3D::GetPreferredRenderer();
if (preferred == D3D::Renderer::Vulkan)
return GSRendererType::VK;
#endif
#if defined(ENABLE_OPENGL)
if (preferred == D3D::Renderer::OpenGL)
return GSRendererType::OGL;
#endif
if (preferred == D3D::Renderer::Direct3D12)
return GSRendererType::DX12;
return GSRendererType::DX11;
#else #else
// Linux: Prefer GL/Vulkan, whatever is available. // Linux: Prefer GL/Vulkan, whatever is available.
#if defined(ENABLE_OPENGL) #if defined(ENABLE_OPENGL)
return GSRendererType::OGL; return GSRendererType::OGL;
#elif defined(ENABLE_VULKAN) #elif defined(ENABLE_VULKAN)
return GSRendererType::Vulkan; return GSRendererType::VK;
#else #else
return GSRendererType::SW; return GSRendererType::SW;
#endif #endif

View File

@ -17,194 +17,278 @@
#include "GS/Renderers/DX11/D3D.h" #include "GS/Renderers/DX11/D3D.h"
#include "GS/GSExtra.h" #include "GS/GSExtra.h"
#include "common/Console.h"
#include "common/StringUtil.h" #include "common/StringUtil.h"
#include <d3d11.h> #include <d3d11.h>
#include "fmt/format.h" #include "fmt/format.h"
namespace D3D wil::com_ptr_nothrow<IDXGIFactory5> D3D::CreateFactory(bool debug)
{ {
wil::com_ptr_nothrow<IDXGIFactory2> CreateFactory(bool debug) UINT flags = 0;
if (debug)
flags |= DXGI_CREATE_FACTORY_DEBUG;
wil::com_ptr_nothrow<IDXGIFactory5> factory;
const HRESULT hr = CreateDXGIFactory2(flags, IID_PPV_ARGS(factory.put()));
if (FAILED(hr))
Console.Error("D3D: Failed to create DXGI factory: %08X", hr);
return factory;
}
static std::string FixupDuplicateAdapterNames(const std::vector<std::string>& adapter_names, std::string adapter_name)
{
if (std::any_of(adapter_names.begin(), adapter_names.end(),
[&adapter_name](const std::string& other) { return (adapter_name == other); }))
{ {
UINT flags = 0; std::string original_adapter_name = std::move(adapter_name);
if (debug)
flags |= DXGI_CREATE_FACTORY_DEBUG;
// we use CreateDXGIFactory2 because we assume at least windows 8.1 anyway u32 current_extra = 2;
wil::com_ptr_nothrow<IDXGIFactory2> factory; do
HRESULT hr = CreateDXGIFactory2(flags, IID_PPV_ARGS(factory.put()));
// if we failed to create a factory with debug support
// try one without
if (FAILED(hr) && debug)
{ {
fprintf(stderr, "D3D: failed to create debug dxgi factory, trying without debugging\n"); adapter_name = StringUtil::StdStringFromFormat("%s (%u)", original_adapter_name.c_str(), current_extra);
hr = CreateDXGIFactory2(0, IID_PPV_ARGS(factory.put()));; current_extra++;
} } while (std::any_of(adapter_names.begin(), adapter_names.end(),
[&adapter_name](const std::string& other) { return (adapter_name == other); }));
}
return adapter_name;
}
std::vector<std::string> D3D::GetAdapterNames(IDXGIFactory5* factory)
{
std::vector<std::string> adapter_names;
wil::com_ptr_nothrow<IDXGIAdapter1> adapter;
for (u32 index = 0;; index++)
{
const HRESULT hr = factory->EnumAdapters1(index, adapter.put());
if (hr == DXGI_ERROR_NOT_FOUND)
break;
if (FAILED(hr)) if (FAILED(hr))
{ {
fprintf(stderr, "D3D: failed to create dxgi factory\n" Console.Error(fmt::format("IDXGIFactory2::EnumAdapters() returned %08X", hr));
"check that your system meets our minimum requirements:\n" continue;
"https://github.com/PCSX2/pcsx2#system-requirements\n");
} }
return factory; adapter_names.push_back(FixupDuplicateAdapterNames(adapter_names, GetAdapterName(adapter.get())));
} }
wil::com_ptr_nothrow<IDXGIAdapter1> GetAdapterFromIndex(IDXGIFactory2* factory, int index) return adapter_names;
{ }
ASSERT(factory);
wil::com_ptr_nothrow<IDXGIAdapter1> adapter; wil::com_ptr_nothrow<IDXGIAdapter1> D3D::GetAdapterByName(IDXGIFactory5* factory, const std::string_view& name)
if (index < 0 || factory->EnumAdapters1(index, adapter.put()) == DXGI_ERROR_NOT_FOUND) {
if (name.empty())
return {};
// This might seem a bit odd to cache the names.. but there's a method to the madness.
// We might have two GPUs with the same name... :)
std::vector<std::string> adapter_names;
wil::com_ptr_nothrow<IDXGIAdapter1> adapter;
for (u32 index = 0;; index++)
{
const HRESULT hr = factory->EnumAdapters1(index, adapter.put());
if (hr == DXGI_ERROR_NOT_FOUND)
break;
if (FAILED(hr))
{ {
// try index 0 (default adapter) Console.Error(fmt::format("IDXGIFactory2::EnumAdapters() returned %08X", hr));
if (index >= 0) continue;
fprintf(stderr, "D3D: adapter not found, falling back to the default\n");
if (FAILED(factory->EnumAdapters1(0, adapter.put())))
{
// either there are no adapters connected or something major is wrong with the system
fprintf(stderr, "D3D: failed to EnumAdapters\n");
}
} }
return adapter; std::string adapter_name = FixupDuplicateAdapterNames(adapter_names, GetAdapterName(adapter.get()));
if (adapter_name == name)
{
Console.WriteLn(fmt::format("D3D: Found adapter '{}'", adapter_name));
return adapter;
}
adapter_names.push_back(std::move(adapter_name));
} }
std::string GetDriverVersionFromLUID(const LUID& luid) Console.Warning(fmt::format("Adapter '{}' not found.", name));
{ return {};
std::string ret; }
HKEY hKey; wil::com_ptr_nothrow<IDXGIAdapter1> D3D::GetFirstAdapter(IDXGIFactory5* factory)
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\DirectX", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
wil::com_ptr_nothrow<IDXGIAdapter1> adapter;
HRESULT hr = factory->EnumAdapters1(0, adapter.put());
if (FAILED(hr))
Console.Error(fmt::format("IDXGIFactory2::EnumAdapters() for first adapter returned %08X", hr));
return adapter;
}
wil::com_ptr_nothrow<IDXGIAdapter1> D3D::GetChosenOrFirstAdapter(IDXGIFactory5* factory, const std::string_view& name)
{
wil::com_ptr_nothrow<IDXGIAdapter1> adapter = GetAdapterByName(factory, name);
if (!adapter)
adapter = GetFirstAdapter(factory);
return adapter;
}
std::string D3D::GetAdapterName(IDXGIAdapter1* adapter)
{
std::string ret;
DXGI_ADAPTER_DESC1 desc;
HRESULT hr = adapter->GetDesc1(&desc);
if (SUCCEEDED(hr))
{
ret = StringUtil::WideStringToUTF8String(desc.Description);
}
else
{
Console.Error(fmt::format("IDXGIAdapter1::GetDesc() returned {:08X}", hr));
}
if (ret.empty())
ret = "(Unknown)";
return ret;
}
std::string D3D::GetDriverVersionFromLUID(const LUID& luid)
{
std::string ret;
HKEY hKey;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\DirectX", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
DWORD max_key_len = 0, adapter_count = 0;
if (RegQueryInfoKeyW(hKey, nullptr, nullptr, nullptr, &adapter_count, &max_key_len, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr) == ERROR_SUCCESS)
{ {
DWORD max_key_len = 0, adapter_count = 0; std::vector<TCHAR> current_name(max_key_len + 1);
if (RegQueryInfoKeyW(hKey, nullptr, nullptr, nullptr, &adapter_count, &max_key_len, nullptr, nullptr, for (DWORD i = 0; i < adapter_count; ++i)
nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS)
{ {
std::vector<TCHAR> current_name(max_key_len + 1); DWORD subKeyLength = static_cast<DWORD>(current_name.size());
for (DWORD i = 0; i < adapter_count; ++i) if (RegEnumKeyExW(hKey, i, current_name.data(), &subKeyLength, nullptr, nullptr, nullptr, nullptr) ==
ERROR_SUCCESS)
{ {
DWORD subKeyLength = static_cast<DWORD>(current_name.size()); LUID current_luid = {};
if (RegEnumKeyExW(hKey, i, current_name.data(), &subKeyLength, nullptr, nullptr, nullptr, DWORD current_luid_size = sizeof(uint64_t);
nullptr) == ERROR_SUCCESS) if (RegGetValueW(hKey, current_name.data(), L"AdapterLuid", RRF_RT_QWORD, nullptr, &current_luid,
&current_luid_size) == ERROR_SUCCESS &&
current_luid.HighPart == luid.HighPart && current_luid.LowPart == luid.LowPart)
{ {
LUID current_luid = {}; LARGE_INTEGER driver_version = {};
DWORD current_luid_size = sizeof(uint64_t); DWORD driver_version_size = sizeof(driver_version);
if (RegGetValueW(hKey, current_name.data(), L"AdapterLuid", RRF_RT_QWORD, nullptr, if (RegGetValueW(hKey, current_name.data(), L"DriverVersion", RRF_RT_QWORD, nullptr,
&current_luid, &current_luid_size) == ERROR_SUCCESS && &driver_version, &driver_version_size) == ERROR_SUCCESS)
current_luid.HighPart == luid.HighPart && current_luid.LowPart == luid.LowPart)
{ {
LARGE_INTEGER driver_version = {}; WORD nProduct = HIWORD(driver_version.HighPart);
DWORD driver_version_size = sizeof(driver_version); WORD nVersion = LOWORD(driver_version.HighPart);
if (RegGetValueW(hKey, current_name.data(), L"DriverVersion", RRF_RT_QWORD, nullptr, WORD nSubVersion = HIWORD(driver_version.LowPart);
&driver_version, &driver_version_size) == ERROR_SUCCESS) WORD nBuild = LOWORD(driver_version.LowPart);
{ ret = fmt::format("{}.{}.{}.{}", nProduct, nVersion, nSubVersion, nBuild);
WORD nProduct = HIWORD(driver_version.HighPart);
WORD nVersion = LOWORD(driver_version.HighPart);
WORD nSubVersion = HIWORD(driver_version.LowPart);
WORD nBuild = LOWORD(driver_version.LowPart);
ret = fmt::format("{}.{}.{}.{}", nProduct, nVersion, nSubVersion, nBuild);
}
} }
} }
} }
} }
RegCloseKey(hKey);
} }
return ret; RegCloseKey(hKey);
} }
u8 Vendor() return ret;
}
D3D::VendorID D3D::GetVendorID(IDXGIAdapter1* adapter)
{
DXGI_ADAPTER_DESC1 desc;
const HRESULT hr = adapter->GetDesc1(&desc);
if (FAILED(hr))
{ {
auto factory = CreateFactory(false); Console.Error(fmt::format("IDXGIAdapter1::GetDesc() returned {:08X}", hr));
auto adapter = GetAdapterFromIndex(factory.get(), 0); return VendorID::Unknown;
}
ASSERT(adapter); switch (desc.VendorId)
{
DXGI_ADAPTER_DESC1 desc = {}; case 0x10DE:
if (FAILED(adapter->GetDesc1(&desc))) return VendorID::Nvidia;
{ case 0x1002:
fprintf(stderr, "D3D: failed to get the adapter description\n"); case 0x1022:
return VendorID::AMD;
case 0x163C:
case 0x8086:
case 0x8087:
return VendorID::Intel;
default:
return VendorID::Unknown; return VendorID::Unknown;
} }
}
switch (desc.VendorId) GSRendererType D3D::GetPreferredRenderer()
{ {
case 0x10DE: auto factory = CreateFactory(false);
return VendorID::Nvidia; auto adapter = GetChosenOrFirstAdapter(factory.get(), GSConfig.Adapter);
case 0x1002:
case 0x1022: // If we somehow can't get a D3D11 device, it's unlikely any of the renderers are going to work.
return VendorID::AMD; if (!adapter)
case 0x163C: return GSRendererType::DX11;
case 0x8086:
case 0x8087: D3D_FEATURE_LEVEL feature_level;
return VendorID::Intel;
default: static const D3D_FEATURE_LEVEL check[] = {
return VendorID::Unknown; D3D_FEATURE_LEVEL_12_0,
} D3D_FEATURE_LEVEL_11_0,
};
const HRESULT hr = D3D11CreateDevice(adapter.get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, std::data(check),
std::size(check), D3D11_SDK_VERSION, nullptr, &feature_level, nullptr);
if (FAILED(hr))
{
// See note above.
return GSRendererType::DX11;
} }
u8 ShouldPreferRenderer() switch (GetVendorID(adapter.get()))
{ {
auto factory = CreateFactory(false); case VendorID::Nvidia:
auto adapter = GetAdapterFromIndex(factory.get(), 0);
ASSERT(adapter);
D3D_FEATURE_LEVEL feature_level;
static const D3D_FEATURE_LEVEL check[] = {
D3D_FEATURE_LEVEL_12_0,
D3D_FEATURE_LEVEL_11_0,
};
const HRESULT hr = D3D11CreateDevice(
adapter.get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0,
std::data(check), std::size(check), D3D11_SDK_VERSION, nullptr, &feature_level, nullptr
);
if (FAILED(hr))
return Renderer::Default;
switch (Vendor())
{ {
case VendorID::Nvidia: if (feature_level == D3D_FEATURE_LEVEL_12_0)
{ return GSRendererType::VK;
if (feature_level == D3D_FEATURE_LEVEL_12_0) else if (feature_level == D3D_FEATURE_LEVEL_11_0)
return Renderer::Vulkan; return GSRendererType::OGL;
else if (feature_level == D3D_FEATURE_LEVEL_11_0) else
return Renderer::OpenGL; return GSRendererType::DX11;
else }
return Renderer::Direct3D11;
}
case VendorID::AMD: case VendorID::AMD:
{ {
if (feature_level == D3D_FEATURE_LEVEL_12_0) if (feature_level == D3D_FEATURE_LEVEL_12_0)
return Renderer::Vulkan; return GSRendererType::VK;
else else
return Renderer::Direct3D11; return GSRendererType::DX11;
} }
case VendorID::Intel: case VendorID::Intel:
{ {
// Older Intel GPUs prior to Xe seem to have broken OpenGL drivers which choke // Older Intel GPUs prior to Xe seem to have broken OpenGL drivers which choke
// on some of our shaders, causing what appears to be GPU timeouts+device removals. // on some of our shaders, causing what appears to be GPU timeouts+device removals.
// Vulkan has broken barriers, also prior to Xe. So just fall back to DX11 everywhere, // Vulkan has broken barriers, also prior to Xe. So just fall back to DX11 everywhere,
// unless we can find some way of differentiating Xe. // unless we have Arc, which is easy to identify.
return Renderer::Direct3D11; if (StringUtil::StartsWith(GetAdapterName(adapter.get()), "Intel(R) Arc(TM) "))
} return GSRendererType::VK;
else
return GSRendererType::DX11;
}
default: default:
{ {
// Default is D3D11 // Default is D3D11
return Renderer::Direct3D11; return GSRendererType::DX11;
}
} }
} }
} }

View File

@ -18,26 +18,39 @@
#include "common/RedtapeWindows.h" #include "common/RedtapeWindows.h"
#include "common/RedtapeWilCom.h" #include "common/RedtapeWilCom.h"
#include <dxgi1_3.h> #include "pcsx2/Config.h"
#include <vector>
#include <dxgi1_5.h>
#include <string> #include <string>
#include <string_view>
#include <vector>
namespace D3D namespace D3D
{ {
// create a dxgi factory // create a dxgi factory
wil::com_ptr_nothrow<IDXGIFactory2> CreateFactory(bool debug); wil::com_ptr_nothrow<IDXGIFactory5> CreateFactory(bool debug);
// get an adapter based on position // returns a list of all adapter names
// assuming no one removes/moves it, it should always have the same id std::vector<std::string> GetAdapterNames(IDXGIFactory5* factory);
// however in the event that the adapter is not found due to the above, use the default
wil::com_ptr_nothrow<IDXGIAdapter1> GetAdapterFromIndex(IDXGIFactory2* factory, int index); // get an adapter based on name
wil::com_ptr_nothrow<IDXGIAdapter1> GetAdapterByName(IDXGIFactory5* factory, const std::string_view& name);
// returns the first adapter in the system
wil::com_ptr_nothrow<IDXGIAdapter1> GetFirstAdapter(IDXGIFactory5* factory);
// returns the adapter specified in the configuration, or the default
wil::com_ptr_nothrow<IDXGIAdapter1> GetChosenOrFirstAdapter(IDXGIFactory5* factory, const std::string_view& name);
// returns a utf-8 string of the specified adapter's name
std::string GetAdapterName(IDXGIAdapter1* adapter);
// returns the driver version from the registry as a string // returns the driver version from the registry as a string
std::string GetDriverVersionFromLUID(const LUID& luid); std::string GetDriverVersionFromLUID(const LUID& luid);
// this is sort of a legacy thing that doesn't have much to do with d3d (just the easiest way) // this is sort of a legacy thing that doesn't have much to do with d3d (just the easiest way)
// checks to see if the adapter at 0 is NV and thus we should prefer OpenGL // checks to see if the adapter at 0 is NV and thus we should prefer OpenGL
enum VendorID enum class VendorID
{ {
Unknown, Unknown,
Nvidia, Nvidia,
@ -45,15 +58,6 @@ namespace D3D
Intel Intel
}; };
enum Renderer VendorID GetVendorID(IDXGIAdapter1* adapter);
{ GSRendererType GetPreferredRenderer();
Default, }; // namespace D3D
OpenGL,
Vulkan,
Direct3D11,
Direct3D12
};
u8 Vendor();
u8 ShouldPreferRenderer();
};

View File

@ -119,7 +119,13 @@ bool GSDevice11::Create()
{ {
// HACK: check AMD // HACK: check AMD
// Broken point sampler should be enabled only on AMD. // Broken point sampler should be enabled only on AMD.
m_features.broken_point_sampler = (D3D::Vendor() == D3D::VendorID::AMD); wil::com_ptr_nothrow<IDXGIDevice> dxgi_device;
wil::com_ptr_nothrow<IDXGIAdapter1> dxgi_adapter;
if (SUCCEEDED(m_dev->QueryInterface(dxgi_device.put())) &&
SUCCEEDED(dxgi_device->GetParent(IID_PPV_ARGS(dxgi_adapter.put()))))
{
m_features.broken_point_sampler = (D3D::GetVendorID(dxgi_adapter.get()) == D3D::VendorID::AMD);
}
} }
SetFeatures(); SetFeatures();