From 8a267894f3fa41e639bc52955bdf1dbba63abae1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 25 Mar 2021 16:04:12 +0530 Subject: [PATCH] Make createShmBuffer re-useable --- glfw/backend_utils.c | 70 +++++++++++++++++ glfw/backend_utils.h | 2 + glfw/wl_window.c | 175 +++++++++++++------------------------------ 3 files changed, 124 insertions(+), 123 deletions(-) diff --git a/glfw/backend_utils.c b/glfw/backend_utils.c index 2557111db..546f539fa 100644 --- a/glfw/backend_utils.c +++ b/glfw/backend_utils.c @@ -8,6 +8,7 @@ #define _GNU_SOURCE #include "backend_utils.h" #include "internal.h" +#include "memfd.h" #include #include @@ -350,3 +351,72 @@ GLFWAPI char* utf_8_strndup(const char* source, size_t max_length) { result[length] = 0; return result; } + +/* + * Create a new, unique, anonymous file of the given size, and + * return the file descriptor for it. The file descriptor is set + * CLOEXEC. The file is immediately suitable for mmap()'ing + * the given size at offset zero. + * + * The file should not have a permanent backing store like a disk, + * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. + * + * The file name is deleted from the file system. + * + * The file is suitable for buffer sharing between processes by + * transmitting the file descriptor over Unix sockets using the + * SCM_RIGHTS methods. + * + * posix_fallocate() is used to guarantee that disk space is available + * for the file at the given size. If disk space is insufficient, errno + * is set to ENOSPC. If posix_fallocate() is not supported, program may + * receive SIGBUS on accessing mmap()'ed file contents instead. + */ +int createAnonymousFile(off_t size) { + int ret, fd = -1, shm_anon = 0; +#ifdef HAS_MEMFD_CREATE + fd = memfd_create("glfw-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING); + if (fd < 0) return -1; + // We can add this seal before calling posix_fallocate(), as the file + // is currently zero-sized anyway. + // + // There is also no need to check for the return value, we couldn’t do + // anything with it anyway. + fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL); +#elif defined(SHM_ANON) + fd = shm_open(SHM_ANON, O_RDWR | O_CLOEXEC, 0600); + if (fd < 0) return -1; + shm_anon = 1; +#else + static const char template[] = "/glfw-shared-XXXXXX"; + const char* path; + char* name; + + path = getenv("XDG_RUNTIME_DIR"); + if (!path) + { + errno = ENOENT; + return -1; + } + + name = calloc(strlen(path) + sizeof(template), 1); + strcpy(name, path); + strcat(name, template); + + fd = createTmpfileCloexec(name); + + free(name); + + if (fd < 0) + return -1; +#endif + // posix_fallocate does not work on SHM descriptors + ret = shm_anon ? ftruncate(fd, size) : posix_fallocate(fd, 0, size); + if (ret != 0) + { + close(fd); + errno = ret; + return -1; + } + return fd; +} diff --git a/glfw/backend_utils.h b/glfw/backend_utils.h index cdbbd3eee..00e2b8aa7 100644 --- a/glfw/backend_utils.h +++ b/glfw/backend_utils.h @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef __has_include #if __has_include() @@ -96,3 +97,4 @@ void finalizePollData(EventLoopData *eld); bool initPollData(EventLoopData *eld, int display_fd); void wakeupEventLoop(EventLoopData *eld); char* utf_8_strndup(const char* source, size_t max_length); +int createAnonymousFile(off_t size); diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 87b90eb6e..e4a78f086 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -42,6 +42,58 @@ #include +static struct wl_buffer* createShmBuffer(const GLFWimage* image) +{ + struct wl_shm_pool* pool; + struct wl_buffer* buffer; + int stride = image->width * 4; + int length = image->width * image->height * 4; + void* data; + int fd, i; + + fd = createAnonymousFile(length); + if (fd < 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Creating a buffer file for %d B failed: %s", + length, strerror(errno)); + return NULL; + } + + data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: mmap failed: %s", strerror(errno)); + close(fd); + return NULL; + } + + pool = wl_shm_create_pool(_glfw.wl.shm, fd, length); + + close(fd); + unsigned char* source = (unsigned char*) image->pixels; + unsigned char* target = data; + for (i = 0; i < image->width * image->height; i++, source += 4) + { + unsigned int alpha = source[3]; + + *target++ = (unsigned char) ((source[2] * alpha) / 255); + *target++ = (unsigned char) ((source[1] * alpha) / 255); + *target++ = (unsigned char) ((source[0] * alpha) / 255); + *target++ = (unsigned char) alpha; + } + + buffer = + wl_shm_pool_create_buffer(pool, 0, + image->width, + image->height, + stride, WL_SHM_FORMAT_ARGB8888); + munmap(data, length); + wl_shm_pool_destroy(pool); + + return buffer; +} static void setCursorImage(_GLFWwindow* window, bool on_theme_change) { _GLFWcursorWayland defaultCursor = {.shape = GLFW_ARROW_CURSOR}; @@ -225,129 +277,6 @@ static void dispatchChangesAfterConfigure(_GLFWwindow *window, int32_t width, in } -/* - * Create a new, unique, anonymous file of the given size, and - * return the file descriptor for it. The file descriptor is set - * CLOEXEC. The file is immediately suitable for mmap()'ing - * the given size at offset zero. - * - * The file should not have a permanent backing store like a disk, - * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. - * - * The file name is deleted from the file system. - * - * The file is suitable for buffer sharing between processes by - * transmitting the file descriptor over Unix sockets using the - * SCM_RIGHTS methods. - * - * posix_fallocate() is used to guarantee that disk space is available - * for the file at the given size. If disk space is insufficient, errno - * is set to ENOSPC. If posix_fallocate() is not supported, program may - * receive SIGBUS on accessing mmap()'ed file contents instead. - */ -static int createAnonymousFile(off_t size) -{ - int ret, fd = -1, shm_anon = 0; -#ifdef HAS_MEMFD_CREATE - fd = memfd_create("glfw-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING); - if (fd < 0) return -1; - // We can add this seal before calling posix_fallocate(), as the file - // is currently zero-sized anyway. - // - // There is also no need to check for the return value, we couldn’t do - // anything with it anyway. - fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL); -#elif defined(SHM_ANON) - fd = shm_open(SHM_ANON, O_RDWR | O_CLOEXEC, 0600); - if (fd < 0) return -1; - shm_anon = 1; -#else - static const char template[] = "/glfw-shared-XXXXXX"; - const char* path; - char* name; - - path = getenv("XDG_RUNTIME_DIR"); - if (!path) - { - errno = ENOENT; - return -1; - } - - name = calloc(strlen(path) + sizeof(template), 1); - strcpy(name, path); - strcat(name, template); - - fd = createTmpfileCloexec(name); - - free(name); - - if (fd < 0) - return -1; -#endif - // posix_fallocate does not work on SHM descriptors - ret = shm_anon ? ftruncate(fd, size) : posix_fallocate(fd, 0, size); - if (ret != 0) - { - close(fd); - errno = ret; - return -1; - } - return fd; -} - -static struct wl_buffer* createShmBuffer(const GLFWimage* image) -{ - struct wl_shm_pool* pool; - struct wl_buffer* buffer; - int stride = image->width * 4; - int length = image->width * image->height * 4; - void* data; - int fd, i; - - fd = createAnonymousFile(length); - if (fd < 0) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Creating a buffer file for %d B failed: %s", - length, strerror(errno)); - return NULL; - } - - data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (data == MAP_FAILED) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: mmap failed: %s", strerror(errno)); - close(fd); - return NULL; - } - - pool = wl_shm_create_pool(_glfw.wl.shm, fd, length); - - close(fd); - unsigned char* source = (unsigned char*) image->pixels; - unsigned char* target = data; - for (i = 0; i < image->width * image->height; i++, source += 4) - { - unsigned int alpha = source[3]; - - *target++ = (unsigned char) ((source[2] * alpha) / 255); - *target++ = (unsigned char) ((source[1] * alpha) / 255); - *target++ = (unsigned char) ((source[0] * alpha) / 255); - *target++ = (unsigned char) alpha; - } - - buffer = - wl_shm_pool_create_buffer(pool, 0, - image->width, - image->height, - stride, WL_SHM_FORMAT_ARGB8888); - munmap(data, length); - wl_shm_pool_destroy(pool); - - return buffer; -} - static void createDecoration(_GLFWdecorationWayland* decoration, struct wl_surface* parent, struct wl_buffer* buffer, bool opaque,