c9b312c20f0cefa4ba56f6058ad21439a75eb6cb
[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 <sc1.lim@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 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <time.h>
44 #include <strings.h>
45
46 #include "tdm_client.h"
47 #include "tdm_log.h"
48 #include "tdm_macro.h"
49 #include "tdm_list.h"
50 #include "tdm.h"
51 #include "tdm_private.h"
52 #include "tdm-client-protocol.h"
53
54 typedef struct _tdm_private_client_vblank tdm_private_client_vblank;
55
56 typedef struct _tdm_private_client {
57         struct wl_display *display;
58         struct wl_registry *registry;
59         struct wl_tdm *tdm;
60         struct list_head output_list;
61
62         tdm_private_client_vblank *temp_vblank;
63 } tdm_private_client;
64
65 typedef struct _tdm_private_client_output {
66         tdm_private_client *private_client;
67
68         char name[TDM_NAME_LEN];
69         struct wl_tdm_output *output;
70         int width;
71         int height;
72         int refresh;
73         tdm_output_conn_status connection;
74         tdm_output_dpms dpms;
75         struct list_head vblank_list;
76         struct list_head change_handler_list;
77
78         unsigned int req_id;
79
80         struct list_head link;
81 } tdm_private_client_output;
82
83 struct _tdm_private_client_vblank {
84         tdm_private_client_output *private_output;
85
86         struct wl_tdm_vblank *vblank;
87         struct list_head wait_list;
88
89         unsigned int sync;
90         unsigned int fps;
91         int offset;
92         unsigned int enable_fake;
93
94         unsigned int started;
95
96         struct list_head link;
97 };
98
99 typedef struct _tdm_client_output_handler_info {
100         tdm_private_client_output *private_output;
101
102         tdm_client_output_change_handler func;
103         void *user_data;
104
105         struct list_head link;
106 } tdm_client_output_handler_info;
107
108 typedef struct _tdm_client_wait_info {
109         tdm_private_client_vblank *private_vblank;
110
111         tdm_client_vblank_handler func;
112         void *user_data;
113
114         unsigned int req_id;
115         unsigned int req_sec;
116         unsigned int req_usec;
117         int need_free;
118
119         struct list_head link;
120 } tdm_client_wait_info;
121
122 static void
123 _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank,
124                                                    uint32_t req_id, uint32_t sequence, uint32_t tv_sec,
125                                                    uint32_t tv_usec, uint32_t error)
126 {
127         tdm_private_client_vblank *private_vblank = data;
128         tdm_client_wait_info *w = NULL, *ww = NULL;
129
130         TDM_RETURN_IF_FAIL(private_vblank != NULL);
131
132         TDM_TRACE_COUNT(ClientDoneVBlank, req_id);
133
134         LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
135                 if (w->req_id != req_id)
136                         continue;
137
138                 if (w->func)
139                         w->func(private_vblank, error, sequence, tv_sec, tv_usec, w->user_data);
140
141                 if (w->need_free) {
142                         LIST_DEL(&w->link);
143                         free(w);
144                 } else
145                         w->need_free = 1;
146                 return;
147         }
148 }
149
150 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
151         _tdm_client_vblank_cb_done,
152 };
153
154 static void
155 _tdm_client_output_destroy(tdm_private_client_output *private_output)
156 {
157         tdm_private_client_vblank *v = NULL, *vv = NULL;
158         tdm_client_output_handler_info *h = NULL, *hh = NULL;
159
160         LIST_DEL(&private_output->link);
161
162         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_list, link) {
163                 TDM_ERR("vblanks SHOULD be destroyed first!");
164                 LIST_DEL(&v->link);
165                 v->private_output = NULL;
166         }
167
168         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list, link) {
169                 LIST_DEL(&h->link);
170                 free(h);
171         }
172
173         wl_tdm_output_destroy(private_output->output);
174
175         free(private_output);
176 }
177
178 static void
179 _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output,
180                                                    uint32_t width, uint32_t height, uint32_t refresh)
181 {
182         tdm_private_client_output *private_output = (tdm_private_client_output*)data;
183
184         TDM_RETURN_IF_FAIL(private_output != NULL);
185
186         private_output->width = width;
187         private_output->height = height;
188         private_output->refresh = refresh;
189
190         TDM_DBG("private_output(%p) wl_tbm_output@%d width(%d) height(%d) refresh(%d)",
191                         private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output),
192                         width, height, refresh);
193 }
194
195 static void
196 _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value)
197 {
198         tdm_private_client_output *private_output = (tdm_private_client_output*)data;
199         tdm_client_output_handler_info *h = NULL;
200         tdm_value v;
201
202         TDM_RETURN_IF_FAIL(private_output != NULL);
203
204         if (private_output->connection == value)
205                 return;
206
207         private_output->connection = value;
208
209         TDM_DBG("private_output(%p) wl_tbm_output@%d connection(%d)",
210                         private_output,
211                         wl_proxy_get_id((struct wl_proxy*)private_output->output),
212                         value);
213
214         v.u32 = value;
215         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
216                 if (h->func)
217                         h->func(private_output, TDM_OUTPUT_CHANGE_CONNECTION, v, h->user_data);
218         }
219 }
220
221 static void
222 _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value)
223 {
224         tdm_private_client_output *private_output = (tdm_private_client_output*)data;
225         tdm_client_output_handler_info *h = NULL;
226         tdm_value v;
227
228         TDM_RETURN_IF_FAIL(private_output != NULL);
229
230         if (private_output->dpms == value)
231                 return;
232
233         private_output->dpms = value;
234
235         TDM_DBG("private_output(%p) wl_tbm_output@%d dpms(%d)",
236                         private_output,
237                         wl_proxy_get_id((struct wl_proxy*)private_output->output),
238                         value);
239
240         v.u32 = value;
241         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
242                 if (h->func)
243                         h->func(private_output, TDM_OUTPUT_CHANGE_DPMS, v, h->user_data);
244         }
245 }
246
247 static const struct wl_tdm_output_listener tdm_client_output_listener = {
248         _tdm_client_output_cb_mode,
249         _tdm_client_output_cb_connection,
250         _tdm_client_output_cb_dpms,
251 };
252
253 static void
254 _tdm_client_cb_global(void *data, struct wl_registry *registry,
255                                           uint32_t name, const char *interface,
256                                           uint32_t version)
257 {
258         tdm_private_client *private_client = data;
259
260         if (strncmp(interface, "wl_tdm", 6) == 0) {
261                 private_client->tdm =
262                         wl_registry_bind(registry, name, &wl_tdm_interface, version);
263                 TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
264
265                 wl_display_flush(private_client->display);
266         }
267 }
268
269 static void
270 _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
271 {
272 }
273
274 static const struct wl_registry_listener tdm_client_registry_listener = {
275         _tdm_client_cb_global,
276         _tdm_client_cb_global_remove
277 };
278
279 tdm_client*
280 tdm_client_create(tdm_error *error)
281 {
282         tdm_private_client *private_client;
283
284         private_client = calloc(1, sizeof *private_client);
285         if (!private_client) {
286                 TDM_ERR("alloc failed");
287                 if (error)
288                         *error = TDM_ERROR_OUT_OF_MEMORY;
289                 return NULL;
290         }
291
292         LIST_INITHEAD(&private_client->output_list);
293
294         private_client->display = wl_display_connect("tdm-socket");
295         TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed);
296
297         private_client->registry = wl_display_get_registry(private_client->display);
298         TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed);
299
300         wl_registry_add_listener(private_client->registry,
301                                                          &tdm_client_registry_listener, private_client);
302         wl_display_roundtrip(private_client->display);
303
304         /* check global objects */
305         TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed);
306
307         if (error)
308                 *error = TDM_ERROR_NONE;
309
310         return (tdm_client*)private_client;
311 create_failed:
312         tdm_client_destroy((tdm_client*)private_client);
313         if (error)
314                 *error = TDM_ERROR_OPERATION_FAILED;
315         return NULL;
316 }
317
318 void
319 tdm_client_destroy(tdm_client *client)
320 {
321         tdm_private_client *private_client = (tdm_private_client*)client;
322         tdm_private_client_output *o = NULL, *oo = NULL;
323
324         if (!private_client)
325                 return;
326
327         if (private_client->temp_vblank)
328                 tdm_client_vblank_destroy(private_client->temp_vblank);
329
330         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_client->output_list, link) {
331                 _tdm_client_output_destroy(o);
332         }
333
334         if (private_client->tdm)
335                 wl_tdm_destroy(private_client->tdm);
336         if (private_client->registry)
337                 wl_registry_destroy(private_client->registry);
338         if (private_client->display)
339                 wl_display_disconnect(private_client->display);
340
341         free(private_client);
342 }
343
344 tdm_error
345 tdm_client_get_fd(tdm_client *client, int *fd)
346 {
347         tdm_private_client *private_client;
348
349         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
350         TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_ERROR_INVALID_PARAMETER);
351
352         private_client = (tdm_private_client*)client;
353
354         *fd = wl_display_get_fd(private_client->display);
355         if (*fd < 0)
356                 return TDM_ERROR_OPERATION_FAILED;
357
358         return TDM_ERROR_NONE;
359 }
360
361 tdm_error
362 tdm_client_handle_events(tdm_client *client)
363 {
364         tdm_private_client *private_client;
365
366         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
367
368         private_client = (tdm_private_client*)client;
369
370         wl_display_dispatch(private_client->display);
371
372         return TDM_ERROR_NONE;
373 }
374
375 typedef struct _tdm_client_vblank_temp {
376         tdm_client_vblank_handler2 func;
377         void *user_data;
378 } tdm_client_vblank_temp;
379
380 static void
381 _tdm_client_vblank_handler_temp(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
382                                                                 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
383 {
384         tdm_client_vblank_temp *vblank_temp = user_data;
385
386         TDM_RETURN_IF_FAIL(vblank_temp != NULL);
387
388         if (vblank_temp->func)
389                 vblank_temp->func(sequence, tv_sec, tv_usec, vblank_temp->user_data);
390
391         free(vblank_temp);
392 }
393
394 tdm_error
395 tdm_client_wait_vblank(tdm_client *client, char *name,
396                                            int sw_timer, int interval, int sync,
397                                            tdm_client_vblank_handler2 func, void *user_data)
398 {
399         tdm_private_client *private_client = (tdm_private_client*)client;
400         tdm_client_output *output;
401         tdm_client_vblank_temp *vblank_temp;
402         tdm_error ret;
403
404         TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
405         TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
406         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
407
408         if (!private_client->temp_vblank) {
409                 output = tdm_client_get_output(client, name, &ret);
410                 TDM_RETURN_VAL_IF_FAIL(output != NULL, ret);
411
412                 private_client->temp_vblank = tdm_client_output_create_vblank(output, &ret);
413                 TDM_RETURN_VAL_IF_FAIL(private_client->temp_vblank != NULL, ret);
414         }
415
416         tdm_client_vblank_set_enable_fake(private_client->temp_vblank, sw_timer);
417         tdm_client_vblank_set_sync(private_client->temp_vblank, sync);
418
419         vblank_temp = calloc(1, sizeof *vblank_temp);
420         TDM_RETURN_VAL_IF_FAIL(vblank_temp != NULL, TDM_ERROR_OUT_OF_MEMORY);
421
422         vblank_temp->func = func;
423         vblank_temp->user_data = user_data;
424
425         return tdm_client_vblank_wait(private_client->temp_vblank, interval, _tdm_client_vblank_handler_temp, vblank_temp);
426 }
427
428 tdm_client_output*
429 tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
430 {
431         tdm_private_client *private_client;
432         tdm_private_client_output *private_output = NULL;
433
434         if (error)
435                 *error = TDM_ERROR_NONE;
436
437         if (!client) {
438                 TDM_ERR("'!client' failed");
439                 if (error)
440                         *error = TDM_ERROR_INVALID_PARAMETER;
441                 return NULL;
442         }
443
444         private_client = (tdm_private_client*)client;
445
446         if (!name)
447                 name = "primary";
448
449         LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
450                 if (!strncmp(private_output->name, name, TDM_NAME_LEN))
451                         return (tdm_client_output*)private_output;
452         }
453
454         private_output = calloc(1, sizeof *private_output);
455         if (!private_output) {
456                 TDM_ERR("alloc failed");
457                 if (error)
458                         *error = TDM_ERROR_OUT_OF_MEMORY;
459                 return NULL;
460         }
461
462         private_output->private_client = private_client;
463
464         snprintf(private_output->name, TDM_NAME_LEN, "%s", name);
465         private_output->output = wl_tdm_create_output(private_client->tdm, private_output->name);
466         if (!private_output->output) {
467                 TDM_ERR("couldn't create output resource");
468                 free(private_output);
469                 if (error)
470                         *error = TDM_ERROR_OUT_OF_MEMORY;
471                 return NULL;
472         }
473
474         LIST_INITHEAD(&private_output->vblank_list);
475         LIST_INITHEAD(&private_output->change_handler_list);
476         LIST_ADDTAIL(&private_output->link, &private_client->output_list);
477
478         wl_tdm_output_add_listener(private_output->output,
479                                                            &tdm_client_output_listener, private_output);
480         wl_display_roundtrip(private_client->display);
481
482         return (tdm_client_output*)private_output;
483 }
484
485 tdm_error
486 tdm_client_output_add_change_handler(tdm_client_output *output,
487                                                                          tdm_client_output_change_handler func,
488                                                                          void *user_data)
489 {
490         tdm_private_client_output *private_output;
491         tdm_client_output_handler_info *h;
492
493         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
494         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
495
496         private_output = (tdm_private_client_output*)output;
497
498         h = calloc(1, sizeof *h);
499         TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
500
501         h->private_output = private_output;
502         h->func = func;
503         h->user_data = user_data;
504         LIST_ADDTAIL(&h->link, &private_output->change_handler_list);
505
506         return TDM_ERROR_NOT_IMPLEMENTED;
507 }
508
509 void
510 tdm_client_output_remove_change_handler(tdm_client_output *output,
511                                                                                 tdm_client_output_change_handler func,
512                                                                                 void *user_data)
513 {
514         tdm_private_client_output *private_output;
515         tdm_client_output_handler_info *h = NULL;
516
517         TDM_RETURN_IF_FAIL(output != NULL);
518         TDM_RETURN_IF_FAIL(func != NULL);
519
520         private_output = (tdm_private_client_output*)output;
521
522         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
523                 if (h->func != func || h->user_data != user_data)
524                         continue;
525
526                 LIST_DEL(&h->link);
527                 free(h);
528                 return;
529         }
530 }
531
532 tdm_error
533 tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refresh)
534 {
535         tdm_private_client_output *private_output;
536
537         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
538         TDM_RETURN_VAL_IF_FAIL(refresh != NULL, TDM_ERROR_INVALID_PARAMETER);
539
540         private_output = (tdm_private_client_output*)output;
541
542         *refresh = private_output->refresh;
543
544         return TDM_ERROR_NONE;
545 }
546
547 tdm_error
548 tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_status *status)
549 {
550         tdm_private_client_output *private_output;
551
552         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
553         TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
554
555         private_output = (tdm_private_client_output*)output;
556
557         *status = private_output->connection;
558
559         return TDM_ERROR_NONE;
560 }
561
562 tdm_error
563 tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
564 {
565         tdm_private_client_output *private_output;
566
567         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
568         TDM_RETURN_VAL_IF_FAIL(dpms != NULL, TDM_ERROR_INVALID_PARAMETER);
569
570         private_output = (tdm_private_client_output*)output;
571
572         *dpms = private_output->dpms;
573
574         return TDM_ERROR_NONE;
575 }
576
577 tdm_client_vblank*
578 tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
579 {
580         tdm_private_client_output *private_output;
581         tdm_private_client_vblank *private_vblank;
582
583         if (error)
584                 *error = TDM_ERROR_NONE;
585
586         if (!output) {
587                 TDM_ERR("'!output' failed");
588                 if (error)
589                         *error = TDM_ERROR_INVALID_PARAMETER;
590                 return NULL;
591         }
592
593         private_output = (tdm_private_client_output*)output;
594
595         private_vblank = calloc(1, sizeof *private_vblank);
596         if (!private_vblank) {
597                 TDM_ERR("alloc failed");
598                 if (error)
599                         *error = TDM_ERROR_OUT_OF_MEMORY;
600                 return NULL;
601         }
602
603         private_vblank->private_output = private_output;
604
605         private_vblank->vblank = wl_tdm_output_create_vblank(private_output->output);
606         if (!private_vblank->vblank) {
607                 TDM_ERR("couldn't create vblank resource");
608                 free(private_vblank);
609                 if (error)
610                         *error = TDM_ERROR_OUT_OF_MEMORY;
611                 return NULL;
612         }
613
614         /* initial value */
615         private_vblank->fps = private_output->refresh;
616         private_vblank->offset = 0;
617         private_vblank->enable_fake = 0;
618
619         LIST_INITHEAD(&private_vblank->wait_list);
620         LIST_ADDTAIL(&private_vblank->link, &private_output->vblank_list);
621
622         wl_tdm_vblank_add_listener(private_vblank->vblank,
623                                                            &tdm_client_vblank_listener, private_vblank);
624
625         return (tdm_client_vblank*)private_vblank;
626 }
627
628 void
629 tdm_client_vblank_destroy(tdm_client_vblank *vblank)
630 {
631         tdm_private_client_vblank *private_vblank;
632         tdm_client_wait_info *w = NULL, *ww = NULL;
633
634         TDM_RETURN_IF_FAIL(vblank != NULL);
635
636         private_vblank = vblank;
637         LIST_DEL(&private_vblank->link);
638
639         LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
640                 LIST_DEL(&w->link);
641                 free(w);
642         }
643
644         wl_tdm_vblank_destroy(private_vblank->vblank);
645
646         free(private_vblank);
647 }
648
649 tdm_error
650 tdm_client_vblank_set_sync(tdm_client_vblank *vblank, unsigned int sync)
651 {
652         tdm_private_client_vblank *private_vblank;
653
654         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
655
656         private_vblank = vblank;
657         private_vblank->sync = sync;
658
659         return TDM_ERROR_NONE;
660 }
661
662 tdm_error
663 tdm_client_vblank_set_fps(tdm_client_vblank *vblank, unsigned int fps)
664 {
665         tdm_private_client_vblank *private_vblank;
666
667         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
668         TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER);
669
670         private_vblank = vblank;
671         TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
672
673         if (private_vblank->fps == fps)
674                 return TDM_ERROR_NONE;
675         private_vblank->fps = fps;
676
677         wl_tdm_vblank_set_fps(private_vblank->vblank, fps);
678
679         return TDM_ERROR_NONE;
680 }
681
682 tdm_error
683 tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms)
684 {
685         tdm_private_client_vblank *private_vblank;
686
687         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
688
689         private_vblank = vblank;
690         TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
691
692         if (private_vblank->offset == offset_ms)
693                 return TDM_ERROR_NONE;
694         private_vblank->offset = offset_ms;
695
696         wl_tdm_vblank_set_offset(private_vblank->vblank, offset_ms);
697
698         return TDM_ERROR_NONE;
699 }
700
701 tdm_error
702 tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable_fake)
703 {
704         tdm_private_client_vblank *private_vblank;
705
706         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
707
708         private_vblank = vblank;
709
710         if (private_vblank->enable_fake == enable_fake)
711                 return TDM_ERROR_NONE;
712         private_vblank->enable_fake = enable_fake;
713
714         wl_tdm_vblank_set_enable_fake(private_vblank->vblank, enable_fake);
715
716         return TDM_ERROR_NONE;
717 }
718
719 tdm_error
720 tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_client_vblank_handler func, void *user_data)
721 {
722         tdm_private_client *private_client;
723         tdm_private_client_output *private_output;
724         tdm_private_client_vblank *private_vblank;
725         tdm_client_wait_info *w;
726         struct timespec tp;
727         int ret = 0;
728
729         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
730         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
731         /* can't support "interval 0" and "getting current_msc" things because
732          * there is a socket communication between TDM client and server. It's impossible
733          * to return the current msc or sequence immediately.
734          */
735         TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
736
737         private_vblank = vblank;
738         private_output = private_vblank->private_output;
739         private_client = private_output->private_client;
740
741         if (!private_vblank->started)
742                 private_vblank->started = 1;
743
744         if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) {
745                 TDM_INFO("dpms off");
746                 return TDM_ERROR_DPMS_OFF;
747         }
748
749         w = calloc(1, sizeof *w);
750         if (!w) {
751                 TDM_ERR("alloc failed");
752                 return TDM_ERROR_OUT_OF_MEMORY;
753         }
754
755         w->private_vblank = private_vblank;
756         w->func = func;
757         w->user_data = user_data;
758
759         LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
760
761         clock_gettime(CLOCK_MONOTONIC, &tp);
762         w->req_id = ++private_output->req_id;
763         w->req_sec = (unsigned int)tp.tv_sec;
764         w->req_usec = (unsigned int)(tp.tv_nsec / 1000);
765         w->need_free = (private_vblank->sync) ? 0 : 1;
766
767         wl_tdm_vblank_wait_vblank(private_vblank->vblank, interval, w->req_id, w->req_sec, w->req_usec);
768
769         TDM_TRACE_COUNT(ClientWaitVBlank, w->req_id);
770
771         if (!private_vblank->sync) {
772                 wl_display_flush(private_client->display);
773                 return TDM_ERROR_NONE;
774         }
775
776         while (ret != -1 && !w->need_free)
777                 ret = wl_display_dispatch(private_client->display);
778
779         clock_gettime(CLOCK_MONOTONIC, &tp);
780         TDM_DBG("block during %d us",
781                         ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
782                         - (w->req_sec * 1000000 + w->req_usec));
783
784         LIST_DEL(&w->link);
785         free(w);
786
787         return TDM_ERROR_NONE;
788 }
789
790 tdm_error
791 tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
792                                                    tdm_client_vblank_handler func, void *user_data)
793 {
794         tdm_private_client *private_client;
795         tdm_private_client_output *private_output;
796         tdm_private_client_vblank *private_vblank;
797         tdm_client_wait_info *w;
798         struct timespec tp;
799         int ret = 0;
800
801         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
802         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
803
804         private_vblank = vblank;
805         private_output = private_vblank->private_output;
806         private_client = private_output->private_client;
807
808         if (!private_vblank->started)
809                 private_vblank->started = 1;
810
811         if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) {
812                 TDM_INFO("dpms off");
813                 return TDM_ERROR_DPMS_OFF;
814         }
815
816         w = calloc(1, sizeof *w);
817         if (!w) {
818                 TDM_ERR("alloc failed");
819                 return TDM_ERROR_OUT_OF_MEMORY;
820         }
821
822         w->private_vblank = private_vblank;
823         w->func = func;
824         w->user_data = user_data;
825
826         LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
827
828         clock_gettime(CLOCK_MONOTONIC, &tp);
829         w->req_id = ++private_output->req_id;
830         w->req_sec = (unsigned int)tp.tv_sec;
831         w->req_usec = (unsigned int)(tp.tv_nsec / 1000);
832         w->need_free = (private_vblank->sync) ? 0 : 1;
833
834         wl_tdm_vblank_wait_vblank_seq(private_vblank->vblank, sequence, w->req_id, w->req_sec, w->req_usec);
835
836         TDM_TRACE_COUNT(ClientWaitVBlank, w->req_id);
837
838         if (!private_vblank->sync) {
839                 wl_display_flush(private_client->display);
840                 return TDM_ERROR_NONE;
841         }
842
843         while (ret != -1 && !w->need_free)
844                 ret = wl_display_dispatch(private_client->display);
845
846         clock_gettime(CLOCK_MONOTONIC, &tp);
847         TDM_DBG("block during %d us",
848                         ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
849                         - (w->req_sec * 1000000 + w->req_usec));
850
851         LIST_DEL(&w->link);
852         free(w);
853
854         return TDM_ERROR_NONE;
855 }