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