1f680c8d6dce546833435e6dcdc503a9ac3ce70a
[platform/core/uifw/libtbm.git] / src / tbm_sync.c
1 /**************************************************************************
2
3 libtbm
4
5 Copyright 2012 - 2016 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>,
8          Changyeon Lee <cyeon.lee@samsung.com>,
9                  Boram Park <boram1288.park@samsung.com>,
10                  Sangjin Lee <lsj119@samsung.com>
11
12 Permission is hereby granted, free of charge, to any person obtaining a
13 copy of this software and associated documentation files (the
14 "Software"), to deal in the Software without restriction, including
15 without limitation the rights to use, copy, modify, merge, publish,
16 distribute, sub license, and/or sell copies of the Software, and to
17 permit persons to whom the Software is furnished to do so, subject to
18 the following conditions:
19
20 The above copyright notice and this permission notice (including the
21 next paragraph) shall be included in all copies or substantial portions
22 of the Software.
23
24 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
27 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
28 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
32 **************************************************************************/
33
34 #include "tbm_bufmgr.h"
35 #include "tbm_bufmgr_int.h"
36 #include "tbm_sync.h"
37
38 #include <string.h>
39 #include <errno.h>
40 #include <sys/ioctl.h>
41 #include <linux/types.h>
42
43 #define SYNC_IOC_MAGIC               '>'
44 #define SYNC_IOC_WAIT                _IOW(SYNC_IOC_MAGIC, 0, __s32)
45 #define SYNC_IOC_MERGE               _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data)
46 #define SW_SYNC_IOC_MAGIC            'W'
47 #define SW_SYNC_IOC_CREATE_FENCE     _IOWR(SW_SYNC_IOC_MAGIC, 0,\
48                                          struct sw_sync_create_fence_data)
49 #define SW_SYNC_IOC_INC              _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
50
51 #define SYNC_DEVICE_PATH             "/dev/sw_sync"
52
53 struct _tbm_sync_timeline {
54         int fd;
55 };
56
57 struct _tbm_sync_fence {
58         int fd;
59 };
60
61 static pthread_mutex_t tbm_sync_lock;
62 static int tbm_sync_support = 0;
63
64 static bool
65 _tbm_sync_mutex_init(void)
66 {
67         static bool tbm_sync_mutex_init = false;
68
69         if (tbm_sync_mutex_init)
70                 return true;
71
72         if (pthread_mutex_init(&tbm_sync_lock, NULL)) {
73                 TBM_LOG_E("fail: tbm_sync mutex init\n");
74                 return false;
75         }
76
77         tbm_sync_mutex_init = true;
78
79         return true;
80 }
81
82 static void
83 _tbm_sync_mutex_lock(void)
84 {
85         if (!_tbm_sync_mutex_init())
86                 return;
87
88         pthread_mutex_lock(&tbm_sync_lock);
89 }
90
91 static void
92 _tbm_sync_mutex_unlock(void)
93 {
94         pthread_mutex_unlock(&tbm_sync_lock);
95 }
96
97 static tbm_sync_error_e
98 _tbm_sync_check_capability(void)
99 {
100 #ifdef NOT_IMPELMENT_YET
101         tbm_bufmgr bufmgr = NULL;
102         unsigned int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
103 #endif
104         struct stat st_buf;
105
106     if (tbm_sync_support)
107                 return TBM_SYNC_ERROR_NONE;
108
109 #ifdef NOT_IMPELMENT_YET
110         /* check the bufmgr */
111         bufmgr = _tbm_bufmgr_get_bufmgr();
112         if (!bufmgr) {
113                 return TBM_SYNC_ERROR_INVALID_OPERATION;
114         }
115
116         /* check the tbm_sync capability */
117         capabilities = tbm_bufmgr_get_capability(bufmgr);
118
119         if ((capabilities&TBM_BUFMGR_CAPABILITY_TBM_SYNC) != TBM_BUFMGR_CAPABILITY_TBM_SYNC) {
120                 //TODO: check the sw_sync device node... to verify the timeline sync
121                 tbm_sync_support = 1;
122
123                 return TBM_SYNC_ERROR_INVALID_OPERATION;
124         }
125 #endif
126
127         if (stat(SYNC_DEVICE_PATH, &st_buf) == 0) {
128                 tbm_sync_support = 1;
129         } else {
130                 TBM_LOG_E("TBM_SYNC not supported\n");
131                 return TBM_SYNC_ERROR_INVALID_OPERATION;
132         }
133
134         return TBM_SYNC_ERROR_NONE;
135 }
136
137 tbm_sync_timeline_h
138 tbm_sync_timeline_create(tbm_sync_error_e *error)
139 {
140         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
141         tbm_sync_timeline_h timeline = NULL;
142         int fd;
143
144         _tbm_sync_mutex_lock();
145
146         /* check the tbm_sync capability */
147         ret = _tbm_sync_check_capability();;
148         if (ret != TBM_SYNC_ERROR_NONE)
149                 goto done;
150
151         fd = open(SYNC_DEVICE_PATH, O_RDWR);
152         if (fd < 0) {
153                 ret = TBM_SYNC_ERROR_INVALID_OPERATION;
154                 TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC open failed", errno, strerror(errno));
155         } else {
156                 struct _tbm_sync_timeline *timeline_handle =
157                         calloc(1, sizeof(struct _tbm_sync_timeline));
158
159                 if (timeline_handle == NULL) {
160                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
161                         TBM_LOG_E("%s\n", "TBM_SYNC calloc failed");
162                         close(fd);
163                 } else {
164                         timeline = timeline_handle;
165                 }
166         }
167
168 done:
169         if (error)
170                 *error = ret;
171
172         _tbm_sync_mutex_unlock();
173
174         return timeline;
175 }
176
177 tbm_sync_error_e
178 tbm_sync_timeline_destroy(tbm_sync_timeline_h timeline)
179 {
180         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
181
182         _tbm_sync_mutex_lock();
183
184         /* check the tbm_sync capability */
185         ret = _tbm_sync_check_capability();;
186         if (ret != TBM_SYNC_ERROR_NONE)
187                 goto done;
188
189         if (timeline) {
190                 struct _tbm_sync_timeline *timeline_handle = timeline;
191
192                 if (timeline_handle->fd != -1)
193                         close(timeline_handle->fd);
194                 free(timeline);
195         } else {
196                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
197         }
198
199 done:
200         _tbm_sync_mutex_unlock();
201
202     return ret;
203 }
204
205 tbm_sync_timeline_h
206 tbm_sync_timeline_import(int fd, tbm_sync_error_e *error)
207 {
208         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
209         tbm_sync_timeline_h timeline = NULL;
210
211         _tbm_sync_mutex_lock();
212
213         /* check the tbm_sync capability */
214         ret = _tbm_sync_check_capability();;
215         if (ret != TBM_SYNC_ERROR_NONE)
216                 goto done;
217
218         if (fd < 0) {
219                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
220         } else {
221                 struct _tbm_sync_timeline *timeline_handle =
222                         calloc(1, sizeof(struct _tbm_sync_timeline));
223
224                 if (timeline_handle == NULL) {
225                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
226                         TBM_LOG_E("%s\n", "TBM_SYNC calloc failed");
227                 } else {
228                         timeline_handle->fd = fd;
229                         timeline = timeline_handle;
230                 }
231         }
232
233 done:
234         if (error)
235                 *error = ret;
236
237         _tbm_sync_mutex_unlock();
238
239         return timeline;
240 }
241
242 int
243 tbm_sync_timeline_export(tbm_sync_timeline_h timeline, tbm_sync_error_e *error)
244 {
245         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
246         int fd = -1;
247
248         _tbm_sync_mutex_lock();
249
250         /* check the tbm_sync capability */
251         ret = _tbm_sync_check_capability();;
252         if (ret != TBM_SYNC_ERROR_NONE)
253                 goto done;
254
255         if (timeline) {
256                 struct _tbm_sync_timeline *timeline_handle = timeline;
257                 fd = dup(timeline_handle->fd);
258                 if (fd == -1) {
259                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
260                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC timeline dup failed",
261                                           errno, strerror(errno));
262                 }
263         } else {
264                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
265         }
266
267 done:
268         if (error)
269                 *error = ret;
270
271         _tbm_sync_mutex_unlock();
272
273         return fd;
274 }
275
276 tbm_sync_error_e
277 tbm_sync_timeline_increase_count(tbm_sync_timeline_h timeline, unsigned int interval)
278 {
279         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
280
281         _tbm_sync_mutex_lock();
282
283         /* check the tbm_sync capability */
284         ret = _tbm_sync_check_capability();;
285         if (ret != TBM_SYNC_ERROR_NONE)
286                 goto done;
287
288         if (timeline) {
289                 struct _tbm_sync_timeline *timeline_handle = timeline;
290                 __u32 arg = interval;
291
292                 if (ioctl(timeline_handle->fd, SW_SYNC_IOC_INC, &arg) == -1) {
293                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
294                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC timeline inc failed", errno, strerror(errno));
295                 }
296         } else {
297                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
298         }
299
300 done:
301         _tbm_sync_mutex_unlock();
302
303         return ret;
304 }
305
306 unsigned int
307 tbm_sync_timeline_get_cur_count(tbm_sync_timeline_h timeline, tbm_sync_error_e *error)
308 {
309         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
310         unsigned int cur_count = 0;
311
312         _tbm_sync_mutex_lock();
313
314         /* check the tbm_sync capability */
315         ret = _tbm_sync_check_capability();;
316         if (ret != TBM_SYNC_ERROR_NONE)
317                 goto done;
318
319         /* TODO: sync_timeline_get_cur_count */
320
321 done:
322         if (error)
323                 *error = ret;
324
325         _tbm_sync_mutex_unlock();
326
327         return cur_count;
328 }
329
330 tbm_sync_fence_h
331 tbm_sync_fence_create(tbm_sync_timeline_h timeline, const char *name, unsigned int count_val, tbm_sync_error_e *error)
332 {
333         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
334         tbm_sync_fence_h fence = NULL;
335
336         _tbm_sync_mutex_lock();
337
338         /* check the tbm_sync capability */
339         ret = _tbm_sync_check_capability();;
340         if (ret != TBM_SYNC_ERROR_NONE)
341                 goto done;
342
343         if (timeline) {
344                 struct _tbm_sync_timeline *timeline_handle = timeline;
345                 struct sw_sync_create_fence_data {
346                         __u32 value;
347                         char *name;
348                         __s32 fence;
349                 } data;
350
351                 data.value = count_val;
352                 strncpy(data.name, name ? name : "", 32);
353                 data.name[31] = '\0';
354
355                 if (ioctl(timeline_handle->fd, SW_SYNC_IOC_CREATE_FENCE, &data) == -1) {
356                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
357                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC create fence failed",
358                                           errno, strerror(errno));
359                 } else {
360                         struct _tbm_sync_fence *fence_handle =
361                                 calloc(1, sizeof(struct _tbm_sync_fence));
362
363                         if (fence_handle == NULL) {
364                                 ret = TBM_SYNC_ERROR_INVALID_OPERATION;
365                                 TBM_LOG_E("%s\n", "TBM_SYNC calloc failed");
366                                 close(data.fence);
367                         } else {
368                                 fence_handle->fd = data.fence;
369                                 fence = fence_handle;
370                         }
371                 }
372         } else {
373                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
374         }
375
376 done:
377         if (error)
378                 *error = ret;
379
380         _tbm_sync_mutex_unlock();
381
382         return fence;
383 }
384
385 tbm_sync_error_e
386 tbm_sync_fence_destroy(tbm_sync_fence_h fence)
387 {
388         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
389
390         _tbm_sync_mutex_lock();
391
392         /* check the tbm_sync capability */
393         ret = _tbm_sync_check_capability();;
394         if (ret != TBM_SYNC_ERROR_NONE)
395                 goto done;
396
397         if (fence) {
398                 struct _tbm_sync_fence *fence_handle = fence;
399
400                 if (fence_handle->fd != -1)
401                         close(fence_handle->fd);
402                 free(fence);
403         }
404
405 done:
406         _tbm_sync_mutex_unlock();
407
408         return ret;
409 }
410
411 tbm_sync_error_e
412 tbm_sync_fence_wait(tbm_sync_fence_h fence, int timeout)
413 {
414         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
415
416         _tbm_sync_mutex_lock();
417
418         /* check the tbm_sync capability */
419         ret = _tbm_sync_check_capability();;
420         if (ret != TBM_SYNC_ERROR_NONE)
421                 goto done;
422
423         if (fence) {
424                 struct _tbm_sync_fence *fence_handle = fence;
425                 __s32 to = timeout;
426
427                 if (ioctl(fence_handle->fd, SYNC_IOC_WAIT, &to) == -1) {
428                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
429                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC fence wait failed", errno, strerror(errno));
430                 }
431         } else {
432                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
433         }
434
435 done:
436         _tbm_sync_mutex_unlock();
437
438         return ret;
439 }
440
441 tbm_sync_fence_h
442 tbm_sync_fence_merge(tbm_sync_fence_h fence1, tbm_sync_fence_h fence2, const char *name, tbm_sync_error_e *error)
443 {
444         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
445         tbm_sync_fence_h fence = NULL;
446
447         _tbm_sync_mutex_lock();
448
449         /* check the tbm_sync capability */
450         ret = _tbm_sync_check_capability();;
451         if (ret != TBM_SYNC_ERROR_NONE)
452                 goto done;
453
454         if (fence1 && fence2) {
455                 struct _tbm_sync_fence *fence_handle1 = fence1;
456                 struct _tbm_sync_fence *fence_handle2 = fence2;
457
458                 struct sync_merge_data {
459                         __s32 fd2;
460                         char name[32];
461                         __s32 fence;
462                 } data;
463
464                 data.fd2 = fence_handle2->fd;
465                 strncpy(data.name, name ? name : "", 32);
466                 data.name[31] = '\0';
467
468                 if (ioctl(fence_handle1->fd, SYNC_IOC_MERGE, &data) == -1) {
469                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
470                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC fence merge failed",
471                                           errno, strerror(errno));
472                 } else {
473                         struct _tbm_sync_fence *fence_handle =
474                                 calloc(1, sizeof(struct _tbm_sync_fence));
475
476                         if (fence_handle == NULL) {
477                                 ret = TBM_SYNC_ERROR_INVALID_OPERATION;
478                                 TBM_LOG_E("%s\n", "TBM_SYNC calloc failed");
479                                 close(data.fence);
480                         } else {
481                                 fence_handle->fd = data.fence;
482                         }
483                 }
484         } else {
485                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
486         }
487
488 done:
489         if (error)
490                 *error = ret;
491
492         _tbm_sync_mutex_unlock();
493
494         return fence;
495 }
496
497 unsigned int
498 tbm_sync_fence_get_count_val(tbm_sync_fence_h fence, tbm_sync_error_e *error)
499 {
500         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
501         unsigned int count_val = 0;
502
503         _tbm_sync_mutex_lock();
504
505         /* check the tbm_sync capability */
506         ret = _tbm_sync_check_capability();;
507         if (ret != TBM_SYNC_ERROR_NONE)
508                 goto done;
509
510         /* TODO: sync_fence_get_count_val */
511
512 done:
513         if (error)
514                 *error = ret;
515
516         _tbm_sync_mutex_unlock();
517
518         return count_val;
519 }
520
521 tbm_sync_fence_h
522 tbm_sync_fence_import(int fd, tbm_sync_error_e *error)
523 {
524         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
525         tbm_sync_fence_h fence = NULL;
526
527         _tbm_sync_mutex_lock();
528
529         /* check the tbm_sync capability */
530         ret = _tbm_sync_check_capability();;
531         if (ret != TBM_SYNC_ERROR_NONE)
532                 goto done;
533
534         if (fd < 0) {
535                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
536         } else {
537                 struct _tbm_sync_fence *fence_handle =
538                         calloc(1, sizeof(struct _tbm_sync_fence));
539
540                 if (fence_handle == NULL) {
541                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
542                         TBM_LOG_E("%s\n", "TBM_SYNC calloc failed");
543                 } else {
544                         fence_handle->fd = fd;
545                         fence = fence_handle;
546                 }
547         }
548
549 done:
550         if (error)
551                 *error = ret;
552
553         _tbm_sync_mutex_unlock();
554
555         return fence;
556 }
557
558 int
559 tbm_sync_fence_export(tbm_sync_fence_h fence, tbm_sync_error_e *error)
560 {
561         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
562         int fd = -1;
563
564         _tbm_sync_mutex_lock();
565
566         /* check the tbm_sync capability */
567         ret = _tbm_sync_check_capability();;
568         if (ret != TBM_SYNC_ERROR_NONE)
569                 goto done;
570
571         if (fence) {
572                 struct _tbm_sync_fence *fence_handle = fence;
573                 fd = dup(fence_handle->fd);
574                 if (fd == -1) {
575                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
576                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC fence dup failed",
577                                           errno, strerror(errno));
578                 }
579         } else {
580                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
581         }
582
583 done:
584         if (error)
585                 *error = ret;
586
587         _tbm_sync_mutex_unlock();
588
589         return fd;
590 }