X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fegl%2Fdrivers%2Fdri2%2Fplatform_wayland.c;h=d7e7eaa2c95d3c4ac2120bfbd5bc2fbba2feaf53;hb=a7ecf78b900c28aafdc1cd1e1a4117feb30a66c9;hp=83df0a8776b1d830bd39ee88774e8c99bcdac12b;hpb=a9fb331ea7d1a78936ea8d8385e44cfd66f835c1;p=mesa.git diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index 83df0a8776b..d7e7eaa2c95 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include "drm-uapi/drm_fourcc.h" #include #include "egl_dri2.h" @@ -59,49 +59,57 @@ static const struct dri2_wl_visual { uint32_t wl_drm_format; uint32_t wl_shm_format; int dri_image_format; + /* alt_dri_image_format is a substitute wl_buffer format to use for a + * wl-server unsupported dri_image_format, ie. some other dri_image_format in + * the table, of the same precision but with different channel ordering, or + * __DRI_IMAGE_FORMAT_NONE if an alternate format is not needed or supported. + * The code checks if alt_dri_image_format can be used as a fallback for a + * dri_image_format for a given wl-server implementation. + */ + int alt_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, + __DRI_IMAGE_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XBGR2101010, 32, { 0x3ff00000, 0x000ffc00, 0x000003ff, 0x00000000 } }, { "ARGB2101010", WL_DRM_FORMAT_ARGB2101010, WL_SHM_FORMAT_ARGB2101010, - __DRI_IMAGE_FORMAT_ARGB2101010, 32, + __DRI_IMAGE_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ABGR2101010, 32, { 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 } }, { "XBGR2101010", WL_DRM_FORMAT_XBGR2101010, WL_SHM_FORMAT_XBGR2101010, - __DRI_IMAGE_FORMAT_XBGR2101010, 32, + __DRI_IMAGE_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XRGB2101010, 32, { 0x000003ff, 0x000ffc00, 0x3ff00000, 0x00000000 } }, { "ABGR2101010", WL_DRM_FORMAT_ABGR2101010, WL_SHM_FORMAT_ABGR2101010, - __DRI_IMAGE_FORMAT_ABGR2101010, 32, + __DRI_IMAGE_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ARGB2101010, 32, { 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 } }, { "XRGB8888", WL_DRM_FORMAT_XRGB8888, WL_SHM_FORMAT_XRGB8888, - __DRI_IMAGE_FORMAT_XRGB8888, 32, + __DRI_IMAGE_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_NONE, 32, { 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 } }, { "ARGB8888", WL_DRM_FORMAT_ARGB8888, WL_SHM_FORMAT_ARGB8888, - __DRI_IMAGE_FORMAT_ARGB8888, 32, + __DRI_IMAGE_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_NONE, 32, { 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 } }, { "RGB565", WL_DRM_FORMAT_RGB565, WL_SHM_FORMAT_RGB565, - __DRI_IMAGE_FORMAT_RGB565, 16, + __DRI_IMAGE_FORMAT_RGB565, __DRI_IMAGE_FORMAT_NONE, 16, { 0xf800, 0x07e0, 0x001f, 0x0000 } }, }; @@ -166,6 +174,24 @@ dri2_wl_visual_idx_from_shm_format(uint32_t shm_format) return -1; } +bool +dri2_wl_is_format_supported(void* user_data, uint32_t format) +{ + _EGLDisplay *disp = (_EGLDisplay *) user_data; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + int j = dri2_wl_visual_idx_from_fourcc(format); + + if (j == -1) + return false; + + for (int i = 0; dri2_dpy->driver_configs[i]; i++) + if (j == dri2_wl_visual_idx_from_config(dri2_dpy, + dri2_dpy->driver_configs[i])) + return true; + + return false; +} + static int roundtrip(struct dri2_egl_display *dri2_dpy) { @@ -182,9 +208,12 @@ wl_buffer_release(void *data, struct wl_buffer *buffer) if (dri2_surf->color_buffers[i].wl_buffer == buffer) break; - if (i == ARRAY_SIZE(dri2_surf->color_buffers)) { + assert (i < ARRAY_SIZE(dri2_surf->color_buffers)); + + if (dri2_surf->color_buffers[i].wl_release) { wl_buffer_destroy(buffer); - return; + dri2_surf->color_buffers[i].wl_release = false; + dri2_surf->color_buffers[i].wl_buffer = NULL; } dri2_surf->color_buffers[i].locked = false; @@ -202,7 +231,7 @@ resize_callback(struct wl_egl_window *wl_win, void *data) dri2_egl_display(dri2_surf->base.Resource.Display); /* Update the surface size as soon as native window is resized; from user - * pov, this makes the effect that resize is done inmediately after native + * pov, this makes the effect that resize is done immediately after native * window resize, without requiring to wait until the first draw. * * A more detailed and lengthy explanation can be found at @@ -227,7 +256,7 @@ 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 + * window->version is dereferenceable, 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)); @@ -243,7 +272,6 @@ dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, void *native_window, const EGLint *attrib_list) { - __DRIcreateNewDrawableFunc createNewDrawable; 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; @@ -258,7 +286,7 @@ dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, } if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, - attrib_list, false)) + attrib_list, false, native_window)) goto cleanup_surf; config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT, @@ -320,19 +348,8 @@ dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, if (dri2_dpy->flush) dri2_surf->wl_win->resize_callback = resize_callback; - if (dri2_dpy->image_driver) - createNewDrawable = dri2_dpy->image_driver->createNewDrawable; - else if (dri2_dpy->dri2) - createNewDrawable = dri2_dpy->dri2->createNewDrawable; - else - createNewDrawable = dri2_dpy->swrast->createNewDrawable; - - dri2_surf->dri_drawable = (*createNewDrawable)(dri2_dpy->dri_screen, config, - dri2_surf); - if (dri2_surf->dri_drawable == NULL) { - _eglError(EGL_BAD_ALLOC, "createNewDrawable"); + if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf)) goto cleanup_surf_wrapper; - } dri2_surf->base.SwapInterval = dri2_dpy->default_swap_interval; @@ -425,9 +442,14 @@ dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf) dri2_egl_display(dri2_surf->base.Resource.Display); for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { - 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].wl_buffer) { + if (dri2_surf->color_buffers[i].locked) { + dri2_surf->color_buffers[i].wl_release = true; + } else { + wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); + dri2_surf->color_buffers[i].wl_buffer = NULL; + } + } if (dri2_surf->color_buffers[i].dri_image) dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); if (dri2_surf->color_buffers[i].linear_copy) @@ -436,11 +458,9 @@ dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf) 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 = false; } if (dri2_dpy->dri2) @@ -455,21 +475,35 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) int use_flags; int visual_idx; unsigned int dri_image_format; + unsigned int linear_dri_image_format; uint64_t *modifiers; int num_modifiers; 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; + linear_dri_image_format = dri_image_format; modifiers = u_vector_tail(&dri2_dpy->wl_modifiers[visual_idx]); num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers[visual_idx]); + /* Substitute dri image format if server does not support original format */ + if (!(dri2_dpy->formats & (1 << visual_idx))) + linear_dri_image_format = dri2_wl_visuals[visual_idx].alt_dri_image_format; + + /* These asserts hold, as long as dri2_wl_visuals[] is self-consistent and + * the PRIME substitution logic in dri2_wl_add_configs_for_visuals() is free + * of bugs. + */ + assert(linear_dri_image_format != __DRI_IMAGE_FORMAT_NONE); + assert(dri2_dpy->formats & + (1 << dri2_wl_visual_idx_from_dri_image_format(linear_dri_image_format))); + /* 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); while (dri2_surf->back == NULL) { for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { - /* Get an unlocked buffer, preferrably one with a dri_buffer + /* Get an unlocked buffer, preferably one with a dri_buffer * already allocated. */ if (dri2_surf->color_buffers[i].locked) continue; @@ -510,7 +544,7 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) dri2_dpy->image->createImageWithModifiers(dri2_dpy->dri_screen, dri2_surf->base.Width, dri2_surf->base.Height, - dri_image_format, + linear_dri_image_format, &linear_mod, 1, NULL); @@ -519,7 +553,7 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) dri2_dpy->image->createImage(dri2_dpy->dri_screen, dri2_surf->base.Width, dri2_surf->base.Height, - dri_image_format, + linear_dri_image_format, use_flags | __DRI_IMAGE_USE_LINEAR, NULL); @@ -591,10 +625,8 @@ update_buffers(struct dri2_egl_surface *dri2_surf) struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); - if (dri2_surf->base.Width != dri2_surf->wl_win->attached_width || - dri2_surf->base.Height != dri2_surf->wl_win->attached_height) { - - dri2_wl_release_buffers(dri2_surf); + if (dri2_surf->base.Width != dri2_surf->wl_win->width || + dri2_surf->base.Height != dri2_surf->wl_win->height) { dri2_surf->base.Width = dri2_surf->wl_win->width; dri2_surf->base.Height = dri2_surf->wl_win->height; @@ -602,6 +634,11 @@ update_buffers(struct dri2_egl_surface *dri2_surf) dri2_surf->dy = dri2_surf->wl_win->dy; } + if (dri2_surf->base.Width != dri2_surf->wl_win->attached_width || + dri2_surf->base.Height != dri2_surf->wl_win->attached_height) { + dri2_wl_release_buffers(dri2_surf); + } + if (get_back_bo(dri2_surf) < 0) { _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer"); return -1; @@ -626,6 +663,15 @@ update_buffers(struct dri2_egl_surface *dri2_surf) return 0; } +static int +update_buffers_if_needed(struct dri2_egl_surface *dri2_surf) +{ + if (dri2_surf->back != NULL) + return 0; + + return update_buffers(dri2_surf); +} + static __DRIbuffer * dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable, int *width, int *height, @@ -818,8 +864,7 @@ create_wl_buffer(struct dri2_egl_display *dri2_dpy, __DRI_IMAGE_ATTRIB_MODIFIER_LOWER, &mod_lo); if (query) { - modifier = (uint64_t) mod_hi << 32; - modifier |= (uint64_t) (mod_lo & 0xffffffff); + modifier = combine_u32_into_u64(mod_hi, mod_lo); } } @@ -944,7 +989,7 @@ dri2_wl_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) < 0) + if (update_buffers_if_needed(dri2_surf) < 0) return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers"); if (draw->SwapInterval > 0) { @@ -969,6 +1014,8 @@ dri2_wl_swap_buffers_with_damage(_EGLDriver *drv, dri2_surf->current->wl_buffer = create_wl_buffer(dri2_dpy, dri2_surf, image); + dri2_surf->current->wl_release = false; + wl_buffer_add_listener(dri2_surf->current->wl_buffer, &wl_buffer_listener, dri2_surf); } @@ -1028,7 +1075,7 @@ dri2_wl_query_buffer_age(_EGLDriver *drv, { struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface); - if (get_back_bo(dri2_surf) < 0) { + if (update_buffers_if_needed(dri2_surf) < 0) { _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age"); return -1; } @@ -1059,7 +1106,7 @@ dri2_wl_create_wayland_buffer_from_image(_EGLDriver *drv, if (visual_idx == -1) goto bad_format; - if (!(dri2_dpy->formats & (1 << visual_idx))) + if (!(dri2_dpy->formats & (1u << visual_idx))) goto bad_format; buffer = create_wl_buffer(dri2_dpy, NULL, image); @@ -1120,13 +1167,22 @@ drm_handle_device(void *data, struct wl_drm *drm, const char *device) if (dri2_dpy->fd == -1) { _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)", dri2_dpy->device_name, strerror(errno)); + free(dri2_dpy->device_name); + dri2_dpy->device_name = NULL; return; } if (drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER) { dri2_dpy->authenticated = true; } else { - drmGetMagic(dri2_dpy->fd, &magic); + if (drmGetMagic(dri2_dpy->fd, &magic)) { + close(dri2_dpy->fd); + dri2_dpy->fd = -1; + free(dri2_dpy->device_name); + dri2_dpy->device_name = NULL; + _eglLog(_EGL_WARNING, "wayland-egl: drmGetMagic failed"); + return; + } wl_drm_authenticate(dri2_dpy->wl_drm, magic); } } @@ -1140,7 +1196,7 @@ drm_handle_format(void *data, struct wl_drm *drm, uint32_t format) if (visual_idx == -1) return; - dri2_dpy->formats |= (1 << visual_idx); + dri2_dpy->formats |= (1u << visual_idx); } static void @@ -1189,11 +1245,10 @@ dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, modifier_lo == (DRM_FORMAT_MOD_INVALID & 0xffffffff)) return; - dri2_dpy->formats |= (1 << visual_idx); + dri2_dpy->formats |= (1u << visual_idx); mod = u_vector_add(&dri2_dpy->wl_modifiers[visual_idx]); - *mod = (uint64_t) modifier_hi << 32; - *mod |= (uint64_t) (modifier_lo & 0xffffffff); + *mod = combine_u32_into_u64(modifier_hi, modifier_lo); } static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = { @@ -1283,12 +1338,15 @@ dri2_wl_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp) struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); unsigned int format_count[ARRAY_SIZE(dri2_wl_visuals)] = { 0 }; unsigned int count = 0; + bool assigned; for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) { + assigned = false; + for (unsigned j = 0; j < ARRAY_SIZE(dri2_wl_visuals); j++) { struct dri2_egl_config *dri2_conf; - if (!(dri2_dpy->formats & (1 << j))) + if (!(dri2_dpy->formats & (1u << j))) continue; dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i], @@ -1297,6 +1355,43 @@ dri2_wl_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp) if (dri2_conf->base.ConfigID == count + 1) count++; format_count[j]++; + assigned = true; + } + } + + if (!assigned && dri2_dpy->is_different_gpu) { + struct dri2_egl_config *dri2_conf; + int alt_dri_image_format, c, s; + + /* No match for config. Try if we can blitImage convert to a visual */ + c = dri2_wl_visual_idx_from_config(dri2_dpy, + dri2_dpy->driver_configs[i]); + + if (c == -1) + continue; + + /* Find optimal target visual for blitImage conversion, if any. */ + alt_dri_image_format = dri2_wl_visuals[c].alt_dri_image_format; + s = dri2_wl_visual_idx_from_dri_image_format(alt_dri_image_format); + + if (s == -1 || !(dri2_dpy->formats & (1 << s))) + continue; + + /* Visual s works for the Wayland server, and c can be converted into s + * by our client gpu during PRIME blitImage conversion to a linear + * wl_buffer, so add visual c as supported by the client renderer. + */ + dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i], + count + 1, EGL_WINDOW_BIT, NULL, + dri2_wl_visuals[c].rgba_masks); + if (dri2_conf) { + if (dri2_conf->base.ConfigID == count + 1) + count++; + format_count[c]++; + if (format_count[c] == 1) + _eglLog(_EGL_DEBUG, "Client format %s to server format %s via " + "PRIME blitImage.", dri2_wl_visuals[c].format_name, + dri2_wl_visuals[s].format_name); } } } @@ -1314,10 +1409,9 @@ dri2_wl_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp) static EGLBoolean dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp) { + _EGLDevice *dev; struct dri2_egl_display *dri2_dpy; - loader_set_logger(_eglLog); - dri2_dpy = calloc(1, sizeof *dri2_dpy); if (!dri2_dpy) return _eglError(EGL_BAD_ALLOC, "eglInitialize"); @@ -1368,6 +1462,14 @@ dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp) dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu); + dev = _eglAddDevice(dri2_dpy->fd, false); + if (!dev) { + _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice"); + goto cleanup; + } + + disp->Device = dev; + if (dri2_dpy->is_different_gpu) { free(dri2_dpy->device_name); dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd); @@ -1555,7 +1657,7 @@ create_tmpfile_cloexec(char *tmpname) * * 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. + * given size. If disk space is insufficient, errno is set to ENOSPC. * If posix_fallocate() is not supported, program may receive * SIGBUS on accessing mmap()'ed file contents instead. */ @@ -1613,7 +1715,7 @@ dri2_wl_swrast_allocate_buffer(struct dri2_egl_surface *dri2_surf, stride = dri2_wl_swrast_get_stride_for_format(format, w); size_map = h * stride; - /* Create a sharable buffer */ + /* Create a shareable buffer */ fd = os_create_anonymous_file(size_map); if (fd < 0) return EGL_FALSE; @@ -1646,8 +1748,8 @@ swrast_update_buffers(struct dri2_egl_surface *dri2_surf) if (dri2_surf->back) return 0; - if (dri2_surf->base.Width != dri2_surf->wl_win->attached_width || - dri2_surf->base.Height != dri2_surf->wl_win->attached_height) { + 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); @@ -1906,7 +2008,7 @@ shm_handle_format(void *data, struct wl_shm *shm, uint32_t format) if (visual_idx == -1) return; - dri2_dpy->formats |= (1 << visual_idx); + dri2_dpy->formats |= (1u << visual_idx); } static const struct wl_shm_listener shm_listener = { @@ -1968,10 +2070,9 @@ static const __DRIextension *swrast_loader_extensions[] = { static EGLBoolean dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp) { + _EGLDevice *dev; struct dri2_egl_display *dri2_dpy; - loader_set_logger(_eglLog); - dri2_dpy = calloc(1, sizeof *dri2_dpy); if (!dri2_dpy) return _eglError(EGL_BAD_ALLOC, "eglInitialize"); @@ -1987,6 +2088,14 @@ dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp) dri2_dpy->wl_dpy = disp->PlatformDisplay; } + dev = _eglAddDevice(dri2_dpy->fd, true); + if (!dev) { + _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice"); + goto cleanup; + } + + disp->Device = dev; + 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);