Initial KMS backend implementation. 77/31477/1
authorTakanari Hayama <taki@igel.co.jp>
Tue, 10 Sep 2013 06:57:12 +0000 (15:57 +0900)
committerTony SIM <chinyeow.sim.xt@renesas.com>
Fri, 5 Dec 2014 08:12:13 +0000 (16:12 +0800)
This is the initial KMS backend implementation.

Change-Id: Ie9006e52509a77f352ce1195a48483aafc4025d1
Signed-off-by: Tony SIM <chinyeow.sim.xt@renesas.com>
.gitignore
Makefile.am
backend.c
backend_kms.c [new file with mode: 0644]
configure.ac
gbm_kmsint.h [new file with mode: 0644]

index 3b7bfb9..92b75d1 100644 (file)
@@ -1,29 +1,30 @@
+autom4te.cache/*
 aclocal.m4
 aclocal.m4
-autom4te.cache
-Makefile.in
-Makefile
-.deps
-.libs
+config.*
+configure
+depcomp
+m4/*
+missing
+*/*~
+*~
 *.o
 *.lo
 *.o
 *.lo
-*.la
-libtool
-*.pc
-config.log
-config.status
-config.guess
-config.h
-config.h.in
-config.sub
-config
-configure
-install-sh
+\#*\#
+.deps
+.libs
 ltmain.sh
 ltmain.sh
-missing
 stamp-h1
 stamp-h1
-depcomp
-.cproject
-.project
-.settings
-dri2test
-dri2videotest
+install-sh
+Makefile
+*.pc
+*.la
+libtool
+Makefile.in
+
+# gnu global files
+GPATH
+GRTAGS
+GSYMS
+GTAGS
+HTML
+tags
index 9d5a459..e8e06df 100644 (file)
@@ -1,5 +1,8 @@
 lib_LTLIBRARIES = libgbm.la
 
 lib_LTLIBRARIES = libgbm.la
 
+moduledir = $(libdir)/gbm
+module_LTLIBRARIES = libgbm_kms.la
+
 libgbm_la_SOURCES =    \
        gbm.c           \
        backend.c       \
 libgbm_la_SOURCES =    \
        gbm.c           \
        backend.c       \
@@ -11,15 +14,33 @@ libgbm_la_LIBADD =  \
 libgbm_la_CFLAGS =     \
        @LIBUDEV_CFLAGS@        \
        -D_OS_UNIX=1    \
 libgbm_la_CFLAGS =     \
        @LIBUDEV_CFLAGS@        \
        -D_OS_UNIX=1    \
-       -DMODULEDIR='"$(exec_prefix)/lib/gbm"'
+       -DMODULEDIR='"$(libdir)/gbm"'
 
 libgbm_la_LDFLAGS = -version-info 1:0:0
 
 
 libgbm_la_LDFLAGS = -version-info 1:0:0
 
+libgbm_kms_la_SOURCES =        \
+       backend_kms.c
+
+libgbm_kms_la_LIBADD = \
+       @LIBKMS_LIBS@   \
+       @LIBDRM_LIBS@   \
+       @WAYLAND_KMS_LIBS@
+
+libgbm_kms_la_CFLAGS = \
+       @LIBKMS_CFLAGS@ \
+       @LIBDRM_CFLAGS@ \
+       @WAYLAND_KMS_CFLAGS@
+
+libgbm_kms_la_LDFLAGS = -version-info 1:0:0
+
 extdir = $(includedir)/gbm
 ext_HEADERS =          \
        gbm.h           \
        gbmint.h        \
 extdir = $(includedir)/gbm
 ext_HEADERS =          \
        gbm.h           \
        gbmint.h        \
-       common_drm.h
+       common_drm.h    \
+       common.h        \
+       gbm_kmsint.h
+
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = gbm.pc
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = gbm.pc
index 29d3151..37d2e7a 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -40,9 +40,7 @@
  * directory..
  */
 static const char *backends[] = {
  * directory..
  */
 static const char *backends[] = {
-      "gbm_dri.so",
-      "gbm_gallium_drm.so",
-      "gbm_pvr.so",
+      "libgbm_kms.so",
 };
 
 static const void *
 };
 
 static const void *
