[PATCH 2/2] DEBUG: Add tool to analyze regions used for output repaint

Ander Conselvan de Oliveira conselvan2 at gmail.com
Tue Aug 14 05:26:50 PDT 2012


From: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira at intel.com>

This makes weston write to stdout the regions used for output repaint
such as the primary plane damage, the opaque region, etc and adds a
simple wayland client for visualizing them. The regions for each frame
are drawn one at a time with different colors, and the arrow keys move
between them.

The motivation for this was tracking down the bug described in the
patch I just sent. In that case, repaint damage is not helpful at all
since enabling it disables the overlays, and I felt the need of
stepping slowly through the various steps, although the bug was only
reproducible with fast movement of the overlay surface.

The way this is done is quite invasive, but if there is interest, I can
try to make it upstreamable.
---
 clients/Makefile.am    |    4 +
 clients/damage-debug.c |  270 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/compositor.c       |   27 +++++
 3 files changed, 301 insertions(+)
 create mode 100644 clients/damage-debug.c

diff --git a/clients/Makefile.am b/clients/Makefile.am
index 133eaca..14c2d32 100644
--- a/clients/Makefile.am
+++ b/clients/Makefile.am
@@ -47,6 +47,7 @@ terminal = weston-terminal
 clients_programs =				\
 	flower					\
 	image					\
+	damage-debug				\
 	dnd					\
 	smoke					\
 	resizor					\
@@ -85,6 +86,9 @@ weston_terminal_LDADD = $(toolkit_libs) -lutil
 image_SOURCES = image.c
 image_LDADD = $(toolkit_libs)
 
+damage_debug_SOURCES = damage-debug.c
+damage_debug_LDADD = $(toolkit_libs)
+
 dnd_SOURCES = dnd.c
 dnd_LDADD = $(toolkit_libs)
 
diff --git a/clients/damage-debug.c b/clients/damage-debug.c
new file mode 100644
index 0000000..7e6ee22
--- /dev/null
+++ b/clients/damage-debug.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ * Copyright © 2009 Chris Wilson
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <math.h>
+#include <time.h>
+#include <cairo.h>
+
+#include <linux/input.h>
+
+#include <wayland-client.h>
+
+#include "window.h"
+#include "../shared/cairo-util.h"
+
+struct rect {
+	int32_t x1, y1, x2, y2;
+};
+
+struct region {
+	uint64_t id;
+	uint32_t nrects;
+	struct wl_list link;
+	struct rect rects[];
+};
+
+struct dd {
+	struct window *window;
+	struct widget *widget;
+	struct display *display;
+	int fullscreen;
+	struct wl_list regions;
+	struct region *current;
+};
+
+static int
+load_file(struct dd *dd, char *filename)
+{
+	int fd;
+	struct region *region;
+	int32_t nrect;
+	uint64_t id;
+	ssize_t r;
+
+	fd = open(filename, O_RDONLY);
+	if (!fd)
+		return -1;
+
+	wl_list_init(&dd->regions);
+
+	do {
+		r = read(fd, &id, sizeof id);
+		if (r <= 0)
+			break;
+
+		r = read(fd, &nrect, sizeof nrect);
+		if (r <= 0)
+			break;
+
+
+		region = malloc(sizeof *region +
+				nrect * sizeof(struct rect));
+		if (!region)
+			/* XXX may be leaking other regions */
+			return -1;
+
+		region->id = id;
+		region->nrects = nrect;
+
+		if (nrect) {
+			r = read(fd, region->rects,
+				 nrect * sizeof region->rects[0]);
+			if (r <= 0)
+				break;
+		}
+
+		fprintf(stderr, "read region id %lx with %d rects\n", id, nrect);
+
+		wl_list_insert(dd->regions.prev, &region->link);
+	} while (r > 0);
+
+	close(fd);
+
+	return 0;
+}
+
+struct color {
+	double r, g, b, a;
+};
+
+struct color colors[] = {
+	{1.0, 0.0, 0.0, 1.0},
+	{0.0, 1.0, 0.0, 1.0},
+	{0.0, 0.0, 1.0, 1.0},
+	{1.0, 1.0, 0.0, 1.0},
+	{0.0, 1.0, 1.0, 1.0},
+	{1.0, 0.0, 1.0, 1.0},
+};
+
+static void
+redraw_handler(struct widget *widget, void *data)
+{
+	struct dd *dd = data;
+	struct rectangle allocation;
+	cairo_t *cr;
+	cairo_surface_t *surface;
+	struct color c;
+	uint32_t i;
+
+	surface = window_get_surface(dd->window);
+	cr = cairo_create(surface);
+	widget_get_allocation(dd->widget, &allocation);
+	cairo_rectangle(cr, allocation.x, allocation.y,
+			allocation.width, allocation.height);
+	cairo_clip(cr);
+
+	cairo_rectangle(cr, allocation.x, allocation.y,
+			allocation.width, allocation.height);
+	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+	cairo_set_source_rgba(cr, 0, 0, 0, 1);
+	cairo_fill(cr);
+
+	c = colors[(uint32_t) (dd->current->id & 0xff) - 1];
+	cairo_set_source_rgba(cr, c.r, c.g, c.b, c.a);
+
+	for (i = 0; i < dd->current->nrects; i++) {
+		cairo_rectangle(cr,
+				dd->current->rects[i].x1,
+				dd->current->rects[i].y1,
+				dd->current->rects[i].x2 -
+				dd->current->rects[i].x1,
+				dd->current->rects[i].y2 -
+				dd->current->rects[i].y1);
+		cairo_fill(cr);
+	}
+
+	cairo_destroy(cr);
+	cairo_surface_destroy(surface);
+}
+
+static void
+keyboard_focus_handler(struct window *window,
+		       struct input *device, void *data)
+{
+	struct dd *dd = data;
+
+	window_schedule_redraw(dd->window);
+}
+
+static void
+key_handler(struct window *window, struct input *device,
+	    uint32_t time, uint32_t key, uint32_t unicode,
+	    enum wl_keyboard_key_state state, void *data)
+{
+	struct dd *dd = data;
+	struct wl_list *new = NULL;
+
+	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
+		return;
+
+	if (key == KEY_RIGHT) {
+		if (dd->current->link.next != &dd->regions)
+			new = dd->current->link.next;
+	} else if (key == KEY_LEFT) {
+		if (dd->current->link.prev != &dd->regions)
+			new = dd->current->link.prev;
+	} else if (key == KEY_PAGEUP) {
+		new = dd->regions.next;
+	} else if (key == KEY_PAGEDOWN) {
+		new = dd->regions.prev;
+	} else if (key == KEY_Q) {
+		exit(1);
+	} else
+		return;
+
+	if (!new)
+		return;
+
+	dd->current = container_of(new, struct region, link);
+
+	window_schedule_redraw(dd->window);
+}
+
+static void
+fullscreen_handler(struct window *window, void *data)
+{
+	struct dd *dd = data;
+
+	dd->fullscreen ^= 1;
+	window_set_fullscreen(window, dd->fullscreen);
+}
+
+static struct dd *
+dd_create(struct display *display, char *filename)
+{
+	struct dd *dd;
+
+	dd = malloc(sizeof *dd);
+	if (dd == NULL)
+		return dd;
+	memset(dd, 0, sizeof *dd);
+
+	if (load_file(dd, filename) ||
+	    wl_list_empty(&dd->regions)) {
+		free(dd);
+		return NULL;
+	}
+
+	dd->current = container_of(dd->regions.next, struct region, link);
+	dd->window = window_create(display);
+	dd->widget = frame_create(dd->window, dd);
+	window_set_title(dd->window, "Damage Debug");
+	dd->display = display;
+
+	window_set_user_data(dd->window, dd);
+	widget_set_redraw_handler(dd->widget, redraw_handler);
+	window_set_keyboard_focus_handler(dd->window,
+					  keyboard_focus_handler);
+	window_set_key_handler(dd->window, key_handler);
+	window_set_fullscreen_handler(dd->window, fullscreen_handler);
+
+	widget_schedule_resize(dd->widget, 500, 400);
+
+	return dd;
+}
+
+int
+main(int argc, char *argv[])
+{
+	struct display *d;
+
+	d = display_create(argc, argv);
+	if (d == NULL) {
+		fprintf(stderr, "failed to create display: %m\n");
+		return -1;
+	}
+
+	dd_create(d, argv[1]);
+
+	display_run(d);
+
+	return 0;
+}
diff --git a/src/compositor.c b/src/compositor.c
index 26c57b9..5161ee9 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -1130,6 +1130,25 @@ surface_accumulate_damage(struct weston_surface *surface,
 }
 
 static void
