[PATCH weston 07/10] tests: Add screenshot recording capability to weston-test
Bryce Harrington
bryce at osg.samsung.com
Wed May 6 17:44:26 PDT 2015
Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=83981
Signed-off-by: Bryce Harrington <bryce at osg.samsung.com>
---
Makefile.am | 4 +-
tests/weston-test.c | 244 +++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 245 insertions(+), 3 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index fb3152e..023b7e1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -995,7 +995,7 @@ noinst_PROGRAMS += \
matrix-test
test_module_ldflags = \
- -module -avoid-version -rpath $(libdir) $(COMPOSITOR_LIBS)
+ -module -avoid-version -rpath $(libdir) $(COMPOSITOR_LIBS) $(CAIRO_LIBS)
surface_global_test_la_SOURCES = tests/surface-global-test.c
surface_global_test_la_LDFLAGS = $(test_module_ldflags)
@@ -1007,7 +1007,7 @@ surface_test_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
weston_test_la_LIBADD = $(COMPOSITOR_LIBS) libshared.la
weston_test_la_LDFLAGS = $(test_module_ldflags)
-weston_test_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
+weston_test_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(CAIRO_CFLAGS)
weston_test_la_SOURCES = tests/weston-test.c
nodist_weston_test_la_SOURCES = \
protocol/weston-test-protocol.c \
diff --git a/tests/weston-test.c b/tests/weston-test.c
index 9f1f49b..1d6d264 100644
--- a/tests/weston-test.c
+++ b/tests/weston-test.c
@@ -27,6 +27,7 @@
#include <signal.h>
#include <unistd.h>
#include <string.h>
+#include <cairo.h>
#include "../src/compositor.h"
#include "weston-test-server-protocol.h"
@@ -269,6 +270,247 @@ get_n_buffers(struct wl_client *client, struct wl_resource *resource)
weston_test_send_n_egl_buffers(resource, n_buffers);
}
+enum weston_test_screenshot_outcome {
+ WESTON_TEST_SCREENSHOT_SUCCESS,
+ WESTON_TEST_SCREENSHOT_NO_MEMORY,
+ WESTON_TEST_SCREENSHOT_BAD_BUFFER
+ };
+
+typedef void (*weston_test_screenshot_done_func_t)(void *data,
+ enum weston_test_screenshot_outcome outcome);
+
+struct test_screenshot {
+ struct weston_compositor *ec;
+ struct wl_global *global;
+ struct wl_client *client;
+ struct weston_process process;
+ struct wl_listener destroy_listener;
+};
+
+struct test_screenshot_frame_listener {
+ struct wl_listener listener;
+ struct weston_buffer *buffer;
+ weston_test_screenshot_done_func_t done;
+ void *data;
+};
+
+static void
+copy_bgra_yflip(uint8_t *dst, uint8_t *src, int height, int stride)
+{
+ uint8_t *end;
+
+ end = dst + height * stride;
+ while (dst < end) {
+ memcpy(dst, src, stride);
+ dst += stride;
+ src -= 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)
+{
+ uint32_t *dst = vdst;
+ uint32_t *src = vsrc;
+ uint32_t *end = dst + bytes / 4;
+
+ while (dst < end) {
+ uint32_t v = *src++;
+ /* A R G B */
+ uint32_t tmp = v & 0xff00ff00;
+ tmp |= (v >> 16) & 0x000000ff;
+ tmp |= (v << 16) & 0x00ff0000;
+ *dst++ = tmp;
+ }
+}
+
+static void
+copy_rgba_yflip(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
+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
+test_screenshot_frame_notify(struct wl_listener *listener, void *data)
+{
+ struct test_screenshot_frame_listener *l =
+ container_of(listener,
+ struct test_screenshot_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(compositor->read_format) / 8);
+ pixels = malloc(stride * l->buffer->height);
+
+ if (pixels == NULL) {
+ l->done(l->data, WESTON_TEST_SCREENSHOT_NO_MEMORY);
+ free(l);
+ return;
+ }
+
+ // FIXME: Needs to handle output transformations
+
+ compositor->renderer->read_pixels(output,
+ compositor->read_format,
+ pixels,
+ 0, 0,
+ output->current_mode->width,
+ output->current_mode->height);
+
+ stride = wl_shm_buffer_get_stride(l->buffer->shm_buffer);
+
+ d = wl_shm_buffer_get_data(l->buffer->shm_buffer);
+ s = pixels + stride * (l->buffer->height - 1);
+
+ wl_shm_buffer_begin_access(l->buffer->shm_buffer);
+
+ switch (compositor->read_format) {
+ case PIXMAN_a8r8g8b8:
+ case PIXMAN_x8r8g8b8:
+ if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP)
+ copy_bgra_yflip(d, s, output->current_mode->height, stride);
+ else
+ copy_bgra(d, pixels, output->current_mode->height, stride);
+ break;
+ case PIXMAN_x8b8g8r8:
+ case PIXMAN_a8b8g8r8:
+ if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP)
+ copy_rgba_yflip(d, s, output->current_mode->height, stride);
+ else
+ copy_rgba(d, pixels, output->current_mode->height, stride);
+ break;
+ default:
+ break;
+ }
+
+ wl_shm_buffer_end_access(l->buffer->shm_buffer);
+
+ l->done(l->data, WESTON_TEST_SCREENSHOT_SUCCESS);
+ free(pixels);
+ free(l);
+}
+
+static bool
+weston_test_screenshot_shoot(struct weston_output *output,
+ struct weston_buffer *buffer,
+ weston_test_screenshot_done_func_t done,
+ void *data)
+{
+ struct test_screenshot_frame_listener *l;
+
+ /* Get the shm buffer resource the client created */
+ if (!wl_shm_buffer_get(buffer->resource)) {
+ done(data, WESTON_TEST_SCREENSHOT_BAD_BUFFER);
+ return false;
+ }
+
+ buffer->shm_buffer = wl_shm_buffer_get(buffer->resource);
+ buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer);
+ buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer);
+
+ /* Verify buffer is big enough */
+ if (buffer->width < output->current_mode->width ||
+ buffer->height < output->current_mode->height) {
+ done(data, WESTON_TEST_SCREENSHOT_BAD_BUFFER);
+ return false;
+ }
+
+ /* allocate the frame listener */
+ l = malloc(sizeof *l);
+ if (l == NULL) {
+ done(data, WESTON_TEST_SCREENSHOT_NO_MEMORY);
+ return false;
+ }
+
+ /* Set up the listener */
+ l->buffer = buffer;
+ l->done = done;
+ l->data = data;
+ l->listener.notify = test_screenshot_frame_notify;
+ wl_signal_add(&output->frame_signal, &l->listener);
+
+ /* Fire off a repaint */
+ output->disable_planes++;
+ weston_output_schedule_repaint(output);
+
+ return true;
+}
+
+static void
+capture_screenshot_done(void *data, enum weston_test_screenshot_outcome outcome)
+{
+ struct wl_resource *resource = data;
+
+ switch (outcome) {
+ case WESTON_TEST_SCREENSHOT_SUCCESS:
+ weston_test_send_capture_screenshot_done(resource);
+ break;
+ case WESTON_TEST_SCREENSHOT_NO_MEMORY:
+ wl_resource_post_no_memory(resource);
+ break;
+ default:
+ break;
+ }
+}
+
+
+/**
+ * Grabs a snapshot of the screen.
+ */
+static void
+capture_screenshot(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *output_resource,
+ struct wl_resource *buffer_resource)
+{
+// struct weston_test *test =
+// wl_resource_get_user_data(resource);
+ struct weston_output *output =
+ wl_resource_get_user_data(output_resource);
+ struct weston_buffer *buffer =
+ weston_buffer_from_resource(buffer_resource);
+
+ if (buffer == NULL) {
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ weston_test_screenshot_shoot(output, buffer,
+ capture_screenshot_done, resource);
+}
+
static const struct weston_test_interface test_implementation = {
move_surface,
move_pointer,
@@ -278,6 +520,7 @@ static const struct weston_test_interface test_implementation = {
device_release,
device_add,
get_n_buffers,
+ capture_screenshot,
};
static void
@@ -316,7 +559,6 @@ idle_launch_client(void *data)
sigfillset(&allsigs);
sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
execl(path, path, NULL);
- weston_log("compositor: executing '%s' failed: %m\n", path);
exit(EXIT_FAILURE);
}
--
1.9.1
More information about the wayland-devel
mailing list