diff --git a/include/fb.h b/include/fb.h index 8a8336f..bba8fef 100644 --- a/include/fb.h +++ b/include/fb.h @@ -24,20 +24,30 @@ #include "neatvnc.h" #include "common.h" +struct gbm_bo; + struct nvnc_fb { struct nvnc_common common; + enum nvnc_fb_type type; int ref; int hold_count; nvnc_fb_release_fn on_release; void* release_context; - void* addr; + bool is_external; uint16_t width; uint16_t height; - int32_t stride; uint32_t fourcc_format; - uint64_t fourcc_modifier; - bool is_external; + + /* main memory buffer attributes */ + void* addr; + int32_t stride; + + /* dmabuf attributes */ + struct gbm_bo* bo; + void* bo_map_handle; }; void nvnc_fb_hold(struct nvnc_fb* fb); void nvnc_fb_release(struct nvnc_fb* fb); +int nvnc_fb_map(struct nvnc_fb* fb); +void nvnc_fb_unmap(struct nvnc_fb* fb); diff --git a/include/neatvnc.h b/include/neatvnc.h index bccdc42..2d9b7c5 100644 --- a/include/neatvnc.h +++ b/include/neatvnc.h @@ -25,6 +25,7 @@ struct nvnc_display; struct nvnc_fb; struct nvnc_fb_pool; struct pixman_region16; +struct gbm_bo; enum nvnc_button_mask { NVNC_BUTTON_LEFT = 1 << 0, @@ -34,6 +35,12 @@ enum nvnc_button_mask { NVNC_SCROLL_DOWN = 1 << 4, }; +enum nvnc_fb_type { + NVNC_FB_UNSPEC = 0, + NVNC_FB_SIMPLE, + NVNC_FB_GBM_BO, +}; + typedef void (*nvnc_key_fn)(struct nvnc_client*, uint32_t key, bool is_pressed); typedef void (*nvnc_pointer_fn)(struct nvnc_client*, uint16_t x, uint16_t y, @@ -80,7 +87,9 @@ int nvnc_enable_auth(struct nvnc* self, const char* privkey_path, struct nvnc_fb* nvnc_fb_new(uint16_t width, uint16_t height, uint32_t fourcc_format, uint16_t stride); struct nvnc_fb* nvnc_fb_from_buffer(void* buffer, uint16_t width, - uint16_t height, uint32_t fourcc_format, int32_t stride); + uint16_t height, uint32_t fourcc_format, + int32_t stride); +struct nvnc_fb* nvnc_fb_from_gbm_bo(struct gbm_bo* bo); void nvnc_fb_ref(struct nvnc_fb* fb); void nvnc_fb_unref(struct nvnc_fb* fb); @@ -94,6 +103,7 @@ uint16_t nvnc_fb_get_height(const struct nvnc_fb* fb); uint32_t nvnc_fb_get_fourcc_format(const struct nvnc_fb* fb); int32_t nvnc_fb_get_stride(const struct nvnc_fb* fb); int nvnc_fb_get_pixel_size(const struct nvnc_fb* fb); +struct gbm_bo* nvnc_fb_get_gbm_bo(const struct nvnc_fb* fb); struct nvnc_fb_pool* nvnc_fb_pool_new(uint16_t width, uint16_t height, uint32_t fourcc_format, uint16_t stride); diff --git a/include/raw-encoding.h b/include/raw-encoding.h index 3606a5f..44610ae 100644 --- a/include/raw-encoding.h +++ b/include/raw-encoding.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 - 2020 Andri Yngvason + * Copyright (c) 2019 - 2021 Andri Yngvason * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -22,6 +22,6 @@ struct pixman_region16; struct vec; int raw_encode_frame(struct vec* dst, const struct rfb_pixel_format* dst_fmt, - const struct nvnc_fb* src, + struct nvnc_fb* src, const struct rfb_pixel_format* src_fmt, struct pixman_region16* region); diff --git a/include/tight.h b/include/tight.h index 7c11387..31a0ed4 100644 --- a/include/tight.h +++ b/include/tight.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 - 2020 Andri Yngvason + * Copyright (c) 2019 - 2021 Andri Yngvason * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/include/zrle.h b/include/zrle.h index 46ea906..d15ca33 100644 --- a/include/zrle.h +++ b/include/zrle.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Andri Yngvason + * Copyright (c) 2019 - 2021 Andri Yngvason * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -27,6 +27,6 @@ struct vec; int zrle_encode_frame(z_stream* zs, struct vec* dst, const struct rfb_pixel_format* dst_fmt, - const struct nvnc_fb* src, + struct nvnc_fb* src, const struct rfb_pixel_format* src_fmt, struct pixman_region16* region); diff --git a/meson.build b/meson.build index 2f6fd27..7dd8d9a 100644 --- a/meson.build +++ b/meson.build @@ -48,6 +48,7 @@ pixman = dependency('pixman-1') libturbojpeg = dependency('libturbojpeg', required: get_option('jpeg')) gnutls = dependency('gnutls', required: get_option('tls')) zlib = dependency('zlib') +gbm = dependency('gbm', required: get_option('gbm')) aml_project = subproject('aml', required: false) if aml_project.found() @@ -97,6 +98,11 @@ if host_system == 'linux' and get_option('systemtap') and cc.has_header('sys/sdt config.set('HAVE_USDT', true) endif +if gbm.found() + dependencies += gbm + config.set('HAVE_GBM', true) +endif + configure_file( output: 'config.h', configuration: config, diff --git a/meson_options.txt b/meson_options.txt index 4dfd836..f47eb2b 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -3,3 +3,4 @@ option('examples', type: 'boolean', value: false, description: 'Build examples') option('jpeg', type: 'feature', value: 'auto', description: 'Enable JPEG compression') option('tls', type: 'feature', value: 'auto', description: 'Enable encryption & authentication') option('systemtap', type: 'boolean', value: false, description: 'Enable tracing using sdt') +option('gbm', type: 'feature', value: 'auto', description: 'Enable GBM integration') diff --git a/src/fb.c b/src/fb.c index fee7d43..df1a3cc 100644 --- a/src/fb.c +++ b/src/fb.c @@ -17,12 +17,19 @@ #include "fb.h" #include "pixels.h" #include "neatvnc.h" +#include "logging.h" #include #include #include #include +#include "config.h" + +#ifdef HAVE_GBM +#include +#endif + #define UDIV_UP(a, b) (((a) + (b) - 1) / (b)) #define ALIGN_UP(n, a) (UDIV_UP(n, a) * a) #define EXPORT __attribute__((visibility("default"))) @@ -35,6 +42,7 @@ struct nvnc_fb* nvnc_fb_new(uint16_t width, uint16_t height, if (!fb) return NULL; + fb->type = NVNC_FB_SIMPLE; fb->ref = 1; fb->width = width; fb->height = height; @@ -62,6 +70,7 @@ struct nvnc_fb* nvnc_fb_from_buffer(void* buffer, uint16_t width, uint16_t heigh if (!fb) return NULL; + fb->type = NVNC_FB_SIMPLE; fb->ref = 1; fb->addr = buffer; fb->is_external = true; @@ -73,6 +82,29 @@ struct nvnc_fb* nvnc_fb_from_buffer(void* buffer, uint16_t width, uint16_t heigh return fb; } +EXPORT +struct nvnc_fb* nvnc_fb_from_gbm_bo(struct gbm_bo* bo) +{ +#ifdef HAVE_GBM + struct nvnc_fb* fb = calloc(1, sizeof(*fb)); + if (!fb) + return NULL; + + fb->type = NVNC_FB_GBM_BO; + fb->ref = 1; + fb->is_external = true; + fb->width = gbm_bo_get_width(bo); + fb->height = gbm_bo_get_height(bo); + fb->fourcc_format = gbm_bo_get_format(bo); + fb->bo = bo; + + return fb; +#else + log_error("nvnc_fb_from_gbm_bo was not enabled during build time\n"); + return NULL; +#endif +} + EXPORT void* nvnc_fb_get_addr(const struct nvnc_fb* fb) { @@ -109,14 +141,31 @@ int nvnc_fb_get_pixel_size(const struct nvnc_fb* fb) return pixel_size_from_fourcc(fb->fourcc_format); } +EXPORT +struct gbm_bo* nvnc_fb_get_gbm_bo(const struct nvnc_fb* fb) +{ + return fb->bo; +} + static void nvnc__fb_free(struct nvnc_fb* fb) { nvnc_cleanup_fn cleanup = fb->common.cleanup_fn; if (cleanup) cleanup(fb->common.userdata); + nvnc_fb_unmap(fb); + if (!fb->is_external) - free(fb->addr); + switch (fb->type) { + case NVNC_FB_UNSPEC: + abort(); + case NVNC_FB_SIMPLE: + free(fb->addr); + break; + case NVNC_FB_GBM_BO: + gbm_bo_destroy(fb->bo); + break; + } free(fb); } @@ -151,3 +200,38 @@ void nvnc_fb_release(struct nvnc_fb* fb) if (--fb->hold_count == 0 && fb->on_release) fb->on_release(fb, fb->release_context); } + +int nvnc_fb_map(struct nvnc_fb* fb) +{ +#ifdef HAVE_GBM + if (fb->type != NVNC_FB_GBM_BO || fb->bo_map_handle) + return 0; + + uint32_t stride = 0; + fb->addr = gbm_bo_map(fb->bo, 0, 0, fb->width, fb->height, + GBM_BO_TRANSFER_READ, &stride, &fb->bo_map_handle); + fb->stride = stride; + if (fb->addr) + return 0; + + fb->bo_map_handle = NULL; + return -1; +#else + return 0; +#endif +} + +void nvnc_fb_unmap(struct nvnc_fb* fb) +{ +#ifdef HAVE_GBM + if (fb->type != NVNC_FB_GBM_BO) + return; + + if (fb->bo_map_handle) + gbm_bo_unmap(fb->bo, fb->bo_map_handle); + + fb->bo_map_handle = NULL; + fb->addr = NULL; + fb->stride = 0; +#endif +} diff --git a/src/raw-encoding.c b/src/raw-encoding.c index 2fa3fcd..967ad8a 100644 --- a/src/raw-encoding.c +++ b/src/raw-encoding.c @@ -58,7 +58,7 @@ static int raw_encode_box(struct vec* dst, } int raw_encode_frame(struct vec* dst, const struct rfb_pixel_format* dst_fmt, - const struct nvnc_fb* src, + struct nvnc_fb* src, const struct rfb_pixel_format* src_fmt, struct pixman_region16* region) { @@ -71,6 +71,10 @@ int raw_encode_frame(struct vec* dst, const struct rfb_pixel_format* dst_fmt, n_rects = 1; } + rc = nvnc_fb_map(src); + if (rc < 0) + return -1; + rc = vec_reserve(dst, src->width * src->height * 4); if (rc < 0) return -1; diff --git a/src/tight.c b/src/tight.c index 7288963..962bf4e 100644 --- a/src/tight.c +++ b/src/tight.c @@ -23,6 +23,7 @@ #include "tight.h" #include "config.h" #include "enc-util.h" +#include "fb.h" #include #include @@ -494,9 +495,13 @@ int tight_encode_frame(struct tight_encoder* self, self->on_frame_done = on_done; self->userdata = userdata; + int rc = nvnc_fb_map(self->fb); + if (rc < 0) + return -1; + uint32_t width = nvnc_fb_get_width(src); uint32_t height = nvnc_fb_get_height(src); - int rc = vec_init(&self->dst, width * height * 4); + rc = vec_init(&self->dst, width * height * 4); if (rc < 0) return -1; diff --git a/src/zrle.c b/src/zrle.c index 0275821..720dc78 100644 --- a/src/zrle.c +++ b/src/zrle.c @@ -263,7 +263,7 @@ failure: int zrle_encode_frame(z_stream* zs, struct vec* dst, const struct rfb_pixel_format* dst_fmt, - const struct nvnc_fb* src, + struct nvnc_fb* src, const struct rfb_pixel_format* src_fmt, struct pixman_region16* region) { @@ -276,6 +276,10 @@ int zrle_encode_frame(z_stream* zs, struct vec* dst, n_rects = 1; } + rc = nvnc_fb_map(src); + if (rc < 0) + return -1; + rc = encode_rect_count(dst, n_rects); if (rc < 0) return -1;