1 /**************************************************************************
5 * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
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>
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:
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
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.
34 **************************************************************************/
46 #include "tdm_client.h"
48 #include "tdm_macro.h"
51 #include "tdm_private.h"
52 #include "tdm-client-protocol.h"
54 typedef struct _tdm_private_client_vblank tdm_private_client_vblank;
56 typedef struct _tdm_private_client {
57 struct wl_display *display;
58 struct wl_registry *registry;
60 struct list_head output_list;
62 tdm_private_client_vblank *temp_vblank;
65 typedef struct _tdm_private_client_output {
66 tdm_private_client *private_client;
68 char name[TDM_NAME_LEN];
69 struct wl_tdm_output *output;
73 tdm_output_conn_status connection;
75 struct list_head vblank_list;
76 struct list_head change_handler_list;
80 struct list_head link;
81 } tdm_private_client_output;
83 struct _tdm_private_client_vblank {
84 tdm_private_client_output *private_output;
86 struct wl_tdm_vblank *vblank;
87 struct list_head wait_list;
89 char name[TDM_NAME_LEN];
93 unsigned int enable_fake;
97 struct list_head link;
100 typedef struct _tdm_client_output_handler_info {
101 tdm_private_client_output *private_output;
103 tdm_client_output_change_handler func;
106 struct list_head link;
107 } tdm_client_output_handler_info;
109 typedef struct _tdm_client_wait_info {
110 tdm_private_client_vblank *private_vblank;
112 tdm_client_vblank_handler func;
116 unsigned int req_sec;
117 unsigned int req_usec;
120 struct list_head link;
121 } tdm_client_wait_info;
124 _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank,
125 uint32_t req_id, uint32_t sequence, uint32_t tv_sec,
126 uint32_t tv_usec, uint32_t error)
128 tdm_private_client_vblank *private_vblank = data;
129 tdm_client_wait_info *w = NULL, *ww = NULL;
131 TDM_RETURN_IF_FAIL(private_vblank != NULL);
133 TDM_TRACE_COUNT(ClientDoneVBlank, req_id);
135 LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
136 if (w->req_id != req_id)
140 w->func(private_vblank, error, sequence, tv_sec, tv_usec, w->user_data);
151 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
152 _tdm_client_vblank_cb_done,
156 _tdm_client_output_destroy(tdm_private_client_output *private_output)
158 tdm_private_client_vblank *v = NULL, *vv = NULL;
159 tdm_client_output_handler_info *h = NULL, *hh = NULL;
161 LIST_DEL(&private_output->link);
163 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_list, link) {
164 TDM_ERR("vblanks SHOULD be destroyed first!");
166 v->private_output = NULL;
169 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list, link) {
174 wl_tdm_output_destroy(private_output->output);
176 free(private_output);
180 _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output,
181 uint32_t width, uint32_t height, uint32_t refresh)
183 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
185 TDM_RETURN_IF_FAIL(private_output != NULL);
187 private_output->width = width;
188 private_output->height = height;
189 private_output->refresh = refresh;
191 TDM_DBG("private_output(%p) wl_tbm_output@%d width(%d) height(%d) refresh(%d)",
192 private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output),
193 width, height, refresh);
197 _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value)
199 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
200 tdm_client_output_handler_info *h = NULL;
203 TDM_RETURN_IF_FAIL(private_output != NULL);
205 if (private_output->connection == value)
208 private_output->connection = value;
210 TDM_DBG("private_output(%p) wl_tbm_output@%d connection(%d)",
212 wl_proxy_get_id((struct wl_proxy*)private_output->output),
216 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
218 h->func(private_output, TDM_OUTPUT_CHANGE_CONNECTION, v, h->user_data);
223 _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value)
225 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
226 tdm_client_output_handler_info *h = NULL;
229 TDM_RETURN_IF_FAIL(private_output != NULL);
231 if (private_output->dpms == value)
234 private_output->dpms = value;
236 TDM_DBG("private_output(%p) wl_tbm_output@%d dpms(%d)",
238 wl_proxy_get_id((struct wl_proxy*)private_output->output),
242 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
244 h->func(private_output, TDM_OUTPUT_CHANGE_DPMS, v, h->user_data);
248 static const struct wl_tdm_output_listener tdm_client_output_listener = {
249 _tdm_client_output_cb_mode,
250 _tdm_client_output_cb_connection,
251 _tdm_client_output_cb_dpms,
255 _tdm_client_cb_global(void *data, struct wl_registry *registry,
256 uint32_t name, const char *interface,
259 tdm_private_client *private_client = data;
261 if (strncmp(interface, "wl_tdm", 6) == 0) {
262 private_client->tdm =
263 wl_registry_bind(registry, name, &wl_tdm_interface, version);
264 TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
266 wl_display_flush(private_client->display);
271 _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
275 static const struct wl_registry_listener tdm_client_registry_listener = {
276 _tdm_client_cb_global,
277 _tdm_client_cb_global_remove
281 tdm_client_create(tdm_error *error)
283 tdm_private_client *private_client;
285 private_client = calloc(1, sizeof *private_client);
286 if (!private_client) {
287 TDM_ERR("alloc failed");
289 *error = TDM_ERROR_OUT_OF_MEMORY;
293 LIST_INITHEAD(&private_client->output_list);
295 private_client->display = wl_display_connect("tdm-socket");
296 TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed);
298 private_client->registry = wl_display_get_registry(private_client->display);
299 TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed);
301 wl_registry_add_listener(private_client->registry,
302 &tdm_client_registry_listener, private_client);
303 wl_display_roundtrip(private_client->display);
305 /* check global objects */
306 TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed);
309 *error = TDM_ERROR_NONE;
311 return (tdm_client*)private_client;
313 tdm_client_destroy((tdm_client*)private_client);
315 *error = TDM_ERROR_OPERATION_FAILED;
320 tdm_client_destroy(tdm_client *client)
322 tdm_private_client *private_client = (tdm_private_client*)client;
323 tdm_private_client_output *o = NULL, *oo = NULL;
328 if (private_client->temp_vblank)
329 tdm_client_vblank_destroy(private_client->temp_vblank);
331 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_client->output_list, link) {
332 _tdm_client_output_destroy(o);
335 if (private_client->tdm)
336 wl_tdm_destroy(private_client->tdm);
337 if (private_client->registry)
338 wl_registry_destroy(private_client->registry);
339 if (private_client->display)
340 wl_display_disconnect(private_client->display);
342 free(private_client);
346 tdm_client_get_fd(tdm_client *client, int *fd)
348 tdm_private_client *private_client;
350 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
351 TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_ERROR_INVALID_PARAMETER);
353 private_client = (tdm_private_client*)client;
355 *fd = wl_display_get_fd(private_client->display);
357 return TDM_ERROR_OPERATION_FAILED;
359 return TDM_ERROR_NONE;
363 tdm_client_handle_events(tdm_client *client)
365 tdm_private_client *private_client;
367 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
369 private_client = (tdm_private_client*)client;
371 wl_display_dispatch(private_client->display);
373 return TDM_ERROR_NONE;
376 typedef struct _tdm_client_vblank_temp {
377 tdm_client_vblank_handler2 func;
379 } tdm_client_vblank_temp;
382 _tdm_client_vblank_handler_temp(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
383 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
385 tdm_client_vblank_temp *vblank_temp = user_data;
387 TDM_RETURN_IF_FAIL(vblank_temp != NULL);
389 if (vblank_temp->func)
390 vblank_temp->func(sequence, tv_sec, tv_usec, vblank_temp->user_data);
396 tdm_client_wait_vblank(tdm_client *client, char *name,
397 int sw_timer, int interval, int sync,
398 tdm_client_vblank_handler2 func, void *user_data)
400 tdm_private_client *private_client = (tdm_private_client*)client;
401 tdm_client_output *output;
402 tdm_client_vblank_temp *vblank_temp;
405 TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
406 TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
407 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
409 if (!private_client->temp_vblank) {
410 output = tdm_client_get_output(client, name, &ret);
411 TDM_RETURN_VAL_IF_FAIL(output != NULL, ret);
413 private_client->temp_vblank = tdm_client_output_create_vblank(output, &ret);
414 TDM_RETURN_VAL_IF_FAIL(private_client->temp_vblank != NULL, ret);
417 tdm_client_vblank_set_enable_fake(private_client->temp_vblank, sw_timer);
418 tdm_client_vblank_set_sync(private_client->temp_vblank, sync);
420 vblank_temp = calloc(1, sizeof *vblank_temp);
421 TDM_RETURN_VAL_IF_FAIL(vblank_temp != NULL, TDM_ERROR_OUT_OF_MEMORY);
423 vblank_temp->func = func;
424 vblank_temp->user_data = user_data;
426 return tdm_client_vblank_wait(private_client->temp_vblank, interval, _tdm_client_vblank_handler_temp, vblank_temp);
430 tdm_client_set_client_vblank_fps(tdm_client *client, pid_t pid, const char *name, unsigned int fps)
432 tdm_private_client *private_client = (tdm_private_client*)client;
434 TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
435 TDM_RETURN_VAL_IF_FAIL(pid > 0, TDM_ERROR_INVALID_PARAMETER);
436 TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER);
439 name = TDM_VBLANK_DEFAULT_NAME;
441 wl_tdm_set_client_vblank_fps(private_client->tdm, pid, name, fps);
443 wl_display_flush(private_client->display);
445 return TDM_ERROR_NONE;
449 tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
451 tdm_private_client *private_client;
452 tdm_private_client_output *private_output = NULL;
455 *error = TDM_ERROR_NONE;
458 TDM_ERR("'!client' failed");
460 *error = TDM_ERROR_INVALID_PARAMETER;
464 private_client = (tdm_private_client*)client;
469 LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
470 if (!strncmp(private_output->name, name, TDM_NAME_LEN))
471 return (tdm_client_output*)private_output;
474 private_output = calloc(1, sizeof *private_output);
475 if (!private_output) {
476 TDM_ERR("alloc failed");
478 *error = TDM_ERROR_OUT_OF_MEMORY;
482 private_output->private_client = private_client;
484 snprintf(private_output->name, TDM_NAME_LEN, "%s", name);
485 private_output->output = wl_tdm_create_output(private_client->tdm, private_output->name);
486 if (!private_output->output) {
487 TDM_ERR("couldn't create output resource");
488 free(private_output);
490 *error = TDM_ERROR_OUT_OF_MEMORY;
494 LIST_INITHEAD(&private_output->vblank_list);
495 LIST_INITHEAD(&private_output->change_handler_list);
496 LIST_ADDTAIL(&private_output->link, &private_client->output_list);
498 wl_tdm_output_add_listener(private_output->output,
499 &tdm_client_output_listener, private_output);
500 wl_display_roundtrip(private_client->display);
502 return (tdm_client_output*)private_output;
506 tdm_client_output_add_change_handler(tdm_client_output *output,
507 tdm_client_output_change_handler func,
510 tdm_private_client_output *private_output;
511 tdm_client_output_handler_info *h;
513 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
514 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
516 private_output = (tdm_private_client_output*)output;
518 h = calloc(1, sizeof *h);
519 TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
521 h->private_output = private_output;
523 h->user_data = user_data;
524 LIST_ADDTAIL(&h->link, &private_output->change_handler_list);
526 return TDM_ERROR_NOT_IMPLEMENTED;
530 tdm_client_output_remove_change_handler(tdm_client_output *output,
531 tdm_client_output_change_handler func,
534 tdm_private_client_output *private_output;
535 tdm_client_output_handler_info *h = NULL;
537 TDM_RETURN_IF_FAIL(output != NULL);
538 TDM_RETURN_IF_FAIL(func != NULL);
540 private_output = (tdm_private_client_output*)output;
542 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
543 if (h->func != func || h->user_data != user_data)
553 tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refresh)
555 tdm_private_client_output *private_output;
557 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
558 TDM_RETURN_VAL_IF_FAIL(refresh != NULL, TDM_ERROR_INVALID_PARAMETER);
560 private_output = (tdm_private_client_output*)output;
562 *refresh = private_output->refresh;
564 return TDM_ERROR_NONE;
568 tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_status *status)
570 tdm_private_client_output *private_output;
572 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
573 TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
575 private_output = (tdm_private_client_output*)output;
577 *status = private_output->connection;
579 return TDM_ERROR_NONE;
583 tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
585 tdm_private_client_output *private_output;
587 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
588 TDM_RETURN_VAL_IF_FAIL(dpms != NULL, TDM_ERROR_INVALID_PARAMETER);
590 private_output = (tdm_private_client_output*)output;
592 *dpms = private_output->dpms;
594 return TDM_ERROR_NONE;
598 tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
600 tdm_private_client_output *private_output;
601 tdm_private_client_vblank *private_vblank;
604 *error = TDM_ERROR_NONE;
607 TDM_ERR("'!output' failed");
609 *error = TDM_ERROR_INVALID_PARAMETER;
613 private_output = (tdm_private_client_output*)output;
615 private_vblank = calloc(1, sizeof *private_vblank);
616 if (!private_vblank) {
617 TDM_ERR("alloc failed");
619 *error = TDM_ERROR_OUT_OF_MEMORY;
623 private_vblank->private_output = private_output;
625 private_vblank->vblank = wl_tdm_output_create_vblank(private_output->output);
626 if (!private_vblank->vblank) {
627 TDM_ERR("couldn't create vblank resource");
628 free(private_vblank);
630 *error = TDM_ERROR_OUT_OF_MEMORY;
635 private_vblank->fps = private_output->refresh;
636 private_vblank->offset = 0;
637 private_vblank->enable_fake = 0;
639 LIST_INITHEAD(&private_vblank->wait_list);
640 LIST_ADDTAIL(&private_vblank->link, &private_output->vblank_list);
642 wl_tdm_vblank_add_listener(private_vblank->vblank,
643 &tdm_client_vblank_listener, private_vblank);
645 return (tdm_client_vblank*)private_vblank;
649 tdm_client_vblank_destroy(tdm_client_vblank *vblank)
651 tdm_private_client_vblank *private_vblank;
652 tdm_client_wait_info *w = NULL, *ww = NULL;
654 TDM_RETURN_IF_FAIL(vblank != NULL);
656 private_vblank = vblank;
657 LIST_DEL(&private_vblank->link);
659 LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
664 wl_tdm_vblank_destroy(private_vblank->vblank);
666 free(private_vblank);
670 tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name)
672 tdm_private_client_vblank *private_vblank;
674 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
676 private_vblank = vblank;
679 name = TDM_VBLANK_DEFAULT_NAME;
681 strncpy(private_vblank->name, name, TDM_NAME_LEN - 1);
682 private_vblank->name[TDM_NAME_LEN - 1] = '\0';
684 wl_tdm_vblank_set_name(private_vblank->vblank, private_vblank->name);
686 return TDM_ERROR_NONE;
690 tdm_client_vblank_set_sync(tdm_client_vblank *vblank, unsigned int sync)
692 tdm_private_client_vblank *private_vblank;
694 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
696 private_vblank = vblank;
697 private_vblank->sync = sync;
699 return TDM_ERROR_NONE;
703 tdm_client_vblank_set_fps(tdm_client_vblank *vblank, unsigned int fps)
705 tdm_private_client_vblank *private_vblank;
707 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
708 TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER);
710 private_vblank = vblank;
711 TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
713 if (private_vblank->fps == fps)
714 return TDM_ERROR_NONE;
715 private_vblank->fps = fps;
717 wl_tdm_vblank_set_fps(private_vblank->vblank, fps);
719 return TDM_ERROR_NONE;
723 tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms)
725 tdm_private_client_vblank *private_vblank;
727 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
729 private_vblank = vblank;
730 TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
732 if (private_vblank->offset == offset_ms)
733 return TDM_ERROR_NONE;
734 private_vblank->offset = offset_ms;
736 wl_tdm_vblank_set_offset(private_vblank->vblank, offset_ms);
738 return TDM_ERROR_NONE;
742 tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable_fake)
744 tdm_private_client_vblank *private_vblank;
746 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
748 private_vblank = vblank;
750 if (private_vblank->enable_fake == enable_fake)
751 return TDM_ERROR_NONE;
752 private_vblank->enable_fake = enable_fake;
754 wl_tdm_vblank_set_enable_fake(private_vblank->vblank, enable_fake);
756 return TDM_ERROR_NONE;
760 tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_client_vblank_handler func, void *user_data)
762 tdm_private_client *private_client;
763 tdm_private_client_output *private_output;
764 tdm_private_client_vblank *private_vblank;
765 tdm_client_wait_info *w;
769 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
770 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
771 /* can't support "interval 0" and "getting current_msc" things because
772 * there is a socket communication between TDM client and server. It's impossible
773 * to return the current msc or sequence immediately.
775 TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
777 private_vblank = vblank;
778 private_output = private_vblank->private_output;
779 private_client = private_output->private_client;
781 if (!private_vblank->started)
782 private_vblank->started = 1;
784 if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) {
785 TDM_INFO("dpms off");
786 return TDM_ERROR_DPMS_OFF;
789 w = calloc(1, sizeof *w);
791 TDM_ERR("alloc failed");
792 return TDM_ERROR_OUT_OF_MEMORY;
795 w->private_vblank = private_vblank;
797 w->user_data = user_data;
799 LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
801 clock_gettime(CLOCK_MONOTONIC, &tp);
802 w->req_id = ++private_output->req_id;
803 w->req_sec = (unsigned int)tp.tv_sec;
804 w->req_usec = (unsigned int)(tp.tv_nsec / 1000);
805 w->need_free = (private_vblank->sync) ? 0 : 1;
807 wl_tdm_vblank_wait_vblank(private_vblank->vblank, interval, w->req_id, w->req_sec, w->req_usec);
809 TDM_TRACE_COUNT(ClientWaitVBlank, w->req_id);
811 if (!private_vblank->sync) {
812 wl_display_flush(private_client->display);
813 return TDM_ERROR_NONE;
816 while (ret != -1 && !w->need_free)
817 ret = wl_display_dispatch(private_client->display);
819 clock_gettime(CLOCK_MONOTONIC, &tp);
820 TDM_DBG("block during %d us",
821 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
822 - (w->req_sec * 1000000 + w->req_usec));
827 return TDM_ERROR_NONE;
831 tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
832 tdm_client_vblank_handler func, void *user_data)
834 tdm_private_client *private_client;
835 tdm_private_client_output *private_output;
836 tdm_private_client_vblank *private_vblank;
837 tdm_client_wait_info *w;
841 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
842 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
844 private_vblank = vblank;
845 private_output = private_vblank->private_output;
846 private_client = private_output->private_client;
848 if (!private_vblank->started)
849 private_vblank->started = 1;
851 if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) {
852 TDM_INFO("dpms off");
853 return TDM_ERROR_DPMS_OFF;
856 w = calloc(1, sizeof *w);
858 TDM_ERR("alloc failed");
859 return TDM_ERROR_OUT_OF_MEMORY;
862 w->private_vblank = private_vblank;
864 w->user_data = user_data;
866 LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
868 clock_gettime(CLOCK_MONOTONIC, &tp);
869 w->req_id = ++private_output->req_id;
870 w->req_sec = (unsigned int)tp.tv_sec;
871 w->req_usec = (unsigned int)(tp.tv_nsec / 1000);
872 w->need_free = (private_vblank->sync) ? 0 : 1;
874 wl_tdm_vblank_wait_vblank_seq(private_vblank->vblank, sequence, w->req_id, w->req_sec, w->req_usec);
876 TDM_TRACE_COUNT(ClientWaitVBlank, w->req_id);
878 if (!private_vblank->sync) {
879 wl_display_flush(private_client->display);
880 return TDM_ERROR_NONE;
883 while (ret != -1 && !w->need_free)
884 ret = wl_display_dispatch(private_client->display);
886 clock_gettime(CLOCK_MONOTONIC, &tp);
887 TDM_DBG("block during %d us",
888 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
889 - (w->req_sec * 1000000 + w->req_usec));
894 return TDM_ERROR_NONE;