From 6919c26e411b7f2b303d198652fb64eaa83904ac Mon Sep 17 00:00:00 2001 From: sotaro Date: Tue, 20 Feb 2024 02:58:29 +0000 Subject: [PATCH] Bug 1880926 - Check if system enables HDR on Windows r=gfx-reviewers,lsalzman By using IDXGIOutput6, we could check if system enables HDR on Windows. DeviceManagerDx::SystemHDREnabled() is expected to be called in GPU process. Differential Revision: https://phabricator.services.mozilla.com/D202186 --- gfx/ipc/GPUParent.cpp | 7 ++ gfx/ipc/GPUParent.h | 1 + gfx/ipc/GPUProcessManager.cpp | 12 ++++ gfx/ipc/GPUProcessManager.h | 1 + gfx/ipc/PGPU.ipdl | 1 + gfx/thebes/DeviceManagerDx.cpp | 116 +++++++++++++++++++++++++++++++++ gfx/thebes/DeviceManagerDx.h | 10 +++ 7 files changed, 148 insertions(+) diff --git a/gfx/ipc/GPUParent.cpp b/gfx/ipc/GPUParent.cpp index 283fb87ee916..bf8dc68f612a 100644 --- a/gfx/ipc/GPUParent.cpp +++ b/gfx/ipc/GPUParent.cpp @@ -571,6 +571,13 @@ mozilla::ipc::IPCResult GPUParent::RecvPreferenceUpdate(const Pref& aPref) { return IPC_OK(); } +mozilla::ipc::IPCResult GPUParent::RecvScreenInformationChanged() { +#if defined(XP_WIN) + DeviceManagerDx::Get()->PostUpdateMonitorInfo(); +#endif + return IPC_OK(); +} + static void CopyFeatureChange(Feature aFeature, Maybe* aOut) { FeatureState& feature = gfxConfig::GetFeature(aFeature); if (feature.DisabledByDefault() || feature.IsEnabled()) { diff --git a/gfx/ipc/GPUParent.h b/gfx/ipc/GPUParent.h index 434c9eab79f8..be50f8793f86 100644 --- a/gfx/ipc/GPUParent.h +++ b/gfx/ipc/GPUParent.h @@ -74,6 +74,7 @@ class GPUParent final : public PGPUParent { Endpoint&& aEndpoint); mozilla::ipc::IPCResult RecvUpdateVar(const GfxVarUpdate& pref); mozilla::ipc::IPCResult RecvPreferenceUpdate(const Pref& pref); + mozilla::ipc::IPCResult RecvScreenInformationChanged(); mozilla::ipc::IPCResult RecvNewContentCompositorManager( Endpoint&& aEndpoint, const ContentParentId& aChildId, uint32_t aNamespace); diff --git a/gfx/ipc/GPUProcessManager.cpp b/gfx/ipc/GPUProcessManager.cpp index babc523e3acb..705ab42e7ba6 100644 --- a/gfx/ipc/GPUProcessManager.cpp +++ b/gfx/ipc/GPUProcessManager.cpp @@ -136,6 +136,8 @@ GPUProcessManager::Observer::Observe(nsISupports* aSubject, const char* aTopic, } } else if (!strcmp(aTopic, "application-background")) { mManager->mAppInForeground = false; + } else if (!strcmp(aTopic, "screen-information-changed")) { + mManager->ScreenInformationChanged(); } return NS_OK; } @@ -148,6 +150,7 @@ void GPUProcessManager::OnXPCOMShutdown() { if (obsServ) { obsServ->RemoveObserver(mObserver, "application-foreground"); obsServ->RemoveObserver(mObserver, "application-background"); + obsServ->RemoveObserver(mObserver, "screen-information-changed"); } mObserver = nullptr; } @@ -172,6 +175,14 @@ void GPUProcessManager::OnPreferenceChange(const char16_t* aData) { } } +void GPUProcessManager::ScreenInformationChanged() { +#if defined(XP_WIN) + if (!!mGPUChild) { + mGPUChild->SendScreenInformationChanged(); + } +#endif +} + void GPUProcessManager::ResetProcessStable() { mTotalProcessAttempts++; mProcessStable = false; @@ -207,6 +218,7 @@ bool GPUProcessManager::LaunchGPUProcess() { if (obsServ) { obsServ->AddObserver(mObserver, "application-foreground", false); obsServ->AddObserver(mObserver, "application-background", false); + obsServ->AddObserver(mObserver, "screen-information-changed", false); } } diff --git a/gfx/ipc/GPUProcessManager.h b/gfx/ipc/GPUProcessManager.h index bf5b7e658799..ea2e5fb25666 100644 --- a/gfx/ipc/GPUProcessManager.h +++ b/gfx/ipc/GPUProcessManager.h @@ -214,6 +214,7 @@ class GPUProcessManager final : public GPUProcessHost::Listener { // Called from our xpcom-shutdown observer. void OnXPCOMShutdown(); void OnPreferenceChange(const char16_t* aData); + void ScreenInformationChanged(); bool CreateContentCompositorManager( base::ProcessId aOtherProcess, dom::ContentParentId aChildId, diff --git a/gfx/ipc/PGPU.ipdl b/gfx/ipc/PGPU.ipdl index b6e84bf142f7..ecb4664ed4ba 100644 --- a/gfx/ipc/PGPU.ipdl +++ b/gfx/ipc/PGPU.ipdl @@ -79,6 +79,7 @@ parent: async UpdateVar(GfxVarUpdate var); async PreferenceUpdate(Pref pref); + async ScreenInformationChanged(); // Create a new content-process compositor bridge. async NewContentCompositorManager(Endpoint endpoint, ContentParentId childId, uint32_t aNamespace); diff --git a/gfx/thebes/DeviceManagerDx.cpp b/gfx/thebes/DeviceManagerDx.cpp index 18c5cea7db7c..20b63fd7171d 100644 --- a/gfx/thebes/DeviceManagerDx.cpp +++ b/gfx/thebes/DeviceManagerDx.cpp @@ -206,6 +206,122 @@ bool DeviceManagerDx::GetOutputFromMonitor(HMONITOR monitor, return false; } +void DeviceManagerDx::PostUpdateMonitorInfo() { + MOZ_ASSERT(XRE_IsGPUProcess()); + MOZ_ASSERT(NS_IsMainThread()); + + MutexAutoLock lock(mDeviceLock); + // Reduce frequency of UpdateMonitorInfo() call. + if (mUpdateMonitorInfoRunnable) { + return; + } + + auto* holder = CompositorThreadHolder::GetSingleton(); + if (!holder) { + return; + } + + mUpdateMonitorInfoRunnable = NS_NewRunnableFunction( + "DeviceManagerDx::PostUpdateMonitorInfo::Runnable", []() -> void { + auto* dm = gfx::DeviceManagerDx::Get(); + if (dm) { + dm->UpdateMonitorInfo(); + } + }); + + const uint32_t kDelayMS = 100; + RefPtr runnable = mUpdateMonitorInfoRunnable; + holder->GetCompositorThread()->DelayedDispatch(runnable.forget(), kDelayMS); +} + +void DeviceManagerDx::UpdateMonitorInfo() { + bool systemHdrEnabled = false; + + for (const auto& desc : GetOutputDescs()) { + if (desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) { + systemHdrEnabled = true; + } + } + { + MutexAutoLock lock(mDeviceLock); + mSystemHdrEnabled = Some(systemHdrEnabled); + mUpdateMonitorInfoRunnable = nullptr; + } +} + +std::vector DeviceManagerDx::GetOutputDescs() { + HRESULT hr; + std::vector outputDescs; + + RefPtr dxgiFactory; + hr = ::CreateDXGIFactory1(__uuidof(IDXGIFactory1), + getter_AddRefs(dxgiFactory)); + if (FAILED(hr)) { + gfxCriticalNoteOnce << "Failed to create DXGI factory: " << gfx::hexa(hr); + return outputDescs; + } + + for (UINT adapterIndex = 0;; adapterIndex++) { + RefPtr adapter; + hr = dxgiFactory->EnumAdapters(adapterIndex, getter_AddRefs(adapter)); + if (hr == DXGI_ERROR_NOT_FOUND) { + break; + } + if (FAILED(hr)) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + gfxCriticalNoteOnce << "Failed to enumerate DXGI adapter: " + << gfx::hexa(hr); + break; + } + + for (UINT outputIndex = 0;; ++outputIndex) { + RefPtr output; + hr = adapter->EnumOutputs(outputIndex, getter_AddRefs(output)); + if (hr == DXGI_ERROR_NOT_FOUND) { + break; + } + if (FAILED(hr)) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + gfxCriticalNoteOnce << "Failed to enumulate DXGI output: " + << gfx::hexa(hr); + break; + } + + RefPtr output6; + hr = output->QueryInterface(__uuidof(IDXGIOutput6), + getter_AddRefs(output6)); + if (FAILED(hr)) { + continue; + } + + DXGI_OUTPUT_DESC1 desc; + if (FAILED(output6->GetDesc1(&desc))) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + gfxCriticalNoteOnce << "Failed to get DXGI output descriptor"; + continue; + } + + outputDescs.push_back(std::move(desc)); + } + } + + return outputDescs; +} + +bool DeviceManagerDx::SystemHDREnabled() { + { + MutexAutoLock lock(mDeviceLock); + if (mSystemHdrEnabled.isSome()) { + return mSystemHdrEnabled.ref(); + } + } + + UpdateMonitorInfo(); + + MutexAutoLock lock(mDeviceLock); + return mSystemHdrEnabled.ref(); +} + void DeviceManagerDx::CheckHardwareStretchingSupport(HwStretchingSupport& aRv) { RefPtr adapter = GetDXGIAdapter(); diff --git a/gfx/thebes/DeviceManagerDx.h b/gfx/thebes/DeviceManagerDx.h index 9d127af3585b..c6860c7ffa2b 100644 --- a/gfx/thebes/DeviceManagerDx.h +++ b/gfx/thebes/DeviceManagerDx.h @@ -6,6 +6,8 @@ #ifndef mozilla_gfx_thebes_DeviceManagerDx_h #define mozilla_gfx_thebes_DeviceManagerDx_h +#include + #include "gfxPlatform.h" #include "gfxTelemetry.h" #include "gfxTypes.h" @@ -88,6 +90,9 @@ class DeviceManagerDx final { // 'monitor'; returns false if not found or some error occurred. bool GetOutputFromMonitor(HMONITOR monitor, RefPtr* aOutOutput); + void PostUpdateMonitorInfo(); + bool SystemHDREnabled(); + // Check if the current adapter supports hardware stretching void CheckHardwareStretchingSupport(HwStretchingSupport& aRv); @@ -172,6 +177,9 @@ class DeviceManagerDx final { bool GetAnyDeviceRemovedReason(DeviceResetReason* aOutReason) MOZ_REQUIRES(mDeviceLock); + void UpdateMonitorInfo(); + std::vector GetOutputDescs(); + private: static StaticAutoPtr sInstance; @@ -198,6 +206,8 @@ class DeviceManagerDx final { bool mCompositorDeviceSupportsVideo MOZ_GUARDED_BY(mDeviceLock); Maybe mDeviceStatus MOZ_GUARDED_BY(mDeviceLock); Maybe mDeviceResetReason MOZ_GUARDED_BY(mDeviceLock); + RefPtr mUpdateMonitorInfoRunnable MOZ_GUARDED_BY(mDeviceLock); + Maybe mSystemHdrEnabled MOZ_GUARDED_BY(mDeviceLock); nsModuleHandle mDirectDrawDLL; RefPtr mDirectDraw;