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 | |
65 | QT_BEGIN_NAMESPACE |
66 | |
67 | class QKmsDevice; |
68 | |
69 | class QKmsScreenConfig |
70 | { |
71 | public: |
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 | |
92 | protected: |
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. |
107 | struct 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 | |
151 | Q_DECLARE_OPERATORS_FOR_FLAGS(QKmsPlane::Rotations) |
152 | |
153 | struct 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 | |
189 | class QKmsDevice |
190 | { |
191 | public: |
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 | |
220 | protected: |
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 | |
261 | private: |
262 | Q_DISABLE_COPY(QKmsDevice) |
263 | }; |
264 | |
265 | QT_END_NAMESPACE |
266 | |
267 | #endif |
268 | |