f5c69dbd9526a983e2af15c412bf5c2bd3ae82ce
[platform/core/uifw/libtdm.git] / client / tdm_client.c
1 /**************************************************************************
2  *
3  * libtdm
4  *
5  * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6  *
7  * Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8  *          JinYoung Jeon <jy0.jeon@samsung.com>,
9  *          Taeheon Kim <th908.kim@samsung.com>,
10  *          YoungJun Cho <yj44.cho@samsung.com>,
11  *          SooChan Lim <sc1.lim@samsung.com>,
12  *          Boram Park <boram1288.park@samsung.com>
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the
16  * "Software"), to deal in the Software without restriction, including
17  * without limitation the rights to use, copy, modify, merge, publish,
18  * distribute, sub license, and/or sell copies of the Software, and to
19  * permit persons to whom the Software is furnished to do so, subject to
20  * the following conditions:
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33  *
34 **************************************************************************/
35
36 #define WL_HIDE_DEPRECATED
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include <stdio.h>
43 #include <string.h>
44 #include <stdlib.h>
45 #include <time.h>
46 #include <strings.h>
47 #include <poll.h>
48
49 #include <tdm-client-protocol.h>
50
51 #include "tdm_client.h"
52 #include "tdm_log.h"
53 #include "tdm_macro.h"
54 #include "tdm_list.h"
55 #include "tdm.h"
56 #include "tdm_private.h"
57 #include <tbm_surface_internal.h>
58
59 #define TDM_ARRAY_NTH_DATA(array, type, n) (((type*)((array)->data)) + n)
60
61 typedef struct _tdm_private_client_vblank tdm_private_client_vblank;
62 typedef struct _tdm_private_client_voutput tdm_private_client_voutput;
63
64 typedef struct _tdm_private_client {
65         pthread_mutex_t lock;
66
67         struct wl_display *display;
68         struct wl_event_queue *queue;
69         struct wl_registry *registry;
70         struct wl_tdm *tdm;
71         struct list_head output_list;
72         struct list_head voutput_list;
73
74         unsigned int enable_ttrace;
75         unsigned int stamp;
76
77         tdm_private_client_vblank *temp_vblank;
78 } tdm_private_client;
79
80 typedef struct _tdm_private_client_output {
81         struct list_head link;
82
83         tdm_private_client *private_client;
84
85         char name[TDM_NAME_LEN];
86         struct wl_tdm_output *output;
87         int width;
88         int height;
89         int refresh;
90         tdm_output_conn_status connection;
91         tdm_output_dpms dpms;
92         struct list_head vblank_list;
93         struct list_head change_handler_list;
94
95         unsigned int req_id;
96         unsigned int watch_output_changes;
97
98         struct {
99                 int count;
100                 tdm_client_output_mode *modes;
101         } available_modes;
102
103         tdm_private_client_voutput *voutput;
104 } tdm_private_client_output;
105
106 typedef struct _tdm_private_client_buffer {
107         struct list_head link;
108         struct wl_buffer *wl_buffer;
109 } tdm_private_client_buffer;
110
111 struct _tdm_private_client_voutput {
112         struct list_head link;
113         struct wl_tdm_voutput *wl_voutput;
114         struct list_head commit_handler_list;
115
116         struct {
117                 int count;
118                 tdm_client_output_mode *modes;
119         } available_modes;
120
121         unsigned int mmwidth;
122         unsigned int mmheight;
123
124         uint32_t msg;
125
126         struct list_head buffer_list;
127         tbm_bufmgr bufmgr;
128         tdm_private_client_buffer *attach_buffer;
129
130         tdm_private_client *private_client;
131         tdm_private_client_output *private_output;
132         char name[TDM_NAME_LEN];
133         int get_output;
134 };
135
136 struct _tdm_private_client_vblank {
137         tdm_private_client_output *private_output;
138
139         struct wl_tdm_vblank *vblank;
140         struct list_head wait_list;
141
142         char name[TDM_NAME_LEN];
143         unsigned int sync;
144         unsigned int fps;
145         int offset;
146         unsigned int enable_fake;
147         unsigned int enable_ttrace;
148
149         unsigned int started;
150         unsigned int stamp;
151
152         double req_time;
153         double last_time;
154
155         struct list_head link;
156 };
157
158 typedef struct _tdm_client_output_handler_info {
159         tdm_private_client_output *private_output;
160
161         tdm_client_output_change_handler func;
162         void *user_data;
163
164         struct list_head link;
165         struct list_head call_link;
166 } tdm_client_output_handler_info;
167
168 typedef struct _tdm_client_wait_info {
169         tdm_private_client_vblank *private_vblank;
170
171         tdm_client_vblank_handler func;
172         void *user_data;
173
174         unsigned int req_id;
175         double req_time;
176         int need_free;
177
178         struct list_head link;
179         struct list_head call_link;
180 } tdm_client_wait_info;
181
182 typedef struct _tdm_client_voutput_commit_handler_info
183 {
184         tdm_private_client_voutput *private_voutput;
185
186         tdm_client_voutput_commit_handler func;
187         void *user_data;
188
189         struct list_head link;
190         struct list_head call_link;
191 } tdm_client_voutput_commit_handler_info;
192
193 static unsigned int
194 _tdm_client_check_wl_error(tdm_private_client *private_client, const char *func, int line)
195 {
196         uint32_t ec, id;
197         const struct wl_interface *intf;
198         int err;
199
200         err = wl_display_get_error(private_client->display);
201         if (!err)
202                 return false;
203
204         if (err == EINVAL || err == ENOMEM || err == EFAULT || err == EPROTO) {
205                 ec = wl_display_get_protocol_error(private_client->display, &intf, &id);
206                 TDM_ERR("[%s,%d] errno(%d) Got protocol error '%u' on interface '%s' (object '%u')",
207                                 func, line, err, ec, (intf) ? intf->name : "destroyed", id);
208         } else {
209                 TDM_ERR("[%s,%d] errno(%d)", func, line, err);
210         }
211
212         return true;
213 }
214
215 #define CHECK_WL_PROTOCOL_ERROR(pc)  _tdm_client_check_wl_error(pc, __FUNCTION__, __LINE__)
216
217 static void
218 _tdm_client_vblank_cb_stamp(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t stamp)
219 {
220         tdm_private_client_vblank *private_vblank = data;
221         tdm_private_client *private_client;
222
223         TDM_RETURN_IF_FAIL(private_vblank != NULL);
224
225         private_vblank->stamp = stamp;
226
227         TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
228         private_client = private_vblank->private_output->private_client;
229
230         private_client->stamp = stamp;
231 }
232
233 /* LCOV_EXCL_START */
234 static void
235 _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank,
236                                                    uint32_t req_id, uint32_t sequence, uint32_t tv_sec,
237                                                    uint32_t tv_usec, uint32_t error)
238 {
239         tdm_private_client_vblank *private_vblank = data;
240         tdm_private_client *private_client;
241         tdm_client_wait_info *w = NULL, *wait_info = NULL;
242
243         TDM_RETURN_IF_FAIL(private_vblank != NULL);
244
245         private_client = private_vblank->private_output->private_client;
246
247         private_vblank->last_time = TDM_TIME(tv_sec, tv_usec);
248
249         TDM_DBG("vblank(%p) req_id(%u) sequence(%u) time(%.6f)",
250                         private_vblank, req_id, sequence, TDM_TIME(tv_sec, tv_usec));
251
252         LIST_FOR_EACH_ENTRY(w, &private_vblank->wait_list, link) {
253                 if (w->req_id != req_id)
254                         continue;
255
256                 wait_info = w;
257                 break;
258         }
259
260         if (!wait_info) {
261                 TDM_ERR("no wait infomation for req_id(%d)", req_id);
262                 return;
263         }
264
265         if (private_vblank->enable_ttrace)
266                 TDM_TRACE_ASYNC_END((int)wait_info->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
267
268         if (wait_info->req_time >= private_vblank->last_time)
269                 TDM_WRN("'req(%.6f) < last(%.6f)' failed. error(%d)", wait_info->req_time, private_vblank->last_time, error);
270
271         if (wait_info->need_free)
272                 LIST_DEL(&wait_info->link);
273
274         if (wait_info->func) {
275                 pthread_mutex_unlock(&private_client->lock);
276                 wait_info->func(private_vblank, error, sequence, tv_sec, tv_usec, wait_info->user_data);
277                 pthread_mutex_lock(&private_client->lock);
278         }
279
280         if (wait_info->need_free)
281                 free(w);
282         else
283                 wait_info->need_free = 1;
284 }
285 /* LCOV_EXCL_STOP */
286
287 /* LCOV_EXCL_START */
288 static void
289 _tdm_client_vblank_cb_ttrace(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t enable)
290 {
291         tdm_private_client_vblank *private_vblank = data;
292         tdm_private_client *private_client;
293
294         TDM_RETURN_IF_FAIL(private_vblank != NULL);
295
296         private_vblank->enable_ttrace = enable;
297
298         TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
299         private_client = private_vblank->private_output->private_client;
300
301         private_client->enable_ttrace = enable;
302 }
303 /* LCOV_EXCL_STOP */
304
305 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
306         _tdm_client_vblank_cb_stamp,
307         _tdm_client_vblank_cb_done,
308         _tdm_client_vblank_cb_ttrace,
309 };
310
311 static void
312 _tdm_client_output_destroy(tdm_private_client_output *private_output)
313 {
314         tdm_private_client_vblank *v = NULL, *vv = NULL;
315         tdm_client_output_handler_info *h = NULL, *hh = NULL;
316
317         LIST_DEL(&private_output->link);
318
319         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_list, link) {
320                 TDM_ERR("vblanks SHOULD be destroyed first!");
321                 LIST_DEL(&v->link);
322                 v->private_output = NULL;
323         }
324
325         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list, link) {
326                 LIST_DEL(&h->link);
327                 free(h);
328         }
329
330         wl_tdm_output_destroy(private_output->output);
331
332         free(private_output);
333 }
334
335 static void
336 _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output,
337                                                    uint32_t width, uint32_t height, uint32_t refresh, uint32_t error)
338 {
339         tdm_private_client_output *private_output = (tdm_private_client_output*)data;
340
341         TDM_RETURN_IF_FAIL(private_output != NULL);
342
343         private_output->width = width;
344         private_output->height = height;
345         private_output->refresh = refresh;
346
347         if (error != TDM_ERROR_NONE)
348                 TDM_INFO("mode event error: %d", error);
349
350         TDM_DBG("private_output(%p) wl_tbm_output@%d width(%d) height(%d) refresh(%d)",
351                         private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output),
352                         width, height, refresh);
353 }
354
355 static void
356 _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
357 {
358         tdm_private_client_output *private_output = (tdm_private_client_output*)data;
359         tdm_private_client *private_client;
360         tdm_client_output_handler_info *h = NULL, *hh = NULL;
361         tdm_value v;
362         struct list_head call_list;
363
364         TDM_RETURN_IF_FAIL(private_output != NULL);
365
366         private_client = private_output->private_client;
367
368         if (private_output->connection == value)
369                 return;
370
371         private_output->connection = value;
372
373         if (error != TDM_ERROR_NONE)
374                 TDM_INFO("connection event error: %d", error);
375
376         TDM_DBG("private_output(%p) wl_tbm_output@%d connection(%d)",
377                         private_output,
378                         wl_proxy_get_id((struct wl_proxy*)private_output->output),
379                         value);
380
381         LIST_INITHEAD(&call_list);
382
383         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
384                 LIST_ADDTAIL(&h->call_link, &call_list);
385         }
386
387         v.u32 = value;
388         pthread_mutex_unlock(&private_client->lock);
389         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
390                 if (h->func)
391                         h->func(private_output, TDM_OUTPUT_CHANGE_CONNECTION, v, h->user_data);
392         }
393         pthread_mutex_lock(&private_client->lock);
394 }
395
396 static void
397 _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
398 {
399         tdm_private_client_output *private_output = (tdm_private_client_output*)data;
400         tdm_private_client *private_client;
401         tdm_client_output_handler_info *h = NULL, *hh = NULL;
402         tdm_value v;
403         struct list_head call_list;
404
405         TDM_RETURN_IF_FAIL(private_output != NULL);
406
407         private_client = private_output->private_client;
408
409         /* If value is extended value, we handle it as DPMS on in client side
410          * The extended DPMS value is valid only in server side.
411          * Or, need to export to client side also?
412          */
413         if (value > TDM_OUTPUT_DPMS_OFF)
414                 value = TDM_OUTPUT_DPMS_ON;
415
416         if (private_output->dpms == value)
417                 return;
418
419         private_output->dpms = value;
420
421         if (error != TDM_ERROR_NONE)
422                 TDM_INFO("dpms event error: %d", error);
423
424         TDM_DBG("private_output(%p) wl_tbm_output@%d dpms(%d)",
425                         private_output,
426                         wl_proxy_get_id((struct wl_proxy*)private_output->output),
427                         value);
428
429         LIST_INITHEAD(&call_list);
430
431         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
432                 LIST_ADDTAIL(&h->call_link, &call_list);
433         }
434
435         v.u32 = value;
436         pthread_mutex_unlock(&private_client->lock);
437         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
438                 if (h->func)
439                         h->func(private_output, TDM_OUTPUT_CHANGE_DPMS, v, h->user_data);
440         }
441         pthread_mutex_lock(&private_client->lock);
442 }
443
444 static void
445 _tdm_client_output_cb_availablie_modes(void *data, struct wl_tdm_output *wl_tdm_output, struct wl_array *modes, uint32_t error)
446 {
447         tdm_private_client_output *private_output = (tdm_private_client_output*)data;
448         tdm_output_mode *mode;
449         int size, count = 0, i = 0;
450
451         if (error != TDM_ERROR_NONE)
452                 TDM_INFO("get availablie_modes event error: %d", error);
453
454         private_output->available_modes.count = 0;
455         if (private_output->available_modes.modes)
456                 free(private_output->available_modes.modes);
457
458         wl_array_for_each(mode, modes)
459                 count++;
460         if (count == 0) {
461                 TDM_INFO("no output mode");
462                 return;
463         }
464
465         size = sizeof(tdm_output_mode);
466
467         private_output->available_modes.modes = malloc(count * size);
468         private_output->available_modes.count = count;
469
470         wl_array_for_each(mode, modes)
471                 memcpy(&private_output->available_modes.modes[i++], mode, size);
472 }
473
474 static const struct wl_tdm_output_listener tdm_client_output_listener = {
475         _tdm_client_output_cb_mode,
476         _tdm_client_output_cb_connection,
477         _tdm_client_output_cb_dpms,
478         _tdm_client_output_cb_availablie_modes,
479 };
480
481 static void
482 _tdm_client_cb_global(void *data, struct wl_registry *registry,
483                                           uint32_t name, const char *interface,
484                                           uint32_t version)
485 {
486         tdm_private_client *private_client = data;
487
488         if (strncmp(interface, "wl_tdm", 6) == 0) {
489                 private_client->tdm =
490                         wl_registry_bind(registry, name, &wl_tdm_interface, version);
491                 TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
492
493                 wl_display_flush(private_client->display);
494         }
495 }
496
497 /* LCOV_EXCL_START */
498 static void
499 _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
500 {
501 }
502 /* LCOV_EXCL_STOP */
503
504 static const struct wl_registry_listener tdm_client_registry_listener = {
505         _tdm_client_cb_global,
506         _tdm_client_cb_global_remove
507 };
508
509 tdm_client*
510 tdm_client_create(tdm_error *error)
511 {
512         tdm_private_client *private_client;
513
514         private_client = calloc(1, sizeof *private_client);
515         if (!private_client) {
516                 /* LCOV_EXCL_START */
517
518                 TDM_ERR("alloc failed");
519                 if (error)
520                         *error = TDM_ERROR_OUT_OF_MEMORY;
521                 return NULL;
522
523                 /* LCOV_EXCL_STOP */
524         }
525
526         if (pthread_mutex_init(&private_client->lock, NULL)) {
527                 TDM_ERR("mutex init failed: %m");
528                 free(private_client);
529                 if (error)
530                         *error = TDM_ERROR_OUT_OF_MEMORY;
531                 return NULL;
532         }
533
534         LIST_INITHEAD(&private_client->output_list);
535         LIST_INITHEAD(&private_client->voutput_list);
536
537         private_client->display = wl_display_connect("tdm-socket");
538         TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed);
539
540         private_client->queue = wl_display_create_queue(private_client->display);
541         TDM_GOTO_IF_FAIL(private_client->queue != NULL, create_failed);
542
543         private_client->registry = wl_display_get_registry(private_client->display);
544         TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed);
545
546         wl_registry_add_listener(private_client->registry,
547                                                          &tdm_client_registry_listener, private_client);
548         wl_display_roundtrip(private_client->display);
549
550         if (CHECK_WL_PROTOCOL_ERROR(private_client))
551                 goto create_failed;
552
553         /* check global objects */
554         TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed);
555
556         if (error)
557                 *error = TDM_ERROR_NONE;
558
559         return (tdm_client*)private_client;
560 create_failed:
561         tdm_client_destroy((tdm_client*)private_client);
562         if (error)
563                 *error = TDM_ERROR_OPERATION_FAILED;
564         return NULL;
565 }
566
567 void
568 tdm_client_destroy(tdm_client *client)
569 {
570         tdm_private_client *private_client = (tdm_private_client*)client;
571         tdm_private_client_output *o = NULL, *oo = NULL;
572         tdm_private_client_voutput *vo = NULL, *voo = NULL;
573
574         if (!private_client)
575                 return;
576
577         pthread_mutex_lock(&private_client->lock);
578
579         if (private_client->temp_vblank) {
580                 pthread_mutex_unlock(&private_client->lock);
581                 tdm_client_vblank_destroy(private_client->temp_vblank);
582                 pthread_mutex_lock(&private_client->lock);
583         }
584
585         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_client->output_list, link) {
586                 _tdm_client_output_destroy(o);
587         }
588
589         LIST_FOR_EACH_ENTRY_SAFE(vo, voo, &private_client->voutput_list, link) {
590                 tdm_client_voutput_destroy(vo);
591         }
592
593         if (private_client->tdm)
594                 wl_tdm_destroy(private_client->tdm);
595         if (private_client->registry)
596                 wl_registry_destroy(private_client->registry);
597         if (private_client->queue)
598                 wl_event_queue_destroy(private_client->queue);
599         if (private_client->display)
600                 wl_display_disconnect(private_client->display);
601
602         pthread_mutex_unlock(&private_client->lock);
603         pthread_mutex_destroy(&private_client->lock);
604
605         free(private_client);
606 }
607
608 tdm_error
609 tdm_client_get_fd(tdm_client *client, int *fd)
610 {
611         tdm_private_client *private_client;
612
613         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
614         TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_ERROR_INVALID_PARAMETER);
615
616         private_client = (tdm_private_client*)client;
617
618         pthread_mutex_lock(&private_client->lock);
619
620         *fd = wl_display_get_fd(private_client->display);
621
622         pthread_mutex_unlock(&private_client->lock);
623
624         if (*fd < 0)
625                 return TDM_ERROR_OPERATION_FAILED;
626
627         return TDM_ERROR_NONE;
628 }
629
630 tdm_error
631 tdm_client_handle_events(tdm_client *client)
632 {
633         tdm_private_client *private_client;
634
635         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
636
637         /* LCOV_EXCL_START */
638         private_client = (tdm_private_client*)client;
639
640         pthread_mutex_lock(&private_client->lock);
641
642         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
643                 pthread_mutex_unlock(&private_client->lock);
644                 return TDM_ERROR_PROTOCOL_ERROR;
645         }
646
647         if (private_client->enable_ttrace)
648                 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
649
650         wl_display_dispatch(private_client->display);
651
652         if (private_client->enable_ttrace)
653                 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
654
655         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
656                 pthread_mutex_unlock(&private_client->lock);
657                 return TDM_ERROR_PROTOCOL_ERROR;
658         }
659
660         pthread_mutex_unlock(&private_client->lock);
661
662         return TDM_ERROR_NONE;
663         /* LCOV_EXCL_STOP */
664 }
665
666 static int
667 _tdm_client_poll(struct wl_display *display, short int events, int timeout)
668 {
669         int ret;
670         struct pollfd pfd[1];
671
672         pfd[0].fd = wl_display_get_fd(display);
673         pfd[0].events = events;
674         do {
675                 ret = poll(pfd, 1, timeout);
676         } while (ret == -1 && errno == EINTR);
677
678         return ret;
679 }
680
681 static tdm_error
682 _tdm_client_dispatch_timeout(tdm_private_client *private_client, int timeout)
683 {
684         int ret;
685         struct wl_display *display = private_client->display;
686
687         if (wl_display_prepare_read(display) == -1) {
688                 if (wl_display_dispatch_pending(display) > 0)
689                         return TDM_ERROR_NONE;
690                 else
691                         return TDM_ERROR_OPERATION_FAILED;
692         }
693
694         while (true) {
695                 ret = wl_display_flush(display);
696
697                 if (ret != -1 || errno != EAGAIN)
698                         break;
699
700                 if (_tdm_client_poll(display, POLLOUT, -1) == -1) {
701                         wl_display_cancel_read(display);
702                         TDM_ERR("_tdm_client_poll failed");
703                         return TDM_ERROR_OPERATION_FAILED;
704                 }
705         }
706
707         /* Don't stop if flushing hits an EPIPE; continue so we can read any
708          * protocol error that may have triggered it. */
709         if (ret < 0 && errno != EPIPE) {
710                 TDM_ERR("ret(%d) errno(%d)", ret, errno);
711                 wl_display_cancel_read(display);
712                 return TDM_ERROR_OPERATION_FAILED;
713         }
714
715         ret = _tdm_client_poll(display, POLLIN, timeout);
716         if (ret <= 0) {
717                 wl_display_cancel_read(display);
718                 if (ret == 0) {
719                         TDM_ERR("_tdm_client_poll timeout.");
720                         return TDM_ERROR_TIMEOUT;
721                 } else {
722                         TDM_ERR("_tdm_client_poll failed. (ret:%d)", ret);
723                         return TDM_ERROR_OPERATION_FAILED;
724                 }
725         }
726
727         if (wl_display_read_events(display) == -1) {
728                 TDM_ERR("wl_display_read_events failed");
729                 return TDM_ERROR_OPERATION_FAILED;
730         }
731
732         ret = wl_display_dispatch_pending(display);
733
734         if (ret < 0) {
735                 TDM_ERR("_tdm_client_dispatch_timeout failed");
736                 return TDM_ERROR_OPERATION_FAILED;
737         }
738
739         return TDM_ERROR_NONE;
740 }
741
742 tdm_error
743 tdm_client_handle_events_timeout(tdm_client *client, int ms_timeout)
744 {
745         tdm_private_client *private_client;
746         tdm_error ret;
747         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
748
749         private_client = (tdm_private_client*)client;
750
751         pthread_mutex_lock(&private_client->lock);
752
753         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
754                 pthread_mutex_unlock(&private_client->lock);
755                 return TDM_ERROR_PROTOCOL_ERROR;
756         }
757
758         if (private_client->enable_ttrace)
759                 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
760
761         ret = _tdm_client_dispatch_timeout(private_client, ms_timeout);
762
763         if (private_client->enable_ttrace)
764                 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
765
766         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
767                 pthread_mutex_unlock(&private_client->lock);
768                 return TDM_ERROR_PROTOCOL_ERROR;
769         }
770
771         pthread_mutex_unlock(&private_client->lock);
772
773         return ret;
774 }
775
776 typedef struct _tdm_client_vblank_temp {
777         tdm_client_vblank_handler2 func;
778         void *user_data;
779 } tdm_client_vblank_temp;
780
781 /* LCOV_EXCL_START */
782 static void
783 _tdm_client_vblank_handler_temp(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
784                                                                 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
785 {
786         tdm_client_vblank_temp *vblank_temp = user_data;
787
788         TDM_RETURN_IF_FAIL(vblank_temp != NULL);
789         TDM_RETURN_IF_FAIL(vblank != NULL);
790
791         if (vblank_temp->func)
792                 vblank_temp->func(sequence, tv_sec, tv_usec, vblank_temp->user_data);
793
794         free(vblank_temp);
795 }
796 /* LCOV_EXCL_STOP */
797
798 /* LCOV_EXCL_START */ /* deprecated */
799 tdm_error
800 tdm_client_wait_vblank(tdm_client *client, char *name,
801                                            int sw_timer, int interval, int sync,
802                                            tdm_client_vblank_handler2 func, void *user_data)
803 {
804         tdm_private_client *private_client = (tdm_private_client*)client;
805         tdm_client_output *output;
806         tdm_client_vblank_temp *vblank_temp;
807         tdm_error ret;
808
809         TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
810         TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
811         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
812
813         if (CHECK_WL_PROTOCOL_ERROR(private_client))
814                 return TDM_ERROR_PROTOCOL_ERROR;
815
816         if (!private_client->temp_vblank) {
817                 output = tdm_client_get_output(client, name, &ret);
818                 TDM_RETURN_VAL_IF_FAIL(output != NULL, ret);
819
820                 private_client->temp_vblank = tdm_client_output_create_vblank(output, &ret);
821                 TDM_RETURN_VAL_IF_FAIL(private_client->temp_vblank != NULL, ret);
822         }
823
824         tdm_client_vblank_set_enable_fake(private_client->temp_vblank, sw_timer);
825         tdm_client_vblank_set_sync(private_client->temp_vblank, sync);
826
827         vblank_temp = calloc(1, sizeof *vblank_temp);
828         TDM_RETURN_VAL_IF_FAIL(vblank_temp != NULL, TDM_ERROR_OUT_OF_MEMORY);
829
830         vblank_temp->func = func;
831         vblank_temp->user_data = user_data;
832
833         return tdm_client_vblank_wait(private_client->temp_vblank, interval, _tdm_client_vblank_handler_temp, vblank_temp);
834 }
835 /* LCOV_EXCL_STOP */
836
837 tdm_client_output*
838 tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
839 {
840         tdm_private_client *private_client;
841         tdm_private_client_output *private_output = NULL;
842         struct wl_proxy *wrapper;
843
844         if (error)
845                 *error = TDM_ERROR_NONE;
846
847         if (!client) {
848                 TDM_ERR("'!client' failed");
849                 if (error)
850                         *error = TDM_ERROR_INVALID_PARAMETER;
851                 return NULL;
852         }
853
854         private_client = (tdm_private_client*)client;
855
856         pthread_mutex_lock(&private_client->lock);
857
858         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
859                 if (error)
860                         *error = TDM_ERROR_PROTOCOL_ERROR;
861                 pthread_mutex_unlock(&private_client->lock);
862                 return NULL;
863         }
864
865         if (!name) {
866                 name = "primary";
867         } else if (!strncmp(name, "primary", 7) || !strncmp(name, "default", 7)) {
868                 TDM_DBG("get primary or default output");
869         } else {
870                 tdm_private_client_voutput *private_voutput = NULL;
871                 int find = 0;
872
873                 LIST_FOR_EACH_ENTRY(private_voutput, &private_client->voutput_list, link) {
874                         if (!strncmp(private_voutput->name, name, TDM_NAME_LEN)) {
875                                 find = 1;
876                                 break;
877                         }
878                 }
879                 if (!find) {
880                         if (error)
881                                 *error = TDM_ERROR_INVALID_PARAMETER;
882                         pthread_mutex_unlock(&private_client->lock);
883                         return NULL;
884                 }
885         }
886
887         LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
888                 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
889                         pthread_mutex_unlock(&private_client->lock);
890                         return (tdm_client_output*)private_output;
891                 }
892         }
893
894         wrapper = wl_proxy_create_wrapper(private_client->tdm);
895         if (!wrapper) {
896                 TDM_ERR("create output_wrapper failed");
897                 if (error)
898                         *error = TDM_ERROR_OUT_OF_MEMORY;
899                 pthread_mutex_unlock(&private_client->lock);
900                 return NULL;
901         }
902
903         wl_proxy_set_queue(wrapper, private_client->queue);
904
905         private_output = calloc(1, sizeof *private_output);
906         if (!private_output) {
907                 /* LCOV_EXCL_START */
908                 wl_proxy_wrapper_destroy(wrapper);
909                 TDM_ERR("alloc failed");
910                 if (error)
911                         *error = TDM_ERROR_OUT_OF_MEMORY;
912                 pthread_mutex_unlock(&private_client->lock);
913                 return NULL;
914
915                 /* LCOV_EXCL_STOP */
916         }
917
918         private_output->private_client = private_client;
919
920         snprintf(private_output->name, TDM_NAME_LEN, "%s", name);
921         private_output->output = wl_tdm_create_output((struct wl_tdm *)wrapper, private_output->name);
922         wl_proxy_wrapper_destroy(wrapper);
923         if (!private_output->output) {
924                 /* LCOV_EXCL_START */
925
926                 TDM_ERR("couldn't create output resource");
927                 free(private_output);
928                 if (error)
929                         *error = TDM_ERROR_OUT_OF_MEMORY;
930                 pthread_mutex_unlock(&private_client->lock);
931                 return NULL;
932
933                 /* LCOV_EXCL_STOP */
934         }
935
936         LIST_INITHEAD(&private_output->vblank_list);
937         LIST_INITHEAD(&private_output->change_handler_list);
938
939         wl_tdm_output_add_listener(private_output->output,
940                                                            &tdm_client_output_listener, private_output);
941         wl_display_roundtrip_queue(private_client->display, private_client->queue);
942
943         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
944
945         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
946                 wl_tdm_output_destroy(private_output->output);
947                 free(private_output);
948                 if (error)
949                         *error = TDM_ERROR_PROTOCOL_ERROR;
950                 pthread_mutex_unlock(&private_client->lock);
951                 return NULL;
952         }
953
954         LIST_ADDTAIL(&private_output->link, &private_client->output_list);
955
956         pthread_mutex_unlock(&private_client->lock);
957
958         return (tdm_client_output*)private_output;
959 }
960
961 tdm_error
962 tdm_client_output_add_change_handler(tdm_client_output *output,
963                                                                          tdm_client_output_change_handler func,
964                                                                          void *user_data)
965 {
966         tdm_private_client_output *private_output;
967         tdm_private_client *private_client;
968         tdm_client_output_handler_info *h = NULL;
969
970         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
971         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
972
973         private_output = (tdm_private_client_output*)output;
974         private_client = private_output->private_client;
975
976         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
977                 if (h->func == func && h->user_data == user_data) {
978                         TDM_ERR("can't add twice");
979                         return TDM_ERROR_BAD_REQUEST;
980                 }
981         }
982
983         h = calloc(1, sizeof *h);
984         TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
985
986         pthread_mutex_lock(&private_client->lock);
987
988         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
989                 free(h);
990                 pthread_mutex_unlock(&private_client->lock);
991                 return TDM_ERROR_PROTOCOL_ERROR;
992         }
993
994         if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
995                 wl_tdm_output_watch_output_changes(private_output->output, 1);
996                 wl_display_roundtrip_queue(private_client->display, private_client->queue);
997
998                 /* TODO: this is very tricky.
999                  * If a client adds the change_handler, we might be able to guess that
1000                  * the client will watch the tdm client's fd and handle tdm events in
1001                  * event loop. Otherwise, we CAN'T make sure if a client has event loop
1002                  * which handles tdm events.
1003                  */
1004                 private_output->watch_output_changes = 1;
1005         }
1006
1007         h->private_output = private_output;
1008         h->func = func;
1009         h->user_data = user_data;
1010         LIST_ADDTAIL(&h->link, &private_output->change_handler_list);
1011         LIST_INITHEAD(&h->call_link);
1012
1013         pthread_mutex_unlock(&private_client->lock);
1014
1015         return TDM_ERROR_NONE;
1016 }
1017
1018 void
1019 tdm_client_output_remove_change_handler(tdm_client_output *output,
1020                                                                                 tdm_client_output_change_handler func,
1021                                                                                 void *user_data)
1022 {
1023         tdm_private_client_output *private_output;
1024         tdm_private_client *private_client;
1025         tdm_client_output_handler_info *h = NULL;
1026
1027         TDM_RETURN_IF_FAIL(output != NULL);
1028         TDM_RETURN_IF_FAIL(func != NULL);
1029
1030         private_output = (tdm_private_client_output*)output;
1031         private_client = private_output->private_client;
1032
1033         pthread_mutex_lock(&private_client->lock);
1034
1035         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
1036                 if (h->func != func || h->user_data != user_data)
1037                         continue;
1038
1039                 LIST_DEL(&h->link);
1040                 free(h);
1041
1042                 if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
1043                         private_output->watch_output_changes = 0;
1044                         if (!CHECK_WL_PROTOCOL_ERROR(private_client)) {
1045                                 wl_tdm_output_watch_output_changes(private_output->output, 0);
1046                                 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1047                         }
1048                 }
1049
1050                 pthread_mutex_unlock(&private_client->lock);
1051
1052                 return;
1053         }
1054
1055         pthread_mutex_unlock(&private_client->lock);
1056 }
1057
1058 tdm_error
1059 tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refresh)
1060 {
1061         tdm_private_client_output *private_output;
1062         tdm_private_client *private_client;
1063
1064         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1065         TDM_RETURN_VAL_IF_FAIL(refresh != NULL, TDM_ERROR_INVALID_PARAMETER);
1066
1067         private_output = (tdm_private_client_output*)output;
1068         private_client = private_output->private_client;
1069
1070         pthread_mutex_lock(&private_client->lock);
1071
1072         if (private_output->watch_output_changes) {
1073                 *refresh = private_output->refresh;
1074                 pthread_mutex_unlock(&private_client->lock);
1075                 return TDM_ERROR_NONE;
1076         }
1077
1078         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1079                 pthread_mutex_unlock(&private_client->lock);
1080                 return TDM_ERROR_PROTOCOL_ERROR;
1081         }
1082
1083         wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1084         wl_tdm_output_get_mode(private_output->output);
1085         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1086         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1087
1088         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1089                 pthread_mutex_unlock(&private_client->lock);
1090                 return TDM_ERROR_PROTOCOL_ERROR;
1091         }
1092
1093         *refresh = private_output->refresh;
1094
1095         pthread_mutex_unlock(&private_client->lock);
1096
1097         return TDM_ERROR_NONE;
1098 }
1099
1100 tdm_error
1101 tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_status *status)
1102 {
1103         tdm_private_client_output *private_output;
1104         tdm_private_client *private_client;
1105
1106         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1107         TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
1108
1109         private_output = (tdm_private_client_output*)output;
1110         private_client = private_output->private_client;
1111
1112         pthread_mutex_lock(&private_client->lock);
1113
1114         if (private_output->watch_output_changes) {
1115                 *status = private_output->connection;
1116                 pthread_mutex_unlock(&private_client->lock);
1117                 return TDM_ERROR_NONE;
1118         }
1119
1120         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1121                 pthread_mutex_unlock(&private_client->lock);
1122                 return TDM_ERROR_PROTOCOL_ERROR;
1123         }
1124
1125         wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1126         wl_tdm_output_get_connection(private_output->output);
1127         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1128         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1129
1130         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1131                 pthread_mutex_unlock(&private_client->lock);
1132                 return TDM_ERROR_PROTOCOL_ERROR;
1133         }
1134
1135         *status = private_output->connection;
1136
1137         pthread_mutex_unlock(&private_client->lock);
1138
1139         return TDM_ERROR_NONE;
1140 }
1141
1142 tdm_error
1143 tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
1144 {
1145         tdm_private_client_output *private_output;
1146         tdm_private_client *private_client;
1147
1148         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1149         TDM_RETURN_VAL_IF_FAIL(dpms != NULL, TDM_ERROR_INVALID_PARAMETER);
1150
1151         private_output = (tdm_private_client_output*)output;
1152         private_client = private_output->private_client;
1153
1154         if (private_output->watch_output_changes) {
1155                 *dpms = private_output->dpms;
1156                 return TDM_ERROR_NONE;
1157         }
1158
1159         pthread_mutex_lock(&private_client->lock);
1160
1161         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1162                 pthread_mutex_unlock(&private_client->lock);
1163                 return TDM_ERROR_PROTOCOL_ERROR;
1164         }
1165
1166         wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1167         wl_tdm_output_get_dpms(private_output->output);
1168         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1169         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1170
1171         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1172                 pthread_mutex_unlock(&private_client->lock);
1173                 return TDM_ERROR_PROTOCOL_ERROR;
1174         }
1175
1176         *dpms = private_output->dpms;
1177
1178         pthread_mutex_unlock(&private_client->lock);
1179
1180         return TDM_ERROR_NONE;
1181 }
1182
1183 tdm_error
1184 tdm_client_output_get_available_modes(tdm_client_output *output, tdm_client_output_mode **modes, int *count)
1185 {
1186         tdm_private_client_output *private_output;
1187         tdm_private_client *private_client;
1188
1189         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1190         TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER);
1191         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
1192
1193
1194         private_output = (tdm_private_client_output *)output;
1195         private_client = private_output->private_client;
1196         if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1197                 *modes = NULL;
1198                 *count = 0;
1199                 return TDM_ERROR_NONE;
1200         }
1201
1202         pthread_mutex_lock(&private_client->lock);
1203
1204         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1205                 pthread_mutex_unlock(&private_client->lock);
1206                 return TDM_ERROR_PROTOCOL_ERROR;
1207         }
1208
1209         wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1210         wl_tdm_output_get_available_modes(private_output->output);
1211         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1212         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1213
1214         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1215                 pthread_mutex_unlock(&private_client->lock);
1216                 return TDM_ERROR_PROTOCOL_ERROR;
1217         }
1218
1219         *modes = (tdm_client_output_mode *)private_output->available_modes.modes;
1220         *count = private_output->available_modes.count;
1221
1222         pthread_mutex_unlock(&private_client->lock);
1223
1224         return TDM_ERROR_NONE;
1225 }
1226
1227 tdm_error
1228 tdm_client_output_set_mode(tdm_client_output *output, int index)
1229 {
1230         tdm_private_client_output *private_output;
1231
1232         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1233         TDM_RETURN_VAL_IF_FAIL(index < 0, TDM_ERROR_INVALID_PARAMETER);
1234
1235         private_output = (tdm_private_client_output*)output;
1236
1237         if (private_output->available_modes.count - 1 < index)
1238                 return TDM_ERROR_INVALID_PARAMETER;
1239
1240         if ((private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) ||
1241                 (private_output->available_modes.count == 0))
1242                 return TDM_ERROR_BAD_REQUEST;
1243
1244         wl_tdm_output_set_mode(private_output->output, index);
1245
1246         return TDM_ERROR_NONE;
1247 }
1248
1249 tdm_client_vblank*
1250 tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
1251 {
1252         tdm_private_client *private_client;
1253         tdm_private_client_output *private_output;
1254         tdm_private_client_vblank *private_vblank;
1255         struct wl_proxy *wrapper;
1256
1257         if (error)
1258                 *error = TDM_ERROR_NONE;
1259
1260         if (!output) {
1261                 TDM_ERR("'!output' failed");
1262                 if (error)
1263                         *error = TDM_ERROR_INVALID_PARAMETER;
1264                 return NULL;
1265         }
1266
1267         private_output = (tdm_private_client_output*)output;
1268         private_client = private_output->private_client;
1269
1270         pthread_mutex_lock(&private_client->lock);
1271
1272         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1273                 if (error)
1274                         *error = TDM_ERROR_PROTOCOL_ERROR;
1275                 pthread_mutex_unlock(&private_client->lock);
1276                 return NULL;
1277         }
1278
1279         wrapper = wl_proxy_create_wrapper(private_output->output);
1280         if (!wrapper) {
1281                 TDM_ERR("create output_wrapper failed");
1282                 if (error)
1283                         *error = TDM_ERROR_OUT_OF_MEMORY;
1284                 pthread_mutex_unlock(&private_client->lock);
1285                 return NULL;
1286         }
1287
1288         wl_proxy_set_queue(wrapper, private_client->queue);
1289
1290         private_vblank = calloc(1, sizeof *private_vblank);
1291         if (!private_vblank) {
1292                 /* LCOV_EXCL_START */
1293
1294                 TDM_ERR("alloc failed");
1295                 wl_proxy_wrapper_destroy(wrapper);
1296                 if (error)
1297                         *error = TDM_ERROR_OUT_OF_MEMORY;
1298                 pthread_mutex_unlock(&private_client->lock);
1299                 return NULL;
1300
1301                 /* LCOV_EXCL_STOP */
1302         }
1303
1304         private_vblank->private_output = private_output;
1305
1306         private_vblank->vblank = wl_tdm_output_create_vblank((struct wl_tdm_output*)wrapper);
1307         wl_proxy_wrapper_destroy(wrapper);
1308         if (!private_vblank->vblank) {
1309                 /* LCOV_EXCL_START */
1310
1311                 TDM_ERR("couldn't create vblank resource");
1312                 free(private_vblank);
1313                 if (error)
1314                         *error = TDM_ERROR_OUT_OF_MEMORY;
1315                 pthread_mutex_unlock(&private_client->lock);
1316                 return NULL;
1317
1318                 /* LCOV_EXCL_STOP */
1319         }
1320
1321         /* initial value */
1322         private_vblank->fps = private_output->refresh;
1323         private_vblank->offset = 0;
1324         private_vblank->enable_fake = 0;
1325
1326         LIST_INITHEAD(&private_vblank->wait_list);
1327
1328         wl_tdm_vblank_add_listener(private_vblank->vblank,
1329                                                            &tdm_client_vblank_listener, private_vblank);
1330         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1331
1332         wl_proxy_set_queue((struct wl_proxy *)private_vblank->vblank, NULL);
1333
1334         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1335                 wl_tdm_vblank_destroy(private_vblank->vblank);
1336                 free(private_vblank);
1337                 if (error)
1338                         *error = TDM_ERROR_PROTOCOL_ERROR;
1339                 pthread_mutex_unlock(&private_client->lock);
1340                 return NULL;
1341         }
1342
1343         LIST_ADDTAIL(&private_vblank->link, &private_output->vblank_list);
1344
1345         pthread_mutex_unlock(&private_client->lock);
1346
1347         return (tdm_client_vblank*)private_vblank;
1348 }
1349
1350 void
1351 tdm_client_vblank_destroy(tdm_client_vblank *vblank)
1352 {
1353         tdm_private_client_vblank *private_vblank;
1354         tdm_private_client *private_client;
1355         tdm_client_wait_info *w = NULL, *ww = NULL;
1356
1357         TDM_RETURN_IF_FAIL(vblank != NULL);
1358
1359         private_vblank = vblank;
1360         private_client = private_vblank->private_output->private_client;
1361
1362         pthread_mutex_lock(&private_client->lock);
1363
1364         LIST_DEL(&private_vblank->link);
1365
1366         LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
1367                 LIST_DEL(&w->link);
1368                 free(w);
1369         }
1370
1371         wl_tdm_vblank_destroy(private_vblank->vblank);
1372
1373         free(private_vblank);
1374
1375         pthread_mutex_unlock(&private_client->lock);
1376 }
1377
1378 tdm_error
1379 tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name)
1380 {
1381         tdm_private_client_vblank *private_vblank;
1382         tdm_private_client *private_client;
1383
1384         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1385
1386         private_vblank = vblank;
1387         private_client = private_vblank->private_output->private_client;
1388
1389         pthread_mutex_lock(&private_client->lock);
1390
1391         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1392                 pthread_mutex_unlock(&private_client->lock);
1393                 return TDM_ERROR_PROTOCOL_ERROR;
1394         }
1395
1396         if (!name)
1397                 name = TDM_VBLANK_DEFAULT_NAME;
1398
1399         strncpy(private_vblank->name, name, TDM_NAME_LEN - 1);
1400         private_vblank->name[TDM_NAME_LEN - 1] = '\0';
1401
1402         wl_tdm_vblank_set_name(private_vblank->vblank, private_vblank->name);
1403
1404         pthread_mutex_unlock(&private_client->lock);
1405
1406         return TDM_ERROR_NONE;
1407 }
1408
1409 tdm_error
1410 tdm_client_vblank_set_sync(tdm_client_vblank *vblank, unsigned int sync)
1411 {
1412         tdm_private_client_vblank *private_vblank;
1413         tdm_private_client *private_client;
1414
1415         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1416
1417         private_vblank = vblank;
1418         private_client = private_vblank->private_output->private_client;
1419
1420         pthread_mutex_lock(&private_client->lock);
1421         private_vblank->sync = sync;
1422         pthread_mutex_unlock(&private_client->lock);
1423
1424         return TDM_ERROR_NONE;
1425 }
1426
1427 tdm_error
1428 tdm_client_vblank_set_fps(tdm_client_vblank *vblank, unsigned int fps)
1429 {
1430         tdm_private_client_vblank *private_vblank;
1431         tdm_private_client *private_client;
1432
1433         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1434         TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER);
1435
1436         private_vblank = vblank;
1437         private_client = private_vblank->private_output->private_client;
1438
1439         pthread_mutex_lock(&private_client->lock);
1440
1441         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1442                 pthread_mutex_unlock(&private_client->lock);
1443                 return TDM_ERROR_PROTOCOL_ERROR;
1444         }
1445
1446         if (private_vblank->fps == fps) {
1447                 pthread_mutex_unlock(&private_client->lock);
1448                 return TDM_ERROR_NONE;
1449         }
1450
1451         private_vblank->fps = fps;
1452
1453         wl_tdm_vblank_set_fps(private_vblank->vblank, fps);
1454
1455         pthread_mutex_unlock(&private_client->lock);
1456
1457         return TDM_ERROR_NONE;
1458 }
1459
1460 tdm_error
1461 tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms)
1462 {
1463         tdm_private_client_vblank *private_vblank;
1464         tdm_private_client *private_client;
1465
1466         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1467
1468         private_vblank = vblank;
1469         TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
1470
1471         private_client = private_vblank->private_output->private_client;
1472
1473         pthread_mutex_lock(&private_client->lock);
1474
1475         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1476                 pthread_mutex_unlock(&private_client->lock);
1477                 return TDM_ERROR_PROTOCOL_ERROR;
1478         }
1479
1480         if (private_vblank->offset == offset_ms) {
1481                 pthread_mutex_unlock(&private_client->lock);
1482                 return TDM_ERROR_NONE;
1483         }
1484
1485         private_vblank->offset = offset_ms;
1486
1487         wl_tdm_vblank_set_offset(private_vblank->vblank, offset_ms);
1488
1489         pthread_mutex_unlock(&private_client->lock);
1490
1491         return TDM_ERROR_NONE;
1492 }
1493
1494 tdm_error
1495 tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable_fake)
1496 {
1497         tdm_private_client_vblank *private_vblank;
1498         tdm_private_client *private_client;
1499
1500         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1501
1502         private_vblank = vblank;
1503         private_client = private_vblank->private_output->private_client;
1504
1505         pthread_mutex_lock(&private_client->lock);
1506
1507         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1508                 pthread_mutex_unlock(&private_client->lock);
1509                 return TDM_ERROR_PROTOCOL_ERROR;
1510         }
1511
1512         if (private_vblank->enable_fake == enable_fake) {
1513                 pthread_mutex_unlock(&private_client->lock);
1514                 return TDM_ERROR_NONE;
1515         }
1516
1517         private_vblank->enable_fake = enable_fake;
1518
1519         wl_tdm_vblank_set_enable_fake(private_vblank->vblank, enable_fake);
1520
1521         pthread_mutex_unlock(&private_client->lock);
1522
1523         return TDM_ERROR_NONE;
1524 }
1525
1526 tdm_error
1527 tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_client_vblank_handler func, void *user_data)
1528 {
1529         tdm_private_client *private_client;
1530         tdm_private_client_output *private_output;
1531         tdm_private_client_vblank *private_vblank;
1532         tdm_client_wait_info *w;
1533         struct timespec tp;
1534         unsigned int req_sec, req_usec;
1535         int ret = 0;
1536
1537         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1538         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1539         /* can't support "interval 0" and "getting current_msc" things because
1540          * there is a socket communication between TDM client and server. It's impossible
1541          * to return the current msc or sequence immediately.
1542          */
1543         TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
1544
1545         private_vblank = vblank;
1546         private_output = private_vblank->private_output;
1547         private_client = private_output->private_client;
1548
1549         pthread_mutex_lock(&private_client->lock);
1550
1551         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1552                 pthread_mutex_unlock(&private_client->lock);
1553                 return TDM_ERROR_PROTOCOL_ERROR;
1554         }
1555
1556         if (!private_vblank->started)
1557                 private_vblank->started = 1;
1558
1559         if (!private_vblank->enable_fake) {
1560                 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1561                         TDM_ERR("output disconnected");
1562                         pthread_mutex_unlock(&private_client->lock);
1563                         return TDM_ERROR_OUTPUT_DISCONNECTED;
1564                 }
1565                 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1566                         TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1567                         pthread_mutex_unlock(&private_client->lock);
1568                         return TDM_ERROR_DPMS_OFF;
1569                 }
1570         }
1571
1572         w = calloc(1, sizeof *w);
1573         if (!w) {
1574                 /* LCOV_EXCL_START */
1575
1576                 TDM_ERR("alloc failed");
1577                 pthread_mutex_unlock(&private_client->lock);
1578                 return TDM_ERROR_OUT_OF_MEMORY;
1579
1580                 /* LCOV_EXCL_STOP */
1581         }
1582
1583         w->private_vblank = private_vblank;
1584         w->func = func;
1585         w->user_data = user_data;
1586
1587         LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1588         LIST_INITHEAD(&w->call_link);
1589
1590         clock_gettime(CLOCK_MONOTONIC, &tp);
1591         req_sec = (unsigned int)tp.tv_sec;
1592         req_usec = (unsigned int)(tp.tv_nsec / 1000);
1593
1594         w->req_id = ++private_output->req_id;
1595         w->req_time = TDM_TIME(req_sec, req_usec);
1596         w->need_free = (private_vblank->sync) ? 0 : 1;
1597
1598         wl_tdm_vblank_wait_vblank(private_vblank->vblank, interval, w->req_id, req_sec, req_usec);
1599
1600         if (private_vblank->enable_ttrace)
1601                 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1602
1603         TDM_DBG("vblank(%p) interval(%u) req_id(%d) req(%.6f)",
1604                         vblank, interval, w->req_id, w->req_time);
1605
1606         private_vblank->req_time = w->req_time;
1607
1608         if (private_vblank->last_time >= w->req_time)
1609                 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1610
1611         if (!private_vblank->sync) {
1612                 wl_display_flush(private_client->display);
1613                 pthread_mutex_unlock(&private_client->lock);
1614                 return TDM_ERROR_NONE;
1615         }
1616
1617         /* LCOV_EXCL_START */
1618
1619         while (ret != -1 && !w->need_free)
1620                 ret = wl_display_dispatch(private_client->display);
1621
1622         clock_gettime(CLOCK_MONOTONIC, &tp);
1623         TDM_DBG("block during %d us",
1624                         ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1625                         - (req_sec * 1000000 + req_usec));
1626
1627         LIST_DEL(&w->link);
1628         free(w);
1629
1630         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1631                 pthread_mutex_unlock(&private_client->lock);
1632                 return TDM_ERROR_PROTOCOL_ERROR;
1633         }
1634
1635         pthread_mutex_unlock(&private_client->lock);
1636
1637         return TDM_ERROR_NONE;
1638
1639         /* LCOV_EXCL_STOP */
1640 }
1641
1642 tdm_error
1643 tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
1644                                                    tdm_client_vblank_handler func, void *user_data)
1645 {
1646         tdm_private_client *private_client;
1647         tdm_private_client_output *private_output;
1648         tdm_private_client_vblank *private_vblank;
1649         tdm_client_wait_info *w;
1650         struct timespec tp;
1651         unsigned int req_sec, req_usec;
1652         int ret = 0;
1653
1654         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1655         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1656
1657         private_vblank = vblank;
1658         private_output = private_vblank->private_output;
1659         private_client = private_output->private_client;
1660
1661         pthread_mutex_lock(&private_client->lock);
1662
1663         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1664                 pthread_mutex_unlock(&private_client->lock);
1665                 return TDM_ERROR_PROTOCOL_ERROR;
1666         }
1667
1668         if (!private_vblank->started)
1669                 private_vblank->started = 1;
1670
1671         if (!private_vblank->enable_fake) {
1672                 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1673                         TDM_ERR("output disconnected");
1674                         pthread_mutex_unlock(&private_client->lock);
1675                         return TDM_ERROR_OUTPUT_DISCONNECTED;
1676                 }
1677                 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1678                         TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1679                         pthread_mutex_unlock(&private_client->lock);
1680                         return TDM_ERROR_DPMS_OFF;
1681                 }
1682         }
1683
1684         w = calloc(1, sizeof *w);
1685         if (!w) {
1686                 /* LCOV_EXCL_START */
1687
1688                 TDM_ERR("alloc failed");
1689                 pthread_mutex_unlock(&private_client->lock);
1690                 return TDM_ERROR_OUT_OF_MEMORY;
1691
1692                 /* LCOV_EXCL_STOP */
1693         }
1694
1695         w->private_vblank = private_vblank;
1696         w->func = func;
1697         w->user_data = user_data;
1698
1699         LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1700         LIST_INITHEAD(&w->call_link);
1701
1702         clock_gettime(CLOCK_MONOTONIC, &tp);
1703         req_sec = (unsigned int)tp.tv_sec;
1704         req_usec = (unsigned int)(tp.tv_nsec / 1000);
1705
1706         w->req_id = ++private_output->req_id;
1707         w->req_time = TDM_TIME(req_sec, req_usec);
1708         w->need_free = (private_vblank->sync) ? 0 : 1;
1709
1710         wl_tdm_vblank_wait_vblank_seq(private_vblank->vblank, sequence, w->req_id, req_sec, req_usec);
1711
1712         if (private_vblank->enable_ttrace)
1713                 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1714
1715         TDM_DBG("vblank(%p) sequence(%u) req_id(%d) req(%.6f)",
1716                         vblank, sequence, w->req_id, w->req_time);
1717
1718         private_vblank->req_time = w->req_time;
1719
1720         if (private_vblank->last_time >= w->req_time)
1721                 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1722
1723         if (!private_vblank->sync) {
1724                 wl_display_flush(private_client->display);
1725                 pthread_mutex_unlock(&private_client->lock);
1726                 return TDM_ERROR_NONE;
1727         }
1728
1729         /* LCOV_EXCL_START */
1730
1731         while (ret != -1 && !w->need_free)
1732                 ret = wl_display_dispatch(private_client->display);
1733
1734         clock_gettime(CLOCK_MONOTONIC, &tp);
1735         TDM_DBG("block during %d us",
1736                         ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1737                         - (req_sec * 1000000 + req_usec));
1738
1739         LIST_DEL(&w->link);
1740         free(w);
1741
1742         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1743                 pthread_mutex_unlock(&private_client->lock);
1744                 return TDM_ERROR_PROTOCOL_ERROR;
1745         }
1746
1747         pthread_mutex_unlock(&private_client->lock);
1748
1749         return TDM_ERROR_NONE;
1750
1751         /* LCOV_EXCL_STOP */
1752 }
1753
1754 unsigned int
1755 tdm_client_vblank_is_waiting(tdm_client_vblank *vblank)
1756 {
1757         tdm_private_client_vblank *private_vblank;
1758
1759         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, 0);
1760
1761         private_vblank = vblank;
1762
1763         return (LIST_LENGTH(&private_vblank->wait_list) > 0) ? 1 : 0;
1764 }
1765
1766 static tbm_surface_h
1767 _tdm_client_voutput_create_surface_from_param(tbm_bufmgr bufmgr,
1768                                                          int is_fd,
1769                                                          int32_t width,
1770                                                          int32_t height,
1771                                                          uint32_t format,
1772                                                          int32_t bpp,
1773                                                          int32_t size,
1774                                                          int32_t num_plane,
1775                                                          struct wl_array *plane_buf_idx,
1776                                                          struct wl_array *plane_offset,
1777                                                          struct wl_array *plane_stride,
1778                                                          struct wl_array *plane_size,
1779                                                          uint32_t flags,
1780                                                          int32_t num_buf,
1781                                                          uint32_t buf0,
1782                                                          uint32_t buf1,
1783                                                          uint32_t buf2)
1784 {
1785         int32_t names[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1};
1786         tbm_surface_info_s info = { 0, };
1787         tbm_bo bos[TBM_SURF_PLANE_MAX];
1788         int i, numPlane, numName;
1789         tbm_surface_h tbm_surface;
1790
1791         numPlane = tbm_surface_internal_get_num_planes(format);
1792         TDM_RETURN_VAL_IF_FAIL(numPlane == num_plane, NULL);
1793
1794         info.width = width;
1795         info.height = height;
1796         info.format = format;
1797         info.bpp = bpp;
1798         info.size = size;
1799         info.num_planes = numPlane;
1800
1801         /*Fill plane info*/
1802         for (i = 0; i < numPlane; i++) {
1803                 info.planes[i].offset = *TDM_ARRAY_NTH_DATA(plane_offset, int32_t, i);
1804                 info.planes[i].stride = *TDM_ARRAY_NTH_DATA(plane_stride, int32_t, i);
1805                 info.planes[i].size = *TDM_ARRAY_NTH_DATA(plane_size, int32_t, i);
1806         }
1807
1808         /*Fill buffer*/
1809         numName = num_buf;
1810         names[0] = buf0;
1811         names[1] = buf1;
1812         names[2] = buf2;
1813
1814         for (i = 0; i < numName; i++) {
1815                 if (is_fd)
1816                         bos[i] = tbm_bo_import_fd(bufmgr, names[i]);
1817                 else
1818                         bos[i] = tbm_bo_import(bufmgr, names[i]);
1819         }
1820
1821         tbm_surface = tbm_surface_internal_create_with_bos(&info, bos, numName);
1822         if (tbm_surface == NULL) {
1823                 if (is_fd) {
1824                         close(buf0);
1825                         close(buf1);
1826                         close(buf2);
1827                 }
1828                 return NULL;
1829         }
1830
1831         if (is_fd) {
1832                 close(buf0);
1833                 close(buf1);
1834                 close(buf2);
1835         }
1836
1837         for (i = 0; i < numName; i++)
1838                 tbm_bo_unref(bos[i]);
1839
1840         return tbm_surface;
1841 }
1842 static void
1843 tdm_client_voutput_cb_buffer_import_with_id(void *data,
1844                 struct wl_tdm_voutput *wl_voutput,
1845                 struct wl_buffer *wl_buffer,
1846                 int32_t width,
1847                 int32_t height,
1848                 uint32_t format,
1849                 int32_t bpp,
1850                 int32_t size,
1851                 int32_t num_plane,
1852                 struct wl_array *plane_buf_idx,
1853                 struct wl_array *plane_offset,
1854                 struct wl_array *plane_stride,
1855                 struct wl_array *plane_size,
1856                 uint32_t flags,
1857                 int32_t num_buf,
1858                 uint32_t buf0,
1859                 uint32_t buf1,
1860                 uint32_t buf2)
1861 {
1862         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1863         tdm_private_client_buffer *buffer = NULL;
1864         tbm_surface_h tbm_surface;
1865
1866         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1867
1868         buffer = calloc(1, sizeof *buffer);
1869         TDM_RETURN_IF_FAIL(buffer != NULL);
1870
1871         tbm_surface = _tdm_client_voutput_create_surface_from_param(private_voutput->bufmgr, 0,
1872                               width, height, format, bpp, size,
1873                               num_plane,
1874                               plane_buf_idx, plane_offset, plane_stride, plane_size,
1875                               0,
1876                               num_buf,
1877                               buf0, buf1, buf2);
1878         TDM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
1879
1880         tbm_surface_internal_ref(tbm_surface);
1881         wl_buffer_set_user_data(wl_buffer, tbm_surface);
1882
1883         buffer->wl_buffer = wl_buffer;
1884
1885         LIST_ADDTAIL(&buffer->link, &private_voutput->buffer_list);
1886
1887         return;
1888
1889 fail:
1890         if (buffer)
1891                 free(buffer);
1892
1893         if (wl_buffer)
1894                 wl_buffer_destroy(wl_buffer);
1895 }
1896
1897 static void
1898 tdm_client_voutput_cb_buffer_import_with_fd(void *data,
1899                 struct wl_tdm_voutput *wl_voutput,
1900                 struct wl_buffer *wl_buffer,
1901                 int32_t width,
1902                 int32_t height,
1903                 uint32_t format,
1904                 int32_t bpp,
1905                 int32_t size,
1906                 int32_t num_plane,
1907                 struct wl_array *plane_buf_idx,
1908                 struct wl_array *plane_offset,
1909                 struct wl_array *plane_stride,
1910                 struct wl_array *plane_size,
1911                 uint32_t flags,
1912                 int32_t num_buf,
1913                 int32_t buf0,
1914                 int32_t buf1,
1915                 int32_t buf2)
1916 {
1917         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1918         tdm_private_client_buffer *buffer = NULL;
1919         tbm_surface_h tbm_surface;
1920
1921         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1922
1923         buffer = calloc(1, sizeof *buffer);
1924         TDM_RETURN_IF_FAIL(buffer != NULL);
1925
1926         tbm_surface = _tdm_client_voutput_create_surface_from_param(private_voutput->bufmgr, 1,
1927                               width, height, format, bpp, size,
1928                               num_plane,
1929                               plane_buf_idx, plane_offset, plane_stride, plane_size,
1930                               0,
1931                               num_buf,
1932                               buf0, buf1, buf2);
1933         TDM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
1934
1935         tbm_surface_internal_ref(tbm_surface);
1936         wl_buffer_set_user_data(wl_buffer, tbm_surface);
1937
1938         buffer->wl_buffer = wl_buffer;
1939
1940         LIST_ADDTAIL(&buffer->link, &private_voutput->buffer_list);
1941
1942         return;
1943
1944 fail:
1945         if (buffer)
1946                 free(buffer);
1947
1948         if (wl_buffer)
1949                 wl_buffer_destroy(wl_buffer);
1950 }
1951
1952 static void
1953 tdm_client_voutput_cb_buffer_destroy(void *data,
1954                 struct wl_tdm_voutput *wl_voutput,
1955                 struct wl_buffer *wl_buffer)
1956 {
1957         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1958         tdm_private_client_buffer *cb = NULL, *cbb = NULL;
1959         tbm_surface_h tbm_surface = NULL;
1960
1961         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1962
1963         LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
1964                 if (wl_buffer == cb->wl_buffer) {
1965                         LIST_DEL(&cb->link);
1966
1967                         tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(wl_buffer);
1968                         if (tbm_surface)
1969                                 tbm_surface_internal_unref(tbm_surface);
1970
1971                         wl_buffer_set_user_data(wl_buffer, NULL);
1972                         wl_buffer_destroy(wl_buffer);
1973
1974                         free(cb);
1975
1976                         break;
1977                 }
1978         }
1979
1980         return;
1981 }
1982
1983 void
1984 tdm_client_voutput_cb_attach_buffer(void *data,
1985                 struct wl_tdm_voutput *wl_voutput,
1986                 struct wl_buffer *wl_buffer)
1987 {
1988         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1989         tdm_private_client_buffer *cb = NULL, *cbb = NULL;
1990
1991         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1992
1993         LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
1994                 if (wl_buffer == cb->wl_buffer) {
1995                         private_voutput->attach_buffer = cb;
1996                         break;
1997                 }
1998         }
1999
2000         return;
2001 }
2002
2003 void
2004 tdm_client_voutput_cb_commit(void *data, struct wl_tdm_voutput *wl_voutput)
2005 {
2006         tdm_private_client_voutput *private_voutput;
2007         tdm_private_client *private_client;
2008         tbm_surface_h buffer = NULL;
2009         tdm_client_voutput_commit_handler_info *h = NULL, *hh = NULL;
2010         struct list_head call_list;
2011
2012         private_voutput = (tdm_private_client_voutput *)data;
2013         TDM_RETURN_IF_FAIL(private_voutput != NULL);
2014         TDM_RETURN_IF_FAIL(private_voutput->attach_buffer != NULL);
2015
2016         buffer = (tbm_surface_h)wl_buffer_get_user_data(private_voutput->attach_buffer->wl_buffer);
2017         TDM_RETURN_IF_FAIL(buffer != NULL);
2018
2019         tbm_surface_internal_ref(buffer);
2020
2021         private_client = private_voutput->private_client;
2022
2023         LIST_INITHEAD(&call_list);
2024
2025         LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2026                 LIST_ADDTAIL(&h->call_link, &call_list);
2027         }
2028
2029         pthread_mutex_unlock(&private_client->lock);
2030         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
2031                 if (h->func)
2032                         h->func(private_voutput, buffer, h->user_data);
2033         }
2034         pthread_mutex_lock(&private_client->lock);
2035
2036         /* if no added commit_handler call commit done immediately */
2037         if (LIST_IS_EMPTY(&private_voutput->commit_handler_list))
2038                 tdm_client_voutput_commit_done(private_voutput);
2039 }
2040
2041 void
2042 tdm_client_voutput_cb_ack_message(void *data, struct wl_tdm_voutput *wl_voutput, uint32_t msg)
2043 {
2044         tdm_private_client_voutput *private_voutput = data;
2045
2046         private_voutput->msg = msg;
2047 }
2048
2049 static const struct wl_tdm_voutput_listener tdm_client_voutput_lisntener = {
2050         tdm_client_voutput_cb_buffer_import_with_id,
2051         tdm_client_voutput_cb_buffer_import_with_fd,
2052         tdm_client_voutput_cb_buffer_destroy,
2053         tdm_client_voutput_cb_attach_buffer,
2054         tdm_client_voutput_cb_commit,
2055         tdm_client_voutput_cb_ack_message
2056 };
2057
2058 tdm_client_voutput *
2059 tdm_client_create_voutput(tdm_client *client, const char *name, tdm_error *error)
2060 {
2061         tdm_private_client *private_client;
2062         tdm_private_client_output *private_output;
2063         tdm_private_client_voutput *private_voutput;
2064         struct wl_proxy *wrapper;
2065
2066         if (error)
2067                 *error = TDM_ERROR_NONE;
2068
2069         if (!client) {
2070                 TDM_ERR("'!client' failed");
2071                 if (error)
2072                         *error = TDM_ERROR_INVALID_PARAMETER;
2073                 return NULL;
2074         }
2075
2076         if (!name) {
2077                 TDM_ERR("'!name' failed");
2078                 if (error)
2079                         *error = TDM_ERROR_INVALID_PARAMETER;
2080                 return NULL;
2081         }
2082
2083         private_client = (tdm_private_client *)client;
2084
2085         pthread_mutex_lock(&private_client->lock);
2086
2087         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2088                 if (error)
2089                         *error = TDM_ERROR_PROTOCOL_ERROR;
2090                 pthread_mutex_unlock(&private_client->lock);
2091                 return NULL;
2092         }
2093
2094         LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
2095                 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
2096                         if (error)
2097                                 *error = TDM_ERROR_INVALID_PARAMETER; // FIXME define new error type.
2098                         pthread_mutex_unlock(&private_client->lock);
2099                         return NULL;
2100                 }
2101         }
2102
2103         wrapper = wl_proxy_create_wrapper(private_client->tdm);
2104         if (!wrapper) {
2105                 TDM_ERR("create virtual output wrapper failed");
2106                 if (error)
2107                         *error = TDM_ERROR_OUT_OF_MEMORY;
2108                 pthread_mutex_unlock(&private_client->lock);
2109                 return NULL;
2110         }
2111
2112         wl_proxy_set_queue(wrapper, private_client->queue);
2113
2114         private_voutput = calloc(1, sizeof *private_voutput);
2115         if (!private_voutput) {
2116                 /* LOCV_EXCL_START */
2117                 wl_proxy_wrapper_destroy(wrapper);
2118                 TDM_ERR("alloc failed");
2119                 if (error)
2120                         *error = TDM_ERROR_OUT_OF_MEMORY;
2121                 pthread_mutex_unlock(&private_client->lock);
2122                 return NULL;
2123                 /* LOCV_EXCL_STOP */
2124         }
2125
2126         private_voutput->bufmgr = tbm_bufmgr_init(-1);
2127         if (private_voutput->bufmgr == NULL) {
2128                 /* LCOV_EXCL_START */
2129                 TDM_ERR("fail tbm_bufmgr_init");
2130                 free(private_voutput);
2131                 if (error)
2132                         *error = TDM_ERROR_OUT_OF_MEMORY;
2133                 pthread_mutex_unlock(&private_client->lock);
2134                 return NULL;
2135                 /* LCOV_EXCL_STOP */
2136         }
2137
2138         LIST_INITHEAD(&private_voutput->commit_handler_list);
2139         LIST_INITHEAD(&private_voutput->buffer_list);
2140
2141         private_voutput->private_client = private_client;
2142         strncpy(private_voutput->name, name, TDM_NAME_LEN);
2143
2144         private_voutput->wl_voutput = wl_tdm_create_voutput((struct wl_tdm *)wrapper, name);
2145         wl_proxy_wrapper_destroy(wrapper);
2146         if (!private_voutput->wl_voutput) {
2147                 /* LCOV_EXCL_START */
2148                 TDM_ERR("couldn't create voutput resource");
2149                 free(private_voutput);
2150                 if (error)
2151                         *error = TDM_ERROR_OUT_OF_MEMORY;
2152                 pthread_mutex_unlock(&private_client->lock);
2153                 return NULL;
2154                 /* LCOV_EXCL_STOP */
2155         }
2156
2157         wl_tdm_voutput_add_listener(private_voutput->wl_voutput,
2158                                                                 &tdm_client_voutput_lisntener, private_voutput);
2159         wl_display_roundtrip_queue(private_client->display, private_client->queue);
2160
2161         wl_proxy_set_queue((struct wl_proxy *)private_voutput->wl_voutput, NULL);
2162
2163         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2164                 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2165                 free(private_voutput);
2166                 if (error)
2167                         *error = TDM_ERROR_PROTOCOL_ERROR;
2168                 pthread_mutex_unlock(&private_client->lock);
2169                 return NULL;
2170         }
2171
2172         if (private_voutput->msg != WL_TDM_VOUTPUT_MESSAGE_ADDED)
2173         {
2174                 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2175                 free(private_voutput);
2176                 if (error)
2177                         *error = TDM_ERROR_PROTOCOL_ERROR;      // FIXME add new error type.
2178                 pthread_mutex_unlock(&private_client->lock);
2179                 return NULL;
2180         }
2181
2182         LIST_ADDTAIL(&private_voutput->link, &private_client->voutput_list);
2183
2184         pthread_mutex_unlock(&private_client->lock);
2185
2186         return (tdm_client_voutput *)private_voutput;
2187 }
2188
2189 void
2190 tdm_client_voutput_destroy(tdm_client_voutput *voutput)
2191 {
2192         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)voutput;
2193         tdm_client_voutput_commit_handler_info *h = NULL, *hh = NULL;
2194
2195         if (!private_voutput)
2196                 return;
2197
2198         if (!(LIST_IS_EMPTY(&private_voutput->buffer_list))) {
2199                 tdm_private_client_buffer *cb = NULL, *cbb = NULL;
2200
2201                 LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
2202                         tbm_surface_h tbm_surface = NULL;
2203
2204                         if (!cb) continue;
2205
2206                         LIST_DEL(&cb->link);
2207
2208                         tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(cb->wl_buffer);
2209                         if (tbm_surface)
2210                                 tbm_surface_internal_unref(tbm_surface);
2211
2212                         wl_buffer_set_user_data(cb->wl_buffer, NULL);
2213                         wl_buffer_destroy(cb->wl_buffer);
2214
2215                         free(cb);
2216                 }
2217         }
2218
2219         if (private_voutput->bufmgr)
2220                 tbm_bufmgr_deinit(private_voutput->bufmgr);
2221
2222         if (private_voutput->available_modes.modes)
2223                 free(private_voutput->available_modes.modes);
2224
2225         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_voutput->commit_handler_list, link) {
2226                 LIST_DEL(&h->link);
2227                 free(h);
2228         }
2229
2230         if (private_voutput->get_output)
2231                 _tdm_client_output_destroy(private_voutput->private_output);
2232
2233         wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2234
2235         LIST_DEL(&private_voutput->link);
2236
2237         free(private_voutput);
2238 }
2239
2240 tdm_error
2241 tdm_client_voutput_set_available_modes(tdm_client_voutput *voutput, const tdm_client_output_mode *modes, int count)
2242 {
2243         tdm_private_client_voutput *private_voutput;
2244
2245         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2246
2247         if ((count > 0) && (modes == NULL))
2248                 return TDM_ERROR_INVALID_PARAMETER;
2249
2250         private_voutput = (tdm_private_client_voutput *)voutput;
2251
2252         if (private_voutput->private_output->connection == TDM_OUTPUT_CONN_STATUS_CONNECTED)
2253                 return TDM_ERROR_BAD_REQUEST;
2254
2255         if (private_voutput->available_modes.modes)
2256                 free(private_voutput->available_modes.modes);
2257
2258         private_voutput->available_modes.count = count;
2259
2260         if (count != 0)
2261         {
2262                 private_voutput->available_modes.modes = calloc(count, sizeof(tdm_client_output_mode));
2263                 memcpy(private_voutput->available_modes.modes, modes, sizeof(tdm_client_output_mode) * count);
2264         }
2265
2266         return TDM_ERROR_NONE;
2267 }
2268
2269 tdm_error
2270 tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, unsigned int mmWidth, unsigned int mmHeight)
2271 {
2272         tdm_private_client_voutput *private_voutput;
2273
2274         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2275         TDM_RETURN_VAL_IF_FAIL(mmWidth != 0, TDM_ERROR_INVALID_PARAMETER);
2276         TDM_RETURN_VAL_IF_FAIL(mmHeight != 0, TDM_ERROR_INVALID_PARAMETER);
2277
2278         private_voutput = (tdm_private_client_voutput *)voutput;
2279
2280         if (private_voutput->private_output->connection == TDM_OUTPUT_CONN_STATUS_CONNECTED)
2281                 return TDM_ERROR_BAD_REQUEST;
2282
2283         private_voutput->mmwidth = mmWidth;
2284         private_voutput->mmheight = mmHeight;
2285
2286         return TDM_ERROR_NONE;
2287 }
2288
2289 tdm_error
2290 tdm_client_voutput_add_commit_handler(tdm_client_voutput *voutput,
2291                                                                           tdm_client_voutput_commit_handler func,
2292                                                                           void *user_data)
2293 {
2294         tdm_private_client_voutput *private_voutput;
2295         tdm_private_client *private_client;
2296         tdm_client_voutput_commit_handler_info *h = NULL;
2297
2298         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2299         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
2300
2301         private_voutput = (tdm_private_client_voutput *)voutput;
2302         private_client = private_voutput->private_client;
2303
2304         LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2305                 if (h->func == func && h->user_data == user_data) {
2306                         TDM_ERR("can't add twice");
2307                         return TDM_ERROR_BAD_REQUEST;
2308                 }
2309         }
2310
2311         h = calloc(1, sizeof *h);
2312         TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
2313
2314         pthread_mutex_lock(&private_client->lock);
2315
2316         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2317                 free(h);
2318                 pthread_mutex_unlock(&private_client->lock);
2319                 return TDM_ERROR_PROTOCOL_ERROR;
2320         }
2321
2322         h->private_voutput = private_voutput;
2323         h->func = func;
2324         h->user_data = user_data;
2325         LIST_ADDTAIL(&h->link, &private_voutput->commit_handler_list);
2326         LIST_INITHEAD(&h->call_link);
2327
2328         pthread_mutex_unlock(&private_client->lock);
2329
2330         return TDM_ERROR_NONE;
2331 }
2332
2333 void
2334 tdm_client_voutput_remove_commit_handler(tdm_client_voutput *voutput,
2335                                                                                  tdm_client_voutput_commit_handler func,
2336                                                                                  void *user_data)
2337 {
2338         tdm_private_client_voutput *private_voutput;
2339         tdm_private_client *private_client;
2340         tdm_client_voutput_commit_handler_info *h = NULL;
2341
2342         TDM_RETURN_IF_FAIL(voutput != NULL);
2343         TDM_RETURN_IF_FAIL(func != NULL);
2344
2345         private_voutput = (tdm_private_client_voutput *)voutput;
2346         private_client = private_voutput->private_client;
2347
2348         pthread_mutex_lock(&private_client->lock);
2349
2350         LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2351                 if (h->func != func || h->user_data != user_data)
2352                         continue;
2353
2354                 LIST_DEL(&h->link);
2355                 free(h);
2356
2357                 pthread_mutex_unlock(&private_client->lock);
2358         }
2359
2360         pthread_mutex_unlock(&private_client->lock);
2361 }
2362
2363 tdm_error
2364 tdm_client_voutput_commit_done(tdm_client_voutput *voutput)
2365 {
2366         tdm_private_client_voutput *private_voutput;
2367         tbm_surface_h buffer = NULL;
2368
2369         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2370
2371         private_voutput = (tdm_private_client_voutput *)voutput;
2372         buffer = (tbm_surface_h)wl_buffer_get_user_data(private_voutput->attach_buffer->wl_buffer);
2373         tbm_surface_internal_unref(buffer);
2374         private_voutput->attach_buffer = NULL;
2375         wl_tdm_voutput_commit_done(private_voutput->wl_voutput);
2376
2377         return TDM_ERROR_NONE;
2378 }
2379
2380 tdm_client_output *
2381 tdm_client_voutput_get_client_output(tdm_client_voutput *voutput, tdm_error *error)
2382 {
2383         tdm_private_client_voutput *private_voutput;
2384         tdm_private_client_output *private_output = NULL;
2385         tdm_error ret = TDM_ERROR_NONE;
2386
2387         if (error)
2388                 *error = TDM_ERROR_NONE;
2389
2390         if (!voutput) {
2391                 TDM_ERR("'!voutput' failed");
2392                 if (error)
2393                         *error = TDM_ERROR_INVALID_PARAMETER;
2394                 return NULL;
2395         }
2396
2397         private_voutput = (tdm_private_client_voutput *)voutput;
2398
2399         if (private_voutput->get_output)
2400                 return private_voutput->private_output;
2401
2402         private_output = (tdm_private_client_output *)tdm_client_get_output(private_voutput->private_client, private_voutput->name, &ret);
2403         if (!private_output) {
2404                 TDM_ERR("tdm_client_voutput_get_client_output get private_output fail");
2405                 if (error)
2406                         *error = ret;
2407                 return NULL;
2408         }
2409         private_output->voutput = private_voutput;
2410         private_voutput->private_output = private_output;
2411         private_voutput->get_output = 1;
2412
2413         return private_output;
2414 }
2415
2416 void
2417 _tdm_client_voutput_send_available_modes(tdm_private_client_voutput *private_voutput)
2418 {
2419         tdm_client_output_mode *modes, *mode;
2420         struct wl_array array;
2421         int i, size;
2422
2423         modes = private_voutput->available_modes.modes;
2424         size = sizeof(tdm_client_output_mode);
2425
2426         wl_array_init(&array);
2427         for (i = 0; i < private_voutput->available_modes.count; i++) {
2428                 mode = wl_array_add(&array, size);
2429                 memcpy(mode, &modes[i], size);
2430         }
2431         wl_tdm_voutput_set_available_modes(private_voutput->wl_voutput, &array);
2432         wl_array_release(&array);
2433 }
2434
2435 tdm_error
2436 tdm_client_output_connect(tdm_client_output *output)
2437 {
2438         tdm_private_client_output *private_output;
2439         tdm_private_client_voutput *private_voutput = NULL;
2440
2441         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2442
2443         private_output = (tdm_private_client_output *)output;
2444         if (!private_output->voutput) return TDM_ERROR_INVALID_PARAMETER;
2445         private_voutput = private_output->voutput;
2446
2447         TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_CONNECTED,
2448                                                    TDM_ERROR_BAD_REQUEST);
2449
2450         if (!private_output->watch_output_changes)
2451                 private_output->connection = TDM_OUTPUT_CONN_STATUS_CONNECTED;
2452
2453         _tdm_client_voutput_send_available_modes(private_voutput);
2454
2455         wl_tdm_voutput_set_physical_size(private_voutput->wl_voutput, private_voutput->mmwidth, private_voutput->mmheight);
2456
2457         /* To Do : change voutput to output */
2458         wl_tdm_voutput_connect(private_voutput->wl_voutput);
2459
2460         return TDM_ERROR_NONE;
2461 }
2462
2463 tdm_error
2464 tdm_client_output_disconnect(tdm_client_output *output)
2465 {
2466         tdm_private_client_output *private_output;
2467         tdm_private_client_voutput *private_voutput = NULL;
2468
2469         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2470
2471         private_output = (tdm_private_client_output *)output;
2472         if (!private_output->voutput) return TDM_ERROR_INVALID_PARAMETER;
2473         private_voutput = private_output->voutput;
2474
2475         TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED,
2476                                                    TDM_ERROR_BAD_REQUEST);
2477
2478         if (!private_output->watch_output_changes)
2479                 private_output->connection = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
2480
2481         /* To Do : change voutput to output */
2482         wl_tdm_voutput_disconnect(private_voutput->wl_voutput);
2483
2484         return TDM_ERROR_NONE;
2485 }