X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fegl%2Fdrivers%2Fdri2%2Fplatform_wayland.c;h=06de900d0cc14c19fef04835537d55a5ed2e1675;hb=75d398ed9309c0cb8179380bd317d8f935618df7;hp=99d8729cfc19f03e4a6c702d7687fcef730e7efb;hpb=1fe007399c1ed28b8cef9d4f040164480423f2c9;p=mesa.git diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index 99d8729cfc1..06de900d0cc 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -36,15 +36,22 @@ #include #include "egl_dri2.h" +#include "egl_dri2_fallbacks.h" +#include "loader.h" #include #include "wayland-drm-client-protocol.h" enum wl_drm_format_flags { HAS_ARGB8888 = 1, - HAS_XRGB8888 = 2 + HAS_XRGB8888 = 2, + HAS_RGB565 = 4, }; +static EGLBoolean +dri2_wl_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, + EGLint interval); + static void sync_callback(void *data, struct wl_callback *callback, uint32_t serial) { @@ -112,9 +119,9 @@ resize_callback(struct wl_egl_window *wl_win, void *data) * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). */ static _EGLSurface * -dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, - _EGLConfig *conf, EGLNativeWindowType window, - const EGLint *attrib_list) +dri2_wl_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, + _EGLConfig *conf, EGLNativeWindowType 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); @@ -132,7 +139,9 @@ dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list)) goto cleanup_surf; - if (conf->AlphaSize == 0) + if (conf->RedSize == 5) + dri2_surf->format = WL_DRM_FORMAT_RGB565; + else if (conf->AlphaSize == 0) dri2_surf->format = WL_DRM_FORMAT_XRGB8888; else dri2_surf->format = WL_DRM_FORMAT_ARGB8888; @@ -176,19 +185,27 @@ dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). */ static _EGLSurface * -dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, - _EGLConfig *conf, EGLNativeWindowType window, - const EGLint *attrib_list) +dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, + _EGLConfig *conf, EGLNativeWindowType window, + const EGLint *attrib_list) { - return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf, - window, attrib_list); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + _EGLSurface *surf; + + surf = dri2_wl_create_surface(drv, disp, EGL_WINDOW_BIT, conf, + window, attrib_list); + + if (surf != NULL) + dri2_wl_swap_interval(drv, disp, surf, dri2_dpy->default_swap_interval); + + return surf; } /** * Called via eglDestroySurface(), drv->API.DestroySurface(). */ static EGLBoolean -dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) +dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); @@ -204,9 +221,8 @@ dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { if (dri2_surf->color_buffers[i].wl_buffer) wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); - if (dri2_surf->color_buffers[i].dri_buffer) - dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, - dri2_surf->color_buffers[i].dri_buffer); + if (dri2_surf->color_buffers[i].dri_image) + dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); } for (i = 0; i < __DRI_BUFFER_COUNT; i++) @@ -215,8 +231,8 @@ dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, dri2_surf->dri_buffers[i]); - if (dri2_surf->frame_callback) - wl_callback_destroy(dri2_surf->frame_callback); + if (dri2_surf->throttle_callback) + wl_callback_destroy(dri2_surf->throttle_callback); if (dri2_surf->base.Type == EGL_WINDOW_BIT) { dri2_surf->wl_win->private = NULL; @@ -229,7 +245,7 @@ dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) } static void -dri2_release_buffers(struct dri2_egl_surface *dri2_surf) +dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); @@ -239,12 +255,11 @@ dri2_release_buffers(struct dri2_egl_surface *dri2_surf) if (dri2_surf->color_buffers[i].wl_buffer && !dri2_surf->color_buffers[i].locked) wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); - if (dri2_surf->color_buffers[i].dri_buffer) - dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, - dri2_surf->color_buffers[i].dri_buffer); + if (dri2_surf->color_buffers[i].dri_image) + dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); dri2_surf->color_buffers[i].wl_buffer = NULL; - dri2_surf->color_buffers[i].dri_buffer = NULL; + dri2_surf->color_buffers[i].dri_image = NULL; dri2_surf->color_buffers[i].locked = 0; } @@ -256,47 +271,75 @@ dri2_release_buffers(struct dri2_egl_surface *dri2_surf) } static int -get_back_bo(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer) +get_back_bo(struct dri2_egl_surface *dri2_surf) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); int i; - /* There might be a buffer release already queued that wasn't processed */ - wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_dpy->wl_queue); + /* 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; if (dri2_surf->back == NULL) { for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { - /* Get an unlocked buffer, preferrably one with a dri_buffer already - * allocated. */ - if (dri2_surf->color_buffers[i].locked) + /* Get an unlocked buffer, preferrably one with a dri_buffer + * already allocated. */ + if (dri2_surf->color_buffers[i].locked) continue; if (dri2_surf->back == NULL) - dri2_surf->back = &dri2_surf->color_buffers[i]; - else if (dri2_surf->back->dri_buffer == NULL) - dri2_surf->back = &dri2_surf->color_buffers[i]; + dri2_surf->back = &dri2_surf->color_buffers[i]; + else if (dri2_surf->back->dri_image == NULL) + dri2_surf->back = &dri2_surf->color_buffers[i]; } } if (dri2_surf->back == NULL) return -1; - if (dri2_surf->back->dri_buffer == NULL) { - dri2_surf->back->dri_buffer = - dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, - __DRI_BUFFER_BACK_LEFT, 32, - dri2_surf->base.Width, - dri2_surf->base.Height); + if (dri2_surf->back->dri_image == NULL) { + dri2_surf->back->dri_image = + dri2_dpy->image->createImage(dri2_dpy->dri_screen, + dri2_surf->base.Width, + dri2_surf->base.Height, + __DRI_IMAGE_FORMAT_ARGB8888, + __DRI_IMAGE_USE_SHARE, + NULL); dri2_surf->back->age = 0; } - if (dri2_surf->back->dri_buffer == NULL) + if (dri2_surf->back->dri_image == NULL) return -1; dri2_surf->back->locked = 1; - memcpy(buffer, dri2_surf->back->dri_buffer, sizeof *buffer); return 0; } + +static void +back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + __DRIimage *image; + int name, pitch; + + image = dri2_surf->back->dri_image; + + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name); + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch); + + buffer->attachment = __DRI_BUFFER_BACK_LEFT; + buffer->name = name; + buffer->pitch = pitch; + buffer->cpp = 4; + buffer->flags = 0; +} + static int get_aux_bo(struct dri2_egl_surface *dri2_surf, unsigned int attachment, unsigned int format, __DRIbuffer *buffer) @@ -320,22 +363,18 @@ get_aux_bo(struct dri2_egl_surface *dri2_surf, return 0; } -static __DRIbuffer * -dri2_get_buffers_with_format(__DRIdrawable * driDrawable, - int *width, int *height, - unsigned int *attachments, int count, - int *out_count, void *loaderPrivate) +static int +update_buffers(struct dri2_egl_surface *dri2_surf) { - struct dri2_egl_surface *dri2_surf = loaderPrivate; struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); - int i, j; + int i; if (dri2_surf->base.Type == EGL_WINDOW_BIT && (dri2_surf->base.Width != dri2_surf->wl_win->width || dri2_surf->base.Height != dri2_surf->wl_win->height)) { - dri2_release_buffers(dri2_surf); + dri2_wl_release_buffers(dri2_surf); dri2_surf->base.Width = dri2_surf->wl_win->width; dri2_surf->base.Height = dri2_surf->wl_win->height; @@ -343,13 +382,43 @@ dri2_get_buffers_with_format(__DRIdrawable * driDrawable, dri2_surf->dy = dri2_surf->wl_win->dy; } + if (get_back_bo(dri2_surf) < 0) { + _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer"); + return -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); + dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); + dri2_surf->color_buffers[i].wl_buffer = NULL; + dri2_surf->color_buffers[i].dri_image = NULL; + } + } + + return 0; +} + +static __DRIbuffer * +dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable, + int *width, int *height, + unsigned int *attachments, int count, + int *out_count, void *loaderPrivate) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + int i, j; + + if (update_buffers(dri2_surf) < 0) + return NULL; + for (i = 0, j = 0; i < 2 * count; i += 2, j++) { switch (attachments[i]) { case __DRI_BUFFER_BACK_LEFT: - if (get_back_bo(dri2_surf, &dri2_surf->buffers[j]) < 0) { - _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer"); - return NULL; - } + back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]); break; default: if (get_aux_bo(dri2_surf, attachments[i], attachments[i + 1], @@ -361,20 +430,6 @@ dri2_get_buffers_with_format(__DRIdrawable * driDrawable, } } - /* 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); - dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, - dri2_surf->color_buffers[i].dri_buffer); - dri2_surf->color_buffers[i].wl_buffer = NULL; - dri2_surf->color_buffers[i].dri_buffer = NULL; - } - } - *out_count = j; if (j == 0) return NULL; @@ -386,10 +441,10 @@ dri2_get_buffers_with_format(__DRIdrawable * driDrawable, } static __DRIbuffer * -dri2_get_buffers(__DRIdrawable * driDrawable, - int *width, int *height, - unsigned int *attachments, int count, - int *out_count, void *loaderPrivate) +dri2_wl_get_buffers(__DRIdrawable * driDrawable, + int *width, int *height, + unsigned int *attachments, int count, + int *out_count, void *loaderPrivate) { unsigned int *attachments_with_format; __DRIbuffer *buffer; @@ -408,57 +463,126 @@ dri2_get_buffers(__DRIdrawable * driDrawable, } buffer = - dri2_get_buffers_with_format(driDrawable, - width, height, - attachments_with_format, count, - out_count, loaderPrivate); + dri2_wl_get_buffers_with_format(driDrawable, + width, height, + attachments_with_format, count, + out_count, loaderPrivate); free(attachments_with_format); return buffer; } +static int +image_get_buffers(__DRIdrawable *driDrawable, + unsigned int format, + uint32_t *stamp, + void *loaderPrivate, + uint32_t buffer_mask, + struct __DRIimageList *buffers) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + + if (update_buffers(dri2_surf) < 0) + return 0; + + buffers->image_mask = __DRI_IMAGE_BUFFER_BACK; + buffers->back = dri2_surf->back->dri_image; + + return 1; +} + static void -dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) +dri2_wl_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) { (void) driDrawable; (void) loaderPrivate; } +static const __DRIimageLoaderExtension image_loader_extension = { + .base = { __DRI_IMAGE_LOADER, 1 }, + + .getBuffers = image_get_buffers, + .flushFrontBuffer = dri2_wl_flush_front_buffer, +}; + static void -wayland_frame_callback(void *data, struct wl_callback *callback, uint32_t time) +wayland_throttle_callback(void *data, + struct wl_callback *callback, + uint32_t time) { struct dri2_egl_surface *dri2_surf = data; - dri2_surf->frame_callback = NULL; + dri2_surf->throttle_callback = NULL; wl_callback_destroy(callback); } -static const struct wl_callback_listener frame_listener = { - wayland_frame_callback +static const struct wl_callback_listener throttle_listener = { + wayland_throttle_callback }; +static void +create_wl_buffer(struct dri2_egl_surface *dri2_surf) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + int fd, stride, name; + + if (dri2_surf->current->wl_buffer != NULL) + return; + + if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) { + dri2_dpy->image->queryImage(dri2_surf->current->dri_image, + __DRI_IMAGE_ATTRIB_FD, &fd); + dri2_dpy->image->queryImage(dri2_surf->current->dri_image, + __DRI_IMAGE_ATTRIB_STRIDE, &stride); + + dri2_surf->current->wl_buffer = + wl_drm_create_prime_buffer(dri2_dpy->wl_drm, + fd, + dri2_surf->base.Width, + dri2_surf->base.Height, + dri2_surf->format, + 0, stride, + 0, 0, + 0, 0); + close(fd); + } else { + dri2_dpy->image->queryImage(dri2_surf->current->dri_image, + __DRI_IMAGE_ATTRIB_NAME, &name); + dri2_dpy->image->queryImage(dri2_surf->current->dri_image, + __DRI_IMAGE_ATTRIB_STRIDE, &stride); + + dri2_surf->current->wl_buffer = + wl_drm_create_buffer(dri2_dpy->wl_drm, + name, + dri2_surf->base.Width, + dri2_surf->base.Height, + stride, + dri2_surf->format); + } + + wl_proxy_set_queue((struct wl_proxy *) dri2_surf->current->wl_buffer, + dri2_dpy->wl_queue); + wl_buffer_add_listener(dri2_surf->current->wl_buffer, + &wl_buffer_listener, dri2_surf); +} + /** * Called via eglSwapBuffers(), drv->API.SwapBuffers(). */ static EGLBoolean -dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) +dri2_wl_swap_buffers_with_damage(_EGLDriver *drv, + _EGLDisplay *disp, + _EGLSurface *draw, + const EGLint *rects, + EGLint n_rects) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); - __DRIbuffer buffer; - int i, ret = 0; - - while (dri2_surf->frame_callback && ret != -1) - ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue); - if (ret < 0) - return EGL_FALSE; - - dri2_surf->frame_callback = wl_surface_frame(dri2_surf->wl_win->surface); - wl_callback_add_listener(dri2_surf->frame_callback, - &frame_listener, dri2_surf); - wl_proxy_set_queue((struct wl_proxy *) dri2_surf->frame_callback, - dri2_dpy->wl_queue); + struct dri2_egl_context *dri2_ctx; + _EGLContext *ctx; + int i; for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) if (dri2_surf->color_buffers[i].age > 0) @@ -466,28 +590,25 @@ dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) /* Make sure we have a back buffer in case we're swapping without ever * rendering. */ - if (get_back_bo(dri2_surf, &buffer) < 0) { + if (get_back_bo(dri2_surf) < 0) { _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers"); return EGL_FALSE; } + if (draw->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->back->age = 1; dri2_surf->current = dri2_surf->back; dri2_surf->back = NULL; - if (dri2_surf->current->wl_buffer == NULL) { - dri2_surf->current->wl_buffer = - wl_drm_create_buffer(dri2_dpy->wl_drm, - dri2_surf->current->dri_buffer->name, - dri2_surf->base.Width, - dri2_surf->base.Height, - dri2_surf->current->dri_buffer->pitch, - dri2_surf->format); - wl_proxy_set_queue((struct wl_proxy *) dri2_surf->current->wl_buffer, - dri2_dpy->wl_queue); - wl_buffer_add_listener(dri2_surf->current->wl_buffer, - &wl_buffer_listener, dri2_surf); - } + create_wl_buffer(dri2_surf); wl_surface_attach(dri2_surf->wl_win->surface, dri2_surf->current->wl_buffer, @@ -499,25 +620,58 @@ dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) dri2_surf->dx = 0; dri2_surf->dy = 0; - wl_surface_damage(dri2_surf->wl_win->surface, 0, 0, - dri2_surf->base.Width, dri2_surf->base.Height); + if (n_rects == 0) { + wl_surface_damage(dri2_surf->wl_win->surface, + 0, 0, INT32_MAX, INT32_MAX); + } else { + for (i = 0; i < n_rects; i++) { + const int *rect = &rects[i * 4]; + wl_surface_damage(dri2_surf->wl_win->surface, + rect[0], + dri2_surf->base.Height - rect[1] - rect[3], + rect[2], rect[3]); + } + } - wl_surface_commit(dri2_surf->wl_win->surface); + if (dri2_dpy->flush->base.version >= 4) { + ctx = _eglGetCurrentContext(); + dri2_ctx = dri2_egl_context(ctx); + (*dri2_dpy->flush->flush_with_flags)(dri2_ctx->dri_context, + dri2_surf->dri_drawable, + __DRI2_FLUSH_DRAWABLE, + __DRI2_THROTTLE_SWAPBUFFER); + } else { + (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); + } - (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable); + 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); + return EGL_TRUE; } static EGLint -dri2_query_buffer_age(_EGLDriver *drv, - _EGLDisplay *disp, _EGLSurface *surface) +dri2_wl_query_buffer_age(_EGLDriver *drv, + _EGLDisplay *disp, _EGLSurface *surface) { struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface); - __DRIbuffer buffer; - if (get_back_bo(dri2_surf, &buffer) < 0) { + if (get_back_bo(dri2_surf) < 0) { _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age"); return 0; } @@ -525,8 +679,89 @@ dri2_query_buffer_age(_EGLDriver *drv, return dri2_surf->back->age; } +static EGLBoolean +dri2_wl_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) +{ + return dri2_wl_swap_buffers_with_damage (drv, disp, draw, NULL, 0); +} + +static struct wl_buffer * +dri2_wl_create_wayland_buffer_from_image_wl(_EGLDriver *drv, + _EGLDisplay *disp, + _EGLImage *img) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_image *dri2_img = dri2_egl_image(img); + __DRIimage *image = dri2_img->dri_image; + struct wl_buffer *buffer; + int width, height, format, pitch; + enum wl_drm_format wl_format; + + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format); + + switch (format) { + case __DRI_IMAGE_FORMAT_ARGB8888: + if (!(dri2_dpy->formats & HAS_ARGB8888)) + goto bad_format; + wl_format = WL_DRM_FORMAT_ARGB8888; + break; + case __DRI_IMAGE_FORMAT_XRGB8888: + if (!(dri2_dpy->formats & HAS_XRGB8888)) + goto bad_format; + wl_format = WL_DRM_FORMAT_XRGB8888; + break; + default: + goto bad_format; + } + + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width); + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, &height); + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch); + + if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) { + int fd; + + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd); + + buffer = + wl_drm_create_prime_buffer(dri2_dpy->wl_drm, + fd, + width, height, + wl_format, + 0, pitch, + 0, 0, + 0, 0); + + close(fd); + } else { + int name; + + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name); + + buffer = + wl_drm_create_buffer(dri2_dpy->wl_drm, + name, + width, height, + pitch, + wl_format); + } + + /* The buffer object will have been created with our internal event queue + * because it is using the wl_drm object as a proxy factory. We want the + * buffer to be used by the application so we'll reset it to the display's + * default event queue */ + if (buffer) + wl_proxy_set_queue((struct wl_proxy *) buffer, NULL); + + return buffer; + +bad_format: + _eglError(EGL_BAD_MATCH, "unsupported image format"); + return NULL; +} + static int -dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id) +dri2_wl_authenticate(_EGLDisplay *disp, uint32_t id) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); int ret = 0; @@ -550,7 +785,7 @@ dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id) * Called via eglTerminate(), drv->API.Terminate(). */ static EGLBoolean -dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) +dri2_wl_terminate(_EGLDriver *drv, _EGLDisplay *disp) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); @@ -613,9 +848,20 @@ drm_handle_format(void *data, struct wl_drm *drm, uint32_t format) case WL_DRM_FORMAT_XRGB8888: dri2_dpy->formats |= HAS_XRGB8888; break; + case WL_DRM_FORMAT_RGB565: + dri2_dpy->formats |= HAS_RGB565; + break; } } +static void +drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value) +{ + struct dri2_egl_display *dri2_dpy = data; + + dri2_dpy->capabilities = value; +} + static void drm_handle_authenticated(void *data, struct wl_drm *drm) { @@ -627,7 +873,8 @@ drm_handle_authenticated(void *data, struct wl_drm *drm) static const struct wl_drm_listener drm_listener = { drm_handle_device, drm_handle_format, - drm_handle_authenticated + drm_handle_authenticated, + drm_handle_capabilities }; static void @@ -636,15 +883,92 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t name, { struct dri2_egl_display *dri2_dpy = data; + if (version > 1) + version = 2; if (strcmp(interface, "wl_drm") == 0) { dri2_dpy->wl_drm = - wl_registry_bind(registry, name, &wl_drm_interface, 1); + wl_registry_bind(registry, name, &wl_drm_interface, version); wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy); } } +static void +registry_handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ +} + static const struct wl_registry_listener registry_listener = { - registry_handle_global + registry_handle_global, + registry_handle_global_remove +}; + +static EGLBoolean +dri2_wl_swap_interval(_EGLDriver *drv, + _EGLDisplay *disp, + _EGLSurface *surf, + EGLint interval) +{ + if (interval > surf->Config->MaxSwapInterval) + interval = surf->Config->MaxSwapInterval; + else if (interval < surf->Config->MinSwapInterval) + interval = surf->Config->MinSwapInterval; + + surf->SwapInterval = interval; + + return EGL_TRUE; +} + +static void +dri2_wl_setup_swap_interval(struct dri2_egl_display *dri2_dpy) +{ + GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; + + /* We can't use values greater than 1 on Wayland because we are using the + * frame callback to synchronise the frame and the only way we be sure to + * get a frame callback is to attach a new buffer. Therefore we can't just + * sit drawing nothing to wait until the next ‘n’ frame callbacks */ + + if (dri2_dpy->config) + dri2_dpy->config->configQueryi(dri2_dpy->dri_screen, + "vblank_mode", &vblank_mode); + switch (vblank_mode) { + case DRI_CONF_VBLANK_NEVER: + dri2_dpy->min_swap_interval = 0; + dri2_dpy->max_swap_interval = 0; + dri2_dpy->default_swap_interval = 0; + break; + case DRI_CONF_VBLANK_ALWAYS_SYNC: + dri2_dpy->min_swap_interval = 1; + dri2_dpy->max_swap_interval = 1; + dri2_dpy->default_swap_interval = 1; + break; + case DRI_CONF_VBLANK_DEF_INTERVAL_0: + dri2_dpy->min_swap_interval = 0; + dri2_dpy->max_swap_interval = 1; + dri2_dpy->default_swap_interval = 0; + break; + default: + case DRI_CONF_VBLANK_DEF_INTERVAL_1: + dri2_dpy->min_swap_interval = 0; + dri2_dpy->max_swap_interval = 1; + dri2_dpy->default_swap_interval = 1; + break; + } +} + +static struct dri2_egl_display_vtbl dri2_wl_display_vtbl = { + .authenticate = dri2_wl_authenticate, + .create_window_surface = dri2_wl_create_window_surface, + .create_pixmap_surface = dri2_fallback_create_pixmap_surface, + .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface, + .destroy_surface = dri2_wl_destroy_surface, + .swap_interval = dri2_wl_swap_interval, + .swap_buffers = dri2_wl_swap_buffers, + .swap_buffers_with_damage = dri2_wl_swap_buffers_with_damage, + .swap_buffers_region = dri2_fallback_swap_buffers_region, + .copy_buffers = dri2_fallback_copy_buffers, + .query_buffer_age = dri2_wl_query_buffer_age, }; EGLBoolean @@ -657,12 +981,14 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) 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 }; - drv->API.CreateWindowSurface = dri2_create_window_surface; - drv->API.DestroySurface = dri2_destroy_surface; - drv->API.SwapBuffers = dri2_swap_buffers; - drv->API.Terminate = dri2_terminate; - drv->API.QueryBufferAge = dri2_query_buffer_age; + loader_set_logger(_eglLog); + + drv->API.Terminate = dri2_wl_terminate; + + drv->API.CreateWaylandBufferFromImageWL = + dri2_wl_create_wayland_buffer_from_image_wl; dri2_dpy = calloc(1, sizeof *dri2_dpy); if (!dri2_dpy) @@ -679,6 +1005,10 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) } 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); @@ -693,7 +1023,7 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated) goto cleanup_fd; - dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd); + dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0); if (dri2_dpy->driver_name == NULL) { _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name"); goto cleanup_fd; @@ -704,36 +1034,59 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER; dri2_dpy->dri2_loader_extension.base.version = 3; - dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers; - dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer; + dri2_dpy->dri2_loader_extension.getBuffers = dri2_wl_get_buffers; + dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_wl_flush_front_buffer; dri2_dpy->dri2_loader_extension.getBuffersWithFormat = - dri2_get_buffers_with_format; - + dri2_wl_get_buffers_with_format; + dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base; - dri2_dpy->extensions[1] = &image_lookup_extension.base; - dri2_dpy->extensions[2] = &use_invalidate.base; - dri2_dpy->extensions[3] = NULL; + dri2_dpy->extensions[1] = &image_loader_extension.base; + dri2_dpy->extensions[2] = &image_lookup_extension.base; + dri2_dpy->extensions[3] = &use_invalidate.base; + dri2_dpy->extensions[4] = NULL; + + dri2_dpy->swap_available = EGL_TRUE; if (!dri2_create_screen(disp)) goto cleanup_driver; + dri2_wl_setup_swap_interval(dri2_dpy); + + /* The server shouldn't advertise WL_DRM_CAPABILITY_PRIME if the driver + * doesn't have createImageFromFds, since we're using the same driver on + * both sides. We don't want crash if that happens anyway, so fall back to + * gem names if we don't have prime support. */ + + if (dri2_dpy->image->base.version < 7 || + dri2_dpy->image->createImageFromFds == NULL) + dri2_dpy->capabilities &= WL_DRM_CAPABILITY_PRIME; + 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, 0, types, NULL, rgb_masks); + dri2_add_config(disp, config, i + 1, types, NULL, rgb_masks); if (dri2_dpy->formats & HAS_ARGB8888) - dri2_add_config(disp, config, i + 1, 0, types, NULL, argb_masks); + 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); } disp->Extensions.WL_bind_wayland_display = EGL_TRUE; + disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE; disp->Extensions.EXT_buffer_age = EGL_TRUE; - dri2_dpy->authenticate = dri2_wayland_authenticate; + + disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE; /* 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_display_vtbl; + return EGL_TRUE; cleanup_driver: