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