Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdxgihdrinfo.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6#include <QtCore/private/qsystemerror_p.h>
7
9
10QDxgiHdrInfo::QDxgiHdrInfo()
11{
12 HRESULT hr = CreateDXGIFactory2(0, __uuidof(IDXGIFactory2), reinterpret_cast<void **>(&m_factory));
13 if (FAILED(hr)) {
14 qWarning("QDxgiHdrInfo: CreateDXGIFactory2 failed: %s", qPrintable(QSystemError::windowsComString(hr)));
15 return;
16 }
17
18 // Create the factory but leave m_adapter set to null, indicating that all
19 // outputs of all adapters should be enumerated (if this is a good idea, not
20 // sure, but there is no choice here, when someone wants to use this outside
21 // of QRhi's scope and control)
22}
23
24QDxgiHdrInfo::QDxgiHdrInfo(LUID luid)
25{
26 HRESULT hr = CreateDXGIFactory2(0, __uuidof(IDXGIFactory2), reinterpret_cast<void **>(&m_factory));
27 if (FAILED(hr)) {
28 qWarning("QDxgiHdrInfo: CreateDXGIFactory2 failed: %s", qPrintable(QSystemError::windowsComString(hr)));
29 return;
30 }
31
32 IDXGIAdapter1 *ad;
33 for (int adapterIndex = 0; m_factory->EnumAdapters1(UINT(adapterIndex), &ad) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
34 DXGI_ADAPTER_DESC1 desc;
35 ad->GetDesc1(&desc);
36 if (desc.AdapterLuid.LowPart == luid.LowPart && desc.AdapterLuid.HighPart == luid.HighPart) {
37 m_adapter = ad;
38 break;
39 }
40 ad->Release();
41 }
42
43 if (!m_adapter)
44 qWarning("QDxgiHdrInfo: No adapter found");
45}
46
47QDxgiHdrInfo::QDxgiHdrInfo(IDXGIAdapter1 *adapter)
48 : m_adapter(adapter)
49{
50 m_adapter->AddRef(); // so that the dtor does not destroy it
51}
52
53QDxgiHdrInfo::~QDxgiHdrInfo()
54{
55 if (m_adapter)
56 m_adapter->Release();
57
58 if (m_factory)
59 m_factory->Release();
60}
61
62bool QDxgiHdrInfo::isHdrCapable(QWindow *w)
63{
64 if (!m_adapter && m_factory) {
65 IDXGIAdapter1 *adapter;
66 for (int adapterIndex = 0; m_factory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
67 DXGI_OUTPUT_DESC1 desc1;
68 const bool ok = outputDesc1ForWindow(w, adapter, &desc1) && desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
69 adapter->Release();
70 if (ok)
71 return true;
72 }
73 } else if (m_adapter) {
74 DXGI_OUTPUT_DESC1 desc1;
75 if (outputDesc1ForWindow(w, m_adapter, &desc1)) {
76 // as per https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range
77 if (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
78 // "HDR display with all Advanced Color capabilities"
79 return true;
80 }
81 }
82 }
83
84 return false;
85}
86
87QRhiSwapChainHdrInfo QDxgiHdrInfo::queryHdrInfo(QWindow *w)
88{
89 QRhiSwapChainHdrInfo info;
90 info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits;
91 info.limits.luminanceInNits.minLuminance = 0.0f;
92 info.limits.luminanceInNits.maxLuminance = 1000.0f;
93 info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred;
94 info.sdrWhiteLevel = 200.0f;
95
96 DXGI_OUTPUT_DESC1 hdrOutputDesc;
97 bool ok = false;
98 if (!m_adapter && m_factory) {
99 IDXGIAdapter1 *adapter;
100 for (int adapterIndex = 0; m_factory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
101 ok = outputDesc1ForWindow(w, adapter, &hdrOutputDesc);
102 adapter->Release();
103 if (ok)
104 break;
105 }
106 } else if (m_adapter) {
107 ok = outputDesc1ForWindow(w, m_adapter, &hdrOutputDesc);
108 }
109 if (ok) {
110 info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits;
111 info.limits.luminanceInNits.minLuminance = hdrOutputDesc.MinLuminance;
112 info.limits.luminanceInNits.maxLuminance = hdrOutputDesc.MaxLuminance;
113 info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred; // 1.0 = 80 nits
114 info.sdrWhiteLevel = sdrWhiteLevelInNits(hdrOutputDesc);
115 }
116
117 return info;
118}
119
120bool QDxgiHdrInfo::output6ForWindow(QWindow *w, IDXGIAdapter1 *adapter, IDXGIOutput6 **result)
121{
122 if (!adapter)
123 return false;
124
125 bool ok = false;
126 QRect wr = w->geometry();
127 wr = QRect(wr.topLeft() * w->devicePixelRatio(), wr.size() * w->devicePixelRatio());
128 const QPoint center = wr.center();
129 IDXGIOutput *currentOutput = nullptr;
130 IDXGIOutput *output = nullptr;
131 for (UINT i = 0; adapter->EnumOutputs(i, &output) != DXGI_ERROR_NOT_FOUND; ++i) {
132 if (!output)
133 continue;
134 DXGI_OUTPUT_DESC desc;
135 output->GetDesc(&desc);
136 const RECT r = desc.DesktopCoordinates;
137 const QRect dr(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1));
138 if (dr.contains(center)) {
139 currentOutput = output;
140 break;
141 } else {
142 output->Release();
143 }
144 }
145 if (currentOutput) {
146 ok = SUCCEEDED(currentOutput->QueryInterface(__uuidof(IDXGIOutput6), reinterpret_cast<void **>(result)));
147 currentOutput->Release();
148 }
149 return ok;
150}
151
152bool QDxgiHdrInfo::outputDesc1ForWindow(QWindow *w, IDXGIAdapter1 *adapter, DXGI_OUTPUT_DESC1 *result)
153{
154 bool ok = false;
155 IDXGIOutput6 *out6 = nullptr;
156 if (output6ForWindow(w, adapter, &out6)) {
157 ok = SUCCEEDED(out6->GetDesc1(result));
158 out6->Release();
159 }
160 return ok;
161}
162
163float QDxgiHdrInfo::sdrWhiteLevelInNits(const DXGI_OUTPUT_DESC1 &outputDesc)
164{
165 QVector<DISPLAYCONFIG_PATH_INFO> pathInfos;
166 uint32_t pathInfoCount, modeInfoCount;
167 LONG result;
168 do {
169 if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathInfoCount, &modeInfoCount) == ERROR_SUCCESS) {
170 pathInfos.resize(pathInfoCount);
171 QVector<DISPLAYCONFIG_MODE_INFO> modeInfos(modeInfoCount);
172 result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathInfoCount, pathInfos.data(), &modeInfoCount, modeInfos.data(), nullptr);
173 } else {
174 return 200.0f;
175 }
176 } while (result == ERROR_INSUFFICIENT_BUFFER);
177
178 MONITORINFOEX monitorInfo = {};
179 monitorInfo.cbSize = sizeof(monitorInfo);
180 GetMonitorInfo(outputDesc.Monitor, &monitorInfo);
181
182 for (const DISPLAYCONFIG_PATH_INFO &info : pathInfos) {
183 DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName = {};
184 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
185 deviceName.header.size = sizeof(deviceName);
186 deviceName.header.adapterId = info.sourceInfo.adapterId;
187 deviceName.header.id = info.sourceInfo.id;
188 if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
189 if (!wcscmp(monitorInfo.szDevice, deviceName.viewGdiDeviceName)) {
190 DISPLAYCONFIG_SDR_WHITE_LEVEL whiteLevel = {};
191 whiteLevel.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
192 whiteLevel.header.size = sizeof(DISPLAYCONFIG_SDR_WHITE_LEVEL);
193 whiteLevel.header.adapterId = info.targetInfo.adapterId;
194 whiteLevel.header.id = info.targetInfo.id;
195 if (DisplayConfigGetDeviceInfo(&whiteLevel.header) == ERROR_SUCCESS)
196 return whiteLevel.SDRWhiteLevel * 80 / 1000.0f;
197 }
198 }
199 }
200
201 return 200.0f;
202}
203
204QT_END_NAMESPACE
Combined button and popup list for selecting options.