wayland: Add prime fd passing as a buffer sharing mechanism

Reviewed-by: Ander Conselvan de Oliveira <conselvan2@gmail.com>
This commit is contained in:
Kristian Høgsberg 2013-02-02 12:26:12 -05:00
parent 2356e28452
commit de315f76a2
6 changed files with 149 additions and 34 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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);
}
}

View File

@ -31,6 +31,7 @@
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <unistd.h>
#include <wayland-server.h>
#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);

View File

@ -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);

View File

@ -29,7 +29,7 @@
<!-- drm support. This object is created by the server and published
using the display's global event. -->
<interface name="wl_drm" version="1">
<interface name="wl_drm" version="2">
<enum name="error">
<entry name="authenticate_fail" value="0"/>
<entry name="invalid_format" value="1"/>
@ -135,6 +135,22 @@
<arg name="stride2" type="int"/>
</request>
<!-- Create a wayland buffer for the prime fd. Use for regular and planar
buffers. Pass 0 for offset and stride for unused planes. -->
<request name="create_prime_buffer" since="2">
<arg name="id" type="new_id" interface="wl_buffer"/>
<arg name="name" type="fd"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
<arg name="format" type="uint"/>
<arg name="offset0" type="int"/>
<arg name="stride0" type="int"/>
<arg name="offset1" type="int"/>
<arg name="stride1" type="int"/>
<arg name="offset2" type="int"/>
<arg name="stride2" type="int"/>
</request>
<!-- Notification of the path of the drm device which is used by
the server. The client should use this device for creating
local buffers. Only buffers created from this device should
@ -150,6 +166,17 @@
<!-- Raised if the authenticate request succeeded -->
<event name="authenticated"/>
<enum name="capability" since="2">
<description summary="wl_drm capability bitmask">
Bitmask of capabilities.
</description>
<entry name="prime" value="1" summary="wl_drm prime available"/>
</enum>
<event name="capabilities">
<arg name="value" type="uint"/>
</event>
</interface>
</protocol>