From 3ac4f8a7dc364d6cf64bacc13c016c96c403d8a0 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Wed, 12 Apr 2023 11:05:26 +0300 Subject: [PATCH] core: Introduce base GraphicsBuffer Currently, there exists the separation between the buffers provided by the clients and the buffers created by the compositor. In hindsight, this separation is not great because it leads to specialized code paths in the output backend. For example, we have a separate code path for direct scanout and presenting composited frame. But you could view the latter case as "direct scanout of a compositor buffer". The main idea behind the buffer type is to provide a base buffer type for client buffers and composited frame buffers (not drm fbs) that we could pass around, import as textures, etc. --- src/CMakeLists.txt | 1 + src/core/graphicsbuffer.cpp | 55 +++++++++++++++++ src/core/graphicsbuffer.h | 59 +++++++++++++++++++ .../autotests/client/test_wayland_surface.cpp | 2 +- src/wayland/clientbuffer.cpp | 51 +++------------- src/wayland/clientbuffer.h | 29 +-------- src/wayland/clientbuffer_p.h | 2 - src/wayland/display.cpp | 2 +- 8 files changed, 126 insertions(+), 75 deletions(-) create mode 100644 src/core/graphicsbuffer.cpp create mode 100644 src/core/graphicsbuffer.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 80dbf59446..c871983ae5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,6 +42,7 @@ target_sources(kwin PRIVATE core/colorlut.cpp core/colorpipelinestage.cpp core/colortransformation.cpp + core/graphicsbuffer.cpp core/inputbackend.cpp core/inputdevice.cpp core/output.cpp diff --git a/src/core/graphicsbuffer.cpp b/src/core/graphicsbuffer.cpp new file mode 100644 index 0000000000..36d255073c --- /dev/null +++ b/src/core/graphicsbuffer.cpp @@ -0,0 +1,55 @@ +/* + SPDX-FileCopyrightText: 2023 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "core/graphicsbuffer.h" + +namespace KWin +{ + +GraphicsBuffer::GraphicsBuffer(QObject *parent) + : QObject(parent) +{ +} + +bool GraphicsBuffer::isReferenced() const +{ + return m_refCount > 0; +} + +bool GraphicsBuffer::isDropped() const +{ + return m_dropped; +} + +void GraphicsBuffer::ref() +{ + ++m_refCount; +} + +void GraphicsBuffer::unref() +{ + Q_ASSERT(m_refCount > 0); + --m_refCount; + if (!m_refCount) { + if (m_dropped) { + delete this; + } else { + Q_EMIT released(); + } + } +} + +void GraphicsBuffer::drop() +{ + m_dropped = true; + Q_EMIT dropped(); + + if (!m_refCount) { + delete this; + } +} + +} // namespace KWin diff --git a/src/core/graphicsbuffer.h b/src/core/graphicsbuffer.h new file mode 100644 index 0000000000..2b7aee1977 --- /dev/null +++ b/src/core/graphicsbuffer.h @@ -0,0 +1,59 @@ +/* + SPDX-FileCopyrightText: 2023 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +#include "kwin_export.h" + +#include + +namespace KWin +{ + +/** + * The GraphicsBuffer class represents a chunk of memory containing graphics data. + * + * A graphics buffer can be referenced. In which case, it won't be destroyed until all + * references are dropped. You can use the isDropped() function to check whether the + * buffer has been marked as destroyed. + */ +class KWIN_EXPORT GraphicsBuffer : public QObject +{ + Q_OBJECT + +public: + explicit GraphicsBuffer(QObject *parent = nullptr); + + /** + * This enum type is used to specify the corner where the origin is. That is, the + * buffer corner where 0,0 is located. + */ + enum class Origin { + TopLeft, + BottomLeft, + }; + + bool isReferenced() const; + bool isDropped() const; + + void ref(); + void unref(); + void drop(); + + virtual QSize size() const = 0; + virtual bool hasAlphaChannel() const = 0; + virtual Origin origin() const = 0; + +Q_SIGNALS: + void released(); + void dropped(); + +protected: + int m_refCount = 0; + bool m_dropped = false; +}; + +} // namespace KWin diff --git a/src/wayland/autotests/client/test_wayland_surface.cpp b/src/wayland/autotests/client/test_wayland_surface.cpp index 3850ddd650..5fcd5db2a4 100644 --- a/src/wayland/autotests/client/test_wayland_surface.cpp +++ b/src/wayland/autotests/client/test_wayland_surface.cpp @@ -873,7 +873,7 @@ void TestWaylandSurface::testDestroyAttachedBuffer() // Let's try to destroy it delete m_shm; m_shm = nullptr; - QTRY_VERIFY(serverSurface->buffer()->isDestroyed()); + QTRY_VERIFY(serverSurface->buffer()->isDropped()); } void TestWaylandSurface::testDestroyWithPendingCallback() diff --git a/src/wayland/clientbuffer.cpp b/src/wayland/clientbuffer.cpp index d0034c9b51..21df1bd645 100644 --- a/src/wayland/clientbuffer.cpp +++ b/src/wayland/clientbuffer.cpp @@ -7,7 +7,7 @@ #include "clientbuffer.h" #include "clientbuffer_p.h" -#include "qwayland-server-wayland.h" +#include namespace KWaylandServer { @@ -30,6 +30,12 @@ void ClientBuffer::initialize(wl_resource *resource) { Q_D(ClientBuffer); d->resource = resource; + connect(this, &GraphicsBuffer::dropped, [d]() { + d->resource = nullptr; + }); + connect(this, &GraphicsBuffer::released, [d]() { + wl_buffer_send_release(d->resource); + }); } wl_resource *ClientBuffer::resource() const @@ -38,47 +44,4 @@ wl_resource *ClientBuffer::resource() const return d->resource; } -bool ClientBuffer::isReferenced() const -{ - Q_D(const ClientBuffer); - return d->refCount > 0; -} - -bool ClientBuffer::isDestroyed() const -{ - Q_D(const ClientBuffer); - return d->isDestroyed; -} - -void ClientBuffer::ref() -{ - Q_D(ClientBuffer); - d->refCount++; -} - -void ClientBuffer::unref() -{ - Q_D(ClientBuffer); - Q_ASSERT(d->refCount > 0); - --d->refCount; - if (!isReferenced()) { - if (isDestroyed()) { - delete this; - } else { - wl_buffer_send_release(d->resource); - } - } -} - -void ClientBuffer::markAsDestroyed() -{ - Q_D(ClientBuffer); - if (!isReferenced()) { - delete this; - } else { - d->resource = nullptr; - d->isDestroyed = true; - } -} - } // namespace KWaylandServer diff --git a/src/wayland/clientbuffer.h b/src/wayland/clientbuffer.h index 3fa4c2c283..a4c03c4436 100644 --- a/src/wayland/clientbuffer.h +++ b/src/wayland/clientbuffer.h @@ -6,7 +6,7 @@ #pragma once -#include "kwin_export.h" +#include "core/graphicsbuffer.h" #include #include @@ -27,7 +27,7 @@ class ClientBufferPrivate; * You can use the isDestroyed() function to check whether the wl_buffer object has been * destroyed. */ -class KWIN_EXPORT ClientBuffer : public QObject +class KWIN_EXPORT ClientBuffer : public KWin::GraphicsBuffer { Q_OBJECT Q_DECLARE_PRIVATE(ClientBuffer) @@ -35,37 +35,12 @@ class KWIN_EXPORT ClientBuffer : public QObject public: ~ClientBuffer() override; - /** - * This enum type is used to specify the corner where the origin is. That's it, the - * buffer corner where 0,0 is located. - */ - enum class Origin { - TopLeft, - BottomLeft, - }; - - bool isReferenced() const; - bool isDestroyed() const; - - void ref(); - void unref(); - /** * Returns the wl_resource for this ClientBuffer. If the buffer is destroyed, @c null * will be returned. */ wl_resource *resource() const; - /** - * Returns the size in the native pixels. The returned size is unaffected by buffer - * scale or other surface transforms, e.g. @c wp_viewport. - */ - virtual QSize size() const = 0; - virtual bool hasAlphaChannel() const = 0; - virtual Origin origin() const = 0; - - void markAsDestroyed(); ///< @internal - protected: ClientBuffer(ClientBufferPrivate &dd); ClientBuffer(wl_resource *resource, ClientBufferPrivate &dd); diff --git a/src/wayland/clientbuffer_p.h b/src/wayland/clientbuffer_p.h index 5536259714..3045f423bd 100644 --- a/src/wayland/clientbuffer_p.h +++ b/src/wayland/clientbuffer_p.h @@ -17,9 +17,7 @@ public: { } - int refCount = 0; wl_resource *resource = nullptr; - bool isDestroyed = false; }; } // namespace KWaylandServer diff --git a/src/wayland/display.cpp b/src/wayland/display.cpp index f383315024..cba2216705 100644 --- a/src/wayland/display.cpp +++ b/src/wayland/display.cpp @@ -232,7 +232,7 @@ void bufferDestroyCallback(wl_listener *listener, void *data) ClientBuffer *buffer = displayPrivate->q->clientBufferForResource(static_cast(data)); displayPrivate->unregisterClientBuffer(buffer); - buffer->markAsDestroyed(); + buffer->drop(); } ClientBufferDestroyListener::ClientBufferDestroyListener(Display *display, ClientBuffer *buffer)