KWaylandServer

shmclientbuffer.cpp
1 /*
2  SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 
7 #include "shmclientbuffer.h"
8 #include "clientbuffer_p.h"
9 #include "display.h"
10 
11 #include <wayland-server-core.h>
12 #include <wayland-server-protocol.h>
13 
14 namespace KWaylandServer
15 {
16 static const ShmClientBuffer *s_accessedBuffer = nullptr;
17 static int s_accessCounter = 0;
18 
19 class ShmClientBufferPrivate : public ClientBufferPrivate
20 {
21 public:
22  ShmClientBufferPrivate(ShmClientBuffer *q);
23 
24  static void buffer_destroy_callback(wl_listener *listener, void *data);
25 
26  ShmClientBuffer *q;
28  uint32_t width = 0;
29  uint32_t height = 0;
30  bool hasAlphaChannel = false;
31  QImage savedData;
32 
33  struct DestroyListener {
34  wl_listener listener;
35  ShmClientBufferPrivate *receiver;
36  };
37  DestroyListener destroyListener;
38 };
39 
40 ShmClientBufferPrivate::ShmClientBufferPrivate(ShmClientBuffer *q)
41  : q(q)
42 {
43 }
44 
45 static void cleanupShmPool(void *poolHandle)
46 {
47  wl_shm_pool_unref(static_cast<wl_shm_pool *>(poolHandle));
48 }
49 
50 void ShmClientBufferPrivate::buffer_destroy_callback(wl_listener *listener, void *data)
51 {
52  Q_UNUSED(data)
53 
54  auto bufferPrivate = reinterpret_cast<ShmClientBufferPrivate::DestroyListener *>(listener)->receiver;
55  wl_shm_buffer *buffer = wl_shm_buffer_get(bufferPrivate->q->resource());
56  wl_shm_pool *pool = wl_shm_buffer_ref_pool(buffer);
57 
58  wl_list_remove(&bufferPrivate->destroyListener.listener.link);
59  wl_list_init(&bufferPrivate->destroyListener.listener.link);
60 
61  bufferPrivate->savedData = QImage(static_cast<const uchar *>(wl_shm_buffer_get_data(buffer)),
62  bufferPrivate->width,
63  bufferPrivate->height,
64  wl_shm_buffer_get_stride(buffer),
65  bufferPrivate->format,
66  cleanupShmPool,
67  pool);
68 }
69 
70 static bool alphaChannelFromFormat(uint32_t format)
71 {
72  switch (format) {
73  case WL_SHM_FORMAT_ABGR2101010:
74  case WL_SHM_FORMAT_ARGB2101010:
75  case WL_SHM_FORMAT_ARGB8888:
76  return true;
77  case WL_SHM_FORMAT_XBGR2101010:
78  case WL_SHM_FORMAT_XRGB2101010:
79  case WL_SHM_FORMAT_XRGB8888:
80  default:
81  return false;
82  }
83 }
84 
85 static QImage::Format imageFormatForShmFormat(uint32_t format)
86 {
87  switch (format) {
88 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
89  case WL_SHM_FORMAT_ARGB2101010:
91  case WL_SHM_FORMAT_XRGB2101010:
92  return QImage::Format_RGB30;
93  case WL_SHM_FORMAT_ABGR2101010:
95  case WL_SHM_FORMAT_XBGR2101010:
96  return QImage::Format_BGR30;
97 #endif
98  case WL_SHM_FORMAT_ARGB8888:
100  case WL_SHM_FORMAT_XRGB8888:
101  return QImage::Format_RGB32;
102  default:
103  return QImage::Format_Invalid;
104  }
105 }
106 
107 ShmClientBuffer::ShmClientBuffer(wl_resource *resource)
108  : ClientBuffer(resource, *new ShmClientBufferPrivate(this))
109 {
110  Q_D(ShmClientBuffer);
111 
112  wl_shm_buffer *buffer = wl_shm_buffer_get(resource);
113  d->width = wl_shm_buffer_get_width(buffer);
114  d->height = wl_shm_buffer_get_height(buffer);
115  d->hasAlphaChannel = alphaChannelFromFormat(wl_shm_buffer_get_format(buffer));
116  d->format = imageFormatForShmFormat(wl_shm_buffer_get_format(buffer));
117 
118  // The underlying shm pool will be referenced if the wl_shm_buffer is destroyed so the
119  // compositor can access buffer data even after the buffer is gone.
120  d->destroyListener.receiver = d;
121  d->destroyListener.listener.notify = ShmClientBufferPrivate::buffer_destroy_callback;
122  wl_resource_add_destroy_listener(resource, &d->destroyListener.listener);
123 }
124 
126 {
127  Q_D(const ShmClientBuffer);
128  return QSize(d->width, d->height);
129 }
130 
131 bool ShmClientBuffer::hasAlphaChannel() const
132 {
133  Q_D(const ShmClientBuffer);
134  return d->hasAlphaChannel;
135 }
136 
137 ClientBuffer::Origin ShmClientBuffer::origin() const
138 {
139  return Origin::TopLeft;
140 }
141 
142 static void cleanupShmData(void *bufferHandle)
143 {
144  Q_ASSERT_X(s_accessCounter > 0, "cleanup", "access counter must be positive");
145  s_accessCounter--;
146  if (s_accessCounter == 0) {
147  s_accessedBuffer = nullptr;
148  }
149  wl_shm_buffer_end_access(static_cast<wl_shm_buffer *>(bufferHandle));
150 }
151 
152 QImage ShmClientBuffer::data() const
153 {
154  if (s_accessedBuffer && s_accessedBuffer != this) {
155  return QImage();
156  }
157 
158  Q_D(const ShmClientBuffer);
159  if (wl_shm_buffer *buffer = wl_shm_buffer_get(resource())) {
160  s_accessedBuffer = this;
161  s_accessCounter++;
162  wl_shm_buffer_begin_access(buffer);
163  const uchar *data = static_cast<const uchar *>(wl_shm_buffer_get_data(buffer));
164  const uint32_t stride = wl_shm_buffer_get_stride(buffer);
165  return QImage(data, d->width, d->height, stride, d->format, cleanupShmData, buffer);
166  }
167  return d->savedData;
168 }
169 
170 ShmClientBufferIntegration::ShmClientBufferIntegration(Display *display)
171  : ClientBufferIntegration(display)
172 {
173 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
174  wl_display_add_shm_format(*display, WL_SHM_FORMAT_ARGB2101010);
175  wl_display_add_shm_format(*display, WL_SHM_FORMAT_XRGB2101010);
176  wl_display_add_shm_format(*display, WL_SHM_FORMAT_ABGR2101010);
177  wl_display_add_shm_format(*display, WL_SHM_FORMAT_XBGR2101010);
178 #endif
179  wl_display_init_shm(*display);
180 }
181 
182 ClientBuffer *ShmClientBufferIntegration::createBuffer(::wl_resource *resource)
183 {
184  if (wl_shm_buffer_get(resource)) {
185  return new ShmClientBuffer(resource);
186  }
187  return nullptr;
188 }
189 
190 } // namespace KWaylandServer
Class holding the Wayland server display loop.
Definition: display.h:47
QSize size() const override
Returns the size in the native pixels.
Origin
This enum type is used to specify the corner where the origin is.
Definition: clientbuffer.h:41
The ShmClientBuffer class represents a wl_shm_buffer client buffer.
The ClientBuffer class represents a client buffer.
Definition: clientbuffer.h:29
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 23 2021 23:08:28 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.