From 61ebb5769667038074e64c28e5e7accb80dcd38d Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Mon, 20 Sep 2021 00:28:49 +0000 Subject: [PATCH] Let neatvnc handle buffer transforms --- include/buffer.h | 8 +-- include/damage-refinery.h | 4 +- include/pixman-renderer.h | 27 -------- meson.build | 1 - src/buffer.c | 102 +++++++++++------------------- src/damage-refinery.c | 12 +++- src/main.c | 129 +++++++------------------------------- src/pixman-renderer.c | 75 ---------------------- src/screencopy.c | 2 - 9 files changed, 78 insertions(+), 282 deletions(-) delete mode 100644 include/pixman-renderer.h delete mode 100644 src/pixman-renderer.c diff --git a/include/buffer.h b/include/buffer.h index 3c8fa2b..7db900e 100644 --- a/include/buffer.h +++ b/include/buffer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Andri Yngvason + * Copyright (c) 2020 - 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 @@ -26,6 +26,7 @@ struct wl_buffer; struct gbm_bo; +struct nvnc_fb; enum wv_buffer_type { WV_BUFFER_UNSPEC = 0, @@ -39,6 +40,7 @@ struct wv_buffer { enum wv_buffer_type type; TAILQ_ENTRY(wv_buffer) link; + struct nvnc_fb* nvnc_fb; struct wl_buffer* wl_buffer; void* pixels; @@ -51,7 +53,6 @@ struct wv_buffer { /* The following is only applicable to DMABUF */ struct gbm_bo* bo; - void* bo_map_handle; }; TAILQ_HEAD(wv_buffer_queue, wv_buffer); @@ -69,9 +70,6 @@ struct wv_buffer* wv_buffer_create(enum wv_buffer_type, int width, int height, int stride, uint32_t fourcc); void wv_buffer_destroy(struct wv_buffer* self); -int wv_buffer_map(struct wv_buffer* self); -void wv_buffer_unmap(struct wv_buffer* self); - void wv_buffer_damage_rect(struct wv_buffer* self, int x, int y, int width, int height); void wv_buffer_damage_whole(struct wv_buffer* self); diff --git a/include/damage-refinery.h b/include/damage-refinery.h index a73e776..8fb3088 100644 --- a/include/damage-refinery.h +++ b/include/damage-refinery.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Andri Yngvason + * Copyright (c) 2020 - 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 @@ -29,6 +29,8 @@ struct damage_refinery { int damage_refinery_init(struct damage_refinery* self, uint32_t width, uint32_t height); +int damage_refinery_resize(struct damage_refinery* self, uint32_t width, + uint32_t height); void damage_refinery_destroy(struct damage_refinery* self); void damage_refine(struct damage_refinery* self, diff --git a/include/pixman-renderer.h b/include/pixman-renderer.h deleted file mode 100644 index abbc8ce..0000000 --- a/include/pixman-renderer.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2020 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#pragma once - -#include - -struct nvnc_fb; -struct wv_buffer; -struct pixman_region16; - -void wv_pixman_render(struct nvnc_fb* dst, const struct wv_buffer* src, - enum wl_output_transform transform, - struct pixman_region16* damage); diff --git a/meson.build b/meson.build index bb3aba5..27c2c35 100644 --- a/meson.build +++ b/meson.build @@ -87,7 +87,6 @@ sources = [ 'src/intset.c', 'src/buffer.c', 'src/pixels.c', - 'src/pixman-renderer.c', 'src/transform-util.c', 'src/damage-refinery.c', 'src/murmurhash.c', diff --git a/src/buffer.c b/src/buffer.c index 1fb3e5d..5c01629 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Andri Yngvason + * Copyright (c) 2020 - 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 @@ -23,6 +23,7 @@ #include #include #include +#include #include "linux-dmabuf-unstable-v1.h" #include "shm.h" @@ -90,14 +91,24 @@ struct wv_buffer* wv_buffer_create_shm(int width, if (!self->wl_buffer) goto shm_failure; + // TODO: Get the pixel size from the format instead of assuming it's 4. + self->nvnc_fb = nvnc_fb_from_buffer(self->pixels, width, height, fourcc, + stride / 4); + if (!self->nvnc_fb) { + goto nvnc_fb_failure; + } + + nvnc_set_userdata(self->nvnc_fb, self, NULL); + pixman_region_init(&self->damage); close(fd); return self; +nvnc_fb_failure: + wl_buffer_destroy(self->wl_buffer); shm_failure: pool_failure: - munmap(self->pixels, self->size); mmap_failure: close(fd); failure: @@ -148,8 +159,17 @@ static struct wv_buffer* wv_buffer_create_dmabuf(int width, int height, if (!self->wl_buffer) goto buffer_failure; + self->nvnc_fb = nvnc_fb_from_gbm_bo(self->bo); + if (!self->nvnc_fb) { + goto nvnc_fb_failure; + } + + nvnc_set_userdata(self->nvnc_fb, self, NULL); + return self; +nvnc_fb_failure: + wl_buffer_destroy(self->wl_buffer); buffer_failure: fd_failure: zwp_linux_buffer_params_v1_destroy(params); @@ -180,6 +200,7 @@ struct wv_buffer* wv_buffer_create(enum wv_buffer_type type, int width, static void wv_buffer_destroy_shm(struct wv_buffer* self) { + nvnc_fb_unref(self->nvnc_fb); wl_buffer_destroy(self->wl_buffer); munmap(self->pixels, self->size); free(self); @@ -188,6 +209,7 @@ static void wv_buffer_destroy_shm(struct wv_buffer* self) #ifdef ENABLE_SCREENCOPY_DMABUF static void wv_buffer_destroy_dmabuf(struct wv_buffer* self) { + nvnc_fb_unref(self->nvnc_fb); wl_buffer_destroy(self->wl_buffer); gbm_bo_destroy(self->bo); free(self); @@ -197,7 +219,6 @@ static void wv_buffer_destroy_dmabuf(struct wv_buffer* self) void wv_buffer_destroy(struct wv_buffer* self) { pixman_region_fini(&self->damage); - wv_buffer_unmap(self); switch (self->type) { case WV_BUFFER_SHM: @@ -214,64 +235,6 @@ void wv_buffer_destroy(struct wv_buffer* self) abort(); } -#ifdef ENABLE_SCREENCOPY_DMABUF -static int wv_buffer_map_dmabuf(struct wv_buffer* self) -{ - if (self->bo_map_handle) - return 0; - - 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; - if (self->pixels) - return 0; - - self->bo_map_handle = NULL; - return -1; -} -#endif - -int wv_buffer_map(struct wv_buffer* self) -{ - switch (self->type) { - case WV_BUFFER_SHM: - return 0; -#ifdef ENABLE_SCREENCOPY_DMABUF - case WV_BUFFER_DMABUF: - return wv_buffer_map_dmabuf(self); -#endif - case WV_BUFFER_UNSPEC:; - } - - abort(); -} - -#ifdef ENABLE_SCREENCOPY_DMABUF -static void wv_buffer_unmap_dmabuf(struct wv_buffer* self) -{ - if (self->bo_map_handle) - gbm_bo_unmap(self->bo, self->bo_map_handle); - self->bo_map_handle = NULL; -} -#endif - -void wv_buffer_unmap(struct wv_buffer* self) -{ - switch (self->type) { - case WV_BUFFER_SHM: - return; -#ifdef ENABLE_SCREENCOPY_DMABUF - case WV_BUFFER_DMABUF: - return wv_buffer_unmap_dmabuf(self); -#endif - case WV_BUFFER_UNSPEC:; - - } - - abort(); -} - void wv_buffer_damage_rect(struct wv_buffer* self, int x, int y, int width, int height) { @@ -365,9 +328,16 @@ static bool wv_buffer_pool_match_buffer(struct wv_buffer_pool* pool, return false; } +void wv_buffer_pool__on_release(struct nvnc_fb* fb, void* context) +{ + struct wv_buffer* buffer = nvnc_get_userdata(fb); + struct wv_buffer_pool* pool = context; + + wv_buffer_pool_release(pool, buffer); +} + struct wv_buffer* wv_buffer_pool_acquire(struct wv_buffer_pool* pool) { - struct wv_buffer* buffer = TAILQ_FIRST(&pool->queue); if (buffer) { assert(wv_buffer_pool_match_buffer(pool, buffer)); @@ -375,15 +345,19 @@ struct wv_buffer* wv_buffer_pool_acquire(struct wv_buffer_pool* pool) return buffer; } - return wv_buffer_create(pool->type, pool->width, pool->height, + buffer = wv_buffer_create(pool->type, pool->width, pool->height, pool->stride, pool->format); + if (buffer) + nvnc_fb_set_release_fn(buffer->nvnc_fb, + wv_buffer_pool__on_release, pool); + + return buffer; } void wv_buffer_pool_release(struct wv_buffer_pool* pool, struct wv_buffer* buffer) { wv_buffer_damage_clear(buffer); - wv_buffer_unmap(buffer); if (wv_buffer_pool_match_buffer(pool, buffer)) { TAILQ_INSERT_TAIL(&pool->queue, buffer, link); diff --git a/src/damage-refinery.c b/src/damage-refinery.c index 1722851..3de7d34 100644 --- a/src/damage-refinery.c +++ b/src/damage-refinery.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Andri Yngvason + * Copyright (c) 2020 - 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 @@ -44,6 +44,16 @@ int damage_refinery_init(struct damage_refinery* self, uint32_t width, return 0; } +int damage_refinery_resize(struct damage_refinery* self, uint32_t width, + uint32_t height) +{ + if (width == self->width && height == self->height) + return 0; + + damage_refinery_destroy(self); + return damage_refinery_init(self, width, height); +} + void damage_refinery_destroy(struct damage_refinery* self) { free(self->hashes); diff --git a/src/main.c b/src/main.c index c844b8d..56ca3df 100644 --- a/src/main.c +++ b/src/main.c @@ -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 @@ -49,7 +49,6 @@ #include "keyboard.h" #include "seat.h" #include "cfg.h" -#include "pixman-renderer.h" #include "transform-util.h" #include "damage-refinery.h" #include "usdt.h" @@ -68,13 +67,6 @@ #define MAYBE_UNUSED __attribute__((unused)) -struct fb_side_data { - struct pixman_region16 damage; - LIST_ENTRY(fb_side_data) link; -}; - -LIST_HEAD(fb_side_data_list, fb_side_data); - struct wayvnc { bool do_exit; @@ -103,8 +95,6 @@ struct wayvnc { struct nvnc* nvnc; struct nvnc_display* nvnc_display; - struct nvnc_fb_pool* fb_pool; - struct fb_side_data_list fb_side_data_list; struct damage_refinery damage_refinery; @@ -559,37 +549,6 @@ int wayvnc_start_capture_immediate(struct wayvnc* self) return rc; } -static void fb_side_data_destroy(void* userdata) -{ - struct fb_side_data* fb_side_data = userdata; - LIST_REMOVE(fb_side_data, link); - pixman_region_fini(&fb_side_data->damage); - free(fb_side_data); -} - -static void wv_damage_all_buffers(struct wayvnc* self, - struct pixman_region16* region) -{ - struct fb_side_data *item; - LIST_FOREACH(item, &self->fb_side_data_list, link) - pixman_region_union(&item->damage, &item->damage, region); -} - -void wayvnc_render_to_fb(struct wayvnc* self, struct nvnc_fb* fb) -{ - DTRACE_PROBE(wayvnc, render_start); - - struct fb_side_data* fb_side_data = nvnc_get_userdata(fb); - assert(fb_side_data); - - enum wl_output_transform transform = self->selected_output->transform; - wv_pixman_render(fb, self->screencopy.back, transform, - &fb_side_data->damage); - pixman_region_clear(&fb_side_data->damage); - - DTRACE_PROBE(wayvnc, render_end); -} - // TODO: Handle transform change too void on_output_dimension_change(struct output* output) { @@ -621,73 +580,40 @@ static uint32_t calculate_region_area(struct pixman_region16* region) void wayvnc_process_frame(struct wayvnc* self) { - uint32_t width = output_get_transformed_width(self->selected_output); - uint32_t height = output_get_transformed_height(self->selected_output); - uint32_t format = self->screencopy.back->format; - - if ((int)self->selected_output->width != self->screencopy.back->width - || (int)self->selected_output->height != self->screencopy.back->height) { - log_debug("Frame dimensions don't match output. Recapturing frame...\n"); - wayvnc_start_capture_immediate(self); - return; - } - - bool dimensions_changed = - nvnc_fb_pool_resize(self->fb_pool, width, height, format, - width); - if (dimensions_changed) { - damage_refinery_destroy(&self->damage_refinery); - damage_refinery_init(&self->damage_refinery, - self->screencopy.back->width, - self->screencopy.back->height); - } - - struct nvnc_fb *fb = nvnc_fb_pool_acquire(self->fb_pool); - if (!fb) { - log_error("Failed to acquire a vnc buffer\n"); - return; - } - - struct fb_side_data* fb_side_data = nvnc_get_userdata(fb); - if (!fb_side_data) { - fb_side_data = calloc(1, sizeof(*fb_side_data)); - assert(fb_side_data); - - /* This is a new buffer, so the whole surface is damaged. */ - pixman_region_init_rect(&fb_side_data->damage, 0, 0, width, - height); - - nvnc_set_userdata(fb, fb_side_data, fb_side_data_destroy); - LIST_INSERT_HEAD(&self->fb_side_data_list, fb_side_data, link); - } + struct wv_buffer* buffer = self->screencopy.back; + self->screencopy.back = NULL; self->n_frames_captured++; self->damage_area_sum += - calculate_region_area(&self->screencopy.back->damage); + calculate_region_area(&buffer->damage); + + uint32_t width = buffer->width; + uint32_t height = buffer->height; + + damage_refinery_resize(&self->damage_refinery, width, height); DTRACE_PROBE(wayvnc, refine_damage_start); - - struct pixman_region16 txdamage, refined; - pixman_region_init(&txdamage); + struct pixman_region16 refined; pixman_region_init(&refined); - damage_refine(&self->damage_refinery, &refined, - &self->screencopy.back->damage, - self->screencopy.back); + damage_refine(&self->damage_refinery, &refined, &buffer->damage, + buffer); + DTRACE_PROBE(wayvnc, refine_damage_end); + + struct pixman_region16 txdamage; + pixman_region_init(&txdamage); wv_region_transform(&txdamage, &refined, self->selected_output->transform, self->selected_output->width, self->selected_output->height); - - wv_damage_all_buffers(self, &txdamage); - wayvnc_render_to_fb(self, fb); - nvnc_display_set_buffer(self->nvnc_display, fb); - nvnc_fb_unref(fb); - nvnc_display_damage_region(self->nvnc_display, &txdamage); - pixman_region_fini(&refined); - pixman_region_fini(&txdamage); - DTRACE_PROBE(wayvnc, refine_damage_end); + nvnc_fb_set_transform(buffer->nvnc_fb, + (enum nvnc_transform)self->selected_output->transform); + + nvnc_display_feed_buffer(self->nvnc_display, buffer->nvnc_fb, + &txdamage); + + pixman_region_fini(&txdamage); wayvnc_start_capture(self); } @@ -1011,12 +937,6 @@ int main(int argc, char* argv[]) if (init_nvnc(&self, address, port, use_unix_socket) < 0) goto nvnc_failure; - self.fb_pool = nvnc_fb_pool_new(0, 0, 0, 0); - if (!self.fb_pool) - goto buffer_pool_failure; - - LIST_INIT(&self.fb_side_data_list); - if (self.screencopy.manager) screencopy_init(&self.screencopy); @@ -1049,7 +969,6 @@ int main(int argc, char* argv[]) damage_refinery_destroy(&self.damage_refinery); - nvnc_fb_pool_unref(self.fb_pool); nvnc_display_unref(self.nvnc_display); nvnc_close(self.nvnc); if (zwp_linux_dmabuf) @@ -1070,8 +989,6 @@ int main(int argc, char* argv[]) return 0; capture_failure: - nvnc_fb_pool_unref(self.fb_pool); -buffer_pool_failure: nvnc_display_unref(self.nvnc_display); nvnc_close(self.nvnc); nvnc_failure: diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c deleted file mode 100644 index a526347..0000000 --- a/src/pixman-renderer.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2020 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#include "buffer.h" -#include "pixels.h" -#include "transform-util.h" - -void wv_pixman_render(struct nvnc_fb* dst, const struct wv_buffer* src, - enum wl_output_transform transform, - struct pixman_region16* damage) -{ - uint32_t* dst_pixels = nvnc_fb_get_addr(dst); - uint32_t dst_width = nvnc_fb_get_width(dst); - uint32_t dst_height = nvnc_fb_get_height(dst); - bool ok __attribute__((unused)); - - // TODO: Check that both buffers have the same dimensions after applying - // transform - - pixman_format_code_t dst_fmt = 0; - ok = fourcc_to_pixman_fmt(&dst_fmt, nvnc_fb_get_fourcc_format(dst)); - assert(ok); - - pixman_image_t* dstimg = pixman_image_create_bits_no_clear( - dst_fmt, dst_width, dst_height, dst_pixels, - 4 * dst_width); - - intptr_t src_offset = src->y_inverted ? - src->stride * (src->height - 1) : 0; - void* src_pixels = (void*)((intptr_t)src->pixels + src_offset); - int src_stride = src->y_inverted ? -src->stride : src->stride; - - pixman_format_code_t src_fmt = 0; - ok = fourcc_to_pixman_fmt(&src_fmt, src->format); - assert(ok); - - pixman_image_t* srcimg = pixman_image_create_bits_no_clear( - src_fmt, src->width, src->height, src_pixels, - src_stride); - - pixman_transform_t pxform; - wv_pixman_transform_from_wl_output_transform(&pxform, transform, - src->width, src->height); - - pixman_image_set_transform(srcimg, &pxform); - pixman_image_set_clip_region(dstimg, damage); - - pixman_image_composite(PIXMAN_OP_OVER, srcimg, NULL, dstimg, - 0, 0, - 0, 0, - 0, 0, - dst_width, dst_height); - - pixman_image_unref(srcimg); - pixman_image_unref(dstimg); -} diff --git a/src/screencopy.c b/src/screencopy.c index 24d106d..481b214 100644 --- a/src/screencopy.c +++ b/src/screencopy.c @@ -176,8 +176,6 @@ static void screencopy_ready(void* data, self->back = self->front; self->front = NULL; - wv_buffer_map(self->back); - self->status = SCREENCOPY_DONE; self->on_done(self); }