X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fegl%2Fdrivers%2Fdri2%2Fplatform_wayland.c;h=06de900d0cc14c19fef04835537d55a5ed2e1675;hb=75d398ed9309c0cb8179380bd317d8f935618df7;hp=fc21892813d3c344af3e9203ac7a6ddd14539150;hpb=2efc97d51300849636b4b64ef8dfb5645e3b4e5b;p=mesa.git diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index fc21892813d..06de900d0cc 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -36,6 +36,8 @@ #include #include "egl_dri2.h" +#include "egl_dri2_fallbacks.h" +#include "loader.h" #include #include "wayland-drm-client-protocol.h" @@ -46,6 +48,10 @@ enum wl_drm_format_flags { 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) { @@ -113,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); @@ -179,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); @@ -217,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; @@ -231,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); @@ -257,26 +271,31 @@ 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); - __DRIimage *image; - int i, name, pitch; + 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]; + dri2_surf->back = &dri2_surf->color_buffers[i]; else if (dri2_surf->back->dri_image == NULL) - dri2_surf->back = &dri2_surf->color_buffers[i]; + dri2_surf->back = &dri2_surf->color_buffers[i]; } } @@ -295,23 +314,30 @@ get_back_bo(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer) if (dri2_surf->back->dri_image == NULL) return -1; + dri2_surf->back->locked = 1; + + 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); - dri2_surf->back->name = name; - dri2_surf->back->pitch = pitch; - buffer->attachment = __DRI_BUFFER_BACK_LEFT; buffer->name = name; buffer->pitch = pitch; buffer->cpp = 4; buffer->flags = 0; - - dri2_surf->back->locked = 1; - - return 0; } static int @@ -337,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; @@ -360,22 +382,9 @@ dri2_get_buffers_with_format(__DRIdrawable * driDrawable, dri2_surf->dy = dri2_surf->wl_win->dy; } - 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; - } - break; - default: - if (get_aux_bo(dri2_surf, attachments[i], attachments[i + 1], - &dri2_surf->buffers[j]) < 0) { - _eglError(EGL_BAD_ALLOC, "failed to allocate aux buffer"); - return NULL; - } - break; - } + 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 @@ -391,6 +400,36 @@ dri2_get_buffers_with_format(__DRIdrawable * driDrawable, } } + 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: + back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]); + break; + default: + if (get_aux_bo(dri2_surf, attachments[i], attachments[i + 1], + &dri2_surf->buffers[j]) < 0) { + _eglError(EGL_BAD_ALLOC, "failed to allocate aux buffer"); + return NULL; + } + break; + } + } + *out_count = j; if (j == 0) return NULL; @@ -402,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; @@ -424,34 +463,62 @@ 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 @@ -459,7 +526,7 @@ 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; + int fd, stride, name; if (dri2_surf->current->wl_buffer != NULL) return; @@ -467,6 +534,8 @@ create_wl_buffer(struct dri2_egl_surface *dri2_surf) 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, @@ -474,17 +543,22 @@ create_wl_buffer(struct dri2_egl_surface *dri2_surf) dri2_surf->base.Width, dri2_surf->base.Height, dri2_surf->format, - 0, dri2_surf->current->pitch, + 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, - dri2_surf->current->name, + name, dri2_surf->base.Width, dri2_surf->base.Height, - dri2_surf->current->pitch, + stride, dri2_surf->format); } @@ -498,27 +572,17 @@ create_wl_buffer(struct dri2_egl_surface *dri2_surf) * Called via eglSwapBuffers(), drv->API.SwapBuffers(). */ static EGLBoolean -dri2_swap_buffers_with_damage(_EGLDriver *drv, - _EGLDisplay *disp, - _EGLSurface *draw, - const EGLint *rects, - EGLint n_rects) +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) @@ -526,11 +590,20 @@ dri2_swap_buffers_with_damage(_EGLDriver *drv, /* 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; @@ -548,8 +621,8 @@ dri2_swap_buffers_with_damage(_EGLDriver *drv, dri2_surf->dy = 0; if (n_rects == 0) { - wl_surface_damage(dri2_surf->wl_win->surface, 0, 0, - dri2_surf->base.Width, dri2_surf->base.Height); + 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]; @@ -560,22 +633,45 @@ dri2_swap_buffers_with_damage(_EGLDriver *drv, } } - 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; } @@ -584,13 +680,88 @@ dri2_query_buffer_age(_EGLDriver *drv, } static EGLBoolean -dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) +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) { - return dri2_swap_buffers_with_damage (drv, disp, draw, NULL, 0); + 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; @@ -614,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); @@ -732,6 +903,74 @@ static const struct wl_registry_listener registry_listener = { 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 dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) { @@ -744,12 +983,12 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) 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.SwapBuffersWithDamageEXT = dri2_swap_buffers_with_damage; - 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) @@ -784,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; @@ -795,19 +1034,24 @@ 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 @@ -821,16 +1065,16 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) 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, 0, types, NULL, rgb565_masks); + 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; @@ -838,6 +1082,11 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) 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: