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

source code of qtbase/src/gui/opengl/platform/egl/qeglconvenience.cpp