From 49a2d578d97df07ab3a425db7372d69a6963529f Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Sun, 21 Jun 2020 11:54:46 +0000 Subject: [PATCH] Create pixman renderer --- include/pixman-renderer.h | 11 +++ meson.build | 2 + src/main.c | 42 +--------- src/pixman-renderer.c | 162 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 38 deletions(-) create mode 100644 include/pixman-renderer.h create mode 100644 src/pixman-renderer.c diff --git a/include/pixman-renderer.h b/include/pixman-renderer.h new file mode 100644 index 0000000..6548de4 --- /dev/null +++ b/include/pixman-renderer.h @@ -0,0 +1,11 @@ +#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 0a8711e..056e8fb 100644 --- a/meson.build +++ b/meson.build @@ -71,6 +71,8 @@ sources = [ 'src/intset.c', 'src/damage.c', 'src/buffer.c', + 'src/pixels.c', + 'src/pixman-renderer.c', ] dependencies = [ diff --git a/src/main.c b/src/main.c index 88382ad..1b39ecd 100644 --- a/src/main.c +++ b/src/main.c @@ -52,6 +52,7 @@ #include "seat.h" #include "cfg.h" #include "damage.h" +#include "pixman-renderer.h" #define DEFAULT_ADDRESS "127.0.0.1" #define DEFAULT_PORT 5900 @@ -483,45 +484,10 @@ static void on_render(struct nvnc_display* display, struct nvnc_fb* fb) if (!self->screencopy_backend.back) return; - uint32_t* addr = nvnc_fb_get_addr(fb); - uint32_t width = nvnc_fb_get_width(fb); - uint32_t height = nvnc_fb_get_height(fb); - - pixman_image_t* dstimg = pixman_image_create_bits_no_clear( - PIXMAN_x8b8g8r8, width, height, addr, 4 * width); - - pixman_image_t* srcimg = self->screencopy_backend.back->image; - -#define F1 pixman_fixed_1 - pixman_transform_t y_invert = {{ - { F1, 0, 0 }, - { 0, -F1, height * F1 }, - { 0, 0, F1}, - }}; -#undef F1 - - pixman_transform_t identity; - pixman_transform_init_identity(&identity); - - if (self->screencopy_backend.back->y_inverted) - pixman_image_set_transform(srcimg, &y_invert); - else - pixman_image_set_transform(srcimg, &identity); - - pixman_image_set_clip_region(srcimg, &self->current_damage); - - pixman_image_composite(PIXMAN_OP_OVER, srcimg, NULL, dstimg, - 0, 0, - 0, 0, - 0, 0, - width, height); - - - pixman_image_unref(dstimg); + enum wl_output_transform transform = self->selected_output->transform; + wv_pixman_render(fb, self->screencopy_backend.back, transform, + &self->current_damage); pixman_region_clear(&self->current_damage); - - // XXX: This releases the buffer for now - frame_capture_render(self->capture_backend, &self->renderer, fb); } static void wayvnc_damage_region(struct wayvnc* self, diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c new file mode 100644 index 0000000..5349eca --- /dev/null +++ b/src/pixman-renderer.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include + +#include "buffer.h" +#include "pixels.h" + +void pixman_transform_from_wl_output_transform(pixman_transform_t* dst, + enum wl_output_transform src, int width, int height) +{ +#define F1 pixman_fixed_1 + switch (src) { + case WL_OUTPUT_TRANSFORM_NORMAL: + { + pixman_transform_t t = {{ + { F1, 0, 0 }, + { 0, F1, 0 }, + { 0, 0, F1 }, + }}; + *dst = t; + } + return; + case WL_OUTPUT_TRANSFORM_90: + { + pixman_transform_t t = {{ + { 0, F1, 0 }, + { -F1, 0, height * F1 }, + { 0, 0, F1 }, + }}; + *dst = t; + } + return; + case WL_OUTPUT_TRANSFORM_180: + { + pixman_transform_t t = {{ + { -F1, 0, width * F1 }, + { 0, -F1, height * F1 }, + { 0, 0, F1 }, + }}; + *dst = t; + } + return; + case WL_OUTPUT_TRANSFORM_270: + { + pixman_transform_t t = {{ + { 0, -F1, width * F1 }, + { F1, 0, 0 }, + { 0, 0, F1 }, + }}; + *dst = t; + } + return; + case WL_OUTPUT_TRANSFORM_FLIPPED: + { + pixman_transform_t t = {{ + { -F1, 0, width * F1 }, + { 0, F1, 0 }, + { 0, 0, F1 }, + }}; + *dst = t; + } + return; + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + { + pixman_transform_t t = {{ + { 0, F1, 0 }, + { F1, 0, 0 }, + { 0, 0, F1 }, + }}; + *dst = t; + } + return; + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + { + pixman_transform_t t = {{ + { F1, 0, 0 }, + { 0, -F1, height * F1 }, + { 0, 0, F1 }, + }}; + *dst = t; + } + return; + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + { + pixman_transform_t t = {{ + { 0, -F1, width * F1 }, + { -F1, 0, height * F1 }, + { 0, 0, F1 }, + }}; + *dst = t; + } + return; + } +#undef F1 + + abort(); +} + +/* Borrowed these from wlroots */ +enum wl_output_transform wv_output_transform_invert( + enum wl_output_transform tr) { + if ((tr & WL_OUTPUT_TRANSFORM_90) && !(tr & WL_OUTPUT_TRANSFORM_FLIPPED)) { + tr ^= WL_OUTPUT_TRANSFORM_180; + } + return tr; +} + +enum wl_output_transform wv_output_transform_compose( + enum wl_output_transform tr_a, enum wl_output_transform tr_b) { + uint32_t flipped = (tr_a ^ tr_b) & WL_OUTPUT_TRANSFORM_FLIPPED; + uint32_t rotation_mask = WL_OUTPUT_TRANSFORM_90 | WL_OUTPUT_TRANSFORM_180; + uint32_t rotated; + if (tr_b & WL_OUTPUT_TRANSFORM_FLIPPED) { + // When a rotation of k degrees is followed by a flip, the + // equivalent transform is a flip followed by a rotation of + // -k degrees. + rotated = (tr_b - tr_a) & rotation_mask; + } else { + rotated = (tr_a + tr_b) & rotation_mask; + } + return flipped | rotated; +} + +void wv_pixman_render(struct nvnc_fb* dst, const struct wv_buffer* src, + enum wl_output_transform transform, + struct pixman_region16* damage) { + uint32_t* addr = nvnc_fb_get_addr(dst); + uint32_t width = nvnc_fb_get_width(dst); + uint32_t height = nvnc_fb_get_height(dst); + + // TODO: Check that both buffers have the same dimensions + + pixman_image_t* dstimg = pixman_image_create_bits_no_clear( + PIXMAN_x8b8g8r8, width, height, addr, 4 * width); + + pixman_format_code_t src_fmt = 0; + fourcc_to_pixman_fmt(&src_fmt, src->format); + + pixman_image_t* srcimg = pixman_image_create_bits_no_clear( + src_fmt, width, height, src->pixels, src->stride); + + if (src->y_inverted) + transform = wv_output_transform_compose( + WL_OUTPUT_TRANSFORM_FLIPPED_180, transform); + + pixman_transform_t pxform; + pixman_transform_from_wl_output_transform(&pxform, transform, width, + 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, + width, height); + + pixman_image_unref(srcimg); + pixman_image_unref(dstimg); +}