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