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 | |
14 | class QImage; |
15 | class QSize; |
16 | |
17 | struct wl_shm; |
18 | |
19 | namespace KWayland |
20 | { |
21 | namespace Client |
22 | { |
23 | class 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 | **/ |
115 | class KWAYLANDCLIENT_EXPORT ShmPool : public QObject |
116 | { |
117 | Q_OBJECT |
118 | public: |
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(); |
214 | Q_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 | |
231 | private: |
232 | class Private; |
233 | QScopedPointer<Private> d; |
234 | }; |
235 | |
236 | } |
237 | } |
238 | |
239 | #endif |
240 | |