KWin
Loading...
Searching...
No Matches
surfaceitem.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "scene/surfaceitem.h"
8#include "core/pixelgrid.h"
9#include "scene/scene.h"
10
11using namespace std::chrono_literals;
12
13namespace KWin
14{
15
17 : Item(scene, parent)
18{
19}
20
22{
23 return m_destinationSize;
24}
25
26void SurfaceItem::setDestinationSize(const QSizeF &size)
27{
28 if (m_destinationSize != size) {
32 }
33}
34
36{
37 return m_bufferSourceBox;
38}
39
40void SurfaceItem::setBufferSourceBox(const QRectF &box)
41{
42 if (m_bufferSourceBox != box) {
45 }
46}
47
52
61
63{
64 return m_bufferSize;
65}
66
67void SurfaceItem::setBufferSize(const QSize &size)
68{
69 if (m_bufferSize != size) {
73 }
74}
75
76QRegion SurfaceItem::mapFromBuffer(const QRegion &region) const
77{
79 const qreal xScale = m_destinationSize.width() / sourceBox.width();
80 const qreal yScale = m_destinationSize.height() / sourceBox.height();
81
82 QRegion result;
83 for (QRectF rect : region) {
84 const QRectF r = m_bufferToSurfaceTransform.map(rect, m_bufferSize).translated(-sourceBox.topLeft());
85 result += QRectF(r.x() * xScale, r.y() * yScale, r.width() * xScale, r.height() * yScale).toAlignedRect();
86 }
87 return result;
88}
89
90static QRegion expandRegion(const QRegion &region, const QMargins &padding)
91{
92 if (region.isEmpty()) {
93 return QRegion();
94 }
95
96 QRegion ret;
97 for (const QRect &rect : region) {
98 ret += rect.marginsAdded(padding);
99 }
100
101 return ret;
102}
103
104void SurfaceItem::addDamage(const QRegion &region)
105{
106 if (m_lastDamage) {
107 const auto diff = std::chrono::steady_clock::now() - *m_lastDamage;
108 m_lastDamageTimeDiffs.push_back(diff);
109 if (m_lastDamageTimeDiffs.size() > 100) {
110 m_lastDamageTimeDiffs.pop_front();
111 }
112 m_frameTimeEstimation = std::accumulate(m_lastDamageTimeDiffs.begin(), m_lastDamageTimeDiffs.end(), 0ns) / m_lastDamageTimeDiffs.size();
113 }
114 m_lastDamage = std::chrono::steady_clock::now();
115 m_damage += region;
116
118 const qreal xScale = sourceBox.width() / m_destinationSize.width();
119 const qreal yScale = sourceBox.height() / m_destinationSize.height();
120 const QRegion logicalDamage = mapFromBuffer(region);
121
122 const auto delegates = scene()->delegates();
123 for (SceneDelegate *delegate : delegates) {
124 QRegion delegateDamage = logicalDamage;
125 const qreal delegateScale = delegate->scale();
126 if (xScale != delegateScale || yScale != delegateScale) {
127 // Simplified version of ceil(ceil(0.5 * output_scale / surface_scale) / output_scale)
128 const int xPadding = std::ceil(0.5 / xScale);
129 const int yPadding = std::ceil(0.5 / yScale);
130 delegateDamage = expandRegion(delegateDamage, QMargins(xPadding, yPadding, xPadding, yPadding));
131 }
132 scheduleRepaint(delegate, delegateDamage);
133 }
134
135 Q_EMIT damaged();
136}
137
139{
140 m_damage = QRegion();
141}
142
143QRegion SurfaceItem::damage() const
144{
145 return m_damage;
146}
147
149{
150 if (m_pixmap && m_pixmap->isValid()) {
151 return m_pixmap.get();
152 }
153 if (m_previousPixmap && m_previousPixmap->isValid()) {
154 return m_previousPixmap.get();
155 }
156 return nullptr;
157}
158
160{
161 return m_previousPixmap.get();
162}
163
170
172{
173 if (!m_previousPixmap || !m_previousPixmap->isDiscarded()) {
174 return;
175 }
177 if (m_referencePixmapCounter == 0) {
178 m_previousPixmap.reset();
179 }
180}
181
183{
184 if (!m_pixmap) {
186 }
187 if (m_pixmap->isValid()) {
188 m_pixmap->update();
189 } else {
190 m_pixmap->create();
191 if (m_pixmap->isValid()) {
193 discardQuads();
194 }
195 }
196}
197
199{
200 if (m_pixmap) {
201 if (m_pixmap->isValid()) {
202 m_previousPixmap = std::move(m_pixmap);
203 m_previousPixmap->markAsDiscarded();
205 } else {
206 m_pixmap.reset();
207 }
208 }
209}
210
212{
213 m_pixmap.reset();
214}
215
217{
218 updatePixmap();
219}
220
222{
223 if (!pixmap()) {
224 return {};
225 }
226
227 const QList<QRectF> region = shape();
229 quads.reserve(region.count());
230
232 const qreal xScale = sourceBox.width() / m_destinationSize.width();
233 const qreal yScale = sourceBox.height() / m_destinationSize.height();
234
235 for (const QRectF rect : region) {
236 WindowQuad quad;
237
238 const QPointF bufferTopLeft = snapToPixelGridF(m_bufferSourceBox.topLeft() + m_surfaceToBufferTransform.map(QPointF(rect.left() * xScale, rect.top() * yScale), sourceBox.size()));
239 const QPointF bufferTopRight = snapToPixelGridF(m_bufferSourceBox.topLeft() + m_surfaceToBufferTransform.map(QPointF(rect.right() * xScale, rect.top() * yScale), sourceBox.size()));
240 const QPointF bufferBottomRight = snapToPixelGridF(m_bufferSourceBox.topLeft() + m_surfaceToBufferTransform.map(QPointF(rect.right() * xScale, rect.bottom() * yScale), sourceBox.size()));
241 const QPointF bufferBottomLeft = snapToPixelGridF(m_bufferSourceBox.topLeft() + m_surfaceToBufferTransform.map(QPointF(rect.left() * xScale, rect.bottom() * yScale), sourceBox.size()));
242
243 quad[0] = WindowVertex(rect.topLeft(), QPointF{bufferTopLeft.x() / m_bufferSize.width(), bufferTopLeft.y() / m_bufferSize.height()});
244 quad[1] = WindowVertex(rect.topRight(), QPointF{bufferTopRight.x() / m_bufferSize.width(), bufferTopRight.y() / m_bufferSize.height()});
245 quad[2] = WindowVertex(rect.bottomRight(), QPointF{bufferBottomRight.x() / m_bufferSize.width(), bufferBottomRight.y() / m_bufferSize.height()});
246 quad[3] = WindowVertex(rect.bottomLeft(), QPointF{bufferBottomLeft.x() / m_bufferSize.width(), bufferBottomLeft.y() / m_bufferSize.height()});
247
248 quads << quad;
249 }
250
251 return quads;
252}
253
258
260{
261}
262
263std::chrono::nanoseconds SurfaceItem::frameTimeEstimation() const
264{
265 if (m_lastDamage) {
266 const auto diff = std::chrono::steady_clock::now() - *m_lastDamage;
267 return std::max(m_frameTimeEstimation, diff);
268 } else {
270 }
271}
272
276
277SurfacePixmap::SurfacePixmap(std::unique_ptr<SurfaceTexture> &&texture, QObject *parent)
278 : QObject(parent)
279 , m_texture(std::move(texture))
280{
281}
282
287
289{
290 if (m_bufferRef.buffer() == buffer) {
291 return;
292 }
294 if (m_bufferRef) {
297 }
298}
299
304
309
311{
312}
313
315{
316 return m_texture.get();
317}
318
320{
321 return m_hasAlphaChannel;
322}
323
325{
326 return m_size;
327}
328
330{
331 return m_isDiscarded;
332}
333
335{
336 m_isDiscarded = true;
337}
338
339} // namespace KWin
340
341#include "moc_surfaceitem.cpp"
virtual bool hasAlphaChannel() const =0
virtual QSize size() const =0
GraphicsBuffer * buffer() const
Scene * scene() const
Definition item.cpp:32
WindowQuadList quads() const
Definition item.cpp:355
QRectF rect() const
Definition item.cpp:152
void setSize(const QSizeF &size)
Definition item.cpp:140
void discardQuads()
Definition item.cpp:350
QSizeF size() const
Definition item.cpp:135
void scheduleRepaint(const QRectF &region)
Definition item.cpp:396
virtual QList< QRectF > shape() const
Definition item.cpp:177
QMatrix4x4 transform() const
Definition item.cpp:200
QSizeF map(const QSizeF &size) const
Definition output.cpp:242
OutputTransform inverted() const
Definition output.cpp:69
QList< SceneDelegate * > delegates() const
Definition scene.cpp:121
OutputTransform bufferTransform() const
SurfaceItem(Scene *scene, Item *parent=nullptr)
virtual ContentType contentType() const
SurfacePixmap * previousPixmap() const
std::unique_ptr< SurfacePixmap > m_pixmap
Definition surfaceitem.h:79
virtual std::unique_ptr< SurfacePixmap > createPixmap()=0
QSizeF m_destinationSize
Definition surfaceitem.h:78
void setDestinationSize(const QSizeF &size)
void setBufferTransform(OutputTransform transform)
void preprocess() override
virtual void freeze()
WindowQuadList buildQuads() const override
void setBufferSize(const QSize &size)
QRectF m_bufferSourceBox
Definition surfaceitem.h:76
QRectF bufferSourceBox() const
SurfacePixmap * pixmap() const
void addDamage(const QRegion &region)
std::chrono::nanoseconds m_frameTimeEstimation
Definition surfaceitem.h:84
QRegion damage() const
OutputTransform m_surfaceToBufferTransform
Definition surfaceitem.h:75
void setBufferSourceBox(const QRectF &box)
std::unique_ptr< SurfacePixmap > m_previousPixmap
Definition surfaceitem.h:80
QSizeF destinationSize() const
void unreferencePreviousPixmap()
std::deque< std::chrono::nanoseconds > m_lastDamageTimeDiffs
Definition surfaceitem.h:82
std::optional< std::chrono::steady_clock::time_point > m_lastDamage
Definition surfaceitem.h:83
QSize bufferSize() const
OutputTransform m_bufferToSurfaceTransform
Definition surfaceitem.h:74
void referencePreviousPixmap()
QRegion mapFromBuffer(const QRegion &region) const
std::chrono::nanoseconds frameTimeEstimation() const
virtual void update()
GraphicsBufferOrigin m_bufferOrigin
GraphicsBufferRef m_bufferRef
bool isDiscarded() const
GraphicsBuffer * buffer() const
SurfacePixmap(std::unique_ptr< SurfaceTexture > &&texture, QObject *parent=nullptr)
SurfaceTexture * texture() const
GraphicsBufferOrigin bufferOrigin() const
void setBufferOrigin(GraphicsBufferOrigin origin)
void setBuffer(GraphicsBuffer *buffer)
bool hasAlphaChannel() const
Class representing one area of a window.
Vertex class.
GraphicsBufferOrigin
KWIN_EXPORT QPointF snapToPixelGridF(const QPointF &point)
Definition pixelgrid.h:21
ContentType
Definition globals.h:284