From b9f446b90af21bd3bf908cf39132b4744fd44aeb Mon Sep 17 00:00:00 2001
From: Halley Zhao <halley.zhao@intel.com>
Date: Tue, 10 Apr 2012 15:25:57 +0800
Subject: [PATCH] add wayland-drm protocol module

---
 Makefile.am                      |    6 +-
 configure.ac                     |   16 +++
 wayland/Makefile.am              |   18 +++
 wayland/libdrm_wayland.pc.in     |   10 ++
 wayland/protocol/wayland-drm.xml |  139 ++++++++++++++++++++++++
 wayland/wayland-drm.c            |  221 ++++++++++++++++++++++++++++++++++++++
 wayland/wayland-drm.h            |   35 ++++++
 7 files changed, 444 insertions(+), 1 deletions(-)
 create mode 100644 wayland/Makefile.am
 create mode 100644 wayland/libdrm_wayland.pc.in
 create mode 100644 wayland/protocol/wayland-drm.xml
 create mode 100644 wayland/wayland-drm.c
 create mode 100644 wayland/wayland-drm.h

diff --git a/Makefile.am b/Makefile.am
index a4d07f4..fd9ab43 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -41,7 +41,11 @@ if HAVE_RADEON
 RADEON_SUBDIR = radeon
 endif
 
-SUBDIRS = . $(LIBKMS_SUBDIR) $(INTEL_SUBDIR) $(NOUVEAU_SUBDIR) $(RADEON_SUBDIR) tests include
+if HAVE_WAYLAND_PROTOCOL
+WAYLAND_SUBDIR = wayland
+endif
+
+SUBDIRS = . $(LIBKMS_SUBDIR) $(INTEL_SUBDIR) $(NOUVEAU_SUBDIR) $(RADEON_SUBDIR) $(WAYLAND_SUBDIR) tests include
 
 libdrm_la_LTLIBRARIES = libdrm.la
 libdrm_ladir = $(libdir)
diff --git a/configure.ac b/configure.ac
index 97bbcb7..191b3a6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -87,6 +87,10 @@ AC_ARG_ENABLE(nouveau-experimental-api,
 	      [Enable support for nouveau's experimental API (default: disabled)]),
 	      [NOUVEAU=$enableval], [NOUVEAU=no])
 
+AC_ARG_ENABLE(wayland-protocol,
+	      AS_HELP_STRING([--enable-wayland-protocol],
+	      [Build wayland-drm-protocol (default: disabled)]),
+	      [WAYLAND_PROTOCOL=$enableval], [WAYLAND_PROTOCOL=no])
 
 dnl ===========================================================================
 dnl check compiler flags
@@ -277,6 +281,15 @@ AC_ARG_WITH([kernel-source],
               [specify path to linux kernel source])],
 	    [kernel_source="$with_kernel_source"])
 AC_SUBST(kernel_source)
