summaryrefslogtreecommitdiffstats
path: root/gfx/thebes/DeviceManagerDx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/thebes/DeviceManagerDx.cpp')
-rw-r--r--gfx/thebes/DeviceManagerDx.cpp155
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();
+ }
}
}