File indexing completed on 2024-11-10 04:57:05

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
0006     SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 #include "backingstore.h"
0011 #include "core/graphicsbuffer.h"
0012 #include "core/graphicsbufferview.h"
0013 #include "internalwindow.h"
0014 #include "logging.h"
0015 #include "swapchain.h"
0016 #include "window.h"
0017 
0018 #include <QPainter>
0019 #include <libdrm/drm_fourcc.h>
0020 
0021 namespace KWin
0022 {
0023 namespace QPA
0024 {
0025 
0026 BackingStore::BackingStore(QWindow *window)
0027     : QPlatformBackingStore(window)
0028 {
0029 }
0030 
0031 QPaintDevice *BackingStore::paintDevice()
0032 {
0033     return m_bufferView->image();
0034 }
0035 
0036 void BackingStore::resize(const QSize &size, const QRegion &staticContents)
0037 {
0038     QPlatformWindow *platformWindow = static_cast<QPlatformWindow *>(window()->handle());
0039     platformWindow->invalidateSurface();
0040 }
0041 
0042 void BackingStore::beginPaint(const QRegion &region)
0043 {
0044     Window *platformWindow = static_cast<Window *>(window()->handle());
0045     Swapchain *swapchain = platformWindow->swapchain({{DRM_FORMAT_ARGB8888, {DRM_FORMAT_MOD_LINEAR}}});
0046     if (!swapchain) {
0047         qCCritical(KWIN_QPA, "Failed to ceate a swapchain for the backing store!");
0048         return;
0049     }
0050 
0051     const auto oldBuffer = m_buffer;
0052     m_buffer = swapchain->acquire();
0053     if (!m_buffer) {
0054         qCCritical(KWIN_QPA, "Failed to acquire a graphics buffer for the backing store");
0055         return;
0056     }
0057 
0058     m_bufferView = std::make_unique<GraphicsBufferView>(m_buffer, GraphicsBuffer::Read | GraphicsBuffer::Write);
0059     if (m_bufferView->isNull()) {
0060         qCCritical(KWIN_QPA) << "Failed to map a graphics buffer for the backing store";
0061         return;
0062     }
0063 
0064     if (oldBuffer && oldBuffer != m_buffer && oldBuffer->size() == m_buffer->size()) {
0065         const GraphicsBufferView oldView(oldBuffer, GraphicsBuffer::Read);
0066         std::memcpy(m_bufferView->image()->bits(), oldView.image()->constBits(), oldView.image()->sizeInBytes());
0067     }
0068 
0069     QImage *image = m_bufferView->image();
0070     image->setDevicePixelRatio(platformWindow->devicePixelRatio());
0071 
0072     if (image->hasAlphaChannel()) {
0073         QPainter p(image);
0074         p.setCompositionMode(QPainter::CompositionMode_Source);
0075         const QColor blank = Qt::transparent;
0076         for (const QRect &rect : region) {
0077             p.fillRect(rect, blank);
0078         }
0079     }
0080 }
0081 
0082 void BackingStore::endPaint()
0083 {
0084     m_bufferView.reset();
0085 }
0086 
0087 void BackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
0088 {
0089     Window *platformWindow = static_cast<Window *>(window->handle());
0090     InternalWindow *internalWindow = platformWindow->internalWindow();
0091     if (!internalWindow) {
0092         return;
0093     }
0094 
0095     const qreal scale = platformWindow->devicePixelRatio();
0096     QRegion bufferDamage;
0097     for (const QRect &rect : region) {
0098         bufferDamage += QRectF(rect.x() * scale, rect.y() * scale, rect.width() * scale, rect.height() * scale).toAlignedRect();
0099     }
0100 
0101     internalWindow->present(InternalWindowFrame{
0102         .buffer = m_buffer,
0103         .bufferDamage = bufferDamage,
0104     });
0105 }
0106 
0107 }
0108 }