[PATCH] rpi: Support opaque regions

Tomeu Vizoso tomeu at tomeuvizoso.net
Mon Dec 2 08:18:58 PST 2013


This is needed for XWayland surfaces with alpha channel, as X will be
sending crap in there that should be discarded.

This is currently done with a copy in the compositor, while we wait for
support in the VideoCore side.
---
 src/compositor-rpi.c |   3 ++
 src/compositor.c     |   2 +
 src/rpi-bcm-stubs.h  |   8 ++++
 src/rpi-renderer.c   | 120 +++++++++++++++++++++++++++++++++++++++++++++++++--
 src/rpi-renderer.h   |   1 +
 5 files changed, 130 insertions(+), 4 deletions(-)

diff --git a/src/compositor-rpi.c b/src/compositor-rpi.c
index f163e01..fc78afe 100644
--- a/src/compositor-rpi.c
+++ b/src/compositor-rpi.c
@@ -821,6 +821,7 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
 		.tty = 0, /* default to current tty */
 		.renderer.single_buffer = 0,
 		.output_transform = WL_OUTPUT_TRANSFORM_NORMAL,
+		.renderer.opaque_regions = 0,
 	};
 
 	const struct weston_option rpi_options[] = {
@@ -828,6 +829,8 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
 		{ WESTON_OPTION_BOOLEAN, "single-buffer", 0,
 		  &param.renderer.single_buffer },
 		{ WESTON_OPTION_STRING, "transform", 0, &transform },
+		{ WESTON_OPTION_BOOLEAN, "opaque-regions", 0,
+		  &param.renderer.opaque_regions },
 	};
 
 	parse_options(rpi_options, ARRAY_LENGTH(rpi_options), argc, argv);
diff --git a/src/compositor.c b/src/compositor.c
index b8b7c0f..96f83f1 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -3719,6 +3719,8 @@ usage(int error_code)
 		"  --single-buffer\tUse single-buffered Dispmanx elements.\n"
 		"  --transform=TR\tThe output transformation, TR is one of:\n"
 		"\tnormal 90 180 270 flipped flipped-90 flipped-180 flipped-270\n"
+		"  --opaque-regions\tEnable support for opaque regions, can be "
+		"very slow without support in the GPU firmware.\n"
 		"\n");
 #endif
 
diff --git a/src/rpi-bcm-stubs.h b/src/rpi-bcm-stubs.h
index 31b9b1c..fa30570 100644
--- a/src/rpi-bcm-stubs.h
+++ b/src/rpi-bcm-stubs.h
@@ -308,6 +308,14 @@ vc_dispmanx_set_wl_buffer_in_use(struct wl_resource *_buffer, int in_use)
 {
 }
 
