From b185fe89a1ea8ddbe19d943cb19272f369b7b438 Mon Sep 17 00:00:00 2001
From: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Date: Mon, 25 Nov 2013 11:38:12 +0100
Subject: [PATCH] make weston able to use wl_drm protocol

Make compositor-drm able to provide wl_drm buffer even if EGL isn't used.
Update pixman to allow it to compose wl_drm buffer like it does for wl_shm.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
---
 src/compositor-drm.c  |  131 +++++++++++++++++++++++++++++++++++++++++++++++--
 src/pixman-renderer.c |   60 +++++++++++++++-------
 2 files changed, 169 insertions(+), 22 deletions(-)

diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index da1ba79..b336127 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -45,6 +45,8 @@
 #include "pixman-renderer.h"
 #include "udev-seat.h"
 #include "launcher-util.h"
+#include "wayland-drm.h"
+#include "wayland-drm-server-protocol.h"
 
 static int option_current_mode = 0;
 static char *output_name;
@@ -79,10 +81,12 @@ struct drm_compositor {
 
 	struct udev_monitor *udev_monitor;
 	struct wl_event_source *udev_drm_source;
+	struct wl_drm *wl_server_drm;
 
 	struct {
 		int id;
 		int fd;
+		char *device_name;
 	} drm;
 	struct gbm_device *gbm;
 	uint32_t *crtcs;
@@ -754,7 +758,7 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
 	if (es->alpha != 1.0f)
 		return NULL;
 
-	if (wl_buffer_is_shm(es->buffer_ref.buffer))
+	if (wl_buffer_is_shm(es->buffer_ref.buffer) || wayland_buffer_is_drm(es->buffer_ref.buffer))
 		return NULL;
 
 	if (!drm_surface_transform_supported(es))
@@ -876,7 +880,7 @@ drm_output_prepare_cursor_surface(struct weston_output *output_base,
 	if (c->cursors_are_broken)
 		return NULL;
 	if (es->buffer_ref.buffer == NULL ||
-	    !wl_buffer_is_shm(es->buffer_ref.buffer) ||
+	    (!wl_buffer_is_shm(es->buffer_ref.buffer) && !wayland_buffer_is_drm(es->buffer_ref.buffer)) ||
 	    es->geometry.width > 64 || es->geometry.height > 64)
 		return NULL;
 
@@ -966,10 +970,10 @@ drm_assign_planes(struct weston_output *output)
 	primary = &c->base.primary_plane;
 	wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
 		/* test whether this buffer can ever go into a plane:
-		 * non-shm, or small enough to be a cursor
+		 * non-shm, non-drm, or small enough to be a cursor
 		 */
 		if ((es->buffer_ref.buffer &&
-		     !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
+		     (!wl_buffer_is_shm(es->buffer_ref.buffer) && !wayland_buffer_is_drm(es->buffer_ref.buffer))) ||
 		    (es->geometry.width <= 64 && es->geometry.height <= 64))
 			es->keep_buffer = 1;
 		else
@@ -1174,8 +1178,120 @@ init_drm(struct drm_compositor *ec, struct udev_device *device)
 	weston_log("using %s\n", filename);
 
 	ec->drm.fd = fd;
+	ec->drm.device_name = strdup(filename);
 
+	return 0;
+}
+
+static int
+drm_display_authenticate(void *user_data, uint32_t magic)
+{
+	struct drm_compositor *ec = user_data;
+	weston_log("authentification\n");
+	return drmAuthMagic(ec->drm.fd, magic);
+}
+
+struct drm_driver_buffer {
+	uint32_t size;
+	uint32_t handle;
+	char *data;
+};
+
+static void
+drm_reference_buffer(void *user_data, uint32_t name, int prime_fd,
+		struct wl_drm_buffer *buffer)
+{
+	struct drm_compositor *ec = user_data;
+	uint32_t handles[4], pitches[4], offsets[4];
+	int ret;
+	uint32_t fd;
+	struct drm_driver_buffer *driver_buffer;
 
+	weston_log("reference buffer fd %d\n", prime_fd);
+	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];
+
+	weston_log("drmModeAddFB2 fd %d\n", prime_fd);
+	ret = drmModeAddFB2 (ec->drm.fd, buffer->buffer.width, buffer->buffer.height,
+		  buffer->format, handles, pitches, offsets, &fd, 0);
+	if (ret) {
+		weston_log("addfb2 failed: %m\n");
+		return;
+	}
+
+	weston_log("addfb2 success\n");
+	driver_buffer = malloc(sizeof *driver_buffer);
+	if (driver_buffer == NULL)
+		return;
+
+	driver_buffer->size = buffer->buffer.width * buffer->buffer.height * 4;
+	driver_buffer->handle = handles[0];
+	driver_buffer->data = NULL;
+	buffer->driver_buffer = driver_buffer;
+	weston_log("drm_reference_buffer success\n");
+}
+
+static void
+drm_unreference_buffer(void *user_data, struct wl_drm_buffer *buffer)
+{
+	struct drm_driver_buffer *driver_buffer = buffer->driver_buffer;
+
+	weston_log("unreference buffer\n");
+
+	if(driver_buffer->data)
+		munmap(driver_buffer->data, driver_buffer->size);
+
+	free(buffer->driver_buffer);
+}
+
+static void*
+drm_get_data(void *user_data, struct wl_drm_buffer *buffer)
+{
+	struct drm_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
+drm_put_data(void *user_data, struct wl_drm_buffer *buffer)
+{
+	struct drm_driver_buffer *driver_buffer = buffer->driver_buffer;
+	struct drm_compositor *ec = user_data;
+
+	if (!driver_buffer->data) {
+		munmap (driver_buffer->data, driver_buffer->size);
+		driver_buffer->data = NULL;
+	}
+}
+
+static struct wayland_drm_callbacks wl_drm_callbacks = {
+	drm_display_authenticate,
+	drm_reference_buffer,
+	drm_unreference_buffer,
+	drm_get_data,
+	drm_put_data
+};
+
+static int
+init_drm_protocol(struct drm_compositor *ec)
+{
+	wayland_drm_init(ec->base.wl_display, ec->drm.device_name,
+		&wl_drm_callbacks, ec, 0);
 	return 0;
 }
 
@@ -1982,6 +2098,9 @@ drm_destroy(struct weston_compositor *ec)
 		weston_log("failed to drop master: %m\n");
 	tty_destroy(d->tty);
 
+	if (d->drm.device_name)
+		free(d->drm.device_name);
+
 	free(d);
 }
 
