[PATCH 5/7] compositor-drm: Add option to start with pixman and switch to GL later

Ander Conselvan de Oliveira ander.conselvan.de.oliveira at intel.com
Fri Oct 25 15:26:35 CEST 2013


Option --fast-start will cause the backend to start using the pixman
renderer and at the same time spawn a thread to do the loading of the
gl renderer and creation of the gbm device (which loads a dri driver).
Once that thread signal it is done, a runtime switch to the gl renderer
happens.
---
 man/weston-drm.man   |    5 ++
 src/compositor-drm.c |  153 +++++++++++++++++++++++++++++++++++++++++++++++---
 src/compositor.c     |    1 +
 src/gl-renderer.c    |    6 ++
 4 files changed, 156 insertions(+), 9 deletions(-)

diff --git a/man/weston-drm.man b/man/weston-drm.man
index 35d62ae..035bace 100644
--- a/man/weston-drm.man
+++ b/man/weston-drm.man
@@ -106,6 +106,11 @@ instead of the default seat
 Launch Weston on tty
 .I x
 instead of using the current tty.
+.TP
+.B \-\-fast\-start
+Start using the pixman renderer and later switch to the GL one. This
+should cause the system to able to render earlier when running from
+cold boot and slow storage.
 .
 .\" ***************************************************************
 .SH ENVIRONMENT
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index b929728..96065bd 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -51,6 +51,10 @@
 #include "launcher-util.h"
 #include "vaapi-recorder.h"
 
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
 #ifndef DRM_CAP_TIMESTAMP_MONOTONIC
 #define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
 #endif
