-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshm.c
129 lines (108 loc) · 3.13 KB
/
shm.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include "shm.h"
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <linux/memfd.h>
#include <tllist.h>
#define LOG_MODULE "shm"
#include "log.h"
#include "stride.h"
static void
buffer_destroy(struct buffer *buf)
{
pixman_image_unref(buf->pix);
wl_buffer_destroy(buf->wl_buf);
munmap(buf->mmapped, buf->size);
free(buf);
}
static void
buffer_release(void *data, struct wl_buffer *wl_buffer)
{
struct buffer *buffer = data;
buffer_destroy(buffer);
}
static const struct wl_buffer_listener buffer_listener = {
.release = &buffer_release,
};
struct buffer *
shm_get_buffer(struct wl_shm *shm, int width, int height, unsigned long cookie)
{
/*
* 1. open a memory backed "file" with memfd_create()
* 2. mmap() the memory file, to be used by the pixman image
* 3. create a wayland shm buffer for the same memory file
*
* The pixman image and the wayland buffer are now sharing memory.
*/
int pool_fd = -1;
void *mmapped = NULL;
size_t size = 0;
struct wl_shm_pool *pool = NULL;
struct wl_buffer *buf = NULL;
pixman_image_t *pix = NULL;
/* Backing memory for SHM */
pool_fd = memfd_create("wbg-wayland-shm-buffer-pool", MFD_CLOEXEC);
if (pool_fd == -1) {
LOG_ERRNO("failed to create SHM backing memory file");
goto err;
}
/* Total size */
const uint32_t stride = stride_for_format_and_width(PIXMAN_x8r8g8b8, width);
size = stride * height;
if (ftruncate(pool_fd, size) == -1) {
LOG_ERRNO("failed to truncate SHM pool");
goto err;
}
mmapped = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, pool_fd, 0);
if (mmapped == MAP_FAILED) {
LOG_ERR("failed to mmap SHM backing memory file");
goto err;
}
pool = wl_shm_create_pool(shm, pool_fd, size);
if (pool == NULL) {
LOG_ERR("failed to create SHM pool");
goto err;
}
buf = wl_shm_pool_create_buffer(
pool, 0, width, height, stride, WL_SHM_FORMAT_XRGB8888);
if (buf == NULL) {
LOG_ERR("failed to create SHM buffer");
goto err;
}
/* We use the entire pool for our single buffer */
wl_shm_pool_destroy(pool); pool = NULL;
close(pool_fd); pool_fd = -1;
pix = pixman_image_create_bits_no_clear(
PIXMAN_x8r8g8b8, width, height, mmapped, stride);
if (pix == NULL) {
LOG_ERR("failed to create pixman image");
goto err;
}
struct buffer *buffer = malloc(sizeof(*buffer));
*buffer = (struct buffer){
.width = width,
.height = height,
.stride = stride,
.cookie = cookie,
.busy = true,
.size = size,
.mmapped = mmapped,
.wl_buf = buf,
.pix = pix,
};
wl_buffer_add_listener(buffer->wl_buf, &buffer_listener, buffer);
return buffer;
err:
if (pix != NULL)
pixman_image_unref(pix);
if (buf != NULL)
wl_buffer_destroy(buf);
if (pool != NULL)
wl_shm_pool_destroy(pool);
if (pool_fd != -1)
close(pool_fd);
if (mmapped != NULL)
munmap(mmapped, size);
return NULL;
}