[PATCH 6/9] nested: Add a ‘renderer’ mechanism with a vtable

Neil Roberts neil at linux.intel.com
Mon Sep 9 08:41:42 PDT 2013


Eventually the nested compositor example will want to be able to cope
with either rendering as it does now with a blit to an intermediate
surface or by attaching the client buffers directly to a subsurface
without copying. This patch moves the code that is specific to the
blitting mechanism into a separate set of functions with a vtable to
make it easier to add the second way of rendering in a later patch.
---
 clients/nested.c | 218 +++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 147 insertions(+), 71 deletions(-)

diff --git a/clients/nested.c b/clients/nested.c
index 6f68474..d229a9b 100644
--- a/clients/nested.c
+++ b/clients/nested.c
@@ -58,6 +58,8 @@ struct nested {
 	struct program *texture_program;
 
 	struct wl_list surface_list;
+
+	const struct nested_renderer *renderer;
 };
 
 struct nested_region {
@@ -79,12 +81,9 @@ struct nested_buffer_reference {
 
 struct nested_surface {
 	struct wl_resource *resource;
-	struct nested_buffer_reference buffer_ref;
 	struct nested *nested;
 	EGLImageKHR *image;
-	GLuint texture;
 	struct wl_list link;
-	cairo_surface_t *cairo_surface;
 
 	struct wl_list frame_callback_list;
 
@@ -100,6 +99,15 @@ struct nested_surface {
 		/* wl_surface.damage */
 		pixman_region32_t damage;
 	} pending;
+
+	void *renderer_data;
+};
+
+/* Data used for the blit renderer */
+struct nested_blit_surface {
+	struct nested_buffer_reference buffer_ref;
+	GLuint texture;
+	cairo_surface_t *cairo_surface;
 };
 
 struct nested_frame_callback {
@@ -107,6 +115,16 @@ struct nested_frame_callback {
 	struct wl_list link;
 };
 
+struct nested_renderer {
+	void (* surface_init)(struct nested_surface *surface);
+	void (* surface_fini)(struct nested_surface *surface);
+	void (* render_clients)(struct nested *nested, cairo_t *cr);
+	void (* surface_attach)(struct nested_surface *surface,
+				struct nested_buffer *buffer);
+};
+
+static const struct nested_renderer nested_blit_renderer;
+
 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
 static PFNEGLCREATEIMAGEKHRPROC create_image;
 static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
@@ -209,31 +227,12 @@ flush_surface_frame_callback_list (struct nested_surface *surface,
 }
 
 static void
-frame_callback(void *data, struct wl_callback *callback, uint32_t time)
-{
-	struct nested *nested = data;
-	struct nested_surface *surface;
-
-	wl_list_for_each(surface, &nested->surface_list, link)
-		flush_surface_frame_callback_list(surface, time);
-
-	if (callback)
-		wl_callback_destroy(callback);
-}
-
-static const struct wl_callback_listener frame_listener = {
-	frame_callback
-};
-
-static void
 redraw_handler(struct widget *widget, void *data)
 {
 	struct nested *nested = data;
 	cairo_surface_t *surface;
 	cairo_t *cr;
 	struct rectangle allocation;
-	struct wl_callback *callback;
-	struct nested_surface *s;
 
 	widget_get_allocation(nested->widget, &allocation);
 
@@ -249,34 +248,11 @@ redraw_handler(struct widget *widget, void *data)
 	cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
 	cairo_fill(cr);
 
-	wl_list_for_each(s, &nested->surface_list, link) {
-		display_acquire_window_surface(nested->display,
-					       nested->window, NULL);
-
-		glBindTexture(GL_TEXTURE_2D, s->texture);
-		image_target_texture_2d(GL_TEXTURE_2D, s->image);
-
-		display_release_window_surface(nested->display,
-					       nested->window);
-
-		cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-		cairo_set_source_surface(cr, s->cairo_surface,
-					 allocation.x + 10,
-					 allocation.y + 10);
-		cairo_rectangle(cr, allocation.x + 10,
-				allocation.y + 10,
-				allocation.width - 10,
-				allocation.height - 10);
-
-		cairo_fill(cr);
-	}
+	nested->renderer->render_clients(nested, cr);
 
 	cairo_destroy(cr);
 
 	cairo_surface_destroy(surface);
-
-	callback = wl_surface_frame(window_get_wl_surface(nested->window));
-	wl_callback_add_listener(callback, &frame_listener, nested);
 }
 
 static void
@@ -374,6 +350,7 @@ static void
 destroy_surface(struct wl_resource *resource)
 {
 	struct nested_surface *surface = wl_resource_get_user_data(resource);
+	struct nested *nested = surface->nested;
 	struct nested_frame_callback *cb, *next;
 
 	wl_list_for_each_safe(cb, next,
@@ -384,10 +361,10 @@ destroy_surface(struct wl_resource *resource)
 			      &surface->pending.frame_callback_list, link)
 		wl_resource_destroy(cb->resource);
 
-	nested_buffer_reference(&surface->buffer_ref, NULL);
-
 	pixman_region32_fini(&surface->pending.damage);
 
+	nested->renderer->surface_fini(surface);
+
 	free(surface);
 }
 
@@ -451,15 +428,9 @@ nested_surface_attach(struct nested_surface *surface,
 		      struct nested_buffer *buffer)
 {
 	struct nested *nested = surface->nested;
-	EGLint width, height;
-	cairo_device_t *device;
-
-	nested_buffer_reference(&surface->buffer_ref, buffer);
 
 	if (surface->image != EGL_NO_IMAGE_KHR)
 		destroy_image(nested->egl_display, surface->image);
-	if (surface->cairo_surface)
-		cairo_surface_destroy(surface->cairo_surface);
 
 	surface->image = create_image(nested->egl_display, NULL,
 				      EGL_WAYLAND_BUFFER_WL, buffer->resource,
@@ -469,17 +440,7 @@ nested_surface_attach(struct nested_surface *surface,
 		return;
 	}
 
-	query_buffer(nested->egl_display, buffer->resource,
-		     EGL_WIDTH, &width);
-	query_buffer(nested->egl_display, buffer->resource,
-		     EGL_HEIGHT, &height);
-
-	device = display_get_cairo_device(nested->display);
-	surface->cairo_surface = 
-		cairo_gl_surface_create_for_texture(device,
-						    CAIRO_CONTENT_COLOR_ALPHA,
-						    surface->texture,
-						    width, height);
+	nested->renderer->surface_attach(surface, buffer);
 }
 
 static void
@@ -628,12 +589,7 @@ compositor_create_surface(struct wl_client *client,
 	display_acquire_window_surface(nested->display,
 				       nested->window, NULL);
 
-	glGenTextures(1, &surface->texture);
-	glBindTexture(GL_TEXTURE_2D, surface->texture);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	nested->renderer->surface_init(surface);
 
 	display_release_window_surface(nested->display, nested->window);
 
@@ -771,6 +727,8 @@ nested_init_compositor(struct nested *nested)
 		return -1;
 	}
 
+	nested->renderer = &nested_blit_renderer;
+
 	return 0;
 }
 
@@ -808,6 +766,124 @@ nested_destroy(struct nested *nested)
 	free(nested);
 }
 
+static void
+blit_surface_init(struct nested_surface *surface)
+{
+	struct nested_blit_surface *blit_surface =
+		zalloc(sizeof *blit_surface);
+
+	glGenTextures(1, &blit_surface->texture);
+	glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+	surface->renderer_data = blit_surface;
+}
+
+static void
+blit_surface_fini(struct nested_surface *surface)
+{
+	struct nested_blit_surface *blit_surface = surface->renderer_data;
+
+	nested_buffer_reference(&blit_surface->buffer_ref, NULL);
+
+	glDeleteTextures(1, &blit_surface->texture);
+
+	free(blit_surface);
+}
+
+static void
+blit_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
+{
+	struct nested *nested = data;
+	struct nested_surface *surface;
+
+	wl_list_for_each(surface, &nested->surface_list, link)
+		flush_surface_frame_callback_list(surface, time);
+
+	if (callback)
+		wl_callback_destroy(callback);
+}
+
+static const struct wl_callback_listener blit_frame_listener = {
+	blit_frame_callback
+};
+
+static void
+blit_render_clients(struct nested *nested,
+		    cairo_t *cr)
+{
+	struct nested_surface *s;
+	struct rectangle allocation;
+	struct wl_callback *callback;
+
+	widget_get_allocation(nested->widget, &allocation);
+
+	wl_list_for_each(s, &nested->surface_list, link) {
+		struct nested_blit_surface *blit_surface = s->renderer_data;
+
+		display_acquire_window_surface(nested->display,
+					       nested->window, NULL);
+
+		glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
+		image_target_texture_2d(GL_TEXTURE_2D, s->image);
+
+		display_release_window_surface(nested->display,
+					       nested->window);
+
+		cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+		cairo_set_source_surface(cr, blit_surface->cairo_surface,
+					 allocation.x + 10,
+					 allocation.y + 10);
+		cairo_rectangle(cr, allocation.x + 10,
+				allocation.y + 10,
+				allocation.width - 10,
+				allocation.height - 10);
+
+		cairo_fill(cr);
+	}
+
+	callback = wl_surface_frame(window_get_wl_surface(nested->window));
+	wl_callback_add_listener(callback, &blit_frame_listener, nested);
+}
+
+static void
+blit_surface_attach(struct nested_surface *surface,
+		    struct nested_buffer *buffer)
+{
+	struct nested *nested = surface->nested;
+	struct nested_blit_surface *blit_surface = surface->renderer_data;
+	EGLint width, height;
+	cairo_device_t *device;
+
+	nested_buffer_reference(&blit_surface->buffer_ref, buffer);
+
+	if (blit_surface->cairo_surface)
+		cairo_surface_destroy(blit_surface->cairo_surface);
+
+	query_buffer(nested->egl_display, buffer->resource,
+		     EGL_WIDTH, &width);
+	query_buffer(nested->egl_display, buffer->resource,
+		     EGL_HEIGHT, &height);
+
+	device = display_get_cairo_device(nested->display);
+	blit_surface->cairo_surface =
+		cairo_gl_surface_create_for_texture(device,
+						    CAIRO_CONTENT_COLOR_ALPHA,
+						    blit_surface->texture,
+						    width, height);
+}
+
+static const struct nested_renderer
+nested_blit_renderer = {
+	.surface_init = blit_surface_init,
+	.surface_fini = blit_surface_fini,
+	.render_clients = blit_render_clients,
+	.surface_attach = blit_surface_attach
+};
+
 int
 main(int argc, char *argv[])
 {
-- 
1.8.3.1



More information about the wayland-devel mailing list