Let neatvnc handle buffer transforms

move-buffer-transforms-to-neatvnc
Andri Yngvason 2021-09-20 00:28:49 +00:00
parent 87c040c919
commit 61ebb57696
9 changed files with 78 additions and 282 deletions

View File

@ -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);

View File

@ -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,

View File

@ -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 <wayland-client.h>
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);

View File

@ -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',

View File

@ -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 <libdrm/drm_fourcc.h>
#include <wayland-client.h>
#include <pixman.h>
#include <neatvnc.h>
#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);

View File

@ -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);

View File

@ -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:

View File

@ -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 <stdlib.h>
#include <pixman.h>
#include <wayland-client.h>
#include <neatvnc.h>
#include <assert.h>
#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);
}

View File

@ -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);
}