@@ -108,6 +112,10 @@ struct drm_compositor {
 
 	clockid_t clock;
 	struct udev_input input;
+
+	pthread_t gl_loader_thread;
+	struct wl_event_source *gl_loader_thread_ev_source;
+	int gl_loader_fd;
 };
 
 struct drm_mode {
@@ -199,6 +207,7 @@ struct drm_parameters {
 	int connector;
 	int tty;
 	int use_pixman;
+	int fast_start;
 	const char *seat_id;
 };
 
@@ -596,7 +605,8 @@ drm_output_repaint(struct weston_output *output_base,
 		return -1;
 
 	mode = container_of(output->base.current_mode, struct drm_mode, base);
-	if (!output->current) {
+	if (!output->current ||
+	    output->current->stride != output->next->stride) {
 		ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
 				     output->next->fb_id, 0, 0,
 				     &output->connector_id, 1,
@@ -1281,15 +1291,15 @@ init_drm(struct drm_compositor *ec, struct udev_device *device)
 	return 0;
 }
 
-static int
-init_egl(struct drm_compositor *ec)
+static struct gbm_device *
+create_gbm_device(int fd)
 {
-	EGLint format;
+	struct gbm_device *gbm;
 
 	gl_renderer = weston_load_module("gl-renderer.so",
 					 "gl_renderer_interface");
 	if (!gl_renderer)
-		return -1;
+		return NULL;
 
 	/* GBM will load a dri driver, but even though they need symbols from
 	 * libglapi, in some version of Mesa they are not linked to it. Since
@@ -1298,14 +1308,34 @@ init_egl(struct drm_compositor *ec)
 	 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
 	dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
 
-	ec->gbm = gbm_create_device(ec->drm.fd);
+	gbm = gbm_create_device(fd);
 
-	if (!ec->gbm)
-		return -1;
+	return gbm;
+}
+
+static int
+drm_compositor_create_gl_renderer(struct drm_compositor *ec)
+{
+	EGLint format;
 
 	format = ec->format;
 	if (gl_renderer->create(&ec->base, ec->gbm,
 			       gl_renderer->opaque_attribs, &format) < 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+init_egl(struct drm_compositor *ec)
+{
+	ec->gbm = create_gbm_device(ec->drm.fd);
+
+	if (!ec->gbm)
+		return -1;
+
+	if (drm_compositor_create_gl_renderer(ec) < 0) {
 		gbm_device_destroy(ec->gbm);
 		return -1;
 	}
@@ -2580,6 +2610,107 @@ recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
 }
 #endif
 
+static void
+switch_to_gl_renderer(struct drm_compositor *c)
+{
+	struct drm_output *output;
+
+	if (!c->use_pixman)
+		return;
+
+	weston_log("Switching to GL renderer\n");
+
+	wl_list_for_each(output, &c->base.output_list, base.link)
+		pixman_renderer_output_destroy(&output->base);
+
+	c->base.renderer->destroy(&c->base);
+
+	if (drm_compositor_create_gl_renderer(c) < 0) {
+		gbm_device_destroy(c->gbm);
+		weston_log("Failed to create GL renderer. Quitting.\n");
+		/* FIXME: we need a function to shutdown cleanly */
+		assert(0);
+	}
+
+	wl_list_for_each(output, &c->base.output_list, base.link)
+		drm_output_init_egl(output, c);
+
+	c->use_pixman = 0;
+}
+
+struct gl_loader_thread_data {
+	int drm_fd;
+	int done_fd;
+};
+
+static void *
+gl_loader_thread_func(void *data)
+{
+	struct gl_loader_thread_data *gl_data = data;
+	struct gbm_device *gbm;
+
+	gbm = create_gbm_device(gl_data->drm_fd);
+
+	if (write(gl_data->done_fd, "done", 4) != 4)
+		weston_log("Failed to notify completion of gl-renderer load.");
+
+	close(gl_data->done_fd);
+	free(gl_data);
+
+	return gbm;
+}
+
+static int
+gl_loader_thread_done(int fd, uint32_t mask, void *data)
+{
+	struct drm_compositor *c = data;
+	struct gbm_device *gbm;
+
+	pthread_join(c->gl_loader_thread, (void **) &gbm);
+	if (!gbm) {
+		weston_log("Failed to create GBM device, "
+			   "continuing with pixman renderer.\n");
+		goto done;
+	}
+
+	c->gbm = gbm;
+	switch_to_gl_renderer(c);
+
+done:
+	close(c->gl_loader_fd);
+	wl_event_source_remove(c->gl_loader_thread_ev_source);
+	return 1;
+}
+
+static int
+prepare_renderer_switch(struct drm_compositor *ec)
+{
+	struct gl_loader_thread_data *gl_data;
+	struct wl_event_loop *loop;
+	int sv[2];
+
+	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0)
+		return -1;
+
+	gl_data = malloc(sizeof *gl_data);
+	if (!gl_data)
+		return -1;
+
+	gl_data->drm_fd = ec->drm.fd;
+	gl_data->done_fd = sv[1];
+
+	pthread_create(&ec->gl_loader_thread, NULL,
+		       gl_loader_thread_func, gl_data);
+
+	loop = wl_display_get_event_loop(ec->base.wl_display);
+	ec->gl_loader_thread_ev_source =
+		wl_event_loop_add_fd(loop, sv[0], WL_EVENT_READABLE,
+				     gl_loader_thread_done, ec);
+	ec->gl_loader_fd = sv[0];
+
+	return 0;
+}
+
 static struct weston_compositor *
 drm_compositor_create(struct wl_display *display,
 		      struct drm_parameters *param,
@@ -2620,7 +2751,7 @@ drm_compositor_create(struct wl_display *display,
 	}
 	free(s);
 
-	ec->use_pixman = param->use_pixman;
+	ec->use_pixman = param->use_pixman || param->fast_start;
 
 	if (weston_compositor_init(&ec->base, display, argc, argv,
 				   config) < 0) {
@@ -2660,6 +2791,9 @@ drm_compositor_create(struct wl_display *display,
 	}
 
 	if (ec->use_pixman) {
+		if (param->fast_start)
+			prepare_renderer_switch(ec);
+
 		if (init_pixman(ec) < 0) {
 			weston_log("failed to initialize pixman renderer\n");
 			goto err_udev_dev;
@@ -2767,6 +2901,7 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
 		{ WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
 		{ WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
 		{ WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
+		{ WESTON_OPTION_BOOLEAN, "fast-start", 0, &param.fast_start },
 	};
 
 	param.seat_id = default_seat;
diff --git a/src/compositor.c b/src/compositor.c
index 563bade..d11f765 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -3600,6 +3600,7 @@ usage(int error_code)
 		"  --seat=SEAT\t\tThe seat that weston should run on\n"
 		"  --tty=TTY\t\tThe tty to use\n"
 		"  --use-pixman\t\tUse the pixman (CPU) renderer\n"
+		"  --fast-start\t\tStart with pixman renderer and later switch to GL\n"
 		"  --current-mode\tPrefer current KMS mode over EDID preferred mode\n\n");
 
 	fprintf(stderr,
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index c3c6ae9..06815b4 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -509,6 +509,12 @@ draw_view(struct weston_view *ev, struct weston_output *output,
 	GLint filter;
 	int i;
 
+	/* In case of a runtime switch of renderers, we may not have received
+	 * an attach for this surface since the switch. In that case we don't
+	 * have a valid buffer or a proper shader set up so skip rendering. */
+	if (!gs->shader)
+		return;
+
 	pixman_region32_init(&repaint);
 	pixman_region32_intersect(&repaint,
 				  &ev->transform.boundingbox, damage);
-- 
1.7.9.5



More information about the wayland-devel mailing list