7#include "config-kwin.h"
13#include <drm_fourcc.h>
23static constexpr int s_version = 1;
25static constexpr uint32_t s_formats[] = {
26 WL_SHM_FORMAT_ARGB8888,
27 WL_SHM_FORMAT_XRGB8888,
28#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
29 WL_SHM_FORMAT_ARGB2101010,
30 WL_SHM_FORMAT_XRGB2101010,
31 WL_SHM_FORMAT_ABGR2101010,
32 WL_SHM_FORMAT_XBGR2101010,
33 WL_SHM_FORMAT_ABGR16161616,
34 WL_SHM_FORMAT_XBGR16161616,
46static struct sigaction prevSigbusAction;
48static uint32_t shmFormatToDrmFormat(uint32_t shmFormat)
51 case WL_SHM_FORMAT_ARGB8888:
52 return DRM_FORMAT_ARGB8888;
53 case WL_SHM_FORMAT_XRGB8888:
54 return DRM_FORMAT_XRGB8888;
61 : QtWaylandServer::wl_shm_pool(client, id,
version)
62 , integration(integration)
63 , mapping(std::move(mapping))
67 const int seals = fcntl(this->
fd.
get(), F_GET_SEALS);
70 if ((seals & F_SEAL_SHRINK) && fstat(this->
fd.
get(), &statbuf) >= 0) {
97 wl_resource_destroy(resource->handle);
102 if (std::find(std::begin(s_formats), std::end(s_formats),
format) == std::end(s_formats)) {
103 wl_resource_post_error(resource->handle,
104 WL_SHM_ERROR_INVALID_FORMAT,
105 "invalid format 0x%x",
110 if (offset < 0 || width <= 0 || height <= 0 || stride < width
111 || INT32_MAX / stride < height || offset >
mapping.
size() - stride * height) {
112 wl_resource_post_error(resource->handle,
113 WL_SHM_ERROR_INVALID_STRIDE,
114 "invalid width, height or stride (%dx%d, %u)",
115 width, height, stride);
123 .size = QSize(width, height),
124 .format = shmFormatToDrmFormat(
format),
127 new ShmClientBuffer(
this, std::move(attributes), resource->client(),
id);
133 wl_resource_post_error(resource->handle, WL_SHM_ERROR_INVALID_FD,
"shrinking pool invalid");
137 auto remapping =
MemoryMap(size, PROT_READ | PROT_WRITE, MAP_SHARED,
fd.
get(), 0);
138 if (remapping.isValid()) {
139 mapping = std::move(remapping);
141 wl_resource_post_error(resource->handle, WL_SHM_ERROR_INVALID_FD,
"failed to map shm pool with the new size");
145void ShmClientBuffer::buffer_destroy_resource(wl_resource *resource)
148 buffer->m_resource =
nullptr;
153void ShmClientBuffer::buffer_destroy(wl_client *client, wl_resource *resource)
155 wl_resource_destroy(resource);
164 , m_shmAttributes(std::move(attributes))
169 wl_buffer_send_release(m_resource);
172 m_resource = wl_resource_create(client, &wl_buffer_interface, 1,
id);
173 wl_resource_set_implementation(m_resource, &implementation,
this, buffer_destroy_resource);
183 return m_shmAttributes.
size;
193 return &m_shmAttributes;
198 if (wl_resource_instance_of(resource, &wl_buffer_interface, &implementation)) {
199 return static_cast<ShmClientBuffer *
>(wl_resource_get_user_data(resource));
204static void sigbusHandler(
int signum, siginfo_t *info,
void *context)
206 auto reraise = [&]() {
207 if (prevSigbusAction.sa_flags & SA_SIGINFO) {
208 prevSigbusAction.sa_sigaction(signum, info, context);
210 prevSigbusAction.sa_handler(signum);
214 const ShmPool *pool = sigbusData.
pool;
220 const uchar *addr =
static_cast<uchar *
>(info->si_addr);
221 const uchar *mappingStart =
static_cast<uchar *
>(pool->mapping.data());
222 if (addr < mappingStart || addr >= mappingStart + pool->mapping.size()) {
228 if (mmap(pool->mapping.data(), pool->mapping.size(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0) == MAP_FAILED) {
241 static std::once_flag sigbusOnce;
242 std::call_once(sigbusOnce, []() {
243 struct sigaction action;
244 memset(&action, 0,
sizeof(action));
245 sigemptyset(&action.sa_mask);
246 action.sa_sigaction = sigbusHandler;
247 action.sa_flags = SA_SIGINFO | SA_NODEFER;
248 sigaction(SIGBUS, &action, &prevSigbusAction);
251 Q_ASSERT(!sigbusData.
pool || sigbusData.
pool == m_shmPool);
252 sigbusData.
pool = m_shmPool;
258 .stride = uint32_t(m_shmAttributes.
stride),
271 sigbusData.
pool =
nullptr;
276 : QtWaylandServer::wl_shm(*display, s_version)
283 for (
const uint32_t &
format : s_formats) {
284 send_format(resource->handle,
format);
293 wl_resource_post_error(resource->handle, error_invalid_stride,
"invalid size (%d)", size);
297 auto mapping =
MemoryMap(size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
298 if (!mapping.isValid()) {
299 wl_resource_post_error(resource->handle, error_invalid_fd,
"failed to map shm pool");
303 new ShmPool(
q, resource->client(),
id, resource->version(), std::move(fileDescriptor), std::move(mapping));
318#include "moc_shmclientbuffer_p.cpp"
320#include "moc_shmclientbuffer.cpp"
Class holding the Wayland server display loop.
FileDescriptor duplicate() const
static bool alphaChannelFromDrmFormat(uint32_t format)
~ShmClientBufferIntegration() override
ShmClientBufferIntegration(Display *display)
ShmClientBufferIntegrationPrivate(Display *display, ShmClientBufferIntegration *q)
ShmClientBufferIntegration * q
void shm_bind_resource(Resource *resource) override
void shm_create_pool(Resource *resource, uint32_t id, int32_t fd, int32_t size) override
void shm_pool_destroy_resource(Resource *resource) override
ShmPool(ShmClientBufferIntegration *integration, wl_client *client, int id, uint32_t version, FileDescriptor &&fd, MemoryMap &&mapping)
void shm_pool_resize(Resource *resource, int32_t size) override
void shm_pool_create_buffer(Resource *resource, uint32_t id, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) override
void shm_pool_destroy(Resource *resource) override
ShmClientBuffer(ShmPool *pool, ShmAttributes attributes, wl_client *client, uint32_t id)
~ShmClientBuffer() override
Map map(MapFlags flags) override
static ShmClientBuffer * get(wl_resource *resource)
bool hasAlphaChannel() const override
QSize size() const override
const ShmAttributes * shmAttributes() const override