dxgi.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. /*
  2. * Copyright 2011-2025 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. 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. DXGI_SWAP_CHAIN_DESC1 scd;
  405. scd.Width = _scd.width;
  406. scd.Height = _scd.height;
  407. scd.Format = _scd.format;
  408. scd.Stereo = _scd.stereo;
  409. scd.SampleDesc.Count = 1;
  410. scd.SampleDesc.Quality = 0;
  411. scd.BufferUsage = _scd.bufferUsage;
  412. scd.BufferCount = _scd.bufferCount;
  413. scd.Scaling = _scd.scaling;
  414. scd.SwapEffect = _scd.swapEffect;
  415. scd.AlphaMode = _scd.alphaMode;
  416. scd.Flags = _scd.flags;
  417. #if BX_PLATFORM_LINUX || BX_PLATFORM_WINDOWS
  418. IDXGIFactory5* factory5;
  419. hr = m_factory->QueryInterface(IID_IDXGIFactory5, (void**)&factory5);
  420. if (SUCCEEDED(hr) )
  421. {
  422. BOOL allowTearing = false;
  423. // BK - CheckFeatureSupport with DXGI_FEATURE_PRESENT_ALLOW_TEARING
  424. // will crash on pre Windows 8. Issue #1356.
  425. hr = factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing) );
  426. BX_TRACE("Allow tearing is %ssupported.", allowTearing ? "" : "not ");
  427. scd.Flags |= allowTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
  428. scd.Flags |= false
  429. || _scd.swapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
  430. || _scd.swapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD
  431. ? 0 // DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
  432. : 0
  433. ;
  434. m_tearingSupported = allowTearing;
  435. DX_RELEASE_I(factory5);
  436. }
  437. DXGI_SWAP_CHAIN_FULLSCREEN_DESC scfd;
  438. scfd.RefreshRate.Numerator = 1;
  439. scfd.RefreshRate.Denominator = 60;
  440. scfd.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
  441. scfd.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
  442. scfd.Windowed = _scd.windowed;
  443. hr = m_factory->CreateSwapChainForHwnd(
  444. _device
  445. , (HWND)_scd.nwh
  446. , &scd
  447. , &scfd
  448. , NULL
  449. , reinterpret_cast<IDXGISwapChain1**>(_swapChain)
  450. );
  451. #else
  452. if (NULL == _scd.ndt)
  453. {
  454. hr = m_factory->CreateSwapChainForCoreWindow(
  455. _device
  456. , (::IUnknown*)_scd.nwh
  457. , &scd
  458. , NULL
  459. , reinterpret_cast<IDXGISwapChain1**>(_swapChain)
  460. );
  461. }
  462. else if (reinterpret_cast<void*>(1) == _scd.ndt)
  463. {
  464. return E_FAIL;
  465. }
  466. else
  467. {
  468. hr = m_factory->CreateSwapChainForComposition(
  469. _device
  470. , &scd
  471. , NULL
  472. , reinterpret_cast<IDXGISwapChain1**>(_swapChain)
  473. );
  474. if (FAILED(hr))
  475. {
  476. return hr;
  477. }
  478. # if BX_PLATFORM_WINRT
  479. IInspectable* nativeWindow = reinterpret_cast<IInspectable*>(_scd.nwh);
  480. hr = setSwapChain(nativeWindow, *_swapChain);
  481. if (FAILED(hr) )
  482. {
  483. return hr;
  484. }
  485. # endif // BX_PLATFORM_WINRT
  486. }
  487. #endif // BX_PLATFORM_WINDOWS
  488. if (SUCCEEDED(hr) )
  489. {
  490. IDXGIDevice1* dxgiDevice1;
  491. _device->QueryInterface(IID_IDXGIDevice1, (void**)&dxgiDevice1);
  492. if (NULL != dxgiDevice1)
  493. {
  494. hr = dxgiDevice1->SetMaximumFrameLatency(_scd.maxFrameLatency);
  495. if (FAILED(hr))
  496. {
  497. BX_TRACE("Failed to set maximum frame latency, hr 0x%08x", hr);
  498. hr = S_OK;
  499. }
  500. DX_RELEASE_I(dxgiDevice1);
  501. }
  502. }
  503. if (FAILED(hr))
  504. {
  505. BX_TRACE("Failed to create swap chain.");
  506. return hr;
  507. }
  508. #if BX_PLATFORM_LINUX || BX_PLATFORM_WINDOWS
  509. if (SUCCEEDED(hr) )
  510. {
  511. for (uint32_t ii = 0; ii < BX_COUNTOF(s_dxgiSwapChainIIDs); ++ii)
  512. {
  513. IDXGISwapChain1* swapChain;
  514. hr = (*_swapChain)->QueryInterface(s_dxgiSwapChainIIDs[ii], (void**)&swapChain);
  515. BX_TRACE("DXGI swap chain %d, hr %x", 4-ii, hr);
  516. if (SUCCEEDED(hr) )
  517. {
  518. DX_RELEASE(*_swapChain, 1);
  519. *_swapChain = reinterpret_cast<SwapChainI*>(swapChain);
  520. BX_TRACE("Color space support:");
  521. for (uint32_t jj = 0; jj < BX_COUNTOF(s_colorSpace); ++jj)
  522. {
  523. uint32_t colorSpaceSupport;
  524. reinterpret_cast<IDXGISwapChain3*>(*_swapChain)->CheckColorSpaceSupport(s_colorSpace[jj], &colorSpaceSupport);
  525. BX_TRACE("\t%2d: \"%-20s\", 0x%08x, %s"
  526. , s_colorSpace[jj]
  527. , s_colorSpaceStr[s_colorSpace[jj]]
  528. , colorSpaceSupport
  529. , 0 != (colorSpaceSupport & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)
  530. ? "supported"
  531. : "-"
  532. );
  533. }
  534. break;
  535. }
  536. }
  537. }
  538. #endif // BX_PLATFORM_LINUX || BX_PLATFORM_WINDOWS
  539. updateHdr10(*_swapChain, _scd);
  540. return S_OK;
  541. }
  542. #if BX_PLATFORM_WINRT
  543. HRESULT Dxgi::removeSwapChain(const SwapChainDesc& _scd)
  544. {
  545. IInspectable* nativeWindow = reinterpret_cast<IInspectable*>(_scd.nwh);
  546. return setSwapChain(nativeWindow, NULL);
  547. }
  548. #endif // BX_PLATFORM_WINRT
  549. void Dxgi::updateHdr10(SwapChainI* _swapChain, const SwapChainDesc& _scd)
  550. {
  551. #if BX_PLATFORM_WINDOWS
  552. ::IDXGISwapChain4* swapChain4;
  553. HRESULT hr = _swapChain->QueryInterface(IID_IDXGISwapChain4, (void**)&swapChain4);
  554. if (SUCCEEDED(hr) )
  555. {
  556. const DXGI_COLOR_SPACE_TYPE colorSpace =
  557. _scd.format == DXGI_FORMAT_R10G10B10A2_UNORM ? DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020
  558. : _scd.format == DXGI_FORMAT_R16G16B16A16_FLOAT ? DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709
  559. : DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709
  560. ;
  561. hr = swapChain4->SetColorSpace1(colorSpace);
  562. if (SUCCEEDED(hr) )
  563. {
  564. DXGI_OUTPUT_DESC1 desc;
  565. IDXGIOutput* output;
  566. hr = _swapChain->GetContainingOutput(&output);
  567. if (SUCCEEDED(hr) )
  568. {
  569. IDXGIOutput6* output6;
  570. hr = output->QueryInterface(IID_IDXGIOutput6, (void**)&output6);
  571. if (SUCCEEDED(hr) )
  572. {
  573. hr = output6->GetDesc1(&desc);
  574. if (SUCCEEDED(hr) )
  575. {
  576. BX_TRACE("Display specs:");
  577. BX_TRACE("\t BitsPerColor: %d", desc.BitsPerColor);
  578. BX_TRACE("\t Color space: %s (colorspace, range, gamma, sitting, primaries, transform)"
  579. , s_colorSpaceStr[bx::min<uint32_t>(desc.ColorSpace, kDxgiLastColorSpace+1)]
  580. );
  581. BX_TRACE("\t RedPrimary: %f, %f", desc.RedPrimary[0], desc.RedPrimary[1]);
  582. BX_TRACE("\t GreenPrimary: %f, %f", desc.GreenPrimary[0], desc.GreenPrimary[1]);
  583. BX_TRACE("\t BluePrimary: %f, %f", desc.BluePrimary[0], desc.BluePrimary[1]);
  584. BX_TRACE("\t WhitePoint: %f, %f", desc.WhitePoint[0], desc.WhitePoint[1]);
  585. BX_TRACE("\t MinLuminance: %f", desc.MinLuminance);
  586. BX_TRACE("\t MaxLuminance: %f", desc.MaxLuminance);
  587. BX_TRACE("\tMaxFullFrameLuminance: %f", desc.MaxFullFrameLuminance);
  588. }
  589. DX_RELEASE(output6, 1);
  590. }
  591. DX_RELEASE(output, 0);
  592. }
  593. DXGI_HDR_METADATA_HDR10 hdr10;
  594. hdr10.RedPrimary[0] = uint16_t(desc.RedPrimary[0] * 50000.0f);
  595. hdr10.RedPrimary[1] = uint16_t(desc.RedPrimary[1] * 50000.0f);
  596. hdr10.GreenPrimary[0] = uint16_t(desc.GreenPrimary[0] * 50000.0f);
  597. hdr10.GreenPrimary[1] = uint16_t(desc.GreenPrimary[1] * 50000.0f);
  598. hdr10.BluePrimary[0] = uint16_t(desc.BluePrimary[0] * 50000.0f);
  599. hdr10.BluePrimary[1] = uint16_t(desc.BluePrimary[1] * 50000.0f);
  600. hdr10.WhitePoint[0] = uint16_t(desc.WhitePoint[0] * 50000.0f);
  601. hdr10.WhitePoint[1] = uint16_t(desc.WhitePoint[1] * 50000.0f);
  602. hdr10.MaxMasteringLuminance = uint32_t(desc.MaxLuminance * 10000.0f);
  603. hdr10.MinMasteringLuminance = uint32_t(desc.MinLuminance * 10000.0f);
  604. hdr10.MaxContentLightLevel = uint16_t(desc.MaxFullFrameLuminance);
  605. hdr10.MaxFrameAverageLightLevel = uint16_t(desc.MaxFullFrameLuminance);
  606. hr = swapChain4->SetHDRMetaData(DXGI_HDR_METADATA_TYPE_HDR10, sizeof(DXGI_HDR_METADATA_HDR10), &hdr10);
  607. }
  608. DX_RELEASE(swapChain4, 1);
  609. }
  610. #else
  611. BX_UNUSED(_swapChain, _scd);
  612. #endif // BX_PLATFORM_WINDOWS
  613. }
  614. HRESULT Dxgi::resizeBuffers(SwapChainI* _swapChain, const SwapChainDesc& _scd, const uint32_t* _nodeMask, IUnknown* const* _presentQueue)
  615. {
  616. HRESULT hr;
  617. uint32_t scdFlags = _scd.flags;
  618. #if BX_PLATFORM_LINUX || BX_PLATFORM_WINDOWS
  619. IDXGIFactory5* factory5;
  620. hr = m_factory->QueryInterface(IID_IDXGIFactory5, (void**)&factory5);
  621. if (SUCCEEDED(hr))
  622. {
  623. BOOL allowTearing = false;
  624. // BK - CheckFeatureSupport with DXGI_FEATURE_PRESENT_ALLOW_TEARING
  625. // will crash on pre Windows 8. Issue #1356.
  626. hr = factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing));
  627. BX_TRACE("Allow tearing is %ssupported.", allowTearing ? "" : "not ");
  628. scdFlags |= allowTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
  629. scdFlags |= false
  630. || _scd.swapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
  631. || _scd.swapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD
  632. ? 0 // DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
  633. : 0
  634. ;
  635. DX_RELEASE_I(factory5);
  636. }
  637. if (NULL != _nodeMask
  638. && NULL != _presentQueue)
  639. {
  640. hr = _swapChain->ResizeBuffers1(
  641. _scd.bufferCount
  642. , _scd.width
  643. , _scd.height
  644. , _scd.format
  645. , scdFlags
  646. , _nodeMask
  647. , _presentQueue
  648. );
  649. }
  650. else
  651. #endif // BX_PLATFORM_WINDOWS
  652. {
  653. BX_UNUSED(_nodeMask, _presentQueue);
  654. hr = _swapChain->ResizeBuffers(
  655. _scd.bufferCount
  656. , _scd.width
  657. , _scd.height
  658. , _scd.format
  659. , scdFlags
  660. );
  661. }
  662. if (SUCCEEDED(hr) )
  663. {
  664. updateHdr10(_swapChain, _scd);
  665. }
  666. return hr;
  667. }
  668. void Dxgi::trim()
  669. {
  670. #if BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT
  671. IDXGIDevice3* device;
  672. HRESULT hr = m_factory->QueryInterface(IID_IDXGIDevice3, (void**)&device);
  673. if (SUCCEEDED(hr) )
  674. {
  675. device->Trim();
  676. DX_RELEASE(device, 1);
  677. }
  678. #endif // BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT
  679. }
  680. bool Dxgi::tearingSupported() const
  681. {
  682. return m_tearingSupported;
  683. }
  684. } // namespace bgfx
  685. #endif // BGFX_CONFIG_RENDERER_DIRECT3D11 || BGFX_CONFIG_RENDERER_DIRECT3D12