diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index b22be1aec79..2c72123db11 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -465,6 +465,7 @@ qt_internal_extend_target(Gui CONDITION WIN32 ../3rdparty/D3D12MemoryAllocator/D3D12MemAlloc.h ../3rdparty/D3D12MemoryAllocator/D3D12MemAlloc.cpp rhi/qdxgivsyncservice_p.h rhi/qdxgivsyncservice.cpp + rhi/qdxgihdrinfo_p.h rhi/qdxgihdrinfo.cpp text/windows/qwindowsfontdatabase.cpp text/windows/qwindowsfontdatabase_p.h text/windows/qwindowsfontdatabasebase.cpp text/windows/qwindowsfontdatabasebase_p.h text/windows/qwindowsfontengine.cpp text/windows/qwindowsfontengine_p.h diff --git a/src/gui/rhi/qdxgihdrinfo.cpp b/src/gui/rhi/qdxgihdrinfo.cpp new file mode 100644 index 00000000000..023ca654e04 --- /dev/null +++ b/src/gui/rhi/qdxgihdrinfo.cpp @@ -0,0 +1,203 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qdxgihdrinfo_p.h" +#include + +QT_BEGIN_NAMESPACE + +QDxgiHdrInfo::QDxgiHdrInfo() +{ + HRESULT hr = CreateDXGIFactory2(0, __uuidof(IDXGIFactory2), reinterpret_cast(&m_factory)); + if (FAILED(hr)) { + qWarning("QDxgiHdrInfo: CreateDXGIFactory2 failed: %s", qPrintable(QSystemError::windowsComString(hr))); + return; + } + + // Create the factory but leave m_adapter set to null, indicating that all + // outputs of all adapters should be enumerated (if this is a good idea, not + // sure, but there is no choice here, when someone wants to use this outside + // of QRhi's scope and control) +} + +QDxgiHdrInfo::QDxgiHdrInfo(LUID luid) +{ + HRESULT hr = CreateDXGIFactory2(0, __uuidof(IDXGIFactory2), reinterpret_cast(&m_factory)); + if (FAILED(hr)) { + qWarning("QDxgiHdrInfo: CreateDXGIFactory2 failed: %s", qPrintable(QSystemError::windowsComString(hr))); + return; + } + + IDXGIAdapter1 *ad; + for (int adapterIndex = 0; m_factory->EnumAdapters1(UINT(adapterIndex), &ad) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) { + DXGI_ADAPTER_DESC1 desc; + ad->GetDesc1(&desc); + if (desc.AdapterLuid.LowPart == luid.LowPart && desc.AdapterLuid.HighPart == luid.HighPart) { + m_adapter = ad; + break; + } + ad->Release(); + } + + if (!m_adapter) + qWarning("QDxgiHdrInfo: No adapter found"); +} + +QDxgiHdrInfo::QDxgiHdrInfo(IDXGIAdapter1 *adapter) + : m_adapter(adapter) +{ + m_adapter->AddRef(); // so that the dtor does not destroy it +} + +QDxgiHdrInfo::~QDxgiHdrInfo() +{ + if (m_adapter) + m_adapter->Release(); + + if (m_factory) + m_factory->Release(); +} + +bool QDxgiHdrInfo::isHdrCapable(QWindow *w) +{ + if (!m_adapter && m_factory) { + IDXGIAdapter1 *adapter; + for (int adapterIndex = 0; m_factory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) { + DXGI_OUTPUT_DESC1 desc1; + const bool ok = outputDesc1ForWindow(w, adapter, &desc1) && desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; + adapter->Release(); + if (ok) + return true; + } + } else if (m_adapter) { + DXGI_OUTPUT_DESC1 desc1; + if (outputDesc1ForWindow(w, m_adapter, &desc1)) { + // as per https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range + if (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) { + // "HDR display with all Advanced Color capabilities" + return true; + } + } + } + + return false; +} + +QRhiSwapChainHdrInfo QDxgiHdrInfo::queryHdrInfo(QWindow *w) +{ + QRhiSwapChainHdrInfo info; + info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits; + info.limits.luminanceInNits.minLuminance = 0.0f; + info.limits.luminanceInNits.maxLuminance = 1000.0f; + info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred; + info.sdrWhiteLevel = 200.0f; + + DXGI_OUTPUT_DESC1 hdrOutputDesc; + bool ok = false; + if (!m_adapter && m_factory) { + IDXGIAdapter1 *adapter; + for (int adapterIndex = 0; m_factory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) { + ok = outputDesc1ForWindow(w, adapter, &hdrOutputDesc); + adapter->Release(); + if (ok) + break; + } + } else if (m_adapter) { + ok = outputDesc1ForWindow(w, m_adapter, &hdrOutputDesc); + } + if (ok) { + info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits; + info.limits.luminanceInNits.minLuminance = hdrOutputDesc.MinLuminance; + info.limits.luminanceInNits.maxLuminance = hdrOutputDesc.MaxLuminance; + info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred; // 1.0 = 80 nits + info.sdrWhiteLevel = sdrWhiteLevelInNits(hdrOutputDesc); + } + + return info; +} + +bool QDxgiHdrInfo::output6ForWindow(QWindow *w, IDXGIAdapter1 *adapter, IDXGIOutput6 **result) +{ + if (!adapter) + return false; + + bool ok = false; + QRect wr = w->geometry(); + wr = QRect(wr.topLeft() * w->devicePixelRatio(), wr.size() * w->devicePixelRatio()); + const QPoint center = wr.center(); + IDXGIOutput *currentOutput = nullptr; + IDXGIOutput *output = nullptr; + for (UINT i = 0; adapter->EnumOutputs(i, &output) != DXGI_ERROR_NOT_FOUND; ++i) { + if (!output) + continue; + DXGI_OUTPUT_DESC desc; + output->GetDesc(&desc); + const RECT r = desc.DesktopCoordinates; + const QRect dr(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1)); + if (dr.contains(center)) { + currentOutput = output; + break; + } else { + output->Release(); + } + } + if (currentOutput) { + ok = SUCCEEDED(currentOutput->QueryInterface(__uuidof(IDXGIOutput6), reinterpret_cast(result))); + currentOutput->Release(); + } + return ok; +} + +bool QDxgiHdrInfo::outputDesc1ForWindow(QWindow *w, IDXGIAdapter1 *adapter, DXGI_OUTPUT_DESC1 *result) +{ + bool ok = false; + IDXGIOutput6 *out6 = nullptr; + if (output6ForWindow(w, adapter, &out6)) { + ok = SUCCEEDED(out6->GetDesc1(result)); + out6->Release(); + } + return ok; +} + +float QDxgiHdrInfo::sdrWhiteLevelInNits(const DXGI_OUTPUT_DESC1 &outputDesc) +{ + QVector pathInfos; + uint32_t pathInfoCount, modeInfoCount; + LONG result; + do { + if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathInfoCount, &modeInfoCount) == ERROR_SUCCESS) { + pathInfos.resize(pathInfoCount); + QVector modeInfos(modeInfoCount); + result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathInfoCount, pathInfos.data(), &modeInfoCount, modeInfos.data(), nullptr); + } else { + return 200.0f; + } + } while (result == ERROR_INSUFFICIENT_BUFFER); + + MONITORINFOEX monitorInfo = {}; + monitorInfo.cbSize = sizeof(monitorInfo); + GetMonitorInfo(outputDesc.Monitor, &monitorInfo); + + for (const DISPLAYCONFIG_PATH_INFO &info : pathInfos) { + DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName = {}; + deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + deviceName.header.size = sizeof(deviceName); + deviceName.header.adapterId = info.sourceInfo.adapterId; + deviceName.header.id = info.sourceInfo.id; + if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) { + if (!wcscmp(monitorInfo.szDevice, deviceName.viewGdiDeviceName)) { + DISPLAYCONFIG_SDR_WHITE_LEVEL whiteLevel = {}; + whiteLevel.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL; + whiteLevel.header.size = sizeof(DISPLAYCONFIG_SDR_WHITE_LEVEL); + whiteLevel.header.adapterId = info.targetInfo.adapterId; + whiteLevel.header.id = info.targetInfo.id; + if (DisplayConfigGetDeviceInfo(&whiteLevel.header) == ERROR_SUCCESS) + return whiteLevel.SDRWhiteLevel * 80 / 1000.0f; + } + } + } + + return 200.0f; +} + +QT_END_NAMESPACE diff --git a/src/gui/rhi/qdxgihdrinfo_p.h b/src/gui/rhi/qdxgihdrinfo_p.h new file mode 100644 index 00000000000..d19f87bc55a --- /dev/null +++ b/src/gui/rhi/qdxgihdrinfo_p.h @@ -0,0 +1,69 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QDXGIHDRINFO_P_H +#define QDXGIHDRINFO_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QDxgiHdrInfo +{ +public: + // When already having an adapter, i.e. in a D3D11/12 backend of QRhi; this + // is very cheap to construct. + QDxgiHdrInfo(IDXGIAdapter1 *adapter); + + // When having the adapter LUID from somewhere (e.g. + // VkPhysicalDeviceIDProperties::deviceLUID); This has to create a DXGI + // factory and enumarate to find the matching IDXGIAdapter, so less cheap. + QDxgiHdrInfo(LUID luid); + + // All functions below will enumerate all adapters and all their outputs + // every time they are called. Probably not nice. Use when there is no + // knowledge which GPUs will be used with QRhi. + QDxgiHdrInfo(); + + ~QDxgiHdrInfo(); + + // True if the window belongs to an output where HDR is enabled. Moving a + // window to another screen may make this function return a different value. + // + // If/how DXGI outputs map to screens, is out of our hands, but they will + // typically match. However, this will not be functional when WARP is used + // since the WARP adapter never has any outputs associated (even though + // there are certainly screens still). + // + bool isHdrCapable(QWindow *w); + + // HDR info and white level. Or default, dummy values when the window is not + // on a HDR-enabled output. + QRhiSwapChainHdrInfo queryHdrInfo(QWindow *w); + +private: + static bool output6ForWindow(QWindow *w, IDXGIAdapter1 *adapter, IDXGIOutput6 **result); + static bool outputDesc1ForWindow(QWindow *w, IDXGIAdapter1 *adapter, DXGI_OUTPUT_DESC1 *result); + static float sdrWhiteLevelInNits(const DXGI_OUTPUT_DESC1 &outputDesc); + + IDXGIFactory2 *m_factory = nullptr; + IDXGIAdapter1 *m_adapter = nullptr; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 1e211d98265..8019b585f71 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -385,7 +385,7 @@ bool QRhiD3D11::create(QRhi::Flags flags) adapter1->GetDesc1(&desc); adapterLuid = desc.AdapterLuid; QRhiD3D::fillDriverInfo(&driverInfoStruct, desc); - adapter1->Release(); + activeAdapter = adapter1; } adapter->Release(); } @@ -5071,11 +5071,8 @@ bool QD3D11SwapChain::isFormatSupported(Format f) } QRHI_RES_RHI(QRhiD3D11); - DXGI_OUTPUT_DESC1 desc1; - if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &desc1)) { - if (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) - return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10; - } + if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) + return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10; return false; } @@ -5086,14 +5083,7 @@ QRhiSwapChainHdrInfo QD3D11SwapChain::hdrInfo() // Must use m_window, not window, given this may be called before createOrResize(). if (m_window) { QRHI_RES_RHI(QRhiD3D11); - DXGI_OUTPUT_DESC1 hdrOutputDesc; - if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc)) { - info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits; - info.limits.luminanceInNits.minLuminance = hdrOutputDesc.MinLuminance; - info.limits.luminanceInNits.maxLuminance = hdrOutputDesc.MaxLuminance; - info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred; // 1.0 = 80 nits - info.sdrWhiteLevel = QRhiD3D::sdrWhiteLevelInNits(hdrOutputDesc); - } + info = QDxgiHdrInfo(rhiD->activeAdapter).queryHdrInfo(m_window); } return info; } @@ -5230,10 +5220,9 @@ bool QD3D11SwapChain::createOrResize() srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT; DXGI_COLOR_SPACE_TYPE hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; // SDR - DXGI_OUTPUT_DESC1 hdrOutputDesc; - if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc) && m_format != SDR) { - // https://docs.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range - if (hdrOutputDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) { + if (m_format != SDR) { + if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) { + // https://docs.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range switch (m_format) { case HDRExtendedSrgbLinear: colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT; diff --git a/src/gui/rhi/qrhid3d12.cpp b/src/gui/rhi/qrhid3d12.cpp index be78d532394..bdf84f54d79 100644 --- a/src/gui/rhi/qrhid3d12.cpp +++ b/src/gui/rhi/qrhid3d12.cpp @@ -6400,11 +6400,8 @@ bool QD3D12SwapChain::isFormatSupported(Format f) } QRHI_RES_RHI(QRhiD3D12); - DXGI_OUTPUT_DESC1 desc1; - if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &desc1)) { - if (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) - return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10; - } + if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) + return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10; return false; } @@ -6415,14 +6412,7 @@ QRhiSwapChainHdrInfo QD3D12SwapChain::hdrInfo() // Must use m_window, not window, given this may be called before createOrResize(). if (m_window) { QRHI_RES_RHI(QRhiD3D12); - DXGI_OUTPUT_DESC1 hdrOutputDesc; - if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc)) { - info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits; - info.limits.luminanceInNits.minLuminance = hdrOutputDesc.MinLuminance; - info.limits.luminanceInNits.maxLuminance = hdrOutputDesc.MaxLuminance; - info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred; // 1.0 = 80 nits - info.sdrWhiteLevel = QRhiD3D::sdrWhiteLevelInNits(hdrOutputDesc); - } + info = QDxgiHdrInfo(rhiD->activeAdapter).queryHdrInfo(m_window); } return info; } @@ -6465,11 +6455,10 @@ void QD3D12SwapChain::chooseFormats() colorFormat = DEFAULT_FORMAT; srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT; hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; // SDR - DXGI_OUTPUT_DESC1 hdrOutputDesc; QRHI_RES_RHI(QRhiD3D12); - if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc) && m_format != SDR) { - // https://docs.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range - if (hdrOutputDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) { + if (m_format != SDR) { + if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) { + // https://docs.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range switch (m_format) { case HDRExtendedSrgbLinear: colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT; diff --git a/src/gui/rhi/qrhid3dhelpers.cpp b/src/gui/rhi/qrhid3dhelpers.cpp index 920446fbd9b..4e42411ea1e 100644 --- a/src/gui/rhi/qrhid3dhelpers.cpp +++ b/src/gui/rhi/qrhid3dhelpers.cpp @@ -9,87 +9,6 @@ QT_BEGIN_NAMESPACE namespace QRhiD3D { -bool output6ForWindow(QWindow *w, IDXGIAdapter1 *adapter, IDXGIOutput6 **result) -{ - bool ok = false; - QRect wr = w->geometry(); - wr = QRect(wr.topLeft() * w->devicePixelRatio(), wr.size() * w->devicePixelRatio()); - const QPoint center = wr.center(); - IDXGIOutput *currentOutput = nullptr; - IDXGIOutput *output = nullptr; - for (UINT i = 0; adapter->EnumOutputs(i, &output) != DXGI_ERROR_NOT_FOUND; ++i) { - if (!output) - continue; - DXGI_OUTPUT_DESC desc; - output->GetDesc(&desc); - const RECT r = desc.DesktopCoordinates; - const QRect dr(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1)); - if (dr.contains(center)) { - currentOutput = output; - break; - } else { - output->Release(); - } - } - if (currentOutput) { - ok = SUCCEEDED(currentOutput->QueryInterface(__uuidof(IDXGIOutput6), reinterpret_cast(result))); - currentOutput->Release(); - } - return ok; -} - -bool outputDesc1ForWindow(QWindow *w, IDXGIAdapter1 *adapter, DXGI_OUTPUT_DESC1 *result) -{ - bool ok = false; - IDXGIOutput6 *out6 = nullptr; - if (output6ForWindow(w, adapter, &out6)) { - ok = SUCCEEDED(out6->GetDesc1(result)); - out6->Release(); - } - return ok; -} - -float sdrWhiteLevelInNits(const DXGI_OUTPUT_DESC1 &outputDesc) -{ - QVector pathInfos; - uint32_t pathInfoCount, modeInfoCount; - LONG result; - do { - if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathInfoCount, &modeInfoCount) == ERROR_SUCCESS) { - pathInfos.resize(pathInfoCount); - QVector modeInfos(modeInfoCount); - result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathInfoCount, pathInfos.data(), &modeInfoCount, modeInfos.data(), nullptr); - } else { - return 200.0f; - } - } while (result == ERROR_INSUFFICIENT_BUFFER); - - MONITORINFOEX monitorInfo = {}; - monitorInfo.cbSize = sizeof(monitorInfo); - GetMonitorInfo(outputDesc.Monitor, &monitorInfo); - - for (const DISPLAYCONFIG_PATH_INFO &info : pathInfos) { - DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName = {}; - deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; - deviceName.header.size = sizeof(deviceName); - deviceName.header.adapterId = info.sourceInfo.adapterId; - deviceName.header.id = info.sourceInfo.id; - if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) { - if (!wcscmp(monitorInfo.szDevice, deviceName.viewGdiDeviceName)) { - DISPLAYCONFIG_SDR_WHITE_LEVEL whiteLevel = {}; - whiteLevel.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL; - whiteLevel.header.size = sizeof(DISPLAYCONFIG_SDR_WHITE_LEVEL); - whiteLevel.header.adapterId = info.targetInfo.adapterId; - whiteLevel.header.id = info.targetInfo.id; - if (DisplayConfigGetDeviceInfo(&whiteLevel.header) == ERROR_SUCCESS) - return whiteLevel.SDRWhiteLevel * 80 / 1000.0f; - } - } - } - - return 200.0f; -} - pD3DCompile resolveD3DCompile() { for (const wchar_t *libraryName : {L"D3DCompiler_47", L"D3DCompiler_43"}) { diff --git a/src/gui/rhi/qrhid3dhelpers_p.h b/src/gui/rhi/qrhid3dhelpers_p.h index 814824d774c..2d07620c0b4 100644 --- a/src/gui/rhi/qrhid3dhelpers_p.h +++ b/src/gui/rhi/qrhid3dhelpers_p.h @@ -17,8 +17,6 @@ #include -#include - #include #include #include @@ -29,15 +27,12 @@ #endif #include "qdxgivsyncservice_p.h" +#include "qdxgihdrinfo_p.h" QT_BEGIN_NAMESPACE namespace QRhiD3D { -bool output6ForWindow(QWindow *w, IDXGIAdapter1 *adapter, IDXGIOutput6 **result); -bool outputDesc1ForWindow(QWindow *w, IDXGIAdapter1 *adapter, DXGI_OUTPUT_DESC1 *result); -float sdrWhiteLevelInNits(const DXGI_OUTPUT_DESC1 &outputDesc); - pD3DCompile resolveD3DCompile(); IDCompositionDevice *createDirectCompositionDevice(); diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 3046e310188..be2554bda43 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -968,6 +968,30 @@ bool QRhiVulkan::create(QRhi::Flags flags) } #endif + // On Windows, figure out the DXGI adapter LUID. +#ifdef Q_OS_WIN + adapterLuidValid = false; + adapterLuid = {}; +#ifdef VK_VERSION_1_2 + if (caps.apiVersion >= QVersionNumber(1, 2)) { + VkPhysicalDeviceVulkan11Properties v11props = {}; + v11props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES; + VkPhysicalDeviceProperties2 props2 = {}; + props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + props2.pNext = &v11props; + f->vkGetPhysicalDeviceProperties2(physDev, &props2); + if (v11props.deviceLUIDValid) { + const LUID *luid = reinterpret_cast(v11props.deviceLUID); + memcpy(&adapterLuid, luid, VK_LUID_SIZE); + adapterLuidValid = true; + dxgiHdrInfo = new QDxgiHdrInfo(adapterLuid); + qCDebug(QRHI_LOG_INFO, "DXGI adapter LUID for physical device is %lu, %lu", + adapterLuid.LowPart, adapterLuid.HighPart); + } + } +#endif +#endif + if (!importedAllocator) { VmaVulkanFunctions funcs = {}; funcs.vkGetInstanceProcAddr = wrap_vkGetInstanceProcAddr; @@ -1047,6 +1071,11 @@ void QRhiVulkan::destroy() executeDeferredReleases(true); finishActiveReadbacks(true); +#ifdef Q_OS_WIN + delete dxgiHdrInfo; + dxgiHdrInfo = nullptr; +#endif + if (ofr.cmdFence) { df->vkDestroyFence(dev, ofr.cmdFence, nullptr); ofr.cmdFence = VK_NULL_HANDLE; @@ -8551,6 +8580,18 @@ bool QVkSwapChain::isFormatSupported(Format f) return false; } +QRhiSwapChainHdrInfo QVkSwapChain::hdrInfo() +{ + QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo(); +#ifdef Q_OS_WIN + QRHI_RES_RHI(QRhiVulkan); + // Must use m_window, not window, given this may be called before createOrResize(). + if (m_window && rhiD->adapterLuidValid) + info = rhiD->dxgiHdrInfo->queryHdrInfo(m_window); +#endif + return info; +} + QRhiRenderPassDescriptor *QVkSwapChain::newCompatibleRenderPassDescriptor() { // not yet built so cannot rely on data computed in createOrResize() diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h index ad9ca8cb66c..14936a60ec5 100644 --- a/src/gui/rhi/qrhivulkan_p.h +++ b/src/gui/rhi/qrhivulkan_p.h @@ -17,6 +17,10 @@ #include "qrhi_p.h" +#ifdef Q_OS_WIN +#include "qdxgihdrinfo_p.h" +#endif + QT_BEGIN_NAMESPACE class QVulkanFunctions; @@ -605,6 +609,7 @@ struct QVkSwapChain : public QRhiSwapChain QSize surfacePixelSize() override; bool isFormatSupported(Format f) override; + QRhiSwapChainHdrInfo hdrInfo() override; QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override; bool createOrResize() override; @@ -895,6 +900,12 @@ public: bool deviceLost = false; bool releaseCachedResourcesCalledBeforeFrameStart = false; +#ifdef Q_OS_WIN + bool adapterLuidValid = false; + LUID adapterLuid; + QDxgiHdrInfo *dxgiHdrInfo = nullptr; +#endif + #ifdef VK_EXT_debug_utils PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT = nullptr; PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT = nullptr;