compositor: add capability CAPTURE_YFLIP
Both GL and pixman renderer (pixman probably only because GL did?) return the screen capture image as y-flipped, therefore Weston y-flips it again. However, the future rpi-renderer can produce only right-way-up (non-flipped) screen captures, and does not need an y-flip. Add a capability flag for y-flip, which the rpi-renderer will not set, to get screen captures the right way up. The wcap recording code needs yet another temporary buffer for the non-flipped case, since the WCAP format is flipped, and the code normally overwrites the input image as it compresses it. This becomes difficult, if the compressor is supposed to flip while processing. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
This commit is contained in:
parent
7bb6510748
commit
4fc5dd0099
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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--;
|
||||
|
|
Loading…
Reference in New Issue