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