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