Krita Source Code Documentation
Loading...
Searching...
No Matches
KisScreenInformationAdapter.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2019 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include "kis_debug.h"
10#include <QOpenGLContext>
11
12#include <QGuiApplication>
13#include <QWindow>
14
15#include <config-hdr.h>
16
17
18
19#ifdef Q_OS_WIN
20#include <qpa/qplatformnativeinterface.h>
21#include <d3d11.h>
22#include <wrl/client.h>
23#include <dxgi1_6.h>
24#include "EGL/egl.h"
25#include "EGL/eglext.h"
26#endif
27
28namespace {
29struct EGLException {
30 EGLException() {}
31 EGLException(const QString &what) : m_what(what) {}
32
33 QString what() const {
34 return m_what;
35 }
36
37private:
38 QString m_what;
39};
40
41template <typename FuncType>
42void getProcAddressSafe(QOpenGLContext *context, const char *funcName, FuncType &func)
43{
44 func = reinterpret_cast<FuncType>(context->getProcAddress(funcName));
45 if (!func) {
46 throw EGLException(QString("failed to fetch function %1").arg(funcName));
47 }
48}
49
50#ifdef Q_OS_WIN
51typedef const char *(EGLAPIENTRYP PFNEGLQUERYSTRINGPROC) (EGLDisplay dpy, EGLint name);
52#endif
53}
54
55
57{
58 void initialize(QOpenGLContext *context);
59
60 QOpenGLContext *context;
61 QString errorString;
62
63#ifdef Q_OS_WIN
64 Microsoft::WRL::ComPtr<IDXGIAdapter1> dxgiAdapter;
65#endif
66};
67
69 : m_d(new Private)
70{
71 if (context) {
72 m_d->initialize(context);
73 }
74}
75
79
81{
82 context = newContext;
83 errorString.clear();
84
85 try {
86
87#if defined Q_OS_WIN
88
89 if (!context->isOpenGLES()) {
90 throw EGLException("the context is not OpenGL ES");
91 }
92
93 PFNEGLQUERYSTRINGPROC queryString = nullptr;
94 getProcAddressSafe(context, "eglQueryString", queryString);
95
96 const char* client_extensions = queryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
97 const QList<QByteArray> extensions = QByteArray(client_extensions).split(' ');
98
99 if (!extensions.contains("EGL_ANGLE_platform_angle_d3d") ||
100 !extensions.contains("EGL_ANGLE_device_creation_d3d11")) {
101
102 throw EGLException("the context is not Angle + D3D11");
103 }
104
105 PFNEGLQUERYDISPLAYATTRIBEXTPROC queryDisplayAttribEXT = nullptr;
106 PFNEGLQUERYDEVICEATTRIBEXTPROC queryDeviceAttribEXT = nullptr;
107
108 getProcAddressSafe(context, "eglQueryDisplayAttribEXT", queryDisplayAttribEXT);
109 getProcAddressSafe(context, "eglQueryDeviceAttribEXT", queryDeviceAttribEXT);
110
111 QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface();
112 EGLDisplay display = reinterpret_cast<EGLDisplay>(nativeInterface->nativeResourceForContext("egldisplay", context));
113
114 if (!display) {
115 throw EGLException(
116 QString("couldn't request EGLDisplay handle, display = 0x%1").arg(uintptr_t(display), 0, 16));
117 }
118
119 EGLAttrib value = 0;
120 EGLBoolean result = false;
121
122 result = queryDisplayAttribEXT(display, EGL_DEVICE_EXT, &value);
123
124 if (!result || value == EGL_NONE) {
125 throw EGLException(
126 QString("couldn't request EGLDeviceEXT handle, result = 0x%1, value = 0x%2")
127 .arg(result, 0, 16).arg(value, 0, 16));
128 }
129
130 EGLDeviceEXT device = reinterpret_cast<EGLDeviceEXT>(value);
131
132 result = queryDeviceAttribEXT(device, EGL_D3D11_DEVICE_ANGLE, &value);
133
134 if (!result || value == EGL_NONE) {
135 throw EGLException(
136 QString("couldn't request ID3D11Device pointer, result = 0x%1, value = 0x%2")
137 .arg(result, 0, 16).arg(value, 0, 16));
138 }
139 ID3D11Device *deviceD3D = reinterpret_cast<ID3D11Device*>(value);
140
141 {
142 HRESULT result = 0;
143
144 Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice;
145 result = deviceD3D->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice);
146
147 if (FAILED(result)) {
148 throw EGLException(
149 QString("couldn't request IDXGIDevice pointer, result = 0x%1").arg(result, 0, 16));
150 }
151
152 Microsoft::WRL::ComPtr<IDXGIAdapter1> dxgiAdapter;
153 result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter1), (void**)&dxgiAdapter);
154
155 if (FAILED(result)) {
156 throw EGLException(
157 QString("couldn't request IDXGIAdapter1 pointer, result = 0x%1").arg(result, 0, 16));
158 }
159
160 this->dxgiAdapter = dxgiAdapter;
161 }
162
163#else
164 throw EGLException("current platform doesn't support fetching display information");
165#endif
166
167 } catch (EGLException &e) {
168 this->context = 0;
169 this->errorString = e.what();
170#ifdef Q_OS_WIN
171 this->dxgiAdapter.Reset();
172#endif
173 }
174}
175
177{
178#ifdef Q_OS_WIN
179 return m_d->context && m_d->dxgiAdapter;
180#else
181 return false;
182#endif
183}
184
186{
187 return m_d->errorString;
188}
189
191{
192 ScreenInfo info;
193
194#if defined Q_OS_WIN
195
196 QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface();
197 HMONITOR monitor = reinterpret_cast<HMONITOR>(nativeInterface->nativeResourceForScreen("handle", screen));
198
199 UINT i = 0;
200 Microsoft::WRL::ComPtr<IDXGIOutput> currentOutput;
201
202 while (m_d->dxgiAdapter->EnumOutputs(i, &currentOutput) != DXGI_ERROR_NOT_FOUND)
203 {
204
205 HRESULT result = 0;
206 Microsoft::WRL::ComPtr<IDXGIOutput6> output6;
207 result = currentOutput.As(&output6);
208
209 if (output6) {
210 DXGI_OUTPUT_DESC1 desc;
211 result = output6->GetDesc1(&desc);
212
213 if (desc.Monitor == monitor) {
214 info.screen = screen;
215 info.bitsPerColor = desc.BitsPerColor;
216 info.redPrimary[0] = desc.RedPrimary[0];
217 info.redPrimary[1] = desc.RedPrimary[1];
218 info.greenPrimary[0] = desc.GreenPrimary[0];
219 info.greenPrimary[1] = desc.GreenPrimary[1];
220 info.bluePrimary[0] = desc.BluePrimary[0];
221 info.bluePrimary[1] = desc.BluePrimary[1];
222 info.whitePoint[0] = desc.WhitePoint[0];
223 info.whitePoint[1] = desc.WhitePoint[1];
224 info.minLuminance = desc.MinLuminance;
225 info.maxLuminance = desc.MaxLuminance;
226 info.maxFullFrameLuminance = desc.MaxFullFrameLuminance;
227
229
230 if (desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709) {
232 } else if (desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709) {
233#ifdef HAVE_HDR
235#else
236 qWarning("WARNING: scRGB display color space is not supported by Qt's build");
237#endif
238 } else if (desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
239#ifdef HAVE_HDR
241#else
242 qWarning("WARNING: bt2020-pq display color space is not supported by Qt's build");
243#endif
244 } else {
245 qWarning("WARNING: unknown display color space! 0x%X", desc.ColorSpace);
246 }
247
248 break;
249 }
250 }
251
252 Q_UNUSED(result);
253
254 i++;
255 }
256
257#endif
258 Q_UNUSED(screen);
259 return info;
260}
261
263{
264 QDebugStateSaver saver(dbg);
265
266 if (info.isValid()) {
267 dbg.nospace() << "ScreenInfo("
268 << "screen " << info.screen
269 << ", bitsPerColor " << info.bitsPerColor
270 << ", colorSpace " << info.colorSpace
271 << ", redPrimary " << "(" << info.redPrimary[0] << ", " << info.redPrimary[1] << ")"
272 << ", greenPrimary " << "(" << info.greenPrimary[0] << ", " << info.greenPrimary[1] << ")"
273 << ", bluePrimary " << "(" << info.bluePrimary[0] << ", " << info.bluePrimary[1] << ")"
274 << ", whitePoint " << "(" << info.whitePoint[0] << ", " << info.whitePoint[1] << ")"
275 << ", minLuminance " << info.minLuminance
276 << ", maxLuminance " << info.maxLuminance
277 << ", maxFullFrameLuminance " << info.maxFullFrameLuminance
278 << ')';
279 } else {
280 dbg.nospace() << "ScreenInfo(<invalid>)";
281 }
282
283 return dbg;
284}
float value(const T *src, size_t ch)
QDebug operator<<(QDebug, const KisScreenInformationAdapter::ScreenInfo &)
KisScreenInformationAdapter(QOpenGLContext *context)
ScreenInfo infoForScreen(QScreen *screen) const
const QScopedPointer< Private > m_d