KWindowSystem

shm.cpp
1/*
2 SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
3 SPDX-FileCopyrightText: 2023 David Redondo <kde@david-redondo.de>
4
5 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6*/
7
8#include "shm.h"
9
10#include <QGuiApplication>
11#include <QImage>
12
13#include <fcntl.h>
14#include <sys/mman.h>
15#include <unistd.h>
16
17#include <cstring>
18
19static constexpr auto version = 1;
20
21ShmBuffer::ShmBuffer(::wl_buffer *buffer)
22 : QtWayland::wl_buffer(buffer)
23{
24}
25
26ShmBuffer::~ShmBuffer()
27{
28 destroy();
29}
30
31Shm::Shm(QObject *parent)
32 : QWaylandClientExtensionTemplate(::version)
33{
34 setParent(parent);
35 connect(this, &QWaylandClientExtension::activeChanged, this, [this] {
36 if (!isActive()) {
37 wl_shm_destroy(object());
38 }
39 });
40 initialize();
41}
42
43Shm *Shm::instance()
44{
45 static Shm *instance = new Shm(qGuiApp);
46 return instance;
47}
48
49Shm::~Shm() noexcept
50{
51 if (isActive()) {
52 wl_shm_destroy(object());
53 }
54}
55
56static wl_shm_format toWaylandFormat(QImage::Format format)
57{
58 switch (format) {
60 return WL_SHM_FORMAT_ARGB8888;
62 return WL_SHM_FORMAT_XRGB8888;
64 qCWarning(KWAYLAND_KWS()) << "Unsupported image format: " << format << ". expect slow performance. Use QImage::Format_ARGB32_Premultiplied";
65 return WL_SHM_FORMAT_ARGB8888;
66 default:
67 qCWarning(KWAYLAND_KWS()) << "Unsupported image format: " << format << ". expect slow performance.";
68 return WL_SHM_FORMAT_ARGB8888;
69 }
70}
71
72std::unique_ptr<ShmBuffer> Shm::createBuffer(const QImage &image)
73{
74 if (image.isNull()) {
75 return {};
76 }
77 auto format = toWaylandFormat(image.format());
78 const int stride = image.bytesPerLine();
79 const int32_t byteCount = image.size().height() * stride;
80
81 int fd = -1;
82#if defined HAVE_MEMFD
83 fd = memfd_create("kwayland-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);
84 if (fd >= 0) {
85 fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
86 } else
87#endif
88 {
89 char templateName[] = "/tmp/kwayland-shared-XXXXXX";
90 fd = mkstemp(templateName);
91 if (fd >= 0) {
92 unlink(templateName);
93
94 int flags = fcntl(fd, F_GETFD);
95 if (flags == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
96 close(fd);
97 fd = -1;
98 }
99 }
100 }
101
102 if (fd == -1) {
103 qCDebug(KWAYLAND_KWS) << "Could not open temporary file for Shm pool";
104 return {};
105 }
106
107 if (ftruncate(fd, byteCount) < 0) {
108 qCDebug(KWAYLAND_KWS) << "Could not set size for Shm pool file";
109 close(fd);
110 return {};
111 }
112 auto data = mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
113
114 if (data == MAP_FAILED) {
115 qCDebug(KWAYLAND_KWS) << "Creating Shm pool failed";
116 close(fd);
117 return {};
118 }
119
120 auto pool = create_pool(fd, byteCount);
121 auto *buffer = wl_shm_pool_create_buffer(pool, 0, image.size().width(), image.size().height(), stride, format);
122 wl_shm_pool_destroy(pool);
123
124 const QImage &srcImage = [format, &image] {
125 if (format == WL_SHM_FORMAT_ARGB8888 && image.format() != QImage::Format_ARGB32_Premultiplied) {
127 } else {
128 return image;
129 }
130 }();
131
132 std::memcpy(static_cast<char *>(data), srcImage.bits(), byteCount);
133
134 munmap(data, byteCount);
135 close(fd);
136 return std::make_unique<ShmBuffer>(buffer);
137}
KCRASH_EXPORT void initialize()
KGuiItem close()
uchar * bits()
qsizetype bytesPerLine() const const
QImage convertToFormat(Format format, Qt::ImageConversionFlags flags) &&
Format format() const const
bool isNull() const const
QSize size() const const
int height() const const
int width() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:13:12 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.