Make createShmBuffer re-useable
This commit is contained in:
parent
0510cd47f4
commit
8a267894f3
70
glfw/backend_utils.c
vendored
70
glfw/backend_utils.c
vendored
@ -8,6 +8,7 @@
|
|||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include "backend_utils.h"
|
#include "backend_utils.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "memfd.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -350,3 +351,72 @@ GLFWAPI char* utf_8_strndup(const char* source, size_t max_length) {
|
|||||||
result[length] = 0;
|
result[length] = 0;
|
||||||
return result;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
2
glfw/backend_utils.h
vendored
2
glfw/backend_utils.h
vendored
@ -29,6 +29,7 @@
|
|||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#ifdef __has_include
|
#ifdef __has_include
|
||||||
#if __has_include(<sys/eventfd.h>)
|
#if __has_include(<sys/eventfd.h>)
|
||||||
@ -96,3 +97,4 @@ void finalizePollData(EventLoopData *eld);
|
|||||||
bool initPollData(EventLoopData *eld, int display_fd);
|
bool initPollData(EventLoopData *eld, int display_fd);
|
||||||
void wakeupEventLoop(EventLoopData *eld);
|
void wakeupEventLoop(EventLoopData *eld);
|
||||||
char* utf_8_strndup(const char* source, size_t max_length);
|
char* utf_8_strndup(const char* source, size_t max_length);
|
||||||
|
int createAnonymousFile(off_t size);
|
||||||
|
|||||||
175
glfw/wl_window.c
vendored
175
glfw/wl_window.c
vendored
@ -42,6 +42,58 @@
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
|
||||||
|
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
|
static void
|
||||||
setCursorImage(_GLFWwindow* window, bool on_theme_change) {
|
setCursorImage(_GLFWwindow* window, bool on_theme_change) {
|
||||||
_GLFWcursorWayland defaultCursor = {.shape = GLFW_ARROW_CURSOR};
|
_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,
|
static void createDecoration(_GLFWdecorationWayland* decoration,
|
||||||
struct wl_surface* parent,
|
struct wl_surface* parent,
|
||||||
struct wl_buffer* buffer, bool opaque,
|
struct wl_buffer* buffer, bool opaque,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user