[PATCH v3] compositor-drm: allow to be a wl_dmabuf server
benjamin.gaignard at linaro.org
benjamin.gaignard at linaro.org
Thu Dec 12 12:27:21 PST 2013
From: Benjamin Gaignard <benjamin.gaignard at linaro.org>
Make drm compositor aware of the wl_dmabuf protocol if pixman is used.
Add functions to have a wl_dmabuf server inside drm compositor.
Change pixman to let it know how use a wl_dmabuf buffer.
Signed-off-by: Benjamin Gaignard <benjamin.gaignard at linaro.org>
---
src/compositor-drm.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++--
src/compositor.c | 4 +-
src/compositor.h | 2 +
src/pixman-renderer.c | 86 ++++++++++++++++++-------
4 files changed, 230 insertions(+), 30 deletions(-)
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 4f015d1..dd957cd 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -49,6 +49,8 @@
#include "udev-seat.h"
#include "launcher-util.h"
#include "vaapi-recorder.h"
+#include "wayland-dmabuf.h"
+#include "wayland-dmabuf-server-protocol.h"
#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
@@ -826,7 +828,8 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
if (es->alpha != 1.0f)
return NULL;
- if (wl_shm_buffer_get(es->buffer_ref.buffer->resource))
+ if (wl_shm_buffer_get(es->buffer_ref.buffer->resource)
+ || wl_dmabuf_buffer_get(es->buffer_ref.buffer->resource))
return NULL;
if (!drm_surface_transform_supported(es))
@@ -951,7 +954,8 @@ drm_output_prepare_cursor_surface(struct weston_output *output_base,
if (c->cursors_are_broken)
return NULL;
if (es->buffer_ref.buffer == NULL ||
- !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
+ (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) &&
+ !wl_dmabuf_buffer_get(es->buffer_ref.buffer->resource))||
es->geometry.width > 64 || es->geometry.height > 64)
return NULL;
@@ -985,12 +989,25 @@ drm_output_set_cursor(struct drm_output *output)
output->current_cursor ^= 1;
bo = output->cursor_bo[output->current_cursor];
memset(buf, 0, sizeof buf);
- stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
- s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
+ if (wl_shm_buffer_get(es->buffer_ref.buffer->resource)) {
+ stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
+ s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
+ }
+ if (wl_dmabuf_buffer_get(es->buffer_ref.buffer->resource)) {
+ stride = wl_dmabuf_buffer_get_stride(es->buffer_ref.buffer->dmabuf_buffer, 0);
+ s = wl_dmabuf_buffer_get_data(es->buffer_ref.buffer->dmabuf_buffer);
+ if (!s) {
+ weston_log("failed to get data from dmabuf buffer");
+ return;
+ }
+ }
for (i = 0; i < es->geometry.height; i++)
memcpy(buf + i * 64, s + i * stride,
es->geometry.width * 4);
+ if (wl_dmabuf_buffer_get(es->buffer_ref.buffer->resource))
+ wl_dmabuf_buffer_put_data(es->buffer_ref.buffer->dmabuf_buffer);
+
if (gbm_bo_write(bo, buf, sizeof buf) < 0)
weston_log("failed update cursor: %m\n");
@@ -1044,7 +1061,8 @@ drm_assign_planes(struct weston_output *output)
* non-shm, or small enough to be a cursor
*/
if ((es->buffer_ref.buffer &&
- !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
+ (!wl_shm_buffer_get(es->buffer_ref.buffer->resource))
+ && !wl_dmabuf_buffer_get(es->buffer_ref.buffer->resource)) ||
(es->geometry.width <= 64 && es->geometry.height <= 64))
es->keep_buffer = 1;
else
@@ -1268,6 +1286,142 @@ init_drm(struct drm_compositor *ec, struct udev_device *device)
return 0;
}
+struct dmabuf_driver_buffer {
+ uint32_t size;
+ uint32_t handle;
+ char *data;
+};
+
+static void
+dmabuf_reference_buffer(void *user_data, int prime_fd, struct wl_dmabuf_buffer *buffer)
+{
+ struct drm_compositor *ec = user_data;
+ uint32_t handles[4], pitches[4], offsets[4];
+ int ret;
+ uint32_t fd;
+ struct dmabuf_driver_buffer *driver_buffer;
+
+ if (prime_fd == -1)
+ return;
+
+ drmPrimeFDToHandle(ec->drm.fd, prime_fd, &handles[0]);
+ pitches[0] = buffer->stride[0];
+ pitches[1] = buffer->stride[1];
+ pitches[2] = buffer->stride[2];
+ offsets[0] = buffer->offset[0];
+ offsets[1] = buffer->offset[1];
+ offsets[2] = buffer->offset[2];
+
+ ret = drmModeAddFB2 (ec->drm.fd, buffer->width, buffer->height,
+ buffer->format, handles, pitches, offsets, &fd, 0);
+ if (ret) {
+ weston_log("addfb2 failed: %m\n");
+ return;
+ }
+
+ driver_buffer = malloc(sizeof *driver_buffer);
+ if (driver_buffer == NULL)
+ return;
+
+ driver_buffer->size = buffer->width * buffer->height * 4;
+ driver_buffer->handle = handles[0];
+ driver_buffer->data = NULL;
+ buffer->driver_buffer = driver_buffer;
+}
+
+static void
+dmabuf_unreference_buffer(void *user_data, struct wl_dmabuf_buffer *buffer)
+{
+ struct dmabuf_driver_buffer *driver_buffer = buffer->driver_buffer;
+
+ if(driver_buffer->data)
+ munmap(driver_buffer->data, driver_buffer->size);
+
+ free(buffer->driver_buffer);
+}
+
+static void*
+dmabuf_get_data(void *user_data, struct wl_dmabuf_buffer *buffer)
+{
+ struct dmabuf_driver_buffer *driver_buffer = buffer->driver_buffer;
+ struct drm_compositor *ec = user_data;
+
+ if (!driver_buffer->data) {
+ int fd;
+ drmPrimeHandleToFD(ec->drm.fd, driver_buffer->handle, 0, &fd);
+ driver_buffer->data = mmap (0, driver_buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ close(fd);
+ }
+ return driver_buffer->data;
+}
+
+
+static void
+dmabuf_put_data(void *user_data, struct wl_dmabuf_buffer *buffer)
+{
+ struct dmabuf_driver_buffer *driver_buffer = buffer->driver_buffer;
+
+ if (!driver_buffer->data) {
+ munmap (driver_buffer->data, driver_buffer->size);
+ driver_buffer->data = NULL;
+ }
+}
+
+static void dmabuf_send_supported_formats(void *user_data, struct wl_resource *resource)
+{
+ struct drm_compositor *ec = user_data;
+ drmModePlaneRes *plane_resources;
+ unsigned int i, j;
+
+ weston_log("send supported formats\n");
+
+ plane_resources = drmModeGetPlaneResources(ec->drm.fd);
+ if (!plane_resources)
+ return;
+
+ for (i = 0; i < plane_resources->count_planes; i++) {
+ drmModePlane *ovr = drmModeGetPlane(ec->drm.fd, plane_resources->planes[i]);
+
+ for (j = 0 ; j < ovr->count_formats; j++) {
+ weston_log("server support format %4.4s\n", (char *)&ovr->formats[j]);
+ wl_dmabuf_send_format(resource, ovr->formats[j]);
+ }
+ drmModeFreePlane(ovr);
+ }
+
+ drmModeFreePlaneResources(plane_resources);
+}
+
+static void dmabuf_send_device_name(void *user_data, struct wl_resource *resource)
+{
+ struct drm_compositor *ec = user_data;
+ weston_log("send device name %s\n", ec->drm.filename);
+
+ wl_dmabuf_send_device(resource, ec->drm.filename);
+}
+
+static void dmabuf_send_server_info(void *user_data, struct wl_resource *resource)
+{
+ dmabuf_send_supported_formats(user_data, resource);
+ dmabuf_send_device_name(user_data, resource);
+}
+
+static struct wl_dmabuf_callbacks wl_dmabuf_callbacks = {
+ dmabuf_reference_buffer,
+ dmabuf_unreference_buffer,
+ dmabuf_get_data,
+ dmabuf_put_data,
+ dmabuf_send_server_info
+};
+
+static int
+init_dmabuf_protocol(struct drm_compositor *ec)
+{
+ wl_dmabuf_init(ec->base.wl_display,
+ &wl_dmabuf_callbacks, ec, 0);
+ return 0;
+}
+
static int
init_egl(struct drm_compositor *ec)
{
@@ -1955,6 +2109,10 @@ create_output_for_connector(struct drm_compositor *ec,
weston_log("Failed to init output pixman state\n");
goto err_output;
}
+ if (init_dmabuf_protocol(ec) < 0) {
+ weston_log("Failed to init wl_dmabuf server\n");
+ goto err_output;
+ }
} else if (drm_output_init_egl(output, ec) < 0) {
weston_log("Failed to init output gl state\n");
goto err_output;
diff --git a/src/compositor.c b/src/compositor.c
index 4cb44e5..037b695 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -1257,7 +1257,9 @@ surface_accumulate_damage(struct weston_surface *surface,
pixman_region32_t *opaque)
{
if (surface->buffer_ref.buffer &&
- wl_shm_buffer_get(surface->buffer_ref.buffer->resource))
+ (wl_shm_buffer_get(surface->buffer_ref.buffer->resource)
+ || wl_dmabuf_buffer_get(surface->buffer_ref.buffer->resource))
+ )
surface->compositor->renderer->flush_damage(surface);
if (surface->transform.enabled) {
diff --git a/src/compositor.h b/src/compositor.h
index 0dcb604..537a9b7 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -33,6 +33,7 @@ extern "C" {
#define WL_HIDE_DEPRECATED
#include <wayland-server.h>
+#include <wayland-dmabuf.h>
#include "version.h"
#include "matrix.h"
@@ -626,6 +627,7 @@ struct weston_buffer {
union {
struct wl_shm_buffer *shm_buffer;
+ struct wl_dmabuf_buffer *dmabuf_buffer;
void *legacy_buffer;
};
int32_t width, height;
diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c
index 987c539..7802f2d 100644
--- a/src/pixman-renderer.c
+++ b/src/pixman-renderer.c
@@ -533,6 +533,8 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
{
struct pixman_surface_state *ps = get_surface_state(es);
struct wl_shm_buffer *shm_buffer;
+ struct wl_dmabuf_buffer *dmabuf_buffer;
+
pixman_format_code_t pixman_format;
weston_buffer_reference(&ps->buffer_ref, buffer);
@@ -544,40 +546,76 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
if (!buffer)
return;
-
+
shm_buffer = wl_shm_buffer_get(buffer->resource);
+ dmabuf_buffer = wl_dmabuf_buffer_get(buffer->resource);
- if (! shm_buffer) {
- weston_log("Pixman renderer supports only SHM buffers\n");
+ if (!shm_buffer && !dmabuf_buffer) {
+ weston_log("Pixman renderer supports only SHM and DMABUF buffers\n");
weston_buffer_reference(&ps->buffer_ref, NULL);
return;
}
- switch (wl_shm_buffer_get_format(shm_buffer)) {
- case WL_SHM_FORMAT_XRGB8888:
- pixman_format = PIXMAN_x8r8g8b8;
- break;
- case WL_SHM_FORMAT_ARGB8888:
- pixman_format = PIXMAN_a8r8g8b8;
- break;
- case WL_SHM_FORMAT_RGB565:
- pixman_format = PIXMAN_r5g6b5;
+ if (shm_buffer) {
+ switch (wl_shm_buffer_get_format(shm_buffer)) {
+ case WL_SHM_FORMAT_XRGB8888:
+ pixman_format = PIXMAN_x8r8g8b8;
+ break;
+ case WL_SHM_FORMAT_ARGB8888:
+ pixman_format = PIXMAN_a8r8g8b8;
+ break;
+ case WL_SHM_FORMAT_RGB565:
+ pixman_format = PIXMAN_r5g6b5;
+ break;
+ default:
+ weston_log("Unsupported SHM buffer format\n");
+ weston_buffer_reference(&ps->buffer_ref, NULL);
+ return;
break;
- default:
- weston_log("Unsupported SHM buffer format\n");
- weston_buffer_reference(&ps->buffer_ref, NULL);
- return;
- break;
+ }
+
+ buffer->shm_buffer = shm_buffer;
+ buffer->width = wl_shm_buffer_get_width(shm_buffer);
+ buffer->height = wl_shm_buffer_get_height(shm_buffer);
+
+ ps->image = pixman_image_create_bits(pixman_format,
+ buffer->width, buffer->height,
+ wl_shm_buffer_get_data(shm_buffer),
+ wl_shm_buffer_get_stride(shm_buffer));
}
- buffer->shm_buffer = shm_buffer;
- buffer->width = wl_shm_buffer_get_width(shm_buffer);
- buffer->height = wl_shm_buffer_get_height(shm_buffer);
+ if (dmabuf_buffer) {
+ void *data;
+ switch (wl_dmabuf_buffer_get_format(dmabuf_buffer)) {
+ case WL_DMABUF_FORMAT_XRGB8888:
+ pixman_format = PIXMAN_x8r8g8b8;
+ break;
+ case WL_DMABUF_FORMAT_ARGB8888:
+ pixman_format = PIXMAN_a8r8g8b8;
+ break;
+ case WL_DMABUF_FORMAT_RGB565:
+ pixman_format = PIXMAN_r5g6b5;
+ break;
+ default:
+ weston_log("Unsupported DMABUF buffer format\n");
+ weston_buffer_reference(&ps->buffer_ref, NULL);
+ return;
+ break;
+ }
- ps->image = pixman_image_create_bits(pixman_format,
- buffer->width, buffer->height,
- wl_shm_buffer_get_data(shm_buffer),
- wl_shm_buffer_get_stride(shm_buffer));
+ buffer->dmabuf_buffer = dmabuf_buffer;
+ buffer->width = wl_dmabuf_buffer_get_width(dmabuf_buffer);
+ buffer->height = wl_dmabuf_buffer_get_height(dmabuf_buffer);
+
+ data = wl_dmabuf_buffer_get_data(dmabuf_buffer);
+ if (data) {
+ ps->image = pixman_image_create_bits(pixman_format,
+ buffer->width, buffer->height, data,
+ wl_dmabuf_buffer_get_stride(dmabuf_buffer, 0));
+ wl_dmabuf_buffer_put_data(dmabuf_buffer);
+ } else
+ weston_log("failed to get data from dmabuf buffer");
+ }
}
static int
--
1.7.9.5
More information about the wayland-devel
mailing list