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