qpa: Port BackingStore to shared memory graphics buffer allocator
At the moment, graphics buffers coming from wayland and internal windows use different code paths to update textures. However, they don't have to. If the internal windows are ported to GraphicsBuffer, it will be possible to unify SurfacePixmapInternal and SurfacePixmapWayland to make pixmap logic a bit simpler.
This commit is contained in:
parent
84149945f6
commit
762254c354
8 changed files with 142 additions and 48 deletions
|
@ -366,14 +366,14 @@ const std::shared_ptr<QOpenGLFramebufferObject> &InternalWindow::fbo() const
|
|||
return m_fbo;
|
||||
}
|
||||
|
||||
QImage InternalWindow::image() const
|
||||
GraphicsBuffer *InternalWindow::graphicsBuffer() const
|
||||
{
|
||||
return m_image;
|
||||
return m_graphicsBufferRef.buffer();
|
||||
}
|
||||
|
||||
void InternalWindow::present(const std::shared_ptr<QOpenGLFramebufferObject> fbo)
|
||||
{
|
||||
Q_ASSERT(m_image.isNull());
|
||||
Q_ASSERT(!m_graphicsBufferRef);
|
||||
|
||||
const QSizeF bufferSize = fbo->size() / bufferScale();
|
||||
QRectF geometry(pos(), clientSizeToFrameSize(bufferSize));
|
||||
|
@ -389,11 +389,11 @@ void InternalWindow::present(const std::shared_ptr<QOpenGLFramebufferObject> fbo
|
|||
surfaceItem()->addDamage(QRect(0, 0, fbo->width(), fbo->height()));
|
||||
}
|
||||
|
||||
void InternalWindow::present(const QImage &image, const QRegion &damage)
|
||||
void InternalWindow::present(GraphicsBuffer *buffer, const QRegion &damage)
|
||||
{
|
||||
Q_ASSERT(m_fbo == nullptr);
|
||||
|
||||
const QSize bufferSize = image.size() / bufferScale();
|
||||
const QSize bufferSize = buffer->size() / bufferScale();
|
||||
QRectF geometry(pos(), clientSizeToFrameSize(bufferSize));
|
||||
if (isInteractiveResize()) {
|
||||
geometry = gravitateGeometry(geometry, moveResizeGeometry(), interactiveMoveResizeGravity());
|
||||
|
@ -402,7 +402,7 @@ void InternalWindow::present(const QImage &image, const QRegion &damage)
|
|||
commitGeometry(geometry);
|
||||
markAsMapped();
|
||||
|
||||
m_image = image;
|
||||
m_graphicsBufferRef = buffer;
|
||||
|
||||
surfaceItem()->addDamage(damage);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "core/graphicsbuffer.h"
|
||||
#include "window.h"
|
||||
|
||||
class QOpenGLFramebufferObject;
|
||||
|
@ -60,10 +61,10 @@ public:
|
|||
void pointerLeaveEvent() override;
|
||||
|
||||
const std::shared_ptr<QOpenGLFramebufferObject> &fbo() const;
|
||||
QImage image() const;
|
||||
GraphicsBuffer *graphicsBuffer() const;
|
||||
|
||||
void present(const std::shared_ptr<QOpenGLFramebufferObject> fbo);
|
||||
void present(const QImage &image, const QRegion &damage);
|
||||
void present(GraphicsBuffer *buffer, const QRegion &damage);
|
||||
qreal bufferScale() const;
|
||||
QWindow *handle() const;
|
||||
|
||||
|
@ -93,7 +94,7 @@ private:
|
|||
Qt::WindowFlags m_internalWindowFlags = Qt::WindowFlags();
|
||||
bool m_userNoBorder = false;
|
||||
std::shared_ptr<QOpenGLFramebufferObject> m_fbo;
|
||||
QImage m_image;
|
||||
GraphicsBufferRef m_graphicsBufferRef;
|
||||
|
||||
Q_DISABLE_COPY(InternalWindow)
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include "platformsupport/scenes/opengl/basiceglsurfacetexture_internal.h"
|
||||
#include "core/graphicsbufferview.h"
|
||||
#include "libkwineffects/kwingltexture.h"
|
||||
#include "scene/surfaceitem_internal.h"
|
||||
#include "utils/common.h"
|
||||
|
@ -24,19 +25,24 @@ bool BasicEGLSurfaceTextureInternal::create()
|
|||
{
|
||||
if (updateFromFramebuffer()) {
|
||||
return true;
|
||||
} else if (updateFromImage(m_pixmap->image().rect())) {
|
||||
return true;
|
||||
} else {
|
||||
}
|
||||
|
||||
GraphicsBuffer *buffer = m_pixmap->graphicsBuffer();
|
||||
if (!buffer) {
|
||||
qCDebug(KWIN_OPENGL) << "Failed to create surface texture for internal window";
|
||||
return false;
|
||||
}
|
||||
|
||||
return updateFromImage(QRect(QPoint(0, 0), buffer->size()));
|
||||
}
|
||||
|
||||
void BasicEGLSurfaceTextureInternal::update(const QRegion ®ion)
|
||||
{
|
||||
if (updateFromFramebuffer()) {
|
||||
return;
|
||||
} else if (updateFromImage(region)) {
|
||||
}
|
||||
if (m_pixmap->graphicsBuffer()) {
|
||||
updateFromImage(region);
|
||||
return;
|
||||
} else {
|
||||
qCDebug(KWIN_OPENGL) << "Failed to update surface texture for internal window";
|
||||
|
@ -58,16 +64,16 @@ bool BasicEGLSurfaceTextureInternal::updateFromFramebuffer()
|
|||
|
||||
bool BasicEGLSurfaceTextureInternal::updateFromImage(const QRegion ®ion)
|
||||
{
|
||||
const QImage image = m_pixmap->image();
|
||||
if (image.isNull()) {
|
||||
const GraphicsBufferView view(m_pixmap->graphicsBuffer());
|
||||
if (view.isNull()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_texture) {
|
||||
m_texture = GLTexture::upload(image);
|
||||
m_texture = GLTexture::upload(*view.image());
|
||||
} else {
|
||||
for (const QRect &rect : region) {
|
||||
m_texture->update(image, rect.topLeft(), rect);
|
||||
m_texture->update(*view.image(), rect.topLeft(), rect);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include "qpaintersurfacetexture_internal.h"
|
||||
#include "core/graphicsbufferview.h"
|
||||
#include "scene/surfaceitem_internal.h"
|
||||
|
||||
namespace KWin
|
||||
|
@ -25,7 +26,16 @@ bool QPainterSurfaceTextureInternal::create()
|
|||
|
||||
void QPainterSurfaceTextureInternal::update(const QRegion ®ion)
|
||||
{
|
||||
m_image = m_pixmap->image();
|
||||
if (!m_pixmap->graphicsBuffer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const GraphicsBufferView view(m_pixmap->graphicsBuffer());
|
||||
if (view.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_image = view.image()->copy();
|
||||
}
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -8,46 +8,115 @@
|
|||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include "backingstore.h"
|
||||
#include "core/graphicsbuffer.h"
|
||||
#include "core/graphicsbufferview.h"
|
||||
#include "core/shmgraphicsbufferallocator.h"
|
||||
#include "internalwindow.h"
|
||||
#include "window.h"
|
||||
|
||||
#include "internalwindow.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
#include <libdrm/drm_fourcc.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
namespace QPA
|
||||
{
|
||||
|
||||
class BackingStoreSlot
|
||||
{
|
||||
public:
|
||||
explicit BackingStoreSlot(GraphicsBuffer *graphicsBuffer);
|
||||
~BackingStoreSlot();
|
||||
|
||||
GraphicsBuffer *graphicsBuffer;
|
||||
std::unique_ptr<GraphicsBufferView> graphicsBufferView;
|
||||
};
|
||||
|
||||
BackingStoreSlot::BackingStoreSlot(GraphicsBuffer *graphicsBuffer)
|
||||
: graphicsBuffer(graphicsBuffer)
|
||||
, graphicsBufferView(std::make_unique<GraphicsBufferView>(graphicsBuffer, GraphicsBuffer::Read | GraphicsBuffer::Write))
|
||||
{
|
||||
}
|
||||
|
||||
BackingStoreSlot::~BackingStoreSlot()
|
||||
{
|
||||
graphicsBufferView.reset();
|
||||
graphicsBuffer->drop();
|
||||
}
|
||||
|
||||
BackingStore::BackingStore(QWindow *window)
|
||||
: QPlatformBackingStore(window)
|
||||
{
|
||||
}
|
||||
|
||||
BackingStore::~BackingStore() = default;
|
||||
|
||||
QPaintDevice *BackingStore::paintDevice()
|
||||
{
|
||||
return &m_buffer;
|
||||
return m_backBuffer->graphicsBufferView->image();
|
||||
}
|
||||
|
||||
std::shared_ptr<BackingStoreSlot> BackingStore::allocate(const QSize &size)
|
||||
{
|
||||
ShmGraphicsBufferAllocator allocator;
|
||||
|
||||
GraphicsBuffer *buffer = allocator.allocate(GraphicsBufferOptions{
|
||||
.size = size,
|
||||
.format = DRM_FORMAT_ARGB8888,
|
||||
.software = true,
|
||||
});
|
||||
if (!buffer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto slot = std::make_shared<BackingStoreSlot>(buffer);
|
||||
m_slots.push_back(slot);
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
std::shared_ptr<BackingStoreSlot> BackingStore::acquire()
|
||||
{
|
||||
const QSize bufferSize = m_requestedSize * m_requestedDevicePixelRatio;
|
||||
if (!m_slots.empty()) {
|
||||
const auto front = m_slots.front();
|
||||
if (front->graphicsBuffer->size() == bufferSize) {
|
||||
for (const auto &slot : m_slots) {
|
||||
if (!slot->graphicsBuffer->isReferenced()) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
return allocate(bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
m_slots.clear();
|
||||
return allocate(bufferSize);
|
||||
}
|
||||
|
||||
void BackingStore::resize(const QSize &size, const QRegion &staticContents)
|
||||
{
|
||||
if (m_buffer.size() == size) {
|
||||
return;
|
||||
}
|
||||
m_requestedSize = size;
|
||||
|
||||
const QPlatformWindow *platformWindow = static_cast<QPlatformWindow *>(window()->handle());
|
||||
const qreal devicePixelRatio = platformWindow->devicePixelRatio();
|
||||
|
||||
m_buffer = QImage(size * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
|
||||
m_buffer.setDevicePixelRatio(devicePixelRatio);
|
||||
m_requestedDevicePixelRatio = platformWindow->devicePixelRatio();
|
||||
}
|
||||
|
||||
void BackingStore::beginPaint(const QRegion ®ion)
|
||||
{
|
||||
if (m_buffer.hasAlphaChannel()) {
|
||||
QPainter p(paintDevice());
|
||||
const auto oldBackBuffer = m_backBuffer;
|
||||
m_backBuffer = acquire();
|
||||
|
||||
if (oldBackBuffer && oldBackBuffer != m_backBuffer && oldBackBuffer->graphicsBuffer->size() == m_backBuffer->graphicsBuffer->size()) {
|
||||
const GraphicsBufferView *oldView = oldBackBuffer->graphicsBufferView.get();
|
||||
GraphicsBufferView *view = m_backBuffer->graphicsBufferView.get();
|
||||
std::memcpy(view->image()->bits(), oldView->image()->constBits(), oldView->image()->sizeInBytes());
|
||||
}
|
||||
|
||||
QImage *image = m_backBuffer->graphicsBufferView->image();
|
||||
image->setDevicePixelRatio(m_requestedDevicePixelRatio);
|
||||
|
||||
if (image->hasAlphaChannel()) {
|
||||
QPainter p(image);
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
const QColor blank = Qt::transparent;
|
||||
for (const QRect &rect : region) {
|
||||
|
@ -66,13 +135,13 @@ void BackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &o
|
|||
|
||||
QRegion bufferDamage;
|
||||
for (const QRect &rect : region) {
|
||||
bufferDamage |= QRect(std::floor(rect.x() * m_buffer.devicePixelRatio()),
|
||||
std::floor(rect.y() * m_buffer.devicePixelRatio()),
|
||||
std::ceil(rect.width() * m_buffer.devicePixelRatio()),
|
||||
std::ceil(rect.height() * m_buffer.devicePixelRatio()));
|
||||
bufferDamage |= QRect(std::floor(rect.x() * m_requestedDevicePixelRatio),
|
||||
std::floor(rect.y() * m_requestedDevicePixelRatio),
|
||||
std::ceil(rect.width() * m_requestedDevicePixelRatio),
|
||||
std::ceil(rect.height() * m_requestedDevicePixelRatio));
|
||||
}
|
||||
|
||||
internalWindow->present(m_buffer, bufferDamage);
|
||||
internalWindow->present(m_backBuffer->graphicsBuffer, bufferDamage);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,11 +18,12 @@ namespace KWin
|
|||
namespace QPA
|
||||
{
|
||||
|
||||
class BackingStoreSlot;
|
||||
|
||||
class BackingStore : public QPlatformBackingStore
|
||||
{
|
||||
public:
|
||||
explicit BackingStore(QWindow *window);
|
||||
~BackingStore() override;
|
||||
|
||||
QPaintDevice *paintDevice() override;
|
||||
void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) override;
|
||||
|
@ -30,7 +31,13 @@ public:
|
|||
void beginPaint(const QRegion ®ion) override;
|
||||
|
||||
private:
|
||||
QImage m_buffer;
|
||||
std::shared_ptr<BackingStoreSlot> allocate(const QSize &size);
|
||||
std::shared_ptr<BackingStoreSlot> acquire();
|
||||
|
||||
std::vector<std::shared_ptr<BackingStoreSlot>> m_slots;
|
||||
std::shared_ptr<BackingStoreSlot> m_backBuffer;
|
||||
QSize m_requestedSize;
|
||||
qreal m_requestedDevicePixelRatio = 1;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -67,9 +67,9 @@ QOpenGLFramebufferObject *SurfacePixmapInternal::fbo() const
|
|||
return m_fbo.get();
|
||||
}
|
||||
|
||||
QImage SurfacePixmapInternal::image() const
|
||||
GraphicsBuffer *SurfacePixmapInternal::graphicsBuffer() const
|
||||
{
|
||||
return m_rasterBuffer;
|
||||
return m_graphicsBufferRef.buffer();
|
||||
}
|
||||
|
||||
void SurfacePixmapInternal::create()
|
||||
|
@ -85,16 +85,16 @@ void SurfacePixmapInternal::update()
|
|||
m_fbo = window->fbo();
|
||||
m_size = m_fbo->size();
|
||||
m_hasAlphaChannel = true;
|
||||
} else if (!window->image().isNull()) {
|
||||
m_rasterBuffer = window->image();
|
||||
m_size = m_rasterBuffer.size();
|
||||
m_hasAlphaChannel = m_rasterBuffer.hasAlphaChannel();
|
||||
} else if (window->graphicsBuffer()) {
|
||||
m_graphicsBufferRef = window->graphicsBuffer();
|
||||
m_size = m_graphicsBufferRef->size();
|
||||
m_hasAlphaChannel = m_graphicsBufferRef->hasAlphaChannel();
|
||||
}
|
||||
}
|
||||
|
||||
bool SurfacePixmapInternal::isValid() const
|
||||
{
|
||||
return m_fbo != nullptr || !m_rasterBuffer.isNull();
|
||||
return m_fbo || m_graphicsBufferRef;
|
||||
}
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "core/graphicsbuffer.h"
|
||||
#include "scene/surfaceitem.h"
|
||||
|
||||
class QOpenGLFramebufferObject;
|
||||
|
@ -47,7 +48,7 @@ public:
|
|||
explicit SurfacePixmapInternal(SurfaceItemInternal *item, QObject *parent = nullptr);
|
||||
|
||||
QOpenGLFramebufferObject *fbo() const;
|
||||
QImage image() const;
|
||||
GraphicsBuffer *graphicsBuffer() const;
|
||||
|
||||
void create() override;
|
||||
void update() override;
|
||||
|
@ -56,7 +57,7 @@ public:
|
|||
private:
|
||||
SurfaceItemInternal *m_item;
|
||||
std::shared_ptr<QOpenGLFramebufferObject> m_fbo;
|
||||
QImage m_rasterBuffer;
|
||||
GraphicsBufferRef m_graphicsBufferRef;
|
||||
};
|
||||
|
||||
} // namespace KWin
|
||||
|
|
Loading…
Reference in a new issue