Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
vsp2hardwarelayerintegration.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7extern "C" {
8#define private priv
9#include <wayland-kms.h>
10#undef private
11}
12
13#include <private/qwaylandquickhardwarelayer_p.h>
14#include <private/qwaylandquickitem_p.h>
15#include <private/qwaylandview_p.h>
16#include <QWaylandQuickOutput>
17#include <QQuickWindow>
18
19#include <qpa/qlatformscreen_p.h>
20
21using namespace QNativeInterface::Private;
22
23QT_BEGIN_NAMESPACE
24
25Vsp2Buffer::Vsp2Buffer(wl_kms_buffer *kmsBuffer)
26 : dmabufFd(kmsBuffer->fd)
27 , bytesPerLine(kmsBuffer->stride)
28 , drmPixelFormat(kmsBuffer->format)
29 , size(kmsBuffer->width, kmsBuffer->height)
30{
31}
32
33Vsp2Layer::Vsp2Layer(QWaylandQuickHardwareLayer *hwLayer, Vsp2HardwareLayerIntegration *integration)
34 : m_hwLayer(hwLayer)
35{
36 auto *wlItem = m_hwLayer->waylandItem();
37 m_screen = dynamic_cast<QVsp2Screen*>(wlItem->window()->screen()->handle());
38 Q_ASSERT(m_screen);
39
40 connect(hwLayer, &QWaylandQuickHardwareLayer::stackingLevelChanged, this, [integration](){
41 integration->recreateVspLayers();
42 });
43 connect(hwLayer->waylandItem(), &QWaylandQuickItem::surfaceChanged, this, &Vsp2Layer::handleSurfaceChanged);
44 connect(hwLayer->waylandItem(), &QQuickItem::opacityChanged, this, &Vsp2Layer::updateOpacity);
45 connect(hwLayer->waylandItem()->window(), &QQuickWindow::afterSynchronizing, this, &Vsp2Layer::updatePosition);
46 hwLayer->setSceneGraphPainting(false);
47 QWaylandViewPrivate::get(hwLayer->waylandItem()->view())->independentFrameCallback = true;
49}
50
52{
53 auto *kmsBuffer = nextKmsBuffer();
54
55 if (!kmsBuffer)
56 return;
57
58 m_buffer = Vsp2Buffer(kmsBuffer);
60
61 m_layerIndex = m_screen->addLayer(m_buffer.dmabufFd, m_buffer.size, m_position, m_buffer.drmPixelFormat, m_buffer.bytesPerLine);
62
63 auto *wlItem = m_hwLayer->waylandItem();
64 wlItem->surface()->frameStarted();
66}
67
69{
70 m_screen->removeLayer(m_layerIndex);
71 m_layerIndex = -1;
72 m_screen = nullptr;
73}
74
75void Vsp2Layer::handleBufferCommitted()
76{
77 if (!isEnabled()) {
79 return;
80 }
81
82 auto *kmsBuffer = nextKmsBuffer();
83
84 Vsp2Buffer newBuffer(kmsBuffer);
85 if (m_buffer.dmabufFd != -1) {
86 bool formatChanged = false;
87 formatChanged |= newBuffer.bytesPerLine != m_buffer.bytesPerLine;
88 formatChanged |= newBuffer.size != m_buffer.size;
89 formatChanged |= newBuffer.drmPixelFormat != m_buffer.drmPixelFormat;
90 if (formatChanged) {
91 qWarning() << "The VSP2 Wayland hardware layer integration doesn't support changing"
92 << "surface formats, this will most likely fail";
93 }
94 }
95
96 m_buffer = newBuffer;
97 m_screen->setLayerBuffer(m_layerIndex, m_buffer.dmabufFd);
98
99 auto *wlItem = m_hwLayer->waylandItem();
100 wlItem->surface()->frameStarted();
101}
102
104{
105 auto newSurface = m_hwLayer->waylandItem()->surface();
106
107 if (Q_UNLIKELY(newSurface == m_surface))
108 return;
109
110 if (this->m_surface)
111 disconnect(this->m_surface, &QWaylandSurface::redraw, this, &Vsp2Layer::handleBufferCommitted);
112 if (newSurface)
113 connect(newSurface, &QWaylandSurface::redraw, this, &Vsp2Layer::handleBufferCommitted, Qt::DirectConnection);
114
115 this->m_surface = newSurface;
116}
117
119{
120 QWaylandQuickItem *wlItem = m_hwLayer->waylandItem();
121 QRectF localGeometry(0, 0, wlItem->width(), wlItem->height());
122 auto lastMatrix = QWaylandQuickItemPrivate::get(wlItem)->lastMatrix;
123 auto globalGeometry = lastMatrix.mapRect(localGeometry);
124
125 if (m_buffer.size != globalGeometry.size().toSize()) {
126 qWarning() << "wl_buffer size != WaylandQuickItem size and scaling has not been"
127 << "implemented for the vsp2 hardware layer integration";
128 }
129
130 m_position = globalGeometry.topLeft().toPoint();
131 if (isEnabled())
132 m_screen->setLayerPosition(m_layerIndex, m_position);
133}
134
136{
137 if (isEnabled()) {
138 qreal opacity = m_hwLayer->waylandItem()->opacity();
139 m_screen->setLayerAlpha(m_layerIndex, opacity);
140 }
141}
142
143wl_kms_buffer *Vsp2Layer::nextKmsBuffer()
144{
145 Q_ASSERT(m_hwLayer && m_hwLayer->waylandItem());
146 QWaylandQuickItem *wlItem = m_hwLayer->waylandItem();
147 auto view = wlItem->view();
148 Q_ASSERT(view);
149
150 view->advance();
151 auto wlBuffer = view->currentBuffer().wl_buffer();
152
153 if (!wlBuffer)
154 return nullptr;
155
156 struct wl_kms_buffer *kmsBuffer = wayland_kms_buffer_get(wlBuffer);
157
158 if (!kmsBuffer)
159 qWarning() << "Failed to get wl_kms_buffer for wl_buffer:" << wl_resource_get_id(wlBuffer);
160
161 return kmsBuffer;
162}
163
164void Vsp2HardwareLayerIntegration::enableVspLayers()
165{
166 for (auto &layer : std::as_const(m_layers)) {
167 Q_ASSERT(!layer->isEnabled());
168 layer->enableVspLayer();
169 }
170}
171
172void Vsp2HardwareLayerIntegration::disableVspLayers()
173{
174 for (auto it = m_layers.rbegin(); it != m_layers.rend(); ++it) {
175 if ((*it)->isEnabled())
176 (*it)->disableVspLayer();
177 }
178}
179
180void Vsp2HardwareLayerIntegration::sortLayersByDepth()
181{
182 std::sort(m_layers.begin(), m_layers.end(), [](auto &l1, auto &l2){
183 return l1->hwLayer()->stackingLevel() < l2->hwLayer()->stackingLevel();
184 });
185}
186
187void Vsp2HardwareLayerIntegration::recreateVspLayers() {
188 disableVspLayers();
189 sortLayersByDepth();
190 enableVspLayers();
191}
192
193Vsp2HardwareLayerIntegration::Vsp2HardwareLayerIntegration()
194{
195 if (QGuiApplication::platformName() != "eglfs") {
196 qWarning() << "Vsp2 layers are currently only supported on the eglfs platform plugin"
197 << "with the eglfs_kms_vsp2 device integration.\n"
198 << "You need to set QT_QPA_PLATFORM=eglfs and QT_QPA_EGLFS_INTEGRATION=eglfs_kms_vsp2";
199 }
200 static Vsp2HardwareLayerIntegration *s_instance = this;
201 auto screen = dynamic_cast<QVsp2Screen*>(QGuiApplication::primaryScreen()->handle());
202 screen->addBlendListener([](){
203 s_instance->sendFrameCallbacks();
204 });
205}
206
207void Vsp2HardwareLayerIntegration::add(QWaylandQuickHardwareLayer *hwLayer)
208{
209 disableVspLayers();
210 m_layers.append(QSharedPointer<Vsp2Layer>(new Vsp2Layer(hwLayer, this)));
211 sortLayersByDepth();
212 enableVspLayers();
213}
214
215void Vsp2HardwareLayerIntegration::remove(QWaylandQuickHardwareLayer *hwLayer)
216{
217 disableVspLayers();
218 for (auto it = m_layers.begin(); it != m_layers.end(); ++it) {
219 if ((*it)->hwLayer() == hwLayer) {
220 m_layers.erase(it);
221 break;
222 }
223 }
224 enableVspLayers();
225}
226
228{
229 for (auto &layer : std::as_const(m_layers)) {
230 if (auto *surface = layer->hwLayer()->waylandItem()->surface())
231 surface->sendFrameCallbacks();
232 }
233}
234
235QT_END_NAMESPACE
void add(QWaylandQuickHardwareLayer *layer) override
void remove(QWaylandQuickHardwareLayer *layer) override
Vsp2Buffer(wl_kms_buffer *kmsBuffer)