+static inline int
+vc_dispmanx_element_set_opaque_rect(DISPMANX_UPDATE_HANDLE_T update,
+				    DISPMANX_ELEMENT_HANDLE_T element,
+				    const VC_RECT_T *opaque_rect)
+{
+	return -1;
+}
+
 /* from /opt/vc/include/EGL/eglplatform.h */
 
 typedef struct {
diff --git a/src/rpi-renderer.c b/src/rpi-renderer.c
index 2b6d12c..4140622 100644
--- a/src/rpi-renderer.c
+++ b/src/rpi-renderer.c
@@ -79,12 +79,16 @@
 /* If we had a fully featured vc_dispmanx_resource_write_data()... */
 /*#define HAVE_RESOURCE_WRITE_DATA_RECT 1*/
 
+/* If we had a vc_dispmanx_element_set_opaque_rect()... */
+/*#define HAVE_ELEMENT_SET_OPAQUE_RECT 1*/
+
 struct rpi_resource {
 	DISPMANX_RESOURCE_HANDLE_T handle;
 	int width;
 	int height; /* height of the image (valid pixel data) */
 	int stride; /* bytes */
 	int buffer_height; /* height of the buffer */
+	int enable_opaque_regions;
 	VC_IMAGE_TYPE_T ifmt;
 };
 
@@ -108,6 +112,7 @@ struct rpir_surface {
 	int visible_views;
 	int need_swap;
 	int single_buffer;
+	int enable_opaque_regions;
 
 	struct rpi_resource resources[2];
 	struct rpi_resource *front;
@@ -160,6 +165,7 @@ struct rpi_renderer {
 	struct weston_renderer base;
 
 	int single_buffer;
+	int enable_opaque_regions;
 
 #ifdef ENABLE_EGL
 	EGLDisplay egl_display;
@@ -306,9 +312,47 @@ shm_buffer_get_vc_format(struct wl_shm_buffer *buffer)
 	}
 }
 
+#ifndef HAVE_ELEMENT_SET_OPAQUE_RECT
+static uint32_t *
+apply_opaque_region(struct wl_shm_buffer *buffer,
+		    pixman_region32_t *opaque_region)
+{
+	uint32_t *src, *dst;
+	int width;
+	int height;
+	int stride;
+	int x, y;
+
+	width = wl_shm_buffer_get_width(buffer);
+	height = wl_shm_buffer_get_height(buffer);
+	stride = wl_shm_buffer_get_stride(buffer);
+	src = wl_shm_buffer_get_data(buffer);
+
+	dst = malloc(height * stride);
+	if (dst == NULL) {
+		weston_log("rpi-renderer error: out of memory\n");
+		return NULL;
+	}
+
+	for (y = 0; y < height; y++) {
+		for (x = 0; x < width; x++) {
+			int i = y * stride / 4 + x;
+			pixman_box32_t box;
+			if (pixman_region32_contains_point (opaque_region, x, y, &box)) {
+				dst[i] = src[i] | 0xff000000;
+			} else {
+				dst[i] = src[i];
+			}
+		}
+	}
+
+	return dst;
+}
+#endif
+
 static int
 rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer,
-		    pixman_region32_t *region)
+		    pixman_region32_t *region, pixman_region32_t *opaque_region)
 {
 	pixman_region32_t write_region;
 	pixman_box32_t *r;
@@ -332,6 +376,17 @@ rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer,
 	stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
 	pixels = wl_shm_buffer_get_data(buffer->shm_buffer);
 
+#ifndef HAVE_ELEMENT_SET_OPAQUE_RECT
+	if (pixman_region32_not_empty(opaque_region) &&
+	    wl_shm_buffer_get_format(buffer->shm_buffer) == WL_SHM_FORMAT_ARGB8888 &&
+	    resource->enable_opaque_regions) {
+		pixels = apply_opaque_region(buffer->shm_buffer, opaque_region);
+
+		if (!pixels)
+			return -1;
+	}
+#endif
+
 	ret = rpi_resource_realloc(resource, ifmt & ~PREMULT_ALPHA_FLAG,
 				   width, height, stride, height);
 	if (ret < 0)
@@ -382,6 +437,13 @@ rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer,
 
 	pixman_region32_fini(&write_region);
 
+#ifndef HAVE_ELEMENT_SET_OPAQUE_RECT
+	if (pixman_region32_not_empty(opaque_region) &&
+	    wl_shm_buffer_get_format(buffer->shm_buffer) == WL_SHM_FORMAT_ARGB8888 &&
+	    resource->enable_opaque_regions)
+		free(pixels);
+#endif
+
 	return ret ? -1 : 0;
 }
 
@@ -435,6 +497,7 @@ rpir_surface_create(struct rpi_renderer *renderer)
 	wl_list_init(&surface->views);
 	surface->visible_views = 0;
 	surface->single_buffer = renderer->single_buffer;
+	surface->enable_opaque_regions = renderer->enable_opaque_regions;
 	rpi_resource_init(&surface->resources[0]);
 	rpi_resource_init(&surface->resources[1]);
 	surface->front = &surface->resources[0];
@@ -442,6 +505,10 @@ rpir_surface_create(struct rpi_renderer *renderer)
 		surface->back = &surface->resources[0];
 	else
 		surface->back = &surface->resources[1];
+
+	surface->front->enable_opaque_regions = renderer->enable_opaque_regions;
+	surface->back->enable_opaque_regions = renderer->enable_opaque_regions;
+
 	surface->buffer_type = BUFFER_TYPE_NULL;
 
 	pixman_region32_init(&surface->prev_damage);
