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#if defined HAVE_MEMFD
82 int fd = memfd_create("kwayland-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);
83 if (fd >= 0) {
84 fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
85 } else
86#endif
87 {
88 char templateName[] = "/tmp/kwayland-shared-XXXXXX";
89 fd = mkstemp(templateName);
90 if (fd >= 0) {
91 unlink(templateName);
92
93 int flags = fcntl(fd, F_GETFD);
94 if (flags == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
95 close(fd);
96 fd = -1;
97 }
98 }
99 }
100
101 if (fd == -1) {
102 qCDebug(KWAYLAND_KWS) << "Could not open temporary file for Shm pool";
103 return {};
104 }
105
106 if (ftruncate(fd, byteCount) < 0) {
107 qCDebug(KWAYLAND_KWS) << "Could not set size for Shm pool file";
108 close(fd);
109 return {};
110 }
111 auto data = mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
112
113 if (data == MAP_FAILED) {
114 qCDebug(KWAYLAND_KWS) << "Creating Shm pool failed";
115 close(fd);
116 return {};
117 }
118
119 auto pool = create_pool(fd, byteCount);
120 auto *buffer = wl_shm_pool_create_buffer(pool, 0, image.size().width(), image.size().height(), stride, format);
121 wl_shm_pool_destroy(pool);
122
123 const QImage &srcImage = [format, &image] {
124 if (format == WL_SHM_FORMAT_ARGB8888 && image.format() != QImage::Format_ARGB32_Premultiplied) {
126 } else {
127 return image;
128 }
129 }();
130
131 std::memcpy(static_cast<char *>(data), srcImage.bits(), byteCount);
132
133 munmap(data, byteCount);
134 close(fd);
135 return std::make_unique<ShmBuffer>(buffer);
136}
const QList< QKeySequence > & close()
void initialize(StandardShortcut id)
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 May 3 2024 11:45:49 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.