1 /**************************************************************************
5 Copyright 2012 Samsung Electronics co., Ltd. All Rights Reserved.
7 Contact: SooChan Lim <sc1.lim@samsung.com>, Sangjin Lee <lsj119@samsung.com>
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sub license, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial portions
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
24 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 **************************************************************************/
39 #include <sys/ioctl.h>
40 #include <sys/types.h>
47 #include <tbm_bufmgr.h>
48 #include <tbm_bufmgr_backend.h>
50 #include <tbm_surface.h>
51 #include <tbm_surface_internal.h>
53 #include <tbm_drm_helper.h>
57 #define TBM_COLOR_FORMAT_COUNT 4
60 #define LOG_TAG "TBM_BACKEND"
62 static int bDebug = 0;
69 static int initialized = 0;
70 static char app_name[128];
75 /* get the application name */
76 f = fopen("/proc/self/cmdline", "r");
80 memset(app_name, 0x00, sizeof(app_name));
82 if (fgets(app_name, 100, f) == NULL) {
89 if ((slash = strrchr(app_name, '/')) != NULL)
90 memmove(app_name, slash+1, strlen(slash));
97 #define TBM_DUMB_LOG(fmt, args...) LOGE("\033[31m" "[%s]" fmt "\033[0m", target_name(), ##args)
98 #define DBG(fmt, args...) {if (bDebug&01) LOGE(fmt, ##args); }
100 #define TBM_DUMB_LOG(...)
104 #define SIZE_ALIGN(value, base) (((value) + ((base) - 1)) & ~((base) - 1))
106 #define TBM_SURFACE_ALIGNMENT_PLANE (64)
107 #define TBM_SURFACE_ALIGNMENT_PITCH_RGB (128)
108 #define TBM_SURFACE_ALIGNMENT_PITCH_YUV (16)
110 /* check condition */
111 #define DUMB_RETURN_IF_FAIL(cond) {\
113 TBM_DUMB_LOG("[%s] : '%s' failed.\n", __FUNCTION__, #cond);\
117 #define DUMB_RETURN_VAL_IF_FAIL(cond, val) {\
119 TBM_DUMB_LOG("[%s] : '%s' failed.\n", __FUNCTION__, #cond);\
124 struct dma_buf_info {
126 unsigned int fence_supported;
127 unsigned int padding;
130 #define DMA_BUF_ACCESS_READ 0x1
131 #define DMA_BUF_ACCESS_WRITE 0x2
132 #define DMA_BUF_ACCESS_DMA 0x4
133 #define DMA_BUF_ACCESS_MAX 0x8
135 #define DMA_FENCE_LIST_MAX 5
137 struct dma_buf_fence {
142 #define DMABUF_IOCTL_BASE 'F'
143 #define DMABUF_IOWR(nr, type) _IOWR(DMABUF_IOCTL_BASE, nr, type)
145 #define DMABUF_IOCTL_GET_INFO DMABUF_IOWR(0x00, struct dma_buf_info)
146 #define DMABUF_IOCTL_GET_FENCE DMABUF_IOWR(0x01, struct dma_buf_fence)
147 #define DMABUF_IOCTL_PUT_FENCE DMABUF_IOWR(0x02, struct dma_buf_fence)
149 typedef struct _tbm_bufmgr_dumb *tbm_bufmgr_dumb;
150 typedef struct _tbm_bo_dumb *tbm_bo_dumb;
152 /* tbm buffor object for dumb */
153 struct _tbm_bo_dumb {
156 unsigned int name; /* FLINK ID */
158 unsigned int gem; /* GEM Handle */
160 unsigned int dmabuf; /* fd for dmabuf */
162 void *pBase; /* virtual address */
166 unsigned int flags_dumb;
167 unsigned int flags_tbm;
169 pthread_mutex_t mutex;
170 struct dma_buf_fence dma_fence[DMA_FENCE_LIST_MAX];
175 /* tbm bufmgr private for dumb */
176 struct _tbm_bufmgr_dumb {
186 char *STR_DEVICE[] = {
202 uint32_t tbm_dumb_color_format_list[TBM_COLOR_FORMAT_COUNT] = {
213 struct udev *udev = NULL;
214 struct udev_enumerate *e = NULL;
215 struct udev_list_entry *entry = NULL;
216 struct udev_device *device = NULL, *drm_device = NULL, *pci = NULL;
217 const char *filepath, *id;
224 TBM_DUMB_LOG("udev_new() failed.\n");
228 e = udev_enumerate_new(udev);
229 udev_enumerate_add_match_subsystem(e, "drm");
230 udev_enumerate_add_match_sysname(e, "card[0-9]*");
231 udev_enumerate_scan_devices(e);
234 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
235 filepath = udev_list_entry_get_name(entry);
236 device = udev_device_new_from_syspath(udev, filepath);
240 pci = udev_device_get_parent_with_subsystem_devtype(device, "pci", NULL);
242 id = udev_device_get_sysattr_value(pci, "boot_vga");
243 if (id && !strcmp(id, "1")) {
245 udev_device_unref(drm_device);
254 udev_device_unref(device);
257 udev_enumerate_unref(e);
259 /* Get device file path. */
260 filepath = udev_device_get_devnode(drm_device);
262 TBM_DUMB_LOG("udev_device_get_devnode() failed.\n");
263 udev_device_unref(drm_device);
268 /* Open DRM device file and check validity. */
269 fd = open(filepath, O_RDWR | O_CLOEXEC);
271 TBM_DUMB_LOG("open(%s, O_RDWR | O_CLOEXEC) failed.\n");
272 udev_device_unref(drm_device);
279 TBM_DUMB_LOG("fstat() failed %s.\n");
281 udev_device_unref(drm_device);
286 udev_device_unref(drm_device);
293 _get_dumb_flag_from_tbm(unsigned int ftbm)
295 unsigned int flags = 0;
300 _get_tbm_flag_from_dumb(unsigned int fdumb)
302 unsigned int flags = 0;
304 flags |= TBM_BO_SCANOUT;
305 flags |= TBM_BO_NONCACHABLE;
311 _get_name(int fd, unsigned int gem)
313 struct drm_gem_flink arg = {0,};
316 if (drmIoctl(fd, DRM_IOCTL_GEM_FLINK, &arg)) {
317 TBM_DUMB_LOG("error fail to get flink from gem:%d (DRM_IOCTL_GEM_FLINK)\n",
322 return (unsigned int)arg.name;
326 _dumb_bo_handle(tbm_bo_dumb bo_dumb, int device)
328 tbm_bo_handle bo_handle;
329 memset(&bo_handle, 0x0, sizeof(uint64_t));
332 case TBM_DEVICE_DEFAULT:
334 bo_handle.u32 = (uint32_t)bo_dumb->gem;
337 if (!bo_dumb->pBase) {
338 struct drm_mode_map_dumb arg = {0,};
341 arg.handle = bo_dumb->gem;
342 if (drmIoctl(bo_dumb->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg)) {
343 TBM_DUMB_LOG("error Cannot map_ gem=%d\n", bo_dumb->gem);
344 return (tbm_bo_handle) NULL;
347 map = mmap(NULL, bo_dumb->size, PROT_READ|PROT_WRITE, MAP_SHARED,
348 bo_dumb->fd, arg.offset);
349 if (map == MAP_FAILED) {
350 TBM_DUMB_LOG("error Cannot usrptr gem=%d\n", bo_dumb->gem);
351 return (tbm_bo_handle) NULL;
353 bo_dumb->pBase = map;
355 bo_handle.ptr = (void *)bo_dumb->pBase;
359 if (!bo_dumb->dmabuf) {
360 struct drm_prime_handle arg = {0, };
362 arg.handle = bo_dumb->gem;
363 if (drmIoctl(bo_dumb->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg)) {
364 TBM_DUMB_LOG("error Cannot dmabuf=%d\n", bo_dumb->gem);
365 return (tbm_bo_handle) NULL;
367 bo_dumb->dmabuf = arg.fd;
370 bo_handle.u32 = (uint32_t)bo_dumb->dmabuf;
374 if (!bo_dumb->dmabuf) {
375 struct drm_prime_handle arg = {0, };
377 arg.handle = bo_dumb->gem;
378 if (drmIoctl(bo_dumb->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg)) {
379 TBM_DUMB_LOG("error Cannot dmabuf=%d\n", bo_dumb->gem);
380 return (tbm_bo_handle) NULL;
382 bo_dumb->dmabuf = arg.fd;
385 bo_handle.u32 = (uint32_t)bo_dumb->dmabuf;
388 TBM_DUMB_LOG("error Not supported device:%d\n", device);
389 bo_handle.ptr = (void *) NULL;
398 _dumb_cache_flush(int fd, tbm_bo_dumb bo_dumb, int flags)
400 TBM_DUMB_LOG("warning fail to flush the cache.\n");
406 tbm_dumb_bo_size(tbm_bo bo)
408 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
412 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
414 return bo_dumb->size;
418 tbm_dumb_bo_alloc(tbm_bo bo, int size, int flags)
420 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
423 tbm_bufmgr_dumb bufmgr_dumb;
424 unsigned int dumb_flags;
426 bufmgr_dumb = (tbm_bufmgr_dumb)tbm_backend_get_bufmgr_priv(bo);
427 DUMB_RETURN_VAL_IF_FAIL(bufmgr_dumb != NULL, 0);
429 bo_dumb = calloc(1, sizeof(struct _tbm_bo_dumb));
431 TBM_DUMB_LOG("error fail to allocate the bo private\n");
435 dumb_flags = _get_dumb_flag_from_tbm(flags);
437 struct drm_mode_create_dumb arg = {0, };
438 //as we know only size for new bo set height=1 and bpp=8 and in this case
439 //width will by equal to size in bytes;
443 arg.flags = dumb_flags;
444 if (drmIoctl(bufmgr_dumb->fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg)) {
445 TBM_DUMB_LOG("error Cannot create bo(flag:%x, size:%d)\n", arg.flags, (unsigned int)size);
450 bo_dumb->fd = bufmgr_dumb->fd;
451 bo_dumb->gem = arg.handle;
452 bo_dumb->size = arg.size;
453 bo_dumb->flags_tbm = flags;
454 bo_dumb->flags_dumb = dumb_flags;
455 bo_dumb->name = _get_name(bo_dumb->fd, bo_dumb->gem);
457 pthread_mutex_init(&bo_dumb->mutex, NULL);
459 if (bufmgr_dumb->use_dma_fence
460 && !bo_dumb->dmabuf) {
461 struct drm_prime_handle arg = {0, };
463 arg.handle = bo_dumb->gem;
464 if (drmIoctl(bo_dumb->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg)) {
465 TBM_DUMB_LOG("error Cannot dmabuf=%d\n", bo_dumb->gem);
469 bo_dumb->dmabuf = arg.fd;
473 if (drmHashInsert(bufmgr_dumb->hashBos, bo_dumb->name, (void *)bo_dumb) < 0)
474 TBM_DUMB_LOG("error Cannot insert bo to Hash(%d)\n", bo_dumb->name);
476 DBG(" [%s] bo:%p, gem:%d(%d), flags:%d(%d), size:%d\n", target_name(),
478 bo_dumb->gem, bo_dumb->name,
482 return (void *)bo_dumb;
486 tbm_dumb_bo_free(tbm_bo bo)
489 tbm_bufmgr_dumb bufmgr_dumb;
494 bufmgr_dumb = (tbm_bufmgr_dumb)tbm_backend_get_bufmgr_priv(bo);
495 DUMB_RETURN_IF_FAIL(bufmgr_dumb != NULL);
497 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
498 DUMB_RETURN_IF_FAIL(bo_dumb != NULL);
500 DBG(" [%s] bo:%p, gem:%d(%d), fd:%d, size:%d\n", target_name(),
502 bo_dumb->gem, bo_dumb->name,
506 if (bo_dumb->pBase) {
507 if (munmap(bo_dumb->pBase, bo_dumb->size) == -1) {
508 TBM_DUMB_LOG("error bo:%p fail to munmap(%s)\n",
509 bo, strerror(errno));
514 if (bo_dumb->dmabuf) {
515 close(bo_dumb->dmabuf);
519 /* delete bo from hash */
522 ret = drmHashLookup(bufmgr_dumb->hashBos, bo_dumb->name, (void**)&bo_dumb);
524 drmHashDelete(bufmgr_dumb->hashBos, bo_dumb->name);
526 TBM_DUMB_LOG("warning Cannot find bo to Hash(%d), ret =%d\n", bo_dumb->name, ret);
528 /* Free gem handle */
529 struct drm_gem_close arg = {0, };
530 memset(&arg, 0, sizeof(arg));
531 arg.handle = bo_dumb->gem;
532 if (drmIoctl(bo_dumb->fd, DRM_IOCTL_GEM_CLOSE, &arg)) {
533 TBM_DUMB_LOG("error bo:%p fail to gem close.(%s)\n",
534 bo, strerror(errno));
542 tbm_dumb_bo_import(tbm_bo bo, unsigned int key)
544 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
546 tbm_bufmgr_dumb bufmgr_dumb;
550 bufmgr_dumb = (tbm_bufmgr_dumb)tbm_backend_get_bufmgr_priv(bo);
551 DUMB_RETURN_VAL_IF_FAIL(bufmgr_dumb != NULL, 0);
553 ret = drmHashLookup(bufmgr_dumb->hashBos, key, (void **)&bo_dumb);
557 struct drm_gem_open arg = {0, };
560 if (drmIoctl(bufmgr_dumb->fd, DRM_IOCTL_GEM_OPEN, &arg)) {
561 TBM_DUMB_LOG("error Cannot open gem name=%d\n", key);
565 bo_dumb = calloc(1, sizeof(struct _tbm_bo_dumb));
567 TBM_DUMB_LOG("error fail to allocate the bo private\n");
571 bo_dumb->fd = bufmgr_dumb->fd;
572 bo_dumb->gem = arg.handle;
573 bo_dumb->size = arg.size;
574 bo_dumb->flags_dumb = 0;
576 bo_dumb->flags_tbm = _get_tbm_flag_from_dumb(bo_dumb->flags_dumb);
578 if (!bo_dumb->dmabuf) {
579 struct drm_prime_handle arg = {0, };
581 arg.handle = bo_dumb->gem;
582 if (drmIoctl(bo_dumb->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg)) {
583 TBM_DUMB_LOG("error Cannot dmabuf=%d\n", bo_dumb->gem);
587 bo_dumb->dmabuf = arg.fd;
591 if (drmHashInsert(bufmgr_dumb->hashBos, bo_dumb->name, (void *)bo_dumb) < 0)
592 TBM_DUMB_LOG("error Cannot insert bo to Hash(%d)\n", bo_dumb->name);
594 DBG(" [%s] bo:%p, gem:%d(%d), fd:%d, flags:%d(%d), size:%d\n", target_name(),
596 bo_dumb->gem, bo_dumb->name,
598 bo_dumb->flags_tbm, bo_dumb->flags_dumb,
601 return (void *)bo_dumb;
605 tbm_dumb_bo_import_fd(tbm_bo bo, tbm_fd key)
607 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
609 tbm_bufmgr_dumb bufmgr_dumb;
612 bufmgr_dumb = (tbm_bufmgr_dumb)tbm_backend_get_bufmgr_priv(bo);
613 DUMB_RETURN_VAL_IF_FAIL(bufmgr_dumb != NULL, 0);
617 unsigned int gem = 0;
618 unsigned int name = 0;
619 unsigned int real_size = -1;
621 //getting handle from fd
622 struct drm_prime_handle arg = {0, };
623 struct drm_gem_open gem_open = {0, };
627 if (drmIoctl(bufmgr_dumb->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &arg)) {
628 TBM_DUMB_LOG("error bo:%p Cannot get gem handle from fd:%d (%s)\n",
629 bo, arg.fd, strerror(errno));
634 /* Determine size of bo. The fd-to-handle ioctl really should
635 * return the size, but it doesn't. If we have kernel 3.12 or
636 * later, we can lseek on the prime fd to get the size. Older
637 * kernels will just fail, in which case we fall back to the
638 * provided (estimated or guess size). */
639 real_size = lseek(key, 0, SEEK_END);
641 name = _get_name(bufmgr_dumb->fd, gem);
643 TBM_DUMB_LOG("error bo:%p Cannot get name from gem:%d, fd:%d (%s)\n",
644 bo, gem, key, strerror(errno));
648 ret = drmHashLookup(bufmgr_dumb->hashBos, name, (void **)&bo_dumb);
650 if (gem == bo_dumb->gem)
654 /* Open the same GEM object only for finding out its size */
655 gem_open.name = name;
656 if (drmIoctl(bufmgr_dumb->fd, DRM_IOCTL_GEM_OPEN, &gem_open)) {
657 TBM_DUMB_LOG("error Cannot open gem name=%d\n", key);
660 /* Free gem handle to avoid a memory leak*/
661 struct drm_gem_close gem_close;
662 gem_close.handle = gem_open.handle;
663 if (drmIoctl(bufmgr_dumb->fd, DRM_IOCTL_GEM_CLOSE, &gem_close)) {
664 TBM_DUMB_LOG("error bo:%p fail to gem close.(%s)\n",
665 bo, strerror(errno));
669 real_size = gem_open.size;
671 bo_dumb = calloc(1, sizeof(struct _tbm_bo_dumb));
673 TBM_DUMB_LOG("error bo:%p fail to allocate the bo private\n", bo);
677 bo_dumb->fd = bufmgr_dumb->fd;
680 bo_dumb->size = real_size;
681 bo_dumb->flags_dumb = 0;
682 bo_dumb->flags_tbm = _get_tbm_flag_from_dumb(bo_dumb->flags_dumb);
683 bo_dumb->name = name;
686 if (drmHashInsert(bufmgr_dumb->hashBos, bo_dumb->name, (void *)bo_dumb) < 0)
687 TBM_DUMB_LOG("error Cannot insert bo to Hash(%d)\n", bo_dumb->name);
689 DBG(" [%s] bo:%p, gem:%d(%d), fd:%d, key_fd:%d, flags:%d(%d), size:%d\n", target_name(),
691 bo_dumb->gem, bo_dumb->name,
694 bo_dumb->flags_tbm, bo_dumb->flags_dumb,
697 return (void *)bo_dumb;
701 tbm_dumb_bo_export(tbm_bo bo)
703 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
707 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
708 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, 0);
710 if (!bo_dumb->name) {
711 bo_dumb->name = _get_name(bo_dumb->fd, bo_dumb->gem);
712 if (!bo_dumb->name) {
713 TBM_DUMB_LOG("error Cannot get name\n");
718 DBG(" [%s] bo:%p, gem:%d(%d), fd:%d, flags:%d(%d), size:%d\n", target_name(),
720 bo_dumb->gem, bo_dumb->name,
722 bo_dumb->flags_tbm, bo_dumb->flags_dumb,
725 return (unsigned int)bo_dumb->name;
729 tbm_dumb_bo_export_fd(tbm_bo bo)
731 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, -1);
736 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
737 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, -1);
739 struct drm_prime_handle arg = {0, };
741 arg.handle = bo_dumb->gem;
742 ret = drmIoctl(bo_dumb->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg);
744 TBM_DUMB_LOG("error bo:%p Cannot dmabuf=%d (%s)\n",
745 bo, bo_dumb->gem, strerror(errno));
749 DBG(" [%s] bo:%p, gem:%d(%d), fd:%d, key_fd:%d, flags:%d(%d), size:%d\n", target_name(),
751 bo_dumb->gem, bo_dumb->name,
754 bo_dumb->flags_tbm, bo_dumb->flags_dumb,
757 return (tbm_fd)arg.fd;
761 tbm_dumb_bo_get_handle(tbm_bo bo, int device)
763 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, (tbm_bo_handle) NULL);
765 tbm_bo_handle bo_handle;
768 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
769 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, (tbm_bo_handle) NULL);
772 TBM_DUMB_LOG("error Cannot map gem=%d\n", bo_dumb->gem);
773 return (tbm_bo_handle) NULL;
776 DBG("[%s] bo:%p, gem:%d(%d), fd:%d, flags:%d(%d), size:%d, %s\n", target_name(),
778 bo_dumb->gem, bo_dumb->name,
780 bo_dumb->flags_tbm, bo_dumb->flags_dumb,
784 /*Get mapped bo_handle*/
785 bo_handle = _dumb_bo_handle(bo_dumb, device);
786 if (bo_handle.ptr == NULL) {
787 TBM_DUMB_LOG("error Cannot get handle: gem:%d, device:%d\n", bo_dumb->gem, device);
788 return (tbm_bo_handle) NULL;
795 tbm_dumb_bo_map(tbm_bo bo, int device, int opt)
797 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, (tbm_bo_handle) NULL);
799 tbm_bo_handle bo_handle;
802 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
803 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, (tbm_bo_handle) NULL);
806 TBM_DUMB_LOG("error Cannot map gem=%d\n", bo_dumb->gem);
807 return (tbm_bo_handle) NULL;
810 DBG(" [%s] bo:%p, gem:%d(%d), fd:%d, %s, %s\n", target_name(),
812 bo_dumb->gem, bo_dumb->name,
817 /*Get mapped bo_handle*/
818 bo_handle = _dumb_bo_handle(bo_dumb, device);
819 if (bo_handle.ptr == NULL) {
820 TBM_DUMB_LOG("error Cannot get handle: gem:%d, device:%d, opt:%d\n", bo_dumb->gem, device, opt);
821 return (tbm_bo_handle) NULL;
828 tbm_dumb_bo_unmap(tbm_bo bo)
830 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
834 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
835 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, 0);
840 DBG(" [%s] bo:%p, gem:%d(%d), fd:%d\n", target_name(),
842 bo_dumb->gem, bo_dumb->name,
849 tbm_dumb_bo_lock(tbm_bo bo, int device, int opt)
851 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
854 tbm_bufmgr_dumb bufmgr_dumb;
856 struct dma_buf_fence fence;
857 struct flock filelock;
860 if (device != TBM_DEVICE_3D && device != TBM_DEVICE_CPU) {
861 DBG("[libtbm-dumb:%d] %s not support device type,\n", getpid(), __FUNCTION__);
865 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
866 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, 0);
868 bufmgr_dumb = (tbm_bufmgr_dumb)tbm_backend_get_bufmgr_priv(bo);
869 DUMB_RETURN_VAL_IF_FAIL(bufmgr_dumb != NULL, 0);
871 if (!bufmgr_dumb->use_dma_fence)
874 memset(&fence, 0, sizeof(struct dma_buf_fence));
876 /* Check if the given type is valid or not. */
877 if (opt & TBM_OPTION_WRITE) {
878 if (device == TBM_DEVICE_3D)
879 fence.type = DMA_BUF_ACCESS_WRITE | DMA_BUF_ACCESS_DMA;
880 } else if (opt & TBM_OPTION_READ) {
881 if (device == TBM_DEVICE_3D)
882 fence.type = DMA_BUF_ACCESS_READ | DMA_BUF_ACCESS_DMA;
884 TBM_DUMB_LOG("error Invalid argument\n");
888 /* Check if the tbm manager supports dma fence or not. */
889 if (!bufmgr_dumb->use_dma_fence) {
890 TBM_DUMB_LOG("error Not support DMA FENCE(%s)\n", strerror(errno));
894 if (device == TBM_DEVICE_3D) {
895 ret = ioctl(bo_dumb->dmabuf, DMABUF_IOCTL_GET_FENCE, &fence);
897 TBM_DUMB_LOG("error Cannot set GET FENCE(%s)\n", strerror(errno));
901 if (opt & TBM_OPTION_WRITE)
902 filelock.l_type = F_WRLCK;
904 filelock.l_type = F_RDLCK;
906 filelock.l_whence = SEEK_CUR;
907 filelock.l_start = 0;
910 if (-1 == fcntl(bo_dumb->dmabuf, F_SETLKW, &filelock))
914 pthread_mutex_lock(&bo_dumb->mutex);
916 if (device == TBM_DEVICE_3D) {
918 for (i = 0; i < DMA_FENCE_LIST_MAX; i++) {
919 if (bo_dumb->dma_fence[i].ctx == 0) {
920 bo_dumb->dma_fence[i].type = fence.type;
921 bo_dumb->dma_fence[i].ctx = fence.ctx;
926 if (i == DMA_FENCE_LIST_MAX) {
927 //TODO: if dma_fence list is full, it needs realloc. I will fix this. by minseok3.kim
928 TBM_DUMB_LOG("error fence list is full\n");
932 pthread_mutex_unlock(&bo_dumb->mutex);
934 DBG("[%s] DMABUF_IOCTL_GET_FENCE! bo:%p, gem:%d(%d), fd:%ds\n", target_name(),
936 bo_dumb->gem, bo_dumb->name,
944 tbm_dumb_bo_unlock(tbm_bo bo)
946 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
950 struct dma_buf_fence fence;
951 struct flock filelock;
952 unsigned int dma_type = 0;
955 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
956 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, 0);
958 bufmgr_dumb = (tbm_bufmgr_dumb)tbm_backend_get_bufmgr_priv(bo);
959 DUMB_RETURN_VAL_IF_FAIL(bufmgr_dumb != NULL, 0);
961 if (!bufmgr_dumb->use_dma_fence)
964 if (bo_dumb->dma_fence[0].type & DMA_BUF_ACCESS_DMA)
967 if (!bo_dumb->dma_fence[0].ctx && dma_type) {
968 DBG("error FENCE not support or ignored,\n");
972 if (!bo_dumb->dma_fence[0].ctx && dma_type) {
973 DBG("error device type is not 3D/CPU,\n");
977 pthread_mutex_lock(&bo_dumb->mutex);
980 fence.type = bo_dumb->dma_fence[0].type;
981 fence.ctx = bo_dumb->dma_fence[0].ctx;
983 for (i = 1; i < DMA_FENCE_LIST_MAX; i++) {
984 bo_dumb->dma_fence[i-1].type = bo_dumb->dma_fence[i].type;
985 bo_dumb->dma_fence[i-1].ctx = bo_dumb->dma_fence[i].ctx;
987 bo_dumb->dma_fence[DMA_FENCE_LIST_MAX-1].type = 0;
988 bo_dumb->dma_fence[DMA_FENCE_LIST_MAX-1].ctx = 0;
990 pthread_mutex_unlock(&bo_dumb->mutex);
993 ret = ioctl(bo_dumb->dmabuf, DMABUF_IOCTL_PUT_FENCE, &fence);
995 TBM_DUMB_LOG("error Can not set PUT FENCE(%s)\n", strerror(errno));
999 filelock.l_type = F_UNLCK;
1000 filelock.l_whence = SEEK_CUR;
1001 filelock.l_start = 0;
1004 if (-1 == fcntl(bo_dumb->dmabuf, F_SETLKW, &filelock))
1008 DBG("[%s] DMABUF_IOCTL_PUT_FENCE! bo:%p, gem:%d(%d), fd:%ds\n", target_name(),
1010 bo_dumb->gem, bo_dumb->name,
1018 tbm_dumb_bufmgr_deinit(void *priv)
1020 DUMB_RETURN_IF_FAIL(priv != NULL);
1022 tbm_bufmgr_dumb bufmgr_dumb;
1024 bufmgr_dumb = (tbm_bufmgr_dumb)priv;
1026 if (bufmgr_dumb->hashBos) {
1030 while (drmHashFirst(bufmgr_dumb->hashBos, &key, &value) > 0) {
1032 drmHashDelete(bufmgr_dumb->hashBos, key);
1035 drmHashDestroy(bufmgr_dumb->hashBos);
1036 bufmgr_dumb->hashBos = NULL;
1039 if (bufmgr_dumb->bind_display)
1040 tbm_drm_helper_wl_auth_server_deinit();
1042 if (bufmgr_dumb->device_name)
1043 free(bufmgr_dumb->device_name);
1045 if (tbm_backend_is_display_server())
1046 tbm_drm_helper_unset_tbm_master_fd();
1048 close(bufmgr_dumb->fd);
1054 tbm_dumb_surface_supported_format(uint32_t **formats, uint32_t *num)
1056 uint32_t* color_formats = NULL;
1058 color_formats = (uint32_t*)calloc(1, sizeof(uint32_t) * TBM_COLOR_FORMAT_COUNT);
1060 if (color_formats == NULL)
1063 memcpy(color_formats, tbm_dumb_color_format_list , sizeof(uint32_t) * TBM_COLOR_FORMAT_COUNT);
1065 *formats = color_formats;
1066 *num = TBM_COLOR_FORMAT_COUNT;
1073 * @brief get the plane data of the surface.
1074 * @param[in] width : the width of the surface
1075 * @param[in] height : the height of the surface
1076 * @param[in] format : the format of the surface
1077 * @param[in] plane_idx : the format of the surface
1078 * @param[out] size : the size of the plane
1079 * @param[out] offset : the offset of the plane
1080 * @param[out] pitch : the pitch of the plane
1081 * @param[out] padding : the padding of the plane
1082 * @return 1 if this function succeeds, otherwise 0.
1085 tbm_dumb_surface_get_plane_data(int width, int height, tbm_format format, int plane_idx, uint32_t *size, uint32_t *offset, uint32_t *pitch, int *bo_idx)
1096 case TBM_FORMAT_XRGB4444:
1097 case TBM_FORMAT_XBGR4444:
1098 case TBM_FORMAT_RGBX4444:
1099 case TBM_FORMAT_BGRX4444:
1100 case TBM_FORMAT_ARGB4444:
1101 case TBM_FORMAT_ABGR4444:
1102 case TBM_FORMAT_RGBA4444:
1103 case TBM_FORMAT_BGRA4444:
1104 case TBM_FORMAT_XRGB1555:
1105 case TBM_FORMAT_XBGR1555:
1106 case TBM_FORMAT_RGBX5551:
1107 case TBM_FORMAT_BGRX5551:
1108 case TBM_FORMAT_ARGB1555:
1109 case TBM_FORMAT_ABGR1555:
1110 case TBM_FORMAT_RGBA5551:
1111 case TBM_FORMAT_BGRA5551:
1112 case TBM_FORMAT_RGB565:
1115 _pitch = SIZE_ALIGN((width * bpp)>>3, TBM_SURFACE_ALIGNMENT_PITCH_RGB);
1116 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1120 case TBM_FORMAT_RGB888:
1121 case TBM_FORMAT_BGR888:
1124 _pitch = SIZE_ALIGN((width * bpp)>>3, TBM_SURFACE_ALIGNMENT_PITCH_RGB);
1125 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1129 case TBM_FORMAT_XRGB8888:
1130 case TBM_FORMAT_XBGR8888:
1131 case TBM_FORMAT_RGBX8888:
1132 case TBM_FORMAT_BGRX8888:
1133 case TBM_FORMAT_ARGB8888:
1134 case TBM_FORMAT_ABGR8888:
1135 case TBM_FORMAT_RGBA8888:
1136 case TBM_FORMAT_BGRA8888:
1139 _pitch = SIZE_ALIGN((width * bpp)>>3, TBM_SURFACE_ALIGNMENT_PITCH_RGB);
1140 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1145 case TBM_FORMAT_YUYV:
1146 case TBM_FORMAT_YVYU:
1147 case TBM_FORMAT_UYVY:
1148 case TBM_FORMAT_VYUY:
1149 case TBM_FORMAT_AYUV:
1152 _pitch = SIZE_ALIGN((width * bpp)>>3, TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1153 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1159 * index 0 = Y plane, [7:0] Y
1160 * index 1 = Cr:Cb plane, [15:0] Cr:Cb little endian
1162 * index 1 = Cb:Cr plane, [15:0] Cb:Cr little endian
1164 case TBM_FORMAT_NV12:
1165 case TBM_FORMAT_NV21:
1167 if (plane_idx == 0) {
1169 _pitch = SIZE_ALIGN(width , TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1170 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1172 } else if (plane_idx == 1) {
1173 _offset = width*height;
1174 _pitch = SIZE_ALIGN(width , TBM_SURFACE_ALIGNMENT_PITCH_YUV/2);
1175 _size = SIZE_ALIGN(_pitch * (height / 2), TBM_SURFACE_ALIGNMENT_PLANE);
1180 case TBM_FORMAT_NV16:
1181 case TBM_FORMAT_NV61:
1183 //if (plane_idx == 0)
1186 _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1187 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1192 //else if (plane_idx == 1)
1195 _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV/2);
1196 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1203 * index 0: Y plane, [7:0] Y
1204 * index 1: Cb plane, [7:0] Cb
1205 * index 2: Cr plane, [7:0] Cr
1207 * index 1: Cr plane, [7:0] Cr
1208 * index 2: Cb plane, [7:0] Cb
1211 NATIVE_BUFFER_FORMAT_YV12
1212 NATIVE_BUFFER_FORMAT_I420
1214 case TBM_FORMAT_YUV410:
1215 case TBM_FORMAT_YVU410:
1218 case TBM_FORMAT_YUV411:
1219 case TBM_FORMAT_YVU411:
1220 case TBM_FORMAT_YUV420:
1221 case TBM_FORMAT_YVU420:
1223 //if (plane_idx == 0)
1226 _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1227 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1232 //else if (plane_idx == 1)
1235 _pitch = SIZE_ALIGN(width/2, TBM_SURFACE_ALIGNMENT_PITCH_YUV/2);
1236 _size = SIZE_ALIGN(_pitch * (height / 2), TBM_SURFACE_ALIGNMENT_PLANE);
1241 //else if (plane_idx == 2)
1244 _pitch = SIZE_ALIGN(width/2, TBM_SURFACE_ALIGNMENT_PITCH_YUV/2);
1245 _size = SIZE_ALIGN(_pitch * (height / 2), TBM_SURFACE_ALIGNMENT_PLANE);
1249 case TBM_FORMAT_YUV422:
1250 case TBM_FORMAT_YVU422:
1252 //if (plane_idx == 0)
1255 _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1256 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1261 //else if (plane_idx == 1)
1264 _pitch = SIZE_ALIGN(width/2, TBM_SURFACE_ALIGNMENT_PITCH_YUV/2);
1265 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1270 //else if (plane_idx == 2)
1273 _pitch = SIZE_ALIGN(width/2, TBM_SURFACE_ALIGNMENT_PITCH_YUV/2);
1274 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1278 case TBM_FORMAT_YUV444:
1279 case TBM_FORMAT_YVU444:
1281 //if (plane_idx == 0)
1284 _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1285 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1290 //else if (plane_idx == 1)
1293 _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1294 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1299 //else if (plane_idx == 2)
1302 _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1303 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1321 tbm_dumb_bo_get_flags(tbm_bo bo)
1323 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
1325 tbm_bo_dumb bo_dumb;
1327 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
1328 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, 0);
1330 return bo_dumb->flags_tbm;
1334 tbm_dumb_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *native_display)
1336 tbm_bufmgr_dumb bufmgr_dumb;
1338 bufmgr_dumb = tbm_backend_get_priv_from_bufmgr(bufmgr);
1339 DUMB_RETURN_VAL_IF_FAIL(bufmgr_dumb != NULL, 0);
1341 if (!tbm_drm_helper_wl_auth_server_init(native_display, bufmgr_dumb->fd,
1342 bufmgr_dumb->device_name, 0)) {
1343 TBM_DUMB_LOG("error:Fail to tbm_drm_helper_wl_server_init\n");
1347 bufmgr_dumb->bind_display = native_display;
1352 MODULEINITPPROTO(init_tbm_bufmgr_priv);
1354 static TBMModuleVersionInfo DumbVersRec = {
1360 TBMModuleData tbmModuleData = { &DumbVersRec, init_tbm_bufmgr_priv};
1363 init_tbm_bufmgr_priv(tbm_bufmgr bufmgr, int fd)
1365 tbm_bufmgr_dumb bufmgr_dumb;
1366 tbm_bufmgr_backend bufmgr_backend;
1376 bufmgr_dumb = calloc(1, sizeof(struct _tbm_bufmgr_dumb));
1378 TBM_DUMB_LOG("error: Fail to alloc bufmgr_dumb!\n");
1382 if (tbm_backend_is_display_server()) {
1384 bufmgr_dumb->fd = tbm_drm_helper_get_master_fd();
1385 if (bufmgr_dumb->fd < 0)
1386 bufmgr_dumb->fd = _tbm_dumb_open_drm();
1388 if (bufmgr_dumb->fd < 0) {
1389 TBM_DUMB_LOG("error:Fail to create drm!\n");
1393 tbm_drm_helper_set_tbm_master_fd(bufmgr_dumb->fd);
1395 bufmgr_dumb->device_name = drmGetDeviceNameFromFd(bufmgr_dumb->fd);
1396 if (!bufmgr_dumb->device_name) {
1397 TBM_DUMB_LOG("error:Fail to get device name!\n");
1398 goto fail_get_device_name;
1401 if (!tbm_drm_helper_get_auth_info(&(bufmgr_dumb->fd), &(bufmgr_dumb->device_name), NULL)) {
1402 TBM_DUMB_LOG("error:Fail to get auth drm info!\n");
1403 goto fail_get_auth_info;
1407 ret = drmGetCap(bufmgr_dumb->fd, DRM_CAP_DUMB_BUFFER, &cap);
1408 if (ret || cap == 0) {
1409 TBM_DUMB_LOG("error: drm buffer isn't supported !\n");
1414 bufmgr_dumb->hashBos = drmHashCreate();
1416 //Check if the tbm manager supports dma fence or not.
1417 fp = open("/sys/module/dmabuf_sync/parameters/enabled", O_RDONLY);
1419 length = read(fp, buf, 1);
1421 if (length == 1 && buf[0] == '1')
1422 bufmgr_dumb->use_dma_fence = 1;
1427 bufmgr_backend = tbm_backend_alloc();
1428 if (!bufmgr_backend) {
1429 TBM_DUMB_LOG("error: Fail to create drm!\n");
1430 goto fail_alloc_backend;
1433 bufmgr_backend->priv = (void *)bufmgr_dumb;
1434 bufmgr_backend->bufmgr_deinit = tbm_dumb_bufmgr_deinit,
1435 bufmgr_backend->bo_size = tbm_dumb_bo_size,
1436 bufmgr_backend->bo_alloc = tbm_dumb_bo_alloc,
1437 bufmgr_backend->bo_free = tbm_dumb_bo_free,
1438 bufmgr_backend->bo_import = tbm_dumb_bo_import,
1439 bufmgr_backend->bo_import_fd = tbm_dumb_bo_import_fd,
1440 bufmgr_backend->bo_export = tbm_dumb_bo_export,
1441 bufmgr_backend->bo_export_fd = tbm_dumb_bo_export_fd,
1442 bufmgr_backend->bo_get_handle = tbm_dumb_bo_get_handle,
1443 bufmgr_backend->bo_map = tbm_dumb_bo_map,
1444 bufmgr_backend->bo_unmap = tbm_dumb_bo_unmap,
1445 bufmgr_backend->surface_get_plane_data = tbm_dumb_surface_get_plane_data;
1446 bufmgr_backend->surface_supported_format = tbm_dumb_surface_supported_format;
1447 bufmgr_backend->bo_get_flags = tbm_dumb_bo_get_flags;
1448 bufmgr_backend->bo_lock = tbm_dumb_bo_lock;
1449 bufmgr_backend->bo_unlock = tbm_dumb_bo_unlock;
1450 bufmgr_backend->bufmgr_bind_native_display = tbm_dumb_bufmgr_bind_native_display;
1452 if (!tbm_backend_init(bufmgr, bufmgr_backend)) {
1453 TBM_DUMB_LOG("error: Fail to init backend!\n");
1454 goto fail_init_backend;
1460 env = getenv("TBM_DUMB_DEBUG");
1463 TBM_DUMB_LOG("TBM_DUMB_DEBUG=%s\n", env);
1469 DBG("[%s] DMABUF FENCE is %s\n", target_name(),
1470 bufmgr_dumb->use_dma_fence ? "supported!" : "NOT supported!");
1472 DBG("[%s] drm_fd:%d\n", target_name(), bufmgr_dumb->fd);
1477 tbm_backend_free(bufmgr_backend);
1479 if (bufmgr_dumb->hashBos)
1480 drmHashDestroy(bufmgr_dumb->hashBos);
1481 if (bufmgr_dumb->device_name)
1482 free(bufmgr_dumb->device_name);
1484 fail_get_device_name:
1485 if (tbm_backend_is_display_server())
1486 tbm_drm_helper_unset_tbm_master_fd();
1487 if (bufmgr_dumb->fd >= 0)
1488 close(bufmgr_dumb->fd);