[PATCH weston v3 07/15] tests: Add screenshot recording capability to weston-test

Bryce Harrington bryce at osg.samsung.com
Thu May 21 01:39:29 PDT 2015


Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=83981
Signed-off-by: Bryce Harrington <bryce at osg.samsung.com>
---
 tests/weston-test.c | 243 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 243 insertions(+)

diff --git a/tests/weston-test.c b/tests/weston-test.c
index 9f1f49b..8f8781f 100644
--- a/tests/weston-test.c
+++ b/tests/weston-test.c
@@ -269,6 +269,248 @@ 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 *compositor;
+	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);
+
+	/* XXX: It would be nice if we used Pixman to do all this rather
+	 *  than our own implementation
+	 */
+	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_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
-- 
1.9.1



More information about the wayland-devel mailing list