virtual: support tdm_client output_set_mode
[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         tdm_private_client *private_client;
1232
1233         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1234         TDM_RETURN_VAL_IF_FAIL(index >= 0, TDM_ERROR_INVALID_PARAMETER);
1235
1236         private_output = (tdm_private_client_output*)output;
1237         private_client = private_output->private_client;
1238
1239         pthread_mutex_lock(&private_client->lock);
1240
1241         if (private_output->available_modes.count - 1 < index)
1242                 return TDM_ERROR_INVALID_PARAMETER;
1243
1244         if ((private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) ||
1245                 (private_output->available_modes.count == 0))
1246                 return TDM_ERROR_BAD_REQUEST;
1247
1248         wl_tdm_output_set_mode(private_output->output, index);
1249
1250         pthread_mutex_unlock(&private_client->lock);
1251
1252         return TDM_ERROR_NONE;
1253 }
1254
1255 tdm_client_vblank*
1256 tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
1257 {
1258         tdm_private_client *private_client;
1259         tdm_private_client_output *private_output;
1260         tdm_private_client_vblank *private_vblank;
1261         struct wl_proxy *wrapper;
1262
1263         if (error)
1264                 *error = TDM_ERROR_NONE;
1265
1266         if (!output) {
1267                 TDM_ERR("'!output' failed");
1268                 if (error)
1269                         *error = TDM_ERROR_INVALID_PARAMETER;
1270                 return NULL;
1271         }
1272
1273         private_output = (tdm_private_client_output*)output;
1274         private_client = private_output->private_client;
1275
1276         pthread_mutex_lock(&private_client->lock);
1277
1278         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1279                 if (error)
1280                         *error = TDM_ERROR_PROTOCOL_ERROR;
1281                 pthread_mutex_unlock(&private_client->lock);
1282                 return NULL;
1283         }
1284
1285         wrapper = wl_proxy_create_wrapper(private_output->output);
1286         if (!wrapper) {
1287                 TDM_ERR("create output_wrapper failed");
1288                 if (error)
1289                         *error = TDM_ERROR_OUT_OF_MEMORY;
1290                 pthread_mutex_unlock(&private_client->lock);
1291                 return NULL;
1292         }
1293
1294         wl_proxy_set_queue(wrapper, private_client->queue);
1295
1296         private_vblank = calloc(1, sizeof *private_vblank);
1297         if (!private_vblank) {
1298                 /* LCOV_EXCL_START */
1299
1300                 TDM_ERR("alloc failed");
1301                 wl_proxy_wrapper_destroy(wrapper);
1302                 if (error)
1303                         *error = TDM_ERROR_OUT_OF_MEMORY;
1304                 pthread_mutex_unlock(&private_client->lock);
1305                 return NULL;
1306
1307                 /* LCOV_EXCL_STOP */
1308         }
1309
1310         private_vblank->private_output = private_output;
1311
1312         private_vblank->vblank = wl_tdm_output_create_vblank((struct wl_tdm_output*)wrapper);
1313         wl_proxy_wrapper_destroy(wrapper);
1314         if (!private_vblank->vblank) {
1315                 /* LCOV_EXCL_START */
1316
1317                 TDM_ERR("couldn't create vblank resource");
1318                 free(private_vblank);
1319                 if (error)
1320                         *error = TDM_ERROR_OUT_OF_MEMORY;
1321                 pthread_mutex_unlock(&private_client->lock);
1322                 return NULL;
1323
1324                 /* LCOV_EXCL_STOP */
1325         }
1326
1327         /* initial value */
1328         private_vblank->fps = private_output->refresh;
1329         private_vblank->offset = 0;
1330         private_vblank->enable_fake = 0;
1331
1332         LIST_INITHEAD(&private_vblank->wait_list);
1333
1334         wl_tdm_vblank_add_listener(private_vblank->vblank,
1335                                                            &tdm_client_vblank_listener, private_vblank);
1336         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1337
1338         wl_proxy_set_queue((struct wl_proxy *)private_vblank->vblank, NULL);
1339
1340         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1341                 wl_tdm_vblank_destroy(private_vblank->vblank);
1342                 free(private_vblank);
1343                 if (error)
1344                         *error = TDM_ERROR_PROTOCOL_ERROR;
1345                 pthread_mutex_unlock(&private_client->lock);
1346                 return NULL;
1347         }
1348
1349         LIST_ADDTAIL(&private_vblank->link, &private_output->vblank_list);
1350
1351         pthread_mutex_unlock(&private_client->lock);
1352
1353         return (tdm_client_vblank*)private_vblank;
1354 }
1355
1356 void
1357 tdm_client_vblank_destroy(tdm_client_vblank *vblank)
1358 {
1359         tdm_private_client_vblank *private_vblank;
1360         tdm_private_client *private_client;
1361         tdm_client_wait_info *w = NULL, *ww = NULL;
1362
1363         TDM_RETURN_IF_FAIL(vblank != NULL);
1364
1365         private_vblank = vblank;
1366         private_client = private_vblank->private_output->private_client;
1367
1368         pthread_mutex_lock(&private_client->lock);
1369
1370         LIST_DEL(&private_vblank->link);
1371
1372         LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
1373                 LIST_DEL(&w->link);
1374                 free(w);
1375         }
1376
1377         wl_tdm_vblank_destroy(private_vblank->vblank);
1378
1379         free(private_vblank);
1380
1381         pthread_mutex_unlock(&private_client->lock);
1382 }
1383
1384 tdm_error
1385 tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name)
1386 {
1387         tdm_private_client_vblank *private_vblank;
1388         tdm_private_client *private_client;
1389
1390         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1391
1392         private_vblank = vblank;
1393         private_client = private_vblank->private_output->private_client;
1394
1395         pthread_mutex_lock(&private_client->lock);
1396
1397         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1398                 pthread_mutex_unlock(&private_client->lock);
1399                 return TDM_ERROR_PROTOCOL_ERROR;
1400         }
1401
1402         if (!name)
1403                 name = TDM_VBLANK_DEFAULT_NAME;
1404
1405         strncpy(private_vblank->name, name, TDM_NAME_LEN - 1);
1406         private_vblank->name[TDM_NAME_LEN - 1] = '\0';
1407
1408         wl_tdm_vblank_set_name(private_vblank->vblank, private_vblank->name);
1409
1410         pthread_mutex_unlock(&private_client->lock);
1411
1412         return TDM_ERROR_NONE;
1413 }
1414
1415 tdm_error
1416 tdm_client_vblank_set_sync(tdm_client_vblank *vblank, unsigned int sync)
1417 {
1418         tdm_private_client_vblank *private_vblank;
1419         tdm_private_client *private_client;
1420
1421         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1422
1423         private_vblank = vblank;
1424         private_client = private_vblank->private_output->private_client;
1425
1426         pthread_mutex_lock(&private_client->lock);
1427         private_vblank->sync = sync;
1428         pthread_mutex_unlock(&private_client->lock);
1429
1430         return TDM_ERROR_NONE;
1431 }
1432
1433 tdm_error
1434 tdm_client_vblank_set_fps(tdm_client_vblank *vblank, unsigned int fps)
1435 {
1436         tdm_private_client_vblank *private_vblank;
1437         tdm_private_client *private_client;
1438
1439         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1440         TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER);
1441
1442         private_vblank = vblank;
1443         private_client = private_vblank->private_output->private_client;
1444
1445         pthread_mutex_lock(&private_client->lock);
1446
1447         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1448                 pthread_mutex_unlock(&private_client->lock);
1449                 return TDM_ERROR_PROTOCOL_ERROR;
1450         }
1451
1452         if (private_vblank->fps == fps) {
1453                 pthread_mutex_unlock(&private_client->lock);
1454                 return TDM_ERROR_NONE;
1455         }
1456
1457         private_vblank->fps = fps;
1458
1459         wl_tdm_vblank_set_fps(private_vblank->vblank, fps);
1460
1461         pthread_mutex_unlock(&private_client->lock);
1462
1463         return TDM_ERROR_NONE;
1464 }
1465
1466 tdm_error
1467 tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms)
1468 {
1469         tdm_private_client_vblank *private_vblank;
1470         tdm_private_client *private_client;
1471
1472         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1473
1474         private_vblank = vblank;
1475         TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
1476
1477         private_client = private_vblank->private_output->private_client;
1478
1479         pthread_mutex_lock(&private_client->lock);
1480
1481         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1482                 pthread_mutex_unlock(&private_client->lock);
1483                 return TDM_ERROR_PROTOCOL_ERROR;
1484         }
1485
1486         if (private_vblank->offset == offset_ms) {
1487                 pthread_mutex_unlock(&private_client->lock);
1488                 return TDM_ERROR_NONE;
1489         }
1490
1491         private_vblank->offset = offset_ms;
1492
1493         wl_tdm_vblank_set_offset(private_vblank->vblank, offset_ms);
1494
1495         pthread_mutex_unlock(&private_client->lock);
1496
1497         return TDM_ERROR_NONE;
1498 }
1499
1500 tdm_error
1501 tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable_fake)
1502 {
1503         tdm_private_client_vblank *private_vblank;
1504         tdm_private_client *private_client;
1505
1506         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1507
1508         private_vblank = vblank;
1509         private_client = private_vblank->private_output->private_client;
1510
1511         pthread_mutex_lock(&private_client->lock);
1512
1513         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1514                 pthread_mutex_unlock(&private_client->lock);
1515                 return TDM_ERROR_PROTOCOL_ERROR;
1516         }
1517
1518         if (private_vblank->enable_fake == enable_fake) {
1519                 pthread_mutex_unlock(&private_client->lock);
1520                 return TDM_ERROR_NONE;
1521         }
1522
1523         private_vblank->enable_fake = enable_fake;
1524
1525         wl_tdm_vblank_set_enable_fake(private_vblank->vblank, enable_fake);
1526
1527         pthread_mutex_unlock(&private_client->lock);
1528
1529         return TDM_ERROR_NONE;
1530 }
1531
1532 tdm_error
1533 tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_client_vblank_handler func, void *user_data)
1534 {
1535         tdm_private_client *private_client;
1536         tdm_private_client_output *private_output;
1537         tdm_private_client_vblank *private_vblank;
1538         tdm_client_wait_info *w;
1539         struct timespec tp;
1540         unsigned int req_sec, req_usec;
1541         int ret = 0;
1542
1543         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1544         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1545         /* can't support "interval 0" and "getting current_msc" things because
1546          * there is a socket communication between TDM client and server. It's impossible
1547          * to return the current msc or sequence immediately.
1548          */
1549         TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
1550
1551         private_vblank = vblank;
1552         private_output = private_vblank->private_output;
1553         private_client = private_output->private_client;
1554
1555         pthread_mutex_lock(&private_client->lock);
1556
1557         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1558                 pthread_mutex_unlock(&private_client->lock);
1559                 return TDM_ERROR_PROTOCOL_ERROR;
1560         }
1561
1562         if (!private_vblank->started)
1563                 private_vblank->started = 1;
1564
1565         if (!private_vblank->enable_fake) {
1566                 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1567                         TDM_ERR("output disconnected");
1568                         pthread_mutex_unlock(&private_client->lock);
1569                         return TDM_ERROR_OUTPUT_DISCONNECTED;
1570                 }
1571                 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1572                         TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1573                         pthread_mutex_unlock(&private_client->lock);
1574                         return TDM_ERROR_DPMS_OFF;
1575                 }
1576         }
1577
1578         w = calloc(1, sizeof *w);
1579         if (!w) {
1580                 /* LCOV_EXCL_START */
1581
1582                 TDM_ERR("alloc failed");
1583                 pthread_mutex_unlock(&private_client->lock);
1584                 return TDM_ERROR_OUT_OF_MEMORY;
1585
1586                 /* LCOV_EXCL_STOP */
1587         }
1588
1589         w->private_vblank = private_vblank;
1590         w->func = func;
1591         w->user_data = user_data;
1592
1593         LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1594         LIST_INITHEAD(&w->call_link);
1595
1596         clock_gettime(CLOCK_MONOTONIC, &tp);
1597         req_sec = (unsigned int)tp.tv_sec;
1598         req_usec = (unsigned int)(tp.tv_nsec / 1000);
1599
1600         w->req_id = ++private_output->req_id;
1601         w->req_time = TDM_TIME(req_sec, req_usec);
1602         w->need_free = (private_vblank->sync) ? 0 : 1;
1603
1604         wl_tdm_vblank_wait_vblank(private_vblank->vblank, interval, w->req_id, req_sec, req_usec);
1605
1606         if (private_vblank->enable_ttrace)
1607                 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1608
1609         TDM_DBG("vblank(%p) interval(%u) req_id(%d) req(%.6f)",
1610                         vblank, interval, w->req_id, w->req_time);
1611
1612         private_vblank->req_time = w->req_time;
1613
1614         if (private_vblank->last_time >= w->req_time)
1615                 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1616
1617         if (!private_vblank->sync) {
1618                 wl_display_flush(private_client->display);
1619                 pthread_mutex_unlock(&private_client->lock);
1620                 return TDM_ERROR_NONE;
1621         }
1622
1623         /* LCOV_EXCL_START */
1624
1625         while (ret != -1 && !w->need_free)
1626                 ret = wl_display_dispatch(private_client->display);
1627
1628         clock_gettime(CLOCK_MONOTONIC, &tp);
1629         TDM_DBG("block during %d us",
1630                         ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1631                         - (req_sec * 1000000 + req_usec));
1632
1633         LIST_DEL(&w->link);
1634         free(w);
1635
1636         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1637                 pthread_mutex_unlock(&private_client->lock);
1638                 return TDM_ERROR_PROTOCOL_ERROR;
1639         }
1640
1641         pthread_mutex_unlock(&private_client->lock);
1642
1643         return TDM_ERROR_NONE;
1644
1645         /* LCOV_EXCL_STOP */
1646 }
1647
1648 tdm_error
1649 tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
1650                                                    tdm_client_vblank_handler func, void *user_data)
1651 {
1652         tdm_private_client *private_client;
1653         tdm_private_client_output *private_output;
1654         tdm_private_client_vblank *private_vblank;
1655         tdm_client_wait_info *w;
1656         struct timespec tp;
1657         unsigned int req_sec, req_usec;
1658         int ret = 0;
1659
1660         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1661         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1662
1663         private_vblank = vblank;
1664         private_output = private_vblank->private_output;
1665         private_client = private_output->private_client;
1666
1667         pthread_mutex_lock(&private_client->lock);
1668
1669         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1670                 pthread_mutex_unlock(&private_client->lock);
1671                 return TDM_ERROR_PROTOCOL_ERROR;
1672         }
1673
1674         if (!private_vblank->started)
1675                 private_vblank->started = 1;
1676
1677         if (!private_vblank->enable_fake) {
1678                 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1679                         TDM_ERR("output disconnected");
1680                         pthread_mutex_unlock(&private_client->lock);
1681                         return TDM_ERROR_OUTPUT_DISCONNECTED;
1682                 }
1683                 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1684                         TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1685                         pthread_mutex_unlock(&private_client->lock);
1686                         return TDM_ERROR_DPMS_OFF;
1687                 }
1688         }
1689
1690         w = calloc(1, sizeof *w);
1691         if (!w) {
1692                 /* LCOV_EXCL_START */
1693
1694                 TDM_ERR("alloc failed");
1695                 pthread_mutex_unlock(&private_client->lock);
1696                 return TDM_ERROR_OUT_OF_MEMORY;
1697
1698                 /* LCOV_EXCL_STOP */
1699         }
1700
1701         w->private_vblank = private_vblank;
1702         w->func = func;
1703         w->user_data = user_data;
1704
1705         LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1706         LIST_INITHEAD(&w->call_link);
1707
1708         clock_gettime(CLOCK_MONOTONIC, &tp);
1709         req_sec = (unsigned int)tp.tv_sec;
1710         req_usec = (unsigned int)(tp.tv_nsec / 1000);
1711
1712         w->req_id = ++private_output->req_id;
1713         w->req_time = TDM_TIME(req_sec, req_usec);
1714         w->need_free = (private_vblank->sync) ? 0 : 1;
1715
1716         wl_tdm_vblank_wait_vblank_seq(private_vblank->vblank, sequence, w->req_id, req_sec, req_usec);
1717
1718         if (private_vblank->enable_ttrace)
1719                 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1720
1721         TDM_DBG("vblank(%p) sequence(%u) req_id(%d) req(%.6f)",
1722                         vblank, sequence, w->req_id, w->req_time);
1723
1724         private_vblank->req_time = w->req_time;
1725
1726         if (private_vblank->last_time >= w->req_time)
1727                 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1728
1729         if (!private_vblank->sync) {
1730                 wl_display_flush(private_client->display);
1731                 pthread_mutex_unlock(&private_client->lock);
1732                 return TDM_ERROR_NONE;
1733         }
1734
1735         /* LCOV_EXCL_START */
1736
1737         while (ret != -1 && !w->need_free)
1738                 ret = wl_display_dispatch(private_client->display);
1739
1740         clock_gettime(CLOCK_MONOTONIC, &tp);
1741         TDM_DBG("block during %d us",
1742                         ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1743                         - (req_sec * 1000000 + req_usec));
1744
1745         LIST_DEL(&w->link);
1746         free(w);
1747
1748         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1749                 pthread_mutex_unlock(&private_client->lock);
1750                 return TDM_ERROR_PROTOCOL_ERROR;
1751         }
1752
1753         pthread_mutex_unlock(&private_client->lock);
1754
1755         return TDM_ERROR_NONE;
1756
1757         /* LCOV_EXCL_STOP */
1758 }
1759
1760 unsigned int
1761 tdm_client_vblank_is_waiting(tdm_client_vblank *vblank)
1762 {
1763         tdm_private_client_vblank *private_vblank;
1764
1765         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, 0);
1766
1767         private_vblank = vblank;
1768
1769         return (LIST_LENGTH(&private_vblank->wait_list) > 0) ? 1 : 0;
1770 }
1771
1772 static tbm_surface_h
1773 _tdm_client_voutput_create_surface_from_param(tbm_bufmgr bufmgr,
1774                                                          int is_fd,
1775                                                          int32_t width,
1776                                                          int32_t height,
1777                                                          uint32_t format,
1778                                                          int32_t bpp,
1779                                                          int32_t size,
1780                                                          int32_t num_plane,
1781                                                          struct wl_array *plane_buf_idx,
1782                                                          struct wl_array *plane_offset,
1783                                                          struct wl_array *plane_stride,
1784                                                          struct wl_array *plane_size,
1785                                                          uint32_t flags,
1786                                                          int32_t num_buf,
1787                                                          uint32_t buf0,
1788                                                          uint32_t buf1,
1789                                                          uint32_t buf2)
1790 {
1791         int32_t names[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1};
1792         tbm_surface_info_s info = { 0, };
1793         tbm_bo bos[TBM_SURF_PLANE_MAX];
1794         int i, numPlane, numName;
1795         tbm_surface_h tbm_surface;
1796
1797         numPlane = tbm_surface_internal_get_num_planes(format);
1798         TDM_RETURN_VAL_IF_FAIL(numPlane == num_plane, NULL);
1799
1800         info.width = width;
1801         info.height = height;
1802         info.format = format;
1803         info.bpp = bpp;
1804         info.size = size;
1805         info.num_planes = numPlane;
1806
1807         /*Fill plane info*/
1808         for (i = 0; i < numPlane; i++) {
1809                 info.planes[i].offset = *TDM_ARRAY_NTH_DATA(plane_offset, int32_t, i);
1810                 info.planes[i].stride = *TDM_ARRAY_NTH_DATA(plane_stride, int32_t, i);
1811                 info.planes[i].size = *TDM_ARRAY_NTH_DATA(plane_size, int32_t, i);
1812         }
1813
1814         /*Fill buffer*/
1815         numName = num_buf;
1816         names[0] = buf0;
1817         names[1] = buf1;
1818         names[2] = buf2;
1819
1820         for (i = 0; i < numName; i++) {
1821                 if (is_fd)
1822                         bos[i] = tbm_bo_import_fd(bufmgr, names[i]);
1823                 else
1824                         bos[i] = tbm_bo_import(bufmgr, names[i]);
1825         }
1826
1827         tbm_surface = tbm_surface_internal_create_with_bos(&info, bos, numName);
1828         if (tbm_surface == NULL) {
1829                 if (is_fd) {
1830                         close(buf0);
1831                         close(buf1);
1832                         close(buf2);
1833                 }
1834                 return NULL;
1835         }
1836
1837         if (is_fd) {
1838                 close(buf0);
1839                 close(buf1);
1840                 close(buf2);
1841         }
1842
1843         for (i = 0; i < numName; i++)
1844                 tbm_bo_unref(bos[i]);
1845
1846         return tbm_surface;
1847 }
1848 static void
1849 tdm_client_voutput_cb_buffer_import_with_id(void *data,
1850                 struct wl_tdm_voutput *wl_voutput,
1851                 struct wl_buffer *wl_buffer,
1852                 int32_t width,
1853                 int32_t height,
1854                 uint32_t format,
1855                 int32_t bpp,
1856                 int32_t size,
1857                 int32_t num_plane,
1858                 struct wl_array *plane_buf_idx,
1859                 struct wl_array *plane_offset,
1860                 struct wl_array *plane_stride,
1861                 struct wl_array *plane_size,
1862                 uint32_t flags,
1863                 int32_t num_buf,
1864                 uint32_t buf0,
1865                 uint32_t buf1,
1866                 uint32_t buf2)
1867 {
1868         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1869         tdm_private_client_buffer *buffer = NULL;
1870         tbm_surface_h tbm_surface;
1871
1872         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1873
1874         buffer = calloc(1, sizeof *buffer);
1875         TDM_RETURN_IF_FAIL(buffer != NULL);
1876
1877         tbm_surface = _tdm_client_voutput_create_surface_from_param(private_voutput->bufmgr, 0,
1878                               width, height, format, bpp, size,
1879                               num_plane,
1880                               plane_buf_idx, plane_offset, plane_stride, plane_size,
1881                               0,
1882                               num_buf,
1883                               buf0, buf1, buf2);
1884         TDM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
1885
1886         tbm_surface_internal_ref(tbm_surface);
1887         wl_buffer_set_user_data(wl_buffer, tbm_surface);
1888
1889         buffer->wl_buffer = wl_buffer;
1890
1891         LIST_ADDTAIL(&buffer->link, &private_voutput->buffer_list);
1892
1893         return;
1894
1895 fail:
1896         if (buffer)
1897                 free(buffer);
1898
1899         if (wl_buffer)
1900                 wl_buffer_destroy(wl_buffer);
1901 }
1902
1903 static void
1904 tdm_client_voutput_cb_buffer_import_with_fd(void *data,
1905                 struct wl_tdm_voutput *wl_voutput,
1906                 struct wl_buffer *wl_buffer,
1907                 int32_t width,
1908                 int32_t height,
1909                 uint32_t format,
1910                 int32_t bpp,
1911                 int32_t size,
1912                 int32_t num_plane,
1913                 struct wl_array *plane_buf_idx,
1914                 struct wl_array *plane_offset,
1915                 struct wl_array *plane_stride,
1916                 struct wl_array *plane_size,
1917                 uint32_t flags,
1918                 int32_t num_buf,
1919                 int32_t buf0,
1920                 int32_t buf1,
1921                 int32_t buf2)
1922 {
1923         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1924         tdm_private_client_buffer *buffer = NULL;
1925         tbm_surface_h tbm_surface;
1926
1927         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1928
1929         buffer = calloc(1, sizeof *buffer);
1930         TDM_RETURN_IF_FAIL(buffer != NULL);
1931
1932         tbm_surface = _tdm_client_voutput_create_surface_from_param(private_voutput->bufmgr, 1,
1933                               width, height, format, bpp, size,
1934                               num_plane,
1935                               plane_buf_idx, plane_offset, plane_stride, plane_size,
1936                               0,
1937                               num_buf,
1938                               buf0, buf1, buf2);
1939         TDM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
1940
1941         tbm_surface_internal_ref(tbm_surface);
1942         wl_buffer_set_user_data(wl_buffer, tbm_surface);
1943
1944         buffer->wl_buffer = wl_buffer;
1945
1946         LIST_ADDTAIL(&buffer->link, &private_voutput->buffer_list);
1947
1948         return;
1949
1950 fail:
1951         if (buffer)
1952                 free(buffer);
1953
1954         if (wl_buffer)
1955                 wl_buffer_destroy(wl_buffer);
1956 }
1957
1958 static void
1959 tdm_client_voutput_cb_buffer_destroy(void *data,
1960                 struct wl_tdm_voutput *wl_voutput,
1961                 struct wl_buffer *wl_buffer)
1962 {
1963         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1964         tdm_private_client_buffer *cb = NULL, *cbb = NULL;
1965         tbm_surface_h tbm_surface = NULL;
1966
1967         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1968
1969         LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
1970                 if (wl_buffer == cb->wl_buffer) {
1971                         LIST_DEL(&cb->link);
1972
1973                         tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(wl_buffer);
1974                         if (tbm_surface)
1975                                 tbm_surface_internal_unref(tbm_surface);
1976
1977                         wl_buffer_set_user_data(wl_buffer, NULL);
1978                         wl_buffer_destroy(wl_buffer);
1979
1980                         free(cb);
1981
1982                         break;
1983                 }
1984         }
1985
1986         return;
1987 }
1988
1989 void
1990 tdm_client_voutput_cb_attach_buffer(void *data,
1991                 struct wl_tdm_voutput *wl_voutput,
1992                 struct wl_buffer *wl_buffer)
1993 {
1994         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1995         tdm_private_client_buffer *cb = NULL, *cbb = NULL;
1996
1997         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1998
1999         LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
2000                 if (wl_buffer == cb->wl_buffer) {
2001                         private_voutput->attach_buffer = cb;
2002                         break;
2003                 }
2004         }
2005
2006         return;
2007 }
2008
2009 void
2010 tdm_client_voutput_cb_commit(void *data, struct wl_tdm_voutput *wl_voutput)
2011 {
2012         tdm_private_client_voutput *private_voutput;
2013         tdm_private_client *private_client;
2014         tbm_surface_h buffer = NULL;
2015         tdm_client_voutput_commit_handler_info *h = NULL, *hh = NULL;
2016         struct list_head call_list;
2017
2018         private_voutput = (tdm_private_client_voutput *)data;
2019         TDM_RETURN_IF_FAIL(private_voutput != NULL);
2020         TDM_RETURN_IF_FAIL(private_voutput->attach_buffer != NULL);
2021
2022         buffer = (tbm_surface_h)wl_buffer_get_user_data(private_voutput->attach_buffer->wl_buffer);
2023         TDM_RETURN_IF_FAIL(buffer != NULL);
2024
2025         tbm_surface_internal_ref(buffer);
2026
2027         private_client = private_voutput->private_client;
2028
2029         LIST_INITHEAD(&call_list);
2030
2031         LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2032                 LIST_ADDTAIL(&h->call_link, &call_list);
2033         }
2034
2035         pthread_mutex_unlock(&private_client->lock);
2036         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
2037                 if (h->func)
2038                         h->func(private_voutput, buffer, h->user_data);
2039         }
2040         pthread_mutex_lock(&private_client->lock);
2041
2042         /* if no added commit_handler call commit done immediately */
2043         if (LIST_IS_EMPTY(&private_voutput->commit_handler_list))
2044                 tdm_client_voutput_commit_done(private_voutput);
2045 }
2046
2047 void
2048 tdm_client_voutput_cb_ack_message(void *data, struct wl_tdm_voutput *wl_voutput, uint32_t msg)
2049 {
2050         tdm_private_client_voutput *private_voutput = data;
2051
2052         private_voutput->msg = msg;
2053 }
2054
2055 static const struct wl_tdm_voutput_listener tdm_client_voutput_lisntener = {
2056         tdm_client_voutput_cb_buffer_import_with_id,
2057         tdm_client_voutput_cb_buffer_import_with_fd,
2058         tdm_client_voutput_cb_buffer_destroy,
2059         tdm_client_voutput_cb_attach_buffer,
2060         tdm_client_voutput_cb_commit,
2061         tdm_client_voutput_cb_ack_message
2062 };
2063
2064 tdm_client_voutput *
2065 tdm_client_create_voutput(tdm_client *client, const char *name, tdm_error *error)
2066 {
2067         tdm_private_client *private_client;
2068         tdm_private_client_output *private_output;
2069         tdm_private_client_voutput *private_voutput;
2070         struct wl_proxy *wrapper;
2071
2072         if (error)
2073                 *error = TDM_ERROR_NONE;
2074
2075         if (!client) {
2076                 TDM_ERR("'!client' failed");
2077                 if (error)
2078                         *error = TDM_ERROR_INVALID_PARAMETER;
2079                 return NULL;
2080         }
2081
2082         if (!name) {
2083                 TDM_ERR("'!name' failed");
2084                 if (error)
2085                         *error = TDM_ERROR_INVALID_PARAMETER;
2086                 return NULL;
2087         }
2088
2089         private_client = (tdm_private_client *)client;
2090
2091         pthread_mutex_lock(&private_client->lock);
2092
2093         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2094                 if (error)
2095                         *error = TDM_ERROR_PROTOCOL_ERROR;
2096                 pthread_mutex_unlock(&private_client->lock);
2097                 return NULL;
2098         }
2099
2100         LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
2101                 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
2102                         if (error)
2103                                 *error = TDM_ERROR_INVALID_PARAMETER; // FIXME define new error type.
2104                         pthread_mutex_unlock(&private_client->lock);
2105                         return NULL;
2106                 }
2107         }
2108
2109         wrapper = wl_proxy_create_wrapper(private_client->tdm);
2110         if (!wrapper) {
2111                 TDM_ERR("create virtual output wrapper failed");
2112                 if (error)
2113                         *error = TDM_ERROR_OUT_OF_MEMORY;
2114                 pthread_mutex_unlock(&private_client->lock);
2115                 return NULL;
2116         }
2117
2118         wl_proxy_set_queue(wrapper, private_client->queue);
2119
2120         private_voutput = calloc(1, sizeof *private_voutput);
2121         if (!private_voutput) {
2122                 /* LOCV_EXCL_START */
2123                 wl_proxy_wrapper_destroy(wrapper);
2124                 TDM_ERR("alloc failed");
2125                 if (error)
2126                         *error = TDM_ERROR_OUT_OF_MEMORY;
2127                 pthread_mutex_unlock(&private_client->lock);
2128                 return NULL;
2129                 /* LOCV_EXCL_STOP */
2130         }
2131
2132         private_voutput->bufmgr = tbm_bufmgr_init(-1);
2133         if (private_voutput->bufmgr == NULL) {
2134                 /* LCOV_EXCL_START */
2135                 TDM_ERR("fail tbm_bufmgr_init");
2136                 free(private_voutput);
2137                 if (error)
2138                         *error = TDM_ERROR_OUT_OF_MEMORY;
2139                 pthread_mutex_unlock(&private_client->lock);
2140                 return NULL;
2141                 /* LCOV_EXCL_STOP */
2142         }
2143
2144         LIST_INITHEAD(&private_voutput->commit_handler_list);
2145         LIST_INITHEAD(&private_voutput->buffer_list);
2146
2147         private_voutput->private_client = private_client;
2148         strncpy(private_voutput->name, name, TDM_NAME_LEN);
2149
2150         private_voutput->wl_voutput = wl_tdm_create_voutput((struct wl_tdm *)wrapper, name);
2151         wl_proxy_wrapper_destroy(wrapper);
2152         if (!private_voutput->wl_voutput) {
2153                 /* LCOV_EXCL_START */
2154                 TDM_ERR("couldn't create voutput resource");
2155                 free(private_voutput);
2156                 if (error)
2157                         *error = TDM_ERROR_OUT_OF_MEMORY;
2158                 pthread_mutex_unlock(&private_client->lock);
2159                 return NULL;
2160                 /* LCOV_EXCL_STOP */
2161         }
2162
2163         wl_tdm_voutput_add_listener(private_voutput->wl_voutput,
2164                                                                 &tdm_client_voutput_lisntener, private_voutput);
2165         wl_display_roundtrip_queue(private_client->display, private_client->queue);
2166
2167         wl_proxy_set_queue((struct wl_proxy *)private_voutput->wl_voutput, NULL);
2168
2169         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2170                 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2171                 free(private_voutput);
2172                 if (error)
2173                         *error = TDM_ERROR_PROTOCOL_ERROR;
2174                 pthread_mutex_unlock(&private_client->lock);
2175                 return NULL;
2176         }
2177
2178         if (private_voutput->msg != WL_TDM_VOUTPUT_MESSAGE_ADDED)
2179         {
2180                 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2181                 free(private_voutput);
2182                 if (error)
2183                         *error = TDM_ERROR_PROTOCOL_ERROR;      // FIXME add new error type.
2184                 pthread_mutex_unlock(&private_client->lock);
2185                 return NULL;
2186         }
2187
2188         LIST_ADDTAIL(&private_voutput->link, &private_client->voutput_list);
2189
2190         pthread_mutex_unlock(&private_client->lock);
2191
2192         return (tdm_client_voutput *)private_voutput;
2193 }
2194
2195 void
2196 tdm_client_voutput_destroy(tdm_client_voutput *voutput)
2197 {
2198         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)voutput;
2199         tdm_client_voutput_commit_handler_info *h = NULL, *hh = NULL;
2200
2201         if (!private_voutput)
2202                 return;
2203
2204         if (!(LIST_IS_EMPTY(&private_voutput->buffer_list))) {
2205                 tdm_private_client_buffer *cb = NULL, *cbb = NULL;
2206
2207                 LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
2208                         tbm_surface_h tbm_surface = NULL;
2209
2210                         if (!cb) continue;
2211
2212                         LIST_DEL(&cb->link);
2213
2214                         tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(cb->wl_buffer);
2215                         if (tbm_surface)
2216                                 tbm_surface_internal_unref(tbm_surface);
2217
2218                         wl_buffer_set_user_data(cb->wl_buffer, NULL);
2219                         wl_buffer_destroy(cb->wl_buffer);
2220
2221                         free(cb);
2222                 }
2223         }
2224
2225         if (private_voutput->bufmgr)
2226                 tbm_bufmgr_deinit(private_voutput->bufmgr);
2227
2228         if (private_voutput->available_modes.modes)
2229                 free(private_voutput->available_modes.modes);
2230
2231         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_voutput->commit_handler_list, link) {
2232                 LIST_DEL(&h->link);
2233                 free(h);
2234         }
2235
2236         if (private_voutput->get_output)
2237                 _tdm_client_output_destroy(private_voutput->private_output);
2238
2239         wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2240
2241         LIST_DEL(&private_voutput->link);
2242
2243         free(private_voutput);
2244 }
2245
2246 tdm_error
2247 tdm_client_voutput_set_available_modes(tdm_client_voutput *voutput, const tdm_client_output_mode *modes, int count)
2248 {
2249         tdm_private_client_voutput *private_voutput;
2250
2251         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2252
2253         if ((count > 0) && (modes == NULL))
2254                 return TDM_ERROR_INVALID_PARAMETER;
2255
2256         private_voutput = (tdm_private_client_voutput *)voutput;
2257
2258         if (private_voutput->private_output->connection == TDM_OUTPUT_CONN_STATUS_CONNECTED)
2259                 return TDM_ERROR_BAD_REQUEST;
2260
2261         if (private_voutput->available_modes.modes)
2262                 free(private_voutput->available_modes.modes);
2263
2264         private_voutput->available_modes.count = count;
2265
2266         if (count != 0)
2267         {
2268                 private_voutput->available_modes.modes = calloc(count, sizeof(tdm_client_output_mode));
2269                 memcpy(private_voutput->available_modes.modes, modes, sizeof(tdm_client_output_mode) * count);
2270         }
2271
2272         return TDM_ERROR_NONE;
2273 }
2274
2275 tdm_error
2276 tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, unsigned int mmWidth, unsigned int mmHeight)
2277 {
2278         tdm_private_client_voutput *private_voutput;
2279
2280         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2281         TDM_RETURN_VAL_IF_FAIL(mmWidth != 0, TDM_ERROR_INVALID_PARAMETER);
2282         TDM_RETURN_VAL_IF_FAIL(mmHeight != 0, TDM_ERROR_INVALID_PARAMETER);
2283
2284         private_voutput = (tdm_private_client_voutput *)voutput;
2285
2286         if (private_voutput->private_output->connection == TDM_OUTPUT_CONN_STATUS_CONNECTED)
2287                 return TDM_ERROR_BAD_REQUEST;
2288
2289         private_voutput->mmwidth = mmWidth;
2290         private_voutput->mmheight = mmHeight;
2291
2292         return TDM_ERROR_NONE;
2293 }
2294
2295 tdm_error
2296 tdm_client_voutput_add_commit_handler(tdm_client_voutput *voutput,
2297                                                                           tdm_client_voutput_commit_handler func,
2298                                                                           void *user_data)
2299 {
2300         tdm_private_client_voutput *private_voutput;
2301         tdm_private_client *private_client;
2302         tdm_client_voutput_commit_handler_info *h = NULL;
2303
2304         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2305         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
2306
2307         private_voutput = (tdm_private_client_voutput *)voutput;
2308         private_client = private_voutput->private_client;
2309
2310         LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2311                 if (h->func == func && h->user_data == user_data) {
2312                         TDM_ERR("can't add twice");
2313                         return TDM_ERROR_BAD_REQUEST;
2314                 }
2315         }
2316
2317         h = calloc(1, sizeof *h);
2318         TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
2319
2320         pthread_mutex_lock(&private_client->lock);
2321
2322         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2323                 free(h);
2324                 pthread_mutex_unlock(&private_client->lock);
2325                 return TDM_ERROR_PROTOCOL_ERROR;
2326         }
2327
2328         h->private_voutput = private_voutput;
2329         h->func = func;
2330         h->user_data = user_data;
2331         LIST_ADDTAIL(&h->link, &private_voutput->commit_handler_list);
2332         LIST_INITHEAD(&h->call_link);
2333
2334         pthread_mutex_unlock(&private_client->lock);
2335
2336         return TDM_ERROR_NONE;
2337 }
2338
2339 void
2340 tdm_client_voutput_remove_commit_handler(tdm_client_voutput *voutput,
2341                                                                                  tdm_client_voutput_commit_handler func,
2342                                                                                  void *user_data)
2343 {
2344         tdm_private_client_voutput *private_voutput;
2345         tdm_private_client *private_client;
2346         tdm_client_voutput_commit_handler_info *h = NULL;
2347
2348         TDM_RETURN_IF_FAIL(voutput != NULL);
2349         TDM_RETURN_IF_FAIL(func != NULL);
2350
2351         private_voutput = (tdm_private_client_voutput *)voutput;
2352         private_client = private_voutput->private_client;
2353
2354         pthread_mutex_lock(&private_client->lock);
2355
2356         LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2357                 if (h->func != func || h->user_data != user_data)
2358                         continue;
2359
2360                 LIST_DEL(&h->link);
2361                 free(h);
2362
2363                 pthread_mutex_unlock(&private_client->lock);
2364         }
2365
2366         pthread_mutex_unlock(&private_client->lock);
2367 }
2368
2369 tdm_error
2370 tdm_client_voutput_commit_done(tdm_client_voutput *voutput)
2371 {
2372         tdm_private_client_voutput *private_voutput;
2373         tbm_surface_h buffer = NULL;
2374
2375         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2376
2377         private_voutput = (tdm_private_client_voutput *)voutput;
2378         buffer = (tbm_surface_h)wl_buffer_get_user_data(private_voutput->attach_buffer->wl_buffer);
2379         tbm_surface_internal_unref(buffer);
2380         private_voutput->attach_buffer = NULL;
2381         wl_tdm_voutput_commit_done(private_voutput->wl_voutput);
2382
2383         return TDM_ERROR_NONE;
2384 }
2385
2386 tdm_client_output *
2387 tdm_client_voutput_get_client_output(tdm_client_voutput *voutput, tdm_error *error)
2388 {
2389         tdm_private_client_voutput *private_voutput;
2390         tdm_private_client_output *private_output = NULL;
2391         tdm_error ret = TDM_ERROR_NONE;
2392
2393         if (error)
2394                 *error = TDM_ERROR_NONE;
2395
2396         if (!voutput) {
2397                 TDM_ERR("'!voutput' failed");
2398                 if (error)
2399                         *error = TDM_ERROR_INVALID_PARAMETER;
2400                 return NULL;
2401         }
2402
2403         private_voutput = (tdm_private_client_voutput *)voutput;
2404
2405         if (private_voutput->get_output)
2406                 return private_voutput->private_output;
2407
2408         private_output = (tdm_private_client_output *)tdm_client_get_output(private_voutput->private_client, private_voutput->name, &ret);
2409         if (!private_output) {
2410                 TDM_ERR("tdm_client_voutput_get_client_output get private_output fail");
2411                 if (error)
2412                         *error = ret;
2413                 return NULL;
2414         }
2415         private_output->voutput = private_voutput;
2416         private_voutput->private_output = private_output;
2417         private_voutput->get_output = 1;
2418
2419         return private_output;
2420 }
2421
2422 void
2423 _tdm_client_voutput_send_available_modes(tdm_private_client_voutput *private_voutput)
2424 {
2425         tdm_client_output_mode *modes, *mode;
2426         struct wl_array array;
2427         int i, size;
2428
2429         modes = private_voutput->available_modes.modes;
2430         size = sizeof(tdm_client_output_mode);
2431
2432         wl_array_init(&array);
2433         for (i = 0; i < private_voutput->available_modes.count; i++) {
2434                 mode = wl_array_add(&array, size);
2435                 memcpy(mode, &modes[i], size);
2436         }
2437         wl_tdm_voutput_set_available_modes(private_voutput->wl_voutput, &array);
2438         wl_array_release(&array);
2439 }
2440
2441 tdm_error
2442 tdm_client_output_connect(tdm_client_output *output)
2443 {
2444         tdm_private_client_output *private_output;
2445         tdm_private_client_voutput *private_voutput = NULL;
2446
2447         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2448
2449         private_output = (tdm_private_client_output *)output;
2450         if (!private_output->voutput) return TDM_ERROR_INVALID_PARAMETER;
2451         private_voutput = private_output->voutput;
2452
2453         TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_CONNECTED,
2454                                                    TDM_ERROR_BAD_REQUEST);
2455
2456         if (!private_output->watch_output_changes)
2457                 private_output->connection = TDM_OUTPUT_CONN_STATUS_CONNECTED;
2458
2459         _tdm_client_voutput_send_available_modes(private_voutput);
2460
2461         wl_tdm_voutput_set_physical_size(private_voutput->wl_voutput, private_voutput->mmwidth, private_voutput->mmheight);
2462
2463         /* To Do : change voutput to output */
2464         wl_tdm_voutput_connect(private_voutput->wl_voutput);
2465
2466         return TDM_ERROR_NONE;
2467 }
2468
2469 tdm_error
2470 tdm_client_output_disconnect(tdm_client_output *output)
2471 {
2472         tdm_private_client_output *private_output;
2473         tdm_private_client_voutput *private_voutput = NULL;
2474
2475         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2476
2477         private_output = (tdm_private_client_output *)output;
2478         if (!private_output->voutput) return TDM_ERROR_INVALID_PARAMETER;
2479         private_voutput = private_output->voutput;
2480
2481         TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED,
2482                                                    TDM_ERROR_BAD_REQUEST);
2483
2484         if (!private_output->watch_output_changes)
2485                 private_output->connection = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
2486
2487         /* To Do : change voutput to output */
2488         wl_tdm_voutput_disconnect(private_voutput->wl_voutput);
2489
2490         return TDM_ERROR_NONE;
2491 }