tbm_sync: bug fix timeline create and fence create
[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_handle->fd = fd;
165                         timeline = timeline_handle;
166                 }
167         }
168
169 done:
170         if (error)
171                 *error = ret;
172
173         _tbm_sync_mutex_unlock();
174
175         return timeline;
176 }
177
178 tbm_sync_error_e
179 tbm_sync_timeline_destroy(tbm_sync_timeline_h timeline)
180 {
181         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
182
183         _tbm_sync_mutex_lock();
184
185         /* check the tbm_sync capability */
186         ret = _tbm_sync_check_capability();;
187         if (ret != TBM_SYNC_ERROR_NONE)
188                 goto done;
189
190         if (timeline) {
191                 struct _tbm_sync_timeline *timeline_handle = timeline;
192
193                 if (timeline_handle->fd != -1)
194                         close(timeline_handle->fd);
195                 free(timeline);
196         } else {
197                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
198         }
199
200 done:
201         _tbm_sync_mutex_unlock();
202
203     return ret;
204 }
205
206 tbm_sync_timeline_h
207 tbm_sync_timeline_import(int fd, tbm_sync_error_e *error)
208 {
209         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
210         tbm_sync_timeline_h timeline = NULL;
211
212         _tbm_sync_mutex_lock();
213
214         /* check the tbm_sync capability */
215         ret = _tbm_sync_check_capability();;
216         if (ret != TBM_SYNC_ERROR_NONE)
217                 goto done;
218
219         if (fd < 0) {
220                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
221         } else {
222                 struct _tbm_sync_timeline *timeline_handle =
223                         calloc(1, sizeof(struct _tbm_sync_timeline));
224
225                 if (timeline_handle == NULL) {
226                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
227                         TBM_LOG_E("%s\n", "TBM_SYNC calloc failed");
228                 } else {
229                         timeline_handle->fd = fd;
230                         timeline = timeline_handle;
231                 }
232         }
233
234 done:
235         if (error)
236                 *error = ret;
237
238         _tbm_sync_mutex_unlock();
239
240         return timeline;
241 }
242
243 int
244 tbm_sync_timeline_export(tbm_sync_timeline_h timeline, tbm_sync_error_e *error)
245 {
246         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
247         int fd = -1;
248
249         _tbm_sync_mutex_lock();
250
251         /* check the tbm_sync capability */
252         ret = _tbm_sync_check_capability();;
253         if (ret != TBM_SYNC_ERROR_NONE)
254                 goto done;
255
256         if (timeline) {
257                 struct _tbm_sync_timeline *timeline_handle = timeline;
258                 fd = dup(timeline_handle->fd);
259                 if (fd == -1) {
260                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
261                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC timeline dup failed",
262                                           errno, strerror(errno));
263                 }
264         } else {
265                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
266         }
267
268 done:
269         if (error)
270                 *error = ret;
271
272         _tbm_sync_mutex_unlock();
273
274         return fd;
275 }
276
277 tbm_sync_error_e
278 tbm_sync_timeline_increase_count(tbm_sync_timeline_h timeline, unsigned int interval)
279 {
280         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
281
282         _tbm_sync_mutex_lock();
283
284         /* check the tbm_sync capability */
285         ret = _tbm_sync_check_capability();;
286         if (ret != TBM_SYNC_ERROR_NONE)
287                 goto done;
288
289         if (timeline) {
290                 struct _tbm_sync_timeline *timeline_handle = timeline;
291                 __u32 arg = interval;
292
293                 if (ioctl(timeline_handle->fd, SW_SYNC_IOC_INC, &arg) == -1) {
294                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
295                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC timeline inc failed", errno, strerror(errno));
296                 }
297         } else {
298                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
299         }
300
301 done:
302         _tbm_sync_mutex_unlock();
303
304         return ret;
305 }
306
307 unsigned int
308 tbm_sync_timeline_get_cur_count(tbm_sync_timeline_h timeline, tbm_sync_error_e *error)
309 {
310         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
311         unsigned int cur_count = 0;
312
313         _tbm_sync_mutex_lock();
314
315         /* check the tbm_sync capability */
316         ret = _tbm_sync_check_capability();;
317         if (ret != TBM_SYNC_ERROR_NONE)
318                 goto done;
319
320         /* TODO: sync_timeline_get_cur_count */
321
322 done:
323         if (error)
324                 *error = ret;
325
326         _tbm_sync_mutex_unlock();
327
328         return cur_count;
329 }
330
331 tbm_sync_fence_h
332 tbm_sync_fence_create(tbm_sync_timeline_h timeline, const char *name, unsigned int count_val, tbm_sync_error_e *error)
333 {
334         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
335         tbm_sync_fence_h fence = NULL;
336
337         _tbm_sync_mutex_lock();
338
339         /* check the tbm_sync capability */
340         ret = _tbm_sync_check_capability();;
341         if (ret != TBM_SYNC_ERROR_NONE)
342                 goto done;
343
344         if (timeline) {
345                 struct _tbm_sync_timeline *timeline_handle = timeline;
346                 struct sw_sync_create_fence_data {
347                         __u32 value;
348                         char name[32];
349                         __s32 fence;
350                 } data;
351
352                 data.value = count_val;
353                 strncpy(data.name, name ? name : "", 32);
354                 data.name[31] = '\0';
355
356                 if (ioctl(timeline_handle->fd, SW_SYNC_IOC_CREATE_FENCE, &data) == -1) {
357                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
358                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC create fence failed",
359                                           errno, strerror(errno));
360                 } else {
361                         struct _tbm_sync_fence *fence_handle =
362                                 calloc(1, sizeof(struct _tbm_sync_fence));
363
364                         if (fence_handle == NULL) {
365                                 ret = TBM_SYNC_ERROR_INVALID_OPERATION;
366                                 TBM_LOG_E("%s\n", "TBM_SYNC calloc failed");
367                                 close(data.fence);
368                         } else {
369                                 fence_handle->fd = data.fence;
370                                 fence = fence_handle;
371                         }
372                 }
373         } else {
374                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
375         }
376
377 done:
378         if (error)
379                 *error = ret;
380
381         _tbm_sync_mutex_unlock();
382
383         return fence;
384 }
385
386 tbm_sync_error_e
387 tbm_sync_fence_destroy(tbm_sync_fence_h fence)
388 {
389         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
390
391         _tbm_sync_mutex_lock();
392
393         /* check the tbm_sync capability */
394         ret = _tbm_sync_check_capability();;
395         if (ret != TBM_SYNC_ERROR_NONE)
396                 goto done;
397
398         if (fence) {
399                 struct _tbm_sync_fence *fence_handle = fence;
400
401                 if (fence_handle->fd != -1)
402                         close(fence_handle->fd);
403                 free(fence);
404         }
405
406 done:
407         _tbm_sync_mutex_unlock();
408
409         return ret;
410 }
411
412 tbm_sync_error_e
413 tbm_sync_fence_wait(tbm_sync_fence_h fence, int timeout)
414 {
415         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
416
417         _tbm_sync_mutex_lock();
418
419         /* check the tbm_sync capability */
420         ret = _tbm_sync_check_capability();;
421         if (ret != TBM_SYNC_ERROR_NONE)
422                 goto done;
423
424         if (fence) {
425                 struct _tbm_sync_fence *fence_handle = fence;
426                 __s32 to = timeout;
427
428                 if (ioctl(fence_handle->fd, SYNC_IOC_WAIT, &to) == -1) {
429                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
430                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC fence wait failed", errno, strerror(errno));
431                 }
432         } else {
433                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
434         }
435
436 done:
437         _tbm_sync_mutex_unlock();
438
439         return ret;
440 }
441
442 tbm_sync_fence_h
443 tbm_sync_fence_merge(tbm_sync_fence_h fence1, tbm_sync_fence_h fence2, const char *name, tbm_sync_error_e *error)
444 {
445         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
446         tbm_sync_fence_h fence = NULL;
447
448         _tbm_sync_mutex_lock();
449
450         /* check the tbm_sync capability */
451         ret = _tbm_sync_check_capability();;
452         if (ret != TBM_SYNC_ERROR_NONE)
453                 goto done;
454
455         if (fence1 && fence2) {
456                 struct _tbm_sync_fence *fence_handle1 = fence1;
457                 struct _tbm_sync_fence *fence_handle2 = fence2;
458
459                 struct sync_merge_data {
460                         __s32 fd2;
461                         char name[32];
462                         __s32 fence;
463                 } data;
464
465                 data.fd2 = fence_handle2->fd;
466                 strncpy(data.name, name ? name : "", 32);
467                 data.name[31] = '\0';
468
469                 if (ioctl(fence_handle1->fd, SYNC_IOC_MERGE, &data) == -1) {
470                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
471                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC fence merge failed",
472                                           errno, strerror(errno));
473                 } else {
474                         struct _tbm_sync_fence *fence_handle =
475                                 calloc(1, sizeof(struct _tbm_sync_fence));
476
477                         if (fence_handle == NULL) {
478                                 ret = TBM_SYNC_ERROR_INVALID_OPERATION;
479                                 TBM_LOG_E("%s\n", "TBM_SYNC calloc failed");
480                                 close(data.fence);
481                         } else {
482                                 fence_handle->fd = data.fence;
483                         }
484                 }
485         } else {
486                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
487         }
488
489 done:
490         if (error)
491                 *error = ret;
492
493         _tbm_sync_mutex_unlock();
494
495         return fence;
496 }
497
498 unsigned int
499 tbm_sync_fence_get_count_val(tbm_sync_fence_h fence, tbm_sync_error_e *error)
500 {
501         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
502         unsigned int count_val = 0;
503
504         _tbm_sync_mutex_lock();
505
506         /* check the tbm_sync capability */
507         ret = _tbm_sync_check_capability();;
508         if (ret != TBM_SYNC_ERROR_NONE)
509                 goto done;
510
511         /* TODO: sync_fence_get_count_val */
512
513 done:
514         if (error)
515                 *error = ret;
516
517         _tbm_sync_mutex_unlock();
518
519         return count_val;
520 }
521
522 tbm_sync_fence_h
523 tbm_sync_fence_import(int fd, tbm_sync_error_e *error)
524 {
525         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
526         tbm_sync_fence_h fence = NULL;
527
528         _tbm_sync_mutex_lock();
529
530         /* check the tbm_sync capability */
531         ret = _tbm_sync_check_capability();;
532         if (ret != TBM_SYNC_ERROR_NONE)
533                 goto done;
534
535         if (fd < 0) {
536                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
537         } else {
538                 struct _tbm_sync_fence *fence_handle =
539                         calloc(1, sizeof(struct _tbm_sync_fence));
540
541                 if (fence_handle == NULL) {
542                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
543                         TBM_LOG_E("%s\n", "TBM_SYNC calloc failed");
544                 } else {
545                         fence_handle->fd = fd;
546                         fence = fence_handle;
547                 }
548         }
549
550 done:
551         if (error)
552                 *error = ret;
553
554         _tbm_sync_mutex_unlock();
555
556         return fence;
557 }
558
559 int
560 tbm_sync_fence_export(tbm_sync_fence_h fence, tbm_sync_error_e *error)
561 {
562         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
563         int fd = -1;
564
565         _tbm_sync_mutex_lock();
566
567         /* check the tbm_sync capability */
568         ret = _tbm_sync_check_capability();;
569         if (ret != TBM_SYNC_ERROR_NONE)
570                 goto done;
571
572         if (fence) {
573                 struct _tbm_sync_fence *fence_handle = fence;
574                 fd = dup(fence_handle->fd);
575                 if (fd == -1) {
576                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
577                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC fence dup failed",
578                                           errno, strerror(errno));
579                 }
580         } else {
581                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
582         }
583
584 done:
585         if (error)
586                 *error = ret;
587
588         _tbm_sync_mutex_unlock();
589
590         return fd;
591 }