mirror of https://github.com/PCSX2/pcsx2.git
GS: Unify D3D device creation paths
Also makes Vulkan the device for Intel Arc GPUs.
This commit is contained in:
parent
8989b69ce8
commit
fcbc027abc
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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, ¤t_luid,
|
||||||
|
¤t_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,
|
||||||
¤t_luid, ¤t_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;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
};
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue