diff --git a/src/compositor.c b/src/compositor.c index 6e5879e0..a35649da 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -2889,10 +2889,11 @@ weston_version(int *major, int *minor, int *micro) } static const struct { - uint32_t bit; + uint32_t bit; /* enum weston_capability */ const char *desc; } capability_strings[] = { { WESTON_CAP_ROTATION_ANY, "arbitrary surface rotation:" }, + { WESTON_CAP_CAPTURE_YFLIP, "screen capture uses y-flip:" }, }; static void diff --git a/src/compositor.h b/src/compositor.h index ea3ff654..06476ccf 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -488,6 +488,9 @@ struct weston_renderer { enum weston_capability { /* backend/renderer supports arbitrary rotation */ WESTON_CAP_ROTATION_ANY = 0x0001, + + /* screencaptures need to be y-flipped */ + WESTON_CAP_CAPTURE_YFLIP = 0x0002, }; struct weston_compositor { diff --git a/src/gl-renderer.c b/src/gl-renderer.c index a3785f84..c89b9168 100644 --- a/src/gl-renderer.c +++ b/src/gl-renderer.c @@ -1831,6 +1831,7 @@ gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display, ec->renderer = &gr->base; ec->capabilities |= WESTON_CAP_ROTATION_ANY; + ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP; return 0; diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c index eea32fc0..315ea152 100644 --- a/src/pixman-renderer.c +++ b/src/pixman-renderer.c @@ -659,6 +659,7 @@ pixman_renderer_init(struct weston_compositor *ec) renderer->base.destroy = pixman_renderer_destroy; ec->renderer = &renderer->base; ec->capabilities |= WESTON_CAP_ROTATION_ANY; + ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP; weston_compositor_add_debug_binding(ec, KEY_R, debug_binding, ec); diff --git a/src/screenshooter.c b/src/screenshooter.c index ae97b4ec..6f53fad8 100644 --- a/src/screenshooter.c +++ b/src/screenshooter.c @@ -61,6 +61,13 @@ copy_bgra_yflip(uint8_t *dst, uint8_t *src, int height, int stride) } } +static void +copy_bgra(uint8_t *dst, uint8_t *src, int height, int stride) +{ + /* TODO: optimize this out */ + memcpy(dst, src, height * stride); +} + static void copy_row_swap_RB(void *vdst, void *vsrc, int bytes) { @@ -91,6 +98,19 @@ copy_rgba_yflip(uint8_t *dst, uint8_t *src, int height, int stride) } } +static void +copy_rgba(uint8_t *dst, uint8_t *src, int height, int stride) +{ + uint8_t *end; + + end = dst + height * stride; + while (dst < end) { + copy_row_swap_RB(dst, src, stride); + dst += stride; + src += stride; + } +} + static void screenshooter_frame_notify(struct wl_listener *listener, void *data) { @@ -98,12 +118,13 @@ screenshooter_frame_notify(struct wl_listener *listener, void *data) container_of(listener, struct screenshooter_frame_listener, listener); struct weston_output *output = data; + struct weston_compositor *compositor = output->compositor; int32_t stride; uint8_t *pixels, *d, *s; output->disable_planes--; wl_list_remove(&listener->link); - stride = l->buffer->width * (PIXMAN_FORMAT_BPP(output->compositor->read_format) / 8); + stride = l->buffer->width * (PIXMAN_FORMAT_BPP(compositor->read_format) / 8); pixels = malloc(stride * l->buffer->height); if (pixels == NULL) { @@ -112,8 +133,8 @@ screenshooter_frame_notify(struct wl_listener *listener, void *data) return; } - output->compositor->renderer->read_pixels(output, - output->compositor->read_format, pixels, + compositor->renderer->read_pixels(output, + compositor->read_format, pixels, 0, 0, output->current->width, output->current->height); @@ -122,14 +143,20 @@ screenshooter_frame_notify(struct wl_listener *listener, void *data) d = wl_shm_buffer_get_data(l->buffer); s = pixels + stride * (l->buffer->height - 1); - switch (output->compositor->read_format) { + switch (compositor->read_format) { case PIXMAN_a8r8g8b8: case PIXMAN_x8r8g8b8: - copy_bgra_yflip(d, s, output->current->height, stride); + if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP) + copy_bgra_yflip(d, s, output->current->height, stride); + else + copy_bgra(d, pixels, output->current->height, stride); break; case PIXMAN_x8b8g8r8: case PIXMAN_a8b8g8r8: - copy_rgba_yflip(d, s, output->current->height, stride); + if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP) + copy_rgba_yflip(d, s, output->current->height, stride); + else + copy_rgba(d, pixels, output->current->height, stride); break; default: break; @@ -218,6 +245,7 @@ screenshooter_binding(struct weston_seat *seat, uint32_t time, uint32_t key, struct weston_recorder { struct weston_output *output; uint32_t *frame, *rect; + uint32_t *tmpbuf; uint32_t total; int fd; struct wl_listener frame_listener; @@ -260,7 +288,7 @@ transform_rect(struct weston_output *output, pixman_box32_t *r) { pixman_box32_t s = *r; - switch(output->transform) { + switch (output->transform) { case WL_OUTPUT_TRANSFORM_FLIPPED: case WL_OUTPUT_TRANSFORM_FLIPPED_90: case WL_OUTPUT_TRANSFORM_FLIPPED_180: @@ -272,7 +300,7 @@ transform_rect(struct weston_output *output, pixman_box32_t *r) break; } - switch(output->transform) { + switch (output->transform) { case WL_OUTPUT_TRANSFORM_NORMAL: case WL_OUTPUT_TRANSFORM_FLIPPED: r->x1 = s.x1; @@ -310,6 +338,7 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data) struct weston_recorder *recorder = container_of(listener, struct weston_recorder, frame_listener); struct weston_output *output = data; + struct weston_compositor *compositor = output->compositor; uint32_t msecs = output->frame_time; pixman_box32_t *r; pixman_region32_t damage; @@ -320,6 +349,15 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data) uint32_t nrects; } header; struct iovec v[2]; + int do_yflip; + int y_orig; + uint32_t *outbuf; + + do_yflip = !!(compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP); + if (do_yflip) + outbuf = recorder->rect; + else + outbuf = recorder->tmpbuf; pixman_region32_init(&damage); pixman_region32_intersect(&damage, &output->region, @@ -344,17 +382,26 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data) for (i = 0; i < n; i++) { width = r[i].x2 - r[i].x1; height = r[i].y2 - r[i].y1; - output->compositor->renderer->read_pixels(output, - output->compositor->read_format, recorder->rect, - r[i].x1, output->current->height - r[i].y2, - width, height); + + if (do_yflip) + y_orig = output->current->height - r[i].y2; + else + y_orig = r[i].y1; + + compositor->renderer->read_pixels(output, + compositor->read_format, recorder->rect, + r[i].x1, y_orig, width, height); s = recorder->rect; - p = recorder->rect; + p = outbuf; run = prev = 0; /* quiet gcc */ for (j = 0; j < height; j++) { - d = recorder->frame + - stride * (r[i].y2 - j - 1) + r[i].x1; + if (do_yflip) + y_orig = r[i].y2 - j - 1; + else + y_orig = r[i].y1 + j; + d = recorder->frame + stride * y_orig + r[i].x1; + for (k = 0; k < width; k++) { next = *s++; delta = component_delta(next, *d); @@ -372,15 +419,14 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data) p = output_run(p, prev, run); recorder->total += write(recorder->fd, - recorder->rect, - (p - recorder->rect) * 4); + outbuf, (p - outbuf) * 4); #if 0 fprintf(stderr, "%dx%d at %d,%d rle from %d to %d bytes (%f) total %dM\n", width, height, r[i].x1, r[i].y1, - width * height * 4, (int) (p - recorder->rect) * 4, - (float) (p - recorder->rect) / (width * height), + width * height * 4, (int) (p - outbuf) * 4, + (float) (p - outbuf) / (width * height), recorder->total / 1024 / 1024); #endif } @@ -391,9 +437,13 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data) static void weston_recorder_create(struct weston_output *output, const char *filename) { + struct weston_compositor *compositor = output->compositor; struct weston_recorder *recorder; int stride, size; struct { uint32_t magic, format, width, height; } header; + int do_yflip; + + do_yflip = !!(compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP); recorder = malloc(sizeof *recorder); @@ -406,9 +456,14 @@ weston_recorder_create(struct weston_output *output, const char *filename) recorder->output = output; memset(recorder->frame, 0, size); + if (do_yflip) + recorder->tmpbuf = NULL; + else + recorder->tmpbuf = malloc(size); + header.magic = WCAP_HEADER_MAGIC; - switch (output->compositor->read_format) { + switch (compositor->read_format) { case PIXMAN_a8r8g8b8: header.format = WCAP_FORMAT_XRGB8888; break; @@ -445,6 +500,7 @@ weston_recorder_destroy(struct weston_recorder *recorder) { wl_list_remove(&recorder->frame_listener.link); close(recorder->fd); + free(recorder->tmpbuf); free(recorder->frame); free(recorder->rect); recorder->output->disable_planes--;