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;
79 unsigned int watch_output_changes;
81 struct list_head link;
82 } tdm_private_client_output;
84 struct _tdm_private_client_vblank {
85 tdm_private_client_output *private_output;
87 struct wl_tdm_vblank *vblank;
88 struct list_head wait_list;
90 char name[TDM_NAME_LEN];
94 unsigned int enable_fake;
101 struct list_head link;
104 typedef struct _tdm_client_output_handler_info {
105 tdm_private_client_output *private_output;
107 tdm_client_output_change_handler func;
110 struct list_head link;
111 } tdm_client_output_handler_info;
113 typedef struct _tdm_client_wait_info {
114 tdm_private_client_vblank *private_vblank;
116 tdm_client_vblank_handler func;
123 struct list_head link;
124 } tdm_client_wait_info;
127 _tdm_client_vblank_cb_stamp(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t stamp)
129 tdm_private_client_vblank *private_vblank = data;
131 TDM_RETURN_IF_FAIL(private_vblank != NULL);
133 private_vblank->stamp = stamp;
137 _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank,
138 uint32_t req_id, uint32_t sequence, uint32_t tv_sec,
139 uint32_t tv_usec, uint32_t error)
141 tdm_private_client_vblank *private_vblank = data;
142 tdm_client_wait_info *w = NULL, *ww = NULL;
144 TDM_RETURN_IF_FAIL(private_vblank != NULL);
146 private_vblank->last_time = TDM_TIME(tv_sec, tv_usec);
148 TDM_DBG("vblank(%p) req_id(%u) sequence(%u) time(%.6f)",
149 private_vblank, req_id, sequence, TDM_TIME(tv_sec, tv_usec));
151 TDM_TRACE_COUNT(ClientDoneVBlank, req_id);
153 LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
154 if (w->req_id != req_id)
157 if (w->req_time >= private_vblank->last_time)
158 TDM_WRN("'req(%.6f) < last(%.6f)' failed", w->req_time, private_vblank->last_time);
161 w->func(private_vblank, error, sequence, tv_sec, tv_usec, w->user_data);
172 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
173 _tdm_client_vblank_cb_stamp,
174 _tdm_client_vblank_cb_done,
178 _tdm_client_output_destroy(tdm_private_client_output *private_output)
180 tdm_private_client_vblank *v = NULL, *vv = NULL;
181 tdm_client_output_handler_info *h = NULL, *hh = NULL;
183 LIST_DEL(&private_output->link);
185 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_list, link) {
186 TDM_ERR("vblanks SHOULD be destroyed first!");
188 v->private_output = NULL;
191 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list, link) {
196 wl_tdm_output_destroy(private_output->output);
198 free(private_output);
202 _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output,
203 uint32_t width, uint32_t height, uint32_t refresh, uint32_t error)
205 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
207 TDM_RETURN_IF_FAIL(private_output != NULL);
209 private_output->width = width;
210 private_output->height = height;
211 private_output->refresh = refresh;
213 if (error != TDM_ERROR_NONE)
214 TDM_INFO("mode event error: %d", error);
216 TDM_DBG("private_output(%p) wl_tbm_output@%d width(%d) height(%d) refresh(%d)",
217 private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output),
218 width, height, refresh);
222 _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
224 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
225 tdm_client_output_handler_info *h = NULL;
228 TDM_RETURN_IF_FAIL(private_output != NULL);
230 if (private_output->connection == value)
233 private_output->connection = value;
235 if (error != TDM_ERROR_NONE)
236 TDM_INFO("connection event error: %d", error);
238 TDM_DBG("private_output(%p) wl_tbm_output@%d connection(%d)",
240 wl_proxy_get_id((struct wl_proxy*)private_output->output),
244 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
246 h->func(private_output, TDM_OUTPUT_CHANGE_CONNECTION, v, h->user_data);
251 _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
253 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
254 tdm_client_output_handler_info *h = NULL;
257 TDM_RETURN_IF_FAIL(private_output != NULL);
259 if (private_output->dpms == value)
262 private_output->dpms = value;
264 if (error != TDM_ERROR_NONE)
265 TDM_INFO("dpms event error: %d", error);
267 TDM_DBG("private_output(%p) wl_tbm_output@%d dpms(%d)",
269 wl_proxy_get_id((struct wl_proxy*)private_output->output),
273 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
275 h->func(private_output, TDM_OUTPUT_CHANGE_DPMS, v, h->user_data);
279 static const struct wl_tdm_output_listener tdm_client_output_listener = {
280 _tdm_client_output_cb_mode,
281 _tdm_client_output_cb_connection,
282 _tdm_client_output_cb_dpms,
286 _tdm_client_cb_global(void *data, struct wl_registry *registry,
287 uint32_t name, const char *interface,
290 tdm_private_client *private_client = data;
292 if (strncmp(interface, "wl_tdm", 6) == 0) {
293 private_client->tdm =
294 wl_registry_bind(registry, name, &wl_tdm_interface, version);
295 TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
297 wl_display_flush(private_client->display);
302 _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
306 static const struct wl_registry_listener tdm_client_registry_listener = {
307 _tdm_client_cb_global,
308 _tdm_client_cb_global_remove
312 tdm_client_create(tdm_error *error)
314 tdm_private_client *private_client;
316 private_client = calloc(1, sizeof *private_client);
317 if (!private_client) {
318 TDM_ERR("alloc failed");
320 *error = TDM_ERROR_OUT_OF_MEMORY;
324 LIST_INITHEAD(&private_client->output_list);
326 private_client->display = wl_display_connect("tdm-socket");
327 TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed);
329 private_client->registry = wl_display_get_registry(private_client->display);
330 TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed);
332 wl_registry_add_listener(private_client->registry,
333 &tdm_client_registry_listener, private_client);
334 wl_display_roundtrip(private_client->display);
336 /* check global objects */
337 TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed);
340 *error = TDM_ERROR_NONE;
342 return (tdm_client*)private_client;
344 tdm_client_destroy((tdm_client*)private_client);
346 *error = TDM_ERROR_OPERATION_FAILED;
351 tdm_client_destroy(tdm_client *client)
353 tdm_private_client *private_client = (tdm_private_client*)client;
354 tdm_private_client_output *o = NULL, *oo = NULL;
359 if (private_client->temp_vblank)
360 tdm_client_vblank_destroy(private_client->temp_vblank);
362 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_client->output_list, link) {
363 _tdm_client_output_destroy(o);
366 if (private_client->tdm)
367 wl_tdm_destroy(private_client->tdm);
368 if (private_client->registry)
369 wl_registry_destroy(private_client->registry);
370 if (private_client->display)
371 wl_display_disconnect(private_client->display);
373 free(private_client);
377 tdm_client_get_fd(tdm_client *client, int *fd)
379 tdm_private_client *private_client;
381 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
382 TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_ERROR_INVALID_PARAMETER);
384 private_client = (tdm_private_client*)client;
386 *fd = wl_display_get_fd(private_client->display);
388 return TDM_ERROR_OPERATION_FAILED;
390 return TDM_ERROR_NONE;
394 tdm_client_handle_events(tdm_client *client)
396 tdm_private_client *private_client;
398 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
400 private_client = (tdm_private_client*)client;
402 wl_display_dispatch(private_client->display);
404 return TDM_ERROR_NONE;
407 typedef struct _tdm_client_vblank_temp {
408 tdm_client_vblank_handler2 func;
410 } tdm_client_vblank_temp;
413 _tdm_client_vblank_handler_temp(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
414 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
416 tdm_client_vblank_temp *vblank_temp = user_data;
418 TDM_RETURN_IF_FAIL(vblank_temp != NULL);
420 if (vblank_temp->func)
421 vblank_temp->func(sequence, tv_sec, tv_usec, vblank_temp->user_data);
427 tdm_client_wait_vblank(tdm_client *client, char *name,
428 int sw_timer, int interval, int sync,
429 tdm_client_vblank_handler2 func, void *user_data)
431 tdm_private_client *private_client = (tdm_private_client*)client;
432 tdm_client_output *output;
433 tdm_client_vblank_temp *vblank_temp;
436 TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
437 TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
438 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
440 if (!private_client->temp_vblank) {
441 output = tdm_client_get_output(client, name, &ret);
442 TDM_RETURN_VAL_IF_FAIL(output != NULL, ret);
444 private_client->temp_vblank = tdm_client_output_create_vblank(output, &ret);
445 TDM_RETURN_VAL_IF_FAIL(private_client->temp_vblank != NULL, ret);
448 tdm_client_vblank_set_enable_fake(private_client->temp_vblank, sw_timer);
449 tdm_client_vblank_set_sync(private_client->temp_vblank, sync);
451 vblank_temp = calloc(1, sizeof *vblank_temp);
452 TDM_RETURN_VAL_IF_FAIL(vblank_temp != NULL, TDM_ERROR_OUT_OF_MEMORY);
454 vblank_temp->func = func;
455 vblank_temp->user_data = user_data;
457 return tdm_client_vblank_wait(private_client->temp_vblank, interval, _tdm_client_vblank_handler_temp, vblank_temp);
461 tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
463 tdm_private_client *private_client;
464 tdm_private_client_output *private_output = NULL;
467 *error = TDM_ERROR_NONE;
470 TDM_ERR("'!client' failed");
472 *error = TDM_ERROR_INVALID_PARAMETER;
476 private_client = (tdm_private_client*)client;
481 LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
482 if (!strncmp(private_output->name, name, TDM_NAME_LEN))
483 return (tdm_client_output*)private_output;
486 private_output = calloc(1, sizeof *private_output);
487 if (!private_output) {
488 TDM_ERR("alloc failed");
490 *error = TDM_ERROR_OUT_OF_MEMORY;
494 private_output->private_client = private_client;
496 snprintf(private_output->name, TDM_NAME_LEN, "%s", name);
497 private_output->output = wl_tdm_create_output(private_client->tdm, private_output->name);
498 if (!private_output->output) {
499 TDM_ERR("couldn't create output resource");
500 free(private_output);
502 *error = TDM_ERROR_OUT_OF_MEMORY;
506 LIST_INITHEAD(&private_output->vblank_list);
507 LIST_INITHEAD(&private_output->change_handler_list);
508 LIST_ADDTAIL(&private_output->link, &private_client->output_list);
510 wl_tdm_output_add_listener(private_output->output,
511 &tdm_client_output_listener, private_output);
512 wl_display_roundtrip(private_client->display);
514 return (tdm_client_output*)private_output;
518 tdm_client_output_add_change_handler(tdm_client_output *output,
519 tdm_client_output_change_handler func,
522 tdm_private_client_output *private_output;
523 tdm_client_output_handler_info *h;
525 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
526 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
528 private_output = (tdm_private_client_output*)output;
530 h = calloc(1, sizeof *h);
531 TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
533 if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
534 wl_tdm_output_watch_output_changes(private_output->output, 1);
536 /* TODO: this is very tricky.
537 * If a client adds the change_handler, we might be able to guess that
538 * the client will watch the tdm client's fd and handle tdm events in
539 * event loop. Otherwise, we CAN'T make sure if a client has event loop
540 * which handles tdm events.
542 private_output->watch_output_changes = 1;
545 h->private_output = private_output;
547 h->user_data = user_data;
548 LIST_ADDTAIL(&h->link, &private_output->change_handler_list);
550 return TDM_ERROR_NOT_IMPLEMENTED;
554 tdm_client_output_remove_change_handler(tdm_client_output *output,
555 tdm_client_output_change_handler func,
558 tdm_private_client_output *private_output;
559 tdm_client_output_handler_info *h = NULL;
561 TDM_RETURN_IF_FAIL(output != NULL);
562 TDM_RETURN_IF_FAIL(func != NULL);
564 private_output = (tdm_private_client_output*)output;
566 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
567 if (h->func != func || h->user_data != user_data)
573 if (LIST_IS_EMPTY(&private_output->change_handler_list))
574 wl_tdm_output_watch_output_changes(private_output->output, 0);
581 tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refresh)
583 tdm_private_client_output *private_output;
584 tdm_private_client *private_client;
586 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
587 TDM_RETURN_VAL_IF_FAIL(refresh != NULL, TDM_ERROR_INVALID_PARAMETER);
589 private_output = (tdm_private_client_output*)output;
591 if (private_output->watch_output_changes) {
592 *refresh = private_output->refresh;
593 return TDM_ERROR_NONE;
596 private_client = private_output->private_client;
597 TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
599 wl_tdm_output_get_mode(private_output->output);
600 wl_display_roundtrip(private_client->display);
602 *refresh = private_output->refresh;
604 return TDM_ERROR_NONE;
608 tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_status *status)
610 tdm_private_client_output *private_output;
611 tdm_private_client *private_client;
613 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
614 TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
616 private_output = (tdm_private_client_output*)output;
618 if (private_output->watch_output_changes) {
619 *status = private_output->connection;
620 return TDM_ERROR_NONE;
623 private_client = private_output->private_client;
624 TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
626 wl_tdm_output_get_connection(private_output->output);
627 wl_display_roundtrip(private_client->display);
629 *status = private_output->connection;
631 return TDM_ERROR_NONE;
635 tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
637 tdm_private_client_output *private_output;
638 tdm_private_client *private_client;
640 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
641 TDM_RETURN_VAL_IF_FAIL(dpms != NULL, TDM_ERROR_INVALID_PARAMETER);
643 private_output = (tdm_private_client_output*)output;
645 if (private_output->watch_output_changes) {
646 *dpms = private_output->dpms;
647 return TDM_ERROR_NONE;
650 private_client = private_output->private_client;
651 TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
653 wl_tdm_output_get_dpms(private_output->output);
654 wl_display_roundtrip(private_client->display);
656 *dpms = private_output->dpms;
658 return TDM_ERROR_NONE;
662 tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
664 tdm_private_client *private_client;
665 tdm_private_client_output *private_output;
666 tdm_private_client_vblank *private_vblank;
669 *error = TDM_ERROR_NONE;
672 TDM_ERR("'!output' failed");
674 *error = TDM_ERROR_INVALID_PARAMETER;
678 private_output = (tdm_private_client_output*)output;
679 private_client = private_output->private_client;
681 if (!private_client) {
682 TDM_ERR("'!private_client' failed");
684 *error = TDM_ERROR_INVALID_PARAMETER;
688 private_vblank = calloc(1, sizeof *private_vblank);
689 if (!private_vblank) {
690 TDM_ERR("alloc failed");
692 *error = TDM_ERROR_OUT_OF_MEMORY;
696 private_vblank->private_output = private_output;
698 private_vblank->vblank = wl_tdm_output_create_vblank(private_output->output);
699 if (!private_vblank->vblank) {
700 TDM_ERR("couldn't create vblank resource");
701 free(private_vblank);
703 *error = TDM_ERROR_OUT_OF_MEMORY;
708 private_vblank->fps = private_output->refresh;
709 private_vblank->offset = 0;
710 private_vblank->enable_fake = 0;
712 LIST_INITHEAD(&private_vblank->wait_list);
713 LIST_ADDTAIL(&private_vblank->link, &private_output->vblank_list);
715 wl_tdm_vblank_add_listener(private_vblank->vblank,
716 &tdm_client_vblank_listener, private_vblank);
717 wl_display_roundtrip(private_client->display);
719 return (tdm_client_vblank*)private_vblank;
723 tdm_client_vblank_destroy(tdm_client_vblank *vblank)
725 tdm_private_client_vblank *private_vblank;
726 tdm_client_wait_info *w = NULL, *ww = NULL;
728 TDM_RETURN_IF_FAIL(vblank != NULL);
730 private_vblank = vblank;
731 LIST_DEL(&private_vblank->link);
733 LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
738 wl_tdm_vblank_destroy(private_vblank->vblank);
740 free(private_vblank);
744 tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name)
746 tdm_private_client_vblank *private_vblank;
748 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
750 private_vblank = vblank;
753 name = TDM_VBLANK_DEFAULT_NAME;
755 strncpy(private_vblank->name, name, TDM_NAME_LEN - 1);
756 private_vblank->name[TDM_NAME_LEN - 1] = '\0';
758 wl_tdm_vblank_set_name(private_vblank->vblank, private_vblank->name);
760 return TDM_ERROR_NONE;
764 tdm_client_vblank_set_sync(tdm_client_vblank *vblank, unsigned int sync)
766 tdm_private_client_vblank *private_vblank;
768 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
770 private_vblank = vblank;
771 private_vblank->sync = sync;
773 return TDM_ERROR_NONE;
777 tdm_client_vblank_set_fps(tdm_client_vblank *vblank, unsigned int fps)
779 tdm_private_client_vblank *private_vblank;
781 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
782 TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER);
784 private_vblank = vblank;
786 if (private_vblank->fps == fps)
787 return TDM_ERROR_NONE;
788 private_vblank->fps = fps;
790 wl_tdm_vblank_set_fps(private_vblank->vblank, fps);
792 return TDM_ERROR_NONE;
796 tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms)
798 tdm_private_client_vblank *private_vblank;
800 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
802 private_vblank = vblank;
803 TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
805 if (private_vblank->offset == offset_ms)
806 return TDM_ERROR_NONE;
807 private_vblank->offset = offset_ms;
809 wl_tdm_vblank_set_offset(private_vblank->vblank, offset_ms);
811 return TDM_ERROR_NONE;
815 tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable_fake)
817 tdm_private_client_vblank *private_vblank;
819 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
821 private_vblank = vblank;
823 if (private_vblank->enable_fake == enable_fake)
824 return TDM_ERROR_NONE;
825 private_vblank->enable_fake = enable_fake;
827 wl_tdm_vblank_set_enable_fake(private_vblank->vblank, enable_fake);
829 return TDM_ERROR_NONE;
833 tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_client_vblank_handler func, void *user_data)
835 tdm_private_client *private_client;
836 tdm_private_client_output *private_output;
837 tdm_private_client_vblank *private_vblank;
838 tdm_client_wait_info *w;
840 unsigned int req_sec, req_usec;
843 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
844 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
845 /* can't support "interval 0" and "getting current_msc" things because
846 * there is a socket communication between TDM client and server. It's impossible
847 * to return the current msc or sequence immediately.
849 TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
851 private_vblank = vblank;
852 private_output = private_vblank->private_output;
853 private_client = private_output->private_client;
855 if (!private_vblank->started)
856 private_vblank->started = 1;
858 if (private_output->watch_output_changes && !private_vblank->enable_fake) {
859 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
860 TDM_ERR("output disconnected");
861 return TDM_ERROR_OUTPUT_DISCONNECTED;
863 if (private_output->dpms != TDM_OUTPUT_DPMS_ON) {
865 return TDM_ERROR_DPMS_OFF;
869 w = calloc(1, sizeof *w);
871 TDM_ERR("alloc failed");
872 return TDM_ERROR_OUT_OF_MEMORY;
875 w->private_vblank = private_vblank;
877 w->user_data = user_data;
879 LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
881 clock_gettime(CLOCK_MONOTONIC, &tp);
882 req_sec = (unsigned int)tp.tv_sec;
883 req_usec = (unsigned int)(tp.tv_nsec / 1000);
885 w->req_id = ++private_output->req_id;
886 w->req_time = TDM_TIME(req_sec, req_usec);
887 w->need_free = (private_vblank->sync) ? 0 : 1;
889 wl_tdm_vblank_wait_vblank(private_vblank->vblank, interval, w->req_id, req_sec, req_usec);
891 TDM_TRACE_COUNT(ClientWaitVBlank, w->req_id);
893 TDM_DBG("vblank(%p) interval(%u) req_id(%d) req(%.6f)",
894 vblank, interval, w->req_id, TDM_TIME(req_sec, req_usec));
896 if (private_vblank->last_time >= w->req_time)
897 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
899 if (!private_vblank->sync) {
900 wl_display_flush(private_client->display);
901 return TDM_ERROR_NONE;
904 while (ret != -1 && !w->need_free)
905 ret = wl_display_dispatch(private_client->display);
907 clock_gettime(CLOCK_MONOTONIC, &tp);
908 TDM_DBG("block during %d us",
909 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
910 - (req_sec * 1000000 + req_usec));
915 return TDM_ERROR_NONE;
919 tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
920 tdm_client_vblank_handler func, void *user_data)
922 tdm_private_client *private_client;
923 tdm_private_client_output *private_output;
924 tdm_private_client_vblank *private_vblank;
925 tdm_client_wait_info *w;
927 unsigned int req_sec, req_usec;
930 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
931 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
933 private_vblank = vblank;
934 private_output = private_vblank->private_output;
935 private_client = private_output->private_client;
937 if (!private_vblank->started)
938 private_vblank->started = 1;
940 if (private_output->watch_output_changes && !private_vblank->enable_fake) {
941 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
942 TDM_ERR("output disconnected");
943 return TDM_ERROR_OUTPUT_DISCONNECTED;
945 if (private_output->dpms != TDM_OUTPUT_DPMS_ON) {
947 return TDM_ERROR_DPMS_OFF;
951 w = calloc(1, sizeof *w);
953 TDM_ERR("alloc failed");
954 return TDM_ERROR_OUT_OF_MEMORY;
957 w->private_vblank = private_vblank;
959 w->user_data = user_data;
961 LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
963 clock_gettime(CLOCK_MONOTONIC, &tp);
964 req_sec = (unsigned int)tp.tv_sec;
965 req_usec = (unsigned int)(tp.tv_nsec / 1000);
967 w->req_id = ++private_output->req_id;
968 w->req_time = TDM_TIME(req_sec, req_usec);
969 w->need_free = (private_vblank->sync) ? 0 : 1;
971 wl_tdm_vblank_wait_vblank_seq(private_vblank->vblank, sequence, w->req_id, req_sec, req_usec);
973 TDM_TRACE_COUNT(ClientWaitVBlank, w->req_id);
975 TDM_DBG("vblank(%p) sequence(%u) req_id(%d) req(%.6f)",
976 vblank, sequence, w->req_id, TDM_TIME(req_sec, req_usec));
978 if (private_vblank->last_time >= w->req_time)
979 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
981 if (!private_vblank->sync) {
982 wl_display_flush(private_client->display);
983 return TDM_ERROR_NONE;
986 while (ret != -1 && !w->need_free)
987 ret = wl_display_dispatch(private_client->display);
989 clock_gettime(CLOCK_MONOTONIC, &tp);
990 TDM_DBG("block during %d us",
991 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
992 - (req_sec * 1000000 + req_usec));
997 return TDM_ERROR_NONE;