show the dump path on the console.
[platform/core/uifw/wayland-tbm.git] / src / wayland-tbm-client.c
1 /*
2 Copyright (C) 2015 Samsung Electronics co., Ltd. All Rights Reserved.
3
4 Contact:
5       SooChan Lim <sc1.lim@samsung.com>,
6       Sangjin Lee <lsj119@samsung.com>,
7       Boram Park <boram1288.park@samsung.com>,
8       Changyeon Lee <cyeon.lee@samsung.com>
9
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the "Software"),
12 to deal in the Software without restriction, including without limitation
13 the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 and/or sell copies of the Software, and to permit persons to whom the
15 Software is furnished to do so, subject to the following conditions:
16
17 The above copyright notice and this permission notice (including the next
18 paragraph) shall be included in all copies or substantial portions of the
19 Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 DEALINGS IN THE SOFTWARE.
28 */
29
30 #include "config.h"
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stddef.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38
39 #include <tbm_surface.h>
40 #include <tbm_surface_queue.h>
41 #include <tbm_surface_internal.h>
42 #include <tbm_sync.h>
43
44 #include "wayland-tbm-client.h"
45 #include "wayland-tbm-client-protocol.h"
46 #include "wayland-tbm-int.h"
47
48 struct wayland_tbm_client {
49         struct wl_display *dpy;
50         struct wl_tbm *wl_tbm;
51
52         tbm_bufmgr bufmgr;
53
54         struct wl_list queue_info_list;
55
56         struct wl_event_queue *event_queue;
57 };
58
59 struct wayland_tbm_buffer {
60         struct wl_buffer *wl_buffer;
61         tbm_surface_h tbm_surface;
62         uint32_t flags;
63         int allocated;
64         int reuse;
65         int usable;
66
67         struct wl_tbm_queue *wl_tbm_queue;
68         struct wl_list link;
69 };
70
71 struct wayland_tbm_surface_queue {
72         struct wl_tbm_queue *wl_tbm_queue;
73         tbm_bufmgr bufmgr;
74
75         int width;
76         int height;
77         int format;
78         int flag;
79         uint num_bufs;
80         uint queue_size;
81         struct wl_surface *wl_surface;
82
83         int is_active;
84         int active_flush;
85         int usage;
86         struct wl_list attach_bufs;
87
88         tbm_surface_queue_h tbm_queue;
89
90         struct wl_tbm *wl_tbm;
91         struct wl_list link;
92 };
93
94 static struct wl_tbm_monitor *tbm_monitor;
95
96 #define DEBUG_TRACE
97 #ifdef DEBUG_TRACE
98 #define WL_TBM_TRACE(fmt, ...)   if (bTrace) WL_TBM_C_LOG(fmt, ##__VA_ARGS__)
99 #else
100 #define WL_TBM_TRACE(fmt, ...)
101 #endif
102
103 struct wayland_tbm_buffer *
104 _wayland_tbm_client_find_tbm_buffer_wl_buffer(struct wayland_tbm_client *tbm_client,
105                                 struct wl_buffer *wl_buffer);
106
107 static tbm_surface_h
108 _wayland_tbm_client_create_surface_from_param(tbm_bufmgr bufmgr,
109                          int is_fd,
110                          int32_t width,
111                          int32_t height,
112                          uint32_t format,
113                          int32_t bpp,
114                          int32_t size,
115                          int32_t num_plane,
116                          struct wl_array *plane_buf_idx,
117                          struct wl_array *plane_offset,
118                          struct wl_array *plane_stride,
119                          struct wl_array *plane_size,
120                          uint32_t flags,
121                          int32_t num_buf,
122                          uint32_t buf0,
123                          uint32_t buf1,
124                          uint32_t buf2);
125
126 static void
127 handle_tbm_buffer_import_with_id(void *data,
128                 struct wl_tbm *wl_tbm,
129                 struct wl_buffer *wl_buffer,
130                 int32_t width,
131                 int32_t height,
132                 uint32_t format,
133                 int32_t bpp,
134                 int32_t size,
135                 int32_t num_plane,
136                 struct wl_array *plane_buf_idx,
137                 struct wl_array *plane_offset,
138                 struct wl_array *plane_stride,
139                 struct wl_array *plane_size,
140                 uint32_t flags,
141                 int32_t num_buf,
142                 uint32_t buf0,
143                 uint32_t buf1,
144                 uint32_t buf2)
145 {
146         struct wayland_tbm_client *tbm_client = (struct wayland_tbm_client *)data;
147         tbm_surface_h tbm_surface;
148         char debug_id[64] = {0, };
149
150         tbm_surface = _wayland_tbm_client_create_surface_from_param(tbm_client->bufmgr, 0,
151                               width, height, format, bpp, size,
152                               num_plane,
153                               plane_buf_idx, plane_offset, plane_stride, plane_size,
154                               0,
155                               num_buf,
156                               buf0, buf1, buf2);
157         WL_TBM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
158         wl_buffer_set_user_data(wl_buffer, tbm_surface);
159
160         snprintf(debug_id, sizeof(debug_id), "%u", (unsigned int)wl_proxy_get_id((struct wl_proxy *)wl_buffer));
161         tbm_surface_internal_set_debug_data(tbm_surface, "id", debug_id);
162
163 #ifdef DEBUG_TRACE
164         WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p", getpid(), wl_buffer, tbm_surface);
165 #endif
166
167         return;
168
169 fail:
170         if (wl_buffer)
171                 wl_buffer_destroy(wl_buffer);
172 }
173
174 static void
175 handle_tbm_buffer_import_with_fd(void *data,
176                 struct wl_tbm *wl_tbm,
177                 struct wl_buffer *wl_buffer,
178                 int32_t width,
179                 int32_t height,
180                 uint32_t format,
181                 int32_t bpp,
182                 int32_t size,
183                 int32_t num_plane,
184                 struct wl_array *plane_buf_idx,
185                 struct wl_array *plane_offset,
186                 struct wl_array *plane_stride,
187                 struct wl_array *plane_size,
188                 uint32_t flags,
189                 int32_t num_buf,
190                 int32_t buf0,
191                 int32_t buf1,
192                 int32_t buf2)
193 {
194         struct wayland_tbm_client *tbm_client = (struct wayland_tbm_client *)data;
195         tbm_surface_h tbm_surface;
196         char debug_id[64] = {0, };
197
198         tbm_surface = _wayland_tbm_client_create_surface_from_param(tbm_client->bufmgr, 1,
199                               width, height, format, bpp, size,
200                               num_plane,
201                               plane_buf_idx, plane_offset, plane_stride, plane_size,
202                               0,
203                               num_buf,
204                               buf0, buf1, buf2);
205         WL_TBM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
206
207         wl_buffer_set_user_data(wl_buffer, tbm_surface);
208
209         snprintf(debug_id, sizeof(debug_id), "%u", (unsigned int)wl_proxy_get_id((struct wl_proxy *)wl_buffer));
210         tbm_surface_internal_set_debug_data(tbm_surface, "id", debug_id);
211
212 #ifdef DEBUG_TRACE
213         WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p", getpid(), wl_buffer, tbm_surface);
214 #endif
215
216         return;
217
218 fail:
219         if (wl_buffer)
220                 wl_buffer_destroy(wl_buffer);
221 }
222
223 static void
224 handle_buffer_destroy(void *data,
225                 struct wl_tbm *wl_tbm,
226                 struct wl_buffer *wl_buffer)
227 {
228         struct wayland_tbm_client *tbm_client = (struct wayland_tbm_client *)data;
229         tbm_surface_h tbm_surface;
230         struct wayland_tbm_buffer *buffer = NULL;
231
232 #ifdef DEBUG_TRACE
233         WL_TBM_TRACE("       pid:%d wl_buffer:%p", getpid(), wl_buffer);
234 #endif
235
236         buffer = _wayland_tbm_client_find_tbm_buffer_wl_buffer(tbm_client, wl_buffer);
237         if (buffer)
238                 buffer->wl_buffer = NULL;
239
240         tbm_surface = wl_buffer_get_user_data(wl_buffer);
241         if (tbm_surface)
242                 tbm_surface_internal_unref(tbm_surface);
243
244         wl_buffer_set_user_data(wl_buffer, NULL);
245         wl_buffer_destroy(wl_buffer);
246
247         return;
248 }
249
250 static const struct wl_tbm_listener wl_tbm_client_listener = {
251         handle_tbm_buffer_import_with_id,
252         handle_tbm_buffer_import_with_fd,
253         handle_buffer_destroy,
254 };
255
256 void _waylend_tbm_monitor_client_print_show_to_file(char* show_str)
257 {
258         FILE * f = NULL;
259         static int c = 0;
260         char tmp_file[256];
261
262         snprintf(tmp_file, sizeof(tmp_file), "/tmp/tbm_debug_show_%d%d", getpid(), c++);
263         if ((f = fopen(tmp_file, "a+")) != NULL) {
264                 fprintf(f, "%s", show_str);
265                 fclose(f);
266         }
267 }
268
269 void _waylend_tbm_monitor_client_show(int argc, char *argv[],
270                                       char *reply, int *len, struct wayland_tbm_client *tbm_client)
271 {
272         struct wayland_tbm_monitor_path path = {0};
273         char *show_str;
274
275         _wayland_tbm_util_show_path_parse(argv[2], 0, &path);
276
277         if (path.dlog)
278                 tbm_bufmgr_debug_show(tbm_client->bufmgr);
279
280         /* we have to save result to some file as reply can be very long */
281         show_str = tbm_bufmgr_debug_tbm_info_get(tbm_client->bufmgr);
282         if (show_str) {
283                 _waylend_tbm_monitor_client_print_show_to_file(show_str);
284                 free(show_str);
285         }
286
287
288         /* send empty string to close the session */
289         WL_TBM_MONITOR_SNPRINTF(reply, *len, "\n");
290 }
291
292 void _waylend_tbm_monitor_client_dump_snapshot(int argc, char *argv[],
293                                       char *reply, int *len, struct wayland_tbm_client *tbm_client)
294 {
295         double scale = 0;
296         int i;
297         char *path = NULL;
298
299         for (i = 1; i < argc; i++) {
300                 if (_waylend_tbm_util_scale_parse(argv[i], &scale))
301                         break;
302         }
303
304         path = _wayland_tbm_dump_directory_make();
305         _waylend_tbm_util_dump_snapshot(tbm_client->bufmgr, scale, path);
306         WL_TBM_MONITOR_SNPRINTF(reply, *len, "client(%d): snapshot dump is done. path=%s\n", getpid(), path);
307         free(path);
308 }
309
310 void _waylend_tbm_monitor_client_dump_queue(int argc, char *argv[],
311                                       char *reply, int *len, struct wayland_tbm_client *tbm_client)
312 {
313         int st;
314         double scale = 0;
315         int i;
316
317         st = _waylend_tbm_util_proc_state_parse(argv[1]);
318
319         for (i = 2; i < argc; i++) {
320                 if (_waylend_tbm_util_scale_parse(argv[i], &scale))
321                         break;
322         }
323
324         st = _waylend_tbm_util_dump_queue(st, tbm_client->bufmgr, scale);
325         WL_TBM_MONITOR_SNPRINTF(reply, *len, "client(%d): queue dump state: %s\n", getpid(),
326                                                         st ? "on" : "off");
327 }
328
329 void _waylend_tbm_monitor_client_trace(int argc, char *argv[],
330                                       char *reply, int *len, struct wayland_tbm_client *tbm_client)
331 {
332         int st;
333
334         st = _waylend_tbm_util_trace(_waylend_tbm_util_proc_state_parse(argv[1]), tbm_client->bufmgr);
335         WL_TBM_MONITOR_SNPRINTF(reply, *len, "client(%d): trace state: %s\n", getpid() ,
336                                                         st ? "on" : "off");
337 }
338
339 static struct {
340         const char *opt;
341         void (*func)(int argc, char *argv[], char *reply, int *len, struct wayland_tbm_client *tbm_client);
342 } option_proc[] = {
343         {
344                 "show",
345                 _waylend_tbm_monitor_client_show,
346         },
347         {
348                 "dump_snapshot",
349                 _waylend_tbm_monitor_client_dump_snapshot,
350         },
351         {
352                 "dump_queue",
353                 _waylend_tbm_monitor_client_dump_queue,
354         },
355         {
356                 "trace",
357                 _waylend_tbm_monitor_client_trace,
358         },
359 };
360
361 static void
362 handle_tbm_monitor_client_done(void *data, struct wl_tbm_monitor *wl_tbm_monitor, const char *message)
363 {
364 }
365
366 static void
367 handle_tbm_monitor_client_request_to_client(void *data, struct wl_tbm_monitor *wl_tbm_monitor,
368                                 const char * options, const char * request_id)
369 {
370         struct wayland_tbm_client *tbm_client = (struct wayland_tbm_client *)data;
371         char temp[1024];
372         char *argv[WL_TBM_MONITOR_ARGS_MAX] = {0};
373         int argc = 0;
374
375         char message[WL_TBM_MONITOR_REPLY_MSG_LEN] = {0,};
376         int len = sizeof(message);
377         char *reply = message;
378
379         char *end = NULL;
380         int i;
381
382         snprintf(temp, sizeof(temp), "%s", options);
383
384         argv[argc] = strtok_r(temp, " ", &end);
385         while (argv[argc]) {
386                 argc++;
387                 if (argc == WL_TBM_MONITOR_ARGS_MAX)
388                         break;
389                 argv[argc] = strtok_r(NULL, " ", &end);
390         }
391
392 #ifdef DEBUG_TRACE
393         WL_TBM_TRACE("receive request_id:%s argc:%d [%s %s] options:'%s'", request_id, argc, argv[0], argv[1], temp);
394 #endif
395
396         if (argc > 0) {
397                 for (i = 0; i < sizeof(option_proc) / sizeof(option_proc[0]); i++) {
398                         if (argv[0][0] == '-' && !strncmp(argv[0] + 1, option_proc[i].opt, 32)) {
399                                 if (option_proc[i].func) {
400                                         option_proc[i].func(argc, argv, reply, &len, tbm_client);
401                                         break;
402                                 }
403                         }
404                 }
405         }
406
407         wl_tbm_monitor_responce_to_server(tbm_monitor, message, request_id);
408 }
409
410 static const struct wl_tbm_monitor_listener wl_tbm_monitor_listener = {
411                 handle_tbm_monitor_client_done,
412                 handle_tbm_monitor_client_request_to_client,
413 };
414
415 static void
416 _wayland_tbm_client_registry_handle_global(void *data,
417                                 struct wl_registry *registry, uint32_t name,
418                                 const char *interface, uint32_t version)
419 {
420         struct wayland_tbm_client *tbm_client = (struct wayland_tbm_client *)data;
421
422         if (!strcmp(interface, "wl_tbm")) {
423                 tbm_client->wl_tbm = wl_registry_bind(registry, name, &wl_tbm_interface,
424                                                       version);
425                 WL_TBM_RETURN_IF_FAIL(tbm_client->wl_tbm != NULL);
426
427                 wl_tbm_add_listener(tbm_client->wl_tbm, &wl_tbm_client_listener, tbm_client);
428
429                 if (!tbm_client->bufmgr) {
430                         tbm_client->bufmgr = tbm_bufmgr_init(-1);
431                         if (!tbm_client->bufmgr) {
432                                 WL_TBM_LOG("failed to get auth_info");
433                                 wl_tbm_destroy(tbm_client->wl_tbm);
434                                 tbm_client->wl_tbm = NULL;
435                                 return;
436                         }
437                 }
438         } else if (!strcmp(interface, "wl_tbm_monitor")) {
439                 /*Create wl_monotor proxy by sington*/
440                 if (tbm_monitor)
441                         return;
442
443                 tbm_monitor = wl_registry_bind(registry, name, &wl_tbm_monitor_interface, version);
444                 WL_TBM_RETURN_IF_FAIL(tbm_monitor != NULL);
445
446                 wl_proxy_set_queue((struct wl_proxy *)tbm_monitor, NULL);
447
448                 wl_tbm_monitor_add_listener(tbm_monitor, &wl_tbm_monitor_listener, tbm_client);
449         }
450 }
451
452 static const struct wl_registry_listener registry_listener = {
453         _wayland_tbm_client_registry_handle_global,
454         NULL
455 };
456
457 int
458 wayland_tbm_client_set_event_queue(struct wayland_tbm_client *tbm_client, struct wl_event_queue *queue)
459 {
460         WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, 0);
461
462         wl_proxy_set_queue((struct wl_proxy *)tbm_client->wl_tbm, queue);
463         tbm_client->event_queue = queue;
464
465         return 1;
466 }
467
468 struct wayland_tbm_client *
469 wayland_tbm_client_init(struct wl_display *display)
470 {
471         WL_TBM_RETURN_VAL_IF_FAIL(display != NULL, NULL);
472
473         struct wl_display *display_wrapper;
474         struct wayland_tbm_client *tbm_client;
475         struct wl_event_queue *wl_queue;
476         struct wl_registry *wl_registry;
477
478         _wayland_tbm_check_dlog_enable();
479
480         bTrace = 0;
481
482         tbm_client = calloc(1, sizeof(struct wayland_tbm_client));
483         WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
484
485         tbm_client->dpy = display;
486
487         display_wrapper = wl_proxy_create_wrapper(display);
488         if (!display_wrapper) {
489                 WL_TBM_LOG("Failed to create display_wrapper.");
490                 free(tbm_client);
491                 return NULL;
492         }
493
494         wl_queue = wl_display_create_queue(display);
495         if (!wl_queue) {
496                 WL_TBM_LOG("Failed to create queue.");
497                 wl_proxy_wrapper_destroy(display_wrapper);
498                 free(tbm_client);
499                 return NULL;
500         }
501
502         wl_proxy_set_queue((struct wl_proxy *)display_wrapper, wl_queue);
503
504         wl_registry = wl_display_get_registry(display_wrapper);
505         wl_proxy_wrapper_destroy(display_wrapper);
506         if (!wl_registry) {
507                 WL_TBM_LOG("Failed to get registry");
508
509                 wl_event_queue_destroy(wl_queue);
510                 free(tbm_client);
511                 return NULL;
512         }
513
514         wl_registry_add_listener(wl_registry, &registry_listener, tbm_client);
515         if (wl_display_roundtrip_queue(display, wl_queue) < 0) {
516                 WL_TBM_LOG("Failed to wl_display_roundtrip_queue");
517
518                 wl_registry_destroy(wl_registry);
519                 wl_event_queue_destroy(wl_queue);
520                 free(tbm_client);
521                 return NULL;
522         }
523
524         wl_event_queue_destroy(wl_queue);
525         wl_registry_destroy(wl_registry);
526
527         /* check wl_tbm */
528         if (!tbm_client->wl_tbm) {
529                 WL_TBM_LOG("failed to create wl_tbm");
530                 wayland_tbm_client_deinit(tbm_client);
531                 return NULL;
532         }
533
534         /*
535          * wl_tbm's queue is destroyed above. We should make wl_tbm's queue to
536          * use display's default_queue.
537          */
538         wl_proxy_set_queue((struct wl_proxy *)tbm_client->wl_tbm, NULL);
539
540         /* queue_info list */
541         wl_list_init(&tbm_client->queue_info_list);
542
543         return tbm_client;
544 }
545
546 void
547 wayland_tbm_client_deinit(struct wayland_tbm_client *tbm_client)
548 {
549         if (!tbm_client)
550                 return;
551
552         if (tbm_client->bufmgr)
553                 tbm_bufmgr_deinit(tbm_client->bufmgr);
554
555         if (tbm_client->wl_tbm) {
556                 wl_tbm_set_user_data(tbm_client->wl_tbm, NULL);
557                 wl_tbm_destroy(tbm_client->wl_tbm);
558         }
559
560         if (tbm_monitor
561                 && (tbm_client == wl_tbm_monitor_get_user_data(tbm_monitor))) {
562                 wl_tbm_monitor_destroy(tbm_monitor);
563                 tbm_monitor = NULL;
564         }
565
566         free(tbm_client);
567 }
568
569 struct wayland_tbm_buffer *
570 _wayland_tbm_client_find_tbm_buffer_wl_buffer(struct wayland_tbm_client *tbm_client,
571                                 struct wl_buffer *wl_buffer)
572 {
573         struct wayland_tbm_surface_queue *queue_info = NULL;
574
575         if (wl_list_empty(&tbm_client->queue_info_list)) return NULL;
576
577         wl_list_for_each(queue_info, &tbm_client->queue_info_list, link) {
578                 struct wayland_tbm_buffer *buffer = NULL;
579
580                 wl_list_for_each(buffer, &queue_info->attach_bufs, link) {
581                         if (buffer->wl_buffer == wl_buffer)
582                                 return buffer;
583                 }
584         }
585
586         return NULL;
587 }
588
589 struct wayland_tbm_buffer *
590 _wayland_tbm_client_find_tbm_buffer_surface(struct wayland_tbm_client *tbm_client,
591                                 tbm_surface_h surface)
592 {
593         struct wayland_tbm_surface_queue *queue_info = NULL;
594
595         if (wl_list_empty(&tbm_client->queue_info_list)) return NULL;
596
597         wl_list_for_each(queue_info, &tbm_client->queue_info_list, link) {
598                 struct wayland_tbm_buffer *buffer = NULL;
599
600                 wl_list_for_each(buffer, &queue_info->attach_bufs, link) {
601                         if (buffer->tbm_surface == surface)
602                                 return buffer;
603                 }
604         }
605
606         return NULL;
607 }
608
609 struct wl_buffer *
610 wayland_tbm_client_create_buffer(struct wayland_tbm_client *tbm_client,
611                                  tbm_surface_h surface)
612 {
613         WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
614         WL_TBM_RETURN_VAL_IF_FAIL(surface != NULL, NULL);
615
616         int bufs[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1};
617         struct wl_buffer *wl_buffer = NULL;
618         struct wayland_tbm_buffer *buffer = NULL;
619         int num_buf, is_fd = -1, i;
620         char debug_id[64] = {0, };
621         tbm_surface_info_s info;
622         uint32_t flags = 0;
623         struct wl_array plane_buf_idx, plane_offset, plane_stride, plane_size;
624         int *p;
625
626         /*
627          * if the surface is the attached surface from display server,
628          * return the wl_buffer of the attached surface
629          */
630
631         buffer = _wayland_tbm_client_find_tbm_buffer_surface(tbm_client, surface);
632         if (buffer)
633                 return buffer->wl_buffer;
634
635         if (tbm_surface_get_info(surface, &info) != TBM_SURFACE_ERROR_NONE) {
636                 WL_TBM_LOG("Failed to create buffer from surface");
637                 return NULL;
638         }
639
640         if (info.num_planes > 3) {
641                 WL_TBM_LOG("invalid num_planes(%d)", info.num_planes);
642                 return NULL;
643         }
644
645         num_buf = tbm_surface_internal_get_num_bos(surface);
646         if (num_buf == 0) {
647                 WL_TBM_LOG("surface doesn't have any bo.");
648                 return NULL;
649         }
650
651         for (i = 0; i < num_buf; i++) {
652                 tbm_bo bo = tbm_surface_internal_get_bo(surface, i);
653                 if (bo == NULL) {
654                         WL_TBM_LOG("Failed to get bo from surface");
655                         goto err;
656                 }
657
658                 /* try to get fd first */
659                 if (is_fd == -1 || is_fd == 1) {
660                         bufs[i] = tbm_bo_export_fd(bo);
661                         if (is_fd == -1 && bufs[i] >= 0)
662                                 is_fd = 1;
663                 }
664
665                 /* if fail to get fd, try to get name second */
666                 if (is_fd == -1 || is_fd == 0) {
667                         bufs[i] = tbm_bo_export(bo);
668                         if (is_fd == -1 && bufs[i] > 0)
669                                 is_fd = 0;
670                 }
671
672                 if (is_fd == -1 ||
673                     (is_fd == 1 && bufs[i] < 0) ||
674                     (is_fd == 0 && bufs[i] <= 0)) {
675                         WL_TBM_LOG("Failed to export(is_fd:%d, bufs:%d)", is_fd, bufs[i]);
676                         goto err;
677                 }
678         }
679
680         wl_array_init(&plane_buf_idx);
681         wl_array_init(&plane_offset);
682         wl_array_init(&plane_stride);
683         wl_array_init(&plane_size);
684
685         for (i = 0; i < 3; i++) {
686                 p = wl_array_add(&plane_buf_idx, sizeof(int));
687                 *p = tbm_surface_internal_get_plane_bo_idx(surface, i);
688                 p = wl_array_add(&plane_offset, sizeof(int));
689                 *p = info.planes[i].offset;
690                 p = wl_array_add(&plane_stride, sizeof(int));
691                 *p = info.planes[i].stride;
692                 p = wl_array_add(&plane_size, sizeof(int));
693                 *p = info.planes[i].size;
694         }
695
696         if (is_fd == 1)
697                 wl_buffer = wl_tbm_create_buffer_with_fd(tbm_client->wl_tbm,
698                                 info.width, info.height, info.format, info.bpp, info.size, info.num_planes,
699                                 &plane_buf_idx, &plane_offset, &plane_stride, &plane_size,
700                                 flags, num_buf, bufs[0],
701                                 (bufs[1] == -1) ? bufs[0] : bufs[1],
702                                 (bufs[2] == -1) ? bufs[0] : bufs[2]);
703         else
704                 wl_buffer = wl_tbm_create_buffer(tbm_client->wl_tbm,
705                                  info.width, info.height, info.format, info.bpp, info.size, info.num_planes,
706                                  &plane_buf_idx, &plane_offset, &plane_stride, &plane_size,
707                                  flags,
708                                  num_buf, bufs[0], bufs[1], bufs[2]);
709
710         wl_array_release(&plane_buf_idx);
711         wl_array_release(&plane_offset);
712         wl_array_release(&plane_stride);
713         wl_array_release(&plane_size);
714
715         if (!wl_buffer) {
716                 WL_TBM_LOG("Failed to create wl_buffer");
717                 goto err;
718         }
719
720         for (i = 0; i < TBM_SURF_PLANE_MAX; i++) {
721                 if (is_fd == 1 && (bufs[i] >= 0))
722                         close(bufs[i]);
723         }
724
725         wl_buffer_set_user_data(wl_buffer, surface);
726
727         snprintf(debug_id, sizeof(debug_id), "%u",
728                 (unsigned int)wl_proxy_get_id((struct wl_proxy *)wl_buffer));
729         tbm_surface_internal_set_debug_data(surface, "id", debug_id);
730
731 #ifdef DEBUG_TRACE
732         WL_TBM_TRACE("        pid:%d wl_buffer:%p tbm_surface:%p", getpid(),
733                         wl_buffer, surface);
734 #endif
735
736         return wl_buffer;
737
738 err:
739         for (i = 0; i < TBM_SURF_PLANE_MAX; i++) {
740                 if (is_fd == 1 && (bufs[i] >= 0))
741                         close(bufs[i]);
742         }
743
744         return NULL;
745 }
746
747 void
748 wayland_tbm_client_destroy_buffer(struct wayland_tbm_client *tbm_client,
749                                   struct wl_buffer *wl_buffer)
750 {
751         struct wayland_tbm_buffer *buffer = NULL;
752
753         WL_TBM_RETURN_IF_FAIL(tbm_client != NULL);
754         WL_TBM_RETURN_IF_FAIL(wl_buffer != NULL);
755
756         // TODO: valid check if the buffer is from this tbm_client???
757
758 #ifdef DEBUG_TRACE
759         WL_TBM_TRACE("       pid:%d wl_buffer:%p", getpid(), wl_buffer);
760 #endif
761
762         buffer = _wayland_tbm_client_find_tbm_buffer_wl_buffer(tbm_client, wl_buffer);
763         if (buffer)
764                 buffer->wl_buffer = NULL;
765
766         wl_buffer_set_user_data(wl_buffer, NULL);
767         wl_buffer_destroy(wl_buffer);
768 }
769
770 void
771 wayland_tbm_client_set_sync_timeline(struct wayland_tbm_client *tbm_client,
772                                                                 struct wl_buffer *wl_buffer, tbm_fd timeline)
773 {
774         WL_TBM_RETURN_IF_FAIL(tbm_client != NULL);
775         WL_TBM_RETURN_IF_FAIL(wl_buffer != NULL);
776
777         wl_tbm_set_sync_timeline(tbm_client->wl_tbm, wl_buffer, timeline);
778 }
779
780 void
781 wayland_tbm_client_set_buffer_transform(struct wayland_tbm_client *tbm_client,
782                                                                 struct wl_buffer *wl_buffer, int transform)
783 {
784         WL_TBM_RETURN_IF_FAIL(tbm_client != NULL);
785         WL_TBM_RETURN_IF_FAIL(wl_buffer != NULL);
786         WL_TBM_RETURN_IF_FAIL(transform >= 0);
787
788         wl_tbm_set_buffer_transform(tbm_client->wl_tbm, wl_buffer, transform);
789 }
790
791 void *
792 wayland_tbm_client_get_bufmgr(struct wayland_tbm_client *tbm_client)
793 {
794         WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
795
796         return (void *)tbm_client->bufmgr;
797 }
798
799 static void
800 _wayland_tbm_client_queue_destroy_attach_bufs(struct wayland_tbm_surface_queue *queue_info)
801 {
802         struct wayland_tbm_buffer *buffer, *tmp;
803
804         wl_list_for_each_safe(buffer, tmp, &queue_info->attach_bufs, link) {
805 #ifdef DEBUG_TRACE
806                 WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p", getpid(), buffer->wl_buffer, buffer->tbm_surface);
807 #endif
808                 if (buffer->wl_buffer) {
809                         wl_tbm_queue_detach_buffer(queue_info->wl_tbm_queue, buffer->wl_buffer);
810
811                         if (!buffer->reuse) {
812 #ifdef DEBUG_TRACE
813                                 WL_TBM_TRACE("destroy the wl_buffer:%p", buffer->wl_buffer);
814 #endif
815                                 wl_buffer_destroy(buffer->wl_buffer);
816                                 buffer->wl_buffer = NULL;
817                         }
818                 }
819
820                 tbm_surface_internal_unref(buffer->tbm_surface);
821                 wl_list_remove(&buffer->link);
822                 free(buffer);
823         }
824 }
825
826 static void
827 _wayland_tbm_client_queue_destroy_unused_attach_bufs(struct wayland_tbm_surface_queue *queue_info)
828 {
829         struct wayland_tbm_buffer *buffer, *tmp;
830
831         wl_list_for_each_safe(buffer, tmp, &queue_info->attach_bufs, link) {
832                 if (buffer->allocated) continue;
833 #ifdef DEBUG_TRACE
834                 WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p", getpid(), buffer->wl_buffer, buffer->tbm_surface);
835 #endif
836                 if (buffer->wl_buffer) {
837                         wl_tbm_queue_detach_buffer(queue_info->wl_tbm_queue, buffer->wl_buffer);
838
839                         if (!buffer->reuse) {
840 #ifdef DEBUG_TRACE
841                                 WL_TBM_TRACE("destroy the wl_buffer:%p", buffer->wl_buffer);
842 #endif
843                                 wl_buffer_destroy(buffer->wl_buffer);
844                                 buffer->wl_buffer = NULL;
845                         }
846                 }
847
848                 tbm_surface_internal_unref(buffer->tbm_surface);
849                 wl_list_remove(&buffer->link);
850                 free(buffer);
851         }
852 }
853
854 static void
855 _wayland_tbm_client_surface_queue_flush(struct wayland_tbm_surface_queue *queue_info)
856 {
857 #ifdef DEBUG_TRACE
858         WL_TBM_TRACE("pid:%d", getpid());
859 #endif
860
861         _wayland_tbm_client_queue_destroy_unused_attach_bufs(queue_info);
862         tbm_surface_queue_set_size(queue_info->tbm_queue, queue_info->queue_size, 1);
863 }
864
865 static tbm_surface_h
866 _wayland_tbm_client_create_surface_from_param(tbm_bufmgr bufmgr,
867                                                          int is_fd,
868                                                          int32_t width,
869                                                          int32_t height,
870                                                          uint32_t format,
871                                                          int32_t bpp,
872                                                          int32_t size,
873                                                          int32_t num_plane,
874                                                          struct wl_array *plane_buf_idx,
875                                                          struct wl_array *plane_offset,
876                                                          struct wl_array *plane_stride,
877                                                          struct wl_array *plane_size,
878                                                          uint32_t flags,
879                                                          int32_t num_buf,
880                                                          uint32_t buf0,
881                                                          uint32_t buf1,
882                                                          uint32_t buf2)
883 {
884         int32_t names[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1};
885         tbm_surface_info_s info = { 0, };
886         tbm_bo bos[TBM_SURF_PLANE_MAX];
887         int i, numPlane, numName;
888         tbm_surface_h tbm_surface;
889
890         numPlane = tbm_surface_internal_get_num_planes(format);
891         WL_TBM_RETURN_VAL_IF_FAIL(numPlane == num_plane, NULL);
892
893         info.width = width;
894         info.height = height;
895         info.format = format;
896         info.bpp = bpp;
897         info.size = size;
898         info.num_planes = numPlane;
899
900         /*Fill plane info*/
901         for (i = 0; i < numPlane; i++) {
902                 info.planes[i].offset = *WL_TBM_ARRAY_NTH_DATA(plane_offset, int32_t, i);
903                 info.planes[i].stride = *WL_TBM_ARRAY_NTH_DATA(plane_stride, int32_t, i);
904                 info.planes[i].size = *WL_TBM_ARRAY_NTH_DATA(plane_size, int32_t, i);
905         }
906
907         /*Fill buffer*/
908         numName = num_buf;
909         names[0] = buf0;
910         names[1] = buf1;
911         names[2] = buf2;
912
913         for (i = 0; i < numName; i++) {
914                 if (is_fd)
915                         bos[i] = tbm_bo_import_fd(bufmgr, names[i]);
916                 else
917                         bos[i] = tbm_bo_import(bufmgr, names[i]);
918         }
919
920         tbm_surface = tbm_surface_internal_create_with_bos(&info, bos, numName);
921         if (tbm_surface == NULL) {
922                 if (is_fd) {
923                         close(buf0);
924                         close(buf1);
925                         close(buf2);
926                 }
927                 return NULL;
928         }
929
930         if (is_fd) {
931                 close(buf0);
932                 close(buf1);
933                 close(buf2);
934         }
935
936         for (i = 0; i < numName; i++)
937                 tbm_bo_unref(bos[i]);
938
939         return tbm_surface;
940 }
941
942 static int
943 _wayland_tbm_client_is_valid_attach_bufs(struct wayland_tbm_surface_queue *queue_info,
944          struct wayland_tbm_buffer *buffer)
945 {
946         int width, height, format;
947
948         width = tbm_surface_get_width(buffer->tbm_surface);
949         height = tbm_surface_get_height(buffer->tbm_surface);
950         format = tbm_surface_get_format(buffer->tbm_surface);
951
952         if (queue_info->width != width ||
953                 queue_info->height != height ||
954                 queue_info->format != format)
955                 return 0;
956
957         return 1;
958 }
959
960 static tbm_surface_h
961 __wayland_tbm_client_surface_alloc_cb(tbm_surface_queue_h surface_queue, void *data)
962 {
963         struct wayland_tbm_surface_queue *queue_info =
964                                 (struct wayland_tbm_surface_queue *)data;
965         struct wayland_tbm_buffer *buffer;
966         tbm_surface_h surface = NULL;
967
968         if (queue_info->is_active && queue_info->active_flush) {
969                 wl_list_for_each_reverse(buffer, &queue_info->attach_bufs, link) {
970                         if (!buffer->allocated && buffer->usable) {
971                                 if (_wayland_tbm_client_is_valid_attach_bufs(queue_info, buffer)) {
972                                         surface = buffer->tbm_surface;
973                                         /* ref.. pair of __wayland_tbm_client_surface_free_cb */
974                                         tbm_surface_internal_ref(surface);
975                                         buffer->allocated = 1;
976 #ifdef DEBUG_TRACE
977                                         WL_TBM_TRACE("   pid:%d wl_buffer:%p tbm_surface:%p ACTIVE", getpid(), buffer->wl_buffer, buffer->tbm_surface);
978 #endif
979                                 } else {
980                                         surface = tbm_surface_internal_create_with_flags(queue_info->width,
981                                                 queue_info->height,
982                                                 queue_info->format,
983                                                 queue_info->flag);
984 #ifdef DEBUG_TRACE
985                                         WL_TBM_TRACE("   pid:%d tbm_surface:%p invalid attach_bufs fallback", getpid(), surface);
986 #endif
987                                 }
988
989                                 break;
990                         }
991                 }
992         } else {
993                 /* ref.. pair of __wayland_tbm_client_surface_free_cb */
994                 surface = tbm_surface_internal_create_with_flags(queue_info->width,
995                                                         queue_info->height,
996                                                         queue_info->format,
997                                                         queue_info->flag);
998
999 #ifdef DEBUG_TRACE
1000                 WL_TBM_TRACE("   pid:%d tbm_surface:%p DEACTIVE", getpid(), surface);
1001 #endif
1002         }
1003
1004         return surface;
1005 }
1006
1007 static void
1008 __wayland_tbm_client_surface_free_cb(tbm_surface_queue_h surface_queue, void *data,
1009                       tbm_surface_h surface)
1010 {
1011 #ifdef DEBUG_TRACE
1012         WL_TBM_TRACE("    pid:%d tbm_surface:%p", getpid(), surface);
1013 #endif
1014         struct wayland_tbm_surface_queue *queue_info =
1015                                 (struct wayland_tbm_surface_queue *)data;
1016         struct wayland_tbm_buffer *buffer, *tmp;
1017
1018         wl_list_for_each_safe(buffer, tmp, &queue_info->attach_bufs, link) {
1019                 if (buffer->tbm_surface != surface) continue;
1020                 if (!buffer->allocated) continue;
1021
1022                 buffer->allocated = 0;
1023                 buffer->reuse = 1;
1024
1025                 if (queue_info->is_active) continue;
1026                 if (buffer->wl_buffer)
1027                         wl_tbm_queue_detach_buffer(queue_info->wl_tbm_queue, buffer->wl_buffer);
1028
1029                 tbm_surface_internal_unref(buffer->tbm_surface);
1030                 wl_list_remove(&buffer->link);
1031                 free(buffer);
1032         }
1033
1034         /* unref.. pair of __wayland_tbm_client_surface_alloc_cb */
1035         tbm_surface_internal_unref(surface);
1036 }
1037
1038 static void
1039 handle_tbm_queue_buffer_attached(void *data,
1040                                         struct wl_tbm_queue *wl_tbm_queue,
1041                                         struct wl_buffer *wl_buffer,
1042                                         uint32_t flags)
1043 {
1044         struct wayland_tbm_surface_queue *queue_info =
1045                                 (struct wayland_tbm_surface_queue *)data;
1046         struct wayland_tbm_buffer *buffer;
1047
1048         WL_TBM_RETURN_IF_FAIL(wl_buffer != NULL);
1049
1050         buffer = calloc(1, sizeof(struct wayland_tbm_buffer));
1051         WL_TBM_GOTO_IF_FAIL(buffer != NULL, fail_alloc);
1052
1053         wl_list_init(&buffer->link);
1054
1055         buffer->wl_tbm_queue = wl_tbm_queue;
1056         buffer->wl_buffer = wl_buffer;
1057         buffer->allocated = 0;
1058
1059         buffer->tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(wl_buffer);
1060         WL_TBM_GOTO_IF_FAIL(buffer->tbm_surface != NULL, fail_get_data);
1061         buffer->flags = flags;
1062
1063         wl_list_insert(&queue_info->attach_bufs, &buffer->link);
1064
1065 #ifdef DEBUG_TRACE
1066         WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p",
1067                         getpid(), buffer->wl_buffer, buffer->tbm_surface);
1068 #endif
1069
1070         return;
1071
1072 fail_get_data:
1073         free(buffer);
1074 fail_alloc:
1075         wl_buffer_destroy(wl_buffer);
1076 }
1077
1078 static void
1079 handle_tbm_queue_active(void *data,
1080                         struct wl_tbm_queue *wl_tbm_queue,
1081                         uint32_t usage,
1082                         uint32_t queue_size,
1083                         uint32_t need_flush)
1084 {
1085         struct wayland_tbm_surface_queue *queue_info =
1086                                 (struct wayland_tbm_surface_queue *)data;
1087
1088         WL_TBM_LOG("active queue");
1089
1090         if (queue_info->is_active) {
1091                 WL_TBM_C_LOG("warning: queue_info is already activated");
1092                 return;
1093         }
1094 #ifdef DEBUG_TRACE
1095         WL_TBM_TRACE("                  pid:%d", getpid());
1096 #endif
1097
1098         queue_info->is_active = 1;
1099         queue_info->usage = usage;
1100
1101         if (need_flush) {
1102                 /* flush the allocated surfaces at the client */
1103                 queue_info->active_flush = need_flush;
1104                 tbm_surface_queue_set_size(queue_info->tbm_queue, queue_size, 1);
1105         }
1106 }
1107
1108 static void
1109 handle_tbm_queue_deactive(void *data,
1110                           struct wl_tbm_queue *wl_tbm_queue)
1111 {
1112         struct wayland_tbm_surface_queue *queue_info =
1113                                 (struct wayland_tbm_surface_queue *)data;
1114
1115 #ifdef DEBUG_TRACE
1116         WL_TBM_TRACE("                  pid:%d", getpid());
1117 #endif
1118
1119         WL_TBM_LOG("deactive queue");
1120
1121         if (!queue_info->is_active) {
1122                 WL_TBM_C_LOG("warning: queue_info is already deactivated");
1123                 return;
1124         }
1125
1126         queue_info->is_active = 0;
1127
1128         if (queue_info->active_flush) {
1129                 queue_info->active_flush = 0;
1130                 /* flush the attached surfaces */
1131                 _wayland_tbm_client_surface_queue_flush(queue_info);
1132         }
1133 }
1134
1135 static void
1136 handle_tbm_queue_flush(void *data,
1137                        struct wl_tbm_queue *wl_tbm_queue)
1138 {
1139         struct wayland_tbm_surface_queue *queue_info =
1140                                 (struct wayland_tbm_surface_queue *)data;
1141
1142 #ifdef DEBUG_TRACE
1143         WL_TBM_TRACE("pid:%d", getpid());
1144 #endif
1145         WL_TBM_LOG("flush queue");
1146
1147         if (queue_info->is_active && queue_info->active_flush) {
1148                 WL_TBM_C_LOG("warning: Cannot flush the tbm_surface_queueu. The queue is activate.");
1149                 return;
1150         }
1151
1152         /* flush the allocated surfaces at the client */
1153         tbm_surface_queue_flush(queue_info->tbm_queue);
1154 }
1155
1156 static void
1157 handle_tbm_queue_buffer_usable(void *data,
1158                                         struct wl_tbm_queue *wl_tbm_queue,
1159                                         struct wl_buffer *wl_buffer)
1160 {
1161         struct wayland_tbm_surface_queue *queue_info =
1162                                 (struct wayland_tbm_surface_queue *)data;
1163         struct wayland_tbm_buffer *buffer;
1164
1165         WL_TBM_RETURN_IF_FAIL(wl_buffer != NULL);
1166
1167         wl_list_for_each(buffer, &queue_info->attach_bufs, link) {
1168                 if (buffer->wl_buffer == wl_buffer)
1169                         buffer->usable = 1;
1170         }
1171
1172 #ifdef DEBUG_TRACE
1173         WL_TBM_TRACE("pid:%d wl_buffer:%p tbm_surface:%p",
1174                         getpid(), buffer->wl_buffer, buffer->tbm_surface);
1175 #endif
1176
1177         tbm_surface_queue_notify_dequeuable(queue_info->tbm_queue);
1178
1179         return;
1180 }
1181
1182 const struct wl_tbm_queue_listener wl_tbm_queue_listener = {
1183         handle_tbm_queue_buffer_attached,
1184         handle_tbm_queue_active,
1185         handle_tbm_queue_deactive,
1186         handle_tbm_queue_flush,
1187         handle_tbm_queue_buffer_usable,
1188 };
1189
1190 static struct wayland_tbm_surface_queue *
1191 _wayland_tbm_client_find_queue_info_wl_surface(struct wayland_tbm_client *tbm_client,
1192                                         struct wl_surface *surface)
1193 {
1194         /* set the debug_pid to the surface for debugging */
1195         if (!wl_list_empty(&tbm_client->queue_info_list)) {
1196                 struct wayland_tbm_surface_queue *queue_info = NULL;
1197
1198                 wl_list_for_each(queue_info, &tbm_client->queue_info_list, link) {
1199                         if (queue_info->wl_surface == surface)
1200                                 return queue_info;
1201                 }
1202         }
1203
1204         return NULL;
1205 }
1206
1207 static struct wayland_tbm_surface_queue *
1208 _wayland_tbm_client_find_queue_info_queue(struct wayland_tbm_client *tbm_client,
1209                                         tbm_surface_queue_h queue)
1210 {
1211         /* set the debug_pid to the surface for debugging */
1212         if (!wl_list_empty(&tbm_client->queue_info_list)) {
1213                 struct wayland_tbm_surface_queue *queue_info = NULL;
1214
1215                 wl_list_for_each(queue_info, &tbm_client->queue_info_list, link) {
1216                         if (queue_info->tbm_queue == queue)
1217                                 return queue_info;
1218                 }
1219         }
1220
1221         return NULL;
1222 }
1223
1224
1225 static void
1226 _handle_tbm_surface_queue_destroy_notify(tbm_surface_queue_h surface_queue,
1227                 void *data)
1228 {
1229         struct wayland_tbm_surface_queue *queue_info =
1230                                 (struct wayland_tbm_surface_queue *)data;
1231
1232 #ifdef DEBUG_TRACE
1233         WL_TBM_TRACE(" pid:%d", getpid());
1234 #endif
1235
1236         /* remove the attach_bufs int the queue_info */
1237         _wayland_tbm_client_queue_destroy_attach_bufs(queue_info);
1238
1239         if (queue_info->wl_tbm_queue)
1240                 wl_tbm_queue_destroy(queue_info->wl_tbm_queue);
1241
1242         wl_list_remove(&queue_info->link);
1243         free(queue_info);
1244 }
1245
1246 static void
1247 _handle_tbm_surface_queue_reset_notify(tbm_surface_queue_h surface_queue,
1248                 void *data)
1249 {
1250         struct wayland_tbm_surface_queue *queue_info = data;
1251         int width;
1252         int height;
1253         int format;
1254
1255 #ifdef DEBUG_TRACE
1256         WL_TBM_TRACE(" pid:%d", getpid());
1257 #endif
1258
1259         width = tbm_surface_queue_get_width(surface_queue);
1260         height = tbm_surface_queue_get_height(surface_queue);
1261         format = tbm_surface_queue_get_format(surface_queue);
1262
1263         queue_info->width = width;
1264         queue_info->height = height;
1265         queue_info->format = format;
1266 }
1267
1268 static void
1269 _handle_tbm_surface_queue_can_dequeue_notify(tbm_surface_queue_h surface_queue,
1270                 void *data)
1271 {
1272         struct wayland_tbm_surface_queue *queue_info = data;
1273         struct wayland_tbm_client *tbm_client = NULL;
1274
1275         WL_TBM_RETURN_IF_FAIL(queue_info != NULL);
1276
1277         if (!queue_info->is_active || !queue_info->active_flush) return;
1278
1279         tbm_client = wl_tbm_get_user_data(queue_info->wl_tbm);
1280         WL_TBM_RETURN_IF_FAIL(tbm_client != NULL);
1281
1282         if (!tbm_client->event_queue) return;
1283
1284         if (wl_display_roundtrip_queue(tbm_client->dpy, tbm_client->event_queue) == -1) {
1285                 int dpy_err;
1286
1287                 WL_TBM_LOG_E("failed to wl_display_roundtrip_queue errno:%d", errno);
1288
1289                 dpy_err = wl_display_get_error(tbm_client->dpy);
1290                 if (dpy_err == EPROTO) {
1291                         const struct wl_interface *interface;
1292                         uint32_t proxy_id, code;
1293                         code = wl_display_get_protocol_error(tbm_client->dpy, &interface, &proxy_id);
1294                         WL_TBM_LOG_E("protocol error interface:%s code:%d proxy_id:%d",
1295                                                  interface->name, code, proxy_id);
1296                 }
1297         }
1298 }
1299
1300 static void
1301 _handle_tbm_surface_queue_trace_notify(tbm_surface_queue_h surface_queue,
1302                 tbm_surface_h tbm_surface, tbm_surface_queue_trace trace, void *data)
1303 {
1304         struct wayland_tbm_surface_queue *queue_info = data;
1305         struct wl_buffer *wl_buffer = NULL;
1306         struct wayland_tbm_buffer *buffer = NULL;
1307
1308         WL_TBM_RETURN_IF_FAIL(queue_info != NULL);
1309
1310         if (trace != TBM_SURFACE_QUEUE_TRACE_DEQUEUE) return;
1311         if (!queue_info->is_active || !queue_info->active_flush) return;
1312
1313         wl_list_for_each(buffer, &queue_info->attach_bufs, link) {
1314                 if (buffer->tbm_surface == tbm_surface)
1315                         wl_buffer = buffer->wl_buffer;
1316         }
1317
1318         if (!wl_buffer) return;
1319
1320         wl_tbm_queue_dequeue_buffer(queue_info->wl_tbm_queue, wl_buffer);
1321 }
1322
1323 tbm_surface_queue_h
1324 wayland_tbm_client_create_surface_queue(struct wayland_tbm_client *tbm_client,
1325                                         struct wl_surface *surface,
1326                                         int queue_size,
1327                                         int width, int height, tbm_format format)
1328 {
1329         struct wayland_tbm_surface_queue *queue_info;
1330         struct wl_tbm_queue *queue;
1331
1332 #ifdef DEBUG_TRACE
1333         WL_TBM_TRACE(" pid:%d", getpid());
1334 #endif
1335
1336         WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
1337         WL_TBM_RETURN_VAL_IF_FAIL(surface != NULL, NULL);
1338
1339         queue_info = calloc(1, sizeof(struct wayland_tbm_surface_queue));
1340         WL_TBM_RETURN_VAL_IF_FAIL(queue_info != NULL, NULL);
1341
1342         queue_info->wl_tbm = tbm_client->wl_tbm;
1343         queue_info->bufmgr = tbm_client->bufmgr;
1344         queue_info->wl_surface = surface;
1345         wl_list_init(&queue_info->attach_bufs);
1346
1347         queue = wl_tbm_create_surface_queue(tbm_client->wl_tbm, surface);
1348         WL_TBM_GOTO_IF_FAIL(queue != NULL, fail);
1349
1350         queue_info->wl_tbm_queue = queue;
1351
1352         wl_tbm_queue_add_listener(queue, &wl_tbm_queue_listener, queue_info);
1353
1354         queue_info->width = width;
1355         queue_info->height = height;
1356         queue_info->format = format;
1357         queue_info->flag = 0;
1358         queue_info->queue_size = queue_size;
1359
1360         queue_info->tbm_queue = tbm_surface_queue_sequence_create(queue_size,
1361                                 width, height, format, 0);
1362         WL_TBM_GOTO_IF_FAIL(queue_info->tbm_queue != NULL, fail);
1363
1364         tbm_surface_queue_set_alloc_cb(queue_info->tbm_queue,
1365                                         __wayland_tbm_client_surface_alloc_cb,
1366                                         __wayland_tbm_client_surface_free_cb,
1367                                         queue_info);
1368
1369         tbm_surface_queue_add_destroy_cb(queue_info->tbm_queue,
1370                                         _handle_tbm_surface_queue_destroy_notify,
1371                                         queue_info);
1372
1373         tbm_surface_queue_add_reset_cb(queue_info->tbm_queue,
1374                                         _handle_tbm_surface_queue_reset_notify, queue_info);
1375
1376         tbm_surface_queue_add_can_dequeue_cb(queue_info->tbm_queue,
1377                                         _handle_tbm_surface_queue_can_dequeue_notify, queue_info);
1378
1379         tbm_surface_queue_add_trace_cb(queue_info->tbm_queue,
1380                                         _handle_tbm_surface_queue_trace_notify, queue_info);
1381
1382 #ifdef DEBUG_TRACE
1383         WL_TBM_C_LOG("INFO cur(%dx%d fmt:0x%x num:%d) new(%dx%d fmt:0x%x num:%d)",
1384                 queue_info->width, queue_info->height,
1385                 queue_info->format, queue_info->num_bufs,
1386                 width, height, format, queue_size);
1387 #endif
1388
1389         /* add queue_info to the list */
1390         wl_list_insert(&tbm_client->queue_info_list, &queue_info->link);
1391
1392         return queue_info->tbm_queue;
1393
1394 fail:
1395         if (queue_info->wl_tbm_queue)
1396                 wl_tbm_queue_destroy(queue_info->wl_tbm_queue);
1397         free(queue_info);
1398         return NULL;
1399 }
1400
1401 struct wl_tbm_queue *
1402 wayland_tbm_client_get_wl_tbm_queue(struct wayland_tbm_client *tbm_client, struct wl_surface *surface)
1403 {
1404         struct wayland_tbm_surface_queue *queue_info = NULL;
1405
1406         WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
1407         WL_TBM_RETURN_VAL_IF_FAIL(surface != NULL, NULL);
1408
1409         queue_info = _wayland_tbm_client_find_queue_info_wl_surface(tbm_client, surface);
1410         WL_TBM_RETURN_VAL_IF_FAIL(queue_info != NULL, NULL);
1411         WL_TBM_RETURN_VAL_IF_FAIL(queue_info->wl_tbm_queue != NULL, NULL);
1412
1413         return queue_info->wl_tbm_queue;
1414 }
1415
1416 struct wl_tbm *
1417 wayland_tbm_client_get_wl_tbm(struct wayland_tbm_client *tbm_client)
1418 {
1419         WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
1420
1421         return tbm_client->wl_tbm;
1422 }
1423
1424 int
1425 wayland_tbm_client_queue_check_activate(struct wayland_tbm_client *tbm_client, tbm_surface_queue_h queue)
1426 {
1427         struct wayland_tbm_surface_queue *queue_info = NULL;
1428
1429         WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, 0);
1430         WL_TBM_RETURN_VAL_IF_FAIL(queue != NULL, 0);
1431
1432         queue_info = _wayland_tbm_client_find_queue_info_queue(tbm_client, queue);
1433         WL_TBM_RETURN_VAL_IF_FAIL(queue_info != NULL, 0);
1434
1435         if (queue_info->is_active) return 1;
1436
1437         return 0;
1438 }
1439
1440 int
1441 wayland_tbm_client_queue_get_surfaces(struct wayland_tbm_client *tbm_client,
1442                                         tbm_surface_queue_h queue, tbm_surface_h *surfaces, int *num)
1443 {
1444         struct wayland_tbm_surface_queue *queue_info = NULL;
1445         tbm_surface_h surface = NULL;
1446         struct wayland_tbm_buffer *buffer = NULL;
1447         tbm_surface_queue_error_e tsq_err = TBM_SURFACE_QUEUE_ERROR_NONE;
1448         tbm_surface_h *get_surfaces;
1449         int get_num = 0, dequeued_num = 0, index = 0;
1450         int i;
1451
1452         WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, 0);
1453         WL_TBM_RETURN_VAL_IF_FAIL(queue != NULL, 0);
1454
1455         queue_info = _wayland_tbm_client_find_queue_info_queue(tbm_client, queue);
1456         WL_TBM_RETURN_VAL_IF_FAIL(queue_info != NULL, 0);;
1457
1458         if (!surfaces && !num) {
1459                 WL_TBM_LOG_E("invalid parameter");
1460                 return 0;
1461         }
1462
1463         if (num) {
1464                 if (queue_info->is_active && queue_info->active_flush)
1465                         *num = wl_list_length(&queue_info->attach_bufs);
1466                 else
1467                         *num = queue_info->queue_size;
1468         }
1469
1470         if (surfaces) {
1471                 if (queue_info->is_active && queue_info->active_flush) {
1472                         wl_list_for_each(buffer, &queue_info->attach_bufs, link) {
1473                                 surfaces[index] = buffer->tbm_surface;
1474                                 index++;
1475                         }
1476                 } else {
1477                         get_surfaces = (tbm_surface_h *)calloc(queue_info->queue_size, sizeof(tbm_surface_h));
1478                         if (!get_surfaces) {
1479                                 WL_TBM_LOG_E("failed to alloc get_surfaces");
1480                                 goto fail;
1481                         }
1482
1483                         tsq_err = tbm_surface_queue_get_surfaces(queue, get_surfaces, &get_num);
1484                         if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) {
1485                                 WL_TBM_LOG_E("failed to tbm_surface_queue_get_surfaces");
1486                                 goto fail;
1487                         }
1488
1489                         for (i = 0; i < get_num; i++) {
1490                                 surfaces[index] = get_surfaces[i];
1491                                 index++;
1492                         }
1493
1494                         if (get_num < queue_info->queue_size) {
1495                                 for (i = 0; i < queue_info->queue_size - get_num; i++) {
1496                                         tsq_err  = tbm_surface_queue_dequeue(queue, &surface);
1497                                         if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) {
1498                                                 WL_TBM_LOG_E("failed to tbm_surface_queue_dequeue");
1499                                                 goto fail;
1500                                         }
1501
1502                                         dequeued_num++;
1503                                         surfaces[index] = surface;
1504                                         index++;
1505                                 }
1506                         }
1507
1508                         for (i = 0; i < dequeued_num; i++) {
1509                                 tsq_err  = tbm_surface_queue_release(queue, surfaces[get_num + i]);
1510                                 if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE)
1511                                         WL_TBM_LOG_E("failed to tbm_surface_queue_release");
1512                         }
1513
1514                         if (get_surfaces)
1515                                 free(get_surfaces);
1516                 }
1517         }
1518
1519         return 1;
1520
1521 fail:
1522         if (num) *num = 0;
1523
1524         if (surfaces) {
1525                 for (i = 0; i < dequeued_num; i++) {
1526                         tsq_err  = tbm_surface_queue_release(queue, surfaces[get_num + i]);
1527                         if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE)
1528                                 WL_TBM_LOG_E("failed to tbm_surface_queue_release");
1529                 }
1530
1531                 if (get_surfaces)
1532                         free(get_surfaces);
1533         }
1534
1535         return 0;
1536 }