+print_region(pixman_region32_t *region, uint64_t id)
+{
+	pixman_box32_t *rects;
+	int32_t i, nrects;
+
+	rects = pixman_region32_rectangles(region, &nrects);
+
+	write(1, &id, sizeof id);
+	write(1, &nrects, sizeof nrects);
+
+	for (i = 0; i < nrects; i++) {
+		write(1, &rects[i].x1, sizeof rects[1].x1);
+		write(1, &rects[i].y1, sizeof rects[1].y1);
+		write(1, &rects[i].x2, sizeof rects[1].x2);
+		write(1, &rects[i].y2, sizeof rects[1].y2);
+	}
+}
+
+static void
 weston_output_repaint(struct weston_output *output, uint32_t msecs)
 {
 	struct weston_compositor *ec = output->compositor;
@@ -1184,6 +1203,11 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs)
 	wl_list_for_each(es, &ec->surface_list, link)
 		surface_accumulate_damage(es, &opaque, &previous);
 
+	print_region(&output->region, (uint64_t) msecs << 32 | 1);
+	print_region(&opaque, (uint64_t) msecs << 32 | 2);
+	print_region(&ec->primary_plane.damage, (uint64_t) msecs << 32 | 3);
+	print_region(&output->previous_damage, (uint64_t) msecs << 32 | 4);
+
 	pixman_region32_init(&output_damage);
 	pixman_region32_union(&output_damage, &ec->primary_plane.damage,
 			      &output->previous_damage);
@@ -1200,6 +1224,9 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs)
 
 	output->repaint(output, &output_damage);
 
+	print_region(&output_damage, (uint64_t) msecs << 32 | 5);
+	print_region(&ec->primary_plane.damage, (uint64_t) msecs << 32 | 6);
+
 	pixman_region32_fini(&output_damage);
 
 	output->repaint_needed = 0;
-- 
1.7.9.5



More information about the wayland-devel mailing list