[RFC] clients: add simple-dmabuf
David Herrmann
dh.herrmann at gmail.com
Tue Oct 22 17:23:30 CEST 2013
Hi
On Mon, Oct 21, 2013 at 11:32 PM, David Herrmann <dh.herrmann at gmail.com> wrote:
> simple-dmabuf is an example client which shows how to write wayland
> clients that use render-nodes for hardware-accelerated rendering and pass
> the buffer via dmabuf to the compositor. No mesa/EGL extensions are
> needed! Instead we pass dmabufs as wl_shm buffers to the compositors. This
> allows us to use hardware-accelerated rendering even with fbdev or other
> backends. Hurray!
>
> This still contains some hacks and is more a proof-of-concept than
> something useful. However, it shows what render-nodes allow us to do
> without modifying the compositor at all.
>
> This example requires a 3.12-rc kernel with drm.rnodes=1 on the kernel
> command line (must be set during boot!). Furthermore, this currently only
> works with drivers that implement dmabuf-mmap (which is rcar-du, shmob,
> omapdrm and others). I have some hacks which implement it for i915 (but
> flushing seems to not work..).
>
> I haven't succeeded in making rendering work with i915. I currently have
> no access to other drivers so any further testing/debugging welcome. We
> either still miss some render-nodes ioctls that are needed by mesa (but I
> didn't get any mesa errors..) or my i915-dmabuf-mmap is just wrong.
> If someone gets this working on a specific card (working means non-black
> window), please let me know.
Btw., I got this working with i915 by allowing GEM_OPEN/GEM_FLINK on
the render-node. So if someone else tests this, you might need the
same hacks. I will try to find the code in mesa that requires this.
David
> ---
> clients/.gitignore | 1 +
> clients/Makefile.am | 7 +-
> clients/simple-dmabuf.c | 675 ++++++++++++++++++++++++++++++++++++++++++++++++
> configure.ac | 2 +-
> 4 files changed, 683 insertions(+), 2 deletions(-)
> create mode 100644 clients/simple-dmabuf.c
>
> diff --git a/clients/.gitignore b/clients/.gitignore
> index 23959cc..b77b537 100644
> --- a/clients/.gitignore
> +++ b/clients/.gitignore
> @@ -11,6 +11,7 @@ weston-image
> weston-nested
> weston-nested-client
> weston-resizor
> +weston-simple-dmabuf
> weston-simple-egl
> weston-simple-shm
> weston-simple-touch
> diff --git a/clients/Makefile.am b/clients/Makefile.am
> index 4f9dc48..39dca7f 100644
> --- a/clients/Makefile.am
> +++ b/clients/Makefile.am
> @@ -56,11 +56,16 @@ endif
>
> if BUILD_SIMPLE_EGL_CLIENTS
> simple_egl_clients_programs = \
> - weston-simple-egl
> + weston-simple-egl \
> + weston-simple-dmabuf
>
> weston_simple_egl_SOURCES = simple-egl.c
> weston_simple_egl_CPPFLAGS = $(SIMPLE_EGL_CLIENT_CFLAGS)
> weston_simple_egl_LDADD = $(SIMPLE_EGL_CLIENT_LIBS) -lm
> +
> +weston_simple_dmabuf_SOURCES = simple-dmabuf.c
> +weston_simple_dmabuf_CPPFLAGS = $(SIMPLE_EGL_CLIENT_CFLAGS)
> +weston_simple_dmabuf_LDADD = $(SIMPLE_EGL_CLIENT_LIBS) -lm
> endif
>
> if BUILD_CLIENTS
> diff --git a/clients/simple-dmabuf.c b/clients/simple-dmabuf.c
> new file mode 100644
> index 0000000..570c929
> --- /dev/null
> +++ b/clients/simple-dmabuf.c
> @@ -0,0 +1,675 @@
> +/*
> + * Copyright © 2012-2013 David Herrmann <dh.herrmann at gmail.com>
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and its
> + * documentation for any purpose is hereby granted without fee, provided that
> + * the above copyright notice appear in all copies and that both that copyright
> + * notice and this permission notice appear in supporting documentation, and
> + * that the name of the copyright holders not be used in advertising or
> + * publicity pertaining to distribution of the software without specific,
> + * written prior permission. The copyright holders make no representations
> + * about the suitability of this software for any purpose. It is provided "as
> + * is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
> + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
> + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
> + * OF THIS SOFTWARE.
> + */
> +
> +/*
> + * Simple dmabuf/render-nodes Client
> + * This is a simple example client which uses dmabuf to pass buffers via wl_shm
> + * (instead of wl_drm or other EGL extensions) to the compositor. To render the
> + * images, we use DRM render-nodes or software-rendering as fallback.
> + *
> + * Note that this is a very basic example how to use wl_shm to share buffers
> + * which were rendered using a dedicated GPU. No mesa/EGL internal extensions
> + * are required.
> + * However, this is *not* the recommended way to do it! The mesa/EGL extensions
> + * allow much better integration and control. This client serves as a
> + * proof-of-concept and generic HOWTO.
> + */
> +
> +#define EGL_EGLEXT_PROTOTYPES
> +#define GL_GLEXT_PROTOTYPES
> +
> +#include <config.h>
> +
> +#include <assert.h>
> +#include <dirent.h>
> +#include <EGL/egl.h>
> +#include <EGL/eglext.h>
> +#include <errno.h>
> +#include <error.h>
> +#include <fcntl.h>
> +#include <gbm.h>
> +#include <GLES2/gl2.h>
> +#include <GLES2/gl2ext.h>
> +#include <signal.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <stdbool.h>
> +#include <sys/mman.h>
> +#include <sys/types.h>
> +#include <unistd.h>
> +#include <wayland-client.h>
> +#include <xf86drm.h>
> +
> +/* buffer objects */
> +
> +struct buffer {
> + struct window *window;
> + struct wl_buffer *buffer;
> + void *shm_data;
> +
> + struct rnode_buffer *rnode;
> +};
> +
> +struct rnode_buffer {
> + struct gbm_bo *gbm_bo;
> + int fd;
> + struct buffer buf;
> +};
> +
> +/* window objects */
> +
> +struct rnode_window {
> + struct gbm_surface *gbm_surface;
> + EGLSurface egl_surface;
> +};
> +
> +struct window {
> + struct display *display;
> + int width, height;
> + struct wl_surface *surface;
> + struct wl_shell_surface *shell_surface;
> + struct wl_callback *callback;
> +
> + struct rnode_window rnode;
> +};
> +
> +/* display objects */
> +
> +struct rnode_display {
> + int fd;
> + struct gbm_device *gbm_dev;
> + EGLDisplay egl_display;
> + EGLConfig egl_conf;
> + EGLContext egl_ctx;
> +};
> +
> +struct display {
> + struct wl_display *display;
> + struct wl_registry *registry;
> + struct wl_compositor *compositor;
> + struct wl_shell *shell;
> + struct wl_shm *shm;
> + uint32_t formats;
> +
> + struct rnode_display rnode;
> +};
> +
> +/* forward declarations */
> +
> +static void buffer_init(struct buffer *buf, struct window *w,
> + struct rnode_buffer *b);
> +static void buffer_destroy(struct buffer *buf);
> +
> +/*
> + * Render Nodes
> + */
> +
> +/* rnode_open() tries to find a render-node, open it and return an FD. This
> + * should really be done via udev_enumerate_*() APIs, but to avoid a udev
> + * dependency here, we just hack it up via a /dev/dri/ iterator.
> + * DON'T COPY THAT! It's an ugly hack! */
> +static int rnode_open(void)
> +{
> + DIR *dir;
> + struct dirent *e;
> + int r, fd;
> + char *p;
> +
> + dir = opendir("/dev/dri/");
> + if (!dir)
> + error(1, errno, "cannot open /dev/dri/");
> +
> + fd = -1;
> + while ((e = readdir(dir))) {
> + if (e->d_type != DT_CHR)
> + continue;
> + if (strncmp(e->d_name, "renderD", 7))
> + continue;
> +
> + r = asprintf(&p, "/dev/dri/%s", e->d_name);
> + if (r < 0)
> + error(1, errno, "cannot allocate pathname");
> +
> + r = open(p, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
> + if (r < 0) {
> + free(p);
> + error(0, errno, "cannot open %s", p);
> + continue;
> + }
> +
> + fd = r;
> + fprintf(stderr, "using render node %s\n", p);
> + free(p);
> + break;
> + }
> +
> + if (fd < 0)
> + error(1, 0, "cannot open any render-node in /dev/dri/");
> +
> + return fd;
> +}
> +
> +static void rnode_init(struct display *d)
> +{
> + static const EGLint conf_att[] = {
> + EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
> + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
> + EGL_RED_SIZE, 1,
> + EGL_GREEN_SIZE, 1,
> + EGL_BLUE_SIZE, 1,
> + EGL_ALPHA_SIZE, 0,
> + EGL_NONE,
> + };
> + static const EGLint ctx_att[] = {
> + EGL_CONTEXT_CLIENT_VERSION, 2,
> + EGL_NONE
> + };
> + EGLBoolean b;
> + EGLenum api;
> + EGLint major, minor, n;
> +
> + d->rnode.fd = rnode_open();
> + d->rnode.gbm_dev = gbm_create_device(d->rnode.fd);
> + if (!d->rnode.gbm_dev)
> + error(1, errno, "cannot create gbm device");
> +
> + d->rnode.egl_display = eglGetDisplay((EGLNativeDisplayType)d->rnode.gbm_dev);
> + if (!d->rnode.egl_display)
> + error(1, errno, "cannot create EGL display");
> +
> + b = eglInitialize(d->rnode.egl_display, &major, &minor);
> + if (!b)
> + error(1, errno, "cannot initialize EGL");
> +
> + fprintf(stderr, "EGL major/minor: %d.%d\n", major, minor);
> + fprintf(stderr, "EGL version: %s\n",
> + eglQueryString(d->rnode.egl_display, EGL_VERSION));
> + fprintf(stderr, "EGL vendor: %s\n",
> + eglQueryString(d->rnode.egl_display, EGL_VENDOR));
> + fprintf(stderr, "EGL extensions: %s\n",
> + eglQueryString(d->rnode.egl_display, EGL_EXTENSIONS));
> +
> + api = EGL_OPENGL_ES_API;
> + b = eglBindAPI(api);
> + if (!b)
> + error(1, errno, "cannot bind OpenGLES API");
> +
> + b = eglChooseConfig(d->rnode.egl_display, conf_att, &d->rnode.egl_conf,
> + 1, &n);
> + if (!b || n != 1)
> + error(1, errno, "cannot find suitable EGL config");
> +
> + d->rnode.egl_ctx = eglCreateContext(d->rnode.egl_display,
> + d->rnode.egl_conf,
> + EGL_NO_CONTEXT,
> + ctx_att);
> + if (!d->rnode.egl_ctx)
> + error(1, errno, "cannot create EGL context");
> +}
> +
> +static void rnode_destroy(struct display *d)
> +{
> + eglMakeCurrent(d->rnode.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
> + EGL_NO_CONTEXT);
> + eglDestroyContext(d->rnode.egl_display, d->rnode.egl_ctx);
> + eglTerminate(d->rnode.egl_display);
> + gbm_device_destroy(d->rnode.gbm_dev);
> + close(d->rnode.fd);
> +}
> +
> +static void rnode_buffer_destroy_cb(struct gbm_bo *bo, void *data)
> +{
> + struct rnode_buffer *b = data;
> +
> + if (!b)
> + return;
> +
> + buffer_destroy(&b->buf);
> + close(b->fd);
> + free(b);
> +}
> +
> +static struct rnode_buffer *rnode_bo_to_buffer(struct window *w,
> + struct gbm_bo *bo)
> +{
> + struct display *d = w->display;
> + struct rnode_buffer *b;
> + int r;
> +
> + b = gbm_bo_get_user_data(bo);
> + if (b)
> + return b;
> +
> + b = calloc(1, sizeof(*b));
> + if (!b)
> + error(1, errno, "cannot allocate buffer object");
> +
> + b->gbm_bo = bo;
> +
> + r = drmPrimeHandleToFD(d->rnode.fd, gbm_bo_get_handle(bo).u32,
> + 0, &b->fd);
> + if (r < 0)
> + error(1, errno, "cannot get prime-fd for buffer handle");
> +
> + buffer_init(&b->buf, w, b);
> + gbm_bo_set_user_data(bo, b, rnode_buffer_destroy_cb);
> + return b;
> +}
> +
> +static void rnode_window_create(struct window *w)
> +{
> + struct display *d = w->display;
> + EGLBoolean b;
> +
> + w->rnode.gbm_surface = gbm_surface_create(d->rnode.gbm_dev,
> + w->width, w->height,
> + GBM_FORMAT_XRGB8888,
> + GBM_BO_USE_RENDERING);
> + if (!w->rnode.gbm_surface)
> + error(1, errno, "cannot create gbm surface");
> +
> + w->rnode.egl_surface = eglCreateWindowSurface(d->rnode.egl_display,
> + d->rnode.egl_conf,
> + (EGLNativeWindowType)w->rnode.gbm_surface,
> + NULL);
> + if (!w->rnode.egl_surface)
> + error(1, errno, "cannot create EGL surface");
> +
> + b = eglMakeCurrent(d->rnode.egl_display,
> + w->rnode.egl_surface,
> + w->rnode.egl_surface,
> + d->rnode.egl_ctx);
> + if (!b)
> + error(1, errno, "cannot activate EGL context");
> +
> + glClearColor(0, 0, 0, 1);
> + glClear(GL_COLOR_BUFFER_BIT);
> +}
> +
> +static void rnode_window_destroy(struct window *w)
> +{
> + struct display *d = w->display;
> +
> + eglMakeCurrent(d->rnode.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
> + d->rnode.egl_ctx);
> + eglDestroySurface(d->rnode.egl_display, w->rnode.egl_surface);
> + gbm_surface_destroy(w->rnode.gbm_surface);
> +}
> +
> +static struct buffer *rnode_window_swap(struct window *w)
> +{
> + int r;
> + EGLBoolean eb;
> + struct display *d = w->display;
> + struct gbm_bo *bo;
> + struct rnode_buffer *b;
> +
> + r = gbm_surface_has_free_buffers(w->rnode.gbm_surface);
> + if (!r)
> + error(1, errno, "gbm surface has no free buffers left");
> +
> + glFinish();
> + eb = eglSwapBuffers(d->rnode.egl_display, w->rnode.egl_surface);
> + if (!eb)
> + error(1, errno, "cannot swap buffers");
> +
> + bo = gbm_surface_lock_front_buffer(w->rnode.gbm_surface);
> + if (!bo)
> + error(1, errno, "cannot lock front buffer");
> +
> + b = rnode_bo_to_buffer(w, bo);
> + return &b->buf;
> +}
> +
> +static void rnode_buffer_release(struct buffer *buf)
> +{
> + struct rnode_buffer *b = buf->rnode;
> + struct window *w = buf->window;
> +
> + gbm_surface_release_buffer(w->rnode.gbm_surface, b->gbm_bo);
> +}
> +
> +/*
> + * Buffer Handling
> + */
> +
> +static void
> +buffer_release(void *data, struct wl_buffer *buffer)
> +{
> + struct buffer *buf = data;
> +
> + rnode_buffer_release(buf);
> +}
> +
> +static const struct wl_buffer_listener buffer_listener = {
> + buffer_release,
> +};
> +
> +static void buffer_init(struct buffer *buf, struct window *w,
> + struct rnode_buffer *b)
> +{
> + struct wl_shm_pool *pool;
> + struct display *d = w->display;
> + unsigned int size, stride;
> +
> + buf->window = w;
> + buf->rnode = b;
> +
> + stride = w->width * 4;
> + size = stride * w->height;
> +
> + /* mmap() not needed, but could be used as software fallback */
> + buf->shm_data = mmap(NULL, size, PROT_READ, MAP_SHARED,
> + b->fd, 0);
> + if (buf->shm_data == MAP_FAILED)
> + error(1, errno, "cannot mmap buffer");
> +
> + pool = wl_shm_create_pool(d->shm, b->fd, size);
> + if (!pool)
> + error(1, errno, "cannot create wl_shm pool");
> +
> + buf->buffer = wl_shm_pool_create_buffer(pool, 0, w->width, w->height,
> + stride,
> + WL_SHM_FORMAT_XRGB8888);
> + if (!buf->buffer)
> + error(1, errno, "cannot create wl_shm buffer");
> +
> + wl_buffer_add_listener(buf->buffer, &buffer_listener, buf);
> +
> + wl_shm_pool_destroy(pool);
> +}
> +
> +static void buffer_destroy(struct buffer *buf)
> +{
> + struct window *w = buf->window;
> +
> + munmap(buf->shm_data, w->width * w->height * 4);
> + wl_buffer_destroy(buf->buffer);
> +}
> +
> +/*
> + * Window Handling
> + */
> +
> +static void
> +window_handle_ping(void *data, struct wl_shell_surface *shell_surface,
> + uint32_t serial)
> +{
> + wl_shell_surface_pong(shell_surface, serial);
> +}
> +
> +static void
> +window_handle_configure(void *data, struct wl_shell_surface *shell_surface,
> + uint32_t edges, int32_t width, int32_t height)
> +{
> +}
> +
> +static void
> +window_handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
> +{
> +}
> +
> +static const struct wl_shell_surface_listener window_shell_surface_listener = {
> + window_handle_ping,
> + window_handle_configure,
> + window_handle_popup_done,
> +};
> +
> +static struct window *window_create(struct display *display)
> +{
> + struct window *window;
> +
> + window = calloc(1, sizeof *window);
> + if (!window)
> + error(1, errno, "cannot allocate window object");
> +
> + window->callback = NULL;
> + window->display = display;
> + window->width = 250;
> + window->height = 250;
> +
> + window->surface = wl_compositor_create_surface(display->compositor);
> + if (!window->surface)
> + error(1, errno, "cannot create window surface");
> +
> + window->shell_surface = wl_shell_get_shell_surface(display->shell,
> + window->surface);
> + if (!window->shell_surface)
> + error(1, errno, "cannot create window shell surface");
> +
> + wl_shell_surface_add_listener(window->shell_surface,
> + &window_shell_surface_listener, window);
> + wl_shell_surface_set_title(window->shell_surface, "simple-dmabuf");
> + wl_shell_surface_set_toplevel(window->shell_surface);
> +
> + rnode_window_create(window);
> +
> + return window;
> +}
> +
> +static void window_destroy(struct window *window)
> +{
> + if (window->callback)
> + wl_callback_destroy(window->callback);
> +
> + rnode_window_destroy(window);
> +
> + wl_shell_surface_destroy(window->shell_surface);
> + wl_surface_destroy(window->surface);
> +
> + free(window);
> +}
> +
> +static void paint(int padding, int width, int height, uint32_t time)
> +{
> + glClearColor(1, 0, 0, 1);
> + glClear(GL_COLOR_BUFFER_BIT);
> +}
> +
> +static void
> +window_redraw(void *data, struct wl_callback *callback, uint32_t time);
> +
> +static const struct wl_callback_listener window_frame_listener = {
> + window_redraw,
> +};
> +
> +static void
> +window_redraw(void *data, struct wl_callback *callback, uint32_t time)
> +{
> + struct window *w = data;
> + struct buffer *buf;
> +
> + paint(20, w->width, w->height, time);
> +
> + buf = rnode_window_swap(w);
> +
> + wl_surface_attach(w->surface, buf->buffer, 0, 0);
> + wl_surface_damage(w->surface, 20, 20,
> + w->width - 40, w->height - 40);
> +
> + if (callback)
> + wl_callback_destroy(callback);
> +
> + w->callback = wl_surface_frame(w->surface);
> + if (!w->callback)
> + error(1, errno, "cannot create wayland frame callback");
> +
> + wl_callback_add_listener(w->callback, &window_frame_listener, w);
> + wl_surface_commit(w->surface);
> +}
> +
> +/*
> + * Display Handling
> + */
> +
> +static void
> +display_shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
> +{
> + struct display *d = data;
> +
> + d->formats |= (1 << format);
> +}
> +
> +struct wl_shm_listener display_shm_listener = {
> + display_shm_format,
> +};
> +
> +static void
> +display_registry_handle_global(void *data, struct wl_registry *registry,
> + uint32_t id, const char *interface,
> + uint32_t version)
> +{
> + struct display *d = data;
> +
> + if (!strcmp(interface, "wl_compositor")) {
> + d->compositor = wl_registry_bind(registry, id,
> + &wl_compositor_interface, 1);
> + } else if (!strcmp(interface, "wl_shell")) {
> + d->shell = wl_registry_bind(registry, id,
> + &wl_shell_interface, 1);
> + } else if (!strcmp(interface, "wl_shm")) {
> + d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
> + if (d->shm)
> + wl_shm_add_listener(d->shm, &display_shm_listener, d);
> + }
> +}
> +
> +static void
> +display_registry_handle_global_remove(void *data, struct wl_registry *registry,
> + uint32_t name)
> +{
> +}
> +
> +static const struct wl_registry_listener display_registry_listener = {
> + display_registry_handle_global,
> + display_registry_handle_global_remove,
> +};
> +
> +static struct display *display_create(void)
> +{
> + struct display *display;
> +
> + display = calloc(1, sizeof(*display));
> + if (!display)
> + error(1, ENOMEM, "cannot allocate display");
> +
> + display->display = wl_display_connect(NULL);
> + if (!display->display)
> + error(1, errno, "cannot connect to wayland server");
> +
> + display->registry = wl_display_get_registry(display->display);
> + if (!display->registry)
> + error(1, errno, "cannot allocate wayland registry");
> +
> + wl_registry_add_listener(display->registry,
> + &display_registry_listener,
> + display);
> +
> + /* wait for globals */
> + wl_display_roundtrip(display->display);
> + if (!display->shm || !display->shell || !display->compositor)
> + error(1, 0, "wayland server does not support wl_shm/wl_shell/wl_compositor");
> +
> + /* wait for wl_shm formats */
> + wl_display_roundtrip(display->display);
> + if (!(display->formats & (1 << WL_SHM_FORMAT_XRGB8888)))
> + error(1, 0, "wayland server does not support xrgb32");
> +
> + rnode_init(display);
> +
> + return display;
> +}
> +
> +static void display_destroy(struct display *display)
> +{
> + rnode_destroy(display);
> +
> + wl_shm_destroy(display->shm);
> + wl_shell_destroy(display->shell);
> + wl_compositor_destroy(display->compositor);
> + wl_registry_destroy(display->registry);
> +
> + wl_display_flush(display->display);
> + wl_display_disconnect(display->display);
> +
> + free(display);
> +}
> +
> +/*
> + * Main
> + */
> +
> +static int running = 1;
> +
> +static void
> +signal_int(int signum)
> +{
> + running = 0;
> +}
> +
> +static void
> +signal_setup(void)
> +{
> + struct sigaction sigint;
> +
> + sigint.sa_handler = signal_int;
> + sigemptyset(&sigint.sa_mask);
> + sigint.sa_flags = SA_RESETHAND;
> + sigaction(SIGINT, &sigint, NULL);
> + sigaction(SIGTERM, &sigint, NULL);
> + sigaction(SIGPIPE, &sigint, NULL);
> + sigaction(SIGHUP, &sigint, NULL);
> +}
> +
> +int
> +main(int argc, char **argv)
> +{
> + struct display *display;
> + struct window *window;
> + int r;
> +
> + fprintf(stderr, "initialize..\n");
> +
> + signal_setup();
> + display = display_create();
> + window = window_create(display);
> +
> + fprintf(stderr, "run..\n");
> +
> + /* Initialise damage to full surface, so the padding gets painted */
> + wl_surface_damage(window->surface, 0, 0,
> + window->width, window->height);
> +
> + window_redraw(window, NULL, 0);
> +
> + do {
> + r = wl_display_dispatch(display->display);
> + } while (running && r >= 0);
> +
> + fprintf(stderr, "exit..\n");
> +
> + window_destroy(window);
> + display_destroy(display);
> +
> + return 0;
> +}
> diff --git a/configure.ac b/configure.ac
> index 950086d..3d7b9f5 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -282,7 +282,7 @@ AC_ARG_ENABLE(simple-egl-clients,
> AM_CONDITIONAL(BUILD_SIMPLE_EGL_CLIENTS, test "x$enable_simple_egl_clients" = "xyes")
> if test x$enable_simple_egl_clients = xyes; then
> PKG_CHECK_MODULES(SIMPLE_EGL_CLIENT,
> - [egl >= 7.10 glesv2 wayland-client wayland-egl wayland-cursor])
> + [egl >= 7.10 gbm libdrm glesv2 wayland-client wayland-egl wayland-cursor])
> fi
>
> AC_ARG_ENABLE(clients, [ --enable-clients],, enable_clients=yes)
> --
> 1.8.4.1
>
More information about the wayland-devel
mailing list