diff options
Diffstat (limited to 'gfx/thebes/DeviceManagerDx.cpp')
-rw-r--r-- | gfx/thebes/DeviceManagerDx.cpp | 155 |
1 files changed, 105 insertions, 50 deletions
diff --git a/gfx/thebes/DeviceManagerDx.cpp b/gfx/thebes/DeviceManagerDx.cpp index ba473e0d1e..7d00e5ac1d 100644 --- a/gfx/thebes/DeviceManagerDx.cpp +++ b/gfx/thebes/DeviceManagerDx.cpp @@ -234,17 +234,47 @@ void DeviceManagerDx::PostUpdateMonitorInfo() { holder->GetCompositorThread()->DelayedDispatch(runnable.forget(), kDelayMS); } +static bool ColorSpaceIsHDR(const DXGI_OUTPUT_DESC1& aDesc) { + // Set isHDR to true if the output has a BT2020 colorspace with EOTF2084 + // gamma curve, this indicates the system is sending an HDR format to + // this monitor. The colorspace returned by DXGI is very vague - we only + // see DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 for HDR and + // DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 for SDR modes, even if the + // monitor is using something like YCbCr444 according to Settings + // (System -> Display Settings -> Advanced Display). To get more specific + // info we would need to query the DISPLAYCONFIG values in WinGDI. + // + // Note that we don't check bit depth here, since as of Windows 11 22H2, + // HDR is supported with 8bpc for lower bandwidth, where DWM converts to + // dithered RGB8 rather than RGB10, which doesn't really matter here. + // + // Since RefreshScreens(), the caller of this function, is triggered + // by WM_DISPLAYCHANGE, this will pick up changes to the monitors in + // all the important cases (resolution/color changes by the user). + // + // Further reading: + // https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range + // https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-displayconfig_sdr_white_level + bool isHDR = (aDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020); + + return isHDR; +} + void DeviceManagerDx::UpdateMonitorInfo() { bool systemHdrEnabled = false; + std::set<HMONITOR> hdrMonitors; for (const auto& desc : GetOutputDescs()) { - if (desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) { + if (ColorSpaceIsHDR(desc)) { systemHdrEnabled = true; + hdrMonitors.emplace(desc.Monitor); } } + { MutexAutoLock lock(mDeviceLock); mSystemHdrEnabled = Some(systemHdrEnabled); + mHdrMonitors.swap(hdrMonitors); mUpdateMonitorInfoRunnable = nullptr; } } @@ -329,6 +359,42 @@ bool DeviceManagerDx::SystemHDREnabled() { return mSystemHdrEnabled.ref(); } +bool DeviceManagerDx::WindowHDREnabled(HWND aWindow) { + MOZ_ASSERT(aWindow); + + HMONITOR monitor = ::MonitorFromWindow(aWindow, MONITOR_DEFAULTTONEAREST); + return MonitorHDREnabled(monitor); +} + +bool DeviceManagerDx::MonitorHDREnabled(HMONITOR aMonitor) { + if (!aMonitor) { + return false; + } + + bool needInit = false; + + { + MutexAutoLock lock(mDeviceLock); + if (mSystemHdrEnabled.isNothing()) { + needInit = true; + } + } + + if (needInit) { + UpdateMonitorInfo(); + } + + MutexAutoLock lock(mDeviceLock); + MOZ_ASSERT(mSystemHdrEnabled.isSome()); + + auto it = mHdrMonitors.find(aMonitor); + if (it == mHdrMonitors.end()) { + return false; + } + + return true; +} + void DeviceManagerDx::CheckHardwareStretchingSupport(HwStretchingSupport& aRv) { RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter(); @@ -651,9 +717,11 @@ already_AddRefed<IDXGIAdapter1> DeviceManagerDx::GetDXGIAdapter() { } IDXGIAdapter1* DeviceManagerDx::GetDXGIAdapterLocked() { - if (mAdapter) { + if (mAdapter && mFactory && mFactory->IsCurrent()) { return mAdapter; } + mAdapter = nullptr; + mFactory = nullptr; nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll")); decltype(CreateDXGIFactory1)* createDXGIFactory1 = @@ -668,50 +736,32 @@ IDXGIAdapter1* DeviceManagerDx::GetDXGIAdapterLocked() { // Try to use a DXGI 1.1 adapter in order to share resources // across processes. - RefPtr<IDXGIFactory1> factory1; if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup()) { - RefPtr<IDXGIFactory2> factory2; if (fCreateDXGIFactory2) { auto hr = fCreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG, __uuidof(IDXGIFactory2), - getter_AddRefs(factory2)); + getter_AddRefs(mFactory)); MOZ_ALWAYS_TRUE(!FAILED(hr)); } else { NS_WARNING( "fCreateDXGIFactory2 not loaded, cannot create debug IDXGIFactory2."); } - factory1 = factory2; } - if (!factory1) { + if (!mFactory) { HRESULT hr = - createDXGIFactory1(__uuidof(IDXGIFactory1), getter_AddRefs(factory1)); - if (FAILED(hr) || !factory1) { + createDXGIFactory1(__uuidof(IDXGIFactory1), getter_AddRefs(mFactory)); + if (FAILED(hr) || !mFactory) { // This seems to happen with some people running the iZ3D driver. // They won't get acceleration. return nullptr; } } - if (!mDeviceStatus) { - // If we haven't created a device yet, and have no existing device status, - // then this must be the compositor device. Pick the first adapter we can. - if (FAILED(factory1->EnumAdapters1(0, getter_AddRefs(mAdapter)))) { - return nullptr; - } - } else { - // In the UI and GPU process, we clear mDeviceStatus on device reset, so we - // should never reach here. Furthermore, the UI process does not create - // devices when using a GPU process. - // - // So, this should only ever get called on the content process or RDD - // process - MOZ_ASSERT(XRE_IsContentProcess() || XRE_IsRDDProcess()); - - // In the child process, we search for the adapter that matches the parent - // process. The first adapter can be mismatched on dual-GPU systems. + if (mDeviceStatus) { + // Match the adapter to our mDeviceStatus, if possible. for (UINT index = 0;; index++) { RefPtr<IDXGIAdapter1> adapter; - if (FAILED(factory1->EnumAdapters1(index, getter_AddRefs(adapter)))) { + if (FAILED(mFactory->EnumAdapters1(index, getter_AddRefs(adapter)))) { break; } @@ -730,7 +780,9 @@ IDXGIAdapter1* DeviceManagerDx::GetDXGIAdapterLocked() { } if (!mAdapter) { - return nullptr; + mDeviceStatus.reset(); + // Pick the first adapter available. + mFactory->EnumAdapters1(0, getter_AddRefs(mAdapter)); } // We leak this module everywhere, we might as well do so here as well. @@ -1045,7 +1097,7 @@ FeatureStatus DeviceManagerDx::CreateContentDevice() { } RefPtr<ID3D11Device> DeviceManagerDx::CreateDecoderDevice( - bool aHardwareWebRender) { + DeviceFlagSet aFlags) { MutexAutoLock lock(mDeviceLock); if (!mDeviceStatus) { @@ -1054,30 +1106,33 @@ RefPtr<ID3D11Device> DeviceManagerDx::CreateDecoderDevice( bool isAMD = mDeviceStatus->adapter().VendorId == 0x1002; bool reuseDevice = false; - if (gfxVars::ReuseDecoderDevice()) { - reuseDevice = true; - } else if (isAMD) { - reuseDevice = true; - gfxCriticalNoteOnce << "Always have to reuse decoder device on AMD"; - } + if (!aFlags.contains(DeviceFlag::disableDeviceReuse)) { + if (gfxVars::ReuseDecoderDevice()) { + reuseDevice = true; + } else if (isAMD) { + reuseDevice = true; + gfxCriticalNoteOnce << "Always have to reuse decoder device on AMD"; + } - if (reuseDevice) { - // Use mCompositorDevice for decoder device only for hardware WebRender. - if (aHardwareWebRender && mCompositorDevice && - mCompositorDeviceSupportsVideo && !mDecoderDevice) { - mDecoderDevice = mCompositorDevice; - - RefPtr<ID3D10Multithread> multi; - mDecoderDevice->QueryInterface(__uuidof(ID3D10Multithread), - getter_AddRefs(multi)); - if (multi) { - MOZ_ASSERT(multi->GetMultithreadProtected()); + if (reuseDevice) { + // Use mCompositorDevice for decoder device only for hardware WebRender. + if (aFlags.contains(DeviceFlag::isHardwareWebRenderInUse) && + mCompositorDevice && mCompositorDeviceSupportsVideo && + !mDecoderDevice) { + mDecoderDevice = mCompositorDevice; + + RefPtr<ID3D10Multithread> multi; + mDecoderDevice->QueryInterface(__uuidof(ID3D10Multithread), + getter_AddRefs(multi)); + if (multi) { + MOZ_ASSERT(multi->GetMultithreadProtected()); + } } - } - if (mDecoderDevice) { - RefPtr<ID3D11Device> dev = mDecoderDevice; - return dev.forget(); + if (mDecoderDevice) { + RefPtr<ID3D11Device> dev = mDecoderDevice; + return dev.forget(); + } } } |