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, ¶m.tty }, { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode }, { WESTON_OPTION_BOOLEAN, "use-pixman", 0, ¶m.use_pixman }, + { WESTON_OPTION_BOOLEAN, "fast-start", 0, ¶m.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 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel