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)
488 tbm_bo_dumb bo_dumb, temp;
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**)&temp);
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);
529 TBM_DUMB_LOG("hashBos probably has several BOs with same name!!!\n");
531 /* Free gem handle */
532 struct drm_gem_close arg = {0, };
533 memset(&arg, 0, sizeof(arg));
534 arg.handle = bo_dumb->gem;
535 if (drmIoctl(bo_dumb->fd, DRM_IOCTL_GEM_CLOSE, &arg)) {
536 TBM_DUMB_LOG("error bo:%p fail to gem close.(%s)\n",
537 bo, strerror(errno));
545 tbm_dumb_bo_import(tbm_bo bo, unsigned int key)
547 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
549 tbm_bufmgr_dumb bufmgr_dumb;
553 bufmgr_dumb = (tbm_bufmgr_dumb)tbm_backend_get_bufmgr_priv(bo);
554 DUMB_RETURN_VAL_IF_FAIL(bufmgr_dumb != NULL, 0);
556 ret = drmHashLookup(bufmgr_dumb->hashBos, key, (void **)&bo_dumb);
560 struct drm_gem_open arg = {0, };
563 if (drmIoctl(bufmgr_dumb->fd, DRM_IOCTL_GEM_OPEN, &arg)) {
564 TBM_DUMB_LOG("error Cannot open gem name=%d\n", key);
568 bo_dumb = calloc(1, sizeof(struct _tbm_bo_dumb));
570 TBM_DUMB_LOG("error fail to allocate the bo private\n");
574 bo_dumb->fd = bufmgr_dumb->fd;
575 bo_dumb->gem = arg.handle;
576 bo_dumb->size = arg.size;
577 bo_dumb->flags_dumb = 0;
579 bo_dumb->flags_tbm = _get_tbm_flag_from_dumb(bo_dumb->flags_dumb);
581 if (!bo_dumb->dmabuf) {
582 struct drm_prime_handle arg = {0, };
584 arg.handle = bo_dumb->gem;
585 if (drmIoctl(bo_dumb->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg)) {
586 TBM_DUMB_LOG("error Cannot dmabuf=%d\n", bo_dumb->gem);
590 bo_dumb->dmabuf = arg.fd;
594 if (drmHashInsert(bufmgr_dumb->hashBos, bo_dumb->name, (void *)bo_dumb) < 0)
595 TBM_DUMB_LOG("error Cannot insert bo to Hash(%d)\n", bo_dumb->name);
597 DBG(" [%s] bo:%p, gem:%d(%d), fd:%d, flags:%d(%d), size:%d\n", target_name(),
599 bo_dumb->gem, bo_dumb->name,
601 bo_dumb->flags_tbm, bo_dumb->flags_dumb,
604 return (void *)bo_dumb;
608 tbm_dumb_bo_import_fd(tbm_bo bo, tbm_fd key)
610 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
612 tbm_bufmgr_dumb bufmgr_dumb;
615 bufmgr_dumb = (tbm_bufmgr_dumb)tbm_backend_get_bufmgr_priv(bo);
616 DUMB_RETURN_VAL_IF_FAIL(bufmgr_dumb != NULL, 0);
620 unsigned int gem = 0;
621 unsigned int name = 0;
622 unsigned int real_size = -1;
624 //getting handle from fd
625 struct drm_prime_handle arg = {0, };
626 struct drm_gem_open gem_open = {0, };
630 if (drmIoctl(bufmgr_dumb->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &arg)) {
631 TBM_DUMB_LOG("error bo:%p Cannot get gem handle from fd:%d (%s)\n",
632 bo, arg.fd, strerror(errno));
637 /* Determine size of bo. The fd-to-handle ioctl really should
638 * return the size, but it doesn't. If we have kernel 3.12 or
639 * later, we can lseek on the prime fd to get the size. Older
640 * kernels will just fail, in which case we fall back to the
641 * provided (estimated or guess size). */
642 real_size = lseek(key, 0, SEEK_END);
644 name = _get_name(bufmgr_dumb->fd, gem);
646 TBM_DUMB_LOG("error bo:%p Cannot get name from gem:%d, fd:%d (%s)\n",
647 bo, gem, key, strerror(errno));
651 ret = drmHashLookup(bufmgr_dumb->hashBos, name, (void **)&bo_dumb);
653 if (gem == bo_dumb->gem)
657 /* Open the same GEM object only for finding out its size */
658 gem_open.name = name;
659 if (drmIoctl(bufmgr_dumb->fd, DRM_IOCTL_GEM_OPEN, &gem_open)) {
660 TBM_DUMB_LOG("error Cannot open gem name=%d\n", key);
663 /* Free gem handle to avoid a memory leak*/
664 struct drm_gem_close gem_close;
665 gem_close.handle = gem_open.handle;
666 if (drmIoctl(bufmgr_dumb->fd, DRM_IOCTL_GEM_CLOSE, &gem_close)) {
667 TBM_DUMB_LOG("error bo:%p fail to gem close.(%s)\n",
668 bo, strerror(errno));
672 real_size = gem_open.size;
674 bo_dumb = calloc(1, sizeof(struct _tbm_bo_dumb));
676 TBM_DUMB_LOG("error bo:%p fail to allocate the bo private\n", bo);
680 bo_dumb->fd = bufmgr_dumb->fd;
683 bo_dumb->size = real_size;
684 bo_dumb->flags_dumb = 0;
685 bo_dumb->flags_tbm = _get_tbm_flag_from_dumb(bo_dumb->flags_dumb);
686 bo_dumb->name = name;
689 if (drmHashInsert(bufmgr_dumb->hashBos, bo_dumb->name, (void *)bo_dumb) < 0)
690 TBM_DUMB_LOG("error Cannot insert bo to Hash(%d)\n", bo_dumb->name);
692 DBG(" [%s] bo:%p, gem:%d(%d), fd:%d, key_fd:%d, flags:%d(%d), size:%d\n", target_name(),
694 bo_dumb->gem, bo_dumb->name,
697 bo_dumb->flags_tbm, bo_dumb->flags_dumb,
700 return (void *)bo_dumb;
704 tbm_dumb_bo_export(tbm_bo bo)
706 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
710 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
711 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, 0);
713 if (!bo_dumb->name) {
714 bo_dumb->name = _get_name(bo_dumb->fd, bo_dumb->gem);
715 if (!bo_dumb->name) {
716 TBM_DUMB_LOG("error Cannot get name\n");
721 DBG(" [%s] bo:%p, gem:%d(%d), fd:%d, flags:%d(%d), size:%d\n", target_name(),
723 bo_dumb->gem, bo_dumb->name,
725 bo_dumb->flags_tbm, bo_dumb->flags_dumb,
728 return (unsigned int)bo_dumb->name;
732 tbm_dumb_bo_export_fd(tbm_bo bo)
734 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, -1);
739 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
740 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, -1);
742 struct drm_prime_handle arg = {0, };
744 arg.handle = bo_dumb->gem;
745 ret = drmIoctl(bo_dumb->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg);
747 TBM_DUMB_LOG("error bo:%p Cannot dmabuf=%d (%s)\n",
748 bo, bo_dumb->gem, strerror(errno));
752 DBG(" [%s] bo:%p, gem:%d(%d), fd:%d, key_fd:%d, flags:%d(%d), size:%d\n", target_name(),
754 bo_dumb->gem, bo_dumb->name,
757 bo_dumb->flags_tbm, bo_dumb->flags_dumb,
760 return (tbm_fd)arg.fd;
764 tbm_dumb_bo_get_handle(tbm_bo bo, int device)
766 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, (tbm_bo_handle) NULL);
768 tbm_bo_handle bo_handle;
771 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
772 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, (tbm_bo_handle) NULL);
775 TBM_DUMB_LOG("error Cannot map gem=%d\n", bo_dumb->gem);
776 return (tbm_bo_handle) NULL;
779 DBG("[%s] bo:%p, gem:%d(%d), fd:%d, flags:%d(%d), size:%d, %s\n", target_name(),
781 bo_dumb->gem, bo_dumb->name,
783 bo_dumb->flags_tbm, bo_dumb->flags_dumb,
787 /*Get mapped bo_handle*/
788 bo_handle = _dumb_bo_handle(bo_dumb, device);
789 if (bo_handle.ptr == NULL) {
790 TBM_DUMB_LOG("error Cannot get handle: gem:%d, device:%d\n", bo_dumb->gem, device);
791 return (tbm_bo_handle) NULL;
798 tbm_dumb_bo_map(tbm_bo bo, int device, int opt)
800 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, (tbm_bo_handle) NULL);
802 tbm_bo_handle bo_handle;
805 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
806 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, (tbm_bo_handle) NULL);
809 TBM_DUMB_LOG("error Cannot map gem=%d\n", bo_dumb->gem);
810 return (tbm_bo_handle) NULL;
813 DBG(" [%s] bo:%p, gem:%d(%d), fd:%d, %s, %s\n", target_name(),
815 bo_dumb->gem, bo_dumb->name,
820 /*Get mapped bo_handle*/
821 bo_handle = _dumb_bo_handle(bo_dumb, device);
822 if (bo_handle.ptr == NULL) {
823 TBM_DUMB_LOG("error Cannot get handle: gem:%d, device:%d, opt:%d\n", bo_dumb->gem, device, opt);
824 return (tbm_bo_handle) NULL;
831 tbm_dumb_bo_unmap(tbm_bo bo)
833 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
837 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
838 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, 0);
843 DBG(" [%s] bo:%p, gem:%d(%d), fd:%d\n", target_name(),
845 bo_dumb->gem, bo_dumb->name,
852 tbm_dumb_bo_lock(tbm_bo bo, int device, int opt)
854 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
857 tbm_bufmgr_dumb bufmgr_dumb;
859 struct dma_buf_fence fence;
860 struct flock filelock;
863 if (device != TBM_DEVICE_3D && device != TBM_DEVICE_CPU) {
864 DBG("[libtbm-dumb:%d] %s not support device type,\n", getpid(), __FUNCTION__);
868 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
869 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, 0);
871 bufmgr_dumb = (tbm_bufmgr_dumb)tbm_backend_get_bufmgr_priv(bo);
872 DUMB_RETURN_VAL_IF_FAIL(bufmgr_dumb != NULL, 0);
874 if (!bufmgr_dumb->use_dma_fence)
877 memset(&fence, 0, sizeof(struct dma_buf_fence));
879 /* Check if the given type is valid or not. */
880 if (opt & TBM_OPTION_WRITE) {
881 if (device == TBM_DEVICE_3D)
882 fence.type = DMA_BUF_ACCESS_WRITE | DMA_BUF_ACCESS_DMA;
883 } else if (opt & TBM_OPTION_READ) {
884 if (device == TBM_DEVICE_3D)
885 fence.type = DMA_BUF_ACCESS_READ | DMA_BUF_ACCESS_DMA;
887 TBM_DUMB_LOG("error Invalid argument\n");
891 /* Check if the tbm manager supports dma fence or not. */
892 if (!bufmgr_dumb->use_dma_fence) {
893 TBM_DUMB_LOG("error Not support DMA FENCE(%s)\n", strerror(errno));
897 if (device == TBM_DEVICE_3D) {
898 ret = ioctl(bo_dumb->dmabuf, DMABUF_IOCTL_GET_FENCE, &fence);
900 TBM_DUMB_LOG("error Cannot set GET FENCE(%s)\n", strerror(errno));
904 if (opt & TBM_OPTION_WRITE)
905 filelock.l_type = F_WRLCK;
907 filelock.l_type = F_RDLCK;
909 filelock.l_whence = SEEK_CUR;
910 filelock.l_start = 0;
913 if (-1 == fcntl(bo_dumb->dmabuf, F_SETLKW, &filelock))
917 pthread_mutex_lock(&bo_dumb->mutex);
919 if (device == TBM_DEVICE_3D) {
921 for (i = 0; i < DMA_FENCE_LIST_MAX; i++) {
922 if (bo_dumb->dma_fence[i].ctx == 0) {
923 bo_dumb->dma_fence[i].type = fence.type;
924 bo_dumb->dma_fence[i].ctx = fence.ctx;
929 if (i == DMA_FENCE_LIST_MAX) {
930 //TODO: if dma_fence list is full, it needs realloc. I will fix this. by minseok3.kim
931 TBM_DUMB_LOG("error fence list is full\n");
935 pthread_mutex_unlock(&bo_dumb->mutex);
937 DBG("[%s] DMABUF_IOCTL_GET_FENCE! bo:%p, gem:%d(%d), fd:%ds\n", target_name(),
939 bo_dumb->gem, bo_dumb->name,
947 tbm_dumb_bo_unlock(tbm_bo bo)
949 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
953 struct dma_buf_fence fence;
954 struct flock filelock;
955 unsigned int dma_type = 0;
958 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
959 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, 0);
961 bufmgr_dumb = (tbm_bufmgr_dumb)tbm_backend_get_bufmgr_priv(bo);
962 DUMB_RETURN_VAL_IF_FAIL(bufmgr_dumb != NULL, 0);
964 if (!bufmgr_dumb->use_dma_fence)
967 if (bo_dumb->dma_fence[0].type & DMA_BUF_ACCESS_DMA)
970 if (!bo_dumb->dma_fence[0].ctx && dma_type) {
971 DBG("error FENCE not support or ignored,\n");
975 if (!bo_dumb->dma_fence[0].ctx && dma_type) {
976 DBG("error device type is not 3D/CPU,\n");
980 pthread_mutex_lock(&bo_dumb->mutex);
983 fence.type = bo_dumb->dma_fence[0].type;
984 fence.ctx = bo_dumb->dma_fence[0].ctx;
986 for (i = 1; i < DMA_FENCE_LIST_MAX; i++) {
987 bo_dumb->dma_fence[i-1].type = bo_dumb->dma_fence[i].type;
988 bo_dumb->dma_fence[i-1].ctx = bo_dumb->dma_fence[i].ctx;
990 bo_dumb->dma_fence[DMA_FENCE_LIST_MAX-1].type = 0;
991 bo_dumb->dma_fence[DMA_FENCE_LIST_MAX-1].ctx = 0;
993 pthread_mutex_unlock(&bo_dumb->mutex);
996 ret = ioctl(bo_dumb->dmabuf, DMABUF_IOCTL_PUT_FENCE, &fence);
998 TBM_DUMB_LOG("error Can not set PUT FENCE(%s)\n", strerror(errno));
1002 filelock.l_type = F_UNLCK;
1003 filelock.l_whence = SEEK_CUR;
1004 filelock.l_start = 0;
1007 if (-1 == fcntl(bo_dumb->dmabuf, F_SETLKW, &filelock))
1011 DBG("[%s] DMABUF_IOCTL_PUT_FENCE! bo:%p, gem:%d(%d), fd:%ds\n", target_name(),
1013 bo_dumb->gem, bo_dumb->name,
1021 tbm_dumb_bufmgr_deinit(void *priv)
1023 DUMB_RETURN_IF_FAIL(priv != NULL);
1025 tbm_bufmgr_dumb bufmgr_dumb;
1027 bufmgr_dumb = (tbm_bufmgr_dumb)priv;
1029 if (bufmgr_dumb->hashBos) {
1033 while (drmHashFirst(bufmgr_dumb->hashBos, &key, &value) > 0) {
1035 drmHashDelete(bufmgr_dumb->hashBos, key);
1038 drmHashDestroy(bufmgr_dumb->hashBos);
1039 bufmgr_dumb->hashBos = NULL;
1042 if (bufmgr_dumb->bind_display)
1043 tbm_drm_helper_wl_auth_server_deinit();
1045 if (bufmgr_dumb->device_name)
1046 free(bufmgr_dumb->device_name);
1048 if (tbm_backend_is_display_server())
1049 tbm_drm_helper_unset_tbm_master_fd();
1051 close(bufmgr_dumb->fd);
1057 tbm_dumb_surface_supported_format(uint32_t **formats, uint32_t *num)
1059 uint32_t* color_formats = NULL;
1061 color_formats = (uint32_t*)calloc(1, sizeof(uint32_t) * TBM_COLOR_FORMAT_COUNT);
1063 if (color_formats == NULL)
1066 memcpy(color_formats, tbm_dumb_color_format_list , sizeof(uint32_t) * TBM_COLOR_FORMAT_COUNT);
1068 *formats = color_formats;
1069 *num = TBM_COLOR_FORMAT_COUNT;
1076 * @brief get the plane data of the surface.
1077 * @param[in] width : the width of the surface
1078 * @param[in] height : the height of the surface
1079 * @param[in] format : the format of the surface
1080 * @param[in] plane_idx : the format of the surface
1081 * @param[out] size : the size of the plane
1082 * @param[out] offset : the offset of the plane
1083 * @param[out] pitch : the pitch of the plane
1084 * @param[out] padding : the padding of the plane
1085 * @return 1 if this function succeeds, otherwise 0.
1088 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)
1099 case TBM_FORMAT_XRGB4444:
1100 case TBM_FORMAT_XBGR4444:
1101 case TBM_FORMAT_RGBX4444:
1102 case TBM_FORMAT_BGRX4444:
1103 case TBM_FORMAT_ARGB4444:
1104 case TBM_FORMAT_ABGR4444:
1105 case TBM_FORMAT_RGBA4444:
1106 case TBM_FORMAT_BGRA4444:
1107 case TBM_FORMAT_XRGB1555:
1108 case TBM_FORMAT_XBGR1555:
1109 case TBM_FORMAT_RGBX5551:
1110 case TBM_FORMAT_BGRX5551:
1111 case TBM_FORMAT_ARGB1555:
1112 case TBM_FORMAT_ABGR1555:
1113 case TBM_FORMAT_RGBA5551:
1114 case TBM_FORMAT_BGRA5551:
1115 case TBM_FORMAT_RGB565:
1118 _pitch = SIZE_ALIGN((width * bpp)>>3, TBM_SURFACE_ALIGNMENT_PITCH_RGB);
1119 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1123 case TBM_FORMAT_RGB888:
1124 case TBM_FORMAT_BGR888:
1127 _pitch = SIZE_ALIGN((width * bpp)>>3, TBM_SURFACE_ALIGNMENT_PITCH_RGB);
1128 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1132 case TBM_FORMAT_XRGB8888:
1133 case TBM_FORMAT_XBGR8888:
1134 case TBM_FORMAT_RGBX8888:
1135 case TBM_FORMAT_BGRX8888:
1136 case TBM_FORMAT_ARGB8888:
1137 case TBM_FORMAT_ABGR8888:
1138 case TBM_FORMAT_RGBA8888:
1139 case TBM_FORMAT_BGRA8888:
1142 _pitch = SIZE_ALIGN((width * bpp)>>3, TBM_SURFACE_ALIGNMENT_PITCH_RGB);
1143 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1148 case TBM_FORMAT_YUYV:
1149 case TBM_FORMAT_YVYU:
1150 case TBM_FORMAT_UYVY:
1151 case TBM_FORMAT_VYUY:
1152 case TBM_FORMAT_AYUV:
1155 _pitch = SIZE_ALIGN((width * bpp)>>3, TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1156 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1162 * index 0 = Y plane, [7:0] Y
1163 * index 1 = Cr:Cb plane, [15:0] Cr:Cb little endian
1165 * index 1 = Cb:Cr plane, [15:0] Cb:Cr little endian
1167 case TBM_FORMAT_NV12:
1168 case TBM_FORMAT_NV21:
1170 if (plane_idx == 0) {
1172 _pitch = SIZE_ALIGN(width , TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1173 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1175 } else if (plane_idx == 1) {
1176 _offset = width*height;
1177 _pitch = SIZE_ALIGN(width , TBM_SURFACE_ALIGNMENT_PITCH_YUV/2);
1178 _size = SIZE_ALIGN(_pitch * (height / 2), TBM_SURFACE_ALIGNMENT_PLANE);
1183 case TBM_FORMAT_NV16:
1184 case TBM_FORMAT_NV61:
1186 //if (plane_idx == 0)
1189 _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1190 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1195 //else if (plane_idx == 1)
1198 _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV/2);
1199 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1206 * index 0: Y plane, [7:0] Y
1207 * index 1: Cb plane, [7:0] Cb
1208 * index 2: Cr plane, [7:0] Cr
1210 * index 1: Cr plane, [7:0] Cr
1211 * index 2: Cb plane, [7:0] Cb
1214 NATIVE_BUFFER_FORMAT_YV12
1215 NATIVE_BUFFER_FORMAT_I420
1217 case TBM_FORMAT_YUV410:
1218 case TBM_FORMAT_YVU410:
1221 case TBM_FORMAT_YUV411:
1222 case TBM_FORMAT_YVU411:
1223 case TBM_FORMAT_YUV420:
1224 case TBM_FORMAT_YVU420:
1226 //if (plane_idx == 0)
1229 _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1230 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1235 //else if (plane_idx == 1)
1238 _pitch = SIZE_ALIGN(width/2, TBM_SURFACE_ALIGNMENT_PITCH_YUV/2);
1239 _size = SIZE_ALIGN(_pitch * (height / 2), TBM_SURFACE_ALIGNMENT_PLANE);
1244 //else if (plane_idx == 2)
1247 _pitch = SIZE_ALIGN(width/2, TBM_SURFACE_ALIGNMENT_PITCH_YUV/2);
1248 _size = SIZE_ALIGN(_pitch * (height / 2), TBM_SURFACE_ALIGNMENT_PLANE);
1252 case TBM_FORMAT_YUV422:
1253 case TBM_FORMAT_YVU422:
1255 //if (plane_idx == 0)
1258 _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1259 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1264 //else if (plane_idx == 1)
1267 _pitch = SIZE_ALIGN(width/2, TBM_SURFACE_ALIGNMENT_PITCH_YUV/2);
1268 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1273 //else if (plane_idx == 2)
1276 _pitch = SIZE_ALIGN(width/2, TBM_SURFACE_ALIGNMENT_PITCH_YUV/2);
1277 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1281 case TBM_FORMAT_YUV444:
1282 case TBM_FORMAT_YVU444:
1284 //if (plane_idx == 0)
1287 _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1288 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1293 //else if (plane_idx == 1)
1296 _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1297 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1302 //else if (plane_idx == 2)
1305 _pitch = SIZE_ALIGN(width, TBM_SURFACE_ALIGNMENT_PITCH_YUV);
1306 _size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
1324 tbm_dumb_bo_get_flags(tbm_bo bo)
1326 DUMB_RETURN_VAL_IF_FAIL(bo != NULL, 0);
1328 tbm_bo_dumb bo_dumb;
1330 bo_dumb = (tbm_bo_dumb)tbm_backend_get_bo_priv(bo);
1331 DUMB_RETURN_VAL_IF_FAIL(bo_dumb != NULL, 0);
1333 return bo_dumb->flags_tbm;
1337 tbm_dumb_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *native_display)
1339 tbm_bufmgr_dumb bufmgr_dumb;
1341 bufmgr_dumb = tbm_backend_get_priv_from_bufmgr(bufmgr);
1342 DUMB_RETURN_VAL_IF_FAIL(bufmgr_dumb != NULL, 0);
1344 if (!tbm_drm_helper_wl_auth_server_init(native_display, bufmgr_dumb->fd,
1345 bufmgr_dumb->device_name, 0)) {
1346 TBM_DUMB_LOG("error:Fail to tbm_drm_helper_wl_server_init\n");
1350 bufmgr_dumb->bind_display = native_display;
1355 MODULEINITPPROTO(init_tbm_bufmgr_priv);
1357 static TBMModuleVersionInfo DumbVersRec = {
1363 TBMModuleData tbmModuleData = { &DumbVersRec, init_tbm_bufmgr_priv};
1366 init_tbm_bufmgr_priv(tbm_bufmgr bufmgr, int fd)
1368 tbm_bufmgr_dumb bufmgr_dumb;
1369 tbm_bufmgr_backend bufmgr_backend;
1379 bufmgr_dumb = calloc(1, sizeof(struct _tbm_bufmgr_dumb));
1381 TBM_DUMB_LOG("error: Fail to alloc bufmgr_dumb!\n");
1385 if (tbm_backend_is_display_server()) {
1387 bufmgr_dumb->fd = tbm_drm_helper_get_master_fd();
1388 if (bufmgr_dumb->fd < 0)
1389 bufmgr_dumb->fd = _tbm_dumb_open_drm();
1391 if (bufmgr_dumb->fd < 0) {
1392 TBM_DUMB_LOG("error:Fail to create drm!\n");
1396 tbm_drm_helper_set_tbm_master_fd(bufmgr_dumb->fd);
1398 bufmgr_dumb->device_name = drmGetDeviceNameFromFd(bufmgr_dumb->fd);
1399 if (!bufmgr_dumb->device_name) {
1400 TBM_DUMB_LOG("error:Fail to get device name!\n");
1401 goto fail_get_device_name;
1404 if (!tbm_drm_helper_get_auth_info(&(bufmgr_dumb->fd), &(bufmgr_dumb->device_name), NULL)) {
1405 TBM_DUMB_LOG("error:Fail to get auth drm info!\n");
1406 goto fail_get_auth_info;
1410 ret = drmGetCap(bufmgr_dumb->fd, DRM_CAP_DUMB_BUFFER, &cap);
1411 if (ret || cap == 0) {
1412 TBM_DUMB_LOG("error: drm buffer isn't supported !\n");
1417 bufmgr_dumb->hashBos = drmHashCreate();
1419 //Check if the tbm manager supports dma fence or not.
1420 fp = open("/sys/module/dmabuf_sync/parameters/enabled", O_RDONLY);
1422 length = read(fp, buf, 1);
1424 if (length == 1 && buf[0] == '1')
1425 bufmgr_dumb->use_dma_fence = 1;
1430 bufmgr_backend = tbm_backend_alloc();
1431 if (!bufmgr_backend) {
1432 TBM_DUMB_LOG("error: Fail to create drm!\n");
1433 goto fail_alloc_backend;
1436 bufmgr_backend->priv = (void *)bufmgr_dumb;
1437 bufmgr_backend->bufmgr_deinit = tbm_dumb_bufmgr_deinit,
1438 bufmgr_backend->bo_size = tbm_dumb_bo_size,
1439 bufmgr_backend->bo_alloc = tbm_dumb_bo_alloc,
1440 bufmgr_backend->bo_free = tbm_dumb_bo_free,
1441 bufmgr_backend->bo_import = tbm_dumb_bo_import,
1442 bufmgr_backend->bo_import_fd = tbm_dumb_bo_import_fd,
1443 bufmgr_backend->bo_export = tbm_dumb_bo_export,
1444 bufmgr_backend->bo_export_fd = tbm_dumb_bo_export_fd,
1445 bufmgr_backend->bo_get_handle = tbm_dumb_bo_get_handle,
1446 bufmgr_backend->bo_map = tbm_dumb_bo_map,
1447 bufmgr_backend->bo_unmap = tbm_dumb_bo_unmap,
1448 bufmgr_backend->surface_get_plane_data = tbm_dumb_surface_get_plane_data;
1449 bufmgr_backend->surface_supported_format = tbm_dumb_surface_supported_format;
1450 bufmgr_backend->bo_get_flags = tbm_dumb_bo_get_flags;
1451 bufmgr_backend->bo_lock = tbm_dumb_bo_lock;
1452 bufmgr_backend->bo_unlock = tbm_dumb_bo_unlock;
1453 bufmgr_backend->bufmgr_bind_native_display = tbm_dumb_bufmgr_bind_native_display;
1455 if (!tbm_backend_init(bufmgr, bufmgr_backend)) {
1456 TBM_DUMB_LOG("error: Fail to init backend!\n");
1457 goto fail_init_backend;
1463 env = getenv("TBM_DUMB_DEBUG");
1466 TBM_DUMB_LOG("TBM_DUMB_DEBUG=%s\n", env);
1472 DBG("[%s] DMABUF FENCE is %s\n", target_name(),
1473 bufmgr_dumb->use_dma_fence ? "supported!" : "NOT supported!");
1475 DBG("[%s] drm_fd:%d\n", target_name(), bufmgr_dumb->fd);
1480 tbm_backend_free(bufmgr_backend);
1482 if (bufmgr_dumb->hashBos)
1483 drmHashDestroy(bufmgr_dumb->hashBos);
1484 if (bufmgr_dumb->device_name)
1485 free(bufmgr_dumb->device_name);
1487 fail_get_device_name:
1488 if (tbm_backend_is_display_server())
1489 tbm_drm_helper_unset_tbm_master_fd();
1490 if (bufmgr_dumb->fd >= 0)
1491 close(bufmgr_dumb->fd);