1// Copyright (C) 2017 The Qt Company Ltd.
2// Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
3// Copyright (C) 2016 Pelagicore AG
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5
6#include "qeglfskmsscreen_p.h"
7#include "qeglfskmsdevice_p.h"
8#include <private/qeglfsintegration_p.h>
9
10#include <QtCore/QLoggingCategory>
11
12#include <QtGui/private/qguiapplication_p.h>
13#include <QtFbSupport/private/qfbvthandler_p.h>
14
15QT_BEGIN_NAMESPACE
16
17Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
18
19class QEglFSKmsInterruptHandler : public QObject
20{
21public:
22 QEglFSKmsInterruptHandler(QEglFSKmsScreen *screen) : m_screen(screen) {
23 m_vtHandler = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration())->vtHandler();
24 connect(sender: m_vtHandler, signal: &QFbVtHandler::interrupted, context: this, slot: &QEglFSKmsInterruptHandler::restoreVideoMode);
25 connect(sender: m_vtHandler, signal: &QFbVtHandler::aboutToSuspend, context: this, slot: &QEglFSKmsInterruptHandler::restoreVideoMode);
26 }
27
28public slots:
29 void restoreVideoMode() { m_screen->restoreMode(); }
30
31private:
32 QFbVtHandler *m_vtHandler;
33 QEglFSKmsScreen *m_screen;
34};
35
36QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsDevice *device, const QKmsOutput &output, bool headless)
37 : QEglFSScreen(static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration())->display())
38 , m_device(device)
39 , m_output(output)
40 , m_cursorOutOfRange(false)
41 , m_powerState(PowerStateOn)
42 , m_interruptHandler(new QEglFSKmsInterruptHandler(this))
43 , m_headless(headless)
44{
45 m_siblings << this; // gets overridden later
46
47 if (m_output.edid_blob) {
48 QByteArray edid(reinterpret_cast<const char *>(m_output.edid_blob->data), m_output.edid_blob->length);
49 if (m_edid.parse(blob: edid))
50 qCDebug(qLcEglfsKmsDebug, "EDID data for output \"%s\": identifier '%s', manufacturer '%s', model '%s', serial '%s', physical size: %.2fx%.2f",
51 name().toLatin1().constData(),
52 m_edid.identifier.toLatin1().constData(),
53 m_edid.manufacturer.toLatin1().constData(),
54 m_edid.model.toLatin1().constData(),
55 m_edid.serialNumber.toLatin1().constData(),
56 m_edid.physicalSize.width(), m_edid.physicalSize.height());
57 else
58 qCDebug(qLcEglfsKmsDebug) << "Failed to parse EDID data for output" << name(); // keep this debug, not warning
59 } else {
60 qCDebug(qLcEglfsKmsDebug) << "No EDID data for output" << name();
61 }
62}
63
64QEglFSKmsScreen::~QEglFSKmsScreen()
65{
66 m_output.cleanup(device: m_device);
67 delete m_interruptHandler;
68}
69
70void QEglFSKmsScreen::setVirtualPosition(const QPoint &pos)
71{
72 m_pos = pos;
73}
74
75// Reimplement rawGeometry(), not geometry(). The base class implementation of
76// geometry() calls rawGeometry() and may apply additional transforms.
77QRect QEglFSKmsScreen::rawGeometry() const
78{
79 if (m_headless)
80 return QRect(QPoint(0, 0), m_device->screenConfig()->headlessSize());
81
82 return QRect(m_pos.x(), m_pos.y(),
83 m_output.size.width(),
84 m_output.size.height());
85}
86
87int QEglFSKmsScreen::depth() const
88{
89 return format() == QImage::Format_RGB16 ? 16 : 32;
90}
91
92QImage::Format QEglFSKmsScreen::format() const
93{
94 // the result can be slightly incorrect, it won't matter in practice
95 switch (m_output.drm_format) {
96 case DRM_FORMAT_ARGB8888:
97 case DRM_FORMAT_ABGR8888:
98 return QImage::Format_ARGB32;
99 case DRM_FORMAT_RGB565:
100 case DRM_FORMAT_BGR565:
101 return QImage::Format_RGB16;
102 case DRM_FORMAT_XRGB2101010:
103 return QImage::Format_RGB30;
104 case DRM_FORMAT_XBGR2101010:
105 return QImage::Format_BGR30;
106 case DRM_FORMAT_ARGB2101010:
107 return QImage::Format_A2RGB30_Premultiplied;
108 case DRM_FORMAT_ABGR2101010:
109 return QImage::Format_A2BGR30_Premultiplied;
110 default:
111 return QImage::Format_RGB32;
112 }
113}
114
115QSizeF QEglFSKmsScreen::physicalSize() const
116{
117 if (!m_output.physical_size.isEmpty()) {
118 return m_output.physical_size;
119 } else {
120 const QSize s = geometry().size();
121 return QSizeF(0.254 * s.width(), 0.254 * s.height());
122 }
123}
124
125QDpi QEglFSKmsScreen::logicalDpi() const
126{
127 return logicalBaseDpi();
128}
129
130QDpi QEglFSKmsScreen::logicalBaseDpi() const
131{
132 return QDpi(100, 100);
133}
134
135Qt::ScreenOrientation QEglFSKmsScreen::nativeOrientation() const
136{
137 return Qt::PrimaryOrientation;
138}
139
140Qt::ScreenOrientation QEglFSKmsScreen::orientation() const
141{
142 return Qt::PrimaryOrientation;
143}
144
145QString QEglFSKmsScreen::name() const
146{
147 return !m_headless ? m_output.name : QStringLiteral("qt_Headless");
148}
149
150QString QEglFSKmsScreen::manufacturer() const
151{
152 return m_edid.manufacturer;
153}
154
155QString QEglFSKmsScreen::model() const
156{
157 return m_edid.model.isEmpty() ? m_edid.identifier : m_edid.model;
158}
159
160QString QEglFSKmsScreen::serialNumber() const
161{
162 return m_edid.serialNumber;
163}
164
165void QEglFSKmsScreen::waitForFlip()
166{
167}
168
169void QEglFSKmsScreen::restoreMode()
170{
171 m_output.restoreMode(device: m_device);
172}
173
174qreal QEglFSKmsScreen::refreshRate() const
175{
176 if (m_headless)
177 return 60;
178
179 quint32 refresh = m_output.modes[m_output.mode].vrefresh;
180 return refresh > 0 ? refresh : 60;
181}
182
183QList<QPlatformScreen::Mode> QEglFSKmsScreen::modes() const
184{
185 QList<QPlatformScreen::Mode> list;
186 list.reserve(asize: m_output.modes.size());
187
188 for (const drmModeModeInfo &info : std::as_const(t: m_output.modes))
189 list.append(t: {.size: QSize(info.hdisplay, info.vdisplay),
190 .refreshRate: qreal(info.vrefresh > 0 ? info.vrefresh : 60)});
191
192 return list;
193}
194
195int QEglFSKmsScreen::currentMode() const
196{
197 return m_output.mode;
198}
199
200int QEglFSKmsScreen::preferredMode() const
201{
202 return m_output.preferred_mode;
203}
204
205QPlatformScreen::SubpixelAntialiasingType QEglFSKmsScreen::subpixelAntialiasingTypeHint() const
206{
207 return m_output.subpixelAntialiasingTypeHint();
208}
209
210QPlatformScreen::PowerState QEglFSKmsScreen::powerState() const
211{
212 return m_powerState;
213}
214
215void QEglFSKmsScreen::setPowerState(QPlatformScreen::PowerState state)
216{
217 m_output.setPowerState(device: m_device, state);
218 m_powerState = state;
219}
220
221/* Informs exact page flip timing which can be used rendering optimization.
222 Consider this is from drm event reader thread. */
223void QEglFSKmsScreen::pageFlipped(unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec)
224{
225 Q_UNUSED(sequence);
226 Q_UNUSED(tv_sec);
227 Q_UNUSED(tv_usec);
228}
229
230QT_END_NAMESPACE
231

source code of qtbase/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp