Atlas - SDL_waylandshmbuffer.c

Home / ext / SDL / src / video / wayland Lines: 1 | Size: 5796 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21 22#include "SDL_internal.h" 23 24#ifdef SDL_VIDEO_DRIVER_WAYLAND 25 26#include <errno.h> 27#include <fcntl.h> 28#include <limits.h> 29#include <signal.h> 30#include <sys/mman.h> 31#include <unistd.h> 32 33#include "SDL_waylandshmbuffer.h" 34#include "SDL_waylandvideo.h" 35#include "single-pixel-buffer-v1-client-protocol.h" 36 37static bool SetTempFileSize(int fd, off_t size) 38{ 39#ifdef HAVE_POSIX_FALLOCATE 40 sigset_t set, old_set; 41 int ret; 42 43 /* SIGALRM can potentially block a large posix_fallocate() operation 44 * from succeeding, so block it. 45 */ 46 sigemptyset(&set); 47 sigaddset(&set, SIGALRM); 48 sigprocmask(SIG_BLOCK, &set, &old_set); 49 50 do { 51 ret = posix_fallocate(fd, 0, size); 52 } while (ret == EINTR); 53 54 sigprocmask(SIG_SETMASK, &old_set, NULL); 55 56 if (ret == 0) { 57 return true; 58 } else if (ret != EINVAL && errno != EOPNOTSUPP) { 59 return false; 60 } 61#endif 62 63 if (ftruncate(fd, size) < 0) { 64 return false; 65 } 66 return true; 67} 68 69static int CreateTempFD(off_t size) 70{ 71 int fd; 72 73#ifdef HAVE_MEMFD_CREATE 74 fd = memfd_create("SDL", MFD_CLOEXEC | MFD_ALLOW_SEALING); 75 if (fd >= 0) { 76 fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL); 77 } else 78#endif 79 { 80 static const char template[] = "/sdl-shared-XXXXXX"; 81 const char *xdg_path; 82 char tmp_path[PATH_MAX]; 83 84 xdg_path = SDL_getenv("XDG_RUNTIME_DIR"); 85 if (!xdg_path) { 86 return -1; 87 } 88 89 SDL_strlcpy(tmp_path, xdg_path, PATH_MAX); 90 SDL_strlcat(tmp_path, template, PATH_MAX); 91 92 fd = mkostemp(tmp_path, O_CLOEXEC); 93 if (fd < 0) { 94 return -1; 95 } 96 97 // Need to manually unlink the temp files, or they can persist after close and fill up the temp storage. 98 unlink(tmp_path); 99 } 100 101 if (!SetTempFileSize(fd, size)) { 102 close(fd); 103 return -1; 104 } 105 106 return fd; 107} 108 109static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer) 110{ 111 // NOP 112} 113 114static struct wl_buffer_listener buffer_listener = { 115 buffer_handle_release 116}; 117 118struct Wayland_SHMPool 119{ 120 struct wl_shm_pool *shm_pool; 121 void *shm_pool_memory; 122 int shm_pool_size; 123 int offset; 124}; 125 126Wayland_SHMPool *Wayland_AllocSHMPool(int size) 127{ 128 SDL_VideoDevice *vd = SDL_GetVideoDevice(); 129 SDL_VideoData *data = vd->internal; 130 131 if (size <= 0) { 132 return NULL; 133 } 134 135 Wayland_SHMPool *shmPool = SDL_calloc(1, sizeof(Wayland_SHMPool)); 136 if (!shmPool) { 137 return NULL; 138 } 139 140 shmPool->shm_pool_size = (size + 15) & (~15); 141 142 const int shm_fd = CreateTempFD(shmPool->shm_pool_size); 143 if (shm_fd < 0) { 144 SDL_free(shmPool); 145 SDL_SetError("Creating SHM buffer failed."); 146 return NULL; 147 } 148 149 shmPool->shm_pool_memory = mmap(NULL, shmPool->shm_pool_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); 150 if (shmPool->shm_pool_memory == MAP_FAILED) { 151 shmPool->shm_pool_memory = NULL; 152 close(shm_fd); 153 SDL_free(shmPool); 154 SDL_SetError("mmap() failed."); 155 return NULL; 156 } 157 158 shmPool->shm_pool = wl_shm_create_pool(data->shm, shm_fd, shmPool->shm_pool_size); 159 close(shm_fd); 160 161 return shmPool; 162} 163 164struct wl_buffer *Wayland_AllocBufferFromPool(Wayland_SHMPool *shmPool, int width, int height, void **data) 165{ 166 const Uint32 SHM_FMT = WL_SHM_FORMAT_ARGB8888; 167 168 if (!shmPool || !width || !height || !data) { 169 return NULL; 170 } 171 172 *data = (Uint8 *)shmPool->shm_pool_memory + shmPool->offset; 173 struct wl_buffer *buffer = wl_shm_pool_create_buffer(shmPool->shm_pool, shmPool->offset, width, height, width * 4, SHM_FMT); 174 wl_buffer_add_listener(buffer, &buffer_listener, shmPool); 175 176 shmPool->offset += width * height * 4; 177 178 return buffer; 179} 180 181void Wayland_ReleaseSHMPool(Wayland_SHMPool *shmPool) 182{ 183 if (shmPool) { 184 wl_shm_pool_destroy(shmPool->shm_pool); 185 munmap(shmPool->shm_pool_memory, shmPool->shm_pool_size); 186 SDL_free(shmPool); 187 } 188} 189 190struct wl_buffer *Wayland_CreateSinglePixelBuffer(Uint32 r, Uint32 g, Uint32 b, Uint32 a) 191{ 192 SDL_VideoData *viddata = SDL_GetVideoDevice()->internal; 193 194 // The single-pixel buffer protocol is preferred, as the compositor can choose an optimal format. 195 if (viddata->single_pixel_buffer_manager) { 196 return wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(viddata->single_pixel_buffer_manager, r, g, b, a); 197 } else { 198 Wayland_SHMPool *pool = Wayland_AllocSHMPool(4); 199 if (!pool) { 200 return NULL; 201 } 202 203 void *mem; 204 struct wl_buffer *wl_buffer = Wayland_AllocBufferFromPool(pool, 1, 1, &mem); 205 206 const Uint8 pixel[4] = { r >> 24, g >> 24, b >> 24, a >> 24 }; 207 SDL_memcpy(mem, pixel, sizeof(pixel)); 208 209 Wayland_ReleaseSHMPool(pool); 210 return wl_buffer; 211 } 212} 213 214#endif 215
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.