From 4fa019d31fa0c30f6ffdfd70bb1ddf2b87aed925 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Tue, 23 Jun 2020 18:30:08 +0000 Subject: [PATCH] buffer: Add DMA-BUFs --- include/buffer.h | 12 +++++ meson.build | 2 + src/buffer.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 2 + 4 files changed, 131 insertions(+) diff --git a/include/buffer.h b/include/buffer.h index db88778..d3e2631 100644 --- a/include/buffer.h +++ b/include/buffer.h @@ -7,21 +7,33 @@ #include struct wl_buffer; +struct gbm_bo; enum wv_buffer_type { WV_BUFFER_UNSPEC = 0, WV_BUFFER_SHM, + WV_BUFFER_DMABUF, }; struct wv_buffer { enum wv_buffer_type type; TAILQ_ENTRY(wv_buffer) link; + struct wl_buffer* wl_buffer; + void* pixels; size_t size; int width, height, stride; uint32_t format; bool y_inverted; + + /* The following is only applicable to DMABUF */ + struct gbm_bo* bo; + void* bo_map_handle; + + bool is_ready; + void (*on_ready)(struct wv_buffer*); + void* userdata; }; TAILQ_HEAD(wv_buffer_queue, wv_buffer); diff --git a/meson.build b/meson.build index b76c3aa..65dfba0 100644 --- a/meson.build +++ b/meson.build @@ -30,6 +30,7 @@ librt = cc.find_library('rt', required: false) pixman = dependency('pixman-1') egl = dependency('egl') glesv2 = dependency('glesv2') +gbm = dependency('gbm') xkbcommon = dependency('xkbcommon') wayland_client = dependency('wayland-client') @@ -85,6 +86,7 @@ dependencies = [ aml, egl, glesv2, + gbm, wayland_client, neatvnc, xkbcommon, diff --git a/src/buffer.c b/src/buffer.c index ef0c822..fb07c1a 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -6,13 +6,17 @@ #include #include #include +#include +#include "linux-dmabuf-unstable-v1.h" #include "shm.h" #include "sys/queue.h" #include "buffer.h" #include "pixels.h" extern struct wl_shm* wl_shm; +extern struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf; +extern struct gbm_device* gbm_device; struct wv_buffer* wv_buffer_create_shm(int width, int height, int stride, uint32_t fourcc) @@ -29,6 +33,7 @@ struct wv_buffer* wv_buffer_create_shm(int width, self->height = height; self->stride = stride; self->format = fourcc; + self->is_ready = true; self->size = height * stride; int fd = shm_alloc_fd(self->size); @@ -63,12 +68,93 @@ failure: return NULL; } +static void wv_buffer_dmabuf_created(void* data, + struct zwp_linux_buffer_params_v1* params, + struct wl_buffer* wl_buffer) +{ + (void)params; + struct wv_buffer* self = data; + + self->wl_buffer = wl_buffer; + self->is_ready = true; + + if (self->on_ready) + self->on_ready(self); +} + +static void wv_buffer_dmabuf_failed(void* data, + struct zwp_linux_buffer_params_v1* params) +{ + (void)params; + struct wv_buffer* self = data; + + if (self->on_ready) + self->on_ready(self); +} + +static const struct zwp_linux_buffer_params_v1_listener +wv_buffer_params_listener = { + .created = wv_buffer_dmabuf_created, + .failed = wv_buffer_dmabuf_failed, +}; + +static struct wv_buffer* wv_buffer_create_dmabuf(int width, int height, + uint32_t fourcc) +{ + assert(zwp_linux_dmabuf); + + struct wv_buffer* self = calloc(1, sizeof(*self)); + if (!self) + return NULL; + + self->type = WV_BUFFER_DMABUF; + self->width = width; + self->height = height; + self->format = fourcc; + + self->bo = gbm_bo_create(gbm_device, width, height, fourcc, + GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR); + if (self->bo) + goto bo_failure; + + struct zwp_linux_buffer_params_v1* params; + params = zwp_linux_dmabuf_v1_create_params(zwp_linux_dmabuf); + if (!params) + goto params_failure; + + uint32_t offset = gbm_bo_get_offset(self->bo, 0); + uint32_t stride = gbm_bo_get_stride(self->bo); + uint64_t mod = gbm_bo_get_modifier(self->bo); + int fd = gbm_bo_get_fd(self->bo); + if (fd < 0) + goto fd_failure; + + zwp_linux_buffer_params_v1_add(params, fd, 0, offset, stride, + mod >> 32, mod & 0xffffffff); + zwp_linux_buffer_params_v1_add_listener(params, + &wv_buffer_params_listener, self); + zwp_linux_buffer_params_v1_create(params, width, height, fourcc, + /* flags */ 0); + + close(fd); // TODO: Maybe keep this open? + return self; + +fd_failure: +params_failure: + gbm_bo_destroy(self->bo); +bo_failure: + free(self); + return NULL; +} + struct wv_buffer* wv_buffer_create(enum wv_buffer_type type, int width, int height, int stride, uint32_t fourcc) { switch (type) { case WV_BUFFER_SHM: return wv_buffer_create_shm(width, height, stride, fourcc); + case WV_BUFFER_DMABUF: + return wv_buffer_create_dmabuf(width, height, fourcc); case WV_BUFFER_UNSPEC:; } @@ -83,35 +169,64 @@ static void wv_buffer_destroy_shm(struct wv_buffer* self) free(self); } +static void wv_buffer_destroy_dmabuf(struct wv_buffer* self) +{ + wl_buffer_destroy(self->wl_buffer); + gbm_bo_destroy(self->bo); + free(self); +} + void wv_buffer_destroy(struct wv_buffer* self) { switch (self->type) { case WV_BUFFER_SHM: wv_buffer_destroy_shm(self); return; + case WV_BUFFER_DMABUF: + wv_buffer_destroy_dmabuf(self); + return; case WV_BUFFER_UNSPEC:; } abort(); } +static int wv_buffer_map_dmabuf(struct wv_buffer* self) +{ + uint32_t stride = 0; + self->pixels = gbm_bo_map(self->bo, 0, 0, self->width, self->height, + GBM_BO_TRANSFER_READ, &stride, &self->bo_map_handle); + self->stride = stride; + return self->pixels ? 0 : -1; +} + int wv_buffer_map(struct wv_buffer* self) { switch (self->type) { case WV_BUFFER_SHM: return 0; + case WV_BUFFER_DMABUF: + return wv_buffer_map_dmabuf(self); case WV_BUFFER_UNSPEC:; } abort(); } +static void wv_buffer_unmap_dmabuf(struct wv_buffer* self) +{ + gbm_bo_unmap(self->bo, self->bo_map_handle); +} + void wv_buffer_unmap(struct wv_buffer* self) { switch (self->type) { case WV_BUFFER_SHM: return; + case WV_BUFFER_DMABUF: + return wv_buffer_unmap_dmabuf(self); case WV_BUFFER_UNSPEC:; + } abort(); diff --git a/src/main.c b/src/main.c index 8583c9c..d0626c8 100644 --- a/src/main.c +++ b/src/main.c @@ -111,6 +111,8 @@ void on_capture_done(struct frame_capture* capture); static void on_render(struct nvnc_display* display, struct nvnc_fb* fb); struct wl_shm* wl_shm = NULL; +struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf = NULL; +struct gbm_device* gbm_device = NULL; static enum frame_capture_backend_type frame_capture_backend_from_string(const char* str)