KWayland

remote_access_interface.cpp
1 /*
2  SPDX-FileCopyrightText: 2016 Oleg Chernovskiy <[email protected]>
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 
38 BufferHandle::BufferHandle()
39  : d(new Private)
40 {
41 }
42 
43 BufferHandle::~BufferHandle()
44 {
45 }
46 
47 void BufferHandle::setFd(qint32 fd)
48 {
49  d->fd = fd;
50 }
51 
52 qint32 BufferHandle::fd() const
53 {
54  return d->fd;
55 }
56 
57 void BufferHandle::setSize(quint32 width, quint32 height)
58 {
59  d->width = width;
60  d->height = height;
61 }
62 
63 quint32 BufferHandle::width() const
64 {
65  return d->width;
66 }
67 
68 quint32 BufferHandle::height() const
69 {
70  return d->height;
71 }
72 
73 void BufferHandle::setStride(quint32 stride)
74 {
75  d->stride = stride;
76 }
77 
78 quint32 BufferHandle::stride() const
79 {
80  return d->stride;
81 }
82 
83 void BufferHandle::setFormat(quint32 format)
84 {
85  d->format = format;
86 }
87 
88 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);
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 
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 
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 
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 
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 
247 void RemoteAccessManagerInterface::Private::releaseCallback(wl_client *client, wl_resource *resource)
248 {
249  Q_UNUSED(client);
250  unbind(resource);
251 }
252 
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 
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 
273 void RemoteAccessManagerInterface::Private::release(wl_resource *resource)
274 {
275  // all holders should decrement their counter as one client is gone
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 
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 
296 RemoteAccessManagerInterface::RemoteAccessManagerInterface(Display *display, QObject *parent)
297  : Global(new Private(this, display), parent)
298 {
299 }
300 
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 
307 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 
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 
337 RemoteBufferInterface::Private::~Private()
338 {
339 }
340 
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 
346 RemoteBufferInterface::RemoteBufferInterface(RemoteAccessManagerInterface *ram, wl_resource *pResource, const BufferHandle *buf)
347  : Resource(new Private(ram, this, pResource, buf), ram)
348 {
349 }
350 
351 RemoteBufferInterface::Private *RemoteBufferInterface::d_func() const
352 {
353  return reinterpret_cast<Private *>(d.data());
354 }
355 
356 void RemoteBufferInterface::passFd()
357 {
358  d_func()->passFd();
359 }
360 
361 }
362 }
virtual void release(quint64 objid)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Jan 30 2023 03:56:24 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.