add tbm bo allocation for tizen waylandsink
[platform/adaptation/nexell/nx-video-api.git] / src / nx_video_alloc.c
1 /*
2  * Copyright (C) 2016  Nexell Co., Ltd.
3  * Author: SeongO, Park <ray@nexell.co.kr>
4  */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <stdint.h>
11 #include <errno.h>
12 #include <stdarg.h>
13 #include <ctype.h>
14 #include <string.h>
15 #include <strings.h>
16
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/ioctl.h>
20 #include <sys/mman.h>           //      PROT_READ/PROT_WRITE/MAP_SHARED/mmap/munmap
21
22 #include <nexell/nexell_drm.h>
23 #include <nx_video_alloc.h>
24
25 #include <libdrm/drm_fourcc.h>
26 #include <linux/videodev2.h>
27 #include <linux/videodev2_nxp_media.h>
28 #ifdef TIZEN_FEATURE_ARTIK530
29 #include <tbm_bufmgr.h>
30 #endif
31
32 #define DRM_DEVICE_NAME "/dev/dri/card0"
33
34 #define DRM_IOCTL_NR(n)         _IOC_NR(n)
35 #define DRM_IOC_VOID            _IOC_NONE
36 #define DRM_IOC_READ            _IOC_READ
37 #define DRM_IOC_WRITE           _IOC_WRITE
38 #define DRM_IOC_READWRITE       _IOC_READ|_IOC_WRITE
39 #define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
40
41 static int
42 drm_ioctl (int32_t drm_fd, uint32_t request, void *arg)
43 {
44   int ret;
45
46   do {
47     ret = ioctl (drm_fd, request, arg);
48   } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
49   return ret;
50 }
51
52 static int
53 drm_command_write_read (int fd, uint32_t command_index,
54     void *data, uint32_t size)
55 {
56   uint32_t request;
57
58   request = DRM_IOC (DRM_IOC_READ | DRM_IOC_WRITE, DRM_IOCTL_BASE,
59       DRM_COMMAND_BASE + command_index, size);
60   if (drm_ioctl (fd, request, data))
61     return -errno;
62   return 0;
63 }
64
65 /**
66  * return gem_fd
67  */
68 static int
69 alloc_gem (int drm_fd, int size, int flags)
70 {
71   struct nx_drm_gem_create arg = { 0, };
72   int ret;
73
74   arg.size = (uint32_t) size;
75   arg.flags = flags;
76
77   ret = drm_command_write_read (drm_fd, DRM_NX_GEM_CREATE, &arg, sizeof (arg));
78   if (ret) {
79     perror ("drm_command_write_read\n");
80     return ret;
81   }
82   //printf("[DRM ALLOC] gem %d, size %d, flags 0x%x\n", arg.handle, size, flags);
83
84   return arg.handle;
85 }
86
87 static void
88 free_gem (int drm_fd, int gem)
89 {
90   struct drm_gem_close arg = { 0, };
91
92   arg.handle = gem;
93   drm_ioctl (drm_fd, DRM_IOCTL_GEM_CLOSE, &arg);
94 }
95
96 /**
97  * return dmabuf fd
98  */
99 static int
100 gem_to_dmafd (int drm_fd, int gem_fd)
101 {
102   int ret;
103   struct drm_prime_handle arg = { 0, };
104
105   arg.handle = gem_fd;
106   arg.flags = O_CLOEXEC | O_RDWR;
107   ret = drm_ioctl (drm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg);
108   if (0 != ret) {
109     printf ("fail : get fd from gem:%d (DRM_IOCTL_PRIME_HANDLE_TO_FD)\n", ret);
110     return -1;
111   }
112   return arg.fd;
113 }
114
115 static uint32_t
116 get_flink_name (int fd, int gem)
117 {
118   struct drm_gem_flink arg = { 0, };
119
120   arg.handle = gem;
121   if (drm_ioctl (fd, DRM_IOCTL_GEM_FLINK, &arg)) {
122     printf ("fail : get flink from gem:%d (DRM_IOCTL_GEM_FLINK)\n", gem);
123     return 0;
124   }
125   return arg.name;
126 }
127
128 static uint32_t
129 gem_from_flink (int fd, uint32_t flink_name)
130 {
131   struct drm_gem_open arg = { 0, };
132   /* struct nx_drm_gem_info info = { 0, }; */
133
134   arg.name = flink_name;
135   if (drm_ioctl (fd, DRM_IOCTL_GEM_OPEN, &arg)) {
136     printf ("fail : cannot open gem name=%d\n", flink_name);
137     return -EINVAL;
138   }
139   return arg.handle;
140 }
141
142
143 //
144 //      Nexell Private Video Memory Allocator for DRM
145 //
146
147 #ifndef ALIGN
148 #define ALIGN(X,N)      ( (X+N-1) & (~(N-1)) )
149 #endif
150
151 #define ALIGNED16(X)    ALIGN(X,16)
152
153
154 //      Nexell Private Memory Allocator
155 NX_MEMORY_INFO *
156 NX_AllocateMemory (int size, int align)
157 {
158   int gemFd = -1;
159   int dmaFd = -1;
160   int32_t flags = 0;
161   NX_MEMORY_INFO *pMem;
162
163   int drmFd = open (DRM_DEVICE_NAME, O_RDWR);
164   if (drmFd < 0)
165     return NULL;
166
167   drmDropMaster (drmFd);
168
169   gemFd = alloc_gem (drmFd, size, flags);
170   if (gemFd < 0)
171     goto ErrorExit;
172
173   dmaFd = gem_to_dmafd (drmFd, gemFd);
174   if (dmaFd < 0)
175     goto ErrorExit;
176
177   pMem = (NX_MEMORY_INFO *) calloc (1, sizeof (NX_MEMORY_INFO));
178   pMem->drmFd = drmFd;
179   pMem->dmaFd = dmaFd;
180   pMem->gemFd = gemFd;
181   pMem->flink = get_flink_name (drmFd, gemFd);
182   pMem->size = size;
183   pMem->align = align;
184   return pMem;
185
186 ErrorExit:
187   if (gemFd > 0) {
188     free_gem (drmFd, gemFd);
189   }
190   if (drmFd > 0)
191     close (drmFd);
192   return NULL;
193 }
194
195 void
196 NX_FreeMemory (NX_MEMORY_INFO * pMem)
197 {
198   if (pMem) {
199     if (pMem->pBuffer) {
200       munmap (pMem->pBuffer, pMem->size);
201     }
202
203     free_gem (pMem->drmFd, pMem->gemFd);
204     close (pMem->dmaFd);
205     close (pMem->drmFd);
206     free (pMem);
207   }
208 }
209
210
211 //      Video Specific Allocator Wrapper
212 //
213 //      Suport Format & Planes
214 //              YUV420 Format :
215 //                      1 Plane : I420, NV12
216 //                      2 Plane : NV12
217 //                      3 Plane : I420
218 //
219 NX_VID_MEMORY_INFO *
220 NX_AllocateVideoMemory (int width, int height, int32_t planes, uint32_t format,
221     int align)
222 {
223   int gemFd[NX_MAX_PLANES] = { 0, };
224   int dmaFd[NX_MAX_PLANES] = { 0, };
225   int32_t flags = 0, i = 0;
226   int32_t luStride, cStride;
227   int32_t luVStride, cVStride;
228   int32_t stride[NX_MAX_PLANES];
229   int32_t size[NX_MAX_PLANES];
230   uint32_t flink[NX_MAX_PLANES];
231
232   NX_VID_MEMORY_INFO *pVidMem;
233
234   int drmFd = open (DRM_DEVICE_NAME, O_RDWR);
235   if (drmFd < 0)
236     return NULL;
237
238   drmDropMaster (drmFd);
239
240   //      Luma
241   luStride = ALIGN (width, 32);
242   luVStride = ALIGN (height, 16);
243
244   //      Chroma
245   switch (format) {
246     case DRM_FORMAT_YUV420:
247     case DRM_FORMAT_NV12:
248     case DRM_FORMAT_NV21:
249     case V4L2_PIX_FMT_YUV420M:
250     case V4L2_PIX_FMT_NV12M:
251     case V4L2_PIX_FMT_NV21M:
252       cStride = luStride / 2;
253       cVStride = ALIGN (height / 2, 16);
254       break;
255
256     case DRM_FORMAT_YUV422:
257     case DRM_FORMAT_NV16:
258     case DRM_FORMAT_NV61:
259     case V4L2_PIX_FMT_YUV422M:
260 #if 0                           // Disabled by DIGNSYS
261     case V4L2_PIX_FMT_NV16M:
262     case V4L2_PIX_FMT_NV61M:
263 #endif
264       cStride = luStride / 2;
265       cVStride = luVStride;
266       break;
267
268     case DRM_FORMAT_YUV444:
269       //case DRM_FORMAT_NV24:
270       //case DRM_FORMAT_NV42:
271     case V4L2_PIX_FMT_YUV444M:
272     case V4L2_PIX_FMT_NV24M:
273     case V4L2_PIX_FMT_NV42M:
274       cStride = luStride;
275       cVStride = luVStride;
276       break;
277
278     case V4L2_PIX_FMT_GREY:
279       cStride = 0;
280       cVStride = 0;
281       break;
282     default:
283       printf ("Unknown format type\n");
284       goto ErrorExit;
285   }
286
287   //      Decide Memory Size
288   switch (planes) {
289     case 1:
290       size[0] = luStride * luVStride + cStride * cVStride * 2;
291       stride[0] = luStride;
292       gemFd[0] = alloc_gem (drmFd, size[0], flags);
293       if (gemFd[0] < 0)
294         goto ErrorExit;
295       dmaFd[0] = gem_to_dmafd (drmFd, gemFd[0]);
296       if (dmaFd[0] < 0)
297         goto ErrorExit;
298       flink[0] = get_flink_name (drmFd, gemFd[0]);
299       break;
300     case 2:
301       //      Buffer 1
302       size[0] = luStride * luVStride;
303       stride[0] = luStride;
304       gemFd[0] = alloc_gem (drmFd, size[0], flags);
305       if (gemFd[0] < 0)
306         goto ErrorExit;
307       dmaFd[0] = gem_to_dmafd (drmFd, gemFd[0]);
308       if (dmaFd[0] < 0)
309         goto ErrorExit;
310       flink[0] = get_flink_name (drmFd, gemFd[0]);
311
312       //      Buffer 2
313       size[1] = cStride * cVStride * 2;
314       stride[1] = cStride * 2;
315       gemFd[1] = alloc_gem (drmFd, size[1], flags);
316       if (gemFd[1] < 0)
317         goto ErrorExit;
318       dmaFd[1] = gem_to_dmafd (drmFd, gemFd[1]);
319       if (dmaFd[1] < 0)
320         goto ErrorExit;
321       flink[1] = get_flink_name (drmFd, gemFd[1]);
322       break;
323     case 3:
324       //      Buffer 1
325       size[0] = luStride * luVStride;
326       stride[0] = luStride;
327       gemFd[0] = alloc_gem (drmFd, size[0], flags);
328       if (gemFd[0] < 0)
329         goto ErrorExit;
330       dmaFd[0] = gem_to_dmafd (drmFd, gemFd[0]);
331       if (dmaFd[0] < 0)
332         goto ErrorExit;
333       flink[0] = get_flink_name (drmFd, gemFd[0]);
334
335       //      Buffer 2
336       size[1] = cStride * cVStride;
337       stride[1] = cStride;
338       gemFd[1] = alloc_gem (drmFd, size[1], flags);
339       if (gemFd[1] < 0)
340         goto ErrorExit;
341       dmaFd[1] = gem_to_dmafd (drmFd, gemFd[1]);
342       if (dmaFd[1] < 0)
343         goto ErrorExit;
344       flink[1] = get_flink_name (drmFd, gemFd[1]);
345
346       //      Buffer 3
347       size[2] = cStride * cVStride;
348       stride[2] = cStride;
349       gemFd[2] = alloc_gem (drmFd, size[2], flags);
350       if (gemFd[2] < 0)
351         goto ErrorExit;
352       dmaFd[2] = gem_to_dmafd (drmFd, gemFd[2]);
353       if (dmaFd[2] < 0)
354         goto ErrorExit;
355       flink[2] = get_flink_name (drmFd, gemFd[2]);
356       break;
357       break;
358   }
359
360   pVidMem = (NX_VID_MEMORY_INFO *) calloc (1, sizeof (NX_VID_MEMORY_INFO));
361   if (!pVidMem)
362     goto ErrorExit;
363
364 #ifdef TIZEN_FEATURE_ARTIK530
365   pVidMem->bufmgr = tbm_bufmgr_init (drmFd);
366   if (!pVidMem->bufmgr)
367     goto ErrorExit;
368 #endif
369
370   pVidMem->width = width;
371   pVidMem->height = height;
372   pVidMem->align = align;
373   pVidMem->planes = planes;
374   pVidMem->format = format;
375   pVidMem->drmFd = drmFd;
376   for (i = 0; i < planes; i++) {
377     pVidMem->dmaFd[i] = dmaFd[i];
378     pVidMem->gemFd[i] = gemFd[i];
379     pVidMem->size[i] = size[i];
380     pVidMem->stride[i] = stride[i];
381     pVidMem->flink[i] = flink[i];
382 #ifdef TIZEN_FEATURE_ARTIK530
383     pVidMem->bo[i] = tbm_bo_import (pVidMem->bufmgr, flink[i]);
384     if (!pVidMem->bo[i])
385       goto alloc_bo_fail;
386 #endif
387   }
388   return pVidMem;
389
390 #ifdef TIZEN_FEATURE_ARTIK530
391 alloc_bo_fail:
392   for (i = 0; i < planes; i++) {
393     if (pVidMem->bo[i])
394       tbm_bo_unref (pVidMem->bo[i]);
395   }
396 #endif
397
398 ErrorExit:
399   for (i = 0; i < planes; i++) {
400     if (gemFd[i] > 0) {
401       free_gem (drmFd, gemFd[i]);
402     }
403     if (dmaFd[i] > 0) {
404       close (dmaFd[i]);
405     }
406   }
407   if (pVidMem) {
408 #ifdef TIZEN_FEATURE_ARTIK530
409     if (pVidMem->bufmgr)
410       tbm_bufmgr_deinit (pVidMem->bufmgr);
411 #endif
412     free(pVidMem);
413   }
414   if (drmFd > 0)
415     close (drmFd);
416
417   return NULL;
418 }
419
420 void
421 NX_FreeVideoMemory (NX_VID_MEMORY_INFO * pMem)
422 {
423   int32_t i;
424   if (pMem) {
425     for (i = 0; i < pMem->planes; i++) {
426 #ifdef TIZEN_FEATURE_ARTIK530
427       if (pMem->bo[i])
428         tbm_bo_unref (pMem->bo[i]);
429 #endif
430       if (pMem->pBuffer[i]) {
431         munmap (pMem->pBuffer[i], pMem->size[i]);
432       }
433       free_gem (pMem->drmFd, pMem->gemFd[i]);
434       close (pMem->dmaFd[i]);
435     }
436 #ifdef TIZEN_FEATURE_ARTIK530
437     if (pMem->bufmgr)
438       tbm_bufmgr_deinit (pMem->bufmgr);
439 #endif
440     close (pMem->drmFd);
441     free (pMem);
442   }
443 }
444
445
446 //
447 //              Memory Mapping/Unmapping Memory
448 //
449 int
450 NX_MapMemory (NX_MEMORY_INFO * pMem)
451 {
452   void *pBuf;
453   if (!pMem)
454     return -1;
455
456   //      Already Mapped
457   if (pMem->pBuffer)
458     return -1;
459
460   pBuf =
461       mmap (0, pMem->size, PROT_READ | PROT_WRITE, MAP_SHARED, pMem->dmaFd, 0);
462   if (pBuf == MAP_FAILED) {
463     printf("Map failed : size %d, fd %d, error : %s\n", pMem->size, pMem->dmaFd, strerror(errno));
464     return -1;
465   }
466   pMem->pBuffer = pBuf;
467   return 0;
468 }
469
470
471 int
472 NX_UnmapMemory (NX_MEMORY_INFO * pMem)
473 {
474   if (!pMem)
475     return -1;
476
477   if (!pMem->pBuffer)
478     return -1;
479
480   if (0 != munmap (pMem->pBuffer, pMem->size))
481     return -1;
482
483   pMem->pBuffer = NULL;
484   return 0;
485 }
486
487 int
488 NX_MapVideoMemory (NX_VID_MEMORY_INFO * pMem)
489 {
490   int32_t i;
491   void *pBuf;
492   if (!pMem)
493     return -1;
494
495   //      Already Mapped
496   for (i = 0; i < pMem->planes; i++) {
497     if (pMem->pBuffer[i])
498       return -1;
499     else {
500       pBuf =
501           mmap (0, pMem->size[i], PROT_READ | PROT_WRITE, MAP_SHARED,
502           pMem->dmaFd[i], 0);
503       if (pBuf == MAP_FAILED) {
504         return -1;
505       }
506     }
507     pMem->pBuffer[i] = pBuf;
508   }
509   return 0;
510 }
511
512 int
513 NX_UnmapVideoMemory (NX_VID_MEMORY_INFO * pMem)
514 {
515   int32_t i;
516   if (!pMem)
517     return -1;
518   for (i = 0; i < pMem->planes; i++) {
519     if (pMem->pBuffer[i]) {
520       munmap (pMem->pBuffer[i], pMem->size[i]);
521     } else
522       return -1;
523   }
524   return 0;
525 }
526
527 int
528 NX_GetGEMHandles (int drmFd, NX_VID_MEMORY_INFO * pMem,
529     uint32_t handles[NX_MAX_PLANES])
530 {
531   int32_t i;
532   memset (handles, 0, sizeof (uint32_t) * NX_MAX_PLANES);
533
534   for (i = 0; i < pMem->planes; i++) {
535     handles[i] = gem_from_flink (drmFd, pMem->flink[i]);
536     if (0 > (int) handles[i]) {
537       return -1;
538     }
539   }
540   return 0;
541 }
542
543 int
544 NX_GetGemHandle (int drmFd, NX_VID_MEMORY_INFO * pMem, int32_t plane)
545 {
546   if (plane >= NX_MAX_PLANES || plane < 0)
547     return -1;
548
549   return gem_from_flink (drmFd, pMem->flink[plane]);
550 }