dxgi.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. /*
  2. * Copyright 2011-2024 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
  4. */
  5. #include "bgfx_p.h"
  6. #if BGFX_CONFIG_RENDERER_DIRECT3D11 || (BGFX_CONFIG_RENDERER_DIRECT3D12 && !BX_PLATFORM_LINUX)
  7. #include "dxgi.h"
  8. #include "renderer_d3d.h"
  9. #if !BX_PLATFORM_WINDOWS && !BX_PLATFORM_LINUX
  10. # include <inspectable.h>
  11. # if BX_PLATFORM_WINRT
  12. # include <windows.ui.xaml.media.dxinterop.h>
  13. # endif // BX_PLATFORM_WINRT
  14. #endif // !BX_PLATFORM_WINDOWS
  15. #if BX_PLATFORM_WINRT
  16. // Copied from <microsoft.ui.xaml.media.dxinterop.h> from Windows App SDK
  17. // Put in a namespace to avoid conflict with <windows.ui.xaml.media.dxinterop.h>
  18. namespace WinUI3
  19. {
  20. // https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/win32/microsoft.ui.xaml.media.dxinterop/nn-microsoft-ui-xaml-media-dxinterop-iswapchainpanelnative
  21. MIDL_INTERFACE("63aad0b8-7c24-40ff-85a8-640d944cc325")
  22. ISwapChainPanelNative : public IUnknown
  23. {
  24. public:
  25. virtual HRESULT STDMETHODCALLTYPE SetSwapChain(
  26. /* [annotation][in] */
  27. _In_ IDXGISwapChain *swapChain) = 0;
  28. };
  29. // https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/win32/microsoft.ui.xaml.media.dxinterop/nn-microsoft-ui-xaml-media-dxinterop-iswapchainbackgroundpanelnative
  30. MIDL_INTERFACE("24d43d84-4246-4aa7-9774-8604cb73d90d")
  31. ISwapChainBackgroundPanelNative : public IUnknown
  32. {
  33. public:
  34. virtual HRESULT STDMETHODCALLTYPE SetSwapChain(
  35. /* [annotation][in] */
  36. _In_ IDXGISwapChain *swapChain) = 0;
  37. };
  38. }
  39. #endif // BX_PLATFORM_WINRT
  40. namespace bgfx
  41. {
  42. BX_PRAGMA_DIAGNOSTIC_PUSH();
  43. BX_PRAGMA_DIAGNOSTIC_IGNORED_GCC("-Wunused-variable");
  44. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG("-Wunused-const-variable");
  45. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG("-Wunneeded-internal-declaration");
  46. #if BX_PLATFORM_WINDOWS
  47. static PFN_CREATE_DXGI_FACTORY CreateDXGIFactory;
  48. static PFN_GET_DEBUG_INTERFACE DXGIGetDebugInterface;
  49. static PFN_GET_DEBUG_INTERFACE1 DXGIGetDebugInterface1;
  50. #endif // BX_PLATFORM_WINDOWS
  51. static const GUID IID_IDXGIFactory = { 0x7b7166ec, 0x21c7, 0x44ae, { 0xb2, 0x1a, 0xc9, 0xae, 0x32, 0x1a, 0xe3, 0x69 } };
  52. static const GUID IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48, { 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } };
  53. static const GUID IID_IDXGIFactory3 = { 0x25483823, 0xcd46, 0x4c7d, { 0x86, 0xca, 0x47, 0xaa, 0x95, 0xb8, 0x37, 0xbd } };
  54. static const GUID IID_IDXGIFactory4 = { 0x1bc6ea02, 0xef36, 0x464f, { 0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a } };
  55. static const GUID IID_IDXGIFactory5 = { 0x7632e1f5, 0xee65, 0x4dca, { 0x87, 0xfd, 0x84, 0xcd, 0x75, 0xf8, 0x83, 0x8d } };
  56. static const GUID IID_IDXGIDevice0 = { 0x54ec77fa, 0x1377, 0x44e6, { 0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8, 0x4c } };
  57. static const GUID IID_IDXGIDevice1 = { 0x77db970f, 0x6276, 0x48ba, { 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39, 0x2c } };
  58. static const GUID IID_IDXGIDevice2 = { 0x05008617, 0xfbfd, 0x4051, { 0xa7, 0x90, 0x14, 0x48, 0x84, 0xb4, 0xf6, 0xa9 } };
  59. static const GUID IID_IDXGIDevice3 = { 0x6007896c, 0x3244, 0x4afd, { 0xbf, 0x18, 0xa6, 0xd3, 0xbe, 0xda, 0x50, 0x23 } };
  60. static const GUID IID_IDXGIAdapter = { 0x2411e7e1, 0x12ac, 0x4ccf, { 0xbd, 0x14, 0x97, 0x98, 0xe8, 0x53, 0x4d, 0xc0 } };
  61. static const GUID IID_IDXGIAdapter2 = { 0x0aa1ae0a, 0xfa0e, 0x4b84, { 0x86, 0x44, 0xe0, 0x5f, 0xf8, 0xe5, 0xac, 0xb5 } };
  62. static const GUID IID_IDXGIAdapter3 = { 0x645967a4, 0x1392, 0x4310, { 0xa7, 0x98, 0x80, 0x53, 0xce, 0x3e, 0x93, 0xfd } };
  63. static const GUID IID_IDXGIAdapter4 = { 0x3c8d99d1, 0x4fbf, 0x4181, { 0xa8, 0x2c, 0xaf, 0x66, 0xbf, 0x7b, 0xd2, 0x4e } };
  64. static const GUID IID_IDXGISwapChain3 = { 0x94d99bdb, 0xf1f8, 0x4ab0, { 0xb2, 0x36, 0x7d, 0xa0, 0x17, 0x0e, 0xda, 0xb1 } };
  65. static const GUID IID_IDXGISwapChain4 = { 0x3d585d5a, 0xbd4a, 0x489e, { 0xb1, 0xf4, 0x3d, 0xbc, 0xb6, 0x45, 0x2f, 0xfb } };
  66. static const GUID IID_IDXGIOutput6 = { 0x068346e8, 0xaaec, 0x4b84, { 0xad, 0xd7, 0x13, 0x7f, 0x51, 0x3f, 0x77, 0xa1 } };
  67. BX_PRAGMA_DIAGNOSTIC_POP();
  68. static const DXGI_COLOR_SPACE_TYPE s_colorSpace[] =
  69. {
  70. DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // gamma 2.2, BT.709
  71. DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709, // gamma 1.0, BT.709
  72. DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020, // gamma 2084, BT.2020
  73. };
  74. static const char* s_colorSpaceStr[] =
  75. {
  76. // https://msdn.microsoft.com/en-us/library/windows/desktop/dn903661(v=vs.85).aspx
  77. "RGB, 0-255, 2.2, Image, BT.709, n/a", // DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709
  78. "RGB, 0-255, 1.0, Image, BT.709, n/a", // DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709
  79. "RGB, 16-235, 2.2, Image, BT.709, n/a", // DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709
  80. "RGB, 16-235, 2.2, Image, BT.2020, n/a", // DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020
  81. "Reserved", // DXGI_COLOR_SPACE_RESERVED
  82. "YCbCr, 0-255, 2.2, Image, BT.709, BT.601", // DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601
  83. "YCbCr, 16-235, 2.2, Video, BT.601, n/a", // DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601
  84. "YCbCr, 0-255, 2.2, Video, BT.601, n/a", // DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601
  85. "YCbCr, 16-235, 2.2, Video, BT.709, n/a", // DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709
  86. "YCbCr, 0-255, 2.2, Video, BT.709, n/a", // DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709
  87. "YCbCr, 16-235, 2.2, Video, BT.2020, n/a", // DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020
  88. "YCbCr, 0-255, 2.2, Video, BT.2020, n/a", // DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020
  89. "RGB, 0-255, 2084, Image, BT.2020, n/a", // DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020
  90. "YCbCr, 16-235, 2084, Video, BT.2020, n/a", // DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020
  91. "RGB, 0-255, 2084, Image, BT.2020, n/a", // DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020
  92. "YCbCr, 16-235, 2.2, Video, BT.2020, n/a", // DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020
  93. "YCbCr, 16-235, 2084, Video, BT.2020, n/a", // DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020
  94. #if BX_PLATFORM_WINDOWS
  95. "RGB, 0-255, 2.2, Image, BT.2020, n/a", // DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020
  96. "YCbCr, 16-235, HLG, Video, BT.2020, n/a", // DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020
  97. "YCbCr, 0-255, HLG, Video, BT.2020, n/a", // DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020
  98. // "RGB, 16-235, 2.4, Image, BT.709, n/a", // DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P709
  99. // "RGB, 16-235, 2.4, Image, BT.2020, n/a", // DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P2020
  100. // "YCbCr, 16-235, 2.4, Video, BT.709, n/a", // DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P709
  101. // "YCbCr, 16-235, 2.4, Video, BT.2020, n/a", // DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P2020
  102. // "YCbCr, 16-235, 2.4, Video, BT.2020, n/a", // DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_TOPLEFT_P2020
  103. #endif // BX_PLATFORM_WINDOWS
  104. "Custom",
  105. };
  106. static const DXGI_COLOR_SPACE_TYPE kDxgiLastColorSpace =
  107. #if BX_PLATFORM_WINDOWS
  108. DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020
  109. #else
  110. DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020
  111. #endif // BX_PLATFORM_WINDOWS
  112. ;
  113. BX_STATIC_ASSERT(BX_COUNTOF(s_colorSpaceStr) == kDxgiLastColorSpace+2, "Colorspace string table mismatch with DXGI_COLOR_SPACE_*.");
  114. static const GUID s_dxgiDeviceIIDs[] =
  115. {
  116. IID_IDXGIDevice3,
  117. IID_IDXGIDevice2,
  118. IID_IDXGIDevice1,
  119. IID_IDXGIDevice0,
  120. };
  121. static const GUID s_dxgiSwapChainIIDs[] =
  122. {
  123. IID_IDXGISwapChain4,
  124. IID_IDXGISwapChain3,
  125. };
  126. #if BX_PLATFORM_WINRT
  127. template<typename T>
  128. static bool trySetSwapChain(IInspectable* nativeWindow, Dxgi::SwapChainI* swapChain, HRESULT* hr)
  129. {
  130. ISwapChainPanelNative* swapChainPanelNative = NULL;
  131. if (FAILED(nativeWindow->QueryInterface(__uuidof(T), (void**)&swapChainPanelNative) )
  132. || NULL == swapChainPanelNative)
  133. {
  134. return false;
  135. }
  136. *hr = swapChainPanelNative->SetSwapChain(swapChain);
  137. if (SUCCEEDED(*hr) )
  138. {
  139. DX_RELEASE_I(swapChainPanelNative);
  140. }
  141. else
  142. {
  143. DX_RELEASE(swapChainPanelNative, 0);
  144. }
  145. return true;
  146. }
  147. static HRESULT setSwapChain(IInspectable* nativeWindow, Dxgi::SwapChainI* swapChain)
  148. {
  149. HRESULT hr = S_OK;
  150. if (NULL == nativeWindow)
  151. {
  152. return hr;
  153. }
  154. if (trySetSwapChain<ISwapChainPanelNative>(nativeWindow, swapChain, &hr)
  155. || trySetSwapChain<ISwapChainBackgroundPanelNative>(nativeWindow, swapChain, &hr)
  156. || trySetSwapChain<WinUI3::ISwapChainPanelNative>(nativeWindow, swapChain, &hr)
  157. || trySetSwapChain<WinUI3::ISwapChainBackgroundPanelNative>(nativeWindow, swapChain, &hr))
  158. {
  159. if (FAILED(hr))
  160. {
  161. BX_TRACE("Failed to SetSwapChain, hr %x.");
  162. }
  163. }
  164. else
  165. {
  166. BX_TRACE("No available interface on native window to SetSwapChain.");
  167. }
  168. return hr;
  169. }
  170. #endif // BX_PLATFORM_WINRT
  171. DxgiSwapChain::DxgiSwapChain()
  172. {
  173. }
  174. Dxgi::Dxgi()
  175. : m_dxgiDll(NULL)
  176. , m_dxgiDebugDll(NULL)
  177. , m_driverType(D3D_DRIVER_TYPE_NULL)
  178. , m_factory(NULL)
  179. , m_adapter(NULL)
  180. , m_output(NULL)
  181. , m_tearingSupported(false)
  182. {
  183. }
  184. bool Dxgi::init(Caps& _caps)
  185. {
  186. #if BX_PLATFORM_LINUX || BX_PLATFORM_WINDOWS
  187. const char* dxgiDllName =
  188. #if BX_PLATFORM_LINUX
  189. "dxgi.so"
  190. #else
  191. "dxgi.dll"
  192. #endif // BX_PLATFORM_LINUX
  193. ;
  194. m_dxgiDll = bx::dlopen(dxgiDllName);
  195. if (NULL == m_dxgiDll)
  196. {
  197. BX_TRACE("Init error: Failed to load %s.", dxgiDllName);
  198. return false;
  199. }
  200. # if BX_PLATFORM_WINDOWS
  201. m_dxgiDebugDll = bx::dlopen("dxgidebug.dll");
  202. if (NULL != m_dxgiDebugDll)
  203. {
  204. DXGIGetDebugInterface = (PFN_GET_DEBUG_INTERFACE )bx::dlsym(m_dxgiDebugDll, "DXGIGetDebugInterface");
  205. DXGIGetDebugInterface1 = (PFN_GET_DEBUG_INTERFACE1)bx::dlsym(m_dxgiDebugDll, "DXGIGetDebugInterface1");
  206. if (NULL == DXGIGetDebugInterface
  207. && NULL == DXGIGetDebugInterface1)
  208. {
  209. bx::dlclose(m_dxgiDebugDll);
  210. m_dxgiDebugDll = NULL;
  211. }
  212. }
  213. CreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY)bx::dlsym(m_dxgiDll, "CreateDXGIFactory1");
  214. if (NULL == CreateDXGIFactory)
  215. {
  216. CreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY)bx::dlsym(m_dxgiDll, "CreateDXGIFactory");
  217. }
  218. if (NULL == CreateDXGIFactory)
  219. {
  220. BX_TRACE("Init error: Function CreateDXGIFactory not found.");
  221. return false;
  222. }
  223. # endif // BX_PLATFORM_WINDOWS
  224. #endif // BX_PLATFORM_WINDOWS
  225. HRESULT hr = S_OK;
  226. #if BX_PLATFORM_WINRT
  227. // WinRT requires the IDXGIFactory2 interface, which isn't supported on older platforms
  228. hr = CreateDXGIFactory1(IID_IDXGIFactory2, (void**)&m_factory);
  229. #elif BX_PLATFORM_WINDOWS
  230. hr = CreateDXGIFactory(IID_IDXGIFactory, (void**)&m_factory);
  231. #endif // BX_PLATFORM_*
  232. if (FAILED(hr))
  233. {
  234. BX_TRACE("Init error: Unable to create DXGI factory.");
  235. return false;
  236. }
  237. m_driverType = BGFX_PCI_ID_SOFTWARE_RASTERIZER == _caps.vendorId
  238. ? D3D_DRIVER_TYPE_WARP
  239. : D3D_DRIVER_TYPE_HARDWARE
  240. ;
  241. if (NULL != m_factory)
  242. {
  243. AdapterI* adapter;
  244. for (uint32_t ii = 0
  245. ; ii < BX_COUNTOF(_caps.gpu) && DXGI_ERROR_NOT_FOUND != m_factory->EnumAdapters(ii, reinterpret_cast<IDXGIAdapter**>(&adapter) )
  246. ; ++ii
  247. )
  248. {
  249. {
  250. DXGI_ADAPTER_DESC desc;
  251. hr = adapter->GetDesc(&desc);
  252. if (SUCCEEDED(hr) )
  253. {
  254. BX_TRACE("Adapter #%d", ii);
  255. char description[BX_COUNTOF(desc.Description)];
  256. wcstombs(description, desc.Description, BX_COUNTOF(desc.Description) );
  257. BX_TRACE("\tDescription: %s", description);
  258. BX_TRACE("\tVendorId: 0x%08x, DeviceId: 0x%08x, SubSysId: 0x%08x, Revision: 0x%08x"
  259. , desc.VendorId
  260. , desc.DeviceId
  261. , desc.SubSysId
  262. , desc.Revision
  263. );
  264. char dedicatedVideo[16];
  265. bx::prettify(dedicatedVideo, BX_COUNTOF(dedicatedVideo), desc.DedicatedVideoMemory);
  266. char dedicatedSystem[16];
  267. bx::prettify(dedicatedSystem, BX_COUNTOF(dedicatedSystem), desc.DedicatedSystemMemory);
  268. char sharedSystem[16];
  269. bx::prettify(sharedSystem, BX_COUNTOF(sharedSystem), desc.SharedSystemMemory);
  270. BX_TRACE("\tMemory: %s (video), %s (system), %s (shared)"
  271. , dedicatedVideo
  272. , dedicatedSystem
  273. , sharedSystem
  274. );
  275. _caps.gpu[ii].vendorId = (uint16_t)desc.VendorId;
  276. _caps.gpu[ii].deviceId = (uint16_t)desc.DeviceId;
  277. ++_caps.numGPUs;
  278. if (NULL == m_adapter)
  279. {
  280. if ( (BGFX_PCI_ID_NONE != _caps.vendorId || 0 != _caps.deviceId)
  281. && (BGFX_PCI_ID_NONE == _caps.vendorId || desc.VendorId == _caps.vendorId)
  282. && ( 0 == _caps.deviceId || desc.DeviceId == _caps.deviceId) )
  283. {
  284. m_adapter = adapter;
  285. m_adapter->AddRef();
  286. m_driverType = D3D_DRIVER_TYPE_UNKNOWN;
  287. }
  288. if (BX_ENABLED(BGFX_CONFIG_DEBUG_PERFHUD)
  289. && !bx::strFind(description, "PerfHUD").isEmpty() )
  290. {
  291. m_adapter = adapter;
  292. m_driverType = D3D_DRIVER_TYPE_REFERENCE;
  293. }
  294. }
  295. }
  296. }
  297. bool hdr10 = false;
  298. IDXGIOutput* output;
  299. for (uint32_t jj = 0
  300. ; SUCCEEDED(adapter->EnumOutputs(jj, &output) )
  301. ; ++jj
  302. )
  303. {
  304. DXGI_OUTPUT_DESC outputDesc;
  305. hr = output->GetDesc(&outputDesc);
  306. if (SUCCEEDED(hr) )
  307. {
  308. BX_TRACE("\tOutput #%d", jj);
  309. char deviceName[BX_COUNTOF(outputDesc.DeviceName)];
  310. wcstombs(deviceName, outputDesc.DeviceName, BX_COUNTOF(outputDesc.DeviceName) );
  311. BX_TRACE("\t\t DeviceName: %s", deviceName);
  312. BX_TRACE("\t\t DesktopCoordinates: %d, %d, %d, %d"
  313. , outputDesc.DesktopCoordinates.left
  314. , outputDesc.DesktopCoordinates.top
  315. , outputDesc.DesktopCoordinates.right
  316. , outputDesc.DesktopCoordinates.bottom
  317. );
  318. BX_TRACE("\t\t AttachedToDesktop: %d", outputDesc.AttachedToDesktop);
  319. BX_TRACE("\t\t Rotation: %d", outputDesc.Rotation);
  320. #if BX_PLATFORM_LINUX || BX_PLATFORM_WINDOWS
  321. IDXGIOutput6* output6;
  322. hr = output->QueryInterface(IID_IDXGIOutput6, (void**)&output6);
  323. if (SUCCEEDED(hr) )
  324. {
  325. DXGI_OUTPUT_DESC1 desc;
  326. hr = output6->GetDesc1(&desc);
  327. if (SUCCEEDED(hr) )
  328. {
  329. BX_TRACE("\t\t BitsPerColor: %d", desc.BitsPerColor);
  330. BX_TRACE("\t\t Color space: %s (colorspace, range, gamma, sitting, primaries, transform)"
  331. , s_colorSpaceStr[bx::min<uint32_t>(desc.ColorSpace, kDxgiLastColorSpace+1)]
  332. );
  333. BX_TRACE("\t\t RedPrimary: %f, %f", desc.RedPrimary[0], desc.RedPrimary[1]);
  334. BX_TRACE("\t\t GreenPrimary: %f, %f", desc.GreenPrimary[0], desc.GreenPrimary[1]);
  335. BX_TRACE("\t\t BluePrimary: %f, %f", desc.BluePrimary[0], desc.BluePrimary[1]);
  336. BX_TRACE("\t\t WhitePoint: %f, %f", desc.WhitePoint[0], desc.WhitePoint[1]);
  337. BX_TRACE("\t\t MinLuminance: %f", desc.MinLuminance);
  338. BX_TRACE("\t\t MaxLuminance: %f", desc.MaxLuminance);
  339. BX_TRACE("\t\tMaxFullFrameLuminance: %f", desc.MaxFullFrameLuminance);
  340. BX_TRACE("\t\t HDR support: %s", DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 == desc.ColorSpace ? "true" : "false");
  341. hdr10 |= DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 == desc.ColorSpace;
  342. }
  343. // BK - warn only because RenderDoc might be present.
  344. DX_RELEASE_W(output6, 1);
  345. }
  346. #endif // BX_PLATFORM_WINDOWS
  347. DX_RELEASE(output, 0);
  348. }
  349. }
  350. _caps.supported |= hdr10 ? BGFX_CAPS_HDR10 : 0;
  351. _caps.supported |= BX_ENABLED(BX_PLATFORM_WINRT) ? BGFX_CAPS_TRANSPARENT_BACKBUFFER : 0;
  352. DX_RELEASE(adapter, adapter == m_adapter ? 1 : 0);
  353. }
  354. if (NULL == m_adapter)
  355. {
  356. hr = m_factory->EnumAdapters(0, reinterpret_cast<IDXGIAdapter**>(&m_adapter) );
  357. BX_WARN(SUCCEEDED(hr), "EnumAdapters failed 0x%08x.", hr);
  358. m_driverType = D3D_DRIVER_TYPE_UNKNOWN;
  359. }
  360. bx::memSet(&m_adapterDesc, 0, sizeof(m_adapterDesc) );
  361. hr = m_adapter->GetDesc(&m_adapterDesc);
  362. BX_WARN(SUCCEEDED(hr), "Adapter GetDesc failed 0x%08x.", hr);
  363. m_adapter->EnumOutputs(0, &m_output);
  364. _caps.vendorId = 0 == m_adapterDesc.VendorId
  365. ? BGFX_PCI_ID_SOFTWARE_RASTERIZER
  366. : (uint16_t)m_adapterDesc.VendorId
  367. ;
  368. _caps.deviceId = (uint16_t)m_adapterDesc.DeviceId;
  369. }
  370. return true;
  371. }
  372. void Dxgi::shutdown()
  373. {
  374. DX_RELEASE(m_output, 0);
  375. DX_RELEASE(m_adapter, 0);
  376. DX_RELEASE(m_factory, 0);
  377. bx::dlclose(m_dxgiDebugDll);
  378. m_dxgiDebugDll = NULL;
  379. bx::dlclose(m_dxgiDll);
  380. m_dxgiDll = NULL;
  381. }
  382. void Dxgi::update(IUnknown* _device)
  383. {
  384. IDXGIDevice* dxgiDevice = NULL;
  385. HRESULT hr = E_FAIL;
  386. for (uint32_t ii = 0; ii < BX_COUNTOF(s_dxgiDeviceIIDs) && FAILED(hr); ++ii)
  387. {
  388. hr = _device->QueryInterface(s_dxgiDeviceIIDs[ii], (void**)&dxgiDevice);
  389. BX_TRACE("DXGI device 11.%d, hr %x", BX_COUNTOF(s_dxgiDeviceIIDs) - 1 - ii, hr);
  390. }
  391. if (NULL == m_factory)
  392. {
  393. DX_CHECK(dxgiDevice->GetAdapter(reinterpret_cast<IDXGIAdapter**>(&m_adapter) ) );
  394. bx::memSet(&m_adapterDesc, 0, sizeof(m_adapterDesc) );
  395. hr = m_adapter->GetDesc(&m_adapterDesc);
  396. BX_WARN(SUCCEEDED(hr), "Adapter GetDesc failed 0x%08x.", hr);
  397. DX_CHECK(m_adapter->GetParent(IID_IDXGIFactory2, (void**)&m_factory) );
  398. }
  399. DX_RELEASE_I(dxgiDevice);
  400. }
  401. HRESULT Dxgi::createSwapChain(IUnknown* _device, const SwapChainDesc& _scd, SwapChainI** _swapChain)
  402. {
  403. HRESULT hr = S_OK;
  404. uint32_t scdFlags = _scd.flags;
  405. #if BX_PLATFORM_LINUX || BX_PLATFORM_WINDOWS
  406. IDXGIFactory5* factory5;
  407. hr = m_factory->QueryInterface(IID_IDXGIFactory5, (void**)&factory5);
  408. if (SUCCEEDED(hr) )
  409. {
  410. BOOL allowTearing = false;
  411. // BK - CheckFeatureSupport with DXGI_FEATURE_PRESENT_ALLOW_TEARING
  412. // will crash on pre Windows 8. Issue #1356.
  413. hr = factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing) );
  414. BX_TRACE("Allow tearing is %ssupported.", allowTearing ? "" : "not ");
  415. scdFlags |= allowTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
  416. scdFlags |= false
  417. || _scd.swapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
  418. || _scd.swapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD
  419. ? 0 // DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
  420. : 0
  421. ;
  422. m_tearingSupported = allowTearing;
  423. DX_RELEASE_I(factory5);
  424. }
  425. DXGI_SWAP_CHAIN_DESC scd;
  426. scd.BufferDesc.Width = _scd.width;
  427. scd.BufferDesc.Height = _scd.height;
  428. scd.BufferDesc.RefreshRate.Numerator = 1;
  429. scd.BufferDesc.RefreshRate.Denominator = 60;
  430. scd.BufferDesc.Format = _scd.format;
  431. scd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
  432. scd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
  433. scd.SampleDesc.Count = 1;
  434. scd.SampleDesc.Quality = 0;
  435. scd.BufferUsage = _scd.bufferUsage;
  436. scd.BufferCount = _scd.bufferCount;
  437. scd.OutputWindow = (HWND)_scd.nwh;
  438. scd.Windowed = _scd.windowed;
  439. scd.SwapEffect = _scd.swapEffect;
  440. scd.Flags = scdFlags;
  441. hr = m_factory->CreateSwapChain(
  442. _device
  443. , &scd
  444. , reinterpret_cast<IDXGISwapChain**>(_swapChain)
  445. );
  446. #else
  447. DXGI_SWAP_CHAIN_DESC1 scd;
  448. scd.Width = _scd.width;
  449. scd.Height = _scd.height;
  450. scd.Format = _scd.format;
  451. scd.Stereo = _scd.stereo;
  452. scd.SampleDesc.Count = 1;
  453. scd.SampleDesc.Quality = 0;
  454. scd.BufferUsage = _scd.bufferUsage;
  455. scd.BufferCount = _scd.bufferCount;
  456. scd.Scaling = _scd.scaling;
  457. scd.SwapEffect = _scd.swapEffect;
  458. scd.AlphaMode = _scd.alphaMode;
  459. scd.Flags = scdFlags;
  460. if (NULL == _scd.ndt)
  461. {
  462. hr = m_factory->CreateSwapChainForCoreWindow(
  463. _device
  464. , (::IUnknown*)_scd.nwh
  465. , &scd
  466. , NULL
  467. , reinterpret_cast<IDXGISwapChain1**>(_swapChain)
  468. );
  469. }
  470. else if (reinterpret_cast<void*>(1) == _scd.ndt)
  471. {
  472. return E_FAIL;
  473. }
  474. else
  475. {
  476. hr = m_factory->CreateSwapChainForComposition(
  477. _device
  478. , &scd
  479. , NULL
  480. , reinterpret_cast<IDXGISwapChain1**>(_swapChain)
  481. );
  482. if (FAILED(hr))
  483. {
  484. return hr;
  485. }
  486. # if BX_PLATFORM_WINRT
  487. IInspectable* nativeWindow = reinterpret_cast<IInspectable*>(_scd.nwh);
  488. hr = setSwapChain(nativeWindow, *_swapChain);
  489. if (FAILED(hr) )
  490. {
  491. return hr;
  492. }
  493. # endif // BX_PLATFORM_WINRT
  494. }
  495. #endif // BX_PLATFORM_WINDOWS
  496. if (SUCCEEDED(hr) )
  497. {
  498. IDXGIDevice1* dxgiDevice1;
  499. _device->QueryInterface(IID_IDXGIDevice1, (void**)&dxgiDevice1);
  500. if (NULL != dxgiDevice1)
  501. {
  502. hr = dxgiDevice1->SetMaximumFrameLatency(_scd.maxFrameLatency);
  503. if (FAILED(hr))
  504. {
  505. BX_TRACE("Failed to set maximum frame latency, hr 0x%08x", hr);
  506. hr = S_OK;
  507. }
  508. DX_RELEASE_I(dxgiDevice1);
  509. }
  510. }
  511. if (FAILED(hr))
  512. {
  513. BX_TRACE("Failed to create swap chain.");
  514. return hr;
  515. }
  516. #if BX_PLATFORM_LINUX || BX_PLATFORM_WINDOWS
  517. if (SUCCEEDED(hr) )
  518. {
  519. for (uint32_t ii = 0; ii < BX_COUNTOF(s_dxgiSwapChainIIDs); ++ii)
  520. {
  521. IDXGISwapChain1* swapChain;
  522. hr = (*_swapChain)->QueryInterface(s_dxgiSwapChainIIDs[ii], (void**)&swapChain);
  523. BX_TRACE("DXGI swap chain %d, hr %x", 4-ii, hr);
  524. if (SUCCEEDED(hr) )
  525. {
  526. DX_RELEASE(*_swapChain, 1);
  527. *_swapChain = reinterpret_cast<SwapChainI*>(swapChain);
  528. BX_TRACE("Color space support:");
  529. for (uint32_t jj = 0; jj < BX_COUNTOF(s_colorSpace); ++jj)
  530. {
  531. uint32_t colorSpaceSupport;
  532. reinterpret_cast<IDXGISwapChain3*>(*_swapChain)->CheckColorSpaceSupport(s_colorSpace[jj], &colorSpaceSupport);
  533. BX_TRACE("\t%2d: \"%-20s\", 0x%08x, %s"
  534. , s_colorSpace[jj]
  535. , s_colorSpaceStr[s_colorSpace[jj]]
  536. , colorSpaceSupport
  537. , 0 != (colorSpaceSupport & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)
  538. ? "supported"
  539. : "-"
  540. );
  541. }
  542. break;
  543. }
  544. }
  545. }
  546. #endif // BX_PLATFORM_LINUX || BX_PLATFORM_WINDOWS
  547. updateHdr10(*_swapChain, _scd);
  548. return S_OK;
  549. }
  550. #if BX_PLATFORM_WINRT
  551. HRESULT Dxgi::removeSwapChain(const SwapChainDesc& _scd)
  552. {
  553. IInspectable* nativeWindow = reinterpret_cast<IInspectable*>(_scd.nwh);
  554. return setSwapChain(nativeWindow, NULL);
  555. }
  556. #endif // BX_PLATFORM_WINRT
  557. void Dxgi::updateHdr10(SwapChainI* _swapChain, const SwapChainDesc& _scd)
  558. {
  559. #if BX_PLATFORM_WINDOWS
  560. ::IDXGISwapChain4* swapChain4;
  561. HRESULT hr = _swapChain->QueryInterface(IID_IDXGISwapChain4, (void**)&swapChain4);
  562. if (SUCCEEDED(hr) )
  563. {
  564. const DXGI_COLOR_SPACE_TYPE colorSpace =
  565. _scd.format == DXGI_FORMAT_R10G10B10A2_UNORM ? DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020
  566. : _scd.format == DXGI_FORMAT_R16G16B16A16_FLOAT ? DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709
  567. : DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709
  568. ;
  569. hr = swapChain4->SetColorSpace1(colorSpace);
  570. if (SUCCEEDED(hr) )
  571. {
  572. DXGI_OUTPUT_DESC1 desc;
  573. IDXGIOutput* output;
  574. hr = _swapChain->GetContainingOutput(&output);
  575. if (SUCCEEDED(hr) )
  576. {
  577. IDXGIOutput6* output6;
  578. hr = output->QueryInterface(IID_IDXGIOutput6, (void**)&output6);
  579. if (SUCCEEDED(hr) )
  580. {
  581. hr = output6->GetDesc1(&desc);
  582. if (SUCCEEDED(hr) )
  583. {
  584. BX_TRACE("Display specs:");
  585. BX_TRACE("\t BitsPerColor: %d", desc.BitsPerColor);
  586. BX_TRACE("\t Color space: %s (colorspace, range, gamma, sitting, primaries, transform)"
  587. , s_colorSpaceStr[bx::min<uint32_t>(desc.ColorSpace, kDxgiLastColorSpace+1)]
  588. );
  589. BX_TRACE("\t RedPrimary: %f, %f", desc.RedPrimary[0], desc.RedPrimary[1]);
  590. BX_TRACE("\t GreenPrimary: %f, %f", desc.GreenPrimary[0], desc.GreenPrimary[1]);
  591. BX_TRACE("\t BluePrimary: %f, %f", desc.BluePrimary[0], desc.BluePrimary[1]);
  592. BX_TRACE("\t WhitePoint: %f, %f", desc.WhitePoint[0], desc.WhitePoint[1]);
  593. BX_TRACE("\t MinLuminance: %f", desc.MinLuminance);
  594. BX_TRACE("\t MaxLuminance: %f", desc.MaxLuminance);
  595. BX_TRACE("\tMaxFullFrameLuminance: %f", desc.MaxFullFrameLuminance);
  596. }
  597. DX_RELEASE(output6, 1);
  598. }
  599. DX_RELEASE(output, 0);
  600. }
  601. DXGI_HDR_METADATA_HDR10 hdr10;
  602. hdr10.RedPrimary[0] = uint16_t(desc.RedPrimary[0] * 50000.0f);
  603. hdr10.RedPrimary[1] = uint16_t(desc.RedPrimary[1] * 50000.0f);
  604. hdr10.GreenPrimary[0] = uint16_t(desc.GreenPrimary[0] * 50000.0f);
  605. hdr10.GreenPrimary[1] = uint16_t(desc.GreenPrimary[1] * 50000.0f);
  606. hdr10.BluePrimary[0] = uint16_t(desc.BluePrimary[0] * 50000.0f);
  607. hdr10.BluePrimary[1] = uint16_t(desc.BluePrimary[1] * 50000.0f);
  608. hdr10.WhitePoint[0] = uint16_t(desc.WhitePoint[0] * 50000.0f);
  609. hdr10.WhitePoint[1] = uint16_t(desc.WhitePoint[1] * 50000.0f);
  610. hdr10.MaxMasteringLuminance = uint32_t(desc.MaxLuminance * 10000.0f);
  611. hdr10.MinMasteringLuminance = uint32_t(desc.MinLuminance * 10000.0f);
  612. hdr10.MaxContentLightLevel = uint16_t(desc.MaxFullFrameLuminance);
  613. hdr10.MaxFrameAverageLightLevel = uint16_t(desc.MaxFullFrameLuminance);
  614. hr = swapChain4->SetHDRMetaData(DXGI_HDR_METADATA_TYPE_HDR10, sizeof(DXGI_HDR_METADATA_HDR10), &hdr10);
  615. }
  616. DX_RELEASE(swapChain4, 1);
  617. }
  618. #else
  619. BX_UNUSED(_swapChain, _scd);
  620. #endif // BX_PLATFORM_WINDOWS
  621. }
  622. HRESULT Dxgi::resizeBuffers(SwapChainI* _swapChain, const SwapChainDesc& _scd, const uint32_t* _nodeMask, IUnknown* const* _presentQueue)
  623. {
  624. HRESULT hr;
  625. uint32_t scdFlags = _scd.flags;
  626. #if BX_PLATFORM_LINUX || BX_PLATFORM_WINDOWS
  627. IDXGIFactory5* factory5;
  628. hr = m_factory->QueryInterface(IID_IDXGIFactory5, (void**)&factory5);
  629. if (SUCCEEDED(hr))
  630. {
  631. BOOL allowTearing = false;
  632. // BK - CheckFeatureSupport with DXGI_FEATURE_PRESENT_ALLOW_TEARING
  633. // will crash on pre Windows 8. Issue #1356.
  634. hr = factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing));
  635. BX_TRACE("Allow tearing is %ssupported.", allowTearing ? "" : "not ");
  636. scdFlags |= allowTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
  637. scdFlags |= false
  638. || _scd.swapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
  639. || _scd.swapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD
  640. ? 0 // DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
  641. : 0
  642. ;
  643. DX_RELEASE_I(factory5);
  644. }
  645. if (NULL != _nodeMask
  646. && NULL != _presentQueue)
  647. {
  648. hr = _swapChain->ResizeBuffers1(
  649. _scd.bufferCount
  650. , _scd.width
  651. , _scd.height
  652. , _scd.format
  653. , scdFlags
  654. , _nodeMask
  655. , _presentQueue
  656. );
  657. }
  658. else
  659. #endif // BX_PLATFORM_WINDOWS
  660. {
  661. BX_UNUSED(_nodeMask, _presentQueue);
  662. hr = _swapChain->ResizeBuffers(
  663. _scd.bufferCount
  664. , _scd.width
  665. , _scd.height
  666. , _scd.format
  667. , scdFlags
  668. );
  669. }
  670. if (SUCCEEDED(hr) )
  671. {
  672. updateHdr10(_swapChain, _scd);
  673. }
  674. return hr;
  675. }
  676. void Dxgi::trim()
  677. {
  678. #if BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT
  679. IDXGIDevice3* device;
  680. HRESULT hr = m_factory->QueryInterface(IID_IDXGIDevice3, (void**)&device);
  681. if (SUCCEEDED(hr) )
  682. {
  683. device->Trim();
  684. DX_RELEASE(device, 1);
  685. }
  686. #endif // BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT
  687. }
  688. bool Dxgi::tearingSupported() const
  689. {
  690. return m_tearingSupported;
  691. }
  692. } // namespace bgfx
  693. #endif // BGFX_CONFIG_RENDERER_DIRECT3D11 || BGFX_CONFIG_RENDERER_DIRECT3D12