rhi: Make DXGI HDR query usable with Vulkan
Also moves the relevant code into one place, that is usable internally from other places in the future. (the interface might change still) Most importantly, this now makes the Vulkan backend to report the same information as the D3D11/12 ones, as long as the Vulkan implementation reports the deviceLUID in the extended physical device properties. Change-Id: I6aa8adaf40bbc3199959019d323910abd27ec473 Reviewed-by: Kristoffer Skau <kristoffer.skau@qt.io> Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
parent
950c61d48b
commit
da61af8065
@ -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
|
||||
|
203
src/gui/rhi/qdxgihdrinfo.cpp
Normal file
203
src/gui/rhi/qdxgihdrinfo.cpp
Normal file
@ -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 <QtCore/private/qsystemerror_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QDxgiHdrInfo::QDxgiHdrInfo()
|
||||
{
|
||||
HRESULT hr = CreateDXGIFactory2(0, __uuidof(IDXGIFactory2), reinterpret_cast<void **>(&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<void **>(&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<void **>(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<DISPLAYCONFIG_PATH_INFO> pathInfos;
|
||||
uint32_t pathInfoCount, modeInfoCount;
|
||||
LONG result;
|
||||
do {
|
||||
if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathInfoCount, &modeInfoCount) == ERROR_SUCCESS) {
|
||||
pathInfos.resize(pathInfoCount);
|
||||
QVector<DISPLAYCONFIG_MODE_INFO> 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
|
69
src/gui/rhi/qdxgihdrinfo_p.h
Normal file
69
src/gui/rhi/qdxgihdrinfo_p.h
Normal file
@ -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 <QtGui/qwindow.h>
|
||||
#include <rhi/qrhi.h>
|
||||
|
||||
#include <dxgi1_6.h>
|
||||
|
||||
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
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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<void **>(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<DISPLAYCONFIG_PATH_INFO> pathInfos;
|
||||
uint32_t pathInfoCount, modeInfoCount;
|
||||
LONG result;
|
||||
do {
|
||||
if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathInfoCount, &modeInfoCount) == ERROR_SUCCESS) {
|
||||
pathInfos.resize(pathInfoCount);
|
||||
QVector<DISPLAYCONFIG_MODE_INFO> 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"}) {
|
||||
|
@ -17,8 +17,6 @@
|
||||
|
||||
#include <rhi/qrhi.h>
|
||||
|
||||
#include <QtGui/qwindow.h>
|
||||
|
||||
#include <dxgi1_6.h>
|
||||
#include <dcomp.h>
|
||||
#include <d3dcompiler.h>
|
||||
@ -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();
|
||||
|
@ -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<const LUID *>(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()
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user