From cdcfe48fb0431184fabb40aa5a244d086f551df5 Mon Sep 17 00:00:00 2001 From: Axel Davy Date: Fri, 1 May 2015 11:11:20 +0200 Subject: [PATCH] egl/wayland: Implement swrast support Reviewed-by: Dave Airlie Reviewed-by: Daniel Stone . Signed-off-by: Axel Davy --- src/egl/drivers/dri2/egl_dri2.c | 5 +- src/egl/drivers/dri2/egl_dri2.h | 4 + src/egl/drivers/dri2/platform_wayland.c | 704 +++++++++++++++++++++++- 3 files changed, 696 insertions(+), 17 deletions(-) diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index 169abcc4c63..467b81c6e8d 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -729,7 +729,10 @@ dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) #endif #ifdef HAVE_WAYLAND_PLATFORM case _EGL_PLATFORM_WAYLAND: - wl_drm_destroy(dri2_dpy->wl_drm); + if (dri2_dpy->wl_drm) + wl_drm_destroy(dri2_dpy->wl_drm); + if (dri2_dpy->wl_shm) + wl_shm_destroy(dri2_dpy->wl_shm); wl_registry_destroy(dri2_dpy->wl_registry); wl_event_queue_destroy(dri2_dpy->wl_queue); if (dri2_dpy->own_device) { diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index cabeb2dfdc6..adade3db9cc 100644 --- a/src/egl/drivers/dri2/egl_dri2.h +++ b/src/egl/drivers/dri2/egl_dri2.h @@ -196,6 +196,7 @@ struct dri2_egl_display struct wl_registry *wl_registry; struct wl_drm *wl_server_drm; struct wl_drm *wl_drm; + struct wl_shm *wl_shm; struct wl_event_queue *wl_queue; int authenticated; int formats; @@ -257,6 +258,9 @@ struct dri2_egl_surface __DRIimage *dri_image; /* for is_different_gpu case. NULL else */ __DRIimage *linear_copy; + /* for swrast */ + void *data; + int data_size; #endif #ifdef HAVE_DRM_PLATFORM struct gbm_bo *bo; diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index e9f142c64d1..9914b687fb8 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -1,5 +1,6 @@ /* * Copyright © 2011-2012 Intel Corporation + * Copyright © 2012 Collabora, Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -35,6 +36,7 @@ #include #include #include +#include #include "egl_dri2.h" #include "egl_dri2_fallbacks.h" @@ -233,13 +235,18 @@ dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); if (dri2_surf->color_buffers[i].linear_copy) dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy); + if (dri2_surf->color_buffers[i].data) + munmap(dri2_surf->color_buffers[i].data, + dri2_surf->color_buffers[i].data_size); } - for (i = 0; i < __DRI_BUFFER_COUNT; i++) - if (dri2_surf->dri_buffers[i] && - dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT) - dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, - dri2_surf->dri_buffers[i]); + if (dri2_dpy->dri2) { + for (i = 0; i < __DRI_BUFFER_COUNT; i++) + if (dri2_surf->dri_buffers[i] && + dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT) + dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, + dri2_surf->dri_buffers[i]); + } if (dri2_surf->throttle_callback) wl_callback_destroy(dri2_surf->throttle_callback); @@ -267,18 +274,24 @@ dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf) dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); if (dri2_surf->color_buffers[i].linear_copy) dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy); + if (dri2_surf->color_buffers[i].data) + munmap(dri2_surf->color_buffers[i].data, + dri2_surf->color_buffers[i].data_size); dri2_surf->color_buffers[i].wl_buffer = NULL; dri2_surf->color_buffers[i].dri_image = NULL; dri2_surf->color_buffers[i].linear_copy = NULL; + dri2_surf->color_buffers[i].data = NULL; dri2_surf->color_buffers[i].locked = 0; } - for (i = 0; i < __DRI_BUFFER_COUNT; i++) - if (dri2_surf->dri_buffers[i] && - dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT) - dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, - dri2_surf->dri_buffers[i]); + if (dri2_dpy->dri2) { + for (i = 0; i < __DRI_BUFFER_COUNT; i++) + if (dri2_surf->dri_buffers[i] && + dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT) + dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, + dri2_surf->dri_buffers[i]); + } } static int @@ -944,7 +957,7 @@ static const struct wl_drm_listener drm_listener = { }; static void -registry_handle_global(void *data, struct wl_registry *registry, uint32_t name, +registry_handle_global_drm(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { struct dri2_egl_display *dri2_dpy = data; @@ -964,8 +977,8 @@ registry_handle_global_remove(void *data, struct wl_registry *registry, { } -static const struct wl_registry_listener registry_listener = { - registry_handle_global, +static const struct wl_registry_listener registry_listener_drm = { + registry_handle_global_drm, registry_handle_global_remove }; @@ -1041,8 +1054,8 @@ static struct dri2_egl_display_vtbl dri2_wl_display_vtbl = { .get_sync_values = dri2_fallback_get_sync_values, }; -EGLBoolean -dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) +static EGLBoolean +dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp) { struct dri2_egl_display *dri2_dpy; const __DRIconfig *config; @@ -1078,7 +1091,7 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_registry, dri2_dpy->wl_queue); wl_registry_add_listener(dri2_dpy->wl_registry, - ®istry_listener, dri2_dpy); + ®istry_listener_drm, dri2_dpy); if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL) goto cleanup_registry; @@ -1223,3 +1236,662 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) return EGL_FALSE; } + +static int +dri2_wl_swrast_get_stride_for_format(int format, int w) +{ + if (format == WL_SHM_FORMAT_RGB565) + return 2 * w; + else /* ARGB8888 || XRGB8888 */ + return 4 * w; +} + +/* + * Taken from weston shared/os-compatibility.c + */ + +static int +set_cloexec_or_close(int fd) +{ + long flags; + + if (fd == -1) + return -1; + + flags = fcntl(fd, F_GETFD); + if (flags == -1) + goto err; + + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) + goto err; + + return fd; + +err: + close(fd); + return -1; +} + +/* + * Taken from weston shared/os-compatibility.c + */ + +static int +create_tmpfile_cloexec(char *tmpname) +{ + int fd; + +#ifdef HAVE_MKOSTEMP + fd = mkostemp(tmpname, O_CLOEXEC); + if (fd >= 0) + unlink(tmpname); +#else + fd = mkstemp(tmpname); + if (fd >= 0) { + fd = set_cloexec_or_close(fd); + unlink(tmpname); + } +#endif + + return fd; +} + +/* + * Taken from weston shared/os-compatibility.c + * + * Create a new, unique, anonymous file of the given size, and + * return the file descriptor for it. The file descriptor is set + * CLOEXEC. The file is immediately suitable for mmap()'ing + * the given size at offset zero. + * + * The file should not have a permanent backing store like a disk, + * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. + * + * The file name is deleted from the file system. + * + * The file is suitable for buffer sharing between processes by + * transmitting the file descriptor over Unix sockets using the + * SCM_RIGHTS methods. + * + * If the C library implements posix_fallocate(), it is used to + * guarantee that disk space is available for the file at the + * given size. If disk space is insufficent, errno is set to ENOSPC. + * If posix_fallocate() is not supported, program may receive + * SIGBUS on accessing mmap()'ed file contents instead. + */ +static int +os_create_anonymous_file(off_t size) +{ + static const char template[] = "/mesa-shared-XXXXXX"; + const char *path; + char *name; + int fd; + int ret; + + path = getenv("XDG_RUNTIME_DIR"); + if (!path) { + errno = ENOENT; + return -1; + } + + name = malloc(strlen(path) + sizeof(template)); + if (!name) + return -1; + + strcpy(name, path); + strcat(name, template); + + fd = create_tmpfile_cloexec(name); + + free(name); + + if (fd < 0) + return -1; + + ret = ftruncate(fd, size); + if (ret < 0) { + close(fd); + return -1; + } + + return fd; +} + + +static EGLBoolean +dri2_wl_swrast_allocate_buffer(struct dri2_egl_display *dri2_dpy, + int format, int w, int h, + void **data, int *size, + struct wl_buffer **buffer) +{ + struct wl_shm_pool *pool; + int fd, stride, size_map; + void *data_map; + + stride = dri2_wl_swrast_get_stride_for_format(format, w); + size_map = h * stride; + + /* Create a sharable buffer */ + fd = os_create_anonymous_file(size_map); + if (fd < 0) + return EGL_FALSE; + + data_map = mmap(NULL, size_map, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data_map == MAP_FAILED) { + close(fd); + return EGL_FALSE; + } + + /* Share it in a wl_buffer */ + pool = wl_shm_create_pool(dri2_dpy->wl_shm, fd, size_map); + *buffer = wl_shm_pool_create_buffer(pool, 0, w, h, stride, format); + wl_shm_pool_destroy(pool); + close(fd); + + *data = data_map; + *size = size_map; + return EGL_TRUE; +} + +static int +swrast_update_buffers(struct dri2_egl_surface *dri2_surf) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + int i; + + /* we need to do the following operations only once per frame */ + if (dri2_surf->back) + return 0; + + if (dri2_surf->base.Width != dri2_surf->wl_win->width || + dri2_surf->base.Height != dri2_surf->wl_win->height) { + + dri2_wl_release_buffers(dri2_surf); + + dri2_surf->base.Width = dri2_surf->wl_win->width; + dri2_surf->base.Height = dri2_surf->wl_win->height; + dri2_surf->dx = dri2_surf->wl_win->dx; + dri2_surf->dy = dri2_surf->wl_win->dy; + dri2_surf->current = NULL; + } + + /* find back buffer */ + + /* We always want to throttle to some event (either a frame callback or + * a sync request) after the commit so that we can be sure the + * compositor has had a chance to handle it and send us a release event + * before we look for a free buffer */ + while (dri2_surf->throttle_callback != NULL) + if (wl_display_dispatch_queue(dri2_dpy->wl_dpy, + dri2_dpy->wl_queue) == -1) + return -1; + + /* try get free buffer already created */ + for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { + if (!dri2_surf->color_buffers[i].locked && + dri2_surf->color_buffers[i].wl_buffer) { + dri2_surf->back = &dri2_surf->color_buffers[i]; + break; + } + } + + /* else choose any another free location */ + if (!dri2_surf->back) { + for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { + if (!dri2_surf->color_buffers[i].locked) { + dri2_surf->back = &dri2_surf->color_buffers[i]; + if (!dri2_wl_swrast_allocate_buffer(dri2_dpy, + dri2_surf->format, + dri2_surf->base.Width, + dri2_surf->base.Height, + &dri2_surf->back->data, + &dri2_surf->back->data_size, + &dri2_surf->back->wl_buffer)) { + _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer"); + return -1; + } + wl_proxy_set_queue((struct wl_proxy *) dri2_surf->back->wl_buffer, + dri2_dpy->wl_queue); + wl_buffer_add_listener(dri2_surf->back->wl_buffer, + &wl_buffer_listener, dri2_surf); + break; + } + } + } + + if (!dri2_surf->back) { + _eglError(EGL_BAD_ALLOC, "failed to find free buffer"); + return -1; + } + + dri2_surf->back->locked = 1; + + /* If we have an extra unlocked buffer at this point, we had to do triple + * buffering for a while, but now can go back to just double buffering. + * That means we can free any unlocked buffer now. */ + for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { + if (!dri2_surf->color_buffers[i].locked && + dri2_surf->color_buffers[i].wl_buffer) { + wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); + munmap(dri2_surf->color_buffers[i].data, + dri2_surf->color_buffers[i].data_size); + dri2_surf->color_buffers[i].wl_buffer = NULL; + dri2_surf->color_buffers[i].data = NULL; + } + } + + return 0; +} + +static void* +dri2_wl_swrast_get_frontbuffer_data(struct dri2_egl_surface *dri2_surf) +{ + /* if there has been a resize: */ + if (!dri2_surf->current) + return NULL; + + return dri2_surf->current->data; +} + +static void* +dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface *dri2_surf) +{ + assert(dri2_surf->back); + return dri2_surf->back->data; +} + +static void +dri2_wl_swrast_commit_backbuffer(struct dri2_egl_surface *dri2_surf) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); + + if (dri2_surf->base.SwapInterval > 0) { + dri2_surf->throttle_callback = + wl_surface_frame(dri2_surf->wl_win->surface); + wl_callback_add_listener(dri2_surf->throttle_callback, + &throttle_listener, dri2_surf); + wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback, + dri2_dpy->wl_queue); + } + + dri2_surf->current = dri2_surf->back; + dri2_surf->back = NULL; + + wl_surface_attach(dri2_surf->wl_win->surface, + dri2_surf->current->wl_buffer, + dri2_surf->dx, dri2_surf->dy); + + dri2_surf->wl_win->attached_width = dri2_surf->base.Width; + dri2_surf->wl_win->attached_height = dri2_surf->base.Height; + /* reset resize growing parameters */ + dri2_surf->dx = 0; + dri2_surf->dy = 0; + + wl_surface_damage(dri2_surf->wl_win->surface, + 0, 0, INT32_MAX, INT32_MAX); + wl_surface_commit(dri2_surf->wl_win->surface); + + /* If we're not waiting for a frame callback then we'll at least throttle + * to a sync callback so that we always give a chance for the compositor to + * handle the commit and send a release event before checking for a free + * buffer */ + if (dri2_surf->throttle_callback == NULL) { + dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy); + wl_callback_add_listener(dri2_surf->throttle_callback, + &throttle_listener, dri2_surf); + wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback, + dri2_dpy->wl_queue); + } + + wl_display_flush(dri2_dpy->wl_dpy); +} + +static void +dri2_wl_swrast_get_drawable_info(__DRIdrawable * draw, + int *x, int *y, int *w, int *h, + void *loaderPrivate) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + + (void) swrast_update_buffers(dri2_surf); + *x = 0; + *y = 0; + *w = dri2_surf->base.Width; + *h = dri2_surf->base.Height; +} + +static void +dri2_wl_swrast_get_image(__DRIdrawable * read, + int x, int y, int w, int h, + char *data, void *loaderPrivate) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w); + int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x); + int src_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width); + int dst_stride = copy_width; + char *src, *dst; + + src = dri2_wl_swrast_get_frontbuffer_data(dri2_surf); + if (!src) { + memset(data, 0, copy_width * h); + return; + } + + assert(data != src); + assert(copy_width <= src_stride); + + src += x_offset; + src += y * src_stride; + dst = data; + + if (copy_width > src_stride-x_offset) + copy_width = src_stride-x_offset; + if (h > dri2_surf->base.Height-y) + h = dri2_surf->base.Height-y; + + for (; h>0; h--) { + memcpy(dst, src, copy_width); + src += src_stride; + dst += dst_stride; + } +} + +static void +dri2_wl_swrast_put_image2(__DRIdrawable * draw, int op, + int x, int y, int w, int h, int stride, + char *data, void *loaderPrivate) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w); + int dst_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width); + int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x); + char *src, *dst; + + assert(copy_width <= stride); + + (void) swrast_update_buffers(dri2_surf); + dst = dri2_wl_swrast_get_backbuffer_data(dri2_surf); + + /* partial copy, copy old content */ + if (copy_width < dst_stride) + dri2_wl_swrast_get_image(draw, 0, 0, + dri2_surf->base.Width, dri2_surf->base.Height, + dst, loaderPrivate); + + dst += x_offset; + dst += y * dst_stride; + + src = data; + + /* drivers expect we do these checks (and some rely on it) */ + if (copy_width > dst_stride-x_offset) + copy_width = dst_stride-x_offset; + if (h > dri2_surf->base.Height-y) + h = dri2_surf->base.Height-y; + + for (; h>0; h--) { + memcpy(dst, src, copy_width); + src += stride; + dst += dst_stride; + } + dri2_wl_swrast_commit_backbuffer(dri2_surf); +} + +static void +dri2_wl_swrast_put_image(__DRIdrawable * draw, int op, + int x, int y, int w, int h, + char *data, void *loaderPrivate) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + int stride; + + stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w); + dri2_wl_swrast_put_image2(draw, op, x, y, w, h, + stride, data, loaderPrivate); +} + +/** + * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). + */ +static _EGLSurface * +dri2_wl_swrast_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, + _EGLConfig *conf, void *native_window, + const EGLint *attrib_list) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); + struct wl_egl_window *window = native_window; + struct dri2_egl_surface *dri2_surf; + + (void) drv; + + dri2_surf = calloc(1, sizeof *dri2_surf); + if (!dri2_surf) { + _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); + return NULL; + } + + if (!_eglInitSurface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list)) + goto cleanup_surf; + + if (conf->RedSize == 5) + dri2_surf->format = WL_SHM_FORMAT_RGB565; + else if (conf->AlphaSize == 0) + dri2_surf->format = WL_SHM_FORMAT_XRGB8888; + else + dri2_surf->format = WL_SHM_FORMAT_ARGB8888; + + dri2_surf->wl_win = window; + + dri2_surf->base.Width = -1; + dri2_surf->base.Height = -1; + + dri2_surf->dri_drawable = + (*dri2_dpy->swrast->createNewDrawable) (dri2_dpy->dri_screen, + dri2_conf->dri_double_config, + dri2_surf); + if (dri2_surf->dri_drawable == NULL) { + _eglError(EGL_BAD_ALLOC, "swrast->createNewDrawable"); + goto cleanup_dri_drawable; + } + + dri2_wl_swap_interval(drv, disp, &dri2_surf->base, + dri2_dpy->default_swap_interval); + + return &dri2_surf->base; + + cleanup_dri_drawable: + dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); + cleanup_surf: + free(dri2_surf); + + return NULL; +} + +static EGLBoolean +dri2_wl_swrast_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); + + dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable); + return EGL_TRUE; +} + +static void +shm_handle_format(void *data, struct wl_shm *shm, uint32_t format) +{ + struct dri2_egl_display *dri2_dpy = data; + + switch (format) { + case WL_SHM_FORMAT_ARGB8888: + dri2_dpy->formats |= HAS_ARGB8888; + break; + case WL_SHM_FORMAT_XRGB8888: + dri2_dpy->formats |= HAS_XRGB8888; + break; + case WL_SHM_FORMAT_RGB565: + dri2_dpy->formats |= HAS_RGB565; + break; + } +} + +static const struct wl_shm_listener shm_listener = { + shm_handle_format +}; + +static void +registry_handle_global_swrast(void *data, struct wl_registry *registry, uint32_t name, + const char *interface, uint32_t version) +{ + struct dri2_egl_display *dri2_dpy = data; + + if (strcmp(interface, "wl_shm") == 0) { + dri2_dpy->wl_shm = + wl_registry_bind(registry, name, &wl_shm_interface, 1); + wl_shm_add_listener(dri2_dpy->wl_shm, &shm_listener, dri2_dpy); + } +} + +static const struct wl_registry_listener registry_listener_swrast = { + registry_handle_global_swrast, + registry_handle_global_remove +}; + +static struct dri2_egl_display_vtbl dri2_wl_swrast_display_vtbl = { + .authenticate = NULL, + .create_window_surface = dri2_wl_swrast_create_window_surface, + .create_pixmap_surface = dri2_wl_create_pixmap_surface, + .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface, + .destroy_surface = dri2_wl_destroy_surface, + .create_image = dri2_fallback_create_image_khr, + .swap_interval = dri2_wl_swap_interval, + .swap_buffers = dri2_wl_swrast_swap_buffers, + .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage, + .swap_buffers_region = dri2_fallback_swap_buffers_region, + .post_sub_buffer = dri2_fallback_post_sub_buffer, + .copy_buffers = dri2_fallback_copy_buffers, + .query_buffer_age = dri2_fallback_query_buffer_age, + .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image, + .get_sync_values = dri2_fallback_get_sync_values, +}; + +static EGLBoolean +dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp) +{ + struct dri2_egl_display *dri2_dpy; + const __DRIconfig *config; + uint32_t types; + int i; + static const unsigned int argb_masks[4] = + { 0xff0000, 0xff00, 0xff, 0xff000000 }; + static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 }; + static const unsigned int rgb565_masks[4] = { 0xf800, 0x07e0, 0x001f, 0 }; + + loader_set_logger(_eglLog); + + dri2_dpy = calloc(1, sizeof *dri2_dpy); + if (!dri2_dpy) + return _eglError(EGL_BAD_ALLOC, "eglInitialize"); + + disp->DriverData = (void *) dri2_dpy; + if (disp->PlatformDisplay == NULL) { + dri2_dpy->wl_dpy = wl_display_connect(NULL); + if (dri2_dpy->wl_dpy == NULL) + goto cleanup_dpy; + dri2_dpy->own_device = 1; + } else { + dri2_dpy->wl_dpy = disp->PlatformDisplay; + } + + dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy); + + if (dri2_dpy->own_device) + wl_display_dispatch_pending(dri2_dpy->wl_dpy); + + dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy); + wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_registry, + dri2_dpy->wl_queue); + wl_registry_add_listener(dri2_dpy->wl_registry, + ®istry_listener_swrast, dri2_dpy); + + if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_shm == NULL) + goto cleanup_registry; + + if (roundtrip(dri2_dpy) < 0 || dri2_dpy->formats == 0) + goto cleanup_shm; + + dri2_dpy->driver_name = strdup("swrast"); + if (!dri2_load_driver_swrast(disp)) + goto cleanup_shm; + + dri2_dpy->swrast_loader_extension.base.name = __DRI_SWRAST_LOADER; + dri2_dpy->swrast_loader_extension.base.version = 2; + dri2_dpy->swrast_loader_extension.getDrawableInfo = dri2_wl_swrast_get_drawable_info; + dri2_dpy->swrast_loader_extension.putImage = dri2_wl_swrast_put_image; + dri2_dpy->swrast_loader_extension.getImage = dri2_wl_swrast_get_image; + dri2_dpy->swrast_loader_extension.putImage2 = dri2_wl_swrast_put_image2; + + dri2_dpy->extensions[0] = &dri2_dpy->swrast_loader_extension.base; + dri2_dpy->extensions[1] = NULL; + + if (!dri2_create_screen(disp)) + goto cleanup_driver; + + dri2_wl_setup_swap_interval(dri2_dpy); + + types = EGL_WINDOW_BIT; + for (i = 0; dri2_dpy->driver_configs[i]; i++) { + config = dri2_dpy->driver_configs[i]; + if (dri2_dpy->formats & HAS_XRGB8888) + dri2_add_config(disp, config, i + 1, types, NULL, rgb_masks); + if (dri2_dpy->formats & HAS_ARGB8888) + dri2_add_config(disp, config, i + 1, types, NULL, argb_masks); + if (dri2_dpy->formats & HAS_RGB565) + dri2_add_config(disp, config, i + 1, types, NULL, rgb565_masks); + } + + /* we're supporting EGL 1.4 */ + disp->VersionMajor = 1; + disp->VersionMinor = 4; + + /* Fill vtbl last to prevent accidentally calling virtual function during + * initialization. + */ + dri2_dpy->vtbl = &dri2_wl_swrast_display_vtbl; + + return EGL_TRUE; + + cleanup_driver: + dlclose(dri2_dpy->driver); + cleanup_shm: + wl_shm_destroy(dri2_dpy->wl_shm); + cleanup_registry: + wl_registry_destroy(dri2_dpy->wl_registry); + wl_event_queue_destroy(dri2_dpy->wl_queue); + cleanup_dpy: + free(dri2_dpy); + + return EGL_FALSE; +} + +EGLBoolean +dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) +{ + EGLBoolean initialized = EGL_TRUE; + + int hw_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL); + + if (hw_accel) { + if (!dri2_initialize_wayland_drm(drv, disp)) { + initialized = dri2_initialize_wayland_swrast(drv, disp); + } + } else { + initialized = dri2_initialize_wayland_swrast(drv, disp); + } + + return initialized; + +} -- 2.30.2