[PATCH weston 13/13] Update the RPI renderer to handle views

Jason Ekstrand jason at jlekstrand.net
Sun Oct 13 05:38:23 CEST 2013


Note that I have not been able to test that this patch works properly on
the Pi.  Before the RPI EGL patches landed it worked, but I have not been
able to test the rebased version.

Signed-off-by: Jason Ekstrand <jason at jlekstrand.net>
---
 src/compositor.c   |  18 ++-
 src/compositor.h   |   4 +
 src/rpi-renderer.c | 453 +++++++++++++++++++++++++++++++++--------------------
 3 files changed, 298 insertions(+), 177 deletions(-)

diff --git a/src/compositor.c b/src/compositor.c
index e397403..b68b3d3 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -356,6 +356,17 @@ weston_view_create(struct weston_surface *surface)
 	if (view == NULL)
 		return NULL;
 
+	view->surface = surface;
+
+	if (surface->compositor->renderer->create_view &&
+	    surface->compositor->renderer->create_view(view) < 0) {
+		free(view);
+		return NULL;
+	}
+
+	/* Assign to surface */
+	wl_list_insert(&surface->views, &view->surface_link);
+	
 	wl_signal_init(&view->destroy_signal);
 	wl_list_init(&view->link);
 	wl_list_init(&view->layer_link);
@@ -377,10 +388,6 @@ weston_view_create(struct weston_surface *surface)
 
 	view->output = NULL;
 
-	/* Assign to surface */
-	view->surface = surface;
-	wl_list_insert(&surface->views, &view->surface_link);
-
 	return view;
 }
 
@@ -1200,6 +1207,9 @@ weston_view_destroy(struct weston_view *view)
 
 	weston_view_set_transform_parent(view, NULL);
 
+	if (view->surface->compositor->renderer->destroy_view)
+		view->surface->compositor->renderer->destroy_view(view);
+
 	wl_list_remove(&view->surface_link);
 
 	free(view);
diff --git a/src/compositor.h b/src/compositor.h
index 5f82e15..0c37037 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -516,10 +516,12 @@ struct weston_renderer {
 	void (*flush_damage)(struct weston_surface *surface);
 	void (*attach)(struct weston_surface *es, struct weston_buffer *buffer);
 	int (*create_surface)(struct weston_surface *surface);
+	int (*create_view)(struct weston_view *view);
 	void (*surface_set_color)(struct weston_surface *surface,
 			       float red, float green,
 			       float blue, float alpha);
 	void (*destroy_surface)(struct weston_surface *surface);
+	void (*destroy_view)(struct weston_view *view);
 	void (*destroy)(struct weston_compositor *ec);
 };
 