@@ -2229,6 +2348,10 @@ drm_compositor_create(struct wl_display *display,
 			weston_log("failed to initialize pixman renderer\n");
 			goto err_udev_dev;
 		}
+		if (init_drm_protocol(ec) < 0) {
+			weston_log("failed to initialize wayand drm protocol\n");
+			goto err_udev_dev;
+		}
 	} else {
 		if (init_egl(ec) < 0) {
 			weston_log("failed to initialize egl\n");
diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c
index 9dbe9f0..ac671cb 100644
--- a/src/pixman-renderer.c
+++ b/src/pixman-renderer.c
@@ -27,6 +27,7 @@
 #include <stdlib.h>
 
 #include "pixman-renderer.h"
+#include "wayland-drm.h"
 
 #include <linux/input.h>
 
@@ -375,30 +376,53 @@ pixman_renderer_attach(struct weston_surface *es, struct wl_buffer *buffer)
 	if (!buffer)
 		return;
 
-	if (!wl_buffer_is_shm(buffer)) {
-		weston_log("Pixman renderer supports only SHM buffers\n");
+	if (!wl_buffer_is_shm(buffer) && !wayland_buffer_is_drm(buffer)) {
+		weston_log("Pixman renderer supports only SHM and DRM buffers\n");
 		weston_buffer_reference(&ps->buffer_ref, NULL);
 		return;
 	}
 
-	switch (wl_shm_buffer_get_format(buffer)) {
-	case WL_SHM_FORMAT_XRGB8888:
-		pixman_format = PIXMAN_x8r8g8b8;
-		break;
-	case WL_SHM_FORMAT_ARGB8888:
-		pixman_format = PIXMAN_a8r8g8b8;
-		break;
-	default:
+	if (wl_buffer_is_shm(buffer)) {
+		switch (wl_shm_buffer_get_format(buffer)) {
+		case WL_SHM_FORMAT_XRGB8888:
+			pixman_format = PIXMAN_x8r8g8b8;
+			break;
+		case WL_SHM_FORMAT_ARGB8888:
+			pixman_format = PIXMAN_a8r8g8b8;
+			break;
+		default:
 		weston_log("Unsupported SHM buffer format\n");
-		weston_buffer_reference(&ps->buffer_ref, NULL);
-		return;
-	break;
+			weston_buffer_reference(&ps->buffer_ref, NULL);
+			return;
+		}
+		ps->image = pixman_image_create_bits(pixman_format,
+			wl_shm_buffer_get_width(buffer),
+			wl_shm_buffer_get_height(buffer),
+			wl_shm_buffer_get_data(buffer),
+			wl_shm_buffer_get_stride(buffer));
+	}
+
+	if (wayland_buffer_is_drm(buffer)) {
+		switch (wayland_drm_buffer_get_format(buffer)) {
+		case WL_DRM_FORMAT_XRGB8888:
+			pixman_format = PIXMAN_x8r8g8b8;
+			break;
+		case WL_DRM_FORMAT_ARGB8888:
+			pixman_format = PIXMAN_a8r8g8b8;
+			break;
+		default:
+			weston_log("Unsupported DRM buffer format\n");
+			weston_buffer_reference(&ps->buffer_ref, NULL);
+			return;
+		}
+		ps->image = pixman_image_create_bits(pixman_format,
+			wayland_drm_buffer_get_width(buffer),
+			wayland_drm_buffer_get_height(buffer),
+			wayland_drm_buffer_get_data(buffer),
+			wayland_drm_buffer_get_stride(buffer, 0));
+
+		wayland_drm_buffer_put_data(buffer);
 	}
-	ps->image = pixman_image_create_bits(pixman_format,
-		wl_shm_buffer_get_width(buffer),
-		wl_shm_buffer_get_height(buffer),
-		wl_shm_buffer_get_data(buffer),
-		wl_shm_buffer_get_stride(buffer));
 }
 
 static int
-- 
1.7.9.5

