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
6#include "qeglfskmsgbmdevice_p.h"
7#include "qeglfskmsgbmscreen_p.h"
8
9#include <private/qeglfsintegration_p.h>
10#include <private/qeglfskmsintegration_p.h>
11
12#include <QtCore/QLoggingCategory>
13#include <QtCore/private/qcore_unix_p.h>
14
15#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
16
17QT_BEGIN_NAMESPACE
18
19QEglFSKmsGbmDevice::QEglFSKmsGbmDevice(QKmsScreenConfig *screenConfig, const QString &path)
20 : QEglFSKmsDevice(screenConfig, path)
21 , m_gbm_device(nullptr)
22 , m_globalCursor(nullptr)
23{
24}
25
26bool QEglFSKmsGbmDevice::open()
27{
28 Q_ASSERT(fd() == -1);
29 Q_ASSERT(m_gbm_device == nullptr);
30
31 int fd = qt_safe_open(pathname: devicePath().toLocal8Bit().constData(), O_RDWR | O_CLOEXEC);
32 if (fd == -1) {
33 qErrnoWarning(msg: "Could not open DRM device %s", qPrintable(devicePath()));
34 return false;
35 }
36
37 qCDebug(qLcEglfsKmsDebug) << "Creating GBM device for file descriptor" << fd
38 << "obtained from" << devicePath();
39 m_gbm_device = gbm_create_device(fd);
40 if (!m_gbm_device) {
41 qErrnoWarning(msg: "Could not create GBM device");
42 qt_safe_close(fd);
43 fd = -1;
44 return false;
45 }
46
47 setFd(fd);
48
49 if (usesEventReader()) {
50 qCDebug(qLcEglfsKmsDebug, "Using dedicated drm event reading thread");
51 m_eventReader.create(device: this);
52 } else {
53 qCDebug(qLcEglfsKmsDebug, "Not using dedicated drm event reading thread; "
54 "threaded multi-screen setups may experience problems");
55 }
56
57 return true;
58}
59
60void QEglFSKmsGbmDevice::close()
61{
62 // Note: screens are gone at this stage.
63
64 if (usesEventReader())
65 m_eventReader.destroy();
66
67 if (m_gbm_device) {
68 gbm_device_destroy(gbm: m_gbm_device);
69 m_gbm_device = nullptr;
70 }
71
72 if (fd() != -1) {
73 qt_safe_close(fd: fd());
74 setFd(-1);
75 }
76}
77
78void *QEglFSKmsGbmDevice::nativeDisplay() const
79{
80 return m_gbm_device;
81}
82
83gbm_device * QEglFSKmsGbmDevice::gbmDevice() const
84{
85 return m_gbm_device;
86}
87
88QPlatformCursor *QEglFSKmsGbmDevice::globalCursor() const
89{
90 return m_globalCursor;
91}
92
93// Cannot do this from close(), it may be too late.
94// Call this from the last screen dtor instead.
95void QEglFSKmsGbmDevice::destroyGlobalCursor()
96{
97 if (m_globalCursor) {
98 qCDebug(qLcEglfsKmsDebug, "Destroying global GBM mouse cursor");
99 delete m_globalCursor;
100 m_globalCursor = nullptr;
101 }
102}
103
104void QEglFSKmsGbmDevice::createGlobalCursor(QEglFSKmsGbmScreen *screen)
105{
106 if (!m_globalCursor && screenConfig()->hwCursor()) {
107 qCDebug(qLcEglfsKmsDebug, "Creating new global GBM mouse cursor");
108 m_globalCursor = new QEglFSKmsGbmCursor(screen);
109 }
110}
111
112QPlatformScreen *QEglFSKmsGbmDevice::createScreen(const QKmsOutput &output)
113{
114 QEglFSKmsGbmScreen *screen = new QEglFSKmsGbmScreen(this, output, false);
115
116 createGlobalCursor(screen);
117
118 return screen;
119}
120
121QPlatformScreen *QEglFSKmsGbmDevice::createHeadlessScreen()
122{
123 return new QEglFSKmsGbmScreen(this, QKmsOutput(), true);
124}
125
126void QEglFSKmsGbmDevice::registerScreenCloning(QPlatformScreen *screen,
127 QPlatformScreen *screenThisScreenClones,
128 const QList<QPlatformScreen *> &screensCloningThisScreen)
129{
130 if (!screenThisScreenClones && screensCloningThisScreen.isEmpty())
131 return;
132
133 QEglFSKmsGbmScreen *gbmScreen = static_cast<QEglFSKmsGbmScreen *>(screen);
134 gbmScreen->initCloning(screenThisScreenClones, screensCloningThisScreen);
135}
136
137void QEglFSKmsGbmDevice::registerScreen(QPlatformScreen *screen,
138 bool isPrimary,
139 const QPoint &virtualPos,
140 const QList<QPlatformScreen *> &virtualSiblings)
141{
142 QEglFSKmsDevice::registerScreen(screen, isPrimary, virtualPos, virtualSiblings);
143 if (screenConfig()->hwCursor() && m_globalCursor)
144 m_globalCursor->reevaluateVisibilityForScreens();
145}
146
147bool QEglFSKmsGbmDevice::usesEventReader() const
148{
149 static const bool eventReaderThreadDisabled = qEnvironmentVariableIntValue(varName: "QT_QPA_EGLFS_KMS_NO_EVENT_READER_THREAD");
150 return !eventReaderThreadDisabled;
151}
152
153QT_END_NAMESPACE
154

source code of qtbase/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp