1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 The Qt Company Ltd.
4 ** Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
5 ** Copyright (C) 2016 Pelagicore AG
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 #include "qeglfskmsscreen.h"
43 #include "qeglfskmsdevice.h"
44 #include "qeglfsintegration_p.h"
45 
46 #include <QtCore/QLoggingCategory>
47 
48 #include <QtGui/private/qguiapplication_p.h>
49 #include <QtFbSupport/private/qfbvthandler_p.h>
50 
51 QT_BEGIN_NAMESPACE
52 
53 Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
54 
55 class QEglFSKmsInterruptHandler : public QObject
56 {
57 public:
QEglFSKmsInterruptHandler(QEglFSKmsScreen * screen)58     QEglFSKmsInterruptHandler(QEglFSKmsScreen *screen) : m_screen(screen) {
59         m_vtHandler = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration())->vtHandler();
60         connect(m_vtHandler, &QFbVtHandler::interrupted, this, &QEglFSKmsInterruptHandler::restoreVideoMode);
61         connect(m_vtHandler, &QFbVtHandler::aboutToSuspend, this, &QEglFSKmsInterruptHandler::restoreVideoMode);
62     }
63 
64 public slots:
restoreVideoMode()65     void restoreVideoMode() { m_screen->restoreMode(); }
66 
67 private:
68     QFbVtHandler *m_vtHandler;
69     QEglFSKmsScreen *m_screen;
70 };
71 
QEglFSKmsScreen(QEglFSKmsDevice * device,const QKmsOutput & output,bool headless)72 QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsDevice *device, const QKmsOutput &output, bool headless)
73     : QEglFSScreen(static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration())->display())
74     , m_device(device)
75     , m_output(output)
76     , m_cursorOutOfRange(false)
77     , m_powerState(PowerStateOn)
78     , m_interruptHandler(new QEglFSKmsInterruptHandler(this))
79     , m_headless(headless)
80 {
81     m_siblings << this; // gets overridden later
82 
83     if (m_output.edid_blob) {
84         QByteArray edid(reinterpret_cast<const char *>(m_output.edid_blob->data), m_output.edid_blob->length);
85         if (m_edid.parse(edid))
86             qCDebug(qLcEglfsKmsDebug, "EDID data for output \"%s\": identifier '%s', manufacturer '%s', model '%s', serial '%s', physical size: %.2fx%.2f",
87                     name().toLatin1().constData(),
88                     m_edid.identifier.toLatin1().constData(),
89                     m_edid.manufacturer.toLatin1().constData(),
90                     m_edid.model.toLatin1().constData(),
91                     m_edid.serialNumber.toLatin1().constData(),
92                     m_edid.physicalSize.width(), m_edid.physicalSize.height());
93         else
94             qCDebug(qLcEglfsKmsDebug) << "Failed to parse EDID data for output" << name(); // keep this debug, not warning
95     } else {
96         qCDebug(qLcEglfsKmsDebug) << "No EDID data for output" << name();
97     }
98 }
99 
~QEglFSKmsScreen()100 QEglFSKmsScreen::~QEglFSKmsScreen()
101 {
102     m_output.cleanup(m_device);
103     delete m_interruptHandler;
104 }
105 
setVirtualPosition(const QPoint & pos)106 void QEglFSKmsScreen::setVirtualPosition(const QPoint &pos)
107 {
108     m_pos = pos;
109 }
110 
111 // Reimplement rawGeometry(), not geometry(). The base class implementation of
112 // geometry() calls rawGeometry() and may apply additional transforms.
rawGeometry() const113 QRect QEglFSKmsScreen::rawGeometry() const
114 {
115     if (m_headless)
116         return QRect(QPoint(0, 0), m_device->screenConfig()->headlessSize());
117 
118     return QRect(m_pos.x(), m_pos.y(),
119                  m_output.size.width(),
120                  m_output.size.height());
121 }
122 
depth() const123 int QEglFSKmsScreen::depth() const
124 {
125     return format() == QImage::Format_RGB16 ? 16 : 32;
126 }
127 
format() const128 QImage::Format QEglFSKmsScreen::format() const
129 {
130     // the result can be slightly incorrect, it won't matter in practice
131     switch (m_output.drm_format) {
132     case DRM_FORMAT_ARGB8888:
133     case DRM_FORMAT_ABGR8888:
134         return QImage::Format_ARGB32;
135     case DRM_FORMAT_RGB565:
136     case DRM_FORMAT_BGR565:
137         return QImage::Format_RGB16;
138     case DRM_FORMAT_XRGB2101010:
139         return QImage::Format_RGB30;
140     case DRM_FORMAT_XBGR2101010:
141         return QImage::Format_BGR30;
142     case DRM_FORMAT_ARGB2101010:
143         return QImage::Format_A2RGB30_Premultiplied;
144     case DRM_FORMAT_ABGR2101010:
145         return QImage::Format_A2BGR30_Premultiplied;
146     default:
147         return QImage::Format_RGB32;
148     }
149 }
150 
physicalSize() const151 QSizeF QEglFSKmsScreen::physicalSize() const
152 {
153     if (!m_output.physical_size.isEmpty()) {
154         return m_output.physical_size;
155     } else {
156         const QSize s = geometry().size();
157         return QSizeF(0.254 * s.width(), 0.254 * s.height());
158     }
159 }
160 
logicalDpi() const161 QDpi QEglFSKmsScreen::logicalDpi() const
162 {
163     const QSizeF ps = physicalSize();
164     const QSize s = geometry().size();
165 
166     if (!ps.isEmpty() && !s.isEmpty())
167         return QDpi(25.4 * s.width() / ps.width(),
168                     25.4 * s.height() / ps.height());
169     else
170         return QDpi(100, 100);
171 }
172 
nativeOrientation() const173 Qt::ScreenOrientation QEglFSKmsScreen::nativeOrientation() const
174 {
175     return Qt::PrimaryOrientation;
176 }
177 
orientation() const178 Qt::ScreenOrientation QEglFSKmsScreen::orientation() const
179 {
180     return Qt::PrimaryOrientation;
181 }
182 
name() const183 QString QEglFSKmsScreen::name() const
184 {
185     return !m_headless ? m_output.name : QStringLiteral("qt_Headless");
186 }
187 
manufacturer() const188 QString QEglFSKmsScreen::manufacturer() const
189 {
190     return m_edid.manufacturer;
191 }
192 
model() const193 QString QEglFSKmsScreen::model() const
194 {
195     return m_edid.model.isEmpty() ? m_edid.identifier : m_edid.model;
196 }
197 
serialNumber() const198 QString QEglFSKmsScreen::serialNumber() const
199 {
200     return m_edid.serialNumber;
201 }
202 
waitForFlip()203 void QEglFSKmsScreen::waitForFlip()
204 {
205 }
206 
restoreMode()207 void QEglFSKmsScreen::restoreMode()
208 {
209     m_output.restoreMode(m_device);
210 }
211 
refreshRate() const212 qreal QEglFSKmsScreen::refreshRate() const
213 {
214     if (m_headless)
215         return 60;
216 
217     quint32 refresh = m_output.modes[m_output.mode].vrefresh;
218     return refresh > 0 ? refresh : 60;
219 }
220 
modes() const221 QVector<QPlatformScreen::Mode> QEglFSKmsScreen::modes() const
222 {
223     QVector<QPlatformScreen::Mode> list;
224     list.reserve(m_output.modes.size());
225 
226     for (const drmModeModeInfo &info : qAsConst(m_output.modes))
227         list.append({QSize(info.hdisplay, info.vdisplay),
228                      qreal(info.vrefresh > 0 ? info.vrefresh : 60)});
229 
230     return list;
231 }
232 
currentMode() const233 int QEglFSKmsScreen::currentMode() const
234 {
235     return m_output.mode;
236 }
237 
preferredMode() const238 int QEglFSKmsScreen::preferredMode() const
239 {
240     return m_output.preferred_mode;
241 }
242 
subpixelAntialiasingTypeHint() const243 QPlatformScreen::SubpixelAntialiasingType QEglFSKmsScreen::subpixelAntialiasingTypeHint() const
244 {
245     return m_output.subpixelAntialiasingTypeHint();
246 }
247 
powerState() const248 QPlatformScreen::PowerState QEglFSKmsScreen::powerState() const
249 {
250     return m_powerState;
251 }
252 
setPowerState(QPlatformScreen::PowerState state)253 void QEglFSKmsScreen::setPowerState(QPlatformScreen::PowerState state)
254 {
255     m_output.setPowerState(m_device, state);
256     m_powerState = state;
257 }
258 
259 QT_END_NAMESPACE
260