gl-renderer: Build as a loadable module
The time spent loading EGL and GLES libraries from disk can be a
considerable hit in some embedded use cases. If Weston is compiled
with EGL support, the binary will depend on those libraries, even if
a software renderer is in use.
This patch splits the GL renderer into a separate loadable module,
and moves the dependency on EGL and GLES to it. The backends still
need the EGL headers for the native types and EGLint. The function
load_module() is renamed to weston_load_module() and exported, so
that it can be used by the backends.
The gl renderer interface is changed so that there is only one symbol
that needs to be dlsym()'d. This symbol contains pointers to all the
functions and data necessary to interact with the renderer. As a side
effect, this change simplifies gl-renderer.h a great deal.
diff --git a/src/Makefile.am b/src/Makefile.am
index 749c074..b0eae7c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -40,7 +40,6 @@
subsurface-server-protocol.h \
bindings.c \
animation.c \
- gl-renderer.h \
noop-renderer.c \
pixman-renderer.c \
pixman-renderer.h \
@@ -50,13 +49,6 @@
weston-launch.h \
weston-egl-ext.h
-if ENABLE_EGL
-weston_SOURCES += \
- gl-renderer.c \
- vertex-clipping.c \
- vertex-clipping.h
-endif
-
git-version.h : .FORCE
$(AM_V_GEN)(echo "#define BUILD_ID \"$(shell git --git-dir=$(top_srcdir)/.git describe --always --dirty) $(shell git --git-dir=$(top_srcdir)/.git log -1 --format='%s (%ci)')\"" > $@-new; \
cmp -s $@ $@-new || cp $@-new $@; \
@@ -104,6 +96,7 @@
$(tablet_shell) \
$(cms_static) \
$(cms_colord) \
+ $(gl_renderer) \
$(x11_backend) \
$(drm_backend) \
$(wayland_backend) \
@@ -119,6 +112,21 @@
noinst_LTLIBRARIES += $(rpi_backend)
endif
+if ENABLE_EGL
+gl_renderer = gl-renderer.la
+gl_renderer_la_LDFLAGS = -module -avoid-version
+gl_renderer_la_LIBADD = $(COMPOSITOR_LIBS) $(EGL_LIBS)
+gl_renderer_la_CFLAGS = \
+ $(COMPOSITOR_CFLAGS) \
+ $(EGL_CFLAGS) \
+ $(GCC_CFLAGS)
+gl_renderer_la_SOURCES = \
+ gl-renderer.h \
+ gl-renderer.c \
+ vertex-clipping.c \
+ vertex-clipping.h
+endif
+
if ENABLE_X11_COMPOSITOR
x11_backend = x11-backend.la
x11_backend_la_LDFLAGS = -module -avoid-version
@@ -126,6 +134,7 @@
../shared/libshared-cairo.la
x11_backend_la_CFLAGS = \
$(COMPOSITOR_CFLAGS) \
+ $(EGL_CFLAGS) \
$(PIXMAN_CFLAGS) \
$(CAIRO_CFLAGS) \
$(X11_COMPOSITOR_CFLAGS) \
@@ -140,6 +149,7 @@
../shared/libshared.la -lrt
drm_backend_la_CFLAGS = \
$(COMPOSITOR_CFLAGS) \
+ $(EGL_CFLAGS) \
$(DRM_COMPOSITOR_CFLAGS) \
$(GCC_CFLAGS)
drm_backend_la_SOURCES = \
@@ -168,6 +178,7 @@
../shared/libshared-cairo.la
wayland_backend_la_CFLAGS = \
$(COMPOSITOR_CFLAGS) \
+ $(EGL_CFLAGS) \
$(PIXMAN_CFLAGS) \
$(CAIRO_CFLAGS) \
$(WAYLAND_COMPOSITOR_CFLAGS) \
@@ -219,6 +230,7 @@
../shared/libshared.la
fbdev_backend_la_CFLAGS = \
$(COMPOSITOR_CFLAGS) \
+ $(EGL_CFLAGS) \
$(FBDEV_COMPOSITOR_CFLAGS) \
$(PIXMAN_CFLAGS) \
$(GCC_CFLAGS)
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index ad5a2c3..25c34f8 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -33,6 +33,7 @@
#include <linux/vt.h>
#include <assert.h>
#include <sys/mman.h>
+#include <dlfcn.h>
#include <time.h>
#include <xf86drm.h>
@@ -194,6 +195,8 @@
uint32_t formats[];
};
+static struct gl_renderer_interface *gl_renderer;
+
static const char default_seat[] = "seat0";
static void
@@ -1101,7 +1104,7 @@
if (c->use_pixman) {
drm_output_fini_pixman(output);
} else {
- gl_renderer_output_destroy(output_base);
+ gl_renderer->output_destroy(output_base);
gbm_surface_destroy(output->surface);
}
@@ -1192,7 +1195,7 @@
return -1;
}
} else {
- gl_renderer_output_destroy(&output->base);
+ gl_renderer->output_destroy(&output->base);
gbm_surface_destroy(output->surface);
if (drm_output_init_egl(output, ec) < 0) {
@@ -1262,14 +1265,26 @@
{
EGLint format;
+ gl_renderer = weston_load_module("gl-renderer.so",
+ "gl_renderer_interface");
+ if (!gl_renderer)
+ return -1;
+
+ /* 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
+ * only the gl-renderer module links to it, the call above won't make
+ * these symbols globally available, and loading the DRI driver fails.
+ * 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);
if (!ec->gbm)
return -1;
format = ec->format;
- if (gl_renderer_create(&ec->base, ec->gbm,
- gl_renderer_opaque_attribs, &format) < 0) {
+ if (gl_renderer->create(&ec->base, ec->gbm,
+ gl_renderer->opaque_attribs, &format) < 0) {
gbm_device_destroy(ec->gbm);
return -1;
}
@@ -1471,7 +1486,7 @@
return -1;
}
- if (gl_renderer_output_create(&output->base, output->surface) < 0) {
+ if (gl_renderer->output_create(&output->base, output->surface) < 0) {
weston_log("failed to create gl renderer output state\n");
gbm_surface_destroy(output->surface);
return -1;
diff --git a/src/compositor-fbdev.c b/src/compositor-fbdev.c
index 3d2819b..002ce0b 100644
--- a/src/compositor-fbdev.c
+++ b/src/compositor-fbdev.c
@@ -95,6 +95,8 @@
int use_gl;
};
+struct gl_renderer_interface *gl_renderer;
+
static const char default_seat[] = "seat0";
static inline struct fbdev_output *
@@ -623,7 +625,7 @@
goto out_shadow_surface;
} else {
setenv("HYBRIS_EGLPLATFORM", "wayland", 1);
- if (gl_renderer_output_create(&output->base,
+ if (gl_renderer->output_create(&output->base,
(EGLNativeWindowType)NULL) < 0) {
weston_log("gl_renderer_output_create failed.\n");
goto out_shadow_surface;
@@ -684,7 +686,7 @@
output->shadow_buf = NULL;
}
} else {
- gl_renderer_output_destroy(base);
+ gl_renderer->output_destroy(base);
}
/* Remove the output. */
@@ -923,8 +925,16 @@
if (pixman_renderer_init(&compositor->base) < 0)
goto out_launcher;
} else {
- if (gl_renderer_create(&compositor->base, EGL_DEFAULT_DISPLAY,
- gl_renderer_opaque_attribs, NULL) < 0) {
+ gl_renderer = weston_load_module("gl-renderer.so",
+ "gl_renderer_interface");
+ if (!gl_renderer) {
+ weston_log("could not load gl renderer\n");
+ goto out_launcher;
+ }
+
+ if (gl_renderer->create(&compositor->base, EGL_DEFAULT_DISPLAY,
+ gl_renderer->opaque_attribs,
+ NULL) < 0) {
weston_log("gl_renderer_create failed.\n");
goto out_launcher;
}
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index 77b2a2c..7b670d9 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -89,6 +89,8 @@
struct wayland_output *output;
};
+struct gl_renderer_interface *gl_renderer;
+
static void
create_border(struct wayland_compositor *c)
{
@@ -106,7 +108,7 @@
edges[2] = c->border.top;
edges[3] = c->border.bottom;
- gl_renderer_set_border(&c->base, pixman_image_get_width(image),
+ gl_renderer->set_border(&c->base, pixman_image_get_width(image),
pixman_image_get_height(image),
pixman_image_get_data(image), edges);
@@ -233,7 +235,7 @@
{
struct wayland_output *output = (struct wayland_output *) output_base;
- gl_renderer_output_destroy(output_base);
+ gl_renderer->output_destroy(output_base);
wl_egl_window_destroy(output->parent.egl_window);
free(output);
@@ -283,7 +285,7 @@
goto cleanup_output;
}
- if (gl_renderer_output_create(&output->base,
+ if (gl_renderer->output_create(&output->base,
output->parent.egl_window) < 0)
goto cleanup_window;
@@ -742,8 +744,14 @@
wl_display_dispatch(c->parent.wl_display);
c->base.wl_display = display;
- if (gl_renderer_create(&c->base, c->parent.wl_display,
- gl_renderer_alpha_attribs,
+
+ gl_renderer = weston_load_module("gl-renderer.so",
+ "gl_renderer_interface");
+ if (!gl_renderer)
+ goto err_display;
+
+ if (gl_renderer->create(&c->base, c->parent.wl_display,
+ gl_renderer->alpha_attribs,
NULL) < 0)
goto err_display;
@@ -759,7 +767,7 @@
if (wayland_compositor_create_output(c, width, height) < 0)
goto err_gl;
- /* requires gl_renderer_output_state_create called
+ /* requires gl_renderer->output_state_create called
* by wayland_compositor_create_output */
create_border(c);
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index 704e751..44e92ba 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -115,6 +115,8 @@
int32_t scale;
};
+struct gl_renderer_interface *gl_renderer;
+
static struct xkb_keymap *
x11_compositor_get_keymap(struct x11_compositor *c)
{
@@ -519,7 +521,7 @@
pixman_renderer_output_destroy(output_base);
x11_output_deinit_shm(compositor, output);
} else
- gl_renderer_output_destroy(output_base);
+ gl_renderer->output_destroy(output_base);
xcb_destroy_window(compositor->conn, output->window);
@@ -785,6 +787,7 @@
struct wm_normal_hints normal_hints;
struct wl_event_loop *loop;
int output_width, output_height;
+ int ret;
uint32_t mask = XCB_CW_EVENT_MASK | XCB_CW_CURSOR;
xcb_atom_t atom_list[1];
uint32_t values[2] = {
@@ -905,7 +908,9 @@
return NULL;
}
} else {
- if (gl_renderer_output_create(&output->base, (EGLNativeWindowType)output->window) < 0)
+ ret = gl_renderer->output_create(&output->base,
+ (EGLNativeWindowType) output->window);
+ if (ret < 0)
return NULL;
}
@@ -1441,6 +1446,21 @@
return WL_OUTPUT_TRANSFORM_NORMAL;
}
+static int
+init_gl_renderer(struct x11_compositor *c)
+{
+ int ret;
+
+ gl_renderer = weston_load_module("gl-renderer.so",
+ "gl_renderer_interface");
+ if (!gl_renderer)
+ return -1;
+
+ ret = gl_renderer->create(&c->base, (EGLNativeDisplayType) c->dpy,
+ gl_renderer->opaque_attribs, NULL);
+
+ return ret;
+}
static struct weston_compositor *
x11_compositor_create(struct wl_display *display,
int fullscreen,
@@ -1497,10 +1517,8 @@
if (pixman_renderer_init(&c->base) < 0)
goto err_xdisplay;
}
- else {
- if (gl_renderer_create(&c->base, (EGLNativeDisplayType)c->dpy, gl_renderer_opaque_attribs,
- NULL) < 0)
- goto err_xdisplay;
+ else if (init_gl_renderer(c) < 0) {
+ goto err_xdisplay;
}
weston_log("Using %s renderer\n", use_pixman ? "pixman" : "gl");
diff --git a/src/compositor.c b/src/compositor.c
index a89d2a9..34d9024 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -3224,8 +3224,8 @@
raise(SIGTRAP);
}
-static void *
-load_module(const char *name, const char *entrypoint)
+WL_EXPORT void *
+weston_load_module(const char *name, const char *entrypoint)
{
char path[PATH_MAX];
void *module, *init;
@@ -3275,7 +3275,7 @@
while (*p) {
end = strchrnul(p, ',');
snprintf(buffer, sizeof buffer, "%.*s", (int) (end - p), p);
- module_init = load_module(buffer, "module_init");
+ module_init = weston_load_module(buffer, "module_init");
if (module_init)
module_init(ec, argc, argv);
p = end;
@@ -3509,7 +3509,7 @@
section = weston_config_get_section(config, "core", NULL, NULL);
weston_config_section_get_string(section, "modules", &modules, "");
- backend_init = load_module(backend, "backend_init");
+ backend_init = weston_load_module(backend, "backend_init");
if (!backend_init)
exit(EXIT_FAILURE);
diff --git a/src/compositor.h b/src/compositor.h
index 4a2d654..d8a6a73 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -1256,6 +1256,9 @@
int32_t scale,
pixman_box32_t rect);
+void *
+weston_load_module(const char *name, const char *entrypoint);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index ae69f22..f02445b 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -170,7 +170,7 @@
#undef MYERRCODE
}
-WL_EXPORT void
+static void
gl_renderer_print_egl_error_state(void)
{
EGLint code;
@@ -1440,7 +1440,7 @@
output->border.right = gr->border.right;
}
-WL_EXPORT void
+static void
gl_renderer_set_border(struct weston_compositor *ec, int32_t width, int32_t height, void *data,
int32_t *edges)
{
@@ -1475,7 +1475,7 @@
static int
gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface);
-WL_EXPORT int
+static int
gl_renderer_output_create(struct weston_output *output,
EGLNativeWindowType window)
{
@@ -1514,7 +1514,7 @@
return 0;
}
-WL_EXPORT void
+static void
gl_renderer_output_destroy(struct weston_output *output)
{
struct gl_renderer *gr = get_renderer(output->compositor);
@@ -1529,7 +1529,7 @@
free(go);
}
-WL_EXPORT EGLSurface
+static EGLSurface
gl_renderer_output_surface(struct weston_output *output)
{
return get_output_state(output)->egl_surface;
@@ -1602,7 +1602,7 @@
return -1;
}
-WL_EXPORT const EGLint gl_renderer_opaque_attribs[] = {
+static const EGLint gl_renderer_opaque_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
@@ -1612,7 +1612,7 @@
EGL_NONE
};
-WL_EXPORT const EGLint gl_renderer_alpha_attribs[] = {
+static const EGLint gl_renderer_alpha_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
@@ -1622,7 +1622,7 @@
EGL_NONE
};
-WL_EXPORT int
+static int
gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
const EGLint *attribs, const EGLint *visual_id)
{
@@ -1673,7 +1673,7 @@
return -1;
}
-WL_EXPORT EGLDisplay
+static EGLDisplay
gl_renderer_display(struct weston_compositor *ec)
{
return get_renderer(ec)->egl_display;
@@ -1863,3 +1863,16 @@
return 0;
}
+
+WL_EXPORT struct gl_renderer_interface gl_renderer_interface = {
+ .opaque_attribs = gl_renderer_opaque_attribs,
+ .alpha_attribs = gl_renderer_alpha_attribs,
+
+ .create = gl_renderer_create,
+ .display = gl_renderer_display,
+ .output_create = gl_renderer_output_create,
+ .output_destroy = gl_renderer_output_destroy,
+ .output_surface = gl_renderer_output_surface,
+ .set_border = gl_renderer_set_border,
+ .print_egl_error_state = gl_renderer_print_egl_error_state
+};
diff --git a/src/gl-renderer.h b/src/gl-renderer.h
index d16ade2..0342134 100644
--- a/src/gl-renderer.h
+++ b/src/gl-renderer.h
@@ -28,27 +28,6 @@
#include <EGL/egl.h>
-extern const EGLint gl_renderer_opaque_attribs[];
-extern const EGLint gl_renderer_alpha_attribs[];
-
-int
-gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
- const EGLint *attribs, const EGLint *visual_id);
-EGLDisplay
-gl_renderer_display(struct weston_compositor *ec);
-int
-gl_renderer_output_create(struct weston_output *output,
- EGLNativeWindowType window);
-void
-gl_renderer_output_destroy(struct weston_output *output);
-EGLSurface
-gl_renderer_output_surface(struct weston_output *output);
-void
-gl_renderer_set_border(struct weston_compositor *ec, int32_t width, int32_t height, void *data,
- int32_t *edges);
-
-void
-gl_renderer_print_egl_error_state(void);
#else
typedef int EGLint;
@@ -58,49 +37,31 @@
typedef intptr_t EGLNativeWindowType;
#define EGL_DEFAULT_DISPLAY NULL
-static const EGLint gl_renderer_opaque_attribs[];
-static const EGLint gl_renderer_alpha_attribs[];
-
-inline static int
-gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
- const EGLint *attribs, const EGLint *visual_id)
-{
- return -1;
-}
-
-inline static EGLDisplay
-gl_renderer_display(struct weston_compositor *ec)
-{
- return 0;
-}
-
-inline static int
-gl_renderer_output_create(struct weston_output *output,
- EGLNativeWindowType window)
-{
- return -1;
-}
-
-inline static void
-gl_renderer_output_destroy(struct weston_output *output)
-{
-}
-
-inline static EGLSurface
-gl_renderer_output_surface(struct weston_output *output)
-{
- return 0;
-}
-
-inline static void
-gl_renderer_set_border(struct weston_compositor *ec, int32_t width, int32_t height, void *data,
- int32_t *edges)
-{
-}
-
-inline static void
-gl_renderer_print_egl_error_state(void)
-{
-}
-
#endif
+
+struct gl_renderer_interface {
+ const EGLint *opaque_attribs;
+ const EGLint *alpha_attribs;
+
+ int (*create)(struct weston_compositor *ec,
+ EGLNativeDisplayType display,
+ const EGLint *attribs,
+ const EGLint *visual_id);
+
+ EGLDisplay (*display)(struct weston_compositor *ec);
+
+ int (*output_create)(struct weston_output *output,
+ EGLNativeWindowType window);
+
+ void (*output_destroy)(struct weston_output *output);
+
+ EGLSurface (*output_surface)(struct weston_output *output);
+
+ void (*set_border)(struct weston_compositor *ec,
+ int32_t width, int32_t height,
+ void *data, int32_t *edges);
+
+ void (*print_egl_error_state)(void);
+};
+
+struct gl_renderer_interface gl_renderer_interface;