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

source code of qtbase/src/platformsupport/kmsconvenience/qkmsdevice_p.h