@@ -487,11 +554,13 @@ rpir_surface_damage(struct rpir_surface *surface, struct weston_buffer *buffer,
 	/* XXX: todo: if no surface->handle, update front buffer directly
 	 * to avoid creating a new back buffer */
 	if (surface->single_buffer) {
-		ret = rpi_resource_update(surface->front, buffer, damage);
+		ret = rpi_resource_update(surface->front, buffer, damage,
+					  &surface->surface->opaque);
 	} else {
 		pixman_region32_init(&upload);
 		pixman_region32_union(&upload, &surface->prev_damage, damage);
-		ret = rpi_resource_update(surface->back, buffer, &upload);
+		ret = rpi_resource_update(surface->back, buffer, &upload,
+					  &surface->surface->opaque);
 		pixman_region32_fini(&upload);
 	}
 
@@ -849,7 +918,6 @@ vc_image2dispmanx_transform(VC_IMAGE_TRANSFORM_T t)
 	}
 }
 
-
 static DISPMANX_RESOURCE_HANDLE_T
 rpir_surface_get_resource(struct rpir_surface *surface)
 {
@@ -865,6 +933,37 @@ rpir_surface_get_resource(struct rpir_surface *surface)
 	}
 }
 
+#ifdef HAVE_ELEMENT_SET_OPAQUE_RECT
+static int
+rpir_surface_set_opaque_rect(struct rpir_surface *surface,
+			     DISPMANX_UPDATE_HANDLE_T update)
+{
+	int ret;
+
+	if (pixman_region32_not_empty(&surface->surface->opaque) &&
+	    surface->opaque_regions) {
+		pixman_box32_t *box;
+		VC_RECT_T opaque_rect;
+
+		box = pixman_region32_extents(&surface->surface->opaque);
+		opaque_rect.x = box->x1;
+		opaque_rect.y = box->y1;
+		opaque_rect.width = box->x2 - box->x1;
+		opaque_rect.height = box->y2 - box->y1;
+
+		ret = vc_dispmanx_element_set_opaque_rect(update,
+							  surface->handle,
+							  &opaque_rect);
+		if (ret) {
+			weston_log("vc_dispmanx_element_set_opaque_rect failed\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+#endif
+
 static int
 rpir_view_dmx_add(struct rpir_view *view, struct rpir_output *output,
 		  DISPMANX_UPDATE_HANDLE_T update, int layer)
@@ -913,6 +1012,12 @@ rpir_view_dmx_add(struct rpir_view *view, struct rpir_output *output,
 	if (view->handle == DISPMANX_NO_HANDLE)
 		return -1;
 
+#ifdef HAVE_ELEMENT_SET_OPAQUE_RECT
+	ret = rpir_surface_set_opaque_rect(surface, update);
+	if (ret < 0)
+		return -1;
+#endif
+
 	view->surface->visible_views++;
 
 	return 1;
@@ -989,6 +1094,12 @@ rpir_view_dmx_move(struct rpir_view *view,
 	if (ret)
 		return -1;
 
+#ifdef HAVE_ELEMENT_SET_OPAQUE_RECT
+	ret = rpir_surface_set_opaque_rect(surface, update);
+	if (ret < 0)
+		return -1;
+#endif
+
 	return 1;
 }
 
@@ -1618,6 +1729,7 @@ rpi_renderer_create(struct weston_compositor *compositor,
 		return -1;
 
 	renderer->single_buffer = params->single_buffer;
+	renderer->enable_opaque_regions = params->opaque_regions;
 
 	renderer->base.read_pixels = rpi_renderer_read_pixels;
 	renderer->base.repaint_output = rpi_renderer_repaint_output;
diff --git a/src/rpi-renderer.h b/src/rpi-renderer.h
index 28ae303..885631a 100644
--- a/src/rpi-renderer.h
+++ b/src/rpi-renderer.h
@@ -25,6 +25,7 @@
 
 struct rpi_renderer_parameters {
 	int single_buffer;
+	int opaque_regions;
 };
 
 int
-- 
1.8.4.2



More information about the wayland-devel mailing list