2021-02-04 09:07:20 +00:00
|
|
|
/*
|
|
|
|
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
|
|
|
|
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
|
|
|
|
2022-12-15 20:35:22 +00:00
|
|
|
#include "scene/surfaceitem.h"
|
2023-07-04 06:19:08 +00:00
|
|
|
#include "scene/scene.h"
|
2021-02-04 09:07:20 +00:00
|
|
|
|
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
|
2022-12-18 22:20:28 +00:00
|
|
|
SurfaceItem::SurfaceItem(Scene *scene, Item *parent)
|
2022-12-18 12:30:40 +00:00
|
|
|
: Item(scene, parent)
|
2021-02-04 09:07:20 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-07-21 19:25:42 +00:00
|
|
|
QMatrix4x4 SurfaceItem::surfaceToBufferMatrix() const
|
|
|
|
{
|
|
|
|
return m_surfaceToBufferMatrix;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceItem::setSurfaceToBufferMatrix(const QMatrix4x4 &matrix)
|
|
|
|
{
|
|
|
|
m_surfaceToBufferMatrix = matrix;
|
2023-06-12 11:12:16 +00:00
|
|
|
m_bufferToSurfaceMatrix = matrix.inverted();
|
|
|
|
}
|
|
|
|
|
2023-07-04 06:19:08 +00:00
|
|
|
QRectF SurfaceItem::bufferSourceBox() const
|
|
|
|
{
|
|
|
|
return m_bufferSourceBox;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceItem::setBufferSourceBox(const QRectF &box)
|
|
|
|
{
|
|
|
|
m_bufferSourceBox = box;
|
|
|
|
}
|
|
|
|
|
2023-07-10 10:33:09 +00:00
|
|
|
OutputTransform SurfaceItem::bufferTransform() const
|
2023-07-04 06:19:08 +00:00
|
|
|
{
|
|
|
|
return m_bufferTransform;
|
|
|
|
}
|
|
|
|
|
2023-07-10 10:33:09 +00:00
|
|
|
void SurfaceItem::setBufferTransform(OutputTransform transform)
|
2023-07-04 06:19:08 +00:00
|
|
|
{
|
|
|
|
m_bufferTransform = transform;
|
|
|
|
}
|
|
|
|
|
|
|
|
QSize SurfaceItem::bufferSize() const
|
|
|
|
{
|
|
|
|
return m_bufferSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceItem::setBufferSize(const QSize &size)
|
|
|
|
{
|
|
|
|
m_bufferSize = size;
|
|
|
|
}
|
|
|
|
|
2023-06-12 11:12:16 +00:00
|
|
|
QRegion SurfaceItem::mapFromBuffer(const QRegion ®ion) const
|
|
|
|
{
|
|
|
|
QRegion result;
|
|
|
|
for (const QRect &rect : region) {
|
|
|
|
result += m_bufferToSurfaceMatrix.mapRect(QRectF(rect)).toAlignedRect();
|
|
|
|
}
|
|
|
|
return result;
|
2021-07-21 19:25:42 +00:00
|
|
|
}
|
|
|
|
|
2023-07-04 06:19:08 +00:00
|
|
|
static QRegion expandRegion(const QRegion ®ion, const QMargins &padding)
|
|
|
|
{
|
|
|
|
if (region.isEmpty()) {
|
|
|
|
return QRegion();
|
|
|
|
}
|
|
|
|
|
|
|
|
QRegion ret;
|
|
|
|
for (const QRect &rect : region) {
|
|
|
|
ret += rect.marginsAdded(padding);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-02-04 09:07:20 +00:00
|
|
|
void SurfaceItem::addDamage(const QRegion ®ion)
|
|
|
|
{
|
|
|
|
m_damage += region;
|
2023-07-04 06:19:08 +00:00
|
|
|
|
2023-07-10 10:57:57 +00:00
|
|
|
const QRectF sourceBox = m_bufferTransform.map(m_bufferSourceBox, m_bufferSize);
|
2023-07-04 06:19:08 +00:00
|
|
|
const qreal xScale = sourceBox.width() / size().width();
|
|
|
|
const qreal yScale = sourceBox.height() / size().height();
|
|
|
|
const QRegion logicalDamage = mapFromBuffer(region);
|
|
|
|
|
|
|
|
const auto delegates = scene()->delegates();
|
|
|
|
for (SceneDelegate *delegate : delegates) {
|
|
|
|
QRegion delegateDamage = logicalDamage;
|
|
|
|
const qreal delegateScale = delegate->scale();
|
|
|
|
if (xScale != delegateScale || yScale != delegateScale) {
|
|
|
|
// Simplified version of ceil(ceil(0.5 * output_scale / surface_scale) / output_scale)
|
|
|
|
const int xPadding = std::ceil(0.5 / xScale);
|
|
|
|
const int yPadding = std::ceil(0.5 / yScale);
|
|
|
|
delegateDamage = expandRegion(delegateDamage, QMargins(xPadding, yPadding, xPadding, yPadding));
|
|
|
|
}
|
|
|
|
scheduleRepaint(delegate, delegateDamage);
|
|
|
|
}
|
|
|
|
|
2022-12-14 14:52:10 +00:00
|
|
|
Q_EMIT damaged();
|
2021-02-04 09:07:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceItem::resetDamage()
|
|
|
|
{
|
|
|
|
m_damage = QRegion();
|
|
|
|
}
|
|
|
|
|
|
|
|
QRegion SurfaceItem::damage() const
|
|
|
|
{
|
|
|
|
return m_damage;
|
|
|
|
}
|
|
|
|
|
2021-04-09 07:06:04 +00:00
|
|
|
SurfacePixmap *SurfaceItem::pixmap() const
|
2021-02-04 09:07:20 +00:00
|
|
|
{
|
2021-04-09 07:06:04 +00:00
|
|
|
if (m_pixmap && m_pixmap->isValid()) {
|
2022-06-29 11:24:56 +00:00
|
|
|
return m_pixmap.get();
|
2021-02-04 09:07:20 +00:00
|
|
|
}
|
2021-04-09 07:06:04 +00:00
|
|
|
if (m_previousPixmap && m_previousPixmap->isValid()) {
|
2022-06-29 11:24:56 +00:00
|
|
|
return m_previousPixmap.get();
|
2021-02-04 09:07:20 +00:00
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2021-04-09 07:06:04 +00:00
|
|
|
SurfacePixmap *SurfaceItem::previousPixmap() const
|
2021-02-04 09:07:20 +00:00
|
|
|
{
|
2022-06-29 11:24:56 +00:00
|
|
|
return m_previousPixmap.get();
|
2021-02-04 09:07:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceItem::referencePreviousPixmap()
|
|
|
|
{
|
2021-04-09 07:06:04 +00:00
|
|
|
if (m_previousPixmap && m_previousPixmap->isDiscarded()) {
|
2021-02-04 09:07:20 +00:00
|
|
|
m_referencePixmapCounter++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceItem::unreferencePreviousPixmap()
|
|
|
|
{
|
2021-04-09 07:06:04 +00:00
|
|
|
if (!m_previousPixmap || !m_previousPixmap->isDiscarded()) {
|
2021-02-04 09:07:20 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_referencePixmapCounter--;
|
|
|
|
if (m_referencePixmapCounter == 0) {
|
2021-04-09 07:06:04 +00:00
|
|
|
m_previousPixmap.reset();
|
2021-02-04 09:07:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceItem::updatePixmap()
|
|
|
|
{
|
2022-06-29 11:24:56 +00:00
|
|
|
if (!m_pixmap) {
|
|
|
|
m_pixmap = createPixmap();
|
2021-02-04 09:07:20 +00:00
|
|
|
}
|
2021-04-09 07:06:04 +00:00
|
|
|
if (m_pixmap->isValid()) {
|
|
|
|
m_pixmap->update();
|
2021-02-04 09:07:20 +00:00
|
|
|
} else {
|
2021-04-09 07:06:04 +00:00
|
|
|
m_pixmap->create();
|
|
|
|
if (m_pixmap->isValid()) {
|
2021-09-15 13:13:08 +00:00
|
|
|
unreferencePreviousPixmap();
|
2021-02-04 09:07:20 +00:00
|
|
|
discardQuads();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceItem::discardPixmap()
|
|
|
|
{
|
2022-06-29 11:24:56 +00:00
|
|
|
if (m_pixmap) {
|
2021-04-09 07:06:04 +00:00
|
|
|
if (m_pixmap->isValid()) {
|
2022-06-29 11:24:56 +00:00
|
|
|
m_previousPixmap = std::move(m_pixmap);
|
2021-04-09 07:06:04 +00:00
|
|
|
m_previousPixmap->markAsDiscarded();
|
2021-09-15 13:13:08 +00:00
|
|
|
referencePreviousPixmap();
|
2021-02-04 09:07:20 +00:00
|
|
|
} else {
|
2021-04-09 07:06:04 +00:00
|
|
|
m_pixmap.reset();
|
2021-02-04 09:07:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-29 23:20:37 +00:00
|
|
|
void SurfaceItem::destroyPixmap()
|
|
|
|
{
|
|
|
|
m_pixmap.reset();
|
|
|
|
}
|
|
|
|
|
2021-02-04 09:07:20 +00:00
|
|
|
void SurfaceItem::preprocess()
|
|
|
|
{
|
|
|
|
updatePixmap();
|
|
|
|
}
|
|
|
|
|
2021-05-21 10:51:23 +00:00
|
|
|
WindowQuadList SurfaceItem::buildQuads() const
|
|
|
|
{
|
2022-10-20 13:05:40 +00:00
|
|
|
if (!pixmap()) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2022-09-12 09:29:33 +00:00
|
|
|
const QVector<QRectF> region = shape();
|
2022-07-27 11:10:02 +00:00
|
|
|
const auto size = pixmap()->size();
|
2021-05-21 10:51:23 +00:00
|
|
|
|
|
|
|
WindowQuadList quads;
|
2022-09-12 09:29:33 +00:00
|
|
|
quads.reserve(region.count());
|
2021-05-21 10:51:23 +00:00
|
|
|
|
|
|
|
for (const QRectF rect : region) {
|
2021-06-10 10:32:37 +00:00
|
|
|
WindowQuad quad;
|
2021-05-21 10:51:23 +00:00
|
|
|
|
2022-08-12 10:31:50 +00:00
|
|
|
// Use toPoint to round the device position to match what we eventually
|
|
|
|
// do for the geometry, otherwise we end up with mismatched UV
|
|
|
|
// coordinates as the texture size is going to be in (rounded) device
|
|
|
|
// coordinates as well.
|
|
|
|
const QPointF bufferTopLeft = m_surfaceToBufferMatrix.map(rect.topLeft()).toPoint();
|
|
|
|
const QPointF bufferTopRight = m_surfaceToBufferMatrix.map(rect.topRight()).toPoint();
|
|
|
|
const QPointF bufferBottomRight = m_surfaceToBufferMatrix.map(rect.bottomRight()).toPoint();
|
|
|
|
const QPointF bufferBottomLeft = m_surfaceToBufferMatrix.map(rect.bottomLeft()).toPoint();
|
2021-05-21 10:51:23 +00:00
|
|
|
|
2022-07-05 11:27:48 +00:00
|
|
|
quad[0] = WindowVertex(rect.topLeft(), QPointF{bufferTopLeft.x() / size.width(), bufferTopLeft.y() / size.height()});
|
|
|
|
quad[1] = WindowVertex(rect.topRight(), QPointF{bufferTopRight.x() / size.width(), bufferTopRight.y() / size.height()});
|
|
|
|
quad[2] = WindowVertex(rect.bottomRight(), QPointF{bufferBottomRight.x() / size.width(), bufferBottomRight.y() / size.height()});
|
|
|
|
quad[3] = WindowVertex(rect.bottomLeft(), QPointF{bufferBottomLeft.x() / size.width(), bufferBottomLeft.y() / size.height()});
|
2021-05-21 10:51:23 +00:00
|
|
|
|
|
|
|
quads << quad;
|
|
|
|
}
|
|
|
|
|
|
|
|
return quads;
|
|
|
|
}
|
|
|
|
|
2022-05-25 09:38:59 +00:00
|
|
|
ContentType SurfaceItem::contentType() const
|
|
|
|
{
|
|
|
|
return ContentType::None;
|
|
|
|
}
|
|
|
|
|
2021-10-20 14:58:58 +00:00
|
|
|
SurfaceTexture::~SurfaceTexture()
|
2021-04-09 07:06:04 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-06-29 11:21:35 +00:00
|
|
|
SurfacePixmap::SurfacePixmap(std::unique_ptr<SurfaceTexture> &&texture, QObject *parent)
|
2021-04-09 07:06:04 +00:00
|
|
|
: QObject(parent)
|
2022-06-29 11:21:35 +00:00
|
|
|
, m_texture(std::move(texture))
|
2021-04-09 07:06:04 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-08-04 11:13:21 +00:00
|
|
|
GraphicsBuffer *SurfacePixmap::buffer() const
|
|
|
|
{
|
|
|
|
return m_bufferRef.buffer();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfacePixmap::setBuffer(GraphicsBuffer *buffer)
|
|
|
|
{
|
|
|
|
if (m_bufferRef.buffer() == buffer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_bufferRef = buffer;
|
|
|
|
if (m_bufferRef) {
|
|
|
|
m_hasAlphaChannel = m_bufferRef->hasAlphaChannel();
|
|
|
|
m_size = m_bufferRef->size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GraphicsBufferOrigin SurfacePixmap::bufferOrigin() const
|
|
|
|
{
|
|
|
|
return m_bufferOrigin;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfacePixmap::setBufferOrigin(GraphicsBufferOrigin origin)
|
|
|
|
{
|
|
|
|
m_bufferOrigin = origin;
|
|
|
|
}
|
|
|
|
|
2021-04-09 07:06:04 +00:00
|
|
|
void SurfacePixmap::update()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-10-20 14:58:58 +00:00
|
|
|
SurfaceTexture *SurfacePixmap::texture() const
|
2021-04-09 07:06:04 +00:00
|
|
|
{
|
2022-06-29 11:21:35 +00:00
|
|
|
return m_texture.get();
|
2021-04-09 07:06:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SurfacePixmap::hasAlphaChannel() const
|
|
|
|
{
|
|
|
|
return m_hasAlphaChannel;
|
|
|
|
}
|
|
|
|
|
|
|
|
QSize SurfacePixmap::size() const
|
|
|
|
{
|
|
|
|
return m_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SurfacePixmap::isDiscarded() const
|
|
|
|
{
|
|
|
|
return m_isDiscarded;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfacePixmap::markAsDiscarded()
|
|
|
|
{
|
|
|
|
m_isDiscarded = true;
|
|
|
|
}
|
|
|
|
|
2021-02-04 09:07:20 +00:00
|
|
|
} // namespace KWin
|
2023-07-05 06:30:14 +00:00
|
|
|
|
|
|
|
#include "moc_surfaceitem.cpp"
|