1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Copyright (C) 2016 Pelagicore AG
5 ** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
6 ** Contact: https://www.qt.io/licensing/
7 **
8 ** This file is part of the plugins of the Qt Toolkit.
9 **
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** Commercial License Usage
12 ** Licensees holding valid commercial Qt licenses may use this file in
13 ** accordance with the commercial license agreement provided with the
14 ** Software or, alternatively, in accordance with the terms contained in
15 ** a written agreement between you and The Qt Company. For licensing terms
16 ** and conditions see https://www.qt.io/terms-conditions. For further
17 ** information use the contact form at https://www.qt.io/contact-us.
18 **
19 ** GNU Lesser General Public License Usage
20 ** Alternatively, this file may be used under the terms of the GNU Lesser
21 ** General Public License version 3 as published by the Free Software
22 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
23 ** packaging of this file. Please review the following information to
24 ** ensure the GNU Lesser General Public License version 3 requirements
25 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
26 **
27 ** GNU General Public License Usage
28 ** Alternatively, this file may be used under the terms of the GNU
29 ** General Public License version 2.0 or (at your option) the GNU General
30 ** Public license version 3 or any later version approved by the KDE Free
31 ** Qt Foundation. The licenses are as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
33 ** included in the packaging of this file. Please review the following
34 ** information to ensure the GNU General Public License requirements will
35 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
36 ** https://www.gnu.org/licenses/gpl-3.0.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #ifndef QKMSDEVICE_P_H
43 #define QKMSDEVICE_P_H
44 
45 //
46 //  W A R N I N G
47 //  -------------
48 //
49 // This file is not part of the Qt API.  It exists purely as an
50 // implementation detail.  This header file may change from version to
51 // version without notice, or even be removed.
52 //
53 // We mean it.
54 //
55 
56 #include <QtGui/private/qtguiglobal_p.h>
57 #include <qpa/qplatformscreen.h>
58 #include <QtCore/QMap>
59 #include <QtCore/QVariant>
60 #include <QtCore/QThreadStorage>
61 
62 #include <xf86drm.h>
63 #include <xf86drmMode.h>
64 #include <drm_fourcc.h>
65 
66 #include <functional>
67 
68 // In less fortunate cases one may need to build on a system with dev headers
69 // from the dark ages. Let's pull a GL and define the missing stuff outselves.
70 
71 #ifndef DRM_PLANE_TYPE_OVERLAY
72 #define DRM_PLANE_TYPE_OVERLAY 0
73 #endif
74 #ifndef DRM_PLANE_TYPE_PRIMARY
75 #define DRM_PLANE_TYPE_PRIMARY 1
76 #endif
77 #ifndef DRM_PLANE_TYPE_CURSOR
78 #define DRM_PLANE_TYPE_CURSOR 2
79 #endif
80 
81 #ifndef DRM_CLIENT_CAP_UNIVERSAL_PLANES
82 #define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2
83 #endif
84 #ifndef DRM_CLIENT_CAP_ATOMIC
85 #define DRM_CLIENT_CAP_ATOMIC 3
86 #endif
87 
88 #ifndef DRM_MODE_PROP_EXTENDED_TYPE
89 #define DRM_MODE_PROP_EXTENDED_TYPE 0x0000ffc0
90 #endif
91 #ifndef DRM_MODE_PROP_TYPE
92 #define DRM_MODE_PROP_TYPE(n) ((n) << 6)
93 #endif
94 #ifndef DRM_MODE_PROP_OBJECT
95 #define DRM_MODE_PROP_OBJECT DRM_MODE_PROP_TYPE(1)
96 #endif
97 #ifndef DRM_MODE_PROP_SIGNED_RANGE
98 #define DRM_MODE_PROP_SIGNED_RANGE DRM_MODE_PROP_TYPE(2)
99 #endif
100 
101 QT_BEGIN_NAMESPACE
102 
103 class QKmsDevice;
104 
105 class QKmsScreenConfig
106 {
107 public:
108     enum VirtualDesktopLayout {
109         VirtualDesktopLayoutHorizontal,
110         VirtualDesktopLayoutVertical
111     };
112 
113     QKmsScreenConfig();
114 
devicePath()115     QString devicePath() const { return m_devicePath; }
116 
headless()117     bool headless() const { return m_headless; }
headlessSize()118     QSize headlessSize() const { return m_headlessSize; }
hwCursor()119     bool hwCursor() const { return m_hwCursor; }
separateScreens()120     bool separateScreens() const { return m_separateScreens; }
supportsPBuffers()121     bool supportsPBuffers() const { return m_pbuffers; }
virtualDesktopLayout()122     VirtualDesktopLayout virtualDesktopLayout() const { return m_virtualDesktopLayout; }
123 
outputSettings()124     QMap<QString, QVariantMap> outputSettings() const { return m_outputSettings; }
125 
126 private:
127     void loadConfig();
128 
129     QString m_devicePath;
130     bool m_headless;
131     QSize m_headlessSize;
132     bool m_hwCursor;
133     bool m_separateScreens;
134     bool m_pbuffers;
135     VirtualDesktopLayout m_virtualDesktopLayout;
136     QMap<QString, QVariantMap> m_outputSettings;
137 };
138 
139 // NB! QKmsPlane does not store the current state and offers no functions to
140 // change object properties. Any such functionality belongs to subclasses since
141 // in some cases atomic operations will be desired where a mere
142 // drmModeObjectSetProperty would not be acceptable.
143 struct QKmsPlane
144 {
145     enum Type {
146         OverlayPlane = DRM_PLANE_TYPE_OVERLAY,
147         PrimaryPlane = DRM_PLANE_TYPE_PRIMARY,
148         CursorPlane = DRM_PLANE_TYPE_CURSOR
149     };
150 
151     enum Rotation {
152         Rotation0 = 1 << 0,
153         Rotation90 = 1 << 1,
154         Rotation180 = 1 << 2,
155         Rotation270 = 1 << 3,
156         RotationReflectX = 1 << 4,
157         RotationReflectY = 1 << 5
158     };
159     Q_DECLARE_FLAGS(Rotations, Rotation)
160 
161     uint32_t id = 0;
162     Type type = OverlayPlane;
163 
164     int possibleCrtcs = 0;
165 
166     QVector<uint32_t> supportedFormats;
167 
168     Rotations initialRotation = Rotation0;
169     Rotations availableRotations = Rotation0;
170     uint32_t rotationPropertyId = 0;
171     uint32_t crtcPropertyId = 0;
172     uint32_t framebufferPropertyId = 0;
173     uint32_t srcXPropertyId = 0;
174     uint32_t srcYPropertyId = 0;
175     uint32_t crtcXPropertyId = 0;
176     uint32_t crtcYPropertyId = 0;
177     uint32_t srcwidthPropertyId = 0;
178     uint32_t srcheightPropertyId = 0;
179     uint32_t crtcwidthPropertyId = 0;
180     uint32_t crtcheightPropertyId = 0;
181     uint32_t zposPropertyId = 0;
182     uint32_t blendOpPropertyId = 0;
183 
184     uint32_t activeCrtcId = 0;
185 };
186 
187 Q_DECLARE_OPERATORS_FOR_FLAGS(QKmsPlane::Rotations)
188 
189 struct QKmsOutput
190 {
191     QString name;
192     uint32_t connector_id = 0;
193     uint32_t crtc_index = 0;
194     uint32_t crtc_id = 0;
195     QSizeF physical_size;
196     int preferred_mode = -1; // index of preferred mode in list below
197     int mode = -1; // index of selected mode in list below
198     bool mode_set = false;
199     drmModeCrtcPtr saved_crtc = nullptr;
200     QList<drmModeModeInfo> modes;
201     int subpixel = DRM_MODE_SUBPIXEL_UNKNOWN;
202     drmModePropertyPtr dpms_prop = nullptr;
203     drmModePropertyBlobPtr edid_blob = nullptr;
204     bool wants_forced_plane = false;
205     uint32_t forced_plane_id = 0;
206     bool forced_plane_set = false;
207     uint32_t drm_format = DRM_FORMAT_XRGB8888;
208     bool drm_format_requested_by_user = false;
209     QString clone_source;
210     QVector<QKmsPlane> available_planes;
211     struct QKmsPlane *eglfs_plane = nullptr;
212     QSize size;
213     uint32_t crtcIdPropertyId = 0;
214     uint32_t modeIdPropertyId = 0;
215     uint32_t activePropertyId = 0;
216 
217     uint32_t mode_blob_id = 0;
218 
219     void restoreMode(QKmsDevice *device);
220     void cleanup(QKmsDevice *device);
221     QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const;
222     void setPowerState(QKmsDevice *device, QPlatformScreen::PowerState state);
223 };
224 
225 class QKmsDevice
226 {
227 public:
228     struct ScreenInfo {
229         int virtualIndex = 0;
230         QPoint virtualPos;
231         bool isPrimary = false;
232         QKmsOutput output;
233     };
234 
235     QKmsDevice(QKmsScreenConfig *screenConfig, const QString &path = QString());
236     virtual ~QKmsDevice();
237 
238     virtual bool open() = 0;
239     virtual void close() = 0;
240     virtual void *nativeDisplay() const = 0;
241 
242     bool hasAtomicSupport();
243 
244 #if QT_CONFIG(drm_atomic)
245     drmModeAtomicReq *threadLocalAtomicRequest();
246     bool threadLocalAtomicCommit(void *user_data);
247     void threadLocalAtomicReset();
248 #endif
249     void createScreens();
250 
251     int fd() const;
252     QString devicePath() const;
253 
254     QKmsScreenConfig *screenConfig() const;
255 
256 protected:
257     virtual QPlatformScreen *createScreen(const QKmsOutput &output) = 0;
258     virtual QPlatformScreen *createHeadlessScreen();
259     virtual void registerScreenCloning(QPlatformScreen *screen,
260                                        QPlatformScreen *screenThisScreenClones,
261                                        const QVector<QPlatformScreen *> &screensCloningThisScreen);
262     virtual void registerScreen(QPlatformScreen *screen,
263                                 bool isPrimary,
264                                 const QPoint &virtualPos,
265                                 const QList<QPlatformScreen *> &virtualSiblings) = 0;
266 
267     void setFd(int fd);
268     int crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector);
269     QPlatformScreen *createScreenForConnector(drmModeResPtr resources,
270                                               drmModeConnectorPtr connector,
271                                               ScreenInfo *vinfo);
272     drmModePropertyPtr connectorProperty(drmModeConnectorPtr connector, const QByteArray &name);
273     drmModePropertyBlobPtr connectorPropertyBlob(drmModeConnectorPtr connector, const QByteArray &name);
274     typedef std::function<void(drmModePropertyPtr, quint64)> PropCallback;
275     void enumerateProperties(drmModeObjectPropertiesPtr objProps, PropCallback callback);
276     void discoverPlanes();
277     void parseConnectorProperties(uint32_t connectorId, QKmsOutput *output);
278     void parseCrtcProperties(uint32_t crtcId, QKmsOutput *output);
279 
280     QKmsScreenConfig *m_screenConfig;
281     QString m_path;
282     int m_dri_fd;
283 
284     bool m_has_atomic_support;
285 
286 #if QT_CONFIG(drm_atomic)
287     struct AtomicReqs {
288         drmModeAtomicReq *request = nullptr;
289         drmModeAtomicReq *previous_request = nullptr;
290     };
291     QThreadStorage<AtomicReqs> m_atomicReqs;
292 #endif
293     quint32 m_crtc_allocator;
294 
295     QVector<QKmsPlane> m_planes;
296 
297 private:
298     Q_DISABLE_COPY(QKmsDevice)
299 };
300 
301 QT_END_NAMESPACE
302 
303 #endif
304