X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fegl%2Fdrivers%2Fdri2%2Fplatform_wayland.c;h=5b8bec901b076799ee6e762ac5c31b178acfe41d;hb=a34715ad9c84c4209de4c16fdf40655181350bd9;hp=ee68284217b444f32a2f5143c64e31ad9de720a3;hpb=5295df63ad7822e14e7dabfc107bc416271bfcdc;p=mesa.git diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index ee68284217b..5b8bec901b0 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -36,24 +36,130 @@ #include #include #include +#include #include #include "egl_dri2.h" #include "egl_dri2_fallbacks.h" #include "loader.h" +#include "util/u_vector.h" +#include "eglglobals.h" #include #include "wayland-drm-client-protocol.h" +#include "linux-dmabuf-unstable-v1-client-protocol.h" -enum wl_drm_format_flags { - HAS_ARGB8888 = 1, - HAS_XRGB8888 = 2, - HAS_RGB565 = 4, +#ifndef DRM_FORMAT_MOD_INVALID +#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1) +#endif + +#ifndef DRM_FORMAT_MOD_LINEAR +#define DRM_FORMAT_MOD_LINEAR 0 +#endif + +/* + * The index of entries in this table is used as a bitmask in + * dri2_dpy->formats, which tracks the formats supported by our server. + */ +static const struct dri2_wl_visual { + const char *format_name; + uint32_t wl_drm_format; + uint32_t wl_shm_format; + int dri_image_format; + int bpp; + unsigned int rgba_masks[4]; +} dri2_wl_visuals[] = { + { + "XRGB2101010", + WL_DRM_FORMAT_XRGB2101010, WL_SHM_FORMAT_XRGB2101010, + __DRI_IMAGE_FORMAT_XRGB2101010, 32, + { 0x3ff00000, 0x000ffc00, 0x000003ff, 0x00000000 } + }, + { + "ARGB2101010", + WL_DRM_FORMAT_ARGB2101010, WL_SHM_FORMAT_ARGB2101010, + __DRI_IMAGE_FORMAT_ARGB2101010, 32, + { 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 } + }, + { + "XRGB8888", + WL_DRM_FORMAT_XRGB8888, WL_SHM_FORMAT_XRGB8888, + __DRI_IMAGE_FORMAT_XRGB8888, 32, + { 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 } + }, + { + "ARGB8888", + WL_DRM_FORMAT_ARGB8888, WL_SHM_FORMAT_ARGB8888, + __DRI_IMAGE_FORMAT_ARGB8888, 32, + { 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 } + }, + { + "RGB565", + WL_DRM_FORMAT_RGB565, WL_SHM_FORMAT_RGB565, + __DRI_IMAGE_FORMAT_RGB565, 16, + { 0xf800, 0x07e0, 0x001f, 0x0000 } + }, }; -static EGLBoolean -dri2_wl_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, - EGLint interval); +static int +dri2_wl_visual_idx_from_config(struct dri2_egl_display *dri2_dpy, + const __DRIconfig *config) +{ + unsigned int red, green, blue, alpha; + + dri2_dpy->core->getConfigAttrib(config, __DRI_ATTRIB_RED_MASK, &red); + dri2_dpy->core->getConfigAttrib(config, __DRI_ATTRIB_GREEN_MASK, &green); + dri2_dpy->core->getConfigAttrib(config, __DRI_ATTRIB_BLUE_MASK, &blue); + dri2_dpy->core->getConfigAttrib(config, __DRI_ATTRIB_ALPHA_MASK, &alpha); + + for (unsigned int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) { + const struct dri2_wl_visual *wl_visual = &dri2_wl_visuals[i]; + + if (red == wl_visual->rgba_masks[0] && + green == wl_visual->rgba_masks[1] && + blue == wl_visual->rgba_masks[2] && + alpha == wl_visual->rgba_masks[3]) { + return i; + } + } + + return -1; +} + +static int +dri2_wl_visual_idx_from_fourcc(uint32_t fourcc) +{ + for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) { + /* wl_drm format codes overlap with DRIImage FourCC codes for all formats + * we support. */ + if (dri2_wl_visuals[i].wl_drm_format == fourcc) + return i; + } + + return -1; +} + +static int +dri2_wl_visual_idx_from_dri_image_format(uint32_t dri_image_format) +{ + for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) { + if (dri2_wl_visuals[i].dri_image_format == dri_image_format) + return i; + } + + return -1; +} + +static int +dri2_wl_visual_idx_from_shm_format(uint32_t shm_format) +{ + for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) { + if (dri2_wl_visuals[i].wl_shm_format == shm_format) + return i; + } + + return -1; +} static int roundtrip(struct dri2_egl_display *dri2_dpy) @@ -100,6 +206,19 @@ destroy_window_callback(void *data) dri2_surf->wl_win = NULL; } +static struct wl_surface * +get_wl_surface_proxy(struct wl_egl_window *window) +{ + /* Version 3 of wl_egl_window introduced a version field at the same + * location where a pointer to wl_surface was stored. Thus, if + * window->version is dereferencable, we've been given an older version of + * wl_egl_window, and window->version points to wl_surface */ + if (_eglPointerIsDereferencable((void *)(window->version))) { + return wl_proxy_create_wrapper((void *)(window->version)); + } + return wl_proxy_create_wrapper(window->surface); +} + /** * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). */ @@ -113,6 +232,7 @@ dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); struct wl_egl_window *window = native_window; struct dri2_egl_surface *dri2_surf; + int visual_idx; const __DRIconfig *config; dri2_surf = calloc(1, sizeof *dri2_surf); @@ -121,32 +241,22 @@ dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, return NULL; } - if (!_eglInitSurface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list)) + if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, + attrib_list, false)) goto cleanup_surf; - if (dri2_dpy->wl_drm) { - 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; + config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT, + dri2_surf->base.GLColorspace); + visual_idx = dri2_wl_visual_idx_from_config(dri2_dpy, config); + assert(visual_idx != -1); + + if (dri2_dpy->wl_dmabuf || dri2_dpy->wl_drm) { + dri2_surf->format = dri2_wl_visuals[visual_idx].wl_drm_format; } else { assert(dri2_dpy->wl_shm); - 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; - } - - if (!window) { - _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_create_surface"); - goto cleanup_surf; + dri2_surf->format = dri2_wl_visuals[visual_idx].wl_shm_format; } - dri2_surf->wl_win = window; dri2_surf->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy); if (!dri2_surf->wl_queue) { _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); @@ -171,23 +281,17 @@ dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_dpy_wrapper, dri2_surf->wl_queue); - dri2_surf->wl_surface_wrapper = wl_proxy_create_wrapper(window->surface); + dri2_surf->wl_surface_wrapper = get_wl_surface_proxy(window); if (!dri2_surf->wl_surface_wrapper) { _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); - goto cleanup_drm; + goto cleanup_dpy_wrapper; } wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_surface_wrapper, dri2_surf->wl_queue); + dri2_surf->wl_win = window; dri2_surf->wl_win->private = dri2_surf; dri2_surf->wl_win->destroy_window_callback = destroy_window_callback; - - dri2_surf->base.Width = -1; - dri2_surf->base.Height = -1; - - config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT, - dri2_surf->base.GLColorspace); - if (dri2_dpy->flush) dri2_surf->wl_win->resize_callback = resize_callback; @@ -202,14 +306,17 @@ dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, dri2_surf); if (dri2_surf->dri_drawable == NULL) { _eglError(EGL_BAD_ALLOC, "createNewDrawable"); - goto cleanup_surf; + goto cleanup_surf_wrapper; } - dri2_wl_swap_interval(drv, disp, &dri2_surf->base, - dri2_dpy->default_swap_interval); + dri2_surf->base.SwapInterval = dri2_dpy->default_swap_interval; return &dri2_surf->base; + cleanup_surf_wrapper: + wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper); + cleanup_dpy_wrapper: + wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper); cleanup_drm: if (dri2_surf->wl_drm_wrapper) wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper); @@ -262,13 +369,8 @@ dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) dri2_surf->color_buffers[i].data_size); } - if (dri2_dpy->dri2) { - for (int 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) + dri2_egl_surface_free_local_buffers(dri2_surf); if (dri2_surf->throttle_callback) wl_callback_destroy(dri2_surf->throttle_callback); @@ -279,12 +381,13 @@ dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) dri2_surf->wl_win->destroy_window_callback = NULL; } - if (dri2_surf->wl_drm_wrapper) - wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper); wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper); wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper); + if (dri2_surf->wl_drm_wrapper) + wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper); wl_event_queue_destroy(dri2_surf->wl_queue); + dri2_fini_surface(surf); free(surf); return EGL_TRUE; @@ -315,13 +418,8 @@ dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf) dri2_surf->color_buffers[i].locked = false; } - if (dri2_dpy->dri2) { - for (int 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) + dri2_egl_surface_free_local_buffers(dri2_surf); } static int @@ -330,26 +428,16 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); int use_flags; + int visual_idx; unsigned int dri_image_format; + uint64_t *modifiers; + int num_modifiers; - /* currently supports three WL DRM formats, - * WL_DRM_FORMAT_ARGB8888, WL_DRM_FORMAT_XRGB8888, - * and WL_DRM_FORMAT_RGB565 - */ - switch (dri2_surf->format) { - case WL_DRM_FORMAT_ARGB8888: - dri_image_format = __DRI_IMAGE_FORMAT_ARGB8888; - break; - case WL_DRM_FORMAT_XRGB8888: - dri_image_format = __DRI_IMAGE_FORMAT_XRGB8888; - break; - case WL_DRM_FORMAT_RGB565: - dri_image_format = __DRI_IMAGE_FORMAT_RGB565; - break; - default: - /* format is not supported */ - return -1; - } + visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format); + assert(visual_idx != -1); + dri_image_format = dri2_wl_visuals[visual_idx].dri_image_format; + modifiers = u_vector_tail(&dri2_dpy->wl_modifiers[visual_idx]); + num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers[visual_idx]); /* There might be a buffer release already queued that wasn't processed */ wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue); @@ -370,8 +458,13 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) break; /* If we don't have a buffer, then block on the server to release one for - * us, and try again. */ - if (wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_surf->wl_queue) < 0) + * us, and try again. wl_display_dispatch_queue will process any pending + * events, however not all servers flush on issuing a buffer release + * event. So, we spam the server with roundtrips as they always cause a + * client flush. + */ + if (wl_display_roundtrip_queue(dri2_dpy->wl_dpy, + dri2_surf->wl_queue) < 0) return -1; } @@ -382,27 +475,60 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) if (dri2_dpy->is_different_gpu && dri2_surf->back->linear_copy == NULL) { - dri2_surf->back->linear_copy = - dri2_dpy->image->createImage(dri2_dpy->dri_screen, - dri2_surf->base.Width, - dri2_surf->base.Height, - dri_image_format, - use_flags | - __DRI_IMAGE_USE_LINEAR, - NULL); + /* The LINEAR modifier should be a perfect alias of the LINEAR use + * flag; try the new interface first before the old, then fall back. */ + if (dri2_dpy->image->base.version >= 15 && + dri2_dpy->image->createImageWithModifiers) { + uint64_t linear_mod = DRM_FORMAT_MOD_LINEAR; + + dri2_surf->back->linear_copy = + dri2_dpy->image->createImageWithModifiers(dri2_dpy->dri_screen, + dri2_surf->base.Width, + dri2_surf->base.Height, + dri_image_format, + &linear_mod, + 1, + NULL); + } else { + dri2_surf->back->linear_copy = + dri2_dpy->image->createImage(dri2_dpy->dri_screen, + dri2_surf->base.Width, + dri2_surf->base.Height, + dri_image_format, + use_flags | + __DRI_IMAGE_USE_LINEAR, + NULL); + } if (dri2_surf->back->linear_copy == NULL) return -1; } 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, - dri2_dpy->is_different_gpu ? - 0 : use_flags, - NULL); + /* If our DRIImage implementation does not support + * createImageWithModifiers, then fall back to the old createImage, + * and hope it allocates an image which is acceptable to the winsys. + */ + if (num_modifiers && dri2_dpy->image->base.version >= 15 && + dri2_dpy->image->createImageWithModifiers) { + dri2_surf->back->dri_image = + dri2_dpy->image->createImageWithModifiers(dri2_dpy->dri_screen, + dri2_surf->base.Width, + dri2_surf->base.Height, + dri_image_format, + modifiers, + num_modifiers, + NULL); + } else { + dri2_surf->back->dri_image = + dri2_dpy->image->createImage(dri2_dpy->dri_screen, + dri2_surf->base.Width, + dri2_surf->base.Height, + dri_image_format, + dri2_dpy->is_different_gpu ? + 0 : use_flags, + NULL); + } + dri2_surf->back->age = 0; } if (dri2_surf->back->dri_image == NULL) @@ -434,29 +560,6 @@ back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer) buffer->flags = 0; } -static int -get_aux_bo(struct dri2_egl_surface *dri2_surf, - unsigned int attachment, unsigned int format, __DRIbuffer *buffer) -{ - struct dri2_egl_display *dri2_dpy = - dri2_egl_display(dri2_surf->base.Resource.Display); - __DRIbuffer *b = dri2_surf->dri_buffers[attachment]; - - if (b == NULL) { - b = dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, - attachment, format, - dri2_surf->base.Width, - dri2_surf->base.Height); - dri2_surf->dri_buffers[attachment] = b; - } - if (b == NULL) - return -1; - - memcpy(buffer, b, sizeof *buffer); - - return 0; -} - static int update_buffers(struct dri2_egl_surface *dri2_surf) { @@ -511,16 +614,21 @@ dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable, return NULL; for (i = 0, j = 0; i < 2 * count; i += 2, j++) { + __DRIbuffer *local; + 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"); + local = dri2_egl_surface_alloc_local_buffer(dri2_surf, attachments[i], + attachments[i + 1]); + + if (!local) { + _eglError(EGL_BAD_ALLOC, "failed to allocate local buffer"); return NULL; } + dri2_surf->buffers[j] = *local; break; } } @@ -544,20 +652,10 @@ dri2_wl_get_buffers(__DRIdrawable * driDrawable, struct dri2_egl_surface *dri2_surf = loaderPrivate; unsigned int *attachments_with_format; __DRIbuffer *buffer; - unsigned int bpp; - - switch (dri2_surf->format) { - case WL_DRM_FORMAT_ARGB8888: - case WL_DRM_FORMAT_XRGB8888: - bpp = 32; - break; - case WL_DRM_FORMAT_RGB565: - bpp = 16; - break; - default: - /* format is not supported */ + int visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format); + + if (visual_idx == -1) return NULL; - } attachments_with_format = calloc(count, 2 * sizeof(unsigned int)); if (!attachments_with_format) { @@ -567,7 +665,7 @@ dri2_wl_get_buffers(__DRIdrawable * driDrawable, for (int i = 0; i < count; ++i) { attachments_with_format[2*i] = attachments[i]; - attachments_with_format[2*i + 1] = bpp; + attachments_with_format[2*i + 1] = dri2_wl_visuals[visual_idx].bpp; } buffer = @@ -637,51 +735,145 @@ static const struct wl_callback_listener throttle_listener = { .done = wayland_throttle_callback }; -static void -create_wl_buffer(struct dri2_egl_surface *dri2_surf) +static EGLBoolean +get_fourcc(struct dri2_egl_display *dri2_dpy, + __DRIimage *image, int *fourcc) { - struct dri2_egl_display *dri2_dpy = - dri2_egl_display(dri2_surf->base.Resource.Display); - __DRIimage *image; - int fd, stride, name; + EGLBoolean query; + int dri_format; + int visual_idx; + + query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FOURCC, + fourcc); + if (query) + return true; + + query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, + &dri_format); + if (!query) + return false; + + visual_idx = dri2_wl_visual_idx_from_dri_image_format(dri_format); + if (visual_idx == -1) + return false; + + *fourcc = dri2_wl_visuals[visual_idx].wl_drm_format; + return true; +} - if (dri2_surf->current->wl_buffer != NULL) - return; +static struct wl_buffer * +create_wl_buffer(struct dri2_egl_display *dri2_dpy, + struct dri2_egl_surface *dri2_surf, + __DRIimage *image) +{ + struct wl_buffer *ret; + EGLBoolean query; + int width, height, fourcc, num_planes; + uint64_t modifier = DRM_FORMAT_MOD_INVALID; + + query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width); + query &= dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, + &height); + query &= get_fourcc(dri2_dpy, image, &fourcc); + if (!query) + return NULL; - if (dri2_dpy->is_different_gpu) { - image = dri2_surf->current->linear_copy; - } else { - image = dri2_surf->current->dri_image; + query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NUM_PLANES, + &num_planes); + if (!query) + num_planes = 1; + + if (dri2_dpy->image->base.version >= 15) { + int mod_hi, mod_lo; + + query = dri2_dpy->image->queryImage(image, + __DRI_IMAGE_ATTRIB_MODIFIER_UPPER, + &mod_hi); + query &= dri2_dpy->image->queryImage(image, + __DRI_IMAGE_ATTRIB_MODIFIER_LOWER, + &mod_lo); + if (query) { + modifier = (uint64_t) mod_hi << 32; + modifier |= (uint64_t) (mod_lo & 0xffffffff); + } } - if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) { + + if (dri2_dpy->wl_dmabuf && modifier != DRM_FORMAT_MOD_INVALID) { + struct zwp_linux_buffer_params_v1 *params; + int i; + + /* We don't need a wrapper for wl_dmabuf objects, because we have to + * create the intermediate params object; we can set the queue on this, + * and the wl_buffer inherits it race-free. */ + params = zwp_linux_dmabuf_v1_create_params(dri2_dpy->wl_dmabuf); + if (dri2_surf) + wl_proxy_set_queue((struct wl_proxy *) params, dri2_surf->wl_queue); + + for (i = 0; i < num_planes; i++) { + __DRIimage *p_image; + int stride, offset; + int fd = -1; + + p_image = dri2_dpy->image->fromPlanar(image, i, NULL); + if (!p_image) { + assert(i == 0); + p_image = image; + } + + query = dri2_dpy->image->queryImage(p_image, + __DRI_IMAGE_ATTRIB_FD, + &fd); + query &= dri2_dpy->image->queryImage(p_image, + __DRI_IMAGE_ATTRIB_STRIDE, + &stride); + query &= dri2_dpy->image->queryImage(p_image, + __DRI_IMAGE_ATTRIB_OFFSET, + &offset); + if (image != p_image) + dri2_dpy->image->destroyImage(p_image); + + if (!query) { + if (fd >= 0) + close(fd); + zwp_linux_buffer_params_v1_destroy(params); + return NULL; + } + + zwp_linux_buffer_params_v1_add(params, fd, i, offset, stride, + modifier >> 32, modifier & 0xffffffff); + close(fd); + } + + ret = zwp_linux_buffer_params_v1_create_immed(params, width, height, + fourcc, 0); + zwp_linux_buffer_params_v1_destroy(params); + } else if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) { + struct wl_drm *wl_drm = + dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm; + int fd, stride; + + if (num_planes > 1) + return NULL; + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd); dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride); - - dri2_surf->current->wl_buffer = - wl_drm_create_prime_buffer(dri2_surf->wl_drm_wrapper, - fd, - dri2_surf->base.Width, - dri2_surf->base.Height, - dri2_surf->format, - 0, stride, - 0, 0, - 0, 0); + ret = wl_drm_create_prime_buffer(wl_drm, fd, width, height, fourcc, 0, + stride, 0, 0, 0, 0); close(fd); } else { + struct wl_drm *wl_drm = + dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm; + int name, stride; + + if (num_planes > 1) + return NULL; + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name); dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride); - - dri2_surf->current->wl_buffer = - wl_drm_create_buffer(dri2_surf->wl_drm_wrapper, - name, - dri2_surf->base.Width, - dri2_surf->base.Height, - stride, - dri2_surf->format); + ret = wl_drm_create_buffer(wl_drm, name, width, height, stride, fourcc); } - wl_buffer_add_listener(dri2_surf->current->wl_buffer, - &wl_buffer_listener, dri2_surf); + return ret; } static EGLBoolean @@ -741,7 +933,20 @@ dri2_wl_swap_buffers_with_damage(_EGLDriver *drv, dri2_surf->current = dri2_surf->back; dri2_surf->back = NULL; - create_wl_buffer(dri2_surf); + if (!dri2_surf->current->wl_buffer) { + __DRIimage *image; + + if (dri2_dpy->is_different_gpu) + image = dri2_surf->current->linear_copy; + else + image = dri2_surf->current->dri_image; + + dri2_surf->current->wl_buffer = + create_wl_buffer(dri2_dpy, dri2_surf, image); + + wl_buffer_add_listener(dri2_surf->current->wl_buffer, + &wl_buffer_listener, dri2_surf); + } wl_surface_attach(dri2_surf->wl_surface_wrapper, dri2_surf->current->wl_buffer, @@ -809,7 +1014,7 @@ dri2_wl_query_buffer_age(_EGLDriver *drv, static EGLBoolean dri2_wl_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) { - return dri2_wl_swap_buffers_with_damage (drv, disp, draw, NULL, 0); + return dri2_wl_swap_buffers_with_damage(drv, disp, draw, NULL, 0); } static struct wl_buffer * @@ -821,62 +1026,25 @@ dri2_wl_create_wayland_buffer_from_image(_EGLDriver *drv, 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; + int format, visual_idx; + /* Check the upstream display supports this buffer's 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: + visual_idx = dri2_wl_visual_idx_from_dri_image_format(format); + if (visual_idx == -1) 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); + if (!(dri2_dpy->formats & (1 << visual_idx))) + goto bad_format; - buffer = - wl_drm_create_buffer(dri2_dpy->wl_drm, - name, - width, height, - pitch, - wl_format); - } + buffer = create_wl_buffer(dri2_dpy, NULL, image); /* 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 + * because it is using wl_dmabuf/wl_drm 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 */ + * default event queue. This isn't actually racy, as the only event the + * buffer can get is a buffer release, which doesn't happen with an explicit + * attach. */ if (buffer) wl_proxy_set_queue((struct wl_proxy *) buffer, NULL); @@ -942,18 +1110,12 @@ static void drm_handle_format(void *data, struct wl_drm *drm, uint32_t format) { struct dri2_egl_display *dri2_dpy = data; + int visual_idx = dri2_wl_visual_idx_from_fourcc(format); - switch (format) { - case WL_DRM_FORMAT_ARGB8888: - dri2_dpy->formats |= HAS_ARGB8888; - break; - case WL_DRM_FORMAT_XRGB8888: - dri2_dpy->formats |= HAS_XRGB8888; - break; - case WL_DRM_FORMAT_RGB565: - dri2_dpy->formats |= HAS_RGB565; - break; - } + if (visual_idx == -1) + return; + + dri2_dpy->formats |= (1 << visual_idx); } static void @@ -979,6 +1141,41 @@ static const struct wl_drm_listener drm_listener = { .capabilities = drm_handle_capabilities }; +static void +dmabuf_ignore_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, + uint32_t format) +{ + /* formats are implicitly advertised by the 'modifier' event, so ignore */ +} + +static void +dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, + uint32_t format, uint32_t modifier_hi, + uint32_t modifier_lo) +{ + struct dri2_egl_display *dri2_dpy = data; + int visual_idx = dri2_wl_visual_idx_from_fourcc(format); + uint64_t *mod; + + if (visual_idx == -1) + return; + + if (modifier_hi == (DRM_FORMAT_MOD_INVALID >> 32) && + modifier_lo == (DRM_FORMAT_MOD_INVALID & 0xffffffff)) + return; + + dri2_dpy->formats |= (1 << visual_idx); + + mod = u_vector_add(&dri2_dpy->wl_modifiers[visual_idx]); + *mod = (uint64_t) modifier_hi << 32; + *mod |= (uint64_t) (modifier_lo & 0xffffffff); +} + +static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = { + .format = dmabuf_ignore_format, + .modifier = dmabuf_handle_modifier, +}; + static void registry_handle_global_drm(void *data, struct wl_registry *registry, uint32_t name, const char *interface, @@ -990,6 +1187,12 @@ registry_handle_global_drm(void *data, struct wl_registry *registry, dri2_dpy->wl_drm = wl_registry_bind(registry, name, &wl_drm_interface, MIN2(version, 2)); wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy); + } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3) { + dri2_dpy->wl_dmabuf = + wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, + MIN2(version, 3)); + zwp_linux_dmabuf_v1_add_listener(dri2_dpy->wl_dmabuf, &dmabuf_listener, + dri2_dpy); } } @@ -1004,58 +1207,15 @@ static const struct wl_registry_listener registry_listener_drm = { .global_remove = 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) +dri2_wl_setup_swap_interval(_EGLDisplay *disp) { - 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; - } + dri2_setup_swap_interval(disp, 1); } static const struct dri2_egl_display_vtbl dri2_wl_display_vtbl = { @@ -1065,7 +1225,6 @@ static const struct dri2_egl_display_vtbl dri2_wl_display_vtbl = { .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface, .destroy_surface = dri2_wl_destroy_surface, .create_image = dri2_create_image_khr, - .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, @@ -1097,27 +1256,18 @@ static EGLBoolean dri2_wl_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); - static const struct { - const char *format_name; - int has_format; - unsigned int rgba_masks[4]; - } visuals[] = { - { "XRGB8888", HAS_XRGB8888, { 0xff0000, 0xff00, 0x00ff, 0xff000000 } }, - { "ARGB8888", HAS_ARGB8888, { 0xff0000, 0xff00, 0x00ff, 0 } }, - { "RGB565", HAS_RGB565, { 0x00f800, 0x07e0, 0x001f, 0 } }, - }; - unsigned int format_count[ARRAY_SIZE(visuals)] = { 0 }; + unsigned int format_count[ARRAY_SIZE(dri2_wl_visuals)] = { 0 }; unsigned int count = 0; for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) { - for (unsigned j = 0; j < ARRAY_SIZE(visuals); j++) { + for (unsigned j = 0; j < ARRAY_SIZE(dri2_wl_visuals); j++) { struct dri2_egl_config *dri2_conf; - if (!(dri2_dpy->formats & visuals[j].has_format)) + if (!(dri2_dpy->formats & (1 << j))) continue; dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i], - count + 1, EGL_WINDOW_BIT, NULL, visuals[j].rgba_masks); + count + 1, EGL_WINDOW_BIT, NULL, dri2_wl_visuals[j].rgba_masks); if (dri2_conf) { if (dri2_conf->base.ConfigID == count + 1) count++; @@ -1129,7 +1279,7 @@ dri2_wl_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp) for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) { if (!format_count[i]) { _eglLog(_EGL_DEBUG, "No DRI config supports native format %s", - visuals[i].format_name); + dri2_wl_visuals[i].format_name); } } @@ -1158,6 +1308,15 @@ dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp) dri2_dpy->wl_dpy = disp->PlatformDisplay; } + dri2_dpy->wl_modifiers = + calloc(ARRAY_SIZE(dri2_wl_visuals), sizeof(*dri2_dpy->wl_modifiers)); + if (!dri2_dpy->wl_modifiers) + goto cleanup; + for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) { + if (!u_vector_init(&dri2_dpy->wl_modifiers[i], sizeof(uint64_t), 32)) + goto cleanup; + } + dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy); dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy); @@ -1230,7 +1389,7 @@ dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp) dri2_setup_screen(disp); - dri2_wl_setup_swap_interval(dri2_dpy); + dri2_wl_setup_swap_interval(disp); /* To use Prime, we must have _DRI_IMAGE v7 at least. * createImageFromFds support indicates that Prime export/import @@ -1291,10 +1450,9 @@ dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp) 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; + int visual_idx = dri2_wl_visual_idx_from_shm_format(format); + + return w * (dri2_wl_visuals[visual_idx].bpp / 8); } /* @@ -1377,7 +1535,7 @@ create_tmpfile_cloexec(char *tmpname) static int os_create_anonymous_file(off_t size) { - static const char template[] = "/mesa-shared-XXXXXX"; + static const char templ[] = "/mesa-shared-XXXXXX"; const char *path; char *name; int fd; @@ -1389,12 +1547,12 @@ os_create_anonymous_file(off_t size) return -1; } - name = malloc(strlen(path) + sizeof(template)); + name = malloc(strlen(path) + sizeof(templ)); if (!name) return -1; strcpy(name, path); - strcat(name, template); + strcat(name, templ); fd = create_tmpfile_cloexec(name); @@ -1716,18 +1874,12 @@ static void shm_handle_format(void *data, struct wl_shm *shm, uint32_t format) { struct dri2_egl_display *dri2_dpy = data; + int visual_idx = dri2_wl_visual_idx_from_shm_format(format); - 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; - } + if (visual_idx == -1) + return; + + dri2_dpy->formats |= (1 << visual_idx); } static const struct wl_shm_listener shm_listener = { @@ -1759,8 +1911,7 @@ static const struct dri2_egl_display_vtbl dri2_wl_swrast_display_vtbl = { .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, + .create_image = dri2_create_image_khr, .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, @@ -1783,6 +1934,7 @@ static const __DRIswrastLoaderExtension swrast_loader_extension = { static const __DRIextension *swrast_loader_extensions[] = { &swrast_loader_extension.base, + &image_lookup_extension.base, NULL, }; @@ -1844,7 +1996,7 @@ dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp) dri2_setup_screen(disp); - dri2_wl_setup_swap_interval(dri2_dpy); + dri2_wl_setup_swap_interval(disp); if (!dri2_wl_add_configs_for_visuals(drv, disp)) { _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs"); @@ -1866,18 +2018,38 @@ dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp) EGLBoolean dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) { - EGLBoolean initialized = EGL_TRUE; + EGLBoolean initialized = EGL_FALSE; - int hw_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL); + if (!disp->Options.ForceSoftware) + initialized = dri2_initialize_wayland_drm(drv, disp); - if (hw_accel) { - if (!dri2_initialize_wayland_drm(drv, disp)) { - initialized = dri2_initialize_wayland_swrast(drv, disp); - } - } else { + if (!initialized) initialized = dri2_initialize_wayland_swrast(drv, disp); - } return initialized; } + +void +dri2_teardown_wayland(struct dri2_egl_display *dri2_dpy) +{ + if (dri2_dpy->wl_drm) + wl_drm_destroy(dri2_dpy->wl_drm); + if (dri2_dpy->wl_dmabuf) + zwp_linux_dmabuf_v1_destroy(dri2_dpy->wl_dmabuf); + if (dri2_dpy->wl_shm) + wl_shm_destroy(dri2_dpy->wl_shm); + if (dri2_dpy->wl_registry) + wl_registry_destroy(dri2_dpy->wl_registry); + if (dri2_dpy->wl_queue) + wl_event_queue_destroy(dri2_dpy->wl_queue); + if (dri2_dpy->wl_dpy_wrapper) + wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper); + + for (int i = 0; dri2_dpy->wl_modifiers && i < ARRAY_SIZE(dri2_wl_visuals); i++) + u_vector_finish(&dri2_dpy->wl_modifiers[i]); + free(dri2_dpy->wl_modifiers); + + if (dri2_dpy->own_device) + wl_display_disconnect(dri2_dpy->wl_dpy); +}