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