Fixed a bug that could cause deadlock.
[platform/core/uifw/libtpl-egl.git] / src / tpl_wl_egl_thread.c
1 #define inline __inline__
2
3 #undef inline
4
5 #include "tpl_internal.h"
6
7 #include <string.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10
11 #include <tbm_bufmgr.h>
12 #include <tbm_surface.h>
13 #include <tbm_surface_internal.h>
14 #include <tbm_surface_queue.h>
15
16 #include "tpl_wayland_egl_thread.h"
17
18 /* In wayland, application and compositor create its own drawing buffers. Recommend size is more than 2. */
19 #define CLIENT_QUEUE_SIZE 3
20
21 typedef struct _tpl_wayland_egl_display tpl_wayland_egl_display_t;
22 typedef struct _tpl_wayland_egl_surface tpl_wayland_egl_surface_t;
23
24 struct _tpl_wayland_egl_display {
25         twe_thread *wl_egl_thread;
26         twe_display_h twe_display;
27 };
28
29 struct _tpl_wayland_egl_surface {
30         tpl_object_t base;
31         twe_surface_h twe_surface;
32         tbm_surface_queue_h tbm_queue;
33         tpl_bool_t is_activated;
34         tpl_bool_t reset; /* TRUE if queue reseted by external  */
35         tpl_bool_t need_to_enqueue;
36 };
37
38 static tpl_result_t
39 __tpl_wl_egl_display_init(tpl_display_t *display)
40 {
41         tpl_wayland_egl_display_t *wayland_egl_display = NULL;
42
43         TPL_ASSERT(display);
44
45         /* Do not allow default display in wayland. */
46         if (!display->native_handle) {
47                 TPL_ERR("Invalid native handle for display.");
48                 return TPL_ERROR_INVALID_PARAMETER;
49         }
50
51         wayland_egl_display = (tpl_wayland_egl_display_t *) calloc(1,
52                                                   sizeof(tpl_wayland_egl_display_t));
53         if (!wayland_egl_display) {
54                 TPL_ERR("Failed to allocate memory for new tpl_wayland_egl_display_t.");
55                 return TPL_ERROR_OUT_OF_MEMORY;
56         }
57
58         display->backend.data = wayland_egl_display;
59         display->bufmgr_fd = -1;
60
61         if (twe_check_native_handle_is_wl_display(display->native_handle)) {
62                 wayland_egl_display->wl_egl_thread = twe_thread_create();
63                 if (!wayland_egl_display->wl_egl_thread) {
64                         TPL_ERR("Failed to create twe_thread.");
65                         goto free_display;
66                 }
67
68                 wayland_egl_display->twe_display =
69                         twe_display_add(wayland_egl_display->wl_egl_thread,
70                                                         display->native_handle,
71                                                         display->backend.type);
72                 if (!wayland_egl_display->twe_display) {
73                         TPL_ERR("Failed to add native_display(%p) to thread(%p)",
74                                         display->native_handle,
75                                         wayland_egl_display->wl_egl_thread);
76                         goto free_display;
77                 }
78
79         } else {
80                 TPL_ERR("Invalid native handle for display.");
81                 goto free_display;
82         }
83
84         TPL_LOG_T("WL_EGL",
85                           "[INIT DISPLAY] wayland_egl_display(%p) twe_thread(%p) twe_display(%p)",
86                           wayland_egl_display,
87                           wayland_egl_display->wl_egl_thread,
88                           wayland_egl_display->twe_display);
89
90         return TPL_ERROR_NONE;
91
92 free_display:
93         if (wayland_egl_display->twe_display)
94                 twe_display_del(wayland_egl_display->twe_display);
95         if (wayland_egl_display->wl_egl_thread)
96                 twe_thread_destroy(wayland_egl_display->wl_egl_thread);
97         wayland_egl_display->wl_egl_thread = NULL;
98         wayland_egl_display->twe_display = NULL;
99
100         free(wayland_egl_display);
101         display->backend.data = NULL;
102         return TPL_ERROR_INVALID_OPERATION;
103 }
104
105 static void
106 __tpl_wl_egl_display_fini(tpl_display_t *display)
107 {
108         tpl_wayland_egl_display_t *wayland_egl_display;
109
110         TPL_ASSERT(display);
111
112         wayland_egl_display = (tpl_wayland_egl_display_t *)display->backend.data;
113         if (wayland_egl_display) {
114
115                 TPL_LOG_T("WL_EGL",
116                                   "[FINI] wayland_egl_display(%p) twe_thread(%p) twe_display(%p)",
117                                   wayland_egl_display,
118                                   wayland_egl_display->wl_egl_thread,
119                                   wayland_egl_display->twe_display);
120
121                 if (wayland_egl_display->twe_display) {
122                         tpl_result_t ret = TPL_ERROR_NONE;
123                         ret = twe_display_del(wayland_egl_display->twe_display);
124                         if (ret != TPL_ERROR_NONE)
125                                 TPL_ERR("Failed to delete twe_display(%p) from twe_thread(%p)",
126                                                 wayland_egl_display->twe_display,
127                                                 wayland_egl_display->wl_egl_thread);
128                         wayland_egl_display->twe_display = NULL;
129                 }
130
131                 if (wayland_egl_display->wl_egl_thread) {
132                         twe_thread_destroy(wayland_egl_display->wl_egl_thread);
133                         wayland_egl_display->wl_egl_thread = NULL;
134                 }
135
136                 free(wayland_egl_display);
137         }
138
139         display->backend.data = NULL;
140 }
141
142 static tpl_result_t
143 __tpl_wl_egl_display_query_config(tpl_display_t *display,
144                                                                            tpl_surface_type_t surface_type,
145                                                                            int red_size, int green_size,
146                                                                            int blue_size, int alpha_size,
147                                                                            int color_depth, int *native_visual_id,
148                                                                            tpl_bool_t *is_slow)
149 {
150         TPL_ASSERT(display);
151
152         if (surface_type == TPL_SURFACE_TYPE_WINDOW && red_size == 8 &&
153                         green_size == 8 && blue_size == 8 &&
154                         (color_depth == 32 || color_depth == 24)) {
155
156                 if (alpha_size == 8) {
157                         if (native_visual_id) *native_visual_id = TBM_FORMAT_ARGB8888;
158                         if (is_slow) *is_slow = TPL_FALSE;
159                         return TPL_ERROR_NONE;
160                 }
161                 if (alpha_size == 0) {
162                         if (native_visual_id) *native_visual_id = TBM_FORMAT_XRGB8888;
163                         if (is_slow) *is_slow = TPL_FALSE;
164                         return TPL_ERROR_NONE;
165                 }
166         }
167
168         return TPL_ERROR_INVALID_PARAMETER;
169 }
170
171 static tpl_result_t
172 __tpl_wl_egl_display_filter_config(tpl_display_t *display, int *visual_id,
173                                                                                 int alpha_size)
174 {
175         TPL_IGNORE(display);
176         TPL_IGNORE(visual_id);
177         TPL_IGNORE(alpha_size);
178         return TPL_ERROR_NONE;
179 }
180
181 static tpl_result_t
182 __tpl_wl_egl_display_get_window_info(tpl_display_t *display,
183                 tpl_handle_t window, int *width,
184                 int *height, tbm_format *format,
185                 int depth, int a_size)
186 {
187         tpl_result_t ret = TPL_ERROR_NONE;
188
189         TPL_ASSERT(display);
190         TPL_ASSERT(window);
191
192         if ((ret = twe_get_native_window_info(window, width, height, format, a_size))
193                         != TPL_ERROR_NONE) {
194                 TPL_ERR("Failed to get size info of native_window(%p)", window);
195         }
196
197         return ret;
198 }
199
200 static tpl_result_t
201 __tpl_wl_egl_display_get_pixmap_info(tpl_display_t *display,
202                 tpl_handle_t pixmap, int *width,
203                 int *height, tbm_format *format)
204 {
205         tbm_surface_h   tbm_surface = NULL;
206
207         tbm_surface = twe_get_native_buffer_from_pixmap(pixmap);
208         if (!tbm_surface) {
209                 TPL_ERR("Failed to get tbm_surface_h from native pixmap.");
210                 return TPL_ERROR_INVALID_OPERATION;
211         }
212
213         if (width) *width = tbm_surface_get_width(tbm_surface);
214         if (height) *height = tbm_surface_get_height(tbm_surface);
215         if (format) *format = tbm_surface_get_format(tbm_surface);
216
217         return TPL_ERROR_NONE;
218 }
219
220 static tbm_surface_h
221 __tpl_wl_egl_display_get_buffer_from_native_pixmap(tpl_handle_t pixmap)
222 {
223         tbm_surface_h tbm_surface = NULL;
224
225         TPL_ASSERT(pixmap);
226
227         tbm_surface = twe_get_native_buffer_from_pixmap(pixmap);
228         if (!tbm_surface) {
229                 TPL_ERR("Failed to get tbm_surface_h from wayland_tbm.");
230                 return NULL;
231         }
232
233         return tbm_surface;
234 }
235
236 static void
237 __cb_tbm_surface_queue_reset_callback(tbm_surface_queue_h surface_queue,
238                                                                           void *data)
239 {
240         tpl_surface_t *surface = NULL;
241         tpl_wayland_egl_surface_t *wayland_egl_surface = NULL;
242         tpl_bool_t is_activated = TPL_FALSE;
243         int width, height;
244
245         surface = (tpl_surface_t *)data;
246         TPL_CHECK_ON_NULL_RETURN(surface);
247
248         wayland_egl_surface = (tpl_wayland_egl_surface_t *)surface->backend.data;
249         TPL_CHECK_ON_NULL_RETURN(wayland_egl_surface);
250
251         /* When the queue is resized, change the reset flag to TPL_TRUE to reflect
252          * the changed window size at the next frame. */
253         width = tbm_surface_queue_get_width(surface_queue);
254         height = tbm_surface_queue_get_height(surface_queue);
255         if (surface->width != width || surface->height != height) {
256                 TPL_LOG_T("WL_EGL",
257                                   "[QUEUE_RESIZE_CB] wayland_egl_surface(%p) tbm_queue(%p) (%dx%d)",
258                                   wayland_egl_surface, surface_queue, width, height);
259         }
260
261         /* When queue_reset_callback is called, if is_activated is different from
262          * its previous state change the reset flag to TPL_TRUE to get a new buffer
263          * with the changed state(ACTIVATED/DEACTIVATED) at the next frame. */
264         is_activated = twe_surface_check_activated(wayland_egl_surface->twe_surface);
265         if (wayland_egl_surface->is_activated != is_activated) {
266                 if (is_activated) {
267                         TPL_LOG_T("WL_EGL",
268                                           "[ACTIVATED_CB] wayland_egl_surface(%p) tbm_queue(%p)",
269                                           wayland_egl_surface, surface_queue);
270                 } else {
271                         TPL_LOG_T("WL_EGL",
272                                           "[DEACTIVATED_CB] wayland_egl_surface(%p) tbm_queue(%p)",
273                                           wayland_egl_surface, surface_queue);
274                 }
275         }
276
277         wayland_egl_surface->reset = TPL_TRUE;
278
279         if (surface->reset_cb)
280                 surface->reset_cb(surface->reset_data);
281 }
282
283 void __cb_window_rotate_callback(void *data)
284 {
285         tpl_surface_t *surface = (tpl_surface_t *)data;
286         tpl_wayland_egl_surface_t *wayland_egl_surface = NULL;
287         int rotation;
288
289         if (!surface) {
290                 TPL_ERR("Inavlid parameter. surface is NULL.");
291                 return;
292         }
293
294         wayland_egl_surface = (tpl_wayland_egl_surface_t *)surface->backend.data;
295         if (!wayland_egl_surface) {
296                 TPL_ERR("Invalid parameter. surface->backend.data is NULL");
297                 return;
298         }
299
300         rotation = twe_surface_get_rotation(wayland_egl_surface->twe_surface);
301
302         surface->rotation = rotation;
303 }
304
305 static tpl_result_t
306 __tpl_wl_egl_surface_init(tpl_surface_t *surface)
307 {
308         tpl_wayland_egl_display_t *wayland_egl_display = NULL;
309         tpl_wayland_egl_surface_t *wayland_egl_surface = NULL;
310         tbm_surface_queue_h tbm_queue = NULL;
311         twe_surface_h twe_surface = NULL;
312         tpl_result_t ret = TPL_ERROR_NONE;
313
314         TPL_ASSERT(surface);
315         TPL_ASSERT(surface->display);
316         TPL_ASSERT(surface->type == TPL_SURFACE_TYPE_WINDOW);
317         TPL_ASSERT(surface->native_handle);
318
319         wayland_egl_display =
320                 (tpl_wayland_egl_display_t *)surface->display->backend.data;
321         if (!wayland_egl_display) {
322                 TPL_ERR("Invalid parameter. wayland_egl_display(%p)",
323                                 wayland_egl_display);
324                 return TPL_ERROR_INVALID_PARAMETER;
325         }
326
327         wayland_egl_surface = (tpl_wayland_egl_surface_t *) calloc(1,
328                                                   sizeof(tpl_wayland_egl_surface_t));
329         if (!wayland_egl_surface) {
330                 TPL_ERR("Failed to allocate memory for new tpl_wayland_egl_surface_t.");
331                 return TPL_ERROR_OUT_OF_MEMORY;
332         }
333
334         surface->backend.data = (void *)wayland_egl_surface;
335
336         if (__tpl_object_init(&wayland_egl_surface->base,
337                                                   TPL_OBJECT_SURFACE,
338                                                   NULL) != TPL_ERROR_NONE) {
339                 TPL_ERR("Failed to initialize backend surface's base object!");
340                 goto object_init_fail;
341         }
342
343         twe_surface = twe_surface_add(wayland_egl_display->wl_egl_thread,
344                                                                   wayland_egl_display->twe_display,
345                                                                   surface->native_handle,
346                                                                   surface->format, surface->num_buffers);
347         if (!twe_surface) {
348                 TPL_ERR("Failed to add native_window(%p) to thread(%p)",
349                                 surface->native_handle, wayland_egl_display->wl_egl_thread);
350                 goto create_twe_surface_fail;
351         }
352
353         tbm_queue = twe_surface_get_tbm_queue(twe_surface);
354         if (!tbm_queue) {
355                 TPL_ERR("Failed to get tbm_queue from twe_surface(%p)", twe_surface);
356                 goto queue_create_fail;
357         }
358
359         /* Set reset_callback to tbm_queue */
360         if (tbm_surface_queue_add_reset_cb(tbm_queue,
361                                    __cb_tbm_surface_queue_reset_callback,
362                                    (void *)surface)) {
363                 TPL_ERR("TBM surface queue add reset cb failed!");
364                 goto add_reset_cb_fail;
365         }
366
367         wayland_egl_surface->reset = TPL_FALSE;
368         wayland_egl_surface->twe_surface = twe_surface;
369         wayland_egl_surface->tbm_queue = tbm_queue;
370         wayland_egl_surface->is_activated = TPL_FALSE;
371         wayland_egl_surface->need_to_enqueue = TPL_TRUE;
372
373         surface->width = tbm_surface_queue_get_width(tbm_queue);
374         surface->height = tbm_surface_queue_get_height(tbm_queue);
375         surface->rotation = twe_surface_get_rotation(twe_surface);
376
377         ret = twe_surface_set_rotate_callback(twe_surface, (void *)surface,
378                                                 (tpl_surface_cb_func_t)__cb_window_rotate_callback);
379         if (ret != TPL_ERROR_NONE) {
380                 TPL_WARN("Failed to register rotate callback.");
381         }
382
383         TPL_LOG_T("WL_EGL",
384                           "[INIT1/2]tpl_surface(%p) tpl_wayland_egl_surface(%p) twe_surface(%p)",
385                           surface, wayland_egl_surface, twe_surface);
386         TPL_LOG_T("WL_EGL",
387                           "[INIT2/2]size(%dx%d)rot(%d)|tbm_queue(%p)|native_window(%p)",
388                           surface->width, surface->height, surface->rotation,
389                           tbm_queue, surface->native_handle);
390
391         return TPL_ERROR_NONE;
392
393 add_reset_cb_fail:
394 queue_create_fail:
395         twe_surface_del(twe_surface);
396 create_twe_surface_fail:
397 object_init_fail:
398         free(wayland_egl_surface);
399         surface->backend.data = NULL;
400         return TPL_ERROR_INVALID_OPERATION;
401 }
402
403 static void
404 __tpl_wl_egl_surface_fini(tpl_surface_t *surface)
405 {
406         tpl_wayland_egl_surface_t *wayland_egl_surface = NULL;
407         tpl_wayland_egl_display_t *wayland_egl_display = NULL;
408
409         TPL_ASSERT(surface);
410         TPL_ASSERT(surface->display);
411
412         wayland_egl_surface = (tpl_wayland_egl_surface_t *) surface->backend.data;
413         TPL_CHECK_ON_NULL_RETURN(wayland_egl_surface);
414
415         TPL_OBJECT_LOCK(wayland_egl_surface);
416
417         wayland_egl_display = (tpl_wayland_egl_display_t *)
418                                                   surface->display->backend.data;
419
420         if (wayland_egl_display == NULL) {
421                 TPL_ERR("check failed: wayland_egl_display == NULL");
422                 TPL_OBJECT_UNLOCK(wayland_egl_surface);
423                 return;
424         }
425
426         if (surface->type == TPL_SURFACE_TYPE_WINDOW) {
427                 TPL_LOG_T("WL_EGL",
428                                   "[FINI] wayland_egl_surface(%p) native_window(%p) twe_surface(%p)",
429                                   wayland_egl_surface, surface->native_handle,
430                                   wayland_egl_surface->twe_surface);
431
432                 if (twe_surface_del(wayland_egl_surface->twe_surface)
433                                 != TPL_ERROR_NONE) {
434                         TPL_ERR("Failed to delete twe_surface(%p) from thread(%p)",
435                                         wayland_egl_surface->twe_surface,
436                                         wayland_egl_display->wl_egl_thread);
437                 }
438
439                 wayland_egl_surface->twe_surface = NULL;
440                 wayland_egl_surface->tbm_queue = NULL;
441         }
442
443         TPL_OBJECT_UNLOCK(wayland_egl_surface);
444         __tpl_object_fini(&wayland_egl_surface->base);
445         free(wayland_egl_surface);
446         surface->backend.data = NULL;
447 }
448
449 static tpl_result_t
450 __tpl_wl_egl_surface_set_rotation_capability(tpl_surface_t *surface,
451                                                                                                   tpl_bool_t set)
452 {
453         tpl_wayland_egl_surface_t *wayland_egl_surface = NULL;
454
455         if (!surface) {
456                 TPL_ERR("Invalid parameter. tpl_surface(%p)", surface);
457                 return TPL_ERROR_INVALID_PARAMETER;
458         }
459
460         wayland_egl_surface = (tpl_wayland_egl_surface_t *)surface->backend.data;
461         if (!wayland_egl_surface) {
462                 TPL_ERR("Invalid parameter. wayland_egl_surface(%p)",
463                                 wayland_egl_surface);
464                 return TPL_ERROR_INVALID_PARAMETER;
465         }
466
467         if (!wayland_egl_surface->twe_surface) {
468                 TPL_ERR("Invalid parameter. wayland_egl_surface(%p) twe_surface(%p)",
469                                 wayland_egl_surface, wayland_egl_surface->twe_surface);
470                 return TPL_ERROR_INVALID_PARAMETER;
471         }
472
473         twe_surface_set_rotation_capablity(wayland_egl_surface->twe_surface,
474                                                                                          set);
475
476         return TPL_ERROR_NONE;
477 }
478
479 static tpl_result_t
480 __tpl_wl_egl_surface_set_post_interval(tpl_surface_t *surface,
481                 int post_interval)
482 {
483         tpl_wayland_egl_surface_t *wayland_egl_surface = NULL;
484
485         if (!surface) {
486                 TPL_ERR("Invalid parameter. tpl_surface(%p)", surface);
487                 return TPL_ERROR_INVALID_PARAMETER;
488         }
489
490         wayland_egl_surface = (tpl_wayland_egl_surface_t *)surface->backend.data;
491         if (!wayland_egl_surface) {
492                 TPL_ERR("Invalid parameter. wayland_egl_surface(%p)",
493                                 wayland_egl_surface);
494                 return TPL_ERROR_INVALID_PARAMETER;
495         }
496
497         if (!wayland_egl_surface->twe_surface) {
498                 TPL_ERR("Invalid parameter. wayland_egl_surface(%p) twe_surface(%p)",
499                                 wayland_egl_surface, wayland_egl_surface->twe_surface);
500                 return TPL_ERROR_INVALID_PARAMETER;
501         }
502
503         twe_surface_set_post_interval(wayland_egl_surface->twe_surface,
504                                                                   post_interval);
505
506         return TPL_ERROR_NONE;
507 }
508
509 static tpl_result_t
510 __tpl_wl_egl_surface_enqueue_buffer(tpl_surface_t *surface,
511                 tbm_surface_h tbm_surface,
512                 int num_rects, const int *rects, tbm_fd sync_fence)
513 {
514         TPL_ASSERT(surface);
515         TPL_ASSERT(surface->display);
516         TPL_ASSERT(tbm_surface);
517         TPL_OBJECT_CHECK_RETURN(surface, TPL_ERROR_INVALID_PARAMETER);
518
519         tpl_wayland_egl_surface_t *wayland_egl_surface =
520                 (tpl_wayland_egl_surface_t *) surface->backend.data;
521         tbm_surface_queue_error_e tsq_err;
522         tpl_result_t ret = TPL_ERROR_NONE;
523         int bo_name = 0;
524
525         TPL_OBJECT_LOCK(wayland_egl_surface);
526
527         bo_name = tbm_bo_export(tbm_surface_internal_get_bo(tbm_surface, 0));
528
529         if (!wayland_egl_surface) {
530                 TPL_ERR("Invalid parameter. wayland_egl_surface(%p)",
531                                 wayland_egl_surface);
532                 TRACE_ASYNC_END((int)tbm_surface, "[DEQ]~[ENQ] BO_NAME:%d", bo_name);
533                 TPL_OBJECT_UNLOCK(wayland_egl_surface);
534                 return TPL_ERROR_INVALID_PARAMETER;
535         }
536
537         if (!tbm_surface_internal_is_valid(tbm_surface)) {
538                 TPL_ERR("Failed to enqueue tbm_surface(%p) Invalid value.",
539                                 tbm_surface);
540                 TRACE_ASYNC_END((int)tbm_surface, "[DEQ]~[ENQ] BO_NAME:%d", bo_name);
541                 TPL_OBJECT_UNLOCK(wayland_egl_surface);
542                 return TPL_ERROR_INVALID_PARAMETER;
543         }
544
545         TRACE_MARK("[ENQ] BO_NAME:%d", bo_name);
546
547         TPL_LOG_T("WL_EGL",
548                           "[ENQ] wayland_egl_surface(%p) tbm_surface(%p) bo(%d) fence(%d)",
549                           wayland_egl_surface, tbm_surface, bo_name, sync_fence);
550
551         /* If there are received region information,
552          * save it to buf_info in tbm_surface user_data using below API. */
553         if (num_rects && rects) {
554                 ret = twe_surface_set_damage_region(tbm_surface, num_rects, rects);
555                 if (ret != TPL_ERROR_NONE) {
556                         TPL_WARN("Failed to set damage region. num_rects(%d) rects(%p)",
557                                          num_rects, rects);
558                 }
559         }
560
561         if (!wayland_egl_surface->need_to_enqueue ||
562                 !twe_surface_check_commit_needed(wayland_egl_surface->twe_surface,
563                                                                                  tbm_surface)) {
564                 TPL_LOG_T("WL_EGL",
565                                   "[ENQ_SKIP][Frontbuffer:%s] tbm_surface(%p) need not to enqueue",
566                                   ((surface->frontbuffer == tbm_surface) ? "ON" : "OFF"), tbm_surface);
567                 TRACE_ASYNC_END((int)tbm_surface, "[DEQ]~[ENQ] BO_NAME:%d", bo_name);
568                 TPL_OBJECT_UNLOCK(wayland_egl_surface);
569                 return TPL_ERROR_NONE;
570         }
571
572         /* In frontbuffer mode, will skip tbm_surface_queue_enqueue, acquire, and
573          * commit if surface->frontbuffer that is already set and the tbm_surface
574          * client want to enqueue are the same.
575          */
576         if (surface->is_frontbuffer_mode) {
577                 /* The first buffer to be activated in frontbuffer mode must be
578                  * committed. Subsequence frames do not need to be committed because
579                  * the buffer is already displayed.
580                  */
581                 if (surface->frontbuffer == tbm_surface)
582                         wayland_egl_surface->need_to_enqueue = TPL_FALSE;
583
584                 if (sync_fence != -1) {
585                         close(sync_fence);
586                         sync_fence = -1;
587                 }
588         }
589
590         if (sync_fence != -1) {
591                 ret = twe_surface_set_sync_fd(wayland_egl_surface->twe_surface,
592                                                                           tbm_surface, sync_fence);
593                 if (ret != TPL_ERROR_NONE) {
594                         TPL_WARN("Failed to set sync fd (%d). But it will continue.",
595                                          sync_fence);
596                 }
597         }
598
599         tsq_err = tbm_surface_queue_enqueue(wayland_egl_surface->tbm_queue,
600                                                                                 tbm_surface);
601         if (tsq_err == TBM_SURFACE_QUEUE_ERROR_NONE) {
602                 /*
603                  * If tbm_surface_queue has not been reset, tbm_surface_queue_enqueue
604                  * will return ERROR_NONE. Otherwise, queue has been reset
605                  * this tbm_surface may have only one ref_count. So we need to
606                  * unreference this tbm_surface after getting ERROR_NONE result from
607                  * tbm_surface_queue_enqueue in order to prevent destruction.
608                  */
609                 tbm_surface_internal_unref(tbm_surface);
610         } else {
611                 TPL_ERR("Failed to enqueue tbm_surface(%p). tsq_err=%d",
612                                 tbm_surface, tsq_err);
613                 TRACE_ASYNC_END((int)tbm_surface, "[DEQ]~[ENQ] BO_NAME:%d", bo_name);
614                 TPL_OBJECT_UNLOCK(wayland_egl_surface);
615                 return TPL_ERROR_INVALID_OPERATION;
616         }
617
618         TRACE_ASYNC_END((int)tbm_surface, "[DEQ]~[ENQ] BO_NAME:%d", bo_name);
619         TPL_OBJECT_UNLOCK(wayland_egl_surface);
620
621         return TPL_ERROR_NONE;
622 }
623
624 static tpl_bool_t
625 __tpl_wl_egl_surface_validate(tpl_surface_t *surface)
626 {
627         tpl_bool_t retval = TPL_TRUE;
628
629         TPL_ASSERT(surface);
630         TPL_ASSERT(surface->backend.data);
631
632         tpl_wayland_egl_surface_t *wayland_egl_surface =
633                 (tpl_wayland_egl_surface_t *)surface->backend.data;
634
635         retval = !(wayland_egl_surface->reset);
636
637         return retval;
638 }
639
640 static tpl_result_t
641 __tpl_wl_egl_surface_cancel_dequeued_buffer(tpl_surface_t *surface,
642                                                                                         tbm_surface_h tbm_surface)
643 {
644         tpl_wayland_egl_surface_t *wayland_egl_surface = NULL;
645         tbm_surface_queue_error_e tsq_err = TBM_SURFACE_QUEUE_ERROR_NONE;
646
647         wayland_egl_surface = (tpl_wayland_egl_surface_t *)surface->backend.data;
648         if (!wayland_egl_surface) {
649                 TPL_ERR("Invalid backend surface. surface(%p) wayland_egl_surface(%p)",
650                                 surface, wayland_egl_surface);
651                 return TPL_ERROR_INVALID_PARAMETER;
652         }
653
654         if (!tbm_surface_internal_is_valid(tbm_surface)) {
655                 TPL_ERR("Invalid buffer. tbm_surface(%p)", tbm_surface);
656                 return TPL_ERROR_INVALID_PARAMETER;
657         }
658
659         tbm_surface_internal_unref(tbm_surface);
660
661         tsq_err = tbm_surface_queue_cancel_dequeue(wayland_egl_surface->tbm_queue,
662                                                                                            tbm_surface);
663         if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) {
664                 TPL_ERR("Failed to release tbm_surface(%p)", tbm_surface);
665                 return TPL_ERROR_INVALID_OPERATION;
666         }
667
668         TPL_LOG_T("WL_EGL", "[CANCEL BUFFER] tpl_surface(%p) tbm_surface(%p)",
669                           surface, tbm_surface);
670
671         return TPL_ERROR_NONE;
672 }
673
674 #define CAN_DEQUEUE_TIMEOUT_MS 10000
675
676 static tbm_surface_h
677 __tpl_wl_egl_surface_dequeue_buffer(tpl_surface_t *surface, uint64_t timeout_ns,
678                                                                                  tbm_fd *sync_fence)
679 {
680         TPL_ASSERT(surface);
681         TPL_ASSERT(surface->backend.data);
682         TPL_ASSERT(surface->display);
683         TPL_ASSERT(surface->display->backend.data);
684         TPL_OBJECT_CHECK_RETURN(surface, NULL);
685
686         tbm_surface_h tbm_surface = NULL;
687         tpl_wayland_egl_surface_t *wayland_egl_surface =
688                 (tpl_wayland_egl_surface_t *)surface->backend.data;
689         tpl_wayland_egl_display_t *wayland_egl_display =
690                 (tpl_wayland_egl_display_t *)surface->display->backend.data;
691         tbm_surface_queue_error_e tsq_err = 0;
692         int is_activated = 0;
693         int bo_name = 0;
694         tpl_result_t lock_ret = TPL_FALSE;
695
696         if (sync_fence)
697                 *sync_fence = -1;
698
699         TPL_OBJECT_UNLOCK(surface);
700         tsq_err = tbm_surface_queue_can_dequeue_wait_timeout(
701                                 wayland_egl_surface->tbm_queue, CAN_DEQUEUE_TIMEOUT_MS);
702         TPL_OBJECT_LOCK(surface);
703
704         /* After the can dequeue state, call twe_display_lock to prevent other
705          * events from being processed in wayland_egl_thread
706          * during below dequeue procedure. */
707         lock_ret = twe_display_lock(wayland_egl_display->twe_display);
708
709         if (tsq_err == TBM_SURFACE_QUEUE_ERROR_TIMEOUT) {
710                 TPL_ERR("[CAN_DEQUEUE_TIMEOUT] queue(%p) will be reset",
711                                 wayland_egl_surface->tbm_queue);
712                 if (twe_surface_queue_force_flush(wayland_egl_surface->twe_surface)
713                         != TPL_ERROR_NONE) {
714                         TPL_ERR("Failed to timeout reset. tbm_queue(%p)", wayland_egl_surface->tbm_queue);
715                         if (lock_ret == TPL_ERROR_NONE)
716                                 twe_display_unlock(wayland_egl_display->twe_display);
717                         return NULL;
718                 } else {
719                         tsq_err = TBM_SURFACE_QUEUE_ERROR_NONE;
720                 }
721         }
722
723         if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) {
724                 TPL_ERR("Failed to query can_dequeue. tbm_queue(%p)", wayland_egl_surface->tbm_queue);
725                 if (lock_ret == TPL_ERROR_NONE)
726                         twe_display_unlock(wayland_egl_display->twe_display);
727                 return NULL;
728         }
729
730         /* wayland client can check their states (ACTIVATED or DEACTIVATED) with
731          * below function [wayland_tbm_client_queue_check_activate()].
732          * This function has to be called before tbm_surface_queue_dequeue()
733          * in order to know what state the buffer will be dequeued next.
734          *
735          * ACTIVATED state means non-composite mode. Client can get buffers which
736             can be displayed directly(without compositing).
737          * DEACTIVATED state means composite mode. Client's buffer will be displayed
738             by compositor(E20) with compositing.
739          */
740         is_activated = twe_surface_check_activated(wayland_egl_surface->twe_surface);
741         wayland_egl_surface->is_activated = is_activated;
742
743         surface->width = tbm_surface_queue_get_width(wayland_egl_surface->tbm_queue);
744         surface->height = tbm_surface_queue_get_height(wayland_egl_surface->tbm_queue);
745
746         if (surface->is_frontbuffer_mode && surface->frontbuffer != NULL) {
747                 /* If surface->frontbuffer is already set in frontbuffer mode,
748                  * it will return that frontbuffer if it is still activated,
749                  * otherwise dequeue the new buffer after initializing
750                  * surface->frontbuffer to NULL. */
751                 if (is_activated && !wayland_egl_surface->reset) {
752                         TPL_LOG_T("WL_EGL",
753                                           "[DEQ][F] surface->frontbuffer(%p) BO_NAME(%d)",
754                                           surface->frontbuffer,
755                                           tbm_bo_export(tbm_surface_internal_get_bo(
756                                                                         surface->frontbuffer, 0)));
757                         TRACE_ASYNC_BEGIN((int)surface->frontbuffer,
758                                                           "[DEQ]~[ENQ] BO_NAME:%d",
759                                                           tbm_bo_export(tbm_surface_internal_get_bo(
760                                                                                                 surface->frontbuffer, 0)));
761                         if (lock_ret == TPL_ERROR_NONE)
762                                 twe_display_unlock(wayland_egl_display->twe_display);
763                         return surface->frontbuffer;
764                 } else {
765                         surface->frontbuffer = NULL;
766                         wayland_egl_surface->need_to_enqueue = TPL_TRUE;
767                 }
768         } else {
769                 surface->frontbuffer = NULL;
770         }
771
772         tsq_err = tbm_surface_queue_dequeue(wayland_egl_surface->tbm_queue,
773                                                                                 &tbm_surface);
774         if (!tbm_surface) {
775                 TPL_ERR("Failed to get tbm_surface from tbm_surface_queue | tsq_err = %d",
776                                 tsq_err);
777                 if (lock_ret == TPL_ERROR_NONE)
778                         twe_display_unlock(wayland_egl_display->twe_display);
779                 return NULL;
780         }
781
782         tbm_surface_internal_ref(tbm_surface);
783         bo_name = tbm_bo_export(tbm_surface_internal_get_bo(tbm_surface, 0));
784
785         if (surface->is_frontbuffer_mode && is_activated)
786                 surface->frontbuffer = tbm_surface;
787
788         wayland_egl_surface->reset = TPL_FALSE;
789
790         TRACE_MARK("[DEQ][NEW]BO_NAME:%d", bo_name);
791         TRACE_ASYNC_BEGIN((int)tbm_surface, "[DEQ]~[ENQ] BO_NAME:%d", bo_name);
792         TPL_LOG_T("WL_EGL", "[DEQ][N] tbm_surface(%p) bo(%d)",
793                           tbm_surface, bo_name);
794
795         if (lock_ret == TPL_ERROR_NONE)
796                 twe_display_unlock(wayland_egl_display->twe_display);
797
798         return tbm_surface;
799 }
800
801 tpl_bool_t
802 __tpl_display_choose_backend_wl_egl_thread(tpl_handle_t native_dpy)
803 {
804         if (!native_dpy) return TPL_FALSE;
805
806         if (twe_check_native_handle_is_wl_display(native_dpy))
807                 return TPL_TRUE;
808
809         return TPL_FALSE;
810 }
811
812 void
813 __tpl_display_init_backend_wl_egl_thread(tpl_display_backend_t *backend)
814 {
815         TPL_ASSERT(backend);
816
817         backend->type = TPL_BACKEND_WAYLAND_THREAD;
818         backend->data = NULL;
819
820         backend->init = __tpl_wl_egl_display_init;
821         backend->fini = __tpl_wl_egl_display_fini;
822         backend->query_config = __tpl_wl_egl_display_query_config;
823         backend->filter_config = __tpl_wl_egl_display_filter_config;
824         backend->get_window_info = __tpl_wl_egl_display_get_window_info;
825         backend->get_pixmap_info = __tpl_wl_egl_display_get_pixmap_info;
826         backend->get_buffer_from_native_pixmap =
827                 __tpl_wl_egl_display_get_buffer_from_native_pixmap;
828 }
829
830 void
831 __tpl_surface_init_backend_wl_egl_thread(tpl_surface_backend_t *backend)
832 {
833         TPL_ASSERT(backend);
834
835         backend->type = TPL_BACKEND_WAYLAND_THREAD;
836         backend->data = NULL;
837
838         backend->init = __tpl_wl_egl_surface_init;
839         backend->fini = __tpl_wl_egl_surface_fini;
840         backend->validate = __tpl_wl_egl_surface_validate;
841         backend->cancel_dequeued_buffer =
842                 __tpl_wl_egl_surface_cancel_dequeued_buffer;
843         backend->dequeue_buffer = __tpl_wl_egl_surface_dequeue_buffer;
844         backend->enqueue_buffer = __tpl_wl_egl_surface_enqueue_buffer;
845         backend->set_rotation_capability =
846                 __tpl_wl_egl_surface_set_rotation_capability;
847         backend->set_post_interval =
848                 __tpl_wl_egl_surface_set_post_interval;
849 }
850