[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