+       
+AM_CONDITIONAL(HAVE_WAYLAND_PROTOCOL, [test "x$WAYLAND_PROTOCOL" != "xno"])
+if test "x$WAYLAND_PROTOCOL" != "xno"; then 
+    PKG_CHECK_MODULES([WAYLAND], [wayland-client wayland-server],, \
+                  [AC_MSG_ERROR([cannot find libwayland-client])])
+    
+    m4_ifdef([WAYLAND_SCANNER_RULES],
+                  [WAYLAND_SCANNER_RULES(['$(top_srcdir)/wayland/protocol'])])
+fi
 
 AC_SUBST(WARN_CFLAGS)
 AC_CONFIG_FILES([
@@ -289,6 +302,8 @@ AC_CONFIG_FILES([
 	radeon/libdrm_radeon.pc
 	nouveau/Makefile
 	nouveau/libdrm_nouveau.pc
+	wayland/Makefile
+	wayland/libdrm_wayland.pc
 	tests/Makefile
 	tests/modeprint/Makefile
 	tests/modetest/Makefile
@@ -308,4 +323,5 @@ echo "  Intel API      $INTEL"
 echo "  vmwgfx API     $VMWGFX"
 echo "  Radeon API     $RADEON"
 echo "  Nouveau API    $NOUVEAU"
+echo "  wayland protocol $WAYLAND_PROTOCOL"
 echo ""
diff --git a/wayland/Makefile.am b/wayland/Makefile.am
new file mode 100644
index 0000000..9af18bd
--- /dev/null
+++ b/wayland/Makefile.am
@@ -0,0 +1,18 @@
+AM_CFLAGS = $(DEFINES) \
+	    	$(WAYLAND_CFLAGS) 
+
+libdrm_wayland_la_LTLIBRARIES = libwayland-drm.la
+libdrm_wayland_ladir = $(libdir)
+libdrm_wayland_la_LDFLAGS = -no-undefined
+libdrm_wayland_la_LIBADD = ../libdrm.la 
+
+libwayland_drm_la_SOURCES = wayland-drm.c wayland-drm-protocol.c
+noinst_HEADERS = wayland-drm.h
+
+BUILT_SOURCES = wayland-drm-protocol.c \
+		wayland-drm-client-protocol.h \
+		wayland-drm-server-protocol.h
+CLEANFILES = $(BUILT_SOURCES)
+
+pkgconfig_DATA = libdrm_wayland.pc
+@wayland_scanner_rules@
diff --git a/wayland/libdrm_wayland.pc.in b/wayland/libdrm_wayland.pc.in
new file mode 100644
index 0000000..085f018
--- /dev/null
+++ b/wayland/libdrm_wayland.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libdrm-wayland
+Description: wayland drm protocol help library 
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lwayland-drm
+Cflags: -I${includedir} -I${includedir}/libdrm
diff --git a/wayland/protocol/wayland-drm.xml b/wayland/protocol/wayland-drm.xml
new file mode 100644
index 0000000..89fd8f0
--- /dev/null
+++ b/wayland/protocol/wayland-drm.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="drm">
+
+  <copyright>
+    Copyright © 2008-2011 Kristian Høgsberg
+    Copyright © 2010-2011 Intel Corporation
+
+    Permission to use, copy, modify, distribute, and sell this
+    software and its documentation for any purpose is hereby granted
+    without fee, provided that\n the above copyright notice appear in
+    all copies and that both that copyright notice and this permission
+    notice appear in supporting documentation, and that the name of
+    the copyright holders not be used in advertising or publicity
+    pertaining to distribution of the software without specific,
+    written prior permission.  The copyright holders make no
+    representations about the suitability of this software for any
+    purpose.  It is provided "as is" without express or implied
+    warranty.
+
+    THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+    FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+    THIS SOFTWARE.
+  </copyright>
+
+  <!-- drm support. This object is created by the server and published
+       using the display's global event. -->
+  <interface name="wl_drm" version="1">
+    <enum name="error">
+      <entry name="authenticate_fail" value="0"/>
+      <entry name="invalid_format" value="1"/>
+      <entry name="invalid_name" value="2"/>
+    </enum>
+
+    <enum name="format">
+      <!-- The drm format codes match the #defines in drm_fourcc.h.
+           The formats actually supported by the compositor will be
+           reported by the format event. -->
+      <entry name="c8" value="0x20203843"/>
+      <entry name="rgb332" value="0x38424752"/>
+      <entry name="bgr233" value="0x38524742"/>
+      <entry name="xrgb4444" value="0x32315258"/>
+      <entry name="xbgr4444" value="0x32314258"/>
+      <entry name="rgbx4444" value="0x32315852"/>
+      <entry name="bgrx4444" value="0x32315842"/>
+      <entry name="argb4444" value="0x32315241"/>
+      <entry name="abgr4444" value="0x32314241"/>
+      <entry name="rgba4444" value="0x32314152"/>
+      <entry name="bgra4444" value="0x32314142"/>
+      <entry name="xrgb1555" value="0x35315258"/>
+      <entry name="xbgr1555" value="0x35314258"/>
+      <entry name="rgbx5551" value="0x35315852"/>
+      <entry name="bgrx5551" value="0x35315842"/>
+      <entry name="argb1555" value="0x35315241"/>
+      <entry name="abgr1555" value="0x35314241"/>
+      <entry name="rgba5551" value="0x35314152"/>
+      <entry name="bgra5551" value="0x35314142"/>
+      <entry name="rgb565" value="0x36314752"/>
+      <entry name="bgr565" value="0x36314742"/>
+      <entry name="rgb888" value="0x34324752"/>
+      <entry name="bgr888" value="0x34324742"/>
+      <entry name="xrgb8888" value="0x34325258"/>
+      <entry name="xbgr8888" value="0x34324258"/>
+      <entry name="rgbx8888" value="0x34325852"/>
+      <entry name="bgrx8888" value="0x34325842"/>
+      <entry name="argb8888" value="0x34325241"/>
+      <entry name="abgr8888" value="0x34324241"/>
+      <entry name="rgba8888" value="0x34324152"/>
+      <entry name="bgra8888" value="0x34324142"/>
+      <entry name="xrgb2101010" value="0x30335258"/>
+      <entry name="xbgr2101010" value="0x30334258"/>
+      <entry name="rgbx1010102" value="0x30335852"/>
+      <entry name="bgrx1010102" value="0x30335842"/>
+      <entry name="argb2101010" value="0x30335241"/>
+      <entry name="abgr2101010" value="0x30334241"/>
+      <entry name="rgba1010102" value="0x30334152"/>
+      <entry name="bgra1010102" value="0x30334142"/>
+      <entry name="yuyv" value="0x56595559"/>
+      <entry name="yvyu" value="0x55595659"/>
+      <entry name="uyvy" value="0x59565955"/>
+      <entry name="vyuy" value="0x59555956"/>
+      <entry name="ayuv" value="0x56555941"/>
+      <entry name="nv12" value="0x3231564e"/>
+      <entry name="nv21" value="0x3132564e"/>
+      <entry name="nv16" value="0x3631564e"/>
+      <entry name="nv61" value="0x3136564e"/>
+      <entry name="yuv410" value="0x39565559"/>
+      <entry name="yvu410" value="0x39555659"/>
+      <entry name="yuv411" value="0x31315559"/>
+      <entry name="yvu411" value="0x31315659"/>
+      <entry name="yuv420" value="0x32315559"/>
+      <entry name="yvu420" value="0x32315659"/>
+      <entry name="yuv422" value="0x36315559"/>
+      <entry name="yvu422" value="0x36315659"/>
+      <entry name="yuv444" value="0x34325559"/>
+      <entry name="yvu444" value="0x34325659"/>
+    </enum>
+
+    <!-- Call this request with the magic received from drmGetMagic().
+         It will be passed on to the drmAuthMagic() or
+         DRIAuthConnection() call.  This authentication must be
+         completed before create_buffer could be used. -->
+    <request name="authenticate">
+      <arg name="id" type="uint"/>
+    </request>
+
+    <!-- Create a wayland buffer for the named DRM buffer.  The DRM
+         surface must have a name using the flink ioctl -->
+    <request name="create_buffer">
+      <arg name="id" type="new_id" interface="wl_buffer"/>
+      <arg name="name" type="uint"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+      <arg name="stride" type="uint"/>
+      <arg name="format" type="uint"/>
+    </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
+         be be passed to the server using this drm object's
+         create_buffer request. -->
+    <event name="device">
+      <arg name="name" type="string"/>
+    </event>
+
+    <event name="format">
+      <arg name="format" type="uint"/>
+    </event>
+
+    <!-- Raised if the authenticate request succeeded -->
+    <event name="authenticated"/>
+  </interface>
+
+</protocol>
diff --git a/wayland/wayland-drm.c b/wayland/wayland-drm.c
new file mode 100644
index 0000000..42e6788
--- /dev/null
+++ b/wayland/wayland-drm.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright © 2011 Kristian Høgsberg
+ * Copyright © 2011 Benjamin Franzke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Kristian Høgsberg <krh@bitplanet.net>
+ *    Benjamin Franzke <benjaminfranzke@googlemail.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+
+#include <wayland-server.h>
+#include "wayland-drm.h"
+#include "wayland-drm-server-protocol.h"
+
+struct wl_drm {
+	struct wl_display *display;
+
+	void *user_data;
+	char *device_name;
+
+	struct wayland_drm_callbacks *callbacks;
+};
+
+struct wl_drm_buffer {
+	struct wl_buffer buffer;
+	struct wl_drm *drm;
+	uint32_t format;
+
+	void *driver_buffer;
+};
+
+static void
+buffer_damage(struct wl_client *client, struct wl_resource *buffer,
+	      int32_t x, int32_t y, int32_t width, int32_t height)
+{
+}
+
+static void
+destroy_buffer(struct wl_resource *resource)
+{
+	struct wl_drm_buffer *buffer = resource->data;
+	struct wl_drm *drm = buffer->drm;
+
+	drm->callbacks->release_buffer(drm->user_data,
+				       buffer->driver_buffer);
+	free(buffer);
+}
+
+static void
+buffer_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+	wl_resource_destroy(resource, 0);
+}
+
+const static struct wl_buffer_interface drm_buffer_interface = {
+	buffer_damage,
+	buffer_destroy
+};
+
+static void
+drm_create_buffer(struct wl_client *client, struct wl_resource *resource,
+		  uint32_t id, uint32_t name, int32_t width, int32_t height,
+		  uint32_t stride, uint32_t format)
+{
+	struct wl_drm *drm = resource->data;
+	struct wl_drm_buffer *buffer;
+
+	switch (format) {
+	case WL_DRM_FORMAT_ARGB8888:
+	case WL_DRM_FORMAT_XRGB8888:
+		break;
+	default:
+		wl_resource_post_error(resource,
+				       WL_DRM_ERROR_INVALID_FORMAT,
+				       "invalid format");
+		return;
+	}
+
+	buffer = calloc(1, sizeof *buffer);
+	if (buffer == NULL) {
+		wl_resource_post_no_memory(resource);
+		return;
+	}
+
+	buffer->drm = drm;
+	buffer->buffer.width = width;
+	buffer->buffer.height = height;
+	buffer->format = format;
+
+	buffer->driver_buffer =
+		drm->callbacks->reference_buffer(drm->user_data, name,
+						 width, height,
+						 stride, format);
+
+	if (buffer->driver_buffer == NULL) {
+		wl_resource_post_error(resource,
+				       WL_DRM_ERROR_INVALID_NAME,
+				       "invalid name");
+		return;
+	}
+
+	buffer->buffer.resource.object.id = id;
+	buffer->buffer.resource.object.interface = &wl_buffer_interface;
+	buffer->buffer.resource.object.implementation =
+		(void (**)(void)) &drm_buffer_interface;
+	buffer->buffer.resource.data = buffer;
+
+	buffer->buffer.resource.destroy = destroy_buffer;
+	buffer->buffer.resource.client = resource->client;
+
+	wl_client_add_resource(resource->client, &buffer->buffer.resource);
+}
+
+static void
+drm_authenticate(struct wl_client *client,
+		 struct wl_resource *resource, uint32_t id)
+{
+	struct wl_drm *drm = resource->data;
+
+	if (drm->callbacks->authenticate(drm->user_data, id) < 0)
+		wl_resource_post_error(resource,
+				       WL_DRM_ERROR_AUTHENTICATE_FAIL,
+				       "authenicate failed");
+	else
+		wl_resource_post_event(resource, WL_DRM_AUTHENTICATED);
+}
+
+const static struct wl_drm_interface drm_interface = {
+	drm_authenticate,
+	drm_create_buffer
+};
+
+static void
+bind_drm(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+	struct wl_drm *drm = data;
+	struct wl_resource *resource;
+
+	resource = wl_client_add_object(client, &wl_drm_interface,
+					&drm_interface, id, data);
+	wl_resource_post_event(resource, WL_DRM_DEVICE, drm->device_name);
+	wl_resource_post_event(resource, WL_DRM_FORMAT,
+			       WL_DRM_FORMAT_ARGB8888);
+	wl_resource_post_event(resource, WL_DRM_FORMAT,
+			       WL_DRM_FORMAT_XRGB8888);
+}
+
+struct wl_drm *
+wayland_drm_init(struct wl_display *display, char *device_name,
+                 struct wayland_drm_callbacks *callbacks, void *user_data)
+{
+	struct wl_drm *drm;
+
+	drm = malloc(sizeof *drm);
+
+	drm->display = display;
+	drm->device_name = strdup(device_name);
+	drm->callbacks = callbacks;
+	drm->user_data = user_data;
+
+	wl_display_add_global(display, &wl_drm_interface, drm, bind_drm);
+
+	return drm;
+}
+
+void
+wayland_drm_uninit(struct wl_drm *drm)
+{
+	free(drm->device_name);
+
+	/* FIXME: need wl_display_del_{object,global} */
+
+	free(drm);
+}
+
+int
+wayland_buffer_is_drm(struct wl_buffer *buffer)
+{
+	return buffer->resource.object.implementation == 
+		(void (**)(void)) &drm_buffer_interface;
+}
+
+uint32_t
+wayland_drm_buffer_get_format(struct wl_buffer *buffer_base)
+{
+	struct wl_drm_buffer *buffer = (struct wl_drm_buffer *) buffer_base;
+
+	return buffer->format;
+}
+
+void *
+wayland_drm_buffer_get_buffer(struct wl_buffer *buffer_base)
+{
+	struct wl_drm_buffer *buffer = (struct wl_drm_buffer *) buffer_base;
+
+	return buffer->driver_buffer;
+}
diff --git a/wayland/wayland-drm.h b/wayland/wayland-drm.h
new file mode 100644
index 0000000..5c25ce6
--- /dev/null
+++ b/wayland/wayland-drm.h
@@ -0,0 +1,35 @@
+#ifndef WAYLAND_DRM_H
+#define WAYLAND_DRM_H
+
+#include <wayland-server.h>
+#include "wayland-drm-server-protocol.h"
+
+struct wl_drm;
+
+struct wayland_drm_callbacks {
+	int (*authenticate)(void *user_data, uint32_t id);
+
+	void *(*reference_buffer)(void *user_data, uint32_t name,
+				  int32_t width, int32_t height,
+				  uint32_t stride, uint32_t format);
+
+	void (*release_buffer)(void *user_data, void *buffer);
+};
+
+struct wl_drm *
+wayland_drm_init(struct wl_display *display, char *device_name,
+		 struct wayland_drm_callbacks *callbacks, void *user_data);
+
+void
+wayland_drm_uninit(struct wl_drm *drm);
+
+int
+wayland_buffer_is_drm(struct wl_buffer *buffer);
+
+uint32_t
+wayland_drm_buffer_get_format(struct wl_buffer *buffer_base);
+
+void *
+wayland_drm_buffer_get_buffer(struct wl_buffer *buffer);
+
+#endif
-- 
1.7.5.4

