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 "remote_access_interface_p.h"
8 #include "output_interface.h"
9 #include "display.h"
10 #include "global_p.h"
11 #include "resource_p.h"
12 #include "logging.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 
26 class BufferHandle::Private // @see gbm_import_fd_data
27 {
28 public:
29  // Note that on client side received fd number will be different
30  // and meaningful only for client process!
31  // Thus we can use server-side fd as an implicit unique id
32  qint32 fd = 0;
33  quint32 width = 0;
34  quint32 height = 0;
35  quint32 stride = 0;
36  quint32 format = 0;
37 };
38 
39 BufferHandle::BufferHandle()
40  : d(new Private)
41 {
42 }
43 
44 BufferHandle::~BufferHandle()
45 {
46 }
47 
48 void BufferHandle::setFd(qint32 fd)
49 {
50  d->fd = fd;
51 }
52 
53 qint32 BufferHandle::fd() const
54 {
55  return d->fd;
56 }
57 
58 void BufferHandle::setSize(quint32 width, quint32 height)
59 {
60  d->width = width;
61  d->height = height;
62 }
63 
64 quint32 BufferHandle::width() const
65 {
66  return d->width;
67 }
68 
69 quint32 BufferHandle::height() const
70 {
71  return d->height;
72 }
73 
74 void BufferHandle::setStride(quint32 stride)
75 {
76  d->stride = stride;
77 }
78 
79 
80 quint32 BufferHandle::stride() const
81 {
82  return d->stride;
83 }
84 
85 void BufferHandle::setFormat(quint32 format)
86 {
87  d->format = format;
88 }
89 
90 quint32 BufferHandle::format() const
91 {
92  return d->format;
93 }
94 
99 struct BufferHolder
100 {
101  const BufferHandle *buf;
102  quint64 counter;
103 };
104 
105 class RemoteAccessManagerInterface::Private : public Global::Private
106 {
107 public:
108  Private(RemoteAccessManagerInterface *q, Display *d);
109  ~Private() override;
110 
116  void sendBufferReady(const OutputInterface *output, const BufferHandle *buf);
121  void release(wl_resource *resource);
122 
128  QList<wl_resource *> clientResources;
129 private:
130  // methods
131  static void unbind(wl_resource *resource);
132  static Private *cast(wl_resource *r) {
133  return reinterpret_cast<Private*>(wl_resource_get_user_data(r));
134  }
135  static void getBufferCallback(wl_client *client, wl_resource *resource, uint32_t buffer, int32_t internalBufId);
136  static void releaseCallback(wl_client *client, wl_resource *resource);
137  void bind(wl_client *client, uint32_t version, uint32_t id) override;
138 
144  bool unref(BufferHolder &buf);
145 
146  // fields
147  static const struct org_kde_kwin_remote_access_manager_interface s_interface;
148  static const quint32 s_version;
149 
150  RemoteAccessManagerInterface *q;
151 
156  QHash<qint32, BufferHolder> sentBuffers;
157 };
158 
159 const quint32 RemoteAccessManagerInterface::Private::s_version = 1;
160 
161 RemoteAccessManagerInterface::Private::Private(RemoteAccessManagerInterface *q, Display *d)
162  : Global::Private(d, &org_kde_kwin_remote_access_manager_interface, s_version)
163  , q(q)
164 {
165 }
166 
167 void RemoteAccessManagerInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
168 {
169  // create new client resource
170  auto c = display->getConnection(client);
171  wl_resource *resource = c->createResource(&org_kde_kwin_remote_access_manager_interface, qMin(version, s_version), id);
172  if (!resource) {
173  wl_client_post_no_memory(client);
174  return;
175  }
176  wl_resource_set_implementation(resource, &s_interface, this, unbind);
177 
178  // add newly created client resource to the list
179  clientResources << resource;
180 }
181 
182 void RemoteAccessManagerInterface::Private::sendBufferReady(const OutputInterface *output, const BufferHandle *buf)
183 {
184  BufferHolder holder {buf, 0};
185  // notify clients
186  qCDebug(KWAYLAND_SERVER) << "Server buffer sent: fd" << buf->fd();
187  for (auto res : clientResources) {
188  auto client = wl_resource_get_client(res);
189  auto boundScreens = output->clientResources(display->getConnection(client));
190 
191  // clients don't necessarily bind outputs
192  if (boundScreens.isEmpty()) {
193  continue;
194  }
195 
196  // no reason for client to bind wl_output multiple times, send only to first one
197  org_kde_kwin_remote_access_manager_send_buffer_ready(res, buf->fd(), boundScreens[0]);
198  holder.counter++;
199  }
200  if (holder.counter == 0) {
201  // buffer was not requested by any client
202  emit q->bufferReleased(buf);
203  return;
204  }
205  // store buffer locally, clients will ask it later
206  sentBuffers[buf->fd()] = holder;
207 }
208 
209 #ifndef K_DOXYGEN
210 const struct org_kde_kwin_remote_access_manager_interface RemoteAccessManagerInterface::Private::s_interface = {
211  getBufferCallback,
212  releaseCallback
213 };
214 #endif
215 
216 void RemoteAccessManagerInterface::Private::getBufferCallback(wl_client *client, wl_resource *resource, uint32_t buffer, int32_t internalBufId)
217 {
218  Private *p = cast(resource);
219 
220  // client asks for buffer we earlier announced, we must have it
221  if (Q_UNLIKELY(!p->sentBuffers.contains(internalBufId))) { // no such buffer (?)
222  wl_resource_post_no_memory(resource);
223  return;
224  }
225 
226  BufferHolder &bh = p->sentBuffers[internalBufId];
227  auto rbuf = new RemoteBufferInterface(p->q, resource, bh.buf);
228  rbuf->create(p->display->getConnection(client), wl_resource_get_version(resource), buffer);
229  if (!rbuf->resource()) {
230  wl_resource_post_no_memory(resource);
231  delete rbuf;
232  return;
233  }
234 
235  QObject::connect(rbuf, &Resource::aboutToBeUnbound, p->q, [p, rbuf, resource, &bh] {
236  if (!p->clientResources.contains(resource)) {
237  // remote buffer destroy confirmed after client is already gone
238  // all relevant buffers are already unreferenced
239  return;
240  }
241  qCDebug(KWAYLAND_SERVER) << "Remote buffer returned, client" << wl_resource_get_id(resource)
242  << ", id" << rbuf->id()
243  << ", fd" << bh.buf->fd();
244  if (p->unref(bh)) {
245  p->sentBuffers.remove(bh.buf->fd());
246  }
247  });
248 
249  // send buffer params
250  rbuf->passFd();
251 }
252 
253 void RemoteAccessManagerInterface::Private::releaseCallback(wl_client *client, wl_resource *resource)
254 {
255  Q_UNUSED(client);
256  unbind(resource);
257 }
258 
259 bool RemoteAccessManagerInterface::Private::unref(BufferHolder &bh)
260 {
261  bh.counter--;
262  if (!bh.counter) {
263  // no more clients using this buffer
264  qCDebug(KWAYLAND_SERVER) << "Buffer released, fd" << bh.buf->fd();
265  emit q->bufferReleased(bh.buf);
266  return true;
267  }
268 
269  return false;
270 }
271 
272 void RemoteAccessManagerInterface::Private::unbind(wl_resource *resource)
273 {
274  // we're unbinding, all sent buffers for this client are now effectively invalid
275  Private *p = cast(resource);
276  p->release(resource);
277 }
278 
279 void RemoteAccessManagerInterface::Private::release(wl_resource *resource)
280 {
281  // all holders should decrement their counter as one client is gone
283  while (itr.hasNext()) {
284  BufferHolder &bh = itr.next().value();
285  if (unref(bh)) {
286  itr.remove();
287  }
288  }
289 
290  clientResources.removeAll(resource);
291 }
292 
293 RemoteAccessManagerInterface::Private::~Private()
294 {
295  // server deletes created interfaces, release all held buffers
296  auto c = clientResources; // shadow copy
297  for (auto res : c) {
298  release(res);
299  }
300 }
301 
302 RemoteAccessManagerInterface::RemoteAccessManagerInterface(Display *display, QObject *parent)
303  : Global(new Private(this, display), parent)
304 {
305 }
306 
307 void RemoteAccessManagerInterface::sendBufferReady(const OutputInterface *output, const BufferHandle *buf)
308 {
309  Private *priv = reinterpret_cast<Private *>(d.data());
310  priv->sendBufferReady(output, buf);
311 }
312 
313 bool RemoteAccessManagerInterface::isBound() const
314 {
315  Private *priv = reinterpret_cast<Private *>(d.data());
316  return !priv->clientResources.isEmpty();
317 }
318 
319 class RemoteBufferInterface::Private : public Resource::Private
320 {
321 public:
322  Private(RemoteAccessManagerInterface *ram, RemoteBufferInterface *q, wl_resource *pResource, const BufferHandle *buf);
323  ~Private();
324 
325  void passFd();
326 
327 private:
328  static const struct org_kde_kwin_remote_buffer_interface s_interface;
329 
330  const BufferHandle *wrapped;
331 };
332 
333 #ifndef K_DOXYGEN
334 const struct org_kde_kwin_remote_buffer_interface RemoteBufferInterface::Private::s_interface = {
335  resourceDestroyedCallback
336 };
337 #endif
338 
339 RemoteBufferInterface::Private::Private(RemoteAccessManagerInterface *ram, RemoteBufferInterface *q, wl_resource *pResource, const BufferHandle *buf)
340  : Resource::Private(q, ram, pResource, &org_kde_kwin_remote_buffer_interface, &s_interface), wrapped(buf)
341 {
342 }
343 
344 RemoteBufferInterface::Private::~Private()
345 {
346 }
347 
348 void RemoteBufferInterface::Private::passFd()
349 {
350  org_kde_kwin_remote_buffer_send_gbm_handle(resource, wrapped->fd(),
351  wrapped->width(), wrapped->height(), wrapped->stride(), wrapped->format());
352 }
353 
354 RemoteBufferInterface::RemoteBufferInterface(RemoteAccessManagerInterface *ram, wl_resource *pResource, const BufferHandle *buf)
355  : Resource(new Private(ram, this, pResource, buf), ram)
356 {
357 }
358 
359 RemoteBufferInterface::Private *RemoteBufferInterface::d_func() const
360 {
361  return reinterpret_cast<Private*>(d.data());
362 }
363 
364 
365 void RemoteBufferInterface::passFd()
366 {
367  d_func()->passFd();
368 }
369 
370 }
371 }
void release()
Releases the org_kde_kwin_remote_buffer interface.
T * data() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Wed Jul 8 2020 22:48:50 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.