diff options
author | Changyeon Lee <cyeon.lee@samsung.com> | 2021-03-25 12:28:08 +0900 |
---|---|---|
committer | Changyeon Lee <cyeon.lee@samsung.com> | 2021-03-25 17:03:11 +0900 |
commit | 0dcf7c4ac7ac5d3999bb0cb6a7b9e38694370c53 (patch) | |
tree | acaecca498555a520f5eae03cd447e6ea6c1331d | |
parent | bc10080cbc70d40d63e61b51d5024985a3218168 (diff) | |
download | libtbm-msm-0dcf7c4ac7ac5d3999bb0cb6a7b9e38694370c53.tar.gz libtbm-msm-0dcf7c4ac7ac5d3999bb0cb6a7b9e38694370c53.tar.bz2 libtbm-msm-0dcf7c4ac7ac5d3999bb0cb6a7b9e38694370c53.zip |
add initial code
Change-Id: I06ac9f6c6fcd6c8e27c8770a62adec587a68e103
-rw-r--r-- | AUTHORS | 2 | ||||
-rw-r--r-- | COPYING | 21 | ||||
-rw-r--r-- | ChangeLog | 0 | ||||
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | NEWS | 0 | ||||
-rw-r--r-- | README | 0 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | autogen.sh | 12 | ||||
-rw-r--r-- | configure.ac | 64 | ||||
-rw-r--r-- | packaging/libtbm-msm.manifest | 5 | ||||
-rw-r--r-- | packaging/libtbm-msm.spec | 51 | ||||
-rw-r--r-- | src/Makefile.am | 12 | ||||
-rw-r--r-- | src/tbm_bufmgr_msm.c | 1493 |
13 files changed, 1663 insertions, 0 deletions
@@ -0,0 +1,2 @@ +SooChan Lim <sc1.lim@samsung.com> +Changyeon Lee <cyeon.lee@samsung.com> @@ -0,0 +1,21 @@ +Copyright (C) 2021 Samsung Electronics co., Ltd. All Rights Reserved. + +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, sub license, 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/ChangeLog diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..af437a6 --- /dev/null +++ b/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/README.md b/README.md new file mode 100644 index 0000000..3c9c3d3 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# libtbm-msm +TBM backend for Qualcomm GPU Adreno diff --git a/autogen.sh b/autogen.sh new file mode 100644 index 0000000..904cd67 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,12 @@ +#! /bin/sh + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +ORIGDIR=`pwd` +cd $srcdir + +autoreconf -v --install || exit 1 +cd $ORIGDIR || exit $? + +$srcdir/configure --enable-maintainer-mode "$@" diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..169c05c --- /dev/null +++ b/configure.ac @@ -0,0 +1,64 @@ +# +# 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 +# on the rights to use, copy, modify, merge, publish, distribute, sub +# license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL +# ADAM JACKSON 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. + +AC_PREREQ(2.60) +AC_INIT(libtbm-msm, 1.0.0) +AC_USE_SYSTEM_EXTENSIONS +AC_CONFIG_SRCDIR([Makefile.am]) +AM_INIT_AUTOMAKE([dist-bzip2]) + +AM_CONFIG_HEADER([config.h]) + +AC_DISABLE_STATIC +AC_PROG_LIBTOOL +AC_PROG_CC + +AC_HEADER_STDC +AC_SYS_LARGEFILE +AC_FUNC_ALLOCA + +# Enable quiet compiles on automake 1.11. +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +PKG_CHECK_MODULES(LIBDRM, libdrm) +PKG_CHECK_MODULES(LIBTBM, libtbm) +PKG_CHECK_MODULES(DLOG, dlog) +PKG_CHECK_MODULES(LIBUDEV, libudev) + +LIBTBM_MSM_CFLAGS="$LIBDRM_CFLAGS $LIBTBM_CFLAGS $DLOG_CFLAGS $LIBUDEV_CFLAGS " +LIBTBM_MSM_LIBS="$LIBDRM_LIBS $LIBTBM_LIBS $DLOG_LIBS $LIBUDEV_LIBS " + +AC_SUBST(LIBTBM_MSM_CFLAGS) +AC_SUBST(LIBTBM_MSM_LIBS) + +bufmgr_dir=${libdir#*/} +AC_SUBST(bufmgr_dir) + +AC_OUTPUT([ + Makefile + src/Makefile]) + +echo "" +echo "CFLAGS : $CFLAGS" +echo "LDFLAGS : $LDFLAGS" +echo "LIBTBM_MSM_CFLAGS : $LIBTBM_MSM_CFLAGS" +echo "LIBTBM_MSM_LIBS : $LIBTBM_MSM_LIBS" +echo "bufmgr_dir : $bufmgr_dir" +echo "" + diff --git a/packaging/libtbm-msm.manifest b/packaging/libtbm-msm.manifest new file mode 100644 index 0000000..97e8c31 --- /dev/null +++ b/packaging/libtbm-msm.manifest @@ -0,0 +1,5 @@ +<manifest> + <request> + <domain name="_"/> + </request> +</manifest> diff --git a/packaging/libtbm-msm.spec b/packaging/libtbm-msm.spec new file mode 100644 index 0000000..29bf156 --- /dev/null +++ b/packaging/libtbm-msm.spec @@ -0,0 +1,51 @@ +Name: libtbm-msm +Version: 1.0.0 +Release: 1 +License: MIT +Summary: Tizen Buffer Manager - drm msm backend +Group: System/Libraries +ExcludeArch: i586 +Source0: %{name}-%{version}.tar.gz +Source1001: %name.manifest + +BuildRequires: pkgconfig(libdrm) +BuildRequires: pkgconfig(libtbm) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(libudev) + +%description +descriptionion: Tizen Buffer manager backend module uses drm msm + +%global TZ_SYS_RO_SHARE %{?TZ_SYS_RO_SHARE:%TZ_SYS_RO_SHARE}%{!?TZ_SYS_RO_SHARE:/usr/share} + +%prep +%setup -q +cp %{SOURCE1001} . + +%build + +%reconfigure --prefix=%{_prefix} --libdir=%{_libdir}/bufmgr \ + CFLAGS="${CFLAGS} -Wall -Werror" LDFLAGS="${LDFLAGS} -Wl,--hash-style=both -Wl,--as-needed" + +make %{?_smp_mflags} + +%install +rm -rf %{buildroot} +%make_install + + +%post +if [ -f %{_libdir}/bufmgr/libtbm_default.so ]; then + rm -rf %{_libdir}/bufmgr/libtbm_default.so +fi +ln -s libtbm_msm.so %{_libdir}/bufmgr/libtbm_default.so + +%postun -p /sbin/ldconfig + +%files +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license COPYING +%{_libdir}/bufmgr/libtbm_*.so* + + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..8c91b09 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,12 @@ +AM_CFLAGS = \ + @LIBTBM_MSM_CFLAGS@ \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src \ + -I/usr/include/drm + +libtbm_msm_la_LTLIBRARIES = libtbm_msm.la +libtbm_msm_ladir = /${bufmgr_dir} +libtbm_msm_la_LIBADD = @LIBTBM_MSM_LIBS@ + +libtbm_msm_la_SOURCES = \ + tbm_bufmgr_msm.c diff --git a/src/tbm_bufmgr_msm.c b/src/tbm_bufmgr_msm.c new file mode 100644 index 0000000..506673b --- /dev/null +++ b/src/tbm_bufmgr_msm.c @@ -0,0 +1,1493 @@ +/************************************************************************** + +libtbm_msm + +Copyright 2021 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@samsung.com>, + Junkyeong Kim <jk0430.kim@samsung.com>, + Changyeon Lee <cyeon.lee@samsung.com> + +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, sub license, 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <libudev.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <xf86drm.h> +#include <pthread.h> +#include <tbm_backend.h> +#include <tbm_drm_helper.h> +#include <tbm_log.h> +#include <msm_drm.h> + +#define TBM_COLOR_FORMAT_COUNT 4 + +#define SIZE_ALIGN(value, base) (((value) + ((base) - 1)) & ~((base) - 1)) + +#define TBM_SURFACE_ALIGNMENT_PLANE (64) +#define TBM_SURFACE_ALIGNMENT_PITCH_RGB (128) +#define TBM_SURFACE_ALIGNMENT_PITCH_YUV (16) + +typedef struct _tbm_bufmgr_msm *tbm_bufmgr_msm; +typedef struct _tbm_bo_msm *tbm_bo_msm; + +/* tbm buffor object for msm */ +struct _tbm_bo_msm { + int fd; + + unsigned int name; /* FLINK ID */ + + unsigned int gem; /* GEM Handle */ + + int dmabuf; /* fd for dmabuf */ + + void *pBase; /* virtual address */ + + unsigned int size; + + unsigned int flags_msm; + unsigned int flags_tbm; + + pthread_mutex_t mutex; + int device; + int opt; + + tbm_bufmgr_msm bufmgr_msm; +}; + +/* tbm bufmgr private for msm */ +struct _tbm_bufmgr_msm { + int fd; + void* hashBos; + + char *device_name; + void *bind_display; + + tbm_backend_bufmgr_func *bufmgr_func; + tbm_backend_bo_func *bo_func; + + tbm_bufmgr bufmgr; +}; + +char *STR_DEVICE[] = { + "DEF", + "CPU", + "2D", + "3D", + "MM" +}; + +char *STR_OPT[] = { + "NONE", + "RD", + "WR", + "RDWR" +}; + +uint32_t tbm_msm_color_format_list[TBM_COLOR_FORMAT_COUNT] = { + TBM_FORMAT_ARGB8888, + TBM_FORMAT_XRGB8888, + TBM_FORMAT_NV12, + TBM_FORMAT_YUV420 + }; + + +static int +_tbm_msm_open_drm() +{ + struct udev *udev = NULL; + struct udev_enumerate *e = NULL; + struct udev_list_entry *entry = NULL; + struct udev_device *device = NULL, *drm_device = NULL, *pci = NULL; + const char *filepath, *id; + struct stat s; + int fd = -1; + int ret; + + udev = udev_new(); + if (!udev) { + TBM_ERR("udev_new() failed.\n"); + return -1; + } + + e = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(e, "drm"); + udev_enumerate_add_match_sysname(e, "card[0-9]*"); + udev_enumerate_scan_devices(e); + + drm_device = NULL; + udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) { + filepath = udev_list_entry_get_name(entry); + device = udev_device_new_from_syspath(udev, filepath); + if (!device) + continue; + + pci = udev_device_get_parent_with_subsystem_devtype(device, "pci", NULL); + if (pci) { + id = udev_device_get_sysattr_value(pci, "boot_vga"); + if (id && !strcmp(id, "1")) { + if (drm_device) + udev_device_unref(drm_device); + drm_device = device; + break; + } + } + + if (!drm_device) + drm_device = device; + else + udev_device_unref(device); + } + + udev_enumerate_unref(e); + + /* Get device file path. */ + filepath = udev_device_get_devnode(drm_device); + if (!filepath) { + TBM_ERR("udev_device_get_devnode() failed.\n"); + udev_device_unref(drm_device); + udev_unref(udev); + return -1; + } + + /* Open DRM device file and check validity. */ + fd = open(filepath, O_RDWR | O_CLOEXEC); + if (fd < 0) { + TBM_ERR("open(%s, O_RDWR | O_CLOEXEC) failed.\n"); + udev_device_unref(drm_device); + udev_unref(udev); + return -1; + } + + ret = fstat(fd, &s); + if (ret) { + TBM_ERR("fstat() failed %s.\n"); + close(fd); + udev_device_unref(drm_device); + udev_unref(udev); + return -1; + } + + udev_device_unref(drm_device); + udev_unref(udev); + + return fd; +} + +static unsigned int +_get_msm_flag_from_tbm(unsigned int ftbm) +{ + unsigned int flags = 0; + + if (ftbm & TBM_BO_SCANOUT) + flags |= MSM_BO_SCANOUT; + + if (ftbm & TBM_BO_NONCACHABLE) + flags |= MSM_BO_UNCACHED; + else + flags |= MSM_BO_WC; // freedreno use WC by default + + return flags; +} + +static unsigned int +_get_tbm_flag_from_msm(unsigned int fmsm) +{ + unsigned int flags = 0; + + if (fmsm & MSM_BO_SCANOUT) + flags |= TBM_BO_SCANOUT; + + if (fmsm & MSM_BO_UNCACHED) + flags |= TBM_BO_NONCACHABLE; + + return flags; +} + +static unsigned int +_get_msm_access_op_from_tbm(unsigned int tbm_op) +{ + unsigned int op = 0; + + if (tbm_op & TBM_OPTION_READ) + op |= MSM_PREP_READ; + + if (tbm_op & TBM_OPTION_WRITE) + op |= MSM_PREP_WRITE; + + return op; +} + +static unsigned int +_get_name(int fd, unsigned int gem) +{ + struct drm_gem_flink arg = {0, }; + + arg.handle = gem; + + if (drmIoctl(fd, DRM_IOCTL_GEM_FLINK, &arg)) { + TBM_ERR("fail to DRM_IOCTL_GEM_FLINK gem:%d (%m)", gem); + return 0; + } + + return (unsigned int)arg.name; +} + +static int +_get_dmabuf_fd(int fd, unsigned int gem) +{ + struct drm_prime_handle arg = {0, }; + + arg.handle = gem; + + if (drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg)) { + TBM_ERR("fail to DRM_IOCTL_PRIME_HANDLE_TO_FD gem:%d (%m)", gem); + return -1; + } + + return arg.fd; +} + +static tbm_bo_handle +_msm_bo_handle(tbm_bo_msm bo_msm, int device) +{ + tbm_bo_handle bo_handle; + + memset(&bo_handle, 0x0, sizeof(uint64_t)); + + switch (device) { + case TBM_DEVICE_DEFAULT: + case TBM_DEVICE_2D: + bo_handle.u32 = (uint32_t)bo_msm->gem; + break; + case TBM_DEVICE_CPU: + if (!bo_msm->pBase) { + void *map = NULL; + + struct drm_msm_gem_info arg = {0, }; + + arg.handle = bo_msm->gem; + + if (drmCommandWriteRead(bo_msm->fd, DRM_MSM_GEM_INFO, &arg, sizeof(arg))) { + TBM_ERR("fail to DRM_MSM_GEM_INFO gem:%d (%m)", bo_msm->gem); + return (tbm_bo_handle) NULL; + } + + map = mmap(NULL, bo_msm->size, PROT_READ|PROT_WRITE, MAP_SHARED, + bo_msm->fd, arg.offset); + if (map == MAP_FAILED) { + TBM_ERR("Cannot usrptr gem:%d", bo_msm->gem); + return (tbm_bo_handle) NULL; + } + bo_msm->pBase = map; + } + bo_handle.ptr = (void *)bo_msm->pBase; + break; + case TBM_DEVICE_3D: + bo_handle.u32 = (uint32_t)bo_msm->dmabuf; + break; + case TBM_DEVICE_MM: + bo_handle.u32 = (uint32_t)bo_msm->dmabuf; + break; + default: + TBM_ERR("Not supported device:%d", device); + bo_handle.ptr = (void *) NULL; + break; + } + + return bo_handle; +} + +static tbm_bufmgr_capability +tbm_msm_bufmgr_get_capabilities(tbm_backend_bufmgr_data *bufmgr_data, tbm_error_e *error) +{ + tbm_bufmgr_capability capabilities = TBM_BUFMGR_CAPABILITY_NONE; + + capabilities = TBM_BUFMGR_CAPABILITY_SHARE_KEY|TBM_BUFMGR_CAPABILITY_SHARE_FD; + + if (error) + *error = TBM_ERROR_NONE; + + return capabilities; +} + +static tbm_error_e +tbm_msm_bufmgr_bind_native_display(tbm_backend_bufmgr_data *bufmgr_data, tbm_native_display *native_display) +{ + tbm_bufmgr_msm bufmgr_msm = (tbm_bufmgr_msm)bufmgr_data; + TBM_RETURN_VAL_IF_FAIL(bufmgr_msm != NULL, TBM_ERROR_INVALID_PARAMETER); + + if (!tbm_drm_helper_wl_auth_server_init(native_display, bufmgr_msm->fd, + bufmgr_msm->device_name, 0)) { + TBM_ERR("fail to tbm_drm_helper_wl_server_init"); + return TBM_ERROR_INVALID_OPERATION; + } + + bufmgr_msm->bind_display = native_display; + + return TBM_ERROR_NONE; +} + +static tbm_error_e +tbm_msm_bufmgr_get_supported_formats(tbm_backend_bufmgr_data *bufmgr_data, + uint32_t **formats, uint32_t *num) +{ + tbm_bufmgr_msm bufmgr_msm = (tbm_bufmgr_msm)bufmgr_data; + uint32_t *color_formats; + + TBM_RETURN_VAL_IF_FAIL(bufmgr_msm != NULL, TBM_ERROR_INVALID_PARAMETER); + + color_formats = (uint32_t *)calloc(1, sizeof(uint32_t) * TBM_COLOR_FORMAT_COUNT); + if (color_formats == NULL) + return TBM_ERROR_OUT_OF_MEMORY; + + memcpy(color_formats, tbm_msm_color_format_list, sizeof(uint32_t)*TBM_COLOR_FORMAT_COUNT); + + *formats = color_formats; + *num = TBM_COLOR_FORMAT_COUNT; + + TBM_DBG("supported format count = %d", *num); + + return TBM_ERROR_NONE; +} + +static tbm_error_e +tbm_msm_bufmgr_get_plane_data(tbm_backend_bufmgr_data *bufmgr_data, + tbm_format format, int plane_idx, int width, + int height, uint32_t *size, uint32_t *offset, + uint32_t *pitch, int *bo_idx) +{ + tbm_bufmgr_msm bufmgr_msm = (tbm_bufmgr_msm)bufmgr_data; + int bpp; + int _offset = 0; + int _pitch = 0; + int _size = 0; + int _bo_idx = 0; + + TBM_RETURN_VAL_IF_FAIL(bufmgr_msm != NULL, TBM_ERROR_INVALID_PARAMETER); + + switch (format) { + /* 16 bpp RGB */ + case TBM_FORMAT_XRGB4444: + case TBM_FORMAT_XBGR4444: + case TBM_FORMAT_RGBX4444: + case TBM_FORMAT_BGRX4444: + case TBM_FORMAT_ARGB4444: + case TBM_FORMAT_ABGR4444: + case TBM_FORMAT_RGBA4444: + case TBM_FORMAT_BGRA4444: + case TBM_FORMAT_XRGB1555: + case TBM_FORMAT_XBGR1555: + case TBM_FORMAT_RGBX5551: + case TBM_FORMAT_BGRX5551: + case TBM_FORMAT_ARGB1555: + case TBM_FORMAT_ABGR1555: + case TBM_FORMAT_RGBA5551: + case TBM_FORMAT_BGRA5551: + case TBM_FORMAT_RGB565: + bpp = 16; + _offset = 0; + _pitch = SIZE_ALIGN((width * bpp)>>3, TBM_SURFACE_ALIGNMENT_PITCH_RGB); + _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + break; + /* 24 bpp RGB */ + case TBM_FORMAT_RGB888: + case TBM_FORMAT_BGR888: + bpp = 24; + _offset = 0; + _pitch = SIZE_ALIGN((width * bpp)>>3, TBM_SURFACE_ALIGNMENT_PITCH_RGB); + _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + break; + /* 32 bpp RGB */ + case TBM_FORMAT_XRGB8888: + case TBM_FORMAT_XBGR8888: + case TBM_FORMAT_RGBX8888: + case TBM_FORMAT_BGRX8888: + case TBM_FORMAT_ARGB8888: + case TBM_FORMAT_ABGR8888: + case TBM_FORMAT_RGBA8888: + case TBM_FORMAT_BGRA8888: + bpp = 32; + _offset = 0; + _pitch = SIZE_ALIGN((width * bpp)>>3, TBM_SURFACE_ALIGNMENT_PITCH_RGB); + _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + break; + + /* packed YCbCr */ + case TBM_FORMAT_YUYV: + case TBM_FORMAT_YVYU: + case TBM_FORMAT_UYVY: + case TBM_FORMAT_VYUY: + case TBM_FORMAT_AYUV: + bpp = 32; + _offset = 0; + _pitch = SIZE_ALIGN((width * bpp)>>3, TBM_SURFACE_ALIGNMENT_PITCH_YUV); + _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + break; + + /* + * 2 plane YCbCr + * index 0 = Y plane, [7:0] Y + * index 1 = Cr:Cb plane, [15:0] Cr:Cb little endian + * or + * index 1 = Cb:Cr plane, [15:0] Cb:Cr little endian + */ + case TBM_FORMAT_NV12: + case TBM_FORMAT_NV21: + bpp = 12; + //if (plane_idx == 0) + { + _offset = 0; + _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV); + _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + if (plane_idx == 0) + break; + } + //else if (plane_idx == 1) + { + _offset += _size; + _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV); + _size = SIZE_ALIGN(_pitch * (height / 2), TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + } + break; + case TBM_FORMAT_NV16: + case TBM_FORMAT_NV61: + bpp = 16; + //if (plane_idx == 0) + { + _offset = 0; + _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV); + _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + if (plane_idx == 0) + break; + } + //else if (plane_idx == 1) + { + _offset += _size; + _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV); + _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + } + break; + + /* + * 3 plane YCbCr + * index 0: Y plane, [7:0] Y + * index 1: Cb plane, [7:0] Cb + * index 2: Cr plane, [7:0] Cr + * or + * index 1: Cr plane, [7:0] Cr + * index 2: Cb plane, [7:0] Cb + */ + /* + NATIVE_BUFFER_FORMAT_YV12 + NATIVE_BUFFER_FORMAT_I420 + */ + case TBM_FORMAT_YUV410: + case TBM_FORMAT_YVU410: + bpp = 9; + break; + case TBM_FORMAT_YUV411: + case TBM_FORMAT_YVU411: + case TBM_FORMAT_YUV420: + case TBM_FORMAT_YVU420: + bpp = 12; + //if (plane_idx == 0) + { + _offset = 0; + _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV); + _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + if (plane_idx == 0) + break; + } + //else if (plane_idx == 1) + { + _offset += _size; + _pitch = SIZE_ALIGN(width/2, TBM_SURFACE_ALIGNMENT_PITCH_YUV/2); + _size = SIZE_ALIGN(_pitch * (height / 2), TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + if (plane_idx == 1) + break; + } + //else if (plane_idx == 2) + { + _offset += _size; + _pitch = SIZE_ALIGN(width/2, TBM_SURFACE_ALIGNMENT_PITCH_YUV/2); + _size = SIZE_ALIGN(_pitch * (height / 2), TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + } + break; + case TBM_FORMAT_YUV422: + case TBM_FORMAT_YVU422: + bpp = 16; + //if (plane_idx == 0) + { + _offset = 0; + _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV); + _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + if (plane_idx == 0) + break; + } + //else if (plane_idx == 1) + { + _offset += _size; + _pitch = SIZE_ALIGN(width/2, TBM_SURFACE_ALIGNMENT_PITCH_YUV/2); + _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + if (plane_idx == 1) + break; + } + //else if (plane_idx == 2) + { + _offset += _size; + _pitch = SIZE_ALIGN(width/2, TBM_SURFACE_ALIGNMENT_PITCH_YUV/2); + _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + } + break; + case TBM_FORMAT_YUV444: + case TBM_FORMAT_YVU444: + bpp = 24; + //if (plane_idx == 0) + { + _offset = 0; + _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV); + _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + if (plane_idx == 0) + break; + } + //else if (plane_idx == 1) + { + _offset += _size; + _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV); + _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + if (plane_idx == 1) + break; + } + //else if (plane_idx == 2) + { + _offset += _size; + _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV); + _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE); + _bo_idx = 0; + } + break; + default: + bpp = 0; + break; + } + + *size = _size; + *offset = _offset; + *pitch = _pitch; + *bo_idx = _bo_idx; + + return TBM_ERROR_NONE; +} + +static tbm_backend_bo_data * +tbm_msm_bufmgr_alloc_bo(tbm_backend_bufmgr_data *bufmgr_data, unsigned int size, + tbm_bo_memory_type flags, tbm_error_e *error) +{ + tbm_bufmgr_msm bufmgr_msm = (tbm_bufmgr_msm)bufmgr_data; + tbm_bo_msm bo_msm; + unsigned int msm_flags; + + if (bufmgr_msm == NULL) { + TBM_ERR("bufmgr_data is null\n"); + if (error) + *error = TBM_ERROR_INVALID_PARAMETER; + return NULL; + } + + bo_msm = calloc(1, sizeof(struct _tbm_bo_msm)); + if (!bo_msm) { + TBM_ERR("fail to allocate the bo_msm private\n"); + if (error) + *error = TBM_ERROR_OUT_OF_MEMORY; + return NULL; + } + + bo_msm->bufmgr_msm = bufmgr_msm; + + msm_flags = _get_msm_flag_from_tbm(flags); + + struct drm_msm_gem_new arg = {0 ,}; + + arg.size = size; + arg.flags = msm_flags; + + if (drmCommandWriteRead(bufmgr_msm->fd, DRM_MSM_GEM_NEW, &arg, sizeof(arg))) { + TBM_ERR("Cannot create bo_msm(flag:%x, size:%d) (%m)", arg.flags, (unsigned int)size); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + goto fail; + } + + bo_msm->fd = bufmgr_msm->fd; + bo_msm->gem = arg.handle; + bo_msm->size = arg.size; + bo_msm->flags_tbm = flags; + bo_msm->flags_msm = msm_flags; + + bo_msm->name = _get_name(bo_msm->fd, bo_msm->gem); + if (!bo_msm->name) { + TBM_ERR("Cannot get name bo_msm:%p", bo_msm); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + goto fail; + } + + bo_msm->dmabuf = _get_dmabuf_fd(bo_msm->fd, bo_msm->gem); + if (bo_msm->dmabuf < 0) { + TBM_ERR("Cannot get fd bo_msm:%p", bo_msm); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + goto fail; + } + + pthread_mutex_init(&bo_msm->mutex, NULL); + + /* add bo to hash */ + if (drmHashInsert(bufmgr_msm->hashBos, bo_msm->name, (void *)bo_msm) < 0) + TBM_ERR("error Cannot insert bo to Hash(%d)", bo_msm->name); + + TBM_DBG(" bo_msm:%p, gem:%d(%d), flags:%d(%d), size:%d", + bo_msm, + bo_msm->gem, bo_msm->name, + bo_msm->flags_tbm, + bo_msm->size); + + if (error) + *error = TBM_ERROR_NONE; + + return (tbm_backend_bo_data *)bo_msm; + +fail: + if (bo_msm && bo_msm->gem) { + struct drm_gem_close close_arg = {0 ,}; + + close_arg.handle = bo_msm->gem; + + drmIoctl(bufmgr_msm->fd, DRM_IOCTL_GEM_CLOSE, &close_arg); + } + + if (bo_msm) free(bo_msm); + + return NULL; +} + +static tbm_backend_bo_data * +tbm_msm_bufmgr_import_fd(tbm_backend_bufmgr_data *bufmgr_data, tbm_fd key, tbm_error_e *error) +{ + tbm_bufmgr_msm bufmgr_msm = (tbm_bufmgr_msm)bufmgr_data; + tbm_bo_msm bo_msm; + unsigned int gem = 0; + unsigned int name; + int ret; + unsigned int real_size = -1; + + if (bufmgr_msm == NULL) { + TBM_ERR("bufmgr_data is null\n"); + if (error) + *error = TBM_ERROR_INVALID_PARAMETER; + return NULL; + } + + //getting handle from fd + struct drm_prime_handle arg = {0 ,}; + + arg.fd = key; + arg.flags = 0; + + if (drmIoctl(bufmgr_msm->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &arg)) { + TBM_ERR("Cannot get gem handle from fd:%d (%m)", arg.fd); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + return NULL; + } + gem = arg.handle; + + name = _get_name(bufmgr_msm->fd, gem); + if (name == 0) { + TBM_ERR("Cannot get name from gem:%d, fd:%d (%m)", gem, key); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + return NULL; + } + + ret = drmHashLookup(bufmgr_msm->hashBos, name, (void **)&bo_msm); + if (ret == 0) { + if (gem == bo_msm->gem) { + if (error) + *error = TBM_ERROR_NONE; + return bo_msm; + } + } + + /* Determine size of bo. The fd-to-handle ioctl really should + * return the size, but it doesn't. If we have kernel 3.12 or + * later, we can lseek on the prime fd to get the size. Older + * kernels will just fail, in which case we fall back to the + * provided (estimated or guess size). */ + real_size = lseek(key, 0, SEEK_END); + + struct drm_gem_open open_arg = {0, }; + + open_arg.name = name; + + /* Open the same GEM object only for finding out its size */ + if (drmIoctl(bufmgr_msm->fd, DRM_IOCTL_GEM_OPEN, &open_arg)) { + TBM_ERR("Cannot get gem info from gem:%d, fd:%d (%m)", gem, key); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + return NULL; + } + + /* Free gem handle to avoid a memory leak*/ + struct drm_gem_close gem_close = {0, }; + + gem_close.handle = open_arg.handle; + if (drmIoctl(bufmgr_msm->fd, DRM_IOCTL_GEM_CLOSE, &gem_close)) { + TBM_ERR("Cannot close gem_handle. gem:%d (%m)", open_arg.handle); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + return NULL; + } + + if (real_size == -1) + real_size = open_arg.size; + + bo_msm = calloc(1, sizeof(struct _tbm_bo_msm)); + if (!bo_msm) { + TBM_ERR("bo_msm:%p fail to allocate the bo_msm", bo_msm); + if (error) + *error = TBM_ERROR_OUT_OF_MEMORY; + return NULL; + } + + bo_msm->bufmgr_msm = bufmgr_msm; + bo_msm->fd = bufmgr_msm->fd; + bo_msm->gem = gem; + bo_msm->size = real_size; + bo_msm->flags_msm = 0; + bo_msm->flags_tbm = _get_tbm_flag_from_msm(bo_msm->flags_msm); + bo_msm->name = name; + bo_msm->dmabuf = _get_dmabuf_fd(bo_msm->fd, bo_msm->gem); + if (bo_msm->dmabuf < 0) { + TBM_ERR("Cannot get fd bo_msm:%p", bo_msm); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + goto fail; + } + + /* add bo_msm to hash */ + if (drmHashInsert(bufmgr_msm->hashBos, bo_msm->name, (void *)bo_msm) < 0) + TBM_ERR("bo_msm:%p Cannot insert bo_msm to Hash(%d) from gem:%d, fd:%d", + bo_msm, bo_msm->name, gem, key); + + TBM_DBG(" bo_msm:%p, gem:%d(%d), fd:%d, key_fd:%d, flags:%d, size:%d", + bo_msm, + bo_msm->gem, bo_msm->name, + bo_msm->dmabuf, + key, + bo_msm->flags_tbm, + bo_msm->size); + + if (error) + *error = TBM_ERROR_NONE; + + return (tbm_backend_bo_data *)bo_msm; + +fail: + if (bo_msm && bo_msm->gem) { + struct drm_gem_close close_arg = {0, }; + + close_arg.handle = bo_msm->gem; + + drmIoctl(bufmgr_msm->fd, DRM_IOCTL_GEM_CLOSE, &close_arg); + } + + if (bo_msm) free(bo_msm); + + return NULL; +} + +static tbm_backend_bo_data * +tbm_msm_bufmgr_import_key(tbm_backend_bufmgr_data *bufmgr_data, tbm_key key, tbm_error_e *error) +{ + tbm_bufmgr_msm bufmgr_msm = (tbm_bufmgr_msm)bufmgr_data; + tbm_bo_msm bo_msm; + int ret; + + if (bufmgr_msm == NULL) { + TBM_ERR("bufmgr_data is null\n"); + if (error) + *error = TBM_ERROR_INVALID_PARAMETER; + return NULL; + } + + ret = drmHashLookup(bufmgr_msm->hashBos, key, (void **)&bo_msm); + if (ret == 0) { + if (error) + *error = TBM_ERROR_NONE; + return (tbm_backend_bo_data *)bo_msm; + } + + struct drm_gem_open arg = {0 ,}; + + arg.name = key; + + if (drmIoctl(bufmgr_msm->fd, DRM_IOCTL_GEM_OPEN, &arg)) { + TBM_ERR("Cannot open gem name:%d (%m)", key); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + return NULL; + } + + bo_msm = calloc(1, sizeof(struct _tbm_bo_msm)); + if (!bo_msm) { + TBM_ERR("fail to allocate the bo_msm private"); + if (error) + *error = TBM_ERROR_OUT_OF_MEMORY; + return NULL; + } + + bo_msm->bufmgr_msm = bufmgr_msm; + bo_msm->fd = bufmgr_msm->fd; + bo_msm->gem = arg.handle; + bo_msm->size = arg.size; + bo_msm->flags_msm = 0; + bo_msm->flags_tbm = _get_tbm_flag_from_msm(bo_msm->flags_msm); + bo_msm->name = key; + bo_msm->dmabuf = _get_dmabuf_fd(bo_msm->fd, bo_msm->gem); + if (bo_msm->dmabuf < 0) { + TBM_ERR("Cannot get fd bo_msm:%p", bo_msm); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + goto fail; + } + + /* add bo to hash */ + if (drmHashInsert(bufmgr_msm->hashBos, bo_msm->name, (void *)bo_msm) < 0) + TBM_ERR("Cannot insert bo_msm to Hash(%d)", bo_msm->name); + + TBM_DBG(" bo_msm:%p, gem:%d(%d), fd:%d, flags:%d(%d), size:%d", + bo_msm, + bo_msm->gem, bo_msm->name, + bo_msm->dmabuf, + bo_msm->flags_tbm, + bo_msm->size); + + if (error) + *error = TBM_ERROR_NONE; + + return (tbm_backend_bo_data *)bo_msm; + +fail: + if (bo_msm && bo_msm->gem) { + struct drm_gem_close close_arg = {0, }; + + close_arg.handle = bo_msm->gem; + + drmIoctl(bufmgr_msm->fd, DRM_IOCTL_GEM_CLOSE, &close_arg); + } + + if (bo_msm) free(bo_msm); + + return NULL; +} + +static void +tbm_msm_bo_free(tbm_backend_bo_data *bo_data) +{ + tbm_bo_msm bo_msm = (tbm_bo_msm)bo_data; + tbm_bo_msm temp; + tbm_bufmgr_msm bufmgr_msm; + int ret; + + if (!bo_data) + return; + + bufmgr_msm = bo_msm->bufmgr_msm; + if (!bufmgr_msm) + return; + + TBM_DBG(" bo_msm:%p, gem:%d(%d), fd:%d, size:%d", + bo_msm, + bo_msm->gem, bo_msm->name, + bo_msm->dmabuf, + bo_msm->size); + + if (bo_msm->pBase) { + if (munmap(bo_msm->pBase, bo_msm->size) == -1) { + TBM_ERR("bo_msm:%p fail to munmap (%m)", bo_msm); + } + } + + /* close dmabuf */ + if (bo_msm->dmabuf) { + close(bo_msm->dmabuf); + bo_msm->dmabuf = -1; + } + + /* delete bo from hash */ + ret = drmHashLookup(bufmgr_msm->hashBos, bo_msm->name, (void**)&temp); + if (ret == 0) + drmHashDelete(bufmgr_msm->hashBos, bo_msm->name); + else + TBM_ERR("Cannot find bo_msm to Hash(%d), ret=%d", bo_msm->name, ret); + + if (temp != bo_msm) + TBM_ERR("hashBos probably has several BOs with same name!!!"); + + /* Free gem handle */ + struct drm_gem_close arg = {0, }; + + arg.handle = bo_msm->gem; + + if (drmIoctl(bo_msm->fd, DRM_IOCTL_GEM_CLOSE, &arg)) + TBM_ERR("bo_msm:%p fail to gem close (%m)\n", bo_msm); + + free(bo_msm); +} + +static int +tbm_msm_bo_get_size(tbm_backend_bo_data *bo_data, tbm_error_e *error) +{ + tbm_bo_msm bo_msm = (tbm_bo_msm)bo_data; + + if (!bo_msm) { + if (error) + *error = TBM_ERROR_INVALID_PARAMETER; + return 0; + } + + if (error) + *error = TBM_ERROR_NONE; + + return bo_msm->size; +} + +static tbm_bo_memory_type +tbm_msm_bo_get_memory_type(tbm_backend_bo_data *bo_data, tbm_error_e *error) +{ + tbm_bo_msm bo_msm = (tbm_bo_msm)bo_data; + + if (!bo_msm) { + if (error) + *error = TBM_ERROR_INVALID_PARAMETER; + return TBM_BO_DEFAULT; + } + + if (error) + *error = TBM_ERROR_NONE; + + return bo_msm->flags_tbm; +} + +static tbm_bo_handle +tbm_msm_bo_get_handle(tbm_backend_bo_data *bo_data, tbm_bo_device_type device, tbm_error_e *error) +{ + tbm_bo_msm bo_msm = (tbm_bo_msm)bo_data; + tbm_bo_handle bo_handle; + + if (!bo_msm) { + if (error) + *error = TBM_ERROR_INVALID_PARAMETER; + return (tbm_bo_handle) NULL; + } + + if (!bo_msm->gem) { + TBM_ERR("Cannot map gem:%d", bo_msm->gem); + if (error) + *error = TBM_ERROR_INVALID_PARAMETER; + return (tbm_bo_handle) NULL; + } + + TBM_DBG("bo_msm:%p, gem:%d(%d), fd:%d, flags:%d, size:%d, %s", + bo_msm, + bo_msm->gem, bo_msm->name, + bo_msm->dmabuf, + bo_msm->flags_tbm, + bo_msm->size, + STR_DEVICE[device]); + + /*Get mapped bo_handle*/ + bo_handle = _msm_bo_handle(bo_msm, device); + if (bo_handle.ptr == NULL) { + TBM_ERR("Cannot get handle: gem:%d, device:%d\n", + bo_msm->gem, device); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + return (tbm_bo_handle) NULL; + } + + if (error) + *error = TBM_ERROR_NONE; + + return bo_handle; +} + +static tbm_bo_handle +tbm_msm_bo_map(tbm_backend_bo_data *bo_data, tbm_bo_device_type device, + tbm_bo_access_option opt, tbm_error_e *error) +{ + tbm_bo_msm bo_msm = (tbm_bo_msm)bo_data; + tbm_bo_handle bo_handle; + tbm_bufmgr_msm bufmgr_msm; + + if (!bo_msm) { + if (error) + *error = TBM_ERROR_INVALID_PARAMETER; + return (tbm_bo_handle) NULL; + } + + bufmgr_msm = bo_msm->bufmgr_msm; + if (!bufmgr_msm) { + if (error) + *error = TBM_ERROR_INVALID_PARAMETER; + return (tbm_bo_handle) NULL; + } + + if (!bo_msm->gem) { + TBM_ERR("Cannot map gem:%d", bo_msm->gem); + if (error) + *error = TBM_ERROR_INVALID_PARAMETER; + return (tbm_bo_handle) NULL; + } + + TBM_DBG(" bo_msm:%p, gem:%d(%d), fd:%d, %s, %s", + bo_msm, + bo_msm->gem, bo_msm->name, + bo_msm->dmabuf, + STR_DEVICE[device], + STR_OPT[opt]); + + /*Get mapped bo_handle*/ + bo_handle = _msm_bo_handle(bo_msm, device); + if (bo_handle.ptr == NULL) { + TBM_ERR("Cannot get handle: gem:%d, device:%d, opt:%d", + bo_msm->gem, device, opt); + if (error) + *error = TBM_ERROR_INVALID_PARAMETER; + return (tbm_bo_handle) NULL; + } + + if (error) + *error = TBM_ERROR_NONE; + + return bo_handle; +} + +static tbm_error_e +tbm_msm_bo_unmap(tbm_backend_bo_data *bo_data) +{ + tbm_bo_msm bo_msm = (tbm_bo_msm)bo_data; + tbm_bufmgr_msm bufmgr_msm; + + if (!bo_msm) + return TBM_ERROR_INVALID_PARAMETER; + + bufmgr_msm = bo_msm->bufmgr_msm; + if (!bufmgr_msm) + return TBM_ERROR_INVALID_PARAMETER; + + if (!bo_msm->gem) + return TBM_ERROR_INVALID_PARAMETER; + + TBM_DBG(" bo_msm:%p, gem:%d(%d), fd:%d", + bo_msm, + bo_msm->gem, bo_msm->name, + bo_msm->dmabuf); + + return TBM_ERROR_NONE; +} + +static tbm_error_e +tbm_msm_bo_lock(tbm_backend_bo_data *bo_data, tbm_bo_device_type device, + tbm_bo_access_option opt) +{ + tbm_bo_msm bo_msm = (tbm_bo_msm)bo_data; + + if (!bo_msm) + return TBM_ERROR_INVALID_PARAMETER; + + if (!bo_msm->gem) + return TBM_ERROR_INVALID_PARAMETER; + + if (device != TBM_DEVICE_CPU) + return TBM_ERROR_NONE; + + struct drm_msm_gem_cpu_prep arg = {0, }; + + arg.handle = bo_msm->gem; + arg.op = _get_msm_access_op_from_tbm(opt); + arg.timeout.tv_sec = 1; + arg.timeout.tv_nsec = 0; + + if (drmCommandWrite(bo_msm->fd, DRM_MSM_GEM_CPU_PREP, &arg, sizeof(arg))) { + TBM_ERR("fail to DRM_MSM_GEM_CPU_PREP gem:%d (%m)", bo_msm->gem); + return TBM_ERROR_INVALID_OPERATION; + } + + bo_msm->device = TBM_DEVICE_CPU; + + TBM_DBG(" bo_msm:%p, gem:%d(%d), fd:%d", + bo_msm, + bo_msm->gem, bo_msm->name, + bo_msm->dmabuf); + + return TBM_ERROR_NONE; +} + +static tbm_error_e +tbm_msm_bo_unlock(tbm_backend_bo_data *bo_data) +{ + tbm_bo_msm bo_msm = (tbm_bo_msm)bo_data; + + if (!bo_msm) + return TBM_ERROR_INVALID_PARAMETER; + + if (!bo_msm->gem) + return TBM_ERROR_INVALID_PARAMETER; + + if (bo_msm->device != TBM_DEVICE_CPU) + return TBM_ERROR_NONE; + + struct drm_msm_gem_cpu_fini arg = {0, }; + + arg.handle = bo_msm->gem; + + if (drmCommandWrite(bo_msm->fd, DRM_MSM_GEM_CPU_FINI, &arg, sizeof(arg))) { + TBM_ERR("fail to DRM_MSM_GEM_CPU_FINI gem:%d (%m)", bo_msm->gem); + return TBM_ERROR_INVALID_OPERATION; + } + + TBM_DBG(" bo_msm:%p, gem:%d(%d), fd:%d", + bo_msm, + bo_msm->gem, bo_msm->name, + bo_msm->dmabuf); + + return TBM_ERROR_NONE; +} + +tbm_fd +tbm_msm_bo_export_fd(tbm_backend_bo_data *bo_data, tbm_error_e *error) +{ + tbm_bo_msm bo_msm = (tbm_bo_msm)bo_data; + int fd = -1; + + if (!bo_msm) { + if (error) + *error = TBM_ERROR_INVALID_PARAMETER; + return -1; + } + + fd = _get_dmabuf_fd(bo_msm->fd, bo_msm->gem); + if (fd < 0) { + TBM_ERR("bo_msm:%p Cannot dmabuf=%d", + bo_msm, bo_msm->gem); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + return (tbm_fd)-1; + } + + TBM_DBG(" bo_msm:%p, gem:%d(%d), fd:%d, key_fd:%d, flags:%d, size:%d", + bo_msm, + bo_msm->gem, bo_msm->name, + bo_msm->dmabuf, + fd, + bo_msm->flags_tbm, + bo_msm->size); + + if (error) + *error = TBM_ERROR_NONE; + + return (tbm_fd)fd; +} + +static tbm_key +tbm_msm_bo_export_key(tbm_backend_bo_data *bo_data, tbm_error_e *error) +{ + tbm_bo_msm bo_msm = (tbm_bo_msm)bo_data; + + if (!bo_msm) { + if (error) + *error = TBM_ERROR_INVALID_PARAMETER; + return 0; + } + + TBM_DBG(" bo_msm:%p, gem:%d(%d), fd:%d, flags:%d, size:%d", + bo_msm, + bo_msm->gem, bo_msm->name, + bo_msm->dmabuf, + bo_msm->flags_tbm, + bo_msm->size); + + if (error) + *error = TBM_ERROR_NONE; + + return (tbm_key)bo_msm->name; +} + +static void +tbm_msm_deinit(tbm_backend_bufmgr_data *bufmgr_data) +{ + tbm_bufmgr_msm bufmgr_msm = (tbm_bufmgr_msm)bufmgr_data; + tbm_bufmgr bufmgr; + tbm_error_e error; + unsigned long key; + void *value; + + TBM_RETURN_IF_FAIL(bufmgr_msm != NULL); + + bufmgr = bufmgr_msm->bufmgr; + + tbm_backend_bufmgr_free_bufmgr_func(bufmgr, bufmgr_msm->bufmgr_func); + tbm_backend_bufmgr_free_bo_func(bufmgr, bufmgr_msm->bo_func); + + if (bufmgr_msm->hashBos) { + while (drmHashFirst(bufmgr_msm->hashBos, &key, &value) > 0) { + free(value); + drmHashDelete(bufmgr_msm->hashBos, key); + } + + drmHashDestroy(bufmgr_msm->hashBos); + bufmgr_msm->hashBos = NULL; + } + + if (bufmgr_msm->bind_display) + tbm_drm_helper_wl_auth_server_deinit(); + + if (bufmgr_msm->device_name) + free(bufmgr_msm->device_name); + + if (tbm_backend_bufmgr_query_display_server(bufmgr, &error)) + tbm_drm_helper_unset_tbm_master_fd(); + else + tbm_drm_helper_unset_fd(); + + close(bufmgr_msm->fd); + + free(bufmgr_msm); +} + +static tbm_backend_bufmgr_data * +tbm_msm_init(tbm_bufmgr bufmgr, tbm_error_e *error) +{ + tbm_bufmgr_msm bufmgr_msm = NULL; + tbm_backend_bufmgr_func *bufmgr_func = NULL; + tbm_backend_bo_func *bo_func = NULL; + int set_master = 0; + tbm_error_e err; + + if (!bufmgr) { + TBM_ERR("bufmgr is null."); + if (error) + *error = TBM_ERROR_INVALID_PARAMETER; + return NULL; + } + + bufmgr_msm = calloc(1, sizeof(struct _tbm_bufmgr_msm)); + if (!bufmgr_msm) { + TBM_ERR("fail to alloc bufmgr_msm!"); + if (error) + *error = TBM_ERROR_OUT_OF_MEMORY; + return NULL; + } + + /* check the master_fd which already had opened */ + bufmgr_msm->fd = tbm_drm_helper_get_master_fd(); + if (bufmgr_msm->fd < 0) { + bufmgr_msm->fd = _tbm_msm_open_drm(); + if (bufmgr_msm->fd < 0) { + TBM_ERR("fail to open drm!\n"); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + goto fail_open_drm; + } + + if (drmIsMaster(bufmgr_msm->fd)) { + tbm_drm_helper_set_tbm_master_fd(bufmgr_msm->fd); + set_master = 1; + + bufmgr_msm->device_name = drmGetDeviceNameFromFd(bufmgr_msm->fd); + if (!bufmgr_msm->device_name) { + TBM_ERR("fail to get device name!"); + tbm_drm_helper_unset_tbm_master_fd(); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + goto fail_get_device_name; + } + TBM_ERR("This is Master FD(%d) from open_drm.", bufmgr_msm->fd); + } else { + /* close the fd and get the authenticated fd from the master fd */ + close(bufmgr_msm->fd); + bufmgr_msm->fd = -1; + + /* get the authenticated drm fd from the master fd */ + if (!tbm_drm_helper_get_auth_info(&(bufmgr_msm->fd), &(bufmgr_msm->device_name), NULL)) { + TBM_ERR("fail to get auth drm info!"); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + goto fail_get_auth_info; + } + TBM_ERR("This is Authenticated FD(%d)", bufmgr_msm->fd); + } + } else { + bufmgr_msm->device_name = drmGetDeviceNameFromFd(bufmgr_msm->fd); + if (!bufmgr_msm->device_name) { + TBM_ERR("fail to get device name!"); + tbm_drm_helper_unset_tbm_master_fd(); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + goto fail_get_device_name; + } + TBM_ERR("This is Master FD from tbm_drm_helper_get_master_fd(%d)", bufmgr_msm->fd); + } + tbm_drm_helper_set_fd(bufmgr_msm->fd); + + /*Create Hash Table*/ + bufmgr_msm->hashBos = drmHashCreate(); + + /* alloc and register bufmgr_funcs */ + bufmgr_func = tbm_backend_bufmgr_alloc_bufmgr_func(bufmgr, &err); + if (!bufmgr_func) { + TBM_ERR("fail to alloc bufmgr_func! err(%d)", err); + if (error) + *error = TBM_ERROR_OUT_OF_MEMORY; + goto fail_alloc_bufmgr_func; + } + + bufmgr_func->bufmgr_get_capabilities = tbm_msm_bufmgr_get_capabilities; + bufmgr_func->bufmgr_bind_native_display = tbm_msm_bufmgr_bind_native_display; + bufmgr_func->bufmgr_get_supported_formats = tbm_msm_bufmgr_get_supported_formats; + bufmgr_func->bufmgr_get_plane_data = tbm_msm_bufmgr_get_plane_data; + bufmgr_func->bufmgr_alloc_bo = tbm_msm_bufmgr_alloc_bo; + bufmgr_func->bufmgr_alloc_bo_with_format = NULL; + bufmgr_func->bufmgr_import_fd = tbm_msm_bufmgr_import_fd; + bufmgr_func->bufmgr_import_key = tbm_msm_bufmgr_import_key; + + err = tbm_backend_bufmgr_register_bufmgr_func(bufmgr, bufmgr_func); + if (err != TBM_ERROR_NONE) { + TBM_ERR("fail to register bufmgr_func! err(%d)\n", err); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + goto fail_register_bufmgr_func; + } + bufmgr_msm->bufmgr_func = bufmgr_func; + + /* alloc and register bo_funcs */ + bo_func = tbm_backend_bufmgr_alloc_bo_func(bufmgr, &err); + if (!bo_func) { + TBM_ERR("fail to alloc bo_func! err(%d)", err); + if (error) + *error = TBM_ERROR_OUT_OF_MEMORY; + goto fail_alloc_bo_func; + } + + bo_func->bo_free = tbm_msm_bo_free; + bo_func->bo_get_size = tbm_msm_bo_get_size; + bo_func->bo_get_memory_types = tbm_msm_bo_get_memory_type; + bo_func->bo_get_handle = tbm_msm_bo_get_handle; + bo_func->bo_map = tbm_msm_bo_map; + bo_func->bo_unmap = tbm_msm_bo_unmap; + bo_func->bo_lock = tbm_msm_bo_lock; + bo_func->bo_unlock = tbm_msm_bo_unlock; + bo_func->bo_export_fd = tbm_msm_bo_export_fd; + bo_func->bo_export_key = tbm_msm_bo_export_key; + + err = tbm_backend_bufmgr_register_bo_func(bufmgr, bo_func); + if (err != TBM_ERROR_NONE) { + TBM_ERR("fail to register bo_func! err(%d)", err); + if (error) + *error = TBM_ERROR_INVALID_OPERATION; + goto fail_register_bo_func; + } + bufmgr_msm->bo_func = bo_func; + + TBM_DBG("drm_fd:%d", bufmgr_msm->fd); + + if (error) + *error = TBM_ERROR_NONE; + + bufmgr_msm->bufmgr = bufmgr; + + return (tbm_backend_bufmgr_data *)bufmgr_msm; + +fail_register_bo_func: + tbm_backend_bufmgr_free_bo_func(bufmgr, bo_func); +fail_alloc_bo_func: +fail_register_bufmgr_func: + tbm_backend_bufmgr_free_bufmgr_func(bufmgr, bufmgr_func); +fail_alloc_bufmgr_func: + if (bufmgr_msm->hashBos) + drmHashDestroy(bufmgr_msm->hashBos); + if (bufmgr_msm->device_name) + free(bufmgr_msm->device_name); +fail_get_device_name: + if (set_master) + tbm_drm_helper_unset_tbm_master_fd(); + tbm_drm_helper_unset_fd(); + if (bufmgr_msm->fd >= 0) + close(bufmgr_msm->fd); +fail_get_auth_info: +fail_open_drm: + free(bufmgr_msm); + return NULL; +} + +tbm_backend_module tbm_backend_module_data = { + "msm", + "Samsung", + TBM_BACKEND_ABI_VERSION_3_0, + tbm_msm_init, + tbm_msm_deinit +}; + |