@@ -724,6 +726,8 @@ struct weston_view {
 	pixman_region32_t clip;
 	float alpha;                     /* part of geometry, see below */
 
+	void *renderer_state;
+
 	/* Surface geometry state, mutable.
 	 * If you change anything, call weston_surface_geometry_dirty().
 	 * That includes the transformations referenced from the list.
diff --git a/src/rpi-renderer.c b/src/rpi-renderer.c
index a95cc60..235223d 100644
--- a/src/rpi-renderer.c
+++ b/src/rpi-renderer.c
@@ -104,13 +104,8 @@ enum buffer_type {
 struct rpir_surface {
 	struct weston_surface *surface;
 
-	/* If link is empty, the surface is guaranteed to not be on screen,
-	 * i.e. updates removing Elements have completed.
-	 */
-	struct wl_list link;
-
-	DISPMANX_ELEMENT_HANDLE_T handle;
-	int layer;
+	struct wl_list views;
+	int visible_views;
 	int need_swap;
 	int single_buffer;
 
@@ -127,6 +122,20 @@ struct rpir_surface {
 	enum buffer_type buffer_type;
 };
 
+struct rpir_view {
+	struct rpir_surface *surface;
+	struct wl_list surface_link;
+	struct weston_view *view;
+
+	/* If link is empty, the view is guaranteed to not be on screen,
+	 * i.e. updates removing Elements have completed.
+	 */
+	struct wl_list link;
+
+	DISPMANX_ELEMENT_HANDLE_T handle;
+	int layer;
+};
+
 struct rpir_output {
 	DISPMANX_DISPLAY_HANDLE_T display;
 
@@ -134,10 +143,10 @@ struct rpir_output {
 	struct weston_matrix matrix;
 
 	/* all Elements currently on screen */
-	struct wl_list surface_list; /* struct rpir_surface::link */
+	struct wl_list view_list; /* struct rpir_surface::link */
 
 	/* Elements just removed, waiting for update completion */
-	struct wl_list surface_cleanup_list; /* struct rpir_surface::link */
+	struct wl_list view_cleanup_list; /* struct rpir_surface::link */
 
 	struct rpi_resource capture_buffer;
 	uint8_t *capture_data;
@@ -164,6 +173,12 @@ to_rpir_surface(struct weston_surface *surface)
 	return surface->renderer_state;
 }
 
+static inline struct rpir_view *
+to_rpir_view(struct weston_view *view)
+{
+	return view->renderer_state;
+}
+
 static inline struct rpir_output *
 to_rpir_output(struct weston_output *output)
 {
@@ -356,9 +371,8 @@ rpir_surface_create(struct rpi_renderer *renderer)
 	if (!surface)
 		return NULL;
 
-	wl_list_init(&surface->link);
+	surface->visible_views = 0;
 	surface->single_buffer = renderer->single_buffer;
-	surface->handle = DISPMANX_NO_HANDLE;
 	rpi_resource_init(&surface->resources[0]);
 	rpi_resource_init(&surface->resources[1]);
 	surface->front = &surface->resources[0];
@@ -376,15 +390,18 @@ rpir_surface_create(struct rpi_renderer *renderer)
 static void
 rpir_surface_destroy(struct rpir_surface *surface)
 {
-	wl_list_remove(&surface->link);
-
-	if (surface->handle != DISPMANX_NO_HANDLE)
+	if (surface->visible_views)
 		weston_log("ERROR rpi: destroying on-screen element\n");
 
+	assert(wl_list_empty(&surface->views));
+
+	if (surface->surface)
+		surface->surface->renderer_state = NULL;
+
 	pixman_region32_fini(&surface->prev_damage);
 	rpi_resource_release(&surface->resources[0]);
 	rpi_resource_release(&surface->resources[1]);
-	DBG("rpir_surface %p destroyed (%u)\n", surface, surface->handle);
+	DBG("rpir_surface %p destroyed (%u)\n", surface, surface->visible_views);
 
 	if (surface->egl_back != NULL) {
 		weston_buffer_reference(&surface->egl_back->buffer_ref, NULL);
@@ -436,6 +453,46 @@ rpir_surface_damage(struct rpir_surface *surface, struct weston_buffer *buffer,
 	return ret;
 }
 
+static struct rpir_view *
+rpir_view_create(struct rpir_surface *surface)
+{
+	struct rpir_view *view;
+
+	view = calloc(1, sizeof *view);
+	if (!view)
+		return NULL;
+
+	view->surface = surface;
+	wl_list_insert(&surface->views, &view->surface_link);
+
+	wl_list_init(&view->link);
+	view->handle = DISPMANX_NO_HANDLE;
+
+	return view;
+}
+
+static void
+rpir_view_destroy(struct rpir_view *view)
+{
+	wl_list_remove(&view->link);
+
+	if (view->handle != DISPMANX_NO_HANDLE) {
+		view->surface->visible_views--;
+		weston_log("ERROR rpi: destroying on-screen element\n");
+	}
+
+	if (view->view)
+		view->view->renderer_state = NULL;
+
+	wl_list_remove(&view->surface_link);
+	if (wl_list_empty(&view->surface->views) && view->surface->surface == NULL)
+		rpir_surface_destroy(view->surface);
+
+	DBG("rpir_view %p destroyed (%d)\n", view, view->handle);
+
+	free(view);
+}
+
 static void
 matrix_type_str(struct weston_matrix *matrix, char *buf, int len)
 {
@@ -495,13 +552,13 @@ warn_bad_matrix(struct weston_matrix *total, struct weston_matrix *output,
 /*#define SURFACE_TRANSFORM */
 
 static int
-rpir_surface_compute_rects(struct rpir_surface *surface,
-			   VC_RECT_T *src_rect, VC_RECT_T *dst_rect,
-			   VC_IMAGE_TRANSFORM_T *flipmask)
+rpir_view_compute_rects(struct rpir_view *view,
+			VC_RECT_T *src_rect, VC_RECT_T *dst_rect,
+			VC_IMAGE_TRANSFORM_T *flipmask)
 {
-	struct weston_output *output_base = surface->surface->output;
+	struct weston_output *output_base = view->view->surface->output;
 	struct rpir_output *output = to_rpir_output(output_base);
-	struct weston_matrix matrix = surface->surface->transform.matrix;
+	struct weston_matrix matrix = view->view->transform.matrix;
 	VC_IMAGE_TRANSFORM_T flipt = 0;
 	int src_x, src_y;
 	int dst_x, dst_y;
@@ -523,14 +580,15 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
 	src_x = 0 << 16;
 	src_y = 0 << 16;
 
-	if (surface->buffer_type == BUFFER_TYPE_EGL) {
-		struct weston_buffer *buffer = surface->egl_front->buffer_ref.buffer;
+	if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
+		struct weston_buffer *buffer =
+			view->surface->egl_front->buffer_ref.buffer;
 
 		src_width = buffer->width << 16;
 		src_height = buffer->height << 16;
 	} else {
-		src_width = surface->front->width << 16;
-		src_height = surface->front->height << 16;
+		src_width = view->surface->front->width << 16;
+		src_height = view->surface->front->height << 16;
 	}
 
 	weston_matrix_multiply(&matrix, &output->matrix);
@@ -541,7 +599,7 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
 	if (matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE) {
 #endif
 		warn_bad_matrix(&matrix, &output->matrix,
-				&surface->surface->transform.matrix);
+				&view->view->transform.matrix);
 	} else {
 		if (matrix.type & WESTON_MATRIX_TRANSFORM_ROTATE) {
 			if (fabsf(matrix.d[0]) < 1e-4f &&
@@ -552,13 +610,13 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
 				/* no transpose */
 			} else {
 				warn_bad_matrix(&matrix, &output->matrix,
-					&surface->surface->transform.matrix);
+					&view->view->transform.matrix);
 			}
 		}
 	}
 
-	p2.f[0] = surface->surface->geometry.width;
-	p2.f[1] = surface->surface->geometry.height;
+	p2.f[0] = view->view->geometry.width;
+	p2.f[1] = view->view->geometry.height;
 
 	/* transform top-left and bot-right corner into screen coordinates */
 	weston_matrix_transform(&matrix, &p1);
@@ -680,9 +738,9 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
 	src_width = int_max(src_width, 0);
 	src_height = int_max(src_height, 0);
 
-	DBG("rpir_surface %p %dx%d: p1 %f, %f; p2 %f, %f\n", surface,
-	    surface->surface->geometry.width,
-	    surface->surface->geometry.height,
+	DBG("rpir_view %p %dx%d: p1 %f, %f; p2 %f, %f\n", view,
+	    view->view->geometry.width,
+	    view->view->geometry.height,
 	    p1.f[0], p1.f[1], p2.f[0], p2.f[1]);
 	DBG("src rect %d;%d, %d;%d, %d;%dx%d;%d\n",
 	    src_x >> 16, src_x & 0xffff,
@@ -706,7 +764,7 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
 	}
 
 	/* EGL buffers will be upside-down related to what DispmanX expects */
-	if (surface->buffer_type == BUFFER_TYPE_EGL)
+	if (view->surface->buffer_type == BUFFER_TYPE_EGL)
 		flipt ^= TRANSFORM_VFLIP;
 
 	vc_dispmanx_rect_set(src_rect, src_x, src_y, src_width, src_height);
@@ -760,8 +818,8 @@ rpir_surface_get_resource(struct rpir_surface *surface)
 }
 
 static int
-rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
-		    DISPMANX_UPDATE_HANDLE_T update, int layer)
+rpir_view_dmx_add(struct rpir_view *view, struct rpir_output *output,
+		  DISPMANX_UPDATE_HANDLE_T update, int layer)
 {
 	/* Do not use DISPMANX_FLAGS_ALPHA_PREMULT here.
 	 * If you define PREMULT and ALPHA_MIX, the hardware will not
@@ -771,7 +829,7 @@ rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
 	VC_DISPMANX_ALPHA_T alphasetup = {
 		DISPMANX_FLAGS_ALPHA_FROM_SOURCE |
 		DISPMANX_FLAGS_ALPHA_MIX,
-		float2uint8(surface->surface->alpha), /* opacity 0-255 */
+		float2uint8(view->view->alpha), /* opacity 0-255 */
 		0 /* mask resource handle */
 	};
 	VC_RECT_T dst_rect;
@@ -780,18 +838,17 @@ rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
 	int ret;
 	DISPMANX_RESOURCE_HANDLE_T resource_handle;
 
-	resource_handle = rpir_surface_get_resource(surface);
+	resource_handle = rpir_surface_get_resource(view->surface);
 	if (resource_handle == DISPMANX_NO_HANDLE) {
 		weston_log("%s: no buffer yet, aborting\n", __func__);
 		return 0;
 	}
 
-	ret = rpir_surface_compute_rects(surface, &src_rect, &dst_rect,
-					 &flipmask);
+	ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
 	if (ret < 0)
 		return 0;
 
-	surface->handle = vc_dispmanx_element_add(
+	view->handle = vc_dispmanx_element_add(
 		update,
 		output->display,
 		layer,
@@ -802,37 +859,42 @@ rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
 		&alphasetup,
 		NULL /* clamp */,
 		vc_image2dispmanx_transform(flipmask));
-	DBG("rpir_surface %p add %u, alpha %f resource %d\n", surface,
-	    surface->handle, surface->surface->alpha, resource_handle);
+	DBG("rpir_surface %p add %u, alpha %f resource %d\n", view,
+	    view->handle, view->view->alpha, resource_handle);
+
+	if (view->handle == DISPMANX_NO_HANDLE)
+		return -1;
+
+	view->surface->visible_views++;
 
 	return 1;
 }
 
 static void
-rpir_surface_dmx_swap(struct rpir_surface *surface,
-		      DISPMANX_UPDATE_HANDLE_T update)
+rpir_view_dmx_swap(struct rpir_view *view,
+		   DISPMANX_UPDATE_HANDLE_T update)
 {
 	VC_RECT_T rect;
 	pixman_box32_t *r;
 
 	/* XXX: skip, iff resource was not reallocated, and single-buffering */
-	vc_dispmanx_element_change_source(update, surface->handle,
-					  surface->front->handle);
+	vc_dispmanx_element_change_source(update, view->handle,
+					  view->surface->front->handle);
 
 	/* This is current damage now, after rpir_surface_damage() */
-	r = pixman_region32_extents(&surface->prev_damage);
+	r = pixman_region32_extents(&view->surface->prev_damage);
 
 	vc_dispmanx_rect_set(&rect, r->x1, r->y1,
 			     r->x2 - r->x1, r->y2 - r->y1);
-	vc_dispmanx_element_modified(update, surface->handle, &rect);
-	DBG("rpir_surface %p swap\n", surface);
+	vc_dispmanx_element_modified(update, view->handle, &rect);
+	DBG("rpir_view %p swap\n", view);
 }
 
 static int
-rpir_surface_dmx_move(struct rpir_surface *surface,
-		      DISPMANX_UPDATE_HANDLE_T update, int layer)
+rpir_view_dmx_move(struct rpir_view *view,
+		   DISPMANX_UPDATE_HANDLE_T update, int layer)
 {
-	uint8_t alpha = float2uint8(surface->surface->alpha);
+	uint8_t alpha = float2uint8(view->view->alpha);
 	VC_RECT_T dst_rect;
 	VC_RECT_T src_rect;
 	VC_IMAGE_TRANSFORM_T flipmask;
@@ -840,28 +902,27 @@ rpir_surface_dmx_move(struct rpir_surface *surface,
 
 	/* XXX: return early, if all attributes stay the same */
 
-	if (surface->buffer_type == BUFFER_TYPE_EGL) {
+	if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
 		DISPMANX_RESOURCE_HANDLE_T resource_handle;
 
-		resource_handle = rpir_surface_get_resource(surface);
+		resource_handle = rpir_surface_get_resource(view->surface);
 		if (resource_handle == DISPMANX_NO_HANDLE) {
 			weston_log("%s: no buffer yet, aborting\n", __func__);
 			return 0;
 		}
 
 		vc_dispmanx_element_change_source(update,
-						  surface->handle,
+						  view->handle,
 						  resource_handle);
 	}
 
-	ret = rpir_surface_compute_rects(surface, &src_rect, &dst_rect,
-					 &flipmask);
+	ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
 	if (ret < 0)
 		return 0;
 
 	ret = vc_dispmanx_element_change_attributes(
 		update,
-		surface->handle,
+		view->handle,
 		ELEMENT_CHANGE_LAYER |
 			ELEMENT_CHANGE_OPACITY |
 			ELEMENT_CHANGE_TRANSFORM |
@@ -875,7 +936,7 @@ rpir_surface_dmx_move(struct rpir_surface *surface,
 		/* This really is DISPMANX_TRANSFORM_T, no matter
 		 * what the header says. */
 		vc_image2dispmanx_transform(flipmask));
-	DBG("rpir_surface %p move\n", surface);
+	DBG("rpir_view %p move\n", view);
 
 	if (ret)
 		return -1;
@@ -884,15 +945,16 @@ rpir_surface_dmx_move(struct rpir_surface *surface,
 }
 
 static void
-rpir_surface_dmx_remove(struct rpir_surface *surface,
-			DISPMANX_UPDATE_HANDLE_T update)
+rpir_view_dmx_remove(struct rpir_view *view,
+		     DISPMANX_UPDATE_HANDLE_T update)
 {
-	if (surface->handle == DISPMANX_NO_HANDLE)
+	if (view->handle == DISPMANX_NO_HANDLE)
 		return;
 
-	vc_dispmanx_element_remove(update, surface->handle);
-	DBG("rpir_surface %p remove %u\n", surface, surface->handle);
-	surface->handle = DISPMANX_NO_HANDLE;
+	vc_dispmanx_element_remove(update, view->handle);
+	DBG("rpir_view %p remove %u\n", view, view->handle);
+	view->handle = DISPMANX_NO_HANDLE;
+	view->surface->visible_views--;
 }
 
 static void
@@ -900,23 +962,31 @@ rpir_surface_swap_pointers(struct rpir_surface *surface)
 {
 	struct rpi_resource *tmp;
 
-	tmp = surface->front;
-	surface->front = surface->back;
-	surface->back = tmp;
-	surface->need_swap = 0;
+	if (surface->buffer_type == BUFFER_TYPE_EGL) {
+		if (surface->egl_back != NULL) {
+			assert(surface->egl_old_front == NULL);
+			surface->egl_old_front = surface->egl_front;
+			surface->egl_front = surface->egl_back;
+			surface->egl_back = NULL;
+		}
+	} else {
+		tmp = surface->front;
+		surface->front = surface->back;
+		surface->back = tmp;
+	}
 	DBG("new back %p, new front %p\n", surface->back, surface->front);
 }
 
 static int
-is_surface_not_visible(struct weston_surface *surface)
+is_view_not_visible(struct weston_view *view)
 {
 	/* Return true, if surface is guaranteed to be totally obscured. */
 	int ret;
 	pixman_region32_t unocc;
 
 	pixman_region32_init(&unocc);
-	pixman_region32_subtract(&unocc, &surface->transform.boundingbox,
-				 &surface->clip);
+	pixman_region32_subtract(&unocc, &view->transform.boundingbox,
+				 &view->clip);
 	ret = !pixman_region32_not_empty(&unocc);
 	pixman_region32_fini(&unocc);
 
@@ -924,81 +994,55 @@ is_surface_not_visible(struct weston_surface *surface)
 }
 
 static void
-rpir_surface_update(struct rpir_surface *surface, struct rpir_output *output,
-		    DISPMANX_UPDATE_HANDLE_T update, int layer)
+rpir_view_update(struct rpir_view *view, struct rpir_output *output,
+		 DISPMANX_UPDATE_HANDLE_T update, int layer)
 {
-	int need_swap = surface->need_swap;
 	int ret;
 	int obscured;
+	
 
-	if (surface->buffer_type == BUFFER_TYPE_EGL) {
-		if (surface->egl_back != NULL) {
-			assert(surface->egl_old_front == NULL);
-			surface->egl_old_front = surface->egl_front;
-			surface->egl_front = surface->egl_back;
-			surface->egl_back = NULL;
-		}
-		if (surface->egl_front->buffer_ref.buffer == NULL) {
-			weston_log("warning: client unreffed current front buffer\n");
-
-			wl_list_remove(&surface->link);
-			if (surface->handle == DISPMANX_NO_HANDLE) {
-				wl_list_init(&surface->link);
-			} else {
-				rpir_surface_dmx_remove(surface, update);
-				wl_list_insert(&output->surface_cleanup_list,
-						   &surface->link);
-			}
-
-			goto out;
-		}
-	} else {
-		if (need_swap)
-			rpir_surface_swap_pointers(surface);
-	}
-
-	obscured = is_surface_not_visible(surface->surface);
+	obscured = is_view_not_visible(view->view);
 	if (obscured) {
-		DBG("rpir_surface %p totally obscured.\n", surface);
+		DBG("rpir_view %p totally obscured.\n", view);
 
-		wl_list_remove(&surface->link);
-		if (surface->handle == DISPMANX_NO_HANDLE) {
-			wl_list_init(&surface->link);
+		wl_list_remove(&view->link);
+		if (view->handle == DISPMANX_NO_HANDLE) {
+			wl_list_init(&view->link);
 		} else {
-			rpir_surface_dmx_remove(surface, update);
-			wl_list_insert(&output->surface_cleanup_list,
-				       &surface->link);
+			rpir_view_dmx_remove(view, update);
+			wl_list_insert(&output->view_cleanup_list,
+				       &view->link);
 		}
 
 		goto out;
 	}
 
-	if (surface->handle == DISPMANX_NO_HANDLE) {
-		ret = rpir_surface_dmx_add(surface, output, update, layer);
+	if (view->handle == DISPMANX_NO_HANDLE) {
+		ret = rpir_view_dmx_add(view, output, update, layer);
 		if (ret == 0) {
-			wl_list_remove(&surface->link);
-			wl_list_init(&surface->link);
+			wl_list_remove(&view->link);
+			wl_list_init(&view->link);
 		} else if (ret < 0) {
-			weston_log("ERROR rpir_surface_dmx_add() failed.\n");
+			weston_log("ERROR rpir_view_dmx_add() failed.\n");
 		}
 	} else {
-		if (need_swap)
-			rpir_surface_dmx_swap(surface, update);
+		if (view->surface->need_swap)
+			rpir_view_dmx_swap(view, update);
 
-		ret = rpir_surface_dmx_move(surface, update, layer);
+		ret = rpir_view_dmx_move(view, update, layer);
 		if (ret == 0) {
-			rpir_surface_dmx_remove(surface, update);
+			rpir_view_dmx_remove(view, update);
 
-			wl_list_remove(&surface->link);
-			wl_list_insert(&output->surface_cleanup_list,
-				       &surface->link);
+			wl_list_remove(&view->link);
+			wl_list_insert(&output->view_cleanup_list,
+				       &view->link);
 		} else if (ret < 0) {
-			weston_log("ERROR rpir_surface_dmx_move() failed.\n");
+			weston_log("ERROR rpir_view_dmx_move() failed.\n");
 		}
 	}
 
 out:
-	surface->layer = layer;
+	view->layer = layer;
 }
 
 static int
@@ -1105,15 +1149,15 @@ static void
 rpir_output_dmx_remove_all(struct rpir_output *output,
 			   DISPMANX_UPDATE_HANDLE_T update)
 {
-	struct rpir_surface *surface;
+	struct rpir_view *view;
 
-	while (!wl_list_empty(&output->surface_list)) {
-		surface = container_of(output->surface_list.next,
-				       struct rpir_surface, link);
-		rpir_surface_dmx_remove(surface, update);
+	while (!wl_list_empty(&output->view_list)) {
+		view = container_of(output->view_list.next,
+				    struct rpir_view, link);
+		rpir_view_dmx_remove(view, update);
 
-		wl_list_remove(&surface->link);
-		wl_list_insert(&output->surface_cleanup_list, &surface->link);
+		wl_list_remove(&view->link);
+		wl_list_insert(&output->view_cleanup_list, &view->link);
 	}
 }
 
@@ -1186,8 +1230,8 @@ rpi_renderer_repaint_output(struct weston_output *base,
 {
 	struct weston_compositor *compositor = base->compositor;
 	struct rpir_output *output = to_rpir_output(base);
-	struct weston_surface *ws;
-	struct rpir_surface *surface;
+	struct weston_view *wv;
+	struct rpir_view *view;
 	struct wl_list done_list;
 	int layer = 1;
 
@@ -1199,27 +1243,59 @@ rpi_renderer_repaint_output(struct weston_output *base,
 	free(output->capture_data);
 	output->capture_data = NULL;
 
+	/* Swap resources on surfaces as needed */
+	wl_list_for_each_reverse(wv, &compositor->view_list, link)
+		wv->surface->touched = 0;
+
+	wl_list_for_each_reverse(wv, &compositor->view_list, link) {
+		view = to_rpir_view(wv);
+
+		if (!wv->surface->touched) {
+			wv->surface->touched = 1;
+
+			if (view->surface->need_swap)
+				rpir_surface_swap_pointers(view->surface);
+		}
+
+		if (view->surface->egl_front->buffer_ref.buffer == NULL) {
+			weston_log("warning: client unreffed current front buffer\n");
+
+			wl_list_remove(&view->link);
+			if (view->handle == DISPMANX_NO_HANDLE) {
+				wl_list_init(&view->link);
+			} else {
+				rpir_view_dmx_remove(view, output->update);
+				wl_list_insert(&output->view_cleanup_list,
+					       &view->link);
+			}
+		}
+	}
+
 	/* update all renderable surfaces */
 	wl_list_init(&done_list);
-	wl_list_for_each_reverse(ws, &compositor->surface_list, link) {
-		if (ws->plane != &compositor->primary_plane)
+	wl_list_for_each_reverse(wv, &compositor->view_list, link) {
+		if (wv->plane != &compositor->primary_plane)
 			continue;
 
-		surface = to_rpir_surface(ws);
-		assert(!wl_list_empty(&surface->link) ||
-		       surface->handle == DISPMANX_NO_HANDLE);
+		view = to_rpir_view(wv);
+		assert(!wl_list_empty(&view->link) ||
+		       view->handle == DISPMANX_NO_HANDLE);
 
-		wl_list_remove(&surface->link);
-		wl_list_insert(&done_list, &surface->link);
-		rpir_surface_update(surface, output, output->update, layer++);
+		wl_list_remove(&view->link);
+		wl_list_insert(&done_list, &view->link);
+		rpir_view_update(view, output, output->update, layer++);
 	}
 
+	/* Mark all surfaces as swapped */
+	wl_list_for_each_reverse(wv, &compositor->view_list, link)
+		to_rpir_surface(wv->surface)->need_swap = 0;
+
 	/* Remove all surfaces that are still on screen, but were
 	 * not rendered this time.
 	 */
 	rpir_output_dmx_remove_all(output, output->update);
 
-	wl_list_insert_list(&output->surface_list, &done_list);
+	wl_list_insert_list(&output->view_list, &done_list);
 	output->update = DISPMANX_NO_HANDLE;
 
 	/* The frame_signal is emitted in rpi_renderer_finish_frame(),
@@ -1263,7 +1339,7 @@ rpi_renderer_attach(struct weston_surface *base, struct weston_buffer *buffer)
 			/* XXX: need to check if in middle of update */
 			rpi_resource_release(surface->back);
 
-		if (surface->handle == DISPMANX_NO_HANDLE)
+		if (!surface->visible_views)
 			/* XXX: cannot do this, if middle of an update */
 			rpi_resource_release(surface->front);
 
@@ -1336,6 +1412,23 @@ rpi_renderer_create_surface(struct weston_surface *base)
 	return 0;
 }
 
+static int
+rpi_renderer_create_view(struct weston_view *base)
+{
+	struct rpir_surface *surface = to_rpir_surface(base->surface);
+	struct rpir_view *view;
+
+	assert(base->renderer_state == NULL);
+
+	view = rpir_view_create(surface);
+	if (!view)
+		return -1;
+
+	view->view = base;
+	base->renderer_state = view;
+	return 0;
+}
+
 static void
 rpi_renderer_surface_set_color(struct weston_surface *base,
 			       float red, float green, float blue, float alpha)
@@ -1390,13 +1483,27 @@ rpi_renderer_destroy_surface(struct weston_surface *base)
 	surface->surface = NULL;
 	base->renderer_state = NULL;
 
-	/* If guaranteed to not be on screen, just detroy it. */
-	if (wl_list_empty(&surface->link))
+	if (wl_list_empty(&surface->views))
 		rpir_surface_destroy(surface);
+}
 
-	/* Otherwise, the surface is either on screen and needs
+static void
+rpi_renderer_destroy_view(struct weston_view *base)
+{
+	struct rpir_view *view = to_rpir_view(base);
+
+	assert(view);
+	assert(view->view == base);
+	if (!view)
+		return;
+
+	/* If guaranteed to not be on screen, just detroy it. */
+	if (wl_list_empty(&view->link))
+		rpir_view_destroy(view);
+
+	/* Otherwise, the view is either on screen and needs
 	 * to be removed by a repaint update, or it is in the
-	 * surface_cleanup_list, and will be destroyed by
+	 * view_cleanup_list, and will be destroyed by
 	 * rpi_renderer_finish_frame().
 	 */
 }
@@ -1440,8 +1547,10 @@ rpi_renderer_create(struct weston_compositor *compositor,
 	renderer->base.flush_damage = rpi_renderer_flush_damage;
 	renderer->base.attach = rpi_renderer_attach;
 	renderer->base.create_surface = rpi_renderer_create_surface;
+	renderer->base.create_view = rpi_renderer_create_view;
 	renderer->base.surface_set_color = rpi_renderer_surface_set_color;
 	renderer->base.destroy_surface = rpi_renderer_destroy_surface;
+	renderer->base.destroy_view = rpi_renderer_destroy_view;
 	renderer->base.destroy = rpi_renderer_destroy;
 
 #ifdef ENABLE_EGL
@@ -1504,8 +1613,8 @@ rpi_renderer_output_create(struct weston_output *base,
 
 	output->display = display;
 	output->update = DISPMANX_NO_HANDLE;
-	wl_list_init(&output->surface_list);
-	wl_list_init(&output->surface_cleanup_list);
+	wl_list_init(&output->view_list);
+	wl_list_init(&output->view_cleanup_list);
 	rpi_resource_init(&output->capture_buffer);
 	base->renderer_state = output;
 
@@ -1516,7 +1625,7 @@ WL_EXPORT void
 rpi_renderer_output_destroy(struct weston_output *base)
 {
 	struct rpir_output *output = to_rpir_output(base);
-	struct rpir_surface *surface;
+	struct rpir_view *view;
 	DISPMANX_UPDATE_HANDLE_T update;
 
 	rpi_resource_release(&output->capture_buffer);
@@ -1527,12 +1636,10 @@ rpi_renderer_output_destroy(struct weston_output *base)
 	rpir_output_dmx_remove_all(output, update);
 	vc_dispmanx_update_submit_sync(update);
 
-	while (!wl_list_empty(&output->surface_cleanup_list)) {
-		surface = container_of(output->surface_cleanup_list.next,
-				       struct rpir_surface, link);
-		if (surface->surface)
-			surface->surface->renderer_state = NULL;
-		rpir_surface_destroy(surface);
+	while (!wl_list_empty(&output->view_cleanup_list)) {
+		view = container_of(output->view_cleanup_list.next,
+				    struct rpir_view, link);
+		rpir_view_destroy(view);
 	}
 
 	free(output);
@@ -1553,41 +1660,41 @@ rpi_renderer_finish_frame(struct weston_output *base)
 {
 	struct rpir_output *output = to_rpir_output(base);
 	struct weston_compositor *compositor = base->compositor;
-	struct weston_surface *ws;
-	struct rpir_surface *surface;
+	struct weston_view *wv;
+	struct rpir_view *view;
 
-	while (!wl_list_empty(&output->surface_cleanup_list)) {
-		surface = container_of(output->surface_cleanup_list.next,
-				       struct rpir_surface, link);
+	while (!wl_list_empty(&output->view_cleanup_list)) {
+		view = container_of(output->view_cleanup_list.next,
+				    struct rpir_view, link);
 
-		if (surface->surface) {
-			/* The weston_surface still exists, but is
+		if (view->view) {
+			/* The weston_view still exists, but is
 			 * temporarily not visible, and hence its Element
 			 * was removed. The current front buffer contents
 			 * must be preserved.
 			 */
-			if (!surface->single_buffer)
-				rpi_resource_release(surface->back);
+			if (!view->surface->visible_views)
+				rpi_resource_release(view->surface->back);
 
-			wl_list_remove(&surface->link);
-			wl_list_init(&surface->link);
+			wl_list_remove(&view->link);
+			wl_list_init(&view->link);
 		} else {
-			rpir_surface_destroy(surface);
+			rpir_view_destroy(view);
 		}
 	}
 
-	wl_list_for_each(ws, &compositor->surface_list, link) {
-		surface = to_rpir_surface(ws);
+	wl_list_for_each(wv, &compositor->view_list, link) {
+		view = to_rpir_view(wv);
 
-		if (surface->buffer_type != BUFFER_TYPE_EGL)
+		if (view->surface->buffer_type != BUFFER_TYPE_EGL)
 			continue;
 
-		if(surface->egl_old_front == NULL)
+		if (view->surface->egl_old_front == NULL)
 			continue;
 
-		weston_buffer_reference(&surface->egl_old_front->buffer_ref, NULL);
-		free(surface->egl_old_front);
-		surface->egl_old_front = NULL;
+		weston_buffer_reference(&view->surface->egl_old_front->buffer_ref, NULL);
+		free(view->surface->egl_old_front);
+		view->surface->egl_old_front = NULL;
 	}
 
 	wl_signal_emit(&base->frame_signal, base);
-- 
1.8.3.1



More information about the wayland-devel mailing list