From de315f76a266ce51ca0638b9ea2ec3ccfd31f03b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Kristian=20H=C3=B8gsberg?= Date: Sat, 2 Feb 2013 12:26:12 -0500 Subject: [PATCH] wayland: Add prime fd passing as a buffer sharing mechanism Reviewed-by: Ander Conselvan de Oliveira --- src/egl/drivers/dri2/egl_dri2.c | 37 ++++++++--- src/egl/drivers/dri2/egl_dri2.h | 1 + src/egl/drivers/dri2/platform_wayland.c | 69 ++++++++++++++++----- src/egl/wayland/wayland-drm/wayland-drm.c | 40 ++++++++++-- src/egl/wayland/wayland-drm/wayland-drm.h | 7 ++- src/egl/wayland/wayland-drm/wayland-drm.xml | 29 ++++++++- 6 files changed, 149 insertions(+), 34 deletions(-) diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index b7749196c5d..a3aabf5ab51 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -320,7 +320,7 @@ static struct dri2_extension_match dri2_driver_extensions[] = { static struct dri2_extension_match dri2_core_extensions[] = { { __DRI2_FLUSH, 1, offsetof(struct dri2_egl_display, flush) }, { __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) }, - { __DRI_IMAGE, 1, offsetof(struct dri2_egl_display, image) }, + { __DRI_IMAGE, 7, offsetof(struct dri2_egl_display, image) }, { NULL, 0, 0 } }; @@ -1498,7 +1498,7 @@ dri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, #ifdef HAVE_WAYLAND_PLATFORM static void -dri2_wl_reference_buffer(void *user_data, uint32_t name, +dri2_wl_reference_buffer(void *user_data, uint32_t name, int fd, struct wl_drm_buffer *buffer) { _EGLDisplay *disp = user_data; @@ -1506,13 +1506,24 @@ dri2_wl_reference_buffer(void *user_data, uint32_t name, __DRIimage *img; int i, dri_components = 0; - img = dri2_dpy->image->createImageFromNames(dri2_dpy->dri_screen, - buffer->buffer.width, - buffer->buffer.height, - buffer->format, (int*)&name, 1, - buffer->stride, - buffer->offset, - NULL); + if (fd == -1) + img = dri2_dpy->image->createImageFromNames(dri2_dpy->dri_screen, + buffer->buffer.width, + buffer->buffer.height, + buffer->format, + (int*)&name, 1, + buffer->stride, + buffer->offset, + NULL); + else + img = dri2_dpy->image->createImageFromFds(dri2_dpy->dri_screen, + buffer->buffer.width, + buffer->buffer.height, + buffer->format, + &fd, 1, + buffer->stride, + buffer->offset, + NULL); if (img == NULL) return; @@ -1550,6 +1561,8 @@ dri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp, struct wl_display *wl_dpy) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + int ret, flags = 0; + uint64_t cap; (void) drv; @@ -1559,9 +1572,13 @@ dri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp, wl_drm_callbacks.authenticate = (int(*)(void *, uint32_t)) dri2_dpy->authenticate; + ret = drmGetCap(dri2_dpy->fd, DRM_CAP_PRIME, &cap); + if (ret == 0 && cap == (DRM_PRIME_CAP_IMPORT | DRM_PRIME_CAP_EXPORT)) + flags |= WAYLAND_DRM_PRIME; + dri2_dpy->wl_server_drm = wayland_drm_init(wl_dpy, dri2_dpy->device_name, - &wl_drm_callbacks, disp); + &wl_drm_callbacks, disp, flags); if (!dri2_dpy->wl_server_drm) return EGL_FALSE; diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index 7f3ed4e3745..6dfdf946fc8 100644 --- a/src/egl/drivers/dri2/egl_dri2.h +++ b/src/egl/drivers/dri2/egl_dri2.h @@ -132,6 +132,7 @@ struct dri2_egl_display struct wl_event_queue *wl_queue; int authenticated; int formats; + uint32_t capabilities; #endif int (*authenticate) (_EGLDisplay *disp, uint32_t id); diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index b5cd04a5ec3..740fc7d4e0f 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -451,6 +451,46 @@ static const struct wl_callback_listener frame_listener = { wayland_frame_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; + + 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_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, dri2_surf->current->pitch, + 0, 0, + 0, 0); + close(fd); + } else { + dri2_surf->current->wl_buffer = + wl_drm_create_buffer(dri2_dpy->wl_drm, + dri2_surf->current->name, + dri2_surf->base.Width, + dri2_surf->base.Height, + dri2_surf->current->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); +} + /** * Called via eglSwapBuffers(), drv->API.SwapBuffers(). */ @@ -488,19 +528,7 @@ dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) 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->name, - dri2_surf->base.Width, - dri2_surf->base.Height, - dri2_surf->current->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, @@ -629,6 +657,14 @@ drm_handle_format(void *data, struct wl_drm *drm, uint32_t format) } } +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) { @@ -640,7 +676,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 @@ -649,9 +686,11 @@ 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); } } diff --git a/src/egl/wayland/wayland-drm/wayland-drm.c b/src/egl/wayland/wayland-drm/wayland-drm.c index d02aab66324..7e2073a73f3 100644 --- a/src/egl/wayland/wayland-drm/wayland-drm.c +++ b/src/egl/wayland/wayland-drm/wayland-drm.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "wayland-drm.h" @@ -41,6 +42,7 @@ struct wl_drm { void *user_data; char *device_name; + uint32_t flags; struct wayland_drm_callbacks *callbacks; }; @@ -67,7 +69,8 @@ const static struct wl_buffer_interface drm_buffer_interface = { static void create_buffer(struct wl_client *client, struct wl_resource *resource, - uint32_t id, uint32_t name, int32_t width, int32_t height, + uint32_t id, uint32_t name, int fd, + int32_t width, int32_t height, uint32_t format, int32_t offset0, int32_t stride0, int32_t offset1, int32_t stride1, @@ -93,7 +96,7 @@ create_buffer(struct wl_client *client, struct wl_resource *resource, buffer->offset[2] = offset2; buffer->stride[2] = stride2; - drm->callbacks->reference_buffer(drm->user_data, name, buffer); + drm->callbacks->reference_buffer(drm->user_data, name, fd, buffer); if (buffer->driver_buffer == NULL) { wl_resource_post_error(resource, WL_DRM_ERROR_INVALID_NAME, @@ -131,7 +134,7 @@ drm_create_buffer(struct wl_client *client, struct wl_resource *resource, } create_buffer(client, resource, id, - name, width, height, format, 0, stride, 0, 0, 0, 0); + name, -1, width, height, format, 0, stride, 0, 0, 0, 0); } static void @@ -159,10 +162,24 @@ drm_create_planar_buffer(struct wl_client *client, return; } - create_buffer(client, resource, id, name, width, height, format, + create_buffer(client, resource, id, name, -1, width, height, format, offset0, stride0, offset1, stride1, offset2, stride2); } +static void +drm_create_prime_buffer(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, int fd, + int32_t width, int32_t height, uint32_t format, + int32_t offset0, int32_t stride0, + int32_t offset1, int32_t stride1, + int32_t offset2, int32_t stride2) +{ + create_buffer(client, resource, id, 0, fd, width, height, format, + offset0, stride0, offset1, stride1, offset2, stride2); + close(fd); +} + static void drm_authenticate(struct wl_client *client, struct wl_resource *resource, uint32_t id) @@ -180,7 +197,8 @@ drm_authenticate(struct wl_client *client, const static struct wl_drm_interface drm_interface = { drm_authenticate, drm_create_buffer, - drm_create_planar_buffer + drm_create_planar_buffer, + drm_create_prime_buffer }; static void @@ -188,6 +206,7 @@ bind_drm(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct wl_drm *drm = data; struct wl_resource *resource; + uint32_t capabilities; resource = wl_client_add_object(client, &wl_drm_interface, &drm_interface, id, data); @@ -204,11 +223,19 @@ bind_drm(struct wl_client *client, void *data, uint32_t version, uint32_t id) wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV12); wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV16); wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUYV); + + capabilities = 0; + if (drm->flags & WAYLAND_DRM_PRIME) + capabilities |= WL_DRM_CAPABILITY_PRIME; + + if (version >= 2) + wl_resource_post_event(resource, WL_DRM_CAPABILITIES, capabilities); } struct wl_drm * wayland_drm_init(struct wl_display *display, char *device_name, - struct wayland_drm_callbacks *callbacks, void *user_data) + struct wayland_drm_callbacks *callbacks, void *user_data, + uint32_t flags) { struct wl_drm *drm; @@ -218,6 +245,7 @@ wayland_drm_init(struct wl_display *display, char *device_name, drm->device_name = strdup(device_name); drm->callbacks = callbacks; drm->user_data = user_data; + drm->flags = flags; wl_display_add_global(display, &wl_drm_interface, drm, bind_drm); diff --git a/src/egl/wayland/wayland-drm/wayland-drm.h b/src/egl/wayland/wayland-drm/wayland-drm.h index 3e8f95173ac..335073a879c 100644 --- a/src/egl/wayland/wayland-drm/wayland-drm.h +++ b/src/egl/wayland/wayland-drm/wayland-drm.h @@ -82,15 +82,18 @@ struct wl_drm_buffer { struct wayland_drm_callbacks { int (*authenticate)(void *user_data, uint32_t id); - void (*reference_buffer)(void *user_data, uint32_t name, + void (*reference_buffer)(void *user_data, uint32_t name, int fd, struct wl_drm_buffer *buffer); void (*release_buffer)(void *user_data, struct wl_drm_buffer *buffer); }; +enum { WAYLAND_DRM_PRIME = 0x01 }; + struct wl_drm * wayland_drm_init(struct wl_display *display, char *device_name, - struct wayland_drm_callbacks *callbacks, void *user_data); + struct wayland_drm_callbacks *callbacks, void *user_data, + uint32_t flags); void wayland_drm_uninit(struct wl_drm *drm); diff --git a/src/egl/wayland/wayland-drm/wayland-drm.xml b/src/egl/wayland/wayland-drm/wayland-drm.xml index 265d4f892af..8a3ad69b21d 100644 --- a/src/egl/wayland/wayland-drm/wayland-drm.xml +++ b/src/egl/wayland/wayland-drm/wayland-drm.xml @@ -29,7 +29,7 @@ - + @@ -135,6 +135,22 @@ + + + + + + + + + + + + + + + + + + + Bitmask of capabilities. + + + + + + + -- 2.30.2