diff --git a/.pick_status.json b/.pick_status.json index d44cf08908c..2f46ac166e0 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -194,7 +194,7 @@ "description": "Revert \"egl/wayland: Remove EGL_WL_create_wayland_buffer_from_image\"", "nominated": true, "nomination_type": 2, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": "a3418105b9169b8f72745c9901db37cd545ac583", "notes": null diff --git a/docs/_static/specs/OLD/WL_create_wayland_buffer_from_image.spec b/docs/_static/specs/WL_create_wayland_buffer_from_image.spec similarity index 100% rename from docs/_static/specs/OLD/WL_create_wayland_buffer_from_image.spec rename to docs/_static/specs/WL_create_wayland_buffer_from_image.spec diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index 41c9da46a40..dd345924b1b 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -2402,6 +2402,20 @@ dri2_query_surface(_EGLDisplay *disp, _EGLSurface *surf, EGLint attribute, return ret; } +static struct wl_buffer * +dri2_create_wayland_buffer_from_image(_EGLDisplay *disp, _EGLImage *img) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display_lock(disp); + struct wl_buffer *ret = NULL; + + if (dri2_dpy->vtbl->create_wayland_buffer_from_image) + ret = dri2_dpy->vtbl->create_wayland_buffer_from_image(disp, img); + + mtx_unlock(&dri2_dpy->lock); + + return ret; +} + #ifdef HAVE_LIBDRM static _EGLImage * dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx, @@ -3654,6 +3668,7 @@ const _EGLDriver _eglDriver = { .QueryBufferAge = dri2_query_buffer_age, .CreateImageKHR = dri2_create_image, .DestroyImageKHR = dri2_destroy_image_khr, + .CreateWaylandBufferFromImageWL = dri2_create_wayland_buffer_from_image, .QuerySurface = dri2_query_surface, .QueryDriverName = dri2_query_driver_name, .QueryDriverConfig = dri2_query_driver_config, diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index d7d87c2047e..8f57720e2db 100644 --- a/src/egl/drivers/dri2/egl_dri2.h +++ b/src/egl/drivers/dri2/egl_dri2.h @@ -157,6 +157,10 @@ struct dri2_egl_display_vtbl { EGLBoolean (*query_surface)(_EGLDisplay *disp, _EGLSurface *surf, EGLint attribute, EGLint *value); + /* optional */ + struct wl_buffer *(*create_wayland_buffer_from_image)(_EGLDisplay *disp, + _EGLImage *img); + /* optional */ EGLBoolean (*get_sync_values)(_EGLDisplay *display, _EGLSurface *surface, EGLuint64KHR *ust, EGLuint64KHR *msc, diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index c940f0a6f08..08da1ca52bd 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -261,6 +261,12 @@ server_supports_pipe_format(struct dri2_wl_formats *formats, dri2_wl_visual_idx_from_pipe_format(format)); } +static bool +server_supports_fourcc(struct dri2_wl_formats *formats, uint32_t fourcc) +{ + return server_supports_format(formats, dri2_wl_visual_idx_from_fourcc(fourcc)); +} + static int roundtrip(struct dri2_egl_display *dri2_dpy) { @@ -1604,6 +1610,38 @@ dri2_wl_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw) return dri2_wl_swap_buffers_with_damage(disp, draw, NULL, 0); } +static struct wl_buffer * +dri2_wl_create_wayland_buffer_from_image(_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 fourcc; + + /* Check the upstream display supports this buffer's format. */ + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FOURCC, &fourcc); + if (!server_supports_fourcc(&dri2_dpy->formats, fourcc)) + goto bad_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 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. 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); + + return buffer; + +bad_format: + _eglError(EGL_BAD_MATCH, "unsupported image format"); + return NULL; +} + static int dri2_wl_authenticate(_EGLDisplay *disp, uint32_t id) { @@ -1920,6 +1958,7 @@ static const struct dri2_egl_display_vtbl dri2_wl_display_vtbl = { .swap_buffers = dri2_wl_swap_buffers, .swap_buffers_with_damage = dri2_wl_swap_buffers_with_damage, .query_buffer_age = dri2_wl_query_buffer_age, + .create_wayland_buffer_from_image = dri2_wl_create_wayland_buffer_from_image, .get_dri_drawable = dri2_surface_get_dri_drawable, }; @@ -2139,6 +2178,12 @@ dri2_initialize_wayland_drm(_EGLDisplay *disp) dri2_wl_add_configs_for_visuals(disp); dri2_set_WL_bind_wayland_display(disp); + /* When cannot convert EGLImage to wl_buffer when on a different gpu, + * because the buffer of the EGLImage has likely a tiling mode the server + * gpu won't support. These is no way to check for now. Thus do not support + * the extension */ + if (dri2_dpy->fd_render_gpu == dri2_dpy->fd_display_gpu) + disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE; disp->Extensions.EXT_buffer_age = EGL_TRUE; diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index 24c59912b49..f9486deff92 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -602,6 +602,7 @@ _eglCreateExtensionsString(_EGLDisplay *disp) _EGL_CHECK_EXTENSION(NV_post_sub_buffer); _EGL_CHECK_EXTENSION(WL_bind_wayland_display); + _EGL_CHECK_EXTENSION(WL_create_wayland_buffer_from_image); #undef _EGL_CHECK_EXTENSION } @@ -2377,11 +2378,23 @@ static struct wl_buffer *EGLAPIENTRY eglCreateWaylandBufferFromImageWL(EGLDisplay dpy, EGLImage image) { _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLImage *img; + struct wl_buffer *ret; _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL); _EGL_CHECK_DISPLAY(disp, NULL); - RETURN_EGL_EVAL(disp, NULL); + if (!disp->Extensions.WL_create_wayland_buffer_from_image) + RETURN_EGL_EVAL(disp, NULL); + + img = _eglLookupImage(image, disp); + + if (!img) + RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, NULL); + + ret = disp->Driver->CreateWaylandBufferFromImageWL(disp, img); + + RETURN_EGL_EVAL(disp, ret); } static EGLBoolean EGLAPIENTRY diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h index 0aec7021f88..477a24de9b6 100644 --- a/src/egl/main/egldisplay.h +++ b/src/egl/main/egldisplay.h @@ -154,6 +154,7 @@ struct _egl_extensions { EGLBoolean NV_post_sub_buffer; EGLBoolean WL_bind_wayland_display; + EGLBoolean WL_create_wayland_buffer_from_image; }; struct _egl_display { diff --git a/src/egl/main/egldriver.h b/src/egl/main/egldriver.h index 1c931206275..89ac2473527 100644 --- a/src/egl/main/egldriver.h +++ b/src/egl/main/egldriver.h @@ -163,6 +163,10 @@ struct _egl_driver { struct wl_resource *buffer, EGLint attribute, EGLint *value); + /* for EGL_WL_create_wayland_buffer_from_image */ + struct wl_buffer *(*CreateWaylandBufferFromImageWL)(_EGLDisplay *disp, + _EGLImage *img); + /* for EGL_EXT_swap_buffers_with_damage */ EGLBoolean (*SwapBuffersWithDamageEXT)(_EGLDisplay *disp, _EGLSurface *surface,