From: Takanari Hayama Date: Tue, 10 Sep 2013 06:57:12 +0000 (+0900) Subject: Initial KMS backend implementation. X-Git-Tag: accepted/tizen/ivi/20150202.020103~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ce30c1e6ec2f8ae5e1099266a17ec5fe0f03472c;p=platform%2Fupstream%2Flibgbm.git Initial KMS backend implementation. This is the initial KMS backend implementation. Change-Id: Ie9006e52509a77f352ce1195a48483aafc4025d1 Signed-off-by: Tony SIM --- diff --git a/.gitignore b/.gitignore index 3b7bfb9..92b75d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,29 +1,30 @@ +autom4te.cache/* aclocal.m4 -autom4te.cache -Makefile.in -Makefile -.deps -.libs +config.* +configure +depcomp +m4/* +missing +*/*~ +*~ *.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 -missing 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 diff --git a/Makefile.am b/Makefile.am index 9d5a459..e8e06df 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,8 @@ lib_LTLIBRARIES = libgbm.la +moduledir = $(libdir)/gbm +module_LTLIBRARIES = libgbm_kms.la + libgbm_la_SOURCES = \ gbm.c \ backend.c \ @@ -11,15 +14,33 @@ libgbm_la_LIBADD = \ 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_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 \ - common_drm.h + common_drm.h \ + common.h \ + gbm_kmsint.h + pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = gbm.pc diff --git a/backend.c b/backend.c index 29d3151..37d2e7a 100644 --- a/backend.c +++ b/backend.c @@ -40,9 +40,7 @@ * directory.. */ static const char *backends[] = { - "gbm_dri.so", - "gbm_gallium_drm.so", - "gbm_pvr.so", + "libgbm_kms.so", }; static const void * diff --git a/backend_kms.c b/backend_kms.c new file mode 100644 index 0000000..a7662e4 --- /dev/null +++ b/backend_kms.c @@ -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 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#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, +}; diff --git a/configure.ac b/configure.ac index a6ddfd9..6ba5f2b 100644 --- a/configure.ac +++ b/configure.ac @@ -23,20 +23,22 @@ # 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]) -AM_MAINTAINER_MODE +#AM_MAINTAINER_MODE # 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 diff --git a/gbm_kmsint.h b/gbm_kmsint.h new file mode 100644 index 0000000..ec84d1f --- /dev/null +++ b/gbm_kmsint.h @@ -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 + */ + +#ifndef __gbm_kmsint_h__ +#define __gbm_kmsint_h__ + +#include + +#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