From 2344414102789975e6ce425a95e8b96159cf51ba Mon Sep 17 00:00:00 2001 From: Jeremy Attali Date: Thu, 5 Dec 2019 23:01:47 -0500 Subject: [PATCH] feat(draw): draw the screencopy buffer --- src/draw.c | 68 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/src/draw.c b/src/draw.c index 1f857ec..e345480 100644 --- a/src/draw.c +++ b/src/draw.c @@ -14,6 +14,19 @@ static cairo_format_t get_cairo_format(enum wl_shm_format wl_fmt) { } } +static int get_output_flipped(enum wl_output_transform transform) { + return transform & WL_OUTPUT_TRANSFORM_FLIPPED ? -1 : 1; +} + +static void apply_output_transform(enum wl_output_transform transform, + int32_t *width, int32_t *height) { + if (transform & WL_OUTPUT_TRANSFORM_90) { + int32_t tmp = *width; + *width = *height; + *height = tmp; + } +} + static void draw_buffer(cairo_t *cr, struct swappy_state *state) { // FIXME This is wrong, the geometry here is not quite valid // It must be based on output, but will work fine on single screen @@ -22,21 +35,54 @@ static void draw_buffer(cairo_t *cr, struct swappy_state *state) { wl_list_for_each(output, &state->outputs, link) { struct swappy_buffer *buffer = output->buffer; cairo_format_t format = get_cairo_format(buffer->format); - cairo_surface_t *image; g_assert(format != CAIRO_FORMAT_INVALID); - image = cairo_image_surface_create_for_data( - buffer->data, format, geometry->height, geometry->width, - buffer->stride); - cairo_save(cr); - cairo_surface_flush(image); - cairo_surface_mark_dirty(image); - cairo_set_source_surface(cr, image, 0, 0); - cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST); + int32_t output_x = output->logical_geometry.x - geometry->x; + int32_t output_y = output->logical_geometry.y - geometry->y; + int32_t output_width = output->logical_geometry.width; + int32_t output_height = output->logical_geometry.height; + int32_t scale = output->scale; + + int32_t raw_output_width = output->geometry.width; + int32_t raw_output_height = output->geometry.height; + apply_output_transform(output->transform, &raw_output_width, + &raw_output_height); + + int output_flipped_x = get_output_flipped(output->transform); + int output_flipped_y = + output->screencopy_frame_flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT + ? -1 + : 1; + + cairo_surface_t *output_surface = cairo_image_surface_create_for_data( + buffer->data, format, buffer->width, buffer->height, buffer->stride); + cairo_pattern_t *output_pattern = + cairo_pattern_create_for_surface(output_surface); + + // All transformations are in pattern-local coordinates + cairo_matrix_t matrix; + cairo_matrix_init_identity(&matrix); + cairo_matrix_translate(&matrix, (double)output->geometry.width / 2, + (double)output->geometry.height / 2); + // cairo_matrix_rotate(&matrix, -get_output_rotation(output->transform)); + cairo_matrix_scale( + &matrix, (double)raw_output_width / output_width * output_flipped_x, + (double)raw_output_height / output_height * output_flipped_y); + cairo_matrix_translate(&matrix, -(double)output_width / 2, + -(double)output_height / 2); + cairo_matrix_translate(&matrix, -output_x, -output_y); + cairo_matrix_scale(&matrix, 1 / scale, 1 / scale); + cairo_pattern_set_matrix(output_pattern, &matrix); + + cairo_pattern_set_filter(output_pattern, CAIRO_FILTER_BEST); + + cairo_set_source(cr, output_pattern); + cairo_pattern_destroy(output_pattern); + cairo_paint(cr); - cairo_surface_destroy(image); - cairo_restore(cr); + + cairo_surface_destroy(output_surface); } }