1 /*
2 SPDX-FileCopyrightText: 2016 Oleg Chernovskiy <kanedias@xaker.ru>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 #include "remote_access_interface.h"
7 #include "display.h"
8 #include "global_p.h"
9 #include "logging.h"
10 #include "output_interface.h"
11 #include "remote_access_interface_p.h"
12 #include "resource_p.h"
13
14 #include <wayland-remote-access-server-protocol.h>
15
16 #include <QHash>
17 #include <QMutableHashIterator>
18
19 #include <functional>
20
21 namespace KWayland
22 {
23 namespace Server
24 {
25 class BufferHandle::Private // @see gbm_import_fd_data
26 {
27 public:
28 // Note that on client side received fd number will be different
29 // and meaningful only for client process!
30 // Thus we can use server-side fd as an implicit unique id
31 qint32 fd = 0; ///< also internal buffer id for client
32 quint32 width = 0;
33 quint32 height = 0;
34 quint32 stride = 0;
35 quint32 format = 0;
36 };
37
BufferHandle()38 BufferHandle::BufferHandle()
39 : d(new Private)
40 {
41 }
42
~BufferHandle()43 BufferHandle::~BufferHandle()
44 {
45 }
46
setFd(qint32 fd)47 void BufferHandle::setFd(qint32 fd)
48 {
49 d->fd = fd;
50 }
51
fd() const52 qint32 BufferHandle::fd() const
53 {
54 return d->fd;
55 }
56
setSize(quint32 width,quint32 height)57 void BufferHandle::setSize(quint32 width, quint32 height)
58 {
59 d->width = width;
60 d->height = height;
61 }
62
width() const63 quint32 BufferHandle::width() const
64 {
65 return d->width;
66 }
67
height() const68 quint32 BufferHandle::height() const
69 {
70 return d->height;
71 }
72
setStride(quint32 stride)73 void BufferHandle::setStride(quint32 stride)
74 {
75 d->stride = stride;
76 }
77
stride() const78 quint32 BufferHandle::stride() const
79 {
80 return d->stride;
81 }
82
setFormat(quint32 format)83 void BufferHandle::setFormat(quint32 format)
84 {
85 d->format = format;
86 }
87
format() const88 quint32 BufferHandle::format() const
89 {
90 return d->format;
91 }
92
93 /**
94 * @brief helper struct for manual reference counting.
95 * automatic counting via QSharedPointer is no-go here as we hold strong reference in sentBuffers.
96 */
97 struct BufferHolder {
98 const BufferHandle *buf;
99 quint64 counter;
100 };
101
102 class RemoteAccessManagerInterface::Private : public Global::Private
103 {
104 public:
105 Private(RemoteAccessManagerInterface *q, Display *d);
106 ~Private() override;
107
108 /**
109 * @brief Send buffer ready notification to all connected clients
110 * @param output wl_output interface to determine which screen sent this buf
111 * @param buf buffer containing GBM-related params
112 */
113 void sendBufferReady(const OutputInterface *output, const BufferHandle *buf);
114 /**
115 * @brief Release all bound buffers associated with this resource
116 * @param resource one of bound clients
117 */
118 void release(wl_resource *resource);
119
120 /**
121 * Clients of this interface.
122 * This may be screenshot app, video capture app,
123 * remote control app etc.
124 */
125 QList<wl_resource *> clientResources;
126
127 private:
128 // methods
129 static void unbind(wl_resource *resource);
cast(wl_resource * r)130 static Private *cast(wl_resource *r)
131 {
132 return reinterpret_cast<Private *>(wl_resource_get_user_data(r));
133 }
134 static void getBufferCallback(wl_client *client, wl_resource *resource, uint32_t buffer, int32_t internalBufId);
135 static void releaseCallback(wl_client *client, wl_resource *resource);
136 void bind(wl_client *client, uint32_t version, uint32_t id) override;
137
138 /**
139 * @brief Unreferences counter and frees buffer when it reaches zero
140 * @param buf holder to decrease reference counter on
141 * @return true if buffer was released, false otherwise
142 */
143 bool unref(BufferHolder &buf);
144
145 // fields
146 static const struct org_kde_kwin_remote_access_manager_interface s_interface;
147 static const quint32 s_version;
148
149 RemoteAccessManagerInterface *q;
150
151 /**
152 * Buffers that were sent but still not acked by server
153 * Keys are fd numbers as they are unique
154 **/
155 QHash<qint32, BufferHolder> sentBuffers;
156 };
157
158 const quint32 RemoteAccessManagerInterface::Private::s_version = 1;
159
Private(RemoteAccessManagerInterface * q,Display * d)160 RemoteAccessManagerInterface::Private::Private(RemoteAccessManagerInterface *q, Display *d)
161 : Global::Private(d, &org_kde_kwin_remote_access_manager_interface, s_version)
162 , q(q)
163 {
164 }
165
bind(wl_client * client,uint32_t version,uint32_t id)166 void RemoteAccessManagerInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
167 {
168 // create new client resource
169 auto c = display->getConnection(client);
170 wl_resource *resource = c->createResource(&org_kde_kwin_remote_access_manager_interface, qMin(version, s_version), id);
171 if (!resource) {
172 wl_client_post_no_memory(client);
173 return;
174 }
175 wl_resource_set_implementation(resource, &s_interface, this, unbind);
176
177 // add newly created client resource to the list
178 clientResources << resource;
179 }
180
sendBufferReady(const OutputInterface * output,const BufferHandle * buf)181 void RemoteAccessManagerInterface::Private::sendBufferReady(const OutputInterface *output, const BufferHandle *buf)
182 {
183 BufferHolder holder{buf, 0};
184 // notify clients
185 qCDebug(KWAYLAND_SERVER) << "Server buffer sent: fd" << buf->fd();
186 for (auto res : clientResources) {
187 auto client = wl_resource_get_client(res);
188 auto boundScreens = output->clientResources(display->getConnection(client));
189
190 // clients don't necessarily bind outputs
191 if (boundScreens.isEmpty()) {
192 continue;
193 }
194
195 // no reason for client to bind wl_output multiple times, send only to first one
196 org_kde_kwin_remote_access_manager_send_buffer_ready(res, buf->fd(), boundScreens[0]);
197 holder.counter++;
198 }
199 if (holder.counter == 0) {
200 // buffer was not requested by any client
201 Q_EMIT q->bufferReleased(buf);
202 return;
203 }
204 // store buffer locally, clients will ask it later
205 sentBuffers[buf->fd()] = holder;
206 }
207
208 #ifndef K_DOXYGEN
209 const struct org_kde_kwin_remote_access_manager_interface RemoteAccessManagerInterface::Private::s_interface = {getBufferCallback, releaseCallback};
210 #endif
211
getBufferCallback(wl_client * client,wl_resource * resource,uint32_t buffer,int32_t internalBufId)212 void RemoteAccessManagerInterface::Private::getBufferCallback(wl_client *client, wl_resource *resource, uint32_t buffer, int32_t internalBufId)
213 {
214 Private *p = cast(resource);
215
216 // client asks for buffer we earlier announced, we must have it
217 if (Q_UNLIKELY(!p->sentBuffers.contains(internalBufId))) { // no such buffer (?)
218 wl_resource_post_no_memory(resource);
219 return;
220 }
221
222 BufferHolder &bh = p->sentBuffers[internalBufId];
223 auto rbuf = new RemoteBufferInterface(p->q, resource, bh.buf);
224 rbuf->create(p->display->getConnection(client), wl_resource_get_version(resource), buffer);
225 if (!rbuf->resource()) {
226 wl_resource_post_no_memory(resource);
227 delete rbuf;
228 return;
229 }
230
231 QObject::connect(rbuf, &Resource::aboutToBeUnbound, p->q, [p, rbuf, resource, &bh] {
232 if (!p->clientResources.contains(resource)) {
233 // remote buffer destroy confirmed after client is already gone
234 // all relevant buffers are already unreferenced
235 return;
236 }
237 qCDebug(KWAYLAND_SERVER) << "Remote buffer returned, client" << wl_resource_get_id(resource) << ", id" << rbuf->id() << ", fd" << bh.buf->fd();
238 if (p->unref(bh)) {
239 p->sentBuffers.remove(bh.buf->fd());
240 }
241 });
242
243 // send buffer params
244 rbuf->passFd();
245 }
246
releaseCallback(wl_client * client,wl_resource * resource)247 void RemoteAccessManagerInterface::Private::releaseCallback(wl_client *client, wl_resource *resource)
248 {
249 Q_UNUSED(client);
250 unbind(resource);
251 }
252
unref(BufferHolder & bh)253 bool RemoteAccessManagerInterface::Private::unref(BufferHolder &bh)
254 {
255 bh.counter--;
256 if (!bh.counter) {
257 // no more clients using this buffer
258 qCDebug(KWAYLAND_SERVER) << "Buffer released, fd" << bh.buf->fd();
259 Q_EMIT q->bufferReleased(bh.buf);
260 return true;
261 }
262
263 return false;
264 }
265
unbind(wl_resource * resource)266 void RemoteAccessManagerInterface::Private::unbind(wl_resource *resource)
267 {
268 // we're unbinding, all sent buffers for this client are now effectively invalid
269 Private *p = cast(resource);
270 p->release(resource);
271 }
272
release(wl_resource * resource)273 void RemoteAccessManagerInterface::Private::release(wl_resource *resource)
274 {
275 // all holders should decrement their counter as one client is gone
276 QMutableHashIterator<qint32, BufferHolder> itr(sentBuffers);
277 while (itr.hasNext()) {
278 BufferHolder &bh = itr.next().value();
279 if (unref(bh)) {
280 itr.remove();
281 }
282 }
283
284 clientResources.removeAll(resource);
285 }
286
~Private()287 RemoteAccessManagerInterface::Private::~Private()
288 {
289 // server deletes created interfaces, release all held buffers
290 auto c = clientResources; // shadow copy
291 for (auto res : c) {
292 release(res);
293 }
294 }
295
RemoteAccessManagerInterface(Display * display,QObject * parent)296 RemoteAccessManagerInterface::RemoteAccessManagerInterface(Display *display, QObject *parent)
297 : Global(new Private(this, display), parent)
298 {
299 }
300
sendBufferReady(const OutputInterface * output,const BufferHandle * buf)301 void RemoteAccessManagerInterface::sendBufferReady(const OutputInterface *output, const BufferHandle *buf)
302 {
303 Private *priv = reinterpret_cast<Private *>(d.data());
304 priv->sendBufferReady(output, buf);
305 }
306
isBound() const307 bool RemoteAccessManagerInterface::isBound() const
308 {
309 Private *priv = reinterpret_cast<Private *>(d.data());
310 return !priv->clientResources.isEmpty();
311 }
312
313 class RemoteBufferInterface::Private : public Resource::Private
314 {
315 public:
316 Private(RemoteAccessManagerInterface *ram, RemoteBufferInterface *q, wl_resource *pResource, const BufferHandle *buf);
317 ~Private() override;
318
319 void passFd();
320
321 private:
322 static const struct org_kde_kwin_remote_buffer_interface s_interface;
323
324 const BufferHandle *wrapped;
325 };
326
327 #ifndef K_DOXYGEN
328 const struct org_kde_kwin_remote_buffer_interface RemoteBufferInterface::Private::s_interface = {resourceDestroyedCallback};
329 #endif
330
Private(RemoteAccessManagerInterface * ram,RemoteBufferInterface * q,wl_resource * pResource,const BufferHandle * buf)331 RemoteBufferInterface::Private::Private(RemoteAccessManagerInterface *ram, RemoteBufferInterface *q, wl_resource *pResource, const BufferHandle *buf)
332 : Resource::Private(q, ram, pResource, &org_kde_kwin_remote_buffer_interface, &s_interface)
333 , wrapped(buf)
334 {
335 }
336
~Private()337 RemoteBufferInterface::Private::~Private()
338 {
339 }
340
passFd()341 void RemoteBufferInterface::Private::passFd()
342 {
343 org_kde_kwin_remote_buffer_send_gbm_handle(resource, wrapped->fd(), wrapped->width(), wrapped->height(), wrapped->stride(), wrapped->format());
344 }
345
RemoteBufferInterface(RemoteAccessManagerInterface * ram,wl_resource * pResource,const BufferHandle * buf)346 RemoteBufferInterface::RemoteBufferInterface(RemoteAccessManagerInterface *ram, wl_resource *pResource, const BufferHandle *buf)
347 : Resource(new Private(ram, this, pResource, buf), ram)
348 {
349 }
350
d_func() const351 RemoteBufferInterface::Private *RemoteBufferInterface::d_func() const
352 {
353 return reinterpret_cast<Private *>(d.data());
354 }
355
passFd()356 void RemoteBufferInterface::passFd()
357 {
358 d_func()->passFd();
359 }
360
361 }
362 }
363