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_p.h"
43#include "qeglfskmsdevice_p.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
51QT_BEGIN_NAMESPACE
52
53Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
54
55class QEglFSKmsInterruptHandler : public QObject
56{
57public:
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
64public slots:
65 void restoreVideoMode() { m_screen->restoreMode(); }
66
67private:
68 QFbVtHandler *m_vtHandler;
69 QEglFSKmsScreen *m_screen;
70};
71
72QEglFSKmsScreen::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
100QEglFSKmsScreen::~QEglFSKmsScreen()
101{
102 m_output.cleanup(m_device);
103 delete m_interruptHandler;
104}
105
106void 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.
113QRect 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
123int QEglFSKmsScreen::depth() const
124{
125 return format() == QImage::Format_RGB16 ? 16 : 32;
126}
127
128QImage::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
151QSizeF 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
161QDpi QEglFSKmsScreen::logicalDpi() const
162{
163 return logicalBaseDpi();
164}
165
166QDpi QEglFSKmsScreen::logicalBaseDpi() const
167{
168 return QDpi(100, 100);
169}
170
171Qt::ScreenOrientation QEglFSKmsScreen::nativeOrientation() const
172{
173 return Qt::PrimaryOrientation;
174}
175
176Qt::ScreenOrientation QEglFSKmsScreen::orientation() const
177{
178 return Qt::PrimaryOrientation;
179}
180
181QString QEglFSKmsScreen::name() const
182{
183 return !m_headless ? m_output.name : QStringLiteral("qt_Headless");
184}
185
186QString QEglFSKmsScreen::manufacturer() const
187{
188 return m_edid.manufacturer;
189}
190
191QString QEglFSKmsScreen::model() const
192{
193 return m_edid.model.isEmpty() ? m_edid.identifier : m_edid.model;
194}
195
196QString QEglFSKmsScreen::serialNumber() const
197{
198 return m_edid.serialNumber;
199}
200
201void QEglFSKmsScreen::waitForFlip()
202{
203}
204
205void QEglFSKmsScreen::restoreMode()
206{
207 m_output.restoreMode(m_device);
208}
209
210qreal QEglFSKmsScreen::refreshRate() const
211{
212 if (m_headless)
213 return 60;
214
215 quint32 refresh = m_output.modes[m_output.mode].vrefresh;
216 return refresh > 0 ? refresh : 60;
217}
218
219QList<QPlatformScreen::Mode> QEglFSKmsScreen::modes() const
220{
221 QList<QPlatformScreen::Mode> list;
222 list.reserve(m_output.modes.size());
223
224 for (const drmModeModeInfo &info : qAsConst(m_output.modes))
225 list.append({QSize(info.hdisplay, info.vdisplay),
226 qreal(info.vrefresh > 0 ? info.vrefresh : 60)});
227
228 return list;
229}
230
231int QEglFSKmsScreen::currentMode() const
232{
233 return m_output.mode;
234}
235
236int QEglFSKmsScreen::preferredMode() const
237{
238 return m_output.preferred_mode;
239}
240
241QPlatformScreen::SubpixelAntialiasingType QEglFSKmsScreen::subpixelAntialiasingTypeHint() const
242{
243 return m_output.subpixelAntialiasingTypeHint();
244}
245
246QPlatformScreen::PowerState QEglFSKmsScreen::powerState() const
247{
248 return m_powerState;
249}
250
251void QEglFSKmsScreen::setPowerState(QPlatformScreen::PowerState state)
252{
253 m_output.setPowerState(m_device, state);
254 m_powerState = state;
255}
256
257QT_END_NAMESPACE
258