1/*
2 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6#ifndef WAYLAND_SHM_POOL_H
7#define WAYLAND_SHM_POOL_H
8
9#include <QObject>
10
11#include "KWayland/Client/kwaylandclient_export.h"
12#include "buffer.h"
13
14class QImage;
15class QSize;
16
17struct wl_shm;
18
19namespace KWayland
20{
21namespace Client
22{
23class EventQueue;
24
25/**
26 * @short Wrapper class for wl_shm interface.
27 *
28 * This class holds a shared memory pool together with the Wayland server.
29 *
30 * To use this class one needs to interact with the Registry. There are two
31 * possible ways to create a ShmPool instance:
32 * @code
33 * ShmPool *s = registry->createShmPool(name, version);
34 * @endcode
35 *
36 * This creates the ShmPool and sets it up directly. As an alternative this
37 * can also be done in a more low level way:
38 * @code
39 * ShmPool *s = new ShmPool;
40 * s->setup(registry->bindShm(name, version));
41 * @endcode
42 *
43 * The ShmPool holds a memory-mapped file from which it provides Buffers.
44 * All Buffers are held by the ShmPool and can be reused. Whenever a Buffer
45 * is requested the ShmPool tries to reuse an existing Buffer. A Buffer can
46 * be reused if the following conditions hold
47 * @li it's no longer marked as used
48 * @li the server released the buffer
49 * @li the size matches
50 * @li the stride matches
51 * @li the format matches
52 *
53 * The ownership of a Buffer stays with ShmPool. The ShmPool might destroy the
54 * Buffer at any given time. Because of that ShmPool only provides QWeakPointer
55 * for Buffers. Users should always check whether the pointer is still valid and
56 * only promote to a QSharedPointer for a short time, e.g. to set new data.
57 *
58 * The ShmPool can provide Buffers for different purposes. One can create a Buffer
59 * from an existing QImage. This will use a Buffer with same size, stride and image
60 * format as the QImage and <b>copy</b> the content of the QImage into the Buffer.
61 * The memory is <b>not</b> shared:
62 * @code
63 * QImage image(24, 24, QImage::Format_ARG32);
64 * image.fill(Qt::transparent);
65 * Buffer::Ptr buffer = s->createBuffer(image);
66 * @endcode
67 *
68 * It is also possible to create a Buffer and copy the content from a generic location.
69 * Like above this doesn't share the content but copies it:
70 * @code
71 * QImage image(24, 24, QImage::Format_ARG32);
72 * image.fill(Qt::transparent);
73 * Buffer::Ptr buffer = s->createBuffer(image.size(), image.bytesPerLine(), image.constBits());
74 * @endcode
75 *
76 * Last but not least it is possible to get a Buffer without copying content directly to it.
77 * This means an empty area is just reserved and can be used to e.g. share the memory with a
78 * QImage:
79 * @code
80 * const QSize size = QSize(24, 24);
81 * const int stride = size.width() * 4;
82 * Buffer::Ptr buffer = s->getBuffer(size, stride, Buffer::Format::RGB32);
83 * if (!buffer) {
84 * qDebug() << "Didn't get a valid Buffer";
85 * return;
86 * }
87 * QImage image(buffer.toStrongRef()->address(), size.width(), size.height(), stride, QImage::Format_RGB32);
88 * image.fill(Qt::black);
89 * @endcode
90 *
91 * A Buffer can be attached to a Surface:
92 * @code
93 * Compositor *c = registry.createCompositor(name, version);
94 * Surface *s = c->createSurface();
95 * s->attachBuffer(buffer);
96 * s->damage(QRect(QPoint(0, 0), size));
97 * @endcode
98 *
99 * Once a Buffer is attached to a Surface and the Surface is committed, it might be released
100 * by the Wayland server and thus is free to be reused again. If the client code wants to
101 * continue using the Buffer it must call Buffer::setUsed on it. This is important if the memory
102 * is shared for example with a QImage as the memory buffer for a QImage must remain valid
103 * throughout the life time of the QImage:
104 * @code
105 * buffer.toStrongRef()->setUsed(true);
106 * @endcode
107 *
108 * This is also important for the case that the shared memory pool needs to be resized.
109 * The ShmPool will automatically resize if it cannot provide a new Buffer. During the resize
110 * all existing Buffers are unmapped and any shared objects must be recreated. The ShmPool emits
111 * the signal poolResized() after the pool got resized.
112 *
113 * @see Buffer
114 **/
115class KWAYLANDCLIENT_EXPORT ShmPool : public QObject
116{
117 Q_OBJECT
118public:
119 explicit ShmPool(QObject *parent = nullptr);
120 ~ShmPool() override;
121 /**
122 * @returns @c true if the ShmPool references a wl_shm interface and the shared memory pool
123 * is setup.
124 **/
125 bool isValid() const;
126 /**
127 * Setup this ShmPool to manage the @p shm.
128 * This also creates the shared memory pool.
129 * When using Registry::createShmPool there is no need to call this
130 * method.
131 **/
132 void setup(wl_shm *shm);
133 /**
134 * Releases the wl_shm interface.
135 * After the interface has been released the ShmPool instance is no
136 * longer valid and can be setup with another wl_shm interface.
137 *
138 * This also destroys the shared memory pool and all Buffers are destroyed.
139 **/
140 void release();
141 /**
142 * Destroys the data held by this ShmPool.
143 * This method is supposed to be used when the connection to the Wayland
144 * server goes away. If the connection is not valid anymore, it's not
145 * possible to call release anymore as that calls into the Wayland
146 * connection and the call would fail. This method cleans up the data, so
147 * that the instance can be deleted or set up to a new wl_shm interface
148 * once there is a new connection available.
149 *
150 * All Buffers are destroyed!
151 *
152 * This method is automatically invoked when the Registry which created this
153 * ShmPool gets destroyed.
154 *
155 * @see release
156 **/
157 void destroy();
158
159 /**
160 * Sets the @p queue to use for creating a Buffer.
161 **/
162 void setEventQueue(EventQueue *queue);
163 /**
164 * @returns The event queue to use for creating a Buffer.
165 **/
166 EventQueue *eventQueue();
167
168 /**
169 * Provides a Buffer with:
170 * @li same size as @p image
171 * @li same stride as @p image
172 * @li same format as @p image
173 *
174 * If the ShmPool fails to provide such a Buffer a @c null Buffer::Ptr is returned.
175 * The content of the @p image is <b>copied</b> into the buffer. The @p image and
176 * returned Buffer do <b>not</b> share memory.
177 *
178 * @param image The image which should be copied into the Buffer
179 * @return Buffer with copied content of @p image in success case, a @c null Buffer::Ptr otherwise
180 * @see getBuffer
181 **/
182 Buffer::Ptr createBuffer(const QImage &image);
183 /**
184 * Provides a Buffer with @p size, @p stride and @p format.
185 *
186 * If the ShmPool fails to provide such a Buffer a @c null Buffer::Ptr is returned.
187 * A memory copy is performed from @p src into the Buffer. The Buffer does <b>not</b> share
188 * memory with @p src.
189 *
190 * @param size The requested size for the Buffer
191 * @param stride The requested stride for the Buffer
192 * @param src The source memory location to copy from
193 * @param format The requested format for the Buffer
194 * @return Buffer with copied content of @p src in success case, a @c null Buffer::Ptr otherwise
195 * @see getBuffer
196 **/
197 Buffer::Ptr createBuffer(const QSize &size, int32_t stride, const void *src, Buffer::Format format = Buffer::Format::ARGB32);
198 void *poolAddress() const;
199 /**
200 * Provides a Buffer with @p size, @p stride and @p format.
201 *
202 * If the ShmPool fails to provide such a Buffer a @c null Buffer::Ptr is returned.
203 * Unlike with createBuffer there is no memory copy performed. This provides a bare Buffer
204 * to be used by the user.
205 *
206 * @param size The requested size for the Buffer
207 * @param stride The requested stride for the Buffer
208 * @param format The requested format for the Buffer
209 * @return Buffer as requested in success case, a @c null Buffer::Ptr otherwise.
210 * @see createBuffer
211 **/
212 Buffer::Ptr getBuffer(const QSize &size, int32_t stride, Buffer::Format format = Buffer::Format::ARGB32);
213 wl_shm *shm();
214Q_SIGNALS:
215 /**
216 * This signal is emitted whenever the shared memory pool gets resized.
217 * Any used Buffer must be remapped.
218 **/
219 void poolResized();
220
221 /**
222 * The corresponding global for this interface on the Registry got removed.
223 *
224 * This signal gets only emitted if the Compositor got created by
225 * Registry::createShmPool
226 *
227 * @since 5.5
228 **/
229 void removed();
230
231private:
232 class Private;
233 QScopedPointer<Private> d;
234};
235
236}
237}
238
239#endif
240

source code of kwayland/src/client/shm_pool.h