Changeset View
Changeset View
Standalone View
Standalone View
plugins/platforms/wayland/scene_qpainter_wayland_backend.cpp
1 | /******************************************************************** | 1 | /******************************************************************** | ||
---|---|---|---|---|---|
2 | KWin - the KDE window manager | 2 | KWin - the KDE window manager | ||
3 | This file is part of the KDE project. | 3 | This file is part of the KDE project. | ||
4 | 4 | | |||
5 | Copyright (C) 2013, 2015 Martin Gräßlin <mgraesslin@kde.org> | 5 | Copyright 2019 Roman Gilg <subdiff@gmail.com> | ||
6 | Copyright 2013, 2015 Martin Gräßlin <mgraesslin@kde.org> | ||||
6 | 7 | | |||
7 | This program is free software; you can redistribute it and/or modify | 8 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | 9 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | 10 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | 11 | (at your option) any later version. | ||
11 | 12 | | |||
12 | This program is distributed in the hope that it will be useful, | 13 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | 16 | GNU General Public License for more details. | ||
16 | 17 | | |||
17 | You should have received a copy of the GNU General Public License | 18 | You should have received a copy of the GNU General Public License | ||
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 19 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | *********************************************************************/ | 20 | *********************************************************************/ | ||
20 | #include "scene_qpainter_wayland_backend.h" | 21 | #include "scene_qpainter_wayland_backend.h" | ||
22 | #include "wayland_backend.h" | ||||
23 | #include "wayland_output.h" | ||||
24 | | ||||
21 | #include "composite.h" | 25 | #include "composite.h" | ||
22 | #include "logging.h" | 26 | #include "logging.h" | ||
23 | #include "wayland_backend.h" | 27 | | ||
24 | #include <KWayland/Client/buffer.h> | 28 | #include <KWayland/Client/buffer.h> | ||
25 | #include <KWayland/Client/shm_pool.h> | 29 | #include <KWayland/Client/shm_pool.h> | ||
26 | #include <KWayland/Client/surface.h> | 30 | #include <KWayland/Client/surface.h> | ||
27 | 31 | | |||
28 | namespace KWin | 32 | namespace KWin | ||
29 | { | 33 | { | ||
34 | namespace Wayland | ||||
35 | { | ||||
30 | 36 | | |||
31 | WaylandQPainterBackend::WaylandQPainterBackend(Wayland::WaylandBackend *b) | 37 | WaylandQPainterOutput::WaylandQPainterOutput(WaylandOutput *output, QObject *parent) | ||
32 | : QPainterBackend() | 38 | : QObject(parent) | ||
33 | , m_backend(b) | 39 | , m_waylandOutput(output) | ||
34 | , m_needsFullRepaint(true) | | |||
35 | , m_backBuffer(QImage(QSize(), QImage::Format_RGB32)) | | |||
36 | , m_buffer() | | |||
37 | { | 40 | { | ||
38 | connect(b->shmPool(), SIGNAL(poolResized()), SLOT(remapBuffer())); | | |||
39 | connect(b, &Wayland::WaylandBackend::shellSurfaceSizeChanged, | | |||
40 | this, &WaylandQPainterBackend::screenGeometryChanged); | | |||
41 | connect(b->surface(), &KWayland::Client::Surface::frameRendered, | | |||
42 | Compositor::self(), &Compositor::bufferSwapComplete); | | |||
43 | } | 41 | } | ||
44 | 42 | | |||
45 | WaylandQPainterBackend::~WaylandQPainterBackend() | 43 | WaylandQPainterOutput::~WaylandQPainterOutput() | ||
46 | { | 44 | { | ||
47 | if (m_buffer) { | 45 | if (m_buffer) { | ||
48 | m_buffer.toStrongRef()->setUsed(false); | 46 | m_buffer.toStrongRef()->setUsed(false); | ||
49 | } | 47 | } | ||
50 | } | 48 | } | ||
51 | 49 | | |||
52 | bool WaylandQPainterBackend::usesOverlayWindow() const | 50 | bool WaylandQPainterOutput::init(KWayland::Client::ShmPool *pool) | ||
53 | { | 51 | { | ||
54 | return false; | 52 | m_pool = pool; | ||
53 | m_backBuffer = QImage(QSize(), QImage::Format_RGB32); | ||||
54 | | ||||
55 | connect(pool, &KWayland::Client::ShmPool::poolResized, this, &WaylandQPainterOutput::remapBuffer); | ||||
56 | connect(m_waylandOutput, &WaylandOutput::sizeChanged, this, &WaylandQPainterOutput::updateSize); | ||||
57 | | ||||
58 | return true; | ||||
55 | } | 59 | } | ||
56 | 60 | | |||
57 | void WaylandQPainterBackend::present(int mask, const QRegion &damage) | 61 | void WaylandQPainterOutput::remapBuffer() | ||
58 | { | 62 | { | ||
59 | Q_UNUSED(mask) | 63 | if (!m_buffer) { | ||
60 | if (m_backBuffer.isNull()) { | | |||
61 | return; | 64 | return; | ||
62 | } | 65 | } | ||
63 | Compositor::self()->aboutToSwapBuffers(); | 66 | auto b = m_buffer.toStrongRef(); | ||
64 | m_needsFullRepaint = false; | 67 | if (!b->isUsed()){ | ||
65 | auto s = m_backend->surface(); | 68 | return; | ||
66 | s->attachBuffer(m_buffer); | 69 | } | ||
67 | s->damage(damage); | 70 | const QSize size = m_backBuffer.size(); | ||
68 | s->commit(); | 71 | m_backBuffer = QImage(b->address(), size.width(), size.height(), QImage::Format_RGB32); | ||
72 | qCDebug(KWIN_WAYLAND_BACKEND) << "Remapped back buffer of surface" << m_waylandOutput->surface(); | ||||
69 | } | 73 | } | ||
70 | 74 | | |||
71 | void WaylandQPainterBackend::screenGeometryChanged(const QSize &size) | 75 | void WaylandQPainterOutput::updateSize(const QSize &size) | ||
72 | { | 76 | { | ||
73 | Q_UNUSED(size) | 77 | Q_UNUSED(size) | ||
74 | if (!m_buffer) { | 78 | if (!m_buffer) { | ||
75 | return; | 79 | return; | ||
76 | } | 80 | } | ||
77 | m_buffer.toStrongRef()->setUsed(false); | 81 | m_buffer.toStrongRef()->setUsed(false); | ||
78 | m_buffer.clear(); | 82 | m_buffer.clear(); | ||
79 | } | 83 | } | ||
80 | 84 | | |||
81 | QImage *WaylandQPainterBackend::buffer() | 85 | void WaylandQPainterOutput::present(const QRegion &damage) | ||
82 | { | 86 | { | ||
83 | return &m_backBuffer; | 87 | auto s = m_waylandOutput->surface(); | ||
88 | s->attachBuffer(m_buffer); | ||||
89 | s->damage(damage); | ||||
90 | s->commit(); | ||||
84 | } | 91 | } | ||
85 | 92 | | |||
86 | void WaylandQPainterBackend::prepareRenderingFrame() | 93 | void WaylandQPainterOutput::prepareRenderingFrame() | ||
87 | { | 94 | { | ||
88 | if (m_buffer) { | 95 | if (m_buffer) { | ||
89 | auto b = m_buffer.toStrongRef(); | 96 | auto b = m_buffer.toStrongRef(); | ||
90 | if (b->isReleased()) { | 97 | if (b->isReleased()) { | ||
91 | // we can re-use this buffer | 98 | // we can re-use this buffer | ||
92 | b->setReleased(false); | 99 | b->setReleased(false); | ||
93 | return; | 100 | return; | ||
94 | } else { | 101 | } else { | ||
95 | // buffer is still in use, get a new one | 102 | // buffer is still in use, get a new one | ||
96 | b->setUsed(false); | 103 | b->setUsed(false); | ||
97 | } | 104 | } | ||
98 | } | 105 | } | ||
99 | m_buffer.clear(); | 106 | m_buffer.clear(); | ||
100 | const QSize size(m_backend->shellSurfaceSize()); | 107 | | ||
101 | m_buffer = m_backend->shmPool()->getBuffer(size, size.width() * 4); | 108 | const QSize size(m_waylandOutput->geometry().size()); | ||
109 | | ||||
110 | m_buffer = m_pool->getBuffer(size, size.width() * 4); | ||||
102 | if (!m_buffer) { | 111 | if (!m_buffer) { | ||
103 | qCDebug(KWIN_WAYLAND_BACKEND) << "Did not get a new Buffer from Shm Pool"; | 112 | qCDebug(KWIN_WAYLAND_BACKEND) << "Did not get a new Buffer from Shm Pool"; | ||
104 | m_backBuffer = QImage(); | 113 | m_backBuffer = QImage(); | ||
105 | return; | 114 | return; | ||
106 | } | 115 | } | ||
116 | | ||||
107 | auto b = m_buffer.toStrongRef(); | 117 | auto b = m_buffer.toStrongRef(); | ||
108 | b->setUsed(true); | 118 | b->setUsed(true); | ||
119 | | ||||
109 | m_backBuffer = QImage(b->address(), size.width(), size.height(), QImage::Format_RGB32); | 120 | m_backBuffer = QImage(b->address(), size.width(), size.height(), QImage::Format_RGB32); | ||
110 | m_backBuffer.fill(Qt::transparent); | 121 | m_backBuffer.fill(Qt::transparent); | ||
111 | m_needsFullRepaint = true; | 122 | // qCDebug(KWIN_WAYLAND_BACKEND) << "Created a new back buffer for output surface" << m_waylandOutput->surface(); | ||
112 | qCDebug(KWIN_WAYLAND_BACKEND) << "Created a new back buffer"; | | |||
113 | } | 123 | } | ||
114 | 124 | | |||
115 | void WaylandQPainterBackend::remapBuffer() | 125 | WaylandQPainterBackend::WaylandQPainterBackend(Wayland::WaylandBackend *b) | ||
126 | : QPainterBackend() | ||||
127 | , m_backend(b) | ||||
128 | , m_needsFullRepaint(true) | ||||
116 | { | 129 | { | ||
117 | if (!m_buffer) { | 130 | | ||
118 | return; | 131 | const auto waylandOutputs = m_backend->waylandOutputs(); | ||
132 | for (auto *output: waylandOutputs) { | ||||
133 | createOutput(output); | ||||
119 | } | 134 | } | ||
120 | auto b = m_buffer.toStrongRef(); | 135 | connect(m_backend, &WaylandBackend::outputAdded, this, &WaylandQPainterBackend::createOutput); | ||
121 | if (!b->isUsed()){ | 136 | connect(m_backend, &WaylandBackend::outputRemoved, this, | ||
137 | [this] (WaylandOutput *waylandOutput) { | ||||
138 | auto it = std::find_if(m_outputs.begin(), m_outputs.end(), | ||||
139 | [waylandOutput] (WaylandQPainterOutput *output) { | ||||
140 | return output->m_waylandOutput == waylandOutput; | ||||
141 | } | ||||
142 | ); | ||||
143 | if (it == m_outputs.end()) { | ||||
122 | return; | 144 | return; | ||
123 | } | 145 | } | ||
124 | const QSize size = m_backBuffer.size(); | 146 | delete *it; | ||
125 | m_backBuffer = QImage(b->address(), size.width(), size.height(), QImage::Format_RGB32); | 147 | m_outputs.erase(it); | ||
126 | qCDebug(KWIN_WAYLAND_BACKEND) << "Remapped our back buffer"; | 148 | } | ||
149 | ); | ||||
150 | } | ||||
151 | | ||||
152 | WaylandQPainterBackend::~WaylandQPainterBackend() | ||||
153 | { | ||||
154 | } | ||||
155 | | ||||
156 | bool WaylandQPainterBackend::usesOverlayWindow() const | ||||
157 | { | ||||
158 | return false; | ||||
159 | } | ||||
160 | | ||||
161 | bool WaylandQPainterBackend::perScreenRendering() const | ||||
162 | { | ||||
163 | return true; | ||||
164 | } | ||||
165 | | ||||
166 | void WaylandQPainterBackend::createOutput(WaylandOutput *waylandOutput) | ||||
167 | { | ||||
168 | auto *output = new WaylandQPainterOutput(waylandOutput, this); | ||||
169 | output->init(m_backend->shmPool()); | ||||
170 | m_outputs << output; | ||||
171 | } | ||||
172 | | ||||
173 | void WaylandQPainterBackend::present(int mask, const QRegion &damage) | ||||
174 | { | ||||
175 | Q_UNUSED(mask) | ||||
176 | | ||||
177 | Compositor::self()->aboutToSwapBuffers(); | ||||
178 | m_needsFullRepaint = false; | ||||
179 | | ||||
180 | for (auto *output : m_outputs) { | ||||
181 | output->present(damage); | ||||
182 | } | ||||
183 | } | ||||
184 | | ||||
185 | QImage *WaylandQPainterBackend::buffer() | ||||
186 | { | ||||
187 | return bufferForScreen(0); | ||||
188 | } | ||||
189 | | ||||
190 | QImage *WaylandQPainterBackend::bufferForScreen(int screenId) | ||||
191 | { | ||||
192 | auto *output = m_outputs[screenId]; | ||||
193 | return &output->m_backBuffer; | ||||
194 | } | ||||
195 | | ||||
196 | void WaylandQPainterBackend::prepareRenderingFrame() | ||||
197 | { | ||||
198 | for (auto *output : m_outputs) { | ||||
199 | output->prepareRenderingFrame(); | ||||
200 | } | ||||
201 | m_needsFullRepaint = true; | ||||
127 | } | 202 | } | ||
128 | 203 | | |||
129 | bool WaylandQPainterBackend::needsFullRepaint() const | 204 | bool WaylandQPainterBackend::needsFullRepaint() const | ||
130 | { | 205 | { | ||
131 | return m_needsFullRepaint; | 206 | return m_needsFullRepaint; | ||
132 | } | 207 | } | ||
133 | 208 | | |||
134 | } | 209 | } | ||
210 | } |