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)