Qt 6.x
The Qt SDK
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
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
24{
26 format.setAlphaBufferSize(8);
27 return format;
28}
29
31{
32 return EGL_STREAM_BIT_KHR;
33}
34
36{
37 qCDebug(qLcEglfsKmsDebug, "Creating display");
38
40
41 if (m_funcs->has_egl_platform_device) {
42 display = m_funcs->get_platform_display(EGL_PLATFORM_DEVICE_EXT, nativeDisplay, nullptr);
43 } else {
44 qWarning("EGL_EXT_platform_device not available, falling back to legacy path!");
45 display = eglGetDisplay(nativeDisplay);
46 }
47
48 if (Q_UNLIKELY(display == EGL_NO_DISPLAY))
49 qFatal("Could not get EGL display");
50
51 EGLint major, minor;
52 if (Q_UNLIKELY(!eglInitialize(display, &major, &minor)))
53 qFatal("Could not initialize egl display");
54
55 if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_ES_API)))
56 qFatal("Failed to bind EGL_OPENGL_ES_API\n");
57
58 return display;
59}
60
62{
63 // Returning false disables the usage of EGL_KHR_surfaceless_context even when the
64 // extension is available. This is just what we need since, at least with NVIDIA
65 // 352.00 making a null surface current with a context breaks.
66 return false;
67}
68
70{
71 return true;
72}
73
75{
76public:
79 , m_integration(integration)
81 { }
82
84
85 void invalidateSurface() override;
86 void resetSurface() override;
87
90 EGLint m_latency;
91};
92
94{
97}
98
100{
101 qCDebug(qLcEglfsKmsDebug, "Creating stream");
102
104 EGLint streamAttribs[3];
105 int streamAttribCount = 0;
106 int fifoLength = qEnvironmentVariableIntValue("QT_QPA_EGLFS_STREAM_FIFO_LENGTH");
107 if (fifoLength > 0) {
108 streamAttribs[streamAttribCount++] = EGL_STREAM_FIFO_LENGTH_KHR;
109 streamAttribs[streamAttribCount++] = fifoLength;
110 }
111 streamAttribs[streamAttribCount++] = EGL_NONE;
112
113 m_egl_stream = m_integration->m_funcs->create_stream(display, streamAttribs);
115 qWarning("resetSurface: Couldn't create EGLStream for native window");
116 return;
117 }
118
119 qCDebug(qLcEglfsKmsDebug, "Created stream %p on display %p", m_egl_stream, display);
120
121 EGLint count;
123 if (count > 0)
124 qCDebug(qLcEglfsKmsDebug, "Using EGLStream FIFO mode with %d frames", count);
125 else
126 qCDebug(qLcEglfsKmsDebug, "Using EGLStream mailbox mode");
127 } else {
128 qCDebug(qLcEglfsKmsDebug, "Could not query number of EGLStream FIFO frames");
129 }
130
131 if (!m_integration->m_funcs->get_output_layers(display, nullptr, nullptr, 0, &count) || count == 0) {
132 qWarning("No output layers found");
133 return;
134 }
135
136 qCDebug(qLcEglfsKmsDebug, "Output has %d layers", count);
137
139 layers.resize(count);
140 EGLint actualCount;
141 if (!m_integration->m_funcs->get_output_layers(display, nullptr, layers.data(), count, &actualCount)) {
142 qWarning("Failed to get layers");
143 return;
144 }
145
146 QEglFSKmsEglDeviceScreen *cur_screen = static_cast<QEglFSKmsEglDeviceScreen *>(screen());
147 Q_ASSERT(cur_screen);
148 QKmsOutput &output(cur_screen->output());
149 const uint32_t wantedId = !output.wants_forced_plane ? output.crtc_id : output.forced_plane_id;
150 qCDebug(qLcEglfsKmsDebug, "Searching for id: %d", wantedId);
151
153 for (int i = 0; i < actualCount; ++i) {
156 qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - crtc %d", i, layers[i], (int) id);
157 if (id == EGLAttrib(wantedId))
158 layer = layers[i];
160 qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - plane %d", i, layers[i], (int) id);
161 if (id == EGLAttrib(wantedId))
162 layer = layers[i];
163 } else {
164 qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - unknown", i, layers[i]);
165 }
166 }
167
168 QByteArray reqLayerIndex = qgetenv("QT_QPA_EGLFS_LAYER_INDEX");
169 if (!reqLayerIndex.isEmpty()) {
170 int idx = reqLayerIndex.toInt();
171 if (idx >= 0 && idx < layers.size()) {
172 qCDebug(qLcEglfsKmsDebug, "EGLOutput layer index override = %d", idx);
173 layer = layers[idx];
174 }
175 }
176
178 qWarning("resetSurface: Couldn't get EGLOutputLayer for native window");
179 return;
180 }
181
182 qCDebug(qLcEglfsKmsDebug, "Using layer %p", layer);
183
185 qWarning("resetSurface: Unable to connect stream");
186
189 qCDebug(qLcEglfsKmsDebug) << "Stream producer format is" << m_format;
190
191 const int w = cur_screen->rawGeometry().width();
192 const int h = cur_screen->rawGeometry().height();
193 qCDebug(qLcEglfsKmsDebug, "Creating stream producer surface of size %dx%d", w, h);
194
195 const EGLint stream_producer_attribs[] = {
196 EGL_WIDTH, w,
197 EGL_HEIGHT, h,
198 EGL_NONE
199 };
200
202 if (m_surface == EGL_NO_SURFACE)
203 return;
204
205 qCDebug(qLcEglfsKmsDebug, "Created stream producer surface %p", m_surface);
206}
207
209{
211
212 m_funcs->initialize(eglWindow->screen()->display());
213 if (Q_UNLIKELY(!(m_funcs->has_egl_output_base && m_funcs->has_egl_output_drm && m_funcs->has_egl_stream &&
215 qFatal("Required extensions missing!");
216
217 return eglWindow;
218}
219
221{
222 if (Q_UNLIKELY(!query_egl_device()))
223 qFatal("Could not set up EGL device!");
224
225 const char *deviceName = m_funcs->query_device_string(m_egl_device, EGL_DRM_DEVICE_FILE_EXT);
226 if (Q_UNLIKELY(!deviceName))
227 qFatal("Failed to query device name from EGLDevice");
228
229 return new QEglFSKmsEglDevice(this, screenConfig(), QLatin1StringView(deviceName));
230}
231
232bool QEglFSKmsEglDeviceIntegration::query_egl_device()
233{
234 m_funcs = new QEGLStreamConvenience;
235 if (Q_UNLIKELY(!m_funcs->has_egl_device_base))
236 qFatal("EGL_EXT_device_base missing");
237
238 EGLint num_devices = 0;
239 if (m_funcs->query_devices(1, &m_egl_device, &num_devices) != EGL_TRUE) {
240 qWarning("eglQueryDevicesEXT failed: eglError: %x", eglGetError());
241 return false;
242 }
243
244 qCDebug(qLcEglfsKmsDebug, "Found %d EGL devices", num_devices);
245
246 if (num_devices < 1 || m_egl_device == EGL_NO_DEVICE_EXT) {
247 qWarning("eglQueryDevicesEXT could not find any EGL devices");
248 return false;
249 }
250
251 return true;
252}
253
255{
256#if QT_CONFIG(opengl)
257 if (screenConfig()->separateScreens())
258 return new QEglFSCursor(screen);
259#else
261#endif
262 return nullptr;
263}
264
\inmodule QtCore
Definition qbytearray.h:57
int toInt(bool *ok=nullptr, int base=10) const
Returns the byte array converted to an int using base base, which is ten by default.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
void initialize(EGLDisplay dpy)
PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC query_output_layer_attrib
PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC create_stream_producer_surface
PFNEGLQUERYSTREAMKHRPROC query_stream
PFNEGLCREATESTREAMKHRPROC create_stream
PFNEGLGETOUTPUTLAYERSEXTPROC get_output_layers
PFNEGLDESTROYSTREAMKHRPROC destroy_stream
PFNEGLQUERYDEVICESTRINGEXTPROC query_device_string
PFNEGLQUERYDEVICESEXTPROC query_devices
PFNEGLSTREAMCONSUMEROUTPUTEXTPROC stream_consumer_output
PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display
static EGLConfig chooseConfig(EGLDisplay display, const QSurfaceFormat &format)
EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay) override
QEglFSWindow * createWindow(QWindow *window) const override
QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const override
QPlatformCursor * createCursor(QPlatformScreen *screen) const override
void invalidateSurface() override
Invalidates the window's surface by releasing its surface buffers.
QEglFSKmsEglDeviceWindow(QWindow *w, const QEglFSKmsEglDeviceIntegration *integration)
const QEglFSKmsEglDeviceIntegration * m_integration
QKmsScreenConfig * screenConfig() const
QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const override
QKmsOutput & output()
QRect rawGeometry() const override
EGLDisplay display() const
EGLSurface m_surface
EGLConfig m_config
void invalidateSurface() override
Invalidates the window's surface by releasing its surface buffers.
QSurfaceFormat m_format
QEglFSScreen * screen() const override
Definition qlist.h:74
The QPlatformCursor class provides information about pointer device events (movement,...
The QPlatformScreen class provides an abstraction for visual displays.
QWindow * window() const
Returns the window which belongs to the QPlatformWindow.
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:238
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:235
The QSurfaceFormat class represents the format of a QSurface. \inmodule QtGui.
\inmodule QtGui
Definition qwindow.h:63
struct wl_display * display
Definition linuxdmabuf.h:41
Combined button and popup list for selecting options.
#define Q_UNLIKELY(x)
QSurfaceFormat q_glFormatFromConfig(EGLDisplay display, const EGLConfig config, const QSurfaceFormat &referenceFormat)
#define EGL_NO_DEVICE_EXT
#define EGL_DRM_PLANE_EXT
#define EGL_DRM_DEVICE_FILE_EXT
#define EGL_STREAM_BIT_KHR
void * EGLOutputLayerEXT
EGLDeviceEXT EGLint * num_devices
#define EGL_STREAM_FIFO_LENGTH_KHR
intptr_t EGLAttrib
#define EGL_NO_OUTPUT_LAYER_EXT
typedef EGLDisplay(EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC)(EGLenum platform
const EGLAttrib EGLOutputLayerEXT * layers
#define EGL_PLATFORM_DEVICE_EXT
EGLOutputLayerEXT layer
#define EGL_NO_STREAM_KHR
void * EGLStreamKHR
#define EGL_DRM_CRTC_EXT
#define qWarning
Definition qlogging.h:162
#define qFatal
Definition qlogging.h:164
#define qCDebug(category,...)
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint id
[7]
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum format
GLfloat GLfloat GLfloat GLfloat h
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QScreen * screen
[1]
Definition main.cpp:29
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define Q_UNUSED(x)
QT_BEGIN_NAMESPACE typedef uchar * output
QObject::connect nullptr
aWidget window() -> setWindowTitle("New Window Title")
[2]