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
qeglfskmsegldeviceintegration.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Pelagicore AG
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
8#include <QtGui/private/qeglconvenience_p.h>
9#include "private/qeglfswindow_p.h"
10#include "private/qeglfscursor_p.h"
11#include <QLoggingCategory>
12#include <private/qmath_p.h>
13
15
16QEglFSKmsEglDeviceIntegration::QEglFSKmsEglDeviceIntegration()
17 : m_egl_device(EGL_NO_DEVICE_EXT)
18 , m_funcs(nullptr)
19{
20 qCDebug(qLcEglfsKmsDebug, "New DRM/KMS on EGLDevice integration created");
21}
22
23QSurfaceFormat QEglFSKmsEglDeviceIntegration::surfaceFormatFor(const QSurfaceFormat &inputFormat) const
24{
25 QSurfaceFormat format = QEglFSKmsIntegration::surfaceFormatFor(inputFormat);
26 format.setAlphaBufferSize(8);
27 return format;
28}
29
30EGLint QEglFSKmsEglDeviceIntegration::surfaceType() const
31{
32 return EGL_STREAM_BIT_KHR;
33}
34
35EGLDisplay QEglFSKmsEglDeviceIntegration::createDisplay(EGLNativeDisplayType nativeDisplay)
36{
37 qCDebug(qLcEglfsKmsDebug, "Creating display");
38
39 EGLDisplay display;
40
41 EGLint egldevice_fd = device()->fd();
42
43 const EGLint attribs[] = { EGL_DRM_MASTER_FD_EXT, egldevice_fd, EGL_NONE };
44 if (m_funcs->has_egl_platform_device) {
45 display = m_funcs->get_platform_display(EGL_PLATFORM_DEVICE_EXT, nativeDisplay, attribs);
46 } else {
47 qWarning("EGL_EXT_platform_device not available, falling back to legacy path!");
48 display = eglGetDisplay(nativeDisplay);
49 }
50
51 if (Q_UNLIKELY(display == EGL_NO_DISPLAY))
52 qFatal("Could not get EGL display");
53
54 EGLint major, minor;
55 if (Q_UNLIKELY(!eglInitialize(display, &major, &minor)))
56 qFatal("Could not initialize egl display");
57
58 if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_ES_API)))
59 qFatal("Failed to bind EGL_OPENGL_ES_API\n");
60
61 return display;
62}
63
64bool QEglFSKmsEglDeviceIntegration::supportsSurfacelessContexts() const
65{
66 // Returning false disables the usage of EGL_KHR_surfaceless_context even when the
67 // extension is available. This is just what we need since, at least with NVIDIA
68 // 352.00 making a null surface current with a context breaks.
69 return false;
70}
71
72bool QEglFSKmsEglDeviceIntegration::supportsPBuffers() const
73{
74 return true;
75}
76
78{
79public:
80 QEglFSKmsEglDeviceWindow(QWindow *w, const QEglFSKmsEglDeviceIntegration *integration)
82 , m_integration(integration)
84 { }
85
86 ~QEglFSKmsEglDeviceWindow() { destroy(); }
87
90
91 const QEglFSKmsEglDeviceIntegration *m_integration;
94};
95
97{
98 QEglFSWindow::invalidateSurface();
99 m_integration->m_funcs->destroy_stream(screen()->display(), m_egl_stream);
100}
101
103{
104 qCDebug(qLcEglfsKmsDebug, "Creating stream");
105
106 EGLDisplay display = screen()->display();
107 EGLint streamAttribs[3];
108 int streamAttribCount = 0;
109 int fifoLength = qEnvironmentVariableIntValue("QT_QPA_EGLFS_STREAM_FIFO_LENGTH");
110 if (fifoLength > 0) {
111 streamAttribs[streamAttribCount++] = EGL_STREAM_FIFO_LENGTH_KHR;
112 streamAttribs[streamAttribCount++] = fifoLength;
113 }
114 streamAttribs[streamAttribCount++] = EGL_NONE;
115
116 m_egl_stream = m_integration->m_funcs->create_stream(display, streamAttribs);
117 if (m_egl_stream == EGL_NO_STREAM_KHR) {
118 qWarning("resetSurface: Couldn't create EGLStream for native window");
119 return;
120 }
121
122 qCDebug(qLcEglfsKmsDebug, "Created stream %p on display %p", m_egl_stream, display);
123
124 EGLint count;
125 if (m_integration->m_funcs->query_stream(display, m_egl_stream, EGL_STREAM_FIFO_LENGTH_KHR, &count)) {
126 if (count > 0)
127 qCDebug(qLcEglfsKmsDebug, "Using EGLStream FIFO mode with %d frames", count);
128 else
129 qCDebug(qLcEglfsKmsDebug, "Using EGLStream mailbox mode");
130 } else {
131 qCDebug(qLcEglfsKmsDebug, "Could not query number of EGLStream FIFO frames");
132 }
133
134 if (!m_integration->m_funcs->get_output_layers(display, nullptr, nullptr, 0, &count) || count == 0) {
135 qWarning("No output layers found");
136 return;
137 }
138
139 qCDebug(qLcEglfsKmsDebug, "Output has %d layers", count);
140
141 QList<EGLOutputLayerEXT> layers;
142 layers.resize(count);
143 EGLint actualCount;
144 if (!m_integration->m_funcs->get_output_layers(display, nullptr, layers.data(), count, &actualCount)) {
145 qWarning("Failed to get layers");
146 return;
147 }
148
149 QEglFSKmsEglDeviceScreen *cur_screen = static_cast<QEglFSKmsEglDeviceScreen *>(screen());
150 Q_ASSERT(cur_screen);
151 QKmsOutput &output(cur_screen->output());
152 const uint32_t wantedId = !output.wants_forced_plane ? output.crtc_id : output.forced_plane_id;
153 qCDebug(qLcEglfsKmsDebug, "Searching for id: %d", wantedId);
154
155 EGLOutputLayerEXT layer = EGL_NO_OUTPUT_LAYER_EXT;
156 for (int i = 0; i < actualCount; ++i) {
157 EGLAttrib id;
158 if (m_integration->m_funcs->query_output_layer_attrib(display, layers[i], EGL_DRM_CRTC_EXT, &id)) {
159 qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - crtc %d", i, layers[i], (int) id);
160 if (id == EGLAttrib(wantedId))
161 layer = layers[i];
162 } else if (m_integration->m_funcs->query_output_layer_attrib(display, layers[i], EGL_DRM_PLANE_EXT, &id)) {
163 qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - plane %d", i, layers[i], (int) id);
164 if (id == EGLAttrib(wantedId))
165 layer = layers[i];
166 } else {
167 qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - unknown", i, layers[i]);
168 }
169 }
170
171 QByteArray reqLayerIndex = qgetenv("QT_QPA_EGLFS_LAYER_INDEX");
172 if (!reqLayerIndex.isEmpty()) {
173 int idx = reqLayerIndex.toInt();
174 if (idx >= 0 && idx < layers.size()) {
175 qCDebug(qLcEglfsKmsDebug, "EGLOutput layer index override = %d", idx);
176 layer = layers[idx];
177 }
178 }
179
180 if (layer == EGL_NO_OUTPUT_LAYER_EXT) {
181 qWarning("resetSurface: Couldn't get EGLOutputLayer for native window");
182 return;
183 }
184
185 qCDebug(qLcEglfsKmsDebug, "Using layer %p", layer);
186
187 if (!m_integration->m_funcs->stream_consumer_output(display, m_egl_stream, layer))
188 qWarning("resetSurface: Unable to connect stream");
189
190 m_config = QEglFSDeviceIntegration::chooseConfig(display, m_integration->surfaceFormatFor(window()->requestedFormat()));
191 m_format = q_glFormatFromConfig(display, m_config);
192 qCDebug(qLcEglfsKmsDebug) << "Stream producer format is" << m_format;
193
194 const int w = cur_screen->rawGeometry().width();
195 const int h = cur_screen->rawGeometry().height();
196 qCDebug(qLcEglfsKmsDebug, "Creating stream producer surface of size %dx%d", w, h);
197
198 const EGLint stream_producer_attribs[] = {
199 EGL_WIDTH, w,
200 EGL_HEIGHT, h,
201 EGL_NONE
202 };
203
204 m_surface = m_integration->m_funcs->create_stream_producer_surface(display, m_config, m_egl_stream, stream_producer_attribs);
205 if (m_surface == EGL_NO_SURFACE)
206 return;
207
208 qCDebug(qLcEglfsKmsDebug, "Created stream producer surface %p", m_surface);
209}
210
211QEglFSWindow *QEglFSKmsEglDeviceIntegration::createWindow(QWindow *window) const
212{
213 QEglFSKmsEglDeviceWindow *eglWindow = new QEglFSKmsEglDeviceWindow(window, this);
214
215 m_funcs->initialize(eglWindow->screen()->display());
216 if (Q_UNLIKELY(!(m_funcs->has_egl_output_base && m_funcs->has_egl_output_drm
217 && m_funcs->has_egl_stream && m_funcs->has_egl_stream_producer_eglsurface
218 && m_funcs->has_egl_stream_consumer_egloutput))) {
219 qCDebug(qLcEglfsKmsDebug, "EGL_EXTENSIONS %s",
220 eglQueryString(eglWindow->screen()->display(), EGL_EXTENSIONS));
221 qFatal("Required extensions missing!");
222 }
223
224 return eglWindow;
225}
226
227QKmsDevice *QEglFSKmsEglDeviceIntegration::createDevice()
228{
229 if (Q_UNLIKELY(!query_egl_device()))
230 qFatal("Could not set up EGL device!");
231
232 QString path = screenConfig()->devicePath();
233 if (!path.isEmpty()) {
234 qCDebug(qLcEglfsKmsDebug) << "EGLDevice: Using DRM device" << path
235 << "specified in config file";
236 } else {
237 path = QLatin1StringView(
238 m_funcs->query_device_string(m_egl_device, EGL_DRM_DEVICE_FILE_EXT));
239 if (Q_UNLIKELY(path.isEmpty()))
240 qFatal("Failed to query device name from EGLDevice");
241 }
242
243 return new QEglFSKmsEglDevice(this, screenConfig(), path);
244}
245
246bool QEglFSKmsEglDeviceIntegration::query_egl_device()
247{
248 m_funcs = new QEGLStreamConvenience;
249 if (Q_UNLIKELY(!m_funcs->has_egl_device_base))
250 qFatal("EGL_EXT_device_base missing");
251
252 EGLint num_devices = 0;
253 if (m_funcs->query_devices(1, &m_egl_device, &num_devices) != EGL_TRUE) {
254 qWarning("eglQueryDevicesEXT failed: eglError: %x", eglGetError());
255 return false;
256 }
257
258 qCDebug(qLcEglfsKmsDebug, "Found %d EGL devices", num_devices);
259
260 if (num_devices < 1 || m_egl_device == EGL_NO_DEVICE_EXT) {
261 qWarning("eglQueryDevicesEXT could not find any EGL devices");
262 return false;
263 }
264
265 return true;
266}
267
268QPlatformCursor *QEglFSKmsEglDeviceIntegration::createCursor(QPlatformScreen *screen) const
269{
270#if QT_CONFIG(opengl)
271 if (screenConfig()->separateScreens())
272 return new QEglFSCursor(screen);
273#else
274 Q_UNUSED(screen);
275#endif
276 return nullptr;
277}
278
279QT_END_NAMESPACE
const QEglFSKmsEglDeviceIntegration * m_integration
void invalidateSurface() override
Invalidates the window's surface by releasing its surface buffers.
QEglFSKmsEglDeviceWindow(QWindow *w, const QEglFSKmsEglDeviceIntegration *integration)