1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the plugins of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <QByteArray>
41#include <QOpenGLContext>
42
43#ifdef Q_OS_LINUX
44#include <sys/ioctl.h>
45#include <linux/fb.h>
46#endif
47#include <private/qmath_p.h>
48
49#include "qeglconvenience_p.h"
50
51#ifndef EGL_OPENGL_ES3_BIT_KHR
52#define EGL_OPENGL_ES3_BIT_KHR 0x0040
53#endif
54
55QT_BEGIN_NAMESPACE
56
57QVector<EGLint> q_createConfigAttributesFromFormat(const QSurfaceFormat &format)
58{
59 int redSize = format.redBufferSize();
60 int greenSize = format.greenBufferSize();
61 int blueSize = format.blueBufferSize();
62 int alphaSize = format.alphaBufferSize();
63 int depthSize = format.depthBufferSize();
64 int stencilSize = format.stencilBufferSize();
65 int sampleCount = format.samples();
66
67 QVector<EGLint> configAttributes;
68
69 // Map default, unspecified values (-1) to 0. This is important due to sorting rule #3
70 // in section 3.4.1 of the spec and allows picking a potentially faster 16-bit config
71 // over 32-bit ones when there is no explicit request for the color channel sizes:
72 //
73 // The red/green/blue sizes have a sort priority of 3, so they are sorted by
74 // first. (unless a caveat like SLOW or NON_CONFORMANT is present) The sort order is
75 // Special and described as "by larger _total_ number of color bits.". So EGL will put
76 // 32-bit configs in the list before the 16-bit configs. However, the spec also goes
77 // on to say "If the requested number of bits in attrib_list for a particular
78 // component is 0, then the number of bits for that component is not considered". This
79 // part of the spec also seems to imply that setting the red/green/blue bits to zero
80 // means none of the components are considered and EGL disregards the entire sorting
81 // rule. It then looks to the next highest priority rule, which is
82 // EGL_BUFFER_SIZE. Despite the selection criteria being "AtLeast" for
83 // EGL_BUFFER_SIZE, it's sort order is "smaller" meaning 16-bit configs are put in the
84 // list before 32-bit configs.
85 //
86 // This also means that explicitly specifying a size like 565 will still result in
87 // having larger (888) configs first in the returned list. We need to handle this
88 // ourselves later by manually filtering the list, instead of just blindly taking the
89 // first config from it.
90
91 configAttributes.append(EGL_RED_SIZE);
92 configAttributes.append(t: redSize > 0 ? redSize : 0);
93
94 configAttributes.append(EGL_GREEN_SIZE);
95 configAttributes.append(t: greenSize > 0 ? greenSize : 0);
96
97 configAttributes.append(EGL_BLUE_SIZE);
98 configAttributes.append(t: blueSize > 0 ? blueSize : 0);
99
100 configAttributes.append(EGL_ALPHA_SIZE);
101 configAttributes.append(t: alphaSize > 0 ? alphaSize : 0);
102
103 configAttributes.append(EGL_SAMPLES);
104 configAttributes.append(t: sampleCount > 0 ? sampleCount : 0);
105
106 configAttributes.append(EGL_SAMPLE_BUFFERS);
107 configAttributes.append(t: sampleCount > 0);
108
109 if (format.renderableType() != QSurfaceFormat::OpenVG) {
110 configAttributes.append(EGL_DEPTH_SIZE);
111 configAttributes.append(t: depthSize > 0 ? depthSize : 0);
112
113 configAttributes.append(EGL_STENCIL_SIZE);
114 configAttributes.append(t: stencilSize > 0 ? stencilSize : 0);
115 } else {
116 // OpenVG needs alpha mask for clipping
117 configAttributes.append(EGL_ALPHA_MASK_SIZE);
118 configAttributes.append(t: 8);
119 }
120
121 return configAttributes;
122}
123
124bool q_reduceConfigAttributes(QVector<EGLint> *configAttributes)
125{
126 int i = -1;
127 // Reduce the complexity of a configuration request to ask for less
128 // because the previous request did not result in success. Returns
129 // true if the complexity was reduced, or false if no further
130 // reductions in complexity are possible.
131
132 i = configAttributes->indexOf(EGL_SWAP_BEHAVIOR);
133 if (i >= 0) {
134 configAttributes->remove(i,n: 2);
135 }
136
137#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT
138 // For OpenVG, we sometimes try to create a surface using a pre-multiplied format. If we can't
139 // find a config which supports pre-multiplied formats, remove the flag on the surface type:
140
141 i = configAttributes->indexOf(EGL_SURFACE_TYPE);
142 if (i >= 0) {
143 EGLint surfaceType = configAttributes->at(i: i +1);
144 if (surfaceType & EGL_VG_ALPHA_FORMAT_PRE_BIT) {
145 surfaceType ^= EGL_VG_ALPHA_FORMAT_PRE_BIT;
146 configAttributes->replace(i: i+1,t: surfaceType);
147 return true;
148 }
149 }
150#endif
151
152 // EGL chooses configs with the highest color depth over
153 // those with smaller (but faster) lower color depths. One
154 // way around this is to set EGL_BUFFER_SIZE to 16, which
155 // trumps the others. Of course, there may not be a 16-bit
156 // config available, so it's the first restraint we remove.
157 i = configAttributes->indexOf(EGL_BUFFER_SIZE);
158 if (i >= 0) {
159 if (configAttributes->at(i: i+1) == 16) {
160 configAttributes->remove(i,n: 2);
161 return true;
162 }
163 }
164
165 i = configAttributes->indexOf(EGL_SAMPLES);
166 if (i >= 0) {
167 EGLint value = configAttributes->value(i: i+1, defaultValue: 0);
168 if (value > 1)
169 configAttributes->replace(i: i+1, t: qMin(a: EGLint(16), b: value / 2));
170 else
171 configAttributes->remove(i, n: 2);
172 return true;
173 }
174
175 i = configAttributes->indexOf(EGL_SAMPLE_BUFFERS);
176 if (i >= 0) {
177 configAttributes->remove(i,n: 2);
178 return true;
179 }
180
181 i = configAttributes->indexOf(EGL_DEPTH_SIZE);
182 if (i >= 0) {
183 if (configAttributes->at(i: i + 1) >= 32)
184 configAttributes->replace(i: i + 1, t: 24);
185 else if (configAttributes->at(i: i + 1) > 1)
186 configAttributes->replace(i: i + 1, t: 1);
187 else
188 configAttributes->remove(i, n: 2);
189 return true;
190 }
191
192 i = configAttributes->indexOf(EGL_ALPHA_SIZE);
193 if (i >= 0) {
194 configAttributes->remove(i,n: 2);
195#if defined(EGL_BIND_TO_TEXTURE_RGBA) && defined(EGL_BIND_TO_TEXTURE_RGB)
196 i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGBA);
197 if (i >= 0) {
198 configAttributes->replace(i,EGL_BIND_TO_TEXTURE_RGB);
199 configAttributes->replace(i: i+1,t: true);
200
201 }
202#endif
203 return true;
204 }
205
206 i = configAttributes->indexOf(EGL_STENCIL_SIZE);
207 if (i >= 0) {
208 if (configAttributes->at(i: i + 1) > 1)
209 configAttributes->replace(i: i + 1, t: 1);
210 else
211 configAttributes->remove(i, n: 2);
212 return true;
213 }
214
215#ifdef EGL_BIND_TO_TEXTURE_RGB
216 i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGB);
217 if (i >= 0) {
218 configAttributes->remove(i,n: 2);
219 return true;
220 }
221#endif
222
223 return false;
224}
225
226QEglConfigChooser::QEglConfigChooser(EGLDisplay display)
227 : m_display(display)
228 , m_surfaceType(EGL_WINDOW_BIT)
229 , m_ignore(false)
230 , m_confAttrRed(0)
231 , m_confAttrGreen(0)
232 , m_confAttrBlue(0)
233 , m_confAttrAlpha(0)
234{
235}
236
237QEglConfigChooser::~QEglConfigChooser()
238{
239}
240
241EGLConfig QEglConfigChooser::chooseConfig()
242{
243 QVector<EGLint> configureAttributes = q_createConfigAttributesFromFormat(format: m_format);
244 configureAttributes.append(EGL_SURFACE_TYPE);
245 configureAttributes.append(t: surfaceType());
246
247 configureAttributes.append(EGL_RENDERABLE_TYPE);
248 bool needsES2Plus = false;
249 switch (m_format.renderableType()) {
250 case QSurfaceFormat::OpenVG:
251 configureAttributes.append(EGL_OPENVG_BIT);
252 break;
253#ifdef EGL_VERSION_1_4
254 case QSurfaceFormat::DefaultRenderableType:
255#ifndef QT_NO_OPENGL
256 if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL)
257 configureAttributes.append(EGL_OPENGL_BIT);
258 else
259#endif // QT_NO_OPENGL
260 needsES2Plus = true;
261 break;
262 case QSurfaceFormat::OpenGL:
263 configureAttributes.append(EGL_OPENGL_BIT);
264 break;
265#endif
266 case QSurfaceFormat::OpenGLES:
267 if (m_format.majorVersion() == 1) {
268 configureAttributes.append(EGL_OPENGL_ES_BIT);
269 break;
270 }
271 Q_FALLTHROUGH();
272 default:
273 needsES2Plus = true;
274 break;
275 }
276 if (needsES2Plus) {
277 if (m_format.majorVersion() >= 3 && q_hasEglExtension(display: display(), extensionName: "EGL_KHR_create_context"))
278 configureAttributes.append(EGL_OPENGL_ES3_BIT_KHR);
279 else
280 configureAttributes.append(EGL_OPENGL_ES2_BIT);
281 }
282 configureAttributes.append(EGL_NONE);
283
284 EGLConfig cfg = nullptr;
285 do {
286 // Get the number of matching configurations for this set of properties.
287 EGLint matching = 0;
288 if (!eglChooseConfig(dpy: display(), attrib_list: configureAttributes.constData(), configs: nullptr, config_size: 0, num_config: &matching) || !matching)
289 continue;
290
291 // Fetch all of the matching configurations and find the
292 // first that matches the pixel format we wanted.
293 int i = configureAttributes.indexOf(EGL_RED_SIZE);
294 m_confAttrRed = configureAttributes.at(i: i+1);
295 i = configureAttributes.indexOf(EGL_GREEN_SIZE);
296 m_confAttrGreen = configureAttributes.at(i: i+1);
297 i = configureAttributes.indexOf(EGL_BLUE_SIZE);
298 m_confAttrBlue = configureAttributes.at(i: i+1);
299 i = configureAttributes.indexOf(EGL_ALPHA_SIZE);
300 m_confAttrAlpha = i == -1 ? 0 : configureAttributes.at(i: i+1);
301
302 QVector<EGLConfig> configs(matching);
303 eglChooseConfig(dpy: display(), attrib_list: configureAttributes.constData(), configs: configs.data(), config_size: configs.size(), num_config: &matching);
304 if (!cfg && matching > 0)
305 cfg = configs.first();
306
307 // Filter the list. Due to the EGL sorting rules configs with higher depth are
308 // placed first when the minimum color channel sizes have been specified (i.e. the
309 // QSurfaceFormat contains color sizes > 0). To prevent returning a 888 config
310 // when the QSurfaceFormat explicitly asked for 565, go through the returned
311 // configs and look for one that exactly matches the requested sizes. When no
312 // sizes have been given, take the first, which will be a config with the smaller
313 // (e.g. 16-bit) depth.
314 for (int i = 0; i < configs.size(); ++i) {
315 if (filterConfig(config: configs[i]))
316 return configs.at(i);
317 }
318 } while (q_reduceConfigAttributes(configAttributes: &configureAttributes));
319
320 if (!cfg)
321 qWarning(msg: "Cannot find EGLConfig, returning null config");
322 return cfg;
323}
324
325bool QEglConfigChooser::filterConfig(EGLConfig config) const
326{
327 // If we are fine with the highest depth (e.g. RGB888 configs) even when something
328 // smaller (565) was explicitly requested, do nothing.
329 if (m_ignore)
330 return true;
331
332 EGLint red = 0;
333 EGLint green = 0;
334 EGLint blue = 0;
335 EGLint alpha = 0;
336
337 // Compare only if a size was given. Otherwise just accept.
338 if (m_confAttrRed)
339 eglGetConfigAttrib(dpy: display(), config, EGL_RED_SIZE, value: &red);
340 if (m_confAttrGreen)
341 eglGetConfigAttrib(dpy: display(), config, EGL_GREEN_SIZE, value: &green);
342 if (m_confAttrBlue)
343 eglGetConfigAttrib(dpy: display(), config, EGL_BLUE_SIZE, value: &blue);
344 if (m_confAttrAlpha)
345 eglGetConfigAttrib(dpy: display(), config, EGL_ALPHA_SIZE, value: &alpha);
346
347 return red == m_confAttrRed && green == m_confAttrGreen
348 && blue == m_confAttrBlue && alpha == m_confAttrAlpha;
349}
350
351EGLConfig q_configFromGLFormat(EGLDisplay display, const QSurfaceFormat &format, bool highestPixelFormat, int surfaceType)
352{
353 QEglConfigChooser chooser(display);
354 chooser.setSurfaceFormat(format);
355 chooser.setSurfaceType(surfaceType);
356 chooser.setIgnoreColorChannels(highestPixelFormat);
357
358 return chooser.chooseConfig();
359}
360
361QSurfaceFormat q_glFormatFromConfig(EGLDisplay display, const EGLConfig config, const QSurfaceFormat &referenceFormat)
362{
363 QSurfaceFormat format;
364 EGLint redSize = 0;
365 EGLint greenSize = 0;
366 EGLint blueSize = 0;
367 EGLint alphaSize = 0;
368 EGLint depthSize = 0;
369 EGLint stencilSize = 0;
370 EGLint sampleCount = 0;
371 EGLint renderableType = 0;
372
373 eglGetConfigAttrib(dpy: display, config, EGL_RED_SIZE, value: &redSize);
374 eglGetConfigAttrib(dpy: display, config, EGL_GREEN_SIZE, value: &greenSize);
375 eglGetConfigAttrib(dpy: display, config, EGL_BLUE_SIZE, value: &blueSize);
376 eglGetConfigAttrib(dpy: display, config, EGL_ALPHA_SIZE, value: &alphaSize);
377 eglGetConfigAttrib(dpy: display, config, EGL_DEPTH_SIZE, value: &depthSize);
378 eglGetConfigAttrib(dpy: display, config, EGL_STENCIL_SIZE, value: &stencilSize);
379 eglGetConfigAttrib(dpy: display, config, EGL_SAMPLES, value: &sampleCount);
380 eglGetConfigAttrib(dpy: display, config, EGL_RENDERABLE_TYPE, value: &renderableType);
381
382 if (referenceFormat.renderableType() == QSurfaceFormat::OpenVG && (renderableType & EGL_OPENVG_BIT))
383 format.setRenderableType(QSurfaceFormat::OpenVG);
384#ifdef EGL_VERSION_1_4
385 else if (referenceFormat.renderableType() == QSurfaceFormat::OpenGL
386 && (renderableType & EGL_OPENGL_BIT))
387 format.setRenderableType(QSurfaceFormat::OpenGL);
388 else if (referenceFormat.renderableType() == QSurfaceFormat::DefaultRenderableType
389#ifndef QT_NO_OPENGL
390 && QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL
391#endif
392 && (renderableType & EGL_OPENGL_BIT))
393 format.setRenderableType(QSurfaceFormat::OpenGL);
394#endif
395 else
396 format.setRenderableType(QSurfaceFormat::OpenGLES);
397
398 format.setRedBufferSize(redSize);
399 format.setGreenBufferSize(greenSize);
400 format.setBlueBufferSize(blueSize);
401 format.setAlphaBufferSize(alphaSize);
402 format.setDepthBufferSize(depthSize);
403 format.setStencilBufferSize(stencilSize);
404 format.setSamples(sampleCount);
405 format.setStereo(false); // EGL doesn't support stereo buffers
406 format.setSwapInterval(referenceFormat.swapInterval());
407
408 // Clear the EGL error state because some of the above may
409 // have errored out because the attribute is not applicable
410 // to the surface type. Such errors don't matter.
411 eglGetError();
412
413 return format;
414}
415
416bool q_hasEglExtension(EGLDisplay display, const char* extensionName)
417{
418 QList<QByteArray> extensions =
419 QByteArray(reinterpret_cast<const char *>
420 (eglQueryString(dpy: display, EGL_EXTENSIONS))).split(sep: ' ');
421 return extensions.contains(t: extensionName);
422}
423
424struct AttrInfo { EGLint attr; const char *name; };
425static struct AttrInfo attrs[] = {
426 {EGL_BUFFER_SIZE, .name: "EGL_BUFFER_SIZE"},
427 {EGL_ALPHA_SIZE, .name: "EGL_ALPHA_SIZE"},
428 {EGL_BLUE_SIZE, .name: "EGL_BLUE_SIZE"},
429 {EGL_GREEN_SIZE, .name: "EGL_GREEN_SIZE"},
430 {EGL_RED_SIZE, .name: "EGL_RED_SIZE"},
431 {EGL_DEPTH_SIZE, .name: "EGL_DEPTH_SIZE"},
432 {EGL_STENCIL_SIZE, .name: "EGL_STENCIL_SIZE"},
433 {EGL_CONFIG_CAVEAT, .name: "EGL_CONFIG_CAVEAT"},
434 {EGL_CONFIG_ID, .name: "EGL_CONFIG_ID"},
435 {EGL_LEVEL, .name: "EGL_LEVEL"},
436 {EGL_MAX_PBUFFER_HEIGHT, .name: "EGL_MAX_PBUFFER_HEIGHT"},
437 {EGL_MAX_PBUFFER_PIXELS, .name: "EGL_MAX_PBUFFER_PIXELS"},
438 {EGL_MAX_PBUFFER_WIDTH, .name: "EGL_MAX_PBUFFER_WIDTH"},
439 {EGL_NATIVE_RENDERABLE, .name: "EGL_NATIVE_RENDERABLE"},
440 {EGL_NATIVE_VISUAL_ID, .name: "EGL_NATIVE_VISUAL_ID"},
441 {EGL_NATIVE_VISUAL_TYPE, .name: "EGL_NATIVE_VISUAL_TYPE"},
442 {EGL_SAMPLES, .name: "EGL_SAMPLES"},
443 {EGL_SAMPLE_BUFFERS, .name: "EGL_SAMPLE_BUFFERS"},
444 {EGL_SURFACE_TYPE, .name: "EGL_SURFACE_TYPE"},
445 {EGL_TRANSPARENT_TYPE, .name: "EGL_TRANSPARENT_TYPE"},
446 {EGL_TRANSPARENT_BLUE_VALUE, .name: "EGL_TRANSPARENT_BLUE_VALUE"},
447 {EGL_TRANSPARENT_GREEN_VALUE, .name: "EGL_TRANSPARENT_GREEN_VALUE"},
448 {EGL_TRANSPARENT_RED_VALUE, .name: "EGL_TRANSPARENT_RED_VALUE"},
449 {EGL_BIND_TO_TEXTURE_RGB, .name: "EGL_BIND_TO_TEXTURE_RGB"},
450 {EGL_BIND_TO_TEXTURE_RGBA, .name: "EGL_BIND_TO_TEXTURE_RGBA"},
451 {EGL_MIN_SWAP_INTERVAL, .name: "EGL_MIN_SWAP_INTERVAL"},
452 {EGL_MAX_SWAP_INTERVAL, .name: "EGL_MAX_SWAP_INTERVAL"},
453 {.attr: -1, .name: nullptr}};
454
455void q_printEglConfig(EGLDisplay display, EGLConfig config)
456{
457 EGLint index;
458 for (index = 0; attrs[index].attr != -1; ++index) {
459 EGLint value;
460 if (eglGetConfigAttrib(dpy: display, config, attribute: attrs[index].attr, value: &value)) {
461 qDebug(msg: "\t%s: %d", attrs[index].name, (int)value);
462 }
463 }
464}
465
466#ifdef Q_OS_UNIX
467
468QSizeF q_physicalScreenSizeFromFb(int framebufferDevice, const QSize &screenSize)
469{
470#ifndef Q_OS_LINUX
471 Q_UNUSED(framebufferDevice)
472#endif
473 const int defaultPhysicalDpi = 100;
474 static QSizeF size;
475
476 if (size.isEmpty()) {
477 // Note: in millimeters
478 int width = qEnvironmentVariableIntValue(varName: "QT_QPA_EGLFS_PHYSICAL_WIDTH");
479 int height = qEnvironmentVariableIntValue(varName: "QT_QPA_EGLFS_PHYSICAL_HEIGHT");
480
481 if (width && height) {
482 size.setWidth(width);
483 size.setHeight(height);
484 return size;
485 }
486
487 int w = -1;
488 int h = -1;
489 QSize screenResolution;
490#ifdef Q_OS_LINUX
491 struct fb_var_screeninfo vinfo;
492
493 if (framebufferDevice != -1) {
494 if (ioctl(fd: framebufferDevice, FBIOGET_VSCREENINFO, &vinfo) == -1) {
495 qWarning(msg: "eglconvenience: Could not query screen info");
496 } else {
497 w = vinfo.width;
498 h = vinfo.height;
499 screenResolution = QSize(vinfo.xres, vinfo.yres);
500 }
501 } else
502#endif
503 {
504 // Use the provided screen size, when available, since some platforms may have their own
505 // specific way to query it. Otherwise try querying it from the framebuffer.
506 screenResolution = screenSize.isEmpty() ? q_screenSizeFromFb(framebufferDevice) : screenSize;
507 }
508
509 size.setWidth(w <= 0 ? screenResolution.width() * Q_MM_PER_INCH / defaultPhysicalDpi : qreal(w));
510 size.setHeight(h <= 0 ? screenResolution.height() * Q_MM_PER_INCH / defaultPhysicalDpi : qreal(h));
511
512 if (w <= 0 || h <= 0)
513 qWarning(msg: "Unable to query physical screen size, defaulting to %d dpi.\n"
514 "To override, set QT_QPA_EGLFS_PHYSICAL_WIDTH "
515 "and QT_QPA_EGLFS_PHYSICAL_HEIGHT (in millimeters).", defaultPhysicalDpi);
516 }
517
518 return size;
519}
520
521QSize q_screenSizeFromFb(int framebufferDevice)
522{
523#ifndef Q_OS_LINUX
524 Q_UNUSED(framebufferDevice)
525#endif
526 const int defaultWidth = 800;
527 const int defaultHeight = 600;
528 static QSize size;
529
530 if (size.isEmpty()) {
531 int width = qEnvironmentVariableIntValue(varName: "QT_QPA_EGLFS_WIDTH");
532 int height = qEnvironmentVariableIntValue(varName: "QT_QPA_EGLFS_HEIGHT");
533
534 if (width && height) {
535 size.setWidth(width);
536 size.setHeight(height);
537 return size;
538 }
539
540#ifdef Q_OS_LINUX
541 struct fb_var_screeninfo vinfo;
542 int xres = -1;
543 int yres = -1;
544
545 if (framebufferDevice != -1) {
546 if (ioctl(fd: framebufferDevice, FBIOGET_VSCREENINFO, &vinfo) == -1) {
547 qWarning(msg: "eglconvenience: Could not read screen info");
548 } else {
549 xres = vinfo.xres;
550 yres = vinfo.yres;
551 }
552 }
553
554 size.setWidth(xres <= 0 ? defaultWidth : xres);
555 size.setHeight(yres <= 0 ? defaultHeight : yres);
556#else
557 size.setWidth(defaultWidth);
558 size.setHeight(defaultHeight);
559#endif
560 }
561
562 return size;
563}
564
565int q_screenDepthFromFb(int framebufferDevice)
566{
567#ifndef Q_OS_LINUX
568 Q_UNUSED(framebufferDevice)
569#endif
570 const int defaultDepth = 32;
571 static int depth = qEnvironmentVariableIntValue(varName: "QT_QPA_EGLFS_DEPTH");
572
573 if (depth == 0) {
574#ifdef Q_OS_LINUX
575 struct fb_var_screeninfo vinfo;
576
577 if (framebufferDevice != -1) {
578 if (ioctl(fd: framebufferDevice, FBIOGET_VSCREENINFO, &vinfo) == -1)
579 qWarning(msg: "eglconvenience: Could not query screen info");
580 else
581 depth = vinfo.bits_per_pixel;
582 }
583
584 if (depth <= 0)
585 depth = defaultDepth;
586#else
587 depth = defaultDepth;
588#endif
589 }
590
591 return depth;
592}
593
594qreal q_refreshRateFromFb(int framebufferDevice)
595{
596#ifndef Q_OS_LINUX
597 Q_UNUSED(framebufferDevice)
598#endif
599
600 static qreal rate = 0;
601
602#ifdef Q_OS_LINUX
603 if (rate == 0) {
604 if (framebufferDevice != -1) {
605 struct fb_var_screeninfo vinfo;
606 if (ioctl(fd: framebufferDevice, FBIOGET_VSCREENINFO, &vinfo) != -1) {
607 const quint64 quot = quint64(vinfo.left_margin + vinfo.right_margin + vinfo.xres + vinfo.hsync_len)
608 * quint64(vinfo.upper_margin + vinfo.lower_margin + vinfo.yres + vinfo.vsync_len)
609 * vinfo.pixclock;
610 if (quot)
611 rate = 1000000000000LLU / quot;
612 } else {
613 qWarning(msg: "eglconvenience: Could not query screen info");
614 }
615 }
616 }
617#endif
618
619 if (rate == 0)
620 rate = 60;
621
622 return rate;
623}
624
625#endif // Q_OS_UNIX
626
627QT_END_NAMESPACE
628

source code of qtbase/src/platformsupport/eglconvenience/qeglconvenience.cpp