diff --git a/backend_kms.c b/backend_kms.c
new file mode 100644 (file)
index 0000000..a7662e4
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2013 Renesas Solutions Corp.
+ *
+ * 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:
+ *    Takanari Hayama <taki@igel.co.jp>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dlfcn.h>
+
+#include <xf86drm.h>
+#include <libkms.h>
+#include <errno.h>
+
+#include <wayland-kms.h>
+
+#include "gbmint.h"
+#include "common_drm.h"
+#include "gbm_kmsint.h"
+
+#if defined(DEBUG)
+#  define GBM_DEBUG(s, x...)   { printf(s, ## x); }
+#else
+#  define GBM_DEBUG(s, x...)   { }
+#endif
+
+/*
+ * Destroy gbm backend
+ */
+static void gbm_kms_destroy(struct gbm_device *gbm)
+{
+       free(gbm);
+}
+
+/*
+ * Check if the given format is supported
+ *
+ * Weston requires GBM_FORMAT_XRGB8888 only for now.
+ */
+static int gbm_kms_is_format_supported(struct gbm_device *gbm,
+                                      uint32_t format, uint32_t usage)
+{
+       int ret = 0;
+       switch (format) {
+               // 32bpp
+       case GBM_FORMAT_ARGB8888:
+       case GBM_FORMAT_XRGB8888:
+               ret = 1;
+       }
+
+       return ret;
+}
+
+static void gbm_kms_bo_destroy(struct gbm_bo *_bo)
+{
+       struct gbm_kms_bo *bo = (struct gbm_kms_bo*)_bo;
+
+       if (!bo)
+               return;
+
+       if (bo->addr)
+               kms_bo_unmap(bo->addr);
+
+       if (bo->bo)
+               kms_bo_destroy(&bo->bo);
+
+       free(bo);
+
+       return;
+}
+
+static struct gbm_bo *gbm_kms_bo_create(struct gbm_device *gbm,
+                                       uint32_t width, uint32_t height,
+                                       uint32_t format, uint32_t usage)
+{
+       struct gbm_kms_device *dev = (struct gbm_kms_device*)gbm;
+       struct gbm_kms_bo *bo;
+       unsigned attr[] = {
+               KMS_BO_TYPE, KMS_BO_TYPE_SCANOUT_X8R8G8B8,
+               KMS_WIDTH, 0,
+               KMS_HEIGHT, 0,
+               KMS_TERMINATE_PROP_LIST
+       };
+
+       GBM_DEBUG("%s: %s: %d\n", __FILE__, __func__, __LINE__);
+
+       if (!(bo = calloc(1, sizeof(struct gbm_kms_bo))))
+               return NULL;
+
+       switch (format) {
+               // 32bpp
+       case GBM_FORMAT_ARGB8888:
+       case GBM_FORMAT_XRGB8888:
+               break;
+       default:
+               // unsupported...
+               goto error;
+       }
+
+       if (usage & GBM_BO_USE_CURSOR_64X64)
+               attr[1] = KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8;
+       attr[3] = width;
+       attr[5] = height;
+
+       // Create BO
+       if (kms_bo_create(dev->kms, attr, &bo->bo))
+               goto error;
+
+       bo->base.gbm = gbm;
+       bo->base.width = width;
+       bo->base.height = height;
+       bo->base.format = format;
+
+       kms_bo_get_prop(bo->bo, KMS_HANDLE, &bo->base.handle.u32);
+       kms_bo_get_prop(bo->bo, KMS_PITCH, &bo->base.stride);
+
+       bo->size = bo->base.stride * bo->base.height;
+
+       // TODO: We have to export the handle.
+       // drmPrimeHandleToFd() or DRM_IOCTL_GEM_FLINK
+       {
+#if 0
+               if (drmPrimeHandleToFD(dev->base.base.fd, bo->base.handle.u32, DRM_CLOEXEC, &bo->fd)) {
+                       // export failed...anything we can do?
+                       goto error;
+               }
+#else
+               struct drm_gem_flink fl;
+               int ret;
+
+               fl.handle = bo->base.handle.u32;
+               fl.name   = 0;
+
+               ret = drmIoctl( dev->base.base.fd, DRM_IOCTL_GEM_FLINK, &fl );
+               if (ret) {
+                       GBM_DEBUG("%s: %s: DRM_IOCTL_GEM_FLINK failed. %s\n", __FILE__, __func__, strerror(errno));
+                       goto error;
+               }
+
+               bo->fd = fl.name;
+#endif
+       }
+       // Map to the user space for bo_write
+       if (usage & GBM_BO_USE_WRITE) {
+               if (kms_bo_map(bo->bo, &bo->addr))
+                       goto error;
+       }
+
+       return (struct gbm_bo*)bo;
+
+ error:
+       GBM_DEBUG("%s: %s: %d: ERROR!!!!\n", __FILE__, __func__, __LINE__);
+       gbm_kms_bo_destroy((struct gbm_bo*)bo);
+       return NULL;
+}
+
+static int gbm_kms_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
+{
+       struct gbm_kms_bo *bo = (struct gbm_kms_bo*)_bo;
+
+       if (!bo->addr)
+               return -1;
+
+       memcpy(bo->addr, buf, count);
+
+       return 0;
+}
+
+static struct gbm_bo *gbm_kms_bo_import(struct gbm_device *gbm,
+                                       uint32_t type, void *_buffer,
+                                       uint32_t usage)
+{
+       struct gbm_kms_device *dev = (struct gbm_kms_device*)gbm;
+       struct gbm_kms_bo *bo;
+       struct wl_kms_buffer *buffer;
+
+       /*
+        * We need to  import only wl_buffer for Weston, i.e. client's
+        * rendering buffer.
+        *
+        * To make gbm_kms backend to be agnostic to none-DRM/KMS as much as
+        * possible, wl_buffer that we receive must be DRM BO, nothing else.
+        * We are already kind of wayland dependent which is enough.
+        */
+       if (type != GBM_BO_IMPORT_WL_BUFFER)
+               return NULL;
+
+       if (!(buffer = wayland_kms_buffer_get((struct wl_resource*)_buffer)))
+               return NULL;
+
+       // XXX: BO handle is imported in wayland-kms.
+       if (!(bo = calloc(1, sizeof(struct gbm_kms_bo))))
+               return NULL;
+
+       bo->base.gbm = gbm;
+       bo->base.width = buffer->width;
+       bo->base.height = buffer->height;
+       bo->base.format = buffer->format;
+       bo->base.stride = buffer->stride;
+       bo->base.handle.u32 = buffer->handle;
+
+       return (struct gbm_bo*)bo;
+
+ error:
+       if (bo)
+               free(bo);
+
+       return NULL;
+}
+
+static struct gbm_surface *gbm_kms_surface_create(struct gbm_device *gbm,
+                                                 uint32_t width,
+                                                 uint32_t height,
+                                                 uint32_t format,
+                                                 uint32_t flags)
+{
+       struct gbm_kms_device *dev = (struct gbm_kms_device*)gbm;
+       struct gbm_kms_surface *surface;
+       GBM_DEBUG("%s: %s: %d\n", __FILE__, __func__, __LINE__);
+
+       if (!(surface = calloc(1, sizeof(struct gbm_kms_surface))))
+               return NULL;
+
+       surface->base.gbm = gbm;
+       surface->base.width = width;
+       surface->base.height = height;
+       surface->base.format = format;
+       surface->base.flags = flags;
+
+       /* need to map BO */
+       flags |= GBM_BO_USE_WRITE;
+       surface->bo[0] = (struct gbm_kms_bo*)gbm_kms_bo_create(gbm, width, height, format, flags);
+       surface->bo[1] = (struct gbm_kms_bo*)gbm_kms_bo_create(gbm, width, height, format, flags);
+
+       GBM_DEBUG("%s: %s: %d: created surface %dx%d\n", __FILE__, __func__, __LINE__, width, height);
+       surface->front = -1;
+
+       return (struct gbm_surface*)surface;
+}
+
+static void gbm_kms_surface_destroy(struct gbm_surface *_surface)
+{
+       struct gbm_kms_surface *surface = (struct gbm_kms_surface*)_surface;
+
+       if (!surface)
+               return;
+
+       gbm_kms_bo_destroy((struct gbm_bo*)surface->bo[0]);
+       gbm_kms_bo_destroy((struct gbm_bo*)surface->bo[1]);
+
+       free(surface);
+}
+
+static struct gbm_bo *gbm_kms_surface_lock_front_buffer(struct gbm_surface *_surface)
+{
+       struct gbm_kms_surface *surface = (struct gbm_kms_surface*)_surface;
+
+       /*
+        * Drm-compositor in the weston server relies on this API. After
+        * composing clients' surfaces with gl-renderer, drm-compositor locks
+        * the gbm_surface and queries BO attached to it with this API.
+        * Drm-compositor then sets it to DRM/KMS with drmModeAddFB() and
+        * drmModeAddFB2().
+        */
+
+       if (surface->front >= 0) {
+               struct gbm_kms_bo *front = surface->bo[surface->front];
+               front->locked = 1;
+               return (struct gbm_bo*)front;
+       }
+
+       return NULL;
+}
+
+static void gbm_kms_surface_release_buffer(struct gbm_surface *_surface, struct gbm_bo *_bo)
+{
+       struct gbm_kms_bo *bo = (struct gbm_kms_bo*)_bo;
+       bo->locked = 0;
+       return;
+}
+
+static int gbm_kms_surface_has_free_buffers(struct gbm_surface *_surface)
+{
+       struct gbm_kms_surface *surface = (struct gbm_kms_surface*)_surface;
+       return ((!surface->bo[0]->locked) || (!surface->bo[1]->locked));
+}
+
+struct gbm_device kms_gbm_device = {
+       .name = "kms",
+
+       .destroy = gbm_kms_destroy,
+       .is_format_supported = gbm_kms_is_format_supported,
+
+       .bo_create = gbm_kms_bo_create,
+       .bo_import = gbm_kms_bo_import,
+       .bo_write = gbm_kms_bo_write,
+       .bo_destroy = gbm_kms_bo_destroy,
+
+       .surface_create = gbm_kms_surface_create,
+       .surface_lock_front_buffer = gbm_kms_surface_lock_front_buffer,
+       .surface_release_buffer = gbm_kms_surface_release_buffer,
+       .surface_has_free_buffers = gbm_kms_surface_has_free_buffers,
+       .surface_destroy = gbm_kms_surface_destroy,
+};
+
+static struct gbm_device *kms_device_create(int fd)
+{
+       struct gbm_kms_device *dev;
+       int ret;
+
+       GBM_DEBUG("%s: %d\n", __func__, __LINE__);
+
+       if (!(dev = calloc(1, sizeof(struct gbm_kms_device))))
+               return NULL;
+
+       dev->base.type = GBM_DRM_DRIVER_TYPE_CUSTOM;
+
+       dev->base.base = kms_gbm_device;
+       dev->base.base.fd = fd;
+
+       if (kms_create(fd, &dev->kms)) {
+               free(dev);
+               return NULL;
+       }
+
+       return &dev->base.base;
+}
+
+/* backend loader looks for symbol "gbm_backend" */
+struct gbm_backend gbm_backend = {
+       .backend_name = "kms",
+       .create_device = kms_device_create,
+};
index a6ddfd9..6ba5f2b 100644 (file)
 # Initialize Autoconf
 AC_PREREQ([2.60])
 AC_INIT([libgbm], [1.0.0],
 # Initialize Autoconf
 AC_PREREQ([2.60])
 AC_INIT([libgbm], [1.0.0],
-        [https://bugs.freedesktop.org/enter_bug.cgi?product=wayland], [libgbm])
+        [https://bugs.freedesktop.org/enter_bug.cgi?product=Mesa], [libgbm])
 AC_CONFIG_SRCDIR([Makefile.am])
 AC_CONFIG_HEADERS([config.h])
 
 # Initialize Automake
 AM_INIT_AUTOMAKE([foreign dist-bzip2])
 AC_CONFIG_SRCDIR([Makefile.am])
 AC_CONFIG_HEADERS([config.h])
 
 # Initialize Automake
 AM_INIT_AUTOMAKE([foreign dist-bzip2])
-AM_MAINTAINER_MODE
+#AM_MAINTAINER_MODE
 
 # Initialize libtool
 AC_PROG_LIBTOOL
 
 # Obtain compiler/linker options for dependencies
 PKG_CHECK_MODULES([LIBUDEV], [libudev])
 
 # Initialize libtool
 AC_PROG_LIBTOOL
 
 # Obtain compiler/linker options for dependencies
 PKG_CHECK_MODULES([LIBUDEV], [libudev])
-PKG_CHECK_MODULES([DRM], [libdrm])
+PKG_CHECK_MODULES([LIBDRM], [libdrm])
+PKG_CHECK_MODULES([LIBKMS], [libkms])
+PKG_CHECK_MODULES([WAYLAND_KMS], [wayland-kms])
 
 AC_CONFIG_FILES([Makefile gbm.pc])
 AC_OUTPUT
 
 AC_CONFIG_FILES([Makefile gbm.pc])
 AC_OUTPUT
diff --git a/gbm_kmsint.h b/gbm_kmsint.h
new file mode 100644 (file)
index 0000000..ec84d1f
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013 Renesas Solutions Corp.
+ *
+ * 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:
+ *    Takanari Hayama <taki@igel.co.jp>
+ */
+
+#ifndef __gbm_kmsint_h__
+#define __gbm_kmsint_h__
+
+#include <libkms.h>
+
+#include "gbmint.h"
+#include "common_drm.h"
+
+struct gbm_kms_device {
+       struct gbm_drm_device base;
+       struct kms_driver *kms;
+};
+
+struct gbm_kms_bo {
+       struct gbm_bo base;
+       struct kms_bo *bo;
+       void *addr;
+       int fd;                 // FD for export
+       int locked;
+
+       int size;
+};
+
+struct gbm_kms_surface {
+       struct gbm_surface base;
+       struct gbm_kms_bo *bo[2];
+       int front;
+};
+
+/* Internal API */
+static inline struct gbm_kms_surface *gbm_kms_surface(struct gbm_surface *surface)
+{
+       return (struct gbm_kms_surface*)surface;
+}
+
+static inline void gbm_kms_set_front(struct gbm_kms_surface *surface, int front)
+{
+       surface->front = front;
+}
+
+static inline int gbm_kms_is_bo_locked(struct gbm_kms_bo *bo)
+{
+       return bo->locked;
+}
+
+#endif