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
qeglfskmsgbmdevice.cpp
Go to the documentation of this file.
1// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
2// Copyright (C) 2016 The Qt Company Ltd.
3// Copyright (C) 2016 Pelagicore AG
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5// Qt-Security score:significant reason:default
6
9
10#include <private/qeglfsintegration_p.h>
11#include <private/qeglfskmsintegration_p.h>
12
13#include <QtCore/QLoggingCategory>
14#include <QtCore/qtimer.h>
15#include <QtCore/private/qcore_unix_p.h>
16
17#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
18
20
21QEglFSKmsGbmDevice::QEglFSKmsGbmDevice(QKmsScreenConfig *screenConfig, const QString &path)
22 : QEglFSKmsDevice(screenConfig, path)
23 , m_gbm_device(nullptr)
24 , m_globalCursor(nullptr)
25{
26}
27
28bool QEglFSKmsGbmDevice::open()
29{
30 Q_ASSERT(fd() == -1);
31 Q_ASSERT(m_gbm_device == nullptr);
32
33 int fd = qt_safe_open(devicePath().toLocal8Bit().constData(), O_RDWR | O_CLOEXEC);
34 if (fd == -1) {
35 qErrnoWarning("Could not open DRM device %s", qPrintable(devicePath()));
36 return false;
37 }
38
39 qCDebug(qLcEglfsKmsDebug) << "Creating GBM device for file descriptor" << fd
40 << "obtained from" << devicePath();
41 m_gbm_device = gbm_create_device(fd);
42 if (!m_gbm_device) {
43 qErrnoWarning("Could not create GBM device");
44 qt_safe_close(fd);
45 fd = -1;
46 return false;
47 }
48
49 setFd(fd);
50
51 if (usesEventReader()) {
52 qCDebug(qLcEglfsKmsDebug, "Using dedicated drm event reading thread");
53 m_eventReader.create(this);
54 } else {
55 qCDebug(qLcEglfsKmsDebug, "Not using dedicated drm event reading thread; "
56 "threaded multi-screen setups may experience problems");
57 }
58
59 return true;
60}
61
62void QEglFSKmsGbmDevice::close()
63{
64 // Note: screens are gone at this stage.
65
66 if (usesEventReader())
67 m_eventReader.destroy();
68
69 if (m_gbm_device) {
70 gbm_device_destroy(m_gbm_device);
71 m_gbm_device = nullptr;
72 }
73
74 if (fd() != -1) {
75 qt_safe_close(fd());
76 setFd(-1);
77 }
78}
79
80void *QEglFSKmsGbmDevice::nativeDisplay() const
81{
82 return m_gbm_device;
83}
84
85gbm_device * QEglFSKmsGbmDevice::gbmDevice() const
86{
87 return m_gbm_device;
88}
89
90QPlatformCursor *QEglFSKmsGbmDevice::globalCursor() const
91{
92 return m_globalCursor;
93}
94
95// Cannot do this from close(), it may be too late.
96// Call this from the last screen dtor instead.
97void QEglFSKmsGbmDevice::destroyGlobalCursor()
98{
99 if (m_globalCursor) {
100 qCDebug(qLcEglfsKmsDebug, "Destroying global GBM mouse cursor");
101 delete m_globalCursor;
102 m_globalCursor = nullptr;
103 }
104}
105
106void QEglFSKmsGbmDevice::createGlobalCursor(QEglFSKmsGbmScreen *screen)
107{
108 if (!m_globalCursor && screenConfig()->hwCursor()) {
109 qCDebug(qLcEglfsKmsDebug, "Creating new global GBM mouse cursor");
110 m_globalCursor = new QEglFSKmsGbmCursor(screen);
111 }
112}
113
114QPlatformScreen *QEglFSKmsGbmDevice::createScreen(const QKmsOutput &output)
115{
116 QEglFSKmsGbmScreen *screen = new QEglFSKmsGbmScreen(this, output, false);
117
118
119 // On some platforms (e.g. rpi4), you'll get a kernel warning/error
120 // if the cursor is created 'at the same time' as the screen is created.
121 // (drmModeMoveCursor is the specific call that causes the issue)
122 // When this issue is triggered, the screen's connector is unusable until reboot
123 //
124 // Below is a work-around (without negative implications for other platforms).
125 //
126 // interval of 0 and QMetaObject::invokeMethod (w/o Qt::QueuedConnection)
127 // do no help / will still trigger issue
128 QTimer::singleShot(1, [screen, this](){
129 createGlobalCursor(screen);
130 });
131
132 return screen;
133}
134
135QPlatformScreen *QEglFSKmsGbmDevice::createHeadlessScreen()
136{
137 destroyGlobalCursor();
138
139 return new QEglFSKmsGbmScreen(this, QKmsOutput(), true);
140}
141
142void QEglFSKmsGbmDevice::registerScreenCloning(QPlatformScreen *screen,
143 QPlatformScreen *screenThisScreenClones,
144 const QList<QPlatformScreen *> &screensCloningThisScreen)
145{
146 QEglFSKmsGbmScreen *gbmScreen = static_cast<QEglFSKmsGbmScreen *>(screen);
147 gbmScreen->initCloning(screenThisScreenClones, screensCloningThisScreen);
148}
149
150void QEglFSKmsGbmDevice::registerScreen(QPlatformScreen *screen,
151 bool isPrimary,
152 const QPoint &virtualPos,
153 const QList<QPlatformScreen *> &virtualSiblings)
154{
155 QEglFSKmsDevice::registerScreen(screen, isPrimary, virtualPos, virtualSiblings);
156 if (screenConfig()->hwCursor() && m_globalCursor)
157 m_globalCursor->reevaluateVisibilityForScreens();
158}
159
160void QEglFSKmsGbmDevice::unregisterScreen(QPlatformScreen *screen)
161{
162 // The global cursor holds a pointer to a QEglFSKmsGbmScreen.
163 // If that screen is being unregistered,
164 // this will recreate the global cursor with the first sibling screen.
165 if (m_globalCursor && screen == m_globalCursor->screen()) {
166 qCDebug(qLcEglfsKmsDebug) << "Destroying global GBM mouse cursor due to unregistering"
167 << "it's screen - will probably be recreated right away";
168 delete m_globalCursor;
169 m_globalCursor = nullptr;
170
171 QList<QPlatformScreen *> siblings = screen->virtualSiblings();
172 siblings.removeOne(screen);
173 if (siblings.count() > 0) {
174 QEglFSKmsGbmScreen *kmsScreen = static_cast<QEglFSKmsGbmScreen *>(siblings.first());
175 m_globalCursor = new QEglFSKmsGbmCursor(kmsScreen);
176 qCDebug(qLcEglfsKmsDebug) << "Creating new global GBM mouse cursor on sibling screen";
177 } else {
178 qCWarning(qLcEglfsKmsDebug) << "Couldn't find a sibling to recreate"
179 << "the GBM mouse cursor - it might vanish";
180 }
181 }
182
183 QEglFSKmsDevice::unregisterScreen(screen);
184}
185
186bool QEglFSKmsGbmDevice::usesEventReader() const
187{
188 static const bool eventReaderThreadDisabled = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_NO_EVENT_READER_THREAD");
189 return !eventReaderThreadDisabled;
190}
191
192QT_END_NAMESPACE
Combined button and popup list for selecting options.