2015-05-24 04:55:12 +00:00
|
|
|
// Copyright 2010 Dolphin Emulator Project
|
2015-05-17 23:08:10 +00:00
|
|
|
// Licensed under GPLv2+
|
2013-04-18 03:29:41 +00:00
|
|
|
// Refer to the license.txt file included.
|
2010-06-13 19:50:06 +00:00
|
|
|
|
2019-06-01 11:55:09 +00:00
|
|
|
#include "VideoBackends/D3D/D3DBase.h"
|
|
|
|
|
2015-12-12 12:00:08 +00:00
|
|
|
#include <algorithm>
|
2019-06-01 11:55:09 +00:00
|
|
|
#include <array>
|
2015-12-12 12:00:08 +00:00
|
|
|
|
2016-01-17 21:54:31 +00:00
|
|
|
#include "Common/CommonTypes.h"
|
2019-03-09 13:31:36 +00:00
|
|
|
#include "Common/DynamicLibrary.h"
|
2016-01-17 21:54:31 +00:00
|
|
|
#include "Common/Logging/Log.h"
|
|
|
|
#include "Common/MsgHandler.h"
|
2017-05-18 12:59:38 +00:00
|
|
|
#include "Core/Config/GraphicsSettings.h"
|
2016-11-09 00:41:38 +00:00
|
|
|
#include "Core/ConfigManager.h"
|
2014-06-23 06:11:07 +00:00
|
|
|
#include "VideoBackends/D3D/D3DState.h"
|
2019-02-15 01:59:50 +00:00
|
|
|
#include "VideoBackends/D3D/DXTexture.h"
|
2019-03-09 13:31:36 +00:00
|
|
|
#include "VideoBackends/D3DCommon/Common.h"
|
2014-02-19 11:14:09 +00:00
|
|
|
#include "VideoCommon/VideoConfig.h"
|
2010-06-13 19:50:06 +00:00
|
|
|
|
2011-01-29 20:16:51 +00:00
|
|
|
namespace DX11
|
|
|
|
{
|
2019-03-09 13:31:36 +00:00
|
|
|
static Common::DynamicLibrary s_d3d11_library;
|
2010-06-13 19:50:06 +00:00
|
|
|
namespace D3D
|
|
|
|
{
|
2019-05-12 04:42:16 +00:00
|
|
|
ComPtr<IDXGIFactory> dxgi_factory;
|
2019-03-09 13:31:36 +00:00
|
|
|
ComPtr<ID3D11Device> device;
|
|
|
|
ComPtr<ID3D11Device1> device1;
|
|
|
|
ComPtr<ID3D11DeviceContext> context;
|
|
|
|
D3D_FEATURE_LEVEL feature_level;
|
2010-06-19 01:02:43 +00:00
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
static ComPtr<ID3D11Debug> s_debug;
|
2017-11-19 18:23:56 +00:00
|
|
|
|
2019-06-01 11:55:09 +00:00
|
|
|
constexpr std::array<D3D_FEATURE_LEVEL, 3> s_supported_feature_levels{
|
|
|
|
D3D_FEATURE_LEVEL_11_0,
|
|
|
|
D3D_FEATURE_LEVEL_10_1,
|
|
|
|
D3D_FEATURE_LEVEL_10_0,
|
|
|
|
};
|
2010-06-13 19:50:06 +00:00
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
bool Create(u32 adapter_index, bool enable_debug_layer)
|
2010-11-21 15:34:04 +00:00
|
|
|
{
|
2019-03-09 13:31:36 +00:00
|
|
|
PFN_D3D11_CREATE_DEVICE d3d11_create_device;
|
|
|
|
if (!s_d3d11_library.Open("d3d11.dll") ||
|
|
|
|
!s_d3d11_library.GetSymbol("D3D11CreateDevice", &d3d11_create_device))
|
2019-02-15 01:59:50 +00:00
|
|
|
{
|
2019-03-09 13:31:36 +00:00
|
|
|
PanicAlertT("Failed to load d3d11.dll");
|
|
|
|
s_d3d11_library.Close();
|
2019-02-15 01:59:50 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
if (!D3DCommon::LoadLibraries())
|
2018-01-26 06:23:24 +00:00
|
|
|
{
|
2019-03-09 13:31:36 +00:00
|
|
|
s_d3d11_library.Close();
|
2018-01-26 06:23:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
dxgi_factory = D3DCommon::CreateDXGIFactory(enable_debug_layer);
|
|
|
|
if (!dxgi_factory)
|
2018-01-26 06:23:24 +00:00
|
|
|
{
|
2019-03-09 13:31:36 +00:00
|
|
|
PanicAlertT("Failed to create DXGI factory");
|
|
|
|
D3DCommon::UnloadLibraries();
|
|
|
|
s_d3d11_library.Close();
|
2018-01-26 06:23:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
ComPtr<IDXGIAdapter> adapter;
|
2019-07-21 15:10:51 +00:00
|
|
|
HRESULT hr = dxgi_factory->EnumAdapters(adapter_index, adapter.GetAddressOf());
|
2010-06-14 19:20:41 +00:00
|
|
|
if (FAILED(hr))
|
|
|
|
{
|
2020-11-09 08:01:58 +00:00
|
|
|
WARN_LOG_FMT(VIDEO, "Adapter {} not found, using default", adapter_index);
|
2019-03-09 13:31:36 +00:00
|
|
|
adapter = nullptr;
|
2010-06-14 19:20:41 +00:00
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2013-08-15 14:19:14 +00:00
|
|
|
// Creating debug devices can sometimes fail if the user doesn't have the correct
|
|
|
|
// version of the DirectX SDK. If it does, simply fallback to a non-debug device.
|
2019-03-09 13:31:36 +00:00
|
|
|
if (enable_debug_layer)
|
2013-08-15 14:19:14 +00:00
|
|
|
{
|
2019-07-21 15:10:51 +00:00
|
|
|
hr = d3d11_create_device(
|
|
|
|
adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_DEBUG,
|
|
|
|
s_supported_feature_levels.data(), static_cast<UINT>(s_supported_feature_levels.size()),
|
|
|
|
D3D11_SDK_VERSION, device.GetAddressOf(), &feature_level, context.GetAddressOf());
|
2017-06-25 18:57:46 +00:00
|
|
|
|
2015-02-09 12:00:42 +00:00
|
|
|
// Debugbreak on D3D error
|
2019-07-20 22:17:15 +00:00
|
|
|
if (SUCCEEDED(hr) && SUCCEEDED(device.As(&s_debug)))
|
2015-02-09 12:00:42 +00:00
|
|
|
{
|
2019-03-09 13:31:36 +00:00
|
|
|
ComPtr<ID3D11InfoQueue> info_queue;
|
2019-07-20 22:17:15 +00:00
|
|
|
if (SUCCEEDED(s_debug.As(&info_queue)))
|
2015-02-09 12:00:42 +00:00
|
|
|
{
|
2019-03-09 13:31:36 +00:00
|
|
|
info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
|
|
|
|
info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-02-09 12:00:42 +00:00
|
|
|
D3D11_MESSAGE_ID hide[] = {D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS};
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-02-12 13:45:05 +00:00
|
|
|
D3D11_INFO_QUEUE_FILTER filter = {};
|
2015-02-09 12:00:42 +00:00
|
|
|
filter.DenyList.NumIDs = sizeof(hide) / sizeof(D3D11_MESSAGE_ID);
|
|
|
|
filter.DenyList.pIDList = hide;
|
2019-03-09 13:31:36 +00:00
|
|
|
info_queue->AddStorageFilterEntries(&filter);
|
2015-02-09 12:00:42 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-09 13:31:36 +00:00
|
|
|
else
|
|
|
|
{
|
2020-11-09 08:01:58 +00:00
|
|
|
WARN_LOG_FMT(VIDEO, "Debug layer requested but not available.");
|
2019-03-09 13:31:36 +00:00
|
|
|
}
|
2013-08-15 14:19:14 +00:00
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
if (!enable_debug_layer || FAILED(hr))
|
2013-08-15 14:19:14 +00:00
|
|
|
{
|
2019-07-21 15:10:51 +00:00
|
|
|
hr = d3d11_create_device(
|
|
|
|
adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, s_supported_feature_levels.data(),
|
|
|
|
static_cast<UINT>(s_supported_feature_levels.size()), D3D11_SDK_VERSION,
|
|
|
|
device.GetAddressOf(), &feature_level, context.GetAddressOf());
|
2017-07-09 23:02:29 +00:00
|
|
|
}
|
2017-06-25 18:57:46 +00:00
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
if (FAILED(hr))
|
2010-06-13 19:50:06 +00:00
|
|
|
{
|
2019-03-09 13:31:36 +00:00
|
|
|
PanicAlertT(
|
|
|
|
"Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0");
|
2019-05-27 02:59:29 +00:00
|
|
|
dxgi_factory.Reset();
|
2019-03-09 13:31:36 +00:00
|
|
|
D3DCommon::UnloadLibraries();
|
2019-05-27 02:59:29 +00:00
|
|
|
s_d3d11_library.Close();
|
2019-03-09 13:31:36 +00:00
|
|
|
return false;
|
2010-06-13 19:50:06 +00:00
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2019-07-20 22:17:15 +00:00
|
|
|
hr = device.As(&device1);
|
2017-09-03 06:33:47 +00:00
|
|
|
if (FAILED(hr))
|
2018-05-25 14:04:18 +00:00
|
|
|
{
|
2020-11-09 08:01:58 +00:00
|
|
|
WARN_LOG_FMT(VIDEO, "Missing Direct3D 11.1 support. Logical operations will not be supported.");
|
2018-05-25 14:04:18 +00:00
|
|
|
}
|
2017-09-03 06:33:47 +00:00
|
|
|
|
2019-03-29 09:55:00 +00:00
|
|
|
stateman = std::make_unique<StateManager>();
|
2019-03-09 13:31:36 +00:00
|
|
|
return true;
|
2010-06-13 19:50:06 +00:00
|
|
|
}
|
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
void Destroy()
|
2010-06-13 19:50:06 +00:00
|
|
|
{
|
2019-03-29 09:55:00 +00:00
|
|
|
stateman.reset();
|
2014-06-20 01:45:42 +00:00
|
|
|
|
2011-06-11 19:37:21 +00:00
|
|
|
context->ClearState();
|
2019-03-09 13:31:36 +00:00
|
|
|
context->Flush();
|
2011-06-11 19:37:21 +00:00
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
context.Reset();
|
|
|
|
device1.Reset();
|
2015-02-09 12:00:42 +00:00
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
auto remaining_references = device.Reset();
|
2017-11-19 18:23:56 +00:00
|
|
|
if (s_debug)
|
2015-02-09 12:00:42 +00:00
|
|
|
{
|
2019-03-09 13:31:36 +00:00
|
|
|
--remaining_references; // the debug interface increases the refcount of the device, subtract
|
|
|
|
// that.
|
|
|
|
if (remaining_references)
|
2015-02-09 12:00:42 +00:00
|
|
|
{
|
|
|
|
// print out alive objects, but only if we actually have pending references
|
|
|
|
// note this will also print out internal live objects to the debug console
|
2017-11-19 18:23:56 +00:00
|
|
|
s_debug->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL);
|
2015-02-09 12:00:42 +00:00
|
|
|
}
|
2019-03-09 13:31:36 +00:00
|
|
|
s_debug.Reset();
|
2015-02-09 12:00:42 +00:00
|
|
|
}
|
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
if (remaining_references)
|
2020-11-09 08:01:58 +00:00
|
|
|
ERROR_LOG_FMT(VIDEO, "Unreleased references: {}.", remaining_references);
|
2011-06-11 19:37:21 +00:00
|
|
|
else
|
2020-11-09 08:01:58 +00:00
|
|
|
NOTICE_LOG_FMT(VIDEO, "Successfully released all device references!");
|
2010-06-19 01:02:43 +00:00
|
|
|
|
2019-05-27 02:59:29 +00:00
|
|
|
dxgi_factory.Reset();
|
2019-03-09 13:31:36 +00:00
|
|
|
D3DCommon::UnloadLibraries();
|
|
|
|
s_d3d11_library.Close();
|
2017-09-03 15:33:12 +00:00
|
|
|
}
|
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
std::vector<u32> GetAAModes(u32 adapter_index)
|
2010-07-11 16:26:46 +00:00
|
|
|
{
|
2019-03-09 13:31:36 +00:00
|
|
|
// Use temporary device if we don't have one already.
|
|
|
|
Common::DynamicLibrary temp_lib;
|
|
|
|
ComPtr<ID3D11Device> temp_device = device;
|
2019-07-21 10:03:49 +00:00
|
|
|
D3D_FEATURE_LEVEL temp_feature_level = feature_level;
|
2019-03-09 13:31:36 +00:00
|
|
|
if (!temp_device)
|
2010-07-11 16:26:46 +00:00
|
|
|
{
|
2019-05-12 04:42:16 +00:00
|
|
|
ComPtr<IDXGIFactory> temp_dxgi_factory = D3DCommon::CreateDXGIFactory(false);
|
2019-03-09 13:31:36 +00:00
|
|
|
if (!temp_dxgi_factory)
|
|
|
|
return {};
|
2010-07-11 16:26:46 +00:00
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
ComPtr<IDXGIAdapter> adapter;
|
2019-07-21 10:03:49 +00:00
|
|
|
temp_dxgi_factory->EnumAdapters(adapter_index, adapter.GetAddressOf());
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
PFN_D3D11_CREATE_DEVICE d3d11_create_device;
|
|
|
|
if (!temp_lib.Open("d3d11.dll") ||
|
|
|
|
!temp_lib.GetSymbol("D3D11CreateDevice", &d3d11_create_device))
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2019-07-21 10:03:49 +00:00
|
|
|
HRESULT hr = d3d11_create_device(
|
|
|
|
adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, s_supported_feature_levels.data(),
|
|
|
|
static_cast<UINT>(s_supported_feature_levels.size()), D3D11_SDK_VERSION,
|
|
|
|
temp_device.GetAddressOf(), &temp_feature_level, nullptr);
|
2019-03-09 13:31:36 +00:00
|
|
|
if (FAILED(hr))
|
|
|
|
return {};
|
2010-06-17 10:42:57 +00:00
|
|
|
}
|
2010-06-13 19:50:06 +00:00
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
// NOTE: D3D 10.0 doesn't support multisampled resources which are bound as depth buffers AND
|
|
|
|
// shader resources. Thus, we can't have MSAA with 10.0 level hardware.
|
2019-07-21 10:03:49 +00:00
|
|
|
if (temp_feature_level == D3D_FEATURE_LEVEL_10_0)
|
2019-03-09 13:31:36 +00:00
|
|
|
return {};
|
2017-09-03 15:33:12 +00:00
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
std::vector<u32> aa_modes;
|
2019-07-21 10:03:49 +00:00
|
|
|
for (u32 samples = 1; samples <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; ++samples)
|
2017-11-19 18:23:56 +00:00
|
|
|
{
|
2019-03-09 13:31:36 +00:00
|
|
|
UINT quality_levels = 0;
|
|
|
|
if (SUCCEEDED(temp_device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, samples,
|
|
|
|
&quality_levels)) &&
|
|
|
|
quality_levels > 0)
|
|
|
|
{
|
|
|
|
aa_modes.push_back(samples);
|
|
|
|
}
|
2017-11-19 18:23:56 +00:00
|
|
|
}
|
2017-06-26 19:47:34 +00:00
|
|
|
|
2019-03-09 13:31:36 +00:00
|
|
|
return aa_modes;
|
2017-09-02 18:22:18 +00:00
|
|
|
}
|
2019-04-28 05:26:46 +00:00
|
|
|
|
|
|
|
bool SupportsTextureFormat(DXGI_FORMAT format)
|
|
|
|
{
|
|
|
|
UINT support;
|
|
|
|
if (FAILED(device->CheckFormatSupport(format, &support)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return (support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0;
|
|
|
|
}
|
|
|
|
|
2019-07-21 15:10:51 +00:00
|
|
|
bool SupportsLogicOp(u32 adapter_index)
|
|
|
|
{
|
|
|
|
// Use temporary device if we don't have one already.
|
|
|
|
Common::DynamicLibrary temp_lib;
|
|
|
|
ComPtr<ID3D11Device1> temp_device1 = device1;
|
|
|
|
if (!device)
|
|
|
|
{
|
|
|
|
ComPtr<ID3D11Device> temp_device;
|
|
|
|
|
|
|
|
ComPtr<IDXGIFactory> temp_dxgi_factory = D3DCommon::CreateDXGIFactory(false);
|
|
|
|
if (!temp_dxgi_factory)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ComPtr<IDXGIAdapter> adapter;
|
|
|
|
temp_dxgi_factory->EnumAdapters(adapter_index, adapter.GetAddressOf());
|
|
|
|
|
|
|
|
PFN_D3D11_CREATE_DEVICE d3d11_create_device;
|
|
|
|
if (!temp_lib.Open("d3d11.dll") ||
|
|
|
|
!temp_lib.GetSymbol("D3D11CreateDevice", &d3d11_create_device))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT hr = d3d11_create_device(
|
|
|
|
adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, s_supported_feature_levels.data(),
|
|
|
|
static_cast<UINT>(s_supported_feature_levels.size()), D3D11_SDK_VERSION,
|
|
|
|
temp_device.GetAddressOf(), nullptr, nullptr);
|
|
|
|
if (FAILED(hr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (FAILED(temp_device.As(&temp_device1)))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!temp_device1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
D3D11_FEATURE_DATA_D3D11_OPTIONS options{};
|
|
|
|
if (FAILED(temp_device1->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options,
|
|
|
|
sizeof(options))))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return options.OutputMergerLogicOp != FALSE;
|
|
|
|
}
|
|
|
|
|
2011-01-29 20:16:51 +00:00
|
|
|
} // namespace D3D
|
|
|
|
|
2011-02-14 02:18:03 +00:00
|
|
|
} // namespace DX11
|