buffer: Add DMA-BUFs

pixman-rendering
Andri Yngvason 2020-06-23 18:30:08 +00:00
parent f546173bf7
commit a43fdd4779
4 changed files with 131 additions and 0 deletions

View File

@ -7,21 +7,33 @@
#include <stdint.h> #include <stdint.h>
struct wl_buffer; struct wl_buffer;
struct gbm_bo;
enum wv_buffer_type { enum wv_buffer_type {
WV_BUFFER_UNSPEC = 0, WV_BUFFER_UNSPEC = 0,
WV_BUFFER_SHM, WV_BUFFER_SHM,
WV_BUFFER_DMABUF,
}; };
struct wv_buffer { struct wv_buffer {
enum wv_buffer_type type; enum wv_buffer_type type;
TAILQ_ENTRY(wv_buffer) link; TAILQ_ENTRY(wv_buffer) link;
struct wl_buffer* wl_buffer; struct wl_buffer* wl_buffer;
void* pixels; void* pixels;
size_t size; size_t size;
int width, height, stride; int width, height, stride;
uint32_t format; uint32_t format;
bool y_inverted; 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); TAILQ_HEAD(wv_buffer_queue, wv_buffer);

View File

@ -30,6 +30,7 @@ librt = cc.find_library('rt', required: false)
pixman = dependency('pixman-1') pixman = dependency('pixman-1')
egl = dependency('egl') egl = dependency('egl')
glesv2 = dependency('glesv2') glesv2 = dependency('glesv2')
gbm = dependency('gbm')
xkbcommon = dependency('xkbcommon') xkbcommon = dependency('xkbcommon')
wayland_client = dependency('wayland-client') wayland_client = dependency('wayland-client')
@ -85,6 +86,7 @@ dependencies = [
aml, aml,
egl, egl,
glesv2, glesv2,
gbm,
wayland_client, wayland_client,
neatvnc, neatvnc,
xkbcommon, xkbcommon,

View File

@ -6,13 +6,17 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <libdrm/drm_fourcc.h> #include <libdrm/drm_fourcc.h>
#include <wayland-client.h> #include <wayland-client.h>
#include <gbm.h>
#include "linux-dmabuf-unstable-v1.h"
#include "shm.h" #include "shm.h"
#include "sys/queue.h" #include "sys/queue.h"
#include "buffer.h" #include "buffer.h"
#include "pixels.h" #include "pixels.h"
extern struct wl_shm* wl_shm; 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, struct wv_buffer* wv_buffer_create_shm(int width,
int height, int stride, uint32_t fourcc) int height, int stride, uint32_t fourcc)
@ -29,6 +33,7 @@ struct wv_buffer* wv_buffer_create_shm(int width,
self->height = height; self->height = height;
self->stride = stride; self->stride = stride;
self->format = fourcc; self->format = fourcc;
self->is_ready = true;
self->size = height * stride; self->size = height * stride;
int fd = shm_alloc_fd(self->size); int fd = shm_alloc_fd(self->size);
@ -63,12 +68,93 @@ failure:
return NULL; 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, struct wv_buffer* wv_buffer_create(enum wv_buffer_type type, int width,
int height, int stride, uint32_t fourcc) int height, int stride, uint32_t fourcc)
{ {
switch (type) { switch (type) {
case WV_BUFFER_SHM: case WV_BUFFER_SHM:
return wv_buffer_create_shm(width, height, stride, fourcc); 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:; case WV_BUFFER_UNSPEC:;
} }
@ -83,35 +169,64 @@ static void wv_buffer_destroy_shm(struct wv_buffer* self)
free(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) void wv_buffer_destroy(struct wv_buffer* self)
{ {
switch (self->type) { switch (self->type) {
case WV_BUFFER_SHM: case WV_BUFFER_SHM:
wv_buffer_destroy_shm(self); wv_buffer_destroy_shm(self);
return; return;
case WV_BUFFER_DMABUF:
wv_buffer_destroy_dmabuf(self);
return;
case WV_BUFFER_UNSPEC:; case WV_BUFFER_UNSPEC:;
} }
abort(); 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) int wv_buffer_map(struct wv_buffer* self)
{ {
switch (self->type) { switch (self->type) {
case WV_BUFFER_SHM: case WV_BUFFER_SHM:
return 0; return 0;
case WV_BUFFER_DMABUF:
return wv_buffer_map_dmabuf(self);
case WV_BUFFER_UNSPEC:; case WV_BUFFER_UNSPEC:;
} }
abort(); 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) void wv_buffer_unmap(struct wv_buffer* self)
{ {
switch (self->type) { switch (self->type) {
case WV_BUFFER_SHM: case WV_BUFFER_SHM:
return; return;
case WV_BUFFER_DMABUF:
return wv_buffer_unmap_dmabuf(self);
case WV_BUFFER_UNSPEC:; case WV_BUFFER_UNSPEC:;
} }
abort(); abort();

View File

@ -111,6 +111,8 @@ void on_capture_done(struct frame_capture* capture);
static void on_render(struct nvnc_display* display, struct nvnc_fb* fb); static void on_render(struct nvnc_display* display, struct nvnc_fb* fb);
struct wl_shm* wl_shm = NULL; 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 static enum frame_capture_backend_type
frame_capture_backend_from_string(const char* str) frame_capture_backend_from_string(const char* str)