GCC Code Coverage Report


Directory: ./
File: server/buffer.cpp
Date: 2024-01-22 17:25:27
Exec Total Coverage
Lines: 137 205 66.8%
Branches: 46 118 39.0%

Line Branch Exec Source
1 /********************************************************************
2 Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
3 Copyright © 2020 Roman Gilg <subdiff@gmail.com>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) version 3, or any
9 later version accepted by the membership of KDE e.V. (or its
10 successor approved by the membership of KDE e.V.), which shall
11 act as a proxy defined in Section 6 of version 3 of the license.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library. If not, see <http://www.gnu.org/licenses/>.
20 *********************************************************************/
21 #include "buffer_p.h"
22
23 #include "client.h"
24 #include "display.h"
25 #include "logging.h"
26 #include "surface.h"
27
28 #include "wayland/buffer_manager.h"
29 #include "wayland/display.h"
30
31 #include "linux_dmabuf_v1.h"
32 #include "linux_dmabuf_v1_p.h"
33
34 #include <drm_fourcc.h>
35
36 #include <EGL/egl.h>
37 #include <QtGui/qopengl.h>
38
39 namespace EGL
40 {
41 using eglQueryWaylandBufferWL_func
42 = GLboolean (*)(EGLDisplay dpy, struct wl_resource* buffer, EGLint attribute, EGLint* value);
43 }
44
45 namespace Wrapland::Server
46 {
47
48 int constexpr default_bpp{32};
49
50 2362 ShmImage::Private::Private(Buffer* buffer, ShmImage::Format format)
51 1181 : format{format}
52 1181 , stride{wl_shm_buffer_get_stride(buffer->d_ptr->shmBuffer)}
53 1181 , bpp{default_bpp}
54 1181 , data{static_cast<uchar*>(wl_shm_buffer_get_data(buffer->d_ptr->shmBuffer))}
55 1181 , buffer{buffer}
56 1181 , display{buffer->d_ptr->display}
57 {
58 1181 }
59
60 1181 ShmImage::Private::~Private()
61 {
62
2/4
✓ Branch 0 taken 1181 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1181 times.
✗ Branch 3 not taken.
1181 display->bufferManager()->endShmAccess();
63 1181 }
64
65 1180 QImage ShmImage::Private::createQImage()
66 {
67
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1180 times.
1256 if (!image.isNull()) {
68 return image;
69 }
70 76
71 1180 [[maybe_unused]] auto const hasAccess
72 1256 = display->bufferManager()->beginShmAccess(buffer->d_ptr->shmBuffer);
73
1/2
✓ Branch 0 taken 1180 times.
✗ Branch 1 not taken.
1256 assert(hasAccess);
74
75 1180 QImage::Format qtFormat{QImage::Format_Invalid};
76
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1174 times.
✓ Branch 2 taken 6 times.
1180 switch (format) {
77 case ShmImage::Format::argb8888:
78 1174 qtFormat = QImage::Format_ARGB32_Premultiplied;
79 1174 break;
80 case ShmImage::Format::xrgb8888:
81 6 qtFormat = QImage::Format_RGB32;
82 6 break;
83 default:
84 assert(false);
85 }
86
87 1180 auto const size = buffer->size();
88 1180 return {
89 1180 data, size.width(), size.height(), stride, qtFormat, &imageBufferCleanupHandler, display};
90 1180 }
91
92 1180 void ShmImage::Private::imageBufferCleanupHandler(void* info)
93 {
94 1180 auto display = static_cast<Wayland::Display*>(info);
95 1180 display->bufferManager()->endShmAccess();
96 1180 }
97
98 1181 ShmImage::ShmImage(Buffer* buffer, ShmImage::Format format)
99
1/2
✓ Branch 0 taken 1181 times.
✗ Branch 1 not taken.
1181 : d_ptr{new Private(buffer, format)}
100 {
101 1181 }
102
103 ShmImage::ShmImage(ShmImage const& img)
104 : d_ptr{new Private(img.d_ptr->buffer, img.d_ptr->format)}
105 {
106 d_ptr->display->bufferManager()->beginShmAccess(d_ptr->buffer->d_ptr->shmBuffer);
107 }
108
109 ShmImage& ShmImage::operator=(ShmImage const& img)
110 {
111 if (this != &img) {
112 d_ptr->display->bufferManager()->endShmAccess();
113 img.d_ptr->display->bufferManager()->beginShmAccess(img.d_ptr->buffer->d_ptr->shmBuffer);
114
115 d_ptr->format = img.d_ptr->format;
116 d_ptr->stride = img.d_ptr->stride;
117 d_ptr->bpp = img.d_ptr->bpp;
118 d_ptr->data = img.d_ptr->data;
119 d_ptr->buffer = img.d_ptr->buffer;
120 d_ptr->display = img.d_ptr->display;
121 }
122
123 return *this;
124 }
125
126 1182 ShmImage::ShmImage(ShmImage&& img) noexcept
127 1182 : d_ptr{std::move(img.d_ptr)}
128 {
129 1182 }
130
131 ShmImage& ShmImage::operator=(ShmImage&& img) noexcept
132 {
133 if (this != &img) {
134 d_ptr = std::move(img.d_ptr);
135 }
136
137 return *this;
138 }
139
140 2363 ShmImage::~ShmImage() = default;
141
142 1 ShmImage::Format ShmImage::format() const
143 {
144 1 return d_ptr->format;
145 }
146
147 int32_t ShmImage::stride() const
148 {
149 return d_ptr->stride;
150 }
151
152 int32_t ShmImage::bpp() const
153 {
154 return d_ptr->bpp;
155 }
156
157 uchar* ShmImage::data() const
158 {
159 return d_ptr->data;
160 }
161
162 1180 QImage ShmImage::createQImage()
163 {
164 1180 return d_ptr->createQImage();
165 }
166
167 1181 ShmImage::Format getFormat(wl_shm_buffer* shmBuffer)
168 {
169
2/3
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1174 times.
1181 switch (wl_shm_buffer_get_format(shmBuffer)) {
170 case WL_SHM_FORMAT_ARGB8888:
171 1174 return ShmImage::Format::argb8888;
172 case WL_SHM_FORMAT_XRGB8888:
173 7 return ShmImage::Format::xrgb8888;
174 default:
175 return ShmImage::Format::invalid;
176 }
177 1181 }
178
179 1182 std::optional<ShmImage> ShmImage::get(Buffer* buffer)
180 {
181 1182 auto display = buffer->d_ptr->display;
182 1182 auto shmBuffer = buffer->d_ptr->shmBuffer;
183
184
1/2
✓ Branch 0 taken 1182 times.
✗ Branch 1 not taken.
1182 if (!shmBuffer) {
185 return std::nullopt;
186 }
187
188
2/2
✓ Branch 0 taken 1181 times.
✓ Branch 1 taken 1 times.
1182 if (!display->bufferManager()->beginShmAccess(shmBuffer)) {
189 1 return std::nullopt;
190 }
191
192 1181 auto const imageFormat = getFormat(shmBuffer);
193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1181 times.
1181 if (imageFormat == ShmImage::Format::invalid) {
194 display->bufferManager()->endShmAccess();
195 return std::nullopt;
196 }
197
198 1181 return ShmImage(buffer, imageFormat);
199 1182 }
200
201 228 Buffer::Private::Private(Buffer* q_ptr,
202 wl_resource* wlResource,
203 Surface* surface,
204 Wayland::Display* display)
205 76 : resource(wlResource)
206 76 , shmBuffer(wl_shm_buffer_get(wlResource))
207 76 , surface(surface)
208 76 , display(display)
209 76 , q_ptr{q_ptr}
210 {
211
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
76 if (!shmBuffer
212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
76 && wl_resource_instance_of(
213 resource, &wl_buffer_interface, &linux_dmabuf_buffer_v1_res_impl::s_interface)) {
214 dmabufBuffer
215 = Wayland::Resource<linux_dmabuf_buffer_v1_res>::get_handle(resource)->handle.get();
216 }
217
218 76 destroyWrapper.buffer = q_ptr;
219 76 destroyWrapper.listener.notify = destroyListenerCallback;
220 76 destroyWrapper.listener.link.prev = nullptr;
221 76 destroyWrapper.listener.link.next = nullptr;
222 76 wl_resource_add_destroy_listener(resource, &destroyWrapper.listener);
223
224
1/2
✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
76 if (shmBuffer) {
225 76 size = QSize(wl_shm_buffer_get_width(shmBuffer), wl_shm_buffer_get_height(shmBuffer));
226 // check alpha
227
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 10 times.
76 switch (wl_shm_buffer_get_format(shmBuffer)) {
228 case WL_SHM_FORMAT_ARGB8888:
229 66 alpha = true;
230 66 break;
231 10 case WL_SHM_FORMAT_XRGB8888:
232 default:
233 10 alpha = false;
234 10 break;
235 }
236
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
76 } else if (dmabufBuffer) {
237 switch (dmabufBuffer->format) {
238 case DRM_FORMAT_ARGB4444:
239 case DRM_FORMAT_ABGR4444:
240 case DRM_FORMAT_RGBA4444:
241 case DRM_FORMAT_BGRA4444:
242
243 case DRM_FORMAT_ARGB1555:
244 case DRM_FORMAT_ABGR1555:
245 case DRM_FORMAT_RGBA5551:
246 case DRM_FORMAT_BGRA5551:
247
248 case DRM_FORMAT_ARGB8888:
249 case DRM_FORMAT_ABGR8888:
250 case DRM_FORMAT_RGBA8888:
251 case DRM_FORMAT_BGRA8888:
252
253 case DRM_FORMAT_ARGB2101010:
254 case DRM_FORMAT_ABGR2101010:
255 case DRM_FORMAT_RGBA1010102:
256 case DRM_FORMAT_BGRA1010102:
257
258 case DRM_FORMAT_XRGB8888_A8:
259 case DRM_FORMAT_XBGR8888_A8:
260 case DRM_FORMAT_RGBX8888_A8:
261 case DRM_FORMAT_BGRX8888_A8:
262 case DRM_FORMAT_RGB888_A8:
263 case DRM_FORMAT_BGR888_A8:
264 case DRM_FORMAT_RGB565_A8:
265 case DRM_FORMAT_BGR565_A8:
266 alpha = true;
267 break;
268 default:
269 alpha = false;
270 break;
271 }
272 size = dmabufBuffer->size;
273 } else if (surface) {
274 EGLDisplay eglDisplay = surface->client()->display()->eglDisplay();
275
276 using namespace EGL;
277 static eglQueryWaylandBufferWL_func eglQueryWaylandBufferWL{nullptr};
278 static bool resolved{false};
279
280 if (!resolved && eglDisplay != EGL_NO_DISPLAY) {
281 eglQueryWaylandBufferWL = reinterpret_cast<eglQueryWaylandBufferWL_func>(
282 eglGetProcAddress("eglQueryWaylandBufferWL"));
283 resolved = true;
284 }
285
286 if (eglQueryWaylandBufferWL) {
287 EGLint width = 0;
288 EGLint height = 0;
289 bool valid = false;
290 valid = eglQueryWaylandBufferWL(eglDisplay, resource, EGL_WIDTH, &width);
291 valid = valid && eglQueryWaylandBufferWL(eglDisplay, resource, EGL_HEIGHT, &height);
292 if (valid) {
293 size = QSize(width, height);
294 }
295 // check alpha
296 EGLint format = 0;
297 if (eglQueryWaylandBufferWL(eglDisplay, resource, EGL_TEXTURE_FORMAT, &format)) {
298 switch (format) {
299 case EGL_TEXTURE_RGBA:
300 alpha = true;
301 break;
302 case EGL_TEXTURE_RGB:
303 default:
304 alpha = false;
305 break;
306 }
307 }
308 }
309 }
310 76 }
311
312 76 Buffer::Private::~Private()
313 {
314
1/2
✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
76 wl_list_remove(&destroyWrapper.listener.link);
315
2/4
✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
76 display->bufferManager()->removeBuffer(q_ptr);
316 76 }
317
318 67 std::shared_ptr<Buffer> Buffer::make(wl_resource* wlResource, Surface* surface)
319 {
320 67 auto backendDisplay = Wayland::Display::backendCast(surface->client()->display());
321
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 auto buffer = std::shared_ptr<Buffer>{new Buffer(wlResource, surface)};
322
2/4
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
67 backendDisplay->bufferManager()->addBuffer(buffer);
323 67 return buffer;
324
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 }
325
326 9 std::shared_ptr<Buffer> Buffer::make(wl_resource* wlResource, Display* display)
327 {
328 9 auto backendDisplay = Wayland::Display::backendCast(display);
329
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 auto buffer = std::shared_ptr<Buffer>{new Buffer(wlResource, display)};
330
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 backendDisplay->bufferManager()->addBuffer(buffer);
331 9 return buffer;
332
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 }
333
334 12 void Buffer::Private::destroyListenerCallback(wl_listener* listener, [[maybe_unused]] void* data)
335 {
336 // The wl_container_of macro can not be used with auto keyword and in the macro from libwayland
337 // the alignment is increased.
338 // Relevant clang-tidy checks are:
339 // * clang-diagnostic-cast-align
340 // * cppcoreguidelines-pro-bounds-pointer-arithmetic
341 // * hicpp-use-auto
342 // * modernize-use-auto
343 // NOLINTNEXTLINE
344 12 DestroyWrapper* wrapper = wl_container_of(listener, wrapper, listener);
345
346 12 wrapper->buffer->d_ptr->resource = nullptr;
347 12 Q_EMIT wrapper->buffer->resourceDestroyed();
348 12 }
349
350 67 Buffer::Buffer(wl_resource* wlResource, Surface* surface)
351 67 : QObject(nullptr)
352
2/4
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
134 , d_ptr(new Private(this,
353 67 wlResource,
354 67 surface,
355
3/6
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
67 Wayland::Display::backendCast(surface->client()->display())))
356 67 {
357 67 }
358
359 9 Buffer::Buffer(wl_resource* wlResource, Display* display)
360 9 : QObject(nullptr)
361
3/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
9 , d_ptr(new Private(this, wlResource, nullptr, Wayland::Display::backendCast(display)))
362 9 {
363 9 }
364
365 9 std::shared_ptr<Buffer> Buffer::get(Display* display, wl_resource* resource)
366 {
367
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (!resource) {
368 return nullptr;
369 }
370 // TODO(unknown author): verify resource is a buffer
371 9 auto buffer = Wayland::Display::backendCast(display)->bufferManager()->fromResource(resource);
372
2/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
9 return buffer ? buffer.value() : make(resource, display);
373 9 }
374
375 152 Buffer::~Buffer()
376 152 {
377
4/4
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 62 times.
76 if (d_ptr->committed && d_ptr->resource) {
378
1/2
✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
62 wl_buffer_send_release(d_ptr->resource);
379
2/4
✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 62 times.
✗ Branch 3 not taken.
62 wl_client_flush(wl_resource_get_client(d_ptr->resource));
380 62 }
381 152 }
382
383 1182 std::optional<ShmImage> Buffer::shmImage()
384 {
385 1182 return ShmImage::get(this);
386 }
387
388 Surface* Buffer::surface() const
389 {
390 return d_ptr->surface;
391 }
392
393 3 wl_shm_buffer* Buffer::shmBuffer()
394 {
395 3 return d_ptr->shmBuffer;
396 }
397
398 linux_dmabuf_buffer_v1* Buffer::linuxDmabufBuffer()
399 {
400 return d_ptr->dmabufBuffer;
401 }
402
403 36 wl_resource* Buffer::resource() const
404 {
405 36 return d_ptr->resource;
406 }
407
408 1652 QSize Buffer::size() const
409 {
410 1652 return d_ptr->size;
411 }
412
413 bool Buffer::hasAlphaChannel() const
414 {
415 return d_ptr->alpha;
416 }
417
418 66 void Buffer::setCommitted()
419 {
420 66 d_ptr->committed = true;
421 66 }
422
423 }
424