bufpool.h (3983B)
1 /* 2 * bufpool - https://codeberg.org/sewn/drwl 3 * 4 * Copyright (c) 2023-2024 sewn <sewn@disroot.org> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sublicense, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be 15 * included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 #include <stdlib.h> 26 #include <stddef.h> 27 #include <stdint.h> 28 #include <sys/mman.h> 29 #include <fcntl.h> 30 #include <unistd.h> 31 #include <wayland-client.h> 32 #ifdef __linux__ 33 #include <linux/memfd.h> 34 #endif 35 36 #include "drwl.h" 37 38 typedef struct { 39 struct wl_buffer *wl_buf; 40 int32_t size; 41 int busy; 42 void *mmapped; 43 Img *image; 44 } DrwBuf; 45 46 typedef struct { 47 DrwBuf bufs[2]; 48 } BufPool; 49 50 static void 51 drwbuf_cleanup(DrwBuf *buf) 52 { 53 if (buf->wl_buf) 54 wl_buffer_destroy(buf->wl_buf); 55 if (buf->mmapped) 56 munmap(buf->mmapped, buf->size); 57 if (buf->image) 58 drwl_image_destroy(buf->image); 59 *buf = (DrwBuf){0}; 60 } 61 62 static void 63 drwbuf_handle_release(void *data, struct wl_buffer *wl_buffer) 64 { 65 DrwBuf *buf = data; 66 buf->busy = 0; 67 } 68 69 static struct wl_buffer_listener drwbuf_buffer_listener = { 70 .release = drwbuf_handle_release, 71 }; 72 73 static DrwBuf * 74 bufpool_getbuf(BufPool *pool, struct wl_shm *shm, 75 int32_t width, int32_t height) 76 { 77 int i; 78 int fd; 79 void *mmapped; 80 struct wl_shm_pool *shm_pool; 81 struct wl_buffer *wl_buf; 82 int32_t size = width * 4 * height; 83 Img *image; 84 DrwBuf *buf = NULL; 85 86 for (i = 0; i < 2; i++) { 87 if (pool->bufs[i].busy) 88 continue; 89 if (pool->bufs[i].wl_buf && pool->bufs[i].size != size) 90 drwbuf_cleanup(&pool->bufs[i]); 91 buf = &pool->bufs[i]; 92 } 93 if (!buf) 94 return NULL; 95 if (buf->wl_buf && buf->size == size) 96 return buf; 97 98 #if defined(__linux__) || \ 99 ((defined(__FreeBSD__) && (__FreeBSD_version >= 1300048))) 100 fd = memfd_create("drwbuf-shm-buffer-pool", 101 MFD_CLOEXEC | MFD_ALLOW_SEALING | 102 #if defined(MFD_NOEXEC_SEAL) 103 MFD_NOEXEC_SEAL 104 #else 105 0 106 #endif 107 ); 108 #else 109 char template[] = "/tmp/drwbuf-XXXXXX"; 110 #if defined(__OpenBSD__) 111 fd = shm_mkstemp(template); 112 #else 113 fd = mkostemp(template, O_CLOEXEC); 114 #endif 115 if (fd < 0) 116 return NULL; 117 #if defined(__OpenBSD__) 118 shm_unlink(template); 119 #else 120 unlink(template); 121 #endif 122 #endif 123 124 if ((ftruncate(fd, size)) < 0) { 125 close(fd); 126 return NULL; 127 } 128 129 mmapped = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 130 if (mmapped == MAP_FAILED) { 131 close(fd); 132 return NULL; 133 } 134 135 #if defined(__linux__) || \ 136 ((defined(__FreeBSD__) && (__FreeBSD_version >= 1300048))) 137 fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL); 138 #endif 139 140 shm_pool = wl_shm_create_pool(shm, fd, size); 141 wl_buf = wl_shm_pool_create_buffer(shm_pool, 0, 142 width, height, width * 4, WL_SHM_FORMAT_ARGB8888); 143 wl_shm_pool_destroy(shm_pool); 144 close(fd); 145 146 buf->wl_buf = wl_buf; 147 buf->size = size; 148 buf->mmapped = mmapped; 149 buf->busy = 1; 150 if (!(image = drwl_image_create(NULL, width, height, buf->mmapped))) 151 drwbuf_cleanup(buf); 152 buf->image = image; 153 wl_buffer_add_listener(wl_buf, &drwbuf_buffer_listener, buf); 154 return buf; 155 } 156 157 static void 158 bufpool_cleanup(BufPool *pool) 159 { 160 int i; 161 for (i = 0; i < 2; i++) 162 drwbuf_cleanup(&pool->bufs[i]); 163 }