D3DBase.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // Copyright 2010 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "VideoBackends/D3D/D3DBase.h"
  4. #include <algorithm>
  5. #include <array>
  6. #include "Common/CommonTypes.h"
  7. #include "Common/DynamicLibrary.h"
  8. #include "Common/Logging/Log.h"
  9. #include "Common/MsgHandler.h"
  10. #include "Core/Config/GraphicsSettings.h"
  11. #include "Core/ConfigManager.h"
  12. #include "VideoBackends/D3D/D3DState.h"
  13. #include "VideoBackends/D3D/DXTexture.h"
  14. #include "VideoBackends/D3DCommon/D3DCommon.h"
  15. #include "VideoCommon/FramebufferManager.h"
  16. #include "VideoCommon/VideoConfig.h"
  17. namespace DX11
  18. {
  19. static Common::DynamicLibrary s_d3d11_library;
  20. namespace D3D
  21. {
  22. ComPtr<IDXGIFactory> dxgi_factory;
  23. ComPtr<ID3D11Device> device;
  24. ComPtr<ID3D11Device1> device1;
  25. ComPtr<ID3D11DeviceContext> context;
  26. D3D_FEATURE_LEVEL feature_level;
  27. static ComPtr<ID3D11Debug> s_debug;
  28. constexpr std::array<D3D_FEATURE_LEVEL, 3> s_supported_feature_levels{
  29. D3D_FEATURE_LEVEL_11_0,
  30. D3D_FEATURE_LEVEL_10_1,
  31. D3D_FEATURE_LEVEL_10_0,
  32. };
  33. bool Create(u32 adapter_index, bool enable_debug_layer)
  34. {
  35. PFN_D3D11_CREATE_DEVICE d3d11_create_device;
  36. if (!s_d3d11_library.Open("d3d11.dll") ||
  37. !s_d3d11_library.GetSymbol("D3D11CreateDevice", &d3d11_create_device))
  38. {
  39. PanicAlertFmtT("Failed to load d3d11.dll");
  40. s_d3d11_library.Close();
  41. return false;
  42. }
  43. if (!D3DCommon::LoadLibraries())
  44. {
  45. s_d3d11_library.Close();
  46. return false;
  47. }
  48. dxgi_factory = D3DCommon::CreateDXGIFactory(enable_debug_layer);
  49. if (!dxgi_factory)
  50. {
  51. PanicAlertFmtT("Failed to create DXGI factory");
  52. D3DCommon::UnloadLibraries();
  53. s_d3d11_library.Close();
  54. return false;
  55. }
  56. ComPtr<IDXGIAdapter> adapter;
  57. HRESULT hr = dxgi_factory->EnumAdapters(adapter_index, adapter.GetAddressOf());
  58. if (FAILED(hr))
  59. {
  60. WARN_LOG_FMT(VIDEO, "Adapter {} not found, using default: {}", adapter_index, DX11HRWrap(hr));
  61. adapter = nullptr;
  62. }
  63. // Creating debug devices can sometimes fail if the user doesn't have the correct
  64. // version of the DirectX SDK. If it does, simply fallback to a non-debug device.
  65. if (enable_debug_layer)
  66. {
  67. hr = d3d11_create_device(
  68. adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_DEBUG,
  69. s_supported_feature_levels.data(), static_cast<UINT>(s_supported_feature_levels.size()),
  70. D3D11_SDK_VERSION, device.GetAddressOf(), &feature_level, context.GetAddressOf());
  71. // Debugbreak on D3D error
  72. if (SUCCEEDED(hr) && SUCCEEDED(hr = device.As(&s_debug)))
  73. {
  74. ComPtr<ID3D11InfoQueue> info_queue;
  75. if (SUCCEEDED(s_debug.As(&info_queue)))
  76. {
  77. info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
  78. info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
  79. D3D11_MESSAGE_ID hide[] = {D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS};
  80. D3D11_INFO_QUEUE_FILTER filter = {};
  81. filter.DenyList.NumIDs = sizeof(hide) / sizeof(D3D11_MESSAGE_ID);
  82. filter.DenyList.pIDList = hide;
  83. info_queue->AddStorageFilterEntries(&filter);
  84. }
  85. }
  86. else
  87. {
  88. WARN_LOG_FMT(VIDEO, "Debug layer requested but not available: {}", DX11HRWrap(hr));
  89. }
  90. }
  91. if (!enable_debug_layer || FAILED(hr))
  92. {
  93. hr = d3d11_create_device(
  94. adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, s_supported_feature_levels.data(),
  95. static_cast<UINT>(s_supported_feature_levels.size()), D3D11_SDK_VERSION,
  96. device.GetAddressOf(), &feature_level, context.GetAddressOf());
  97. }
  98. if (FAILED(hr))
  99. {
  100. PanicAlertFmtT(
  101. "Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0\n{0}",
  102. DX11HRWrap(hr));
  103. dxgi_factory.Reset();
  104. D3DCommon::UnloadLibraries();
  105. s_d3d11_library.Close();
  106. return false;
  107. }
  108. hr = device.As(&device1);
  109. if (FAILED(hr))
  110. {
  111. WARN_LOG_FMT(VIDEO,
  112. "Missing Direct3D 11.1 support. Logical operations will not be supported.\n{}",
  113. DX11HRWrap(hr));
  114. }
  115. stateman = std::make_unique<StateManager>();
  116. return true;
  117. }
  118. void Destroy()
  119. {
  120. stateman.reset();
  121. context->ClearState();
  122. context->Flush();
  123. context.Reset();
  124. device1.Reset();
  125. auto remaining_references = device.Reset();
  126. if (s_debug)
  127. {
  128. --remaining_references; // the debug interface increases the refcount of the device, subtract
  129. // that.
  130. if (remaining_references)
  131. {
  132. // print out alive objects, but only if we actually have pending references
  133. // note this will also print out internal live objects to the debug console
  134. s_debug->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL);
  135. }
  136. s_debug.Reset();
  137. }
  138. if (remaining_references)
  139. ERROR_LOG_FMT(VIDEO, "Unreleased references: {}.", remaining_references);
  140. else
  141. NOTICE_LOG_FMT(VIDEO, "Successfully released all device references!");
  142. dxgi_factory.Reset();
  143. D3DCommon::UnloadLibraries();
  144. s_d3d11_library.Close();
  145. }
  146. std::vector<u32> GetAAModes(u32 adapter_index)
  147. {
  148. // Use temporary device if we don't have one already.
  149. Common::DynamicLibrary temp_lib;
  150. ComPtr<ID3D11Device> temp_device = device;
  151. D3D_FEATURE_LEVEL temp_feature_level = feature_level;
  152. if (!temp_device)
  153. {
  154. ComPtr<IDXGIFactory> temp_dxgi_factory = D3DCommon::CreateDXGIFactory(false);
  155. if (!temp_dxgi_factory)
  156. return {};
  157. ComPtr<IDXGIAdapter> adapter;
  158. temp_dxgi_factory->EnumAdapters(adapter_index, adapter.GetAddressOf());
  159. PFN_D3D11_CREATE_DEVICE d3d11_create_device;
  160. if (!temp_lib.Open("d3d11.dll") ||
  161. !temp_lib.GetSymbol("D3D11CreateDevice", &d3d11_create_device))
  162. {
  163. return {};
  164. }
  165. HRESULT hr = d3d11_create_device(
  166. adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, s_supported_feature_levels.data(),
  167. static_cast<UINT>(s_supported_feature_levels.size()), D3D11_SDK_VERSION,
  168. temp_device.GetAddressOf(), &temp_feature_level, nullptr);
  169. if (FAILED(hr))
  170. return {};
  171. }
  172. // NOTE: D3D 10.0 doesn't support multisampled resources which are bound as depth buffers AND
  173. // shader resources. Thus, we can't have MSAA with 10.0 level hardware.
  174. if (temp_feature_level == D3D_FEATURE_LEVEL_10_0)
  175. return {};
  176. const DXGI_FORMAT target_format =
  177. D3DCommon::GetDXGIFormatForAbstractFormat(FramebufferManager::GetEFBColorFormat(), false);
  178. std::vector<u32> aa_modes;
  179. for (u32 samples = 1; samples <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; ++samples)
  180. {
  181. UINT quality_levels = 0;
  182. if (SUCCEEDED(
  183. temp_device->CheckMultisampleQualityLevels(target_format, samples, &quality_levels)) &&
  184. quality_levels > 0)
  185. {
  186. aa_modes.push_back(samples);
  187. }
  188. }
  189. return aa_modes;
  190. }
  191. bool SupportsTextureFormat(DXGI_FORMAT format)
  192. {
  193. UINT support;
  194. if (FAILED(device->CheckFormatSupport(format, &support)))
  195. return false;
  196. return (support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0;
  197. }
  198. bool SupportsLogicOp(u32 adapter_index)
  199. {
  200. // Use temporary device if we don't have one already.
  201. Common::DynamicLibrary temp_lib;
  202. ComPtr<ID3D11Device1> temp_device1 = device1;
  203. if (!device)
  204. {
  205. ComPtr<ID3D11Device> temp_device;
  206. ComPtr<IDXGIFactory> temp_dxgi_factory = D3DCommon::CreateDXGIFactory(false);
  207. if (!temp_dxgi_factory)
  208. return false;
  209. ComPtr<IDXGIAdapter> adapter;
  210. temp_dxgi_factory->EnumAdapters(adapter_index, adapter.GetAddressOf());
  211. PFN_D3D11_CREATE_DEVICE d3d11_create_device;
  212. if (!temp_lib.Open("d3d11.dll") ||
  213. !temp_lib.GetSymbol("D3D11CreateDevice", &d3d11_create_device))
  214. {
  215. return false;
  216. }
  217. HRESULT hr = d3d11_create_device(
  218. adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, s_supported_feature_levels.data(),
  219. static_cast<UINT>(s_supported_feature_levels.size()), D3D11_SDK_VERSION,
  220. temp_device.GetAddressOf(), nullptr, nullptr);
  221. if (FAILED(hr))
  222. return false;
  223. if (FAILED(temp_device.As(&temp_device1)))
  224. return false;
  225. }
  226. if (!temp_device1)
  227. return false;
  228. D3D11_FEATURE_DATA_D3D11_OPTIONS options{};
  229. if (FAILED(temp_device1->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options,
  230. sizeof(options))))
  231. {
  232. return false;
  233. }
  234. return options.OutputMergerLogicOp != FALSE;
  235. }
  236. } // namespace D3D
  237. } // namespace DX11