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 <boram1288.park@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 **************************************************************************/
47 #include <tdm-client-protocol.h>
49 #include "tdm_client.h"
51 #include "tdm_macro.h"
54 #include "tdm_private.h"
56 typedef struct _tdm_private_client_vblank tdm_private_client_vblank;
58 typedef struct _tdm_private_client {
61 struct wl_display *display;
62 struct wl_event_queue *queue;
63 struct wl_registry *registry;
65 struct list_head output_list;
67 unsigned int enable_ttrace;
70 tdm_private_client_vblank *temp_vblank;
73 typedef struct _tdm_private_client_output {
74 tdm_private_client *private_client;
76 char name[TDM_NAME_LEN];
77 struct wl_tdm_output *output;
81 tdm_output_conn_status connection;
83 struct list_head vblank_list;
84 struct list_head change_handler_list;
87 unsigned int watch_output_changes;
89 struct list_head link;
90 } tdm_private_client_output;
92 typedef struct _tdm_private_client_voutput {
93 tdm_private_client_output base;
94 struct wl_tdm_voutput *wl_voutput;
99 tdm_client_output_mode *modes;
102 unsigned int mmwidth;
103 unsigned int mmheight;
106 } tdm_private_client_voutput;
108 struct _tdm_private_client_vblank {
109 tdm_private_client_output *private_output;
111 struct wl_tdm_vblank *vblank;
112 struct list_head wait_list;
114 char name[TDM_NAME_LEN];
118 unsigned int enable_fake;
119 unsigned int enable_ttrace;
121 unsigned int started;
127 struct list_head link;
130 typedef struct _tdm_client_output_handler_info {
131 tdm_private_client_output *private_output;
133 tdm_client_output_change_handler func;
136 struct list_head link;
137 struct list_head call_link;
138 } tdm_client_output_handler_info;
140 typedef struct _tdm_client_wait_info {
141 tdm_private_client_vblank *private_vblank;
143 tdm_client_vblank_handler func;
150 struct list_head link;
151 struct list_head call_link;
152 } tdm_client_wait_info;
155 _tdm_client_check_wl_error(tdm_private_client *private_client, const char *func, int line)
158 const struct wl_interface *intf;
161 err = wl_display_get_error(private_client->display);
165 if (err == EINVAL || err == ENOMEM || err == EFAULT || err == EPROTO) {
166 ec = wl_display_get_protocol_error(private_client->display, &intf, &id);
167 TDM_ERR("[%s,%d] errno(%d) Got protocol error '%u' on interface '%s' (object '%u')",
168 func, line, err, ec, (intf) ? intf->name : "destroyed", id);
170 TDM_ERR("[%s,%d] errno(%d)", func, line, err);
176 #define CHECK_WL_PROTOCOL_ERROR(pc) _tdm_client_check_wl_error(pc, __FUNCTION__, __LINE__)
179 _tdm_client_vblank_cb_stamp(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t stamp)
181 tdm_private_client_vblank *private_vblank = data;
182 tdm_private_client *private_client;
184 TDM_RETURN_IF_FAIL(private_vblank != NULL);
186 private_vblank->stamp = stamp;
188 TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
189 private_client = private_vblank->private_output->private_client;
191 private_client->stamp = stamp;
194 /* LCOV_EXCL_START */
196 _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank,
197 uint32_t req_id, uint32_t sequence, uint32_t tv_sec,
198 uint32_t tv_usec, uint32_t error)
200 tdm_private_client_vblank *private_vblank = data;
201 tdm_private_client *private_client;
202 tdm_client_wait_info *w = NULL, *wait_info = NULL;
204 TDM_RETURN_IF_FAIL(private_vblank != NULL);
206 private_client = private_vblank->private_output->private_client;
208 private_vblank->last_time = TDM_TIME(tv_sec, tv_usec);
210 TDM_DBG("vblank(%p) req_id(%u) sequence(%u) time(%.6f)",
211 private_vblank, req_id, sequence, TDM_TIME(tv_sec, tv_usec));
213 LIST_FOR_EACH_ENTRY(w, &private_vblank->wait_list, link) {
214 if (w->req_id != req_id)
222 TDM_ERR("no wait infomation for req_id(%d)", req_id);
226 if (private_vblank->enable_ttrace)
227 TDM_TRACE_ASYNC_END((int)wait_info->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
229 if (wait_info->req_time >= private_vblank->last_time)
230 TDM_WRN("'req(%.6f) < last(%.6f)' failed. error(%d)", wait_info->req_time, private_vblank->last_time, error);
232 if (wait_info->need_free)
233 LIST_DEL(&wait_info->link);
235 if (wait_info->func) {
236 pthread_mutex_unlock(&private_client->lock);
237 wait_info->func(private_vblank, error, sequence, tv_sec, tv_usec, wait_info->user_data);
238 pthread_mutex_lock(&private_client->lock);
241 if (wait_info->need_free)
244 wait_info->need_free = 1;
248 /* LCOV_EXCL_START */
250 _tdm_client_vblank_cb_ttrace(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t enable)
252 tdm_private_client_vblank *private_vblank = data;
253 tdm_private_client *private_client;
255 TDM_RETURN_IF_FAIL(private_vblank != NULL);
257 private_vblank->enable_ttrace = enable;
259 TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
260 private_client = private_vblank->private_output->private_client;
262 private_client->enable_ttrace = enable;
266 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
267 _tdm_client_vblank_cb_stamp,
268 _tdm_client_vblank_cb_done,
269 _tdm_client_vblank_cb_ttrace,
273 _tdm_client_output_destroy(tdm_private_client_output *private_output)
275 tdm_private_client_vblank *v = NULL, *vv = NULL;
276 tdm_client_output_handler_info *h = NULL, *hh = NULL;
278 LIST_DEL(&private_output->link);
280 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_list, link) {
281 TDM_ERR("vblanks SHOULD be destroyed first!");
283 v->private_output = NULL;
286 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list, link) {
291 wl_tdm_output_destroy(private_output->output);
293 free(private_output);
297 _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output,
298 uint32_t width, uint32_t height, uint32_t refresh, uint32_t error)
300 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
302 TDM_RETURN_IF_FAIL(private_output != NULL);
304 private_output->width = width;
305 private_output->height = height;
306 private_output->refresh = refresh;
308 if (error != TDM_ERROR_NONE)
309 TDM_INFO("mode event error: %d", error);
311 TDM_DBG("private_output(%p) wl_tbm_output@%d width(%d) height(%d) refresh(%d)",
312 private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output),
313 width, height, refresh);
317 _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
319 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
320 tdm_private_client *private_client;
321 tdm_client_output_handler_info *h = NULL, *hh = NULL;
323 struct list_head call_list;
325 TDM_RETURN_IF_FAIL(private_output != NULL);
327 private_client = private_output->private_client;
329 if (private_output->connection == value)
332 private_output->connection = value;
334 if (error != TDM_ERROR_NONE)
335 TDM_INFO("connection event error: %d", error);
337 TDM_DBG("private_output(%p) wl_tbm_output@%d connection(%d)",
339 wl_proxy_get_id((struct wl_proxy*)private_output->output),
342 LIST_INITHEAD(&call_list);
344 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
345 LIST_ADDTAIL(&h->call_link, &call_list);
349 pthread_mutex_unlock(&private_client->lock);
350 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
352 h->func(private_output, TDM_OUTPUT_CHANGE_CONNECTION, v, h->user_data);
354 pthread_mutex_lock(&private_client->lock);
358 _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
360 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
361 tdm_private_client *private_client;
362 tdm_client_output_handler_info *h = NULL, *hh = NULL;
364 struct list_head call_list;
366 TDM_RETURN_IF_FAIL(private_output != NULL);
368 private_client = private_output->private_client;
370 /* If value is extended value, we handle it as DPMS on in client side
371 * The extended DPMS value is valid only in server side.
372 * Or, need to export to client side also?
374 if (value > TDM_OUTPUT_DPMS_OFF)
375 value = TDM_OUTPUT_DPMS_ON;
377 if (private_output->dpms == value)
380 private_output->dpms = value;
382 if (error != TDM_ERROR_NONE)
383 TDM_INFO("dpms event error: %d", error);
385 TDM_DBG("private_output(%p) wl_tbm_output@%d dpms(%d)",
387 wl_proxy_get_id((struct wl_proxy*)private_output->output),
390 LIST_INITHEAD(&call_list);
392 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
393 LIST_ADDTAIL(&h->call_link, &call_list);
397 pthread_mutex_unlock(&private_client->lock);
398 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
400 h->func(private_output, TDM_OUTPUT_CHANGE_DPMS, v, h->user_data);
402 pthread_mutex_lock(&private_client->lock);
405 static const struct wl_tdm_output_listener tdm_client_output_listener = {
406 _tdm_client_output_cb_mode,
407 _tdm_client_output_cb_connection,
408 _tdm_client_output_cb_dpms,
412 _tdm_client_cb_global(void *data, struct wl_registry *registry,
413 uint32_t name, const char *interface,
416 tdm_private_client *private_client = data;
418 if (strncmp(interface, "wl_tdm", 6) == 0) {
419 private_client->tdm =
420 wl_registry_bind(registry, name, &wl_tdm_interface, version);
421 TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
423 wl_display_flush(private_client->display);
427 /* LCOV_EXCL_START */
429 _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
434 static const struct wl_registry_listener tdm_client_registry_listener = {
435 _tdm_client_cb_global,
436 _tdm_client_cb_global_remove
440 tdm_client_create(tdm_error *error)
442 tdm_private_client *private_client;
444 private_client = calloc(1, sizeof *private_client);
445 if (!private_client) {
446 /* LCOV_EXCL_START */
448 TDM_ERR("alloc failed");
450 *error = TDM_ERROR_OUT_OF_MEMORY;
456 if (pthread_mutex_init(&private_client->lock, NULL)) {
457 TDM_ERR("mutex init failed: %m");
458 free(private_client);
460 *error = TDM_ERROR_OUT_OF_MEMORY;
464 LIST_INITHEAD(&private_client->output_list);
466 private_client->display = wl_display_connect("tdm-socket");
467 TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed);
469 private_client->queue = wl_display_create_queue(private_client->display);
470 TDM_GOTO_IF_FAIL(private_client->queue != NULL, create_failed);
472 private_client->registry = wl_display_get_registry(private_client->display);
473 TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed);
475 wl_registry_add_listener(private_client->registry,
476 &tdm_client_registry_listener, private_client);
477 wl_display_roundtrip(private_client->display);
479 if (CHECK_WL_PROTOCOL_ERROR(private_client))
482 /* check global objects */
483 TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed);
486 *error = TDM_ERROR_NONE;
488 return (tdm_client*)private_client;
490 tdm_client_destroy((tdm_client*)private_client);
492 *error = TDM_ERROR_OPERATION_FAILED;
497 tdm_client_destroy(tdm_client *client)
499 tdm_private_client *private_client = (tdm_private_client*)client;
500 tdm_private_client_output *o = NULL, *oo = NULL;
505 pthread_mutex_lock(&private_client->lock);
507 if (private_client->temp_vblank) {
508 pthread_mutex_unlock(&private_client->lock);
509 tdm_client_vblank_destroy(private_client->temp_vblank);
510 pthread_mutex_lock(&private_client->lock);
513 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_client->output_list, link) {
514 _tdm_client_output_destroy(o);
517 if (private_client->tdm)
518 wl_tdm_destroy(private_client->tdm);
519 if (private_client->registry)
520 wl_registry_destroy(private_client->registry);
521 if (private_client->queue)
522 wl_event_queue_destroy(private_client->queue);
523 if (private_client->display)
524 wl_display_disconnect(private_client->display);
526 pthread_mutex_unlock(&private_client->lock);
527 pthread_mutex_destroy(&private_client->lock);
529 free(private_client);
533 tdm_client_get_fd(tdm_client *client, int *fd)
535 tdm_private_client *private_client;
537 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
538 TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_ERROR_INVALID_PARAMETER);
540 private_client = (tdm_private_client*)client;
542 pthread_mutex_lock(&private_client->lock);
544 *fd = wl_display_get_fd(private_client->display);
546 pthread_mutex_unlock(&private_client->lock);
549 return TDM_ERROR_OPERATION_FAILED;
551 return TDM_ERROR_NONE;
555 tdm_client_handle_events(tdm_client *client)
557 tdm_private_client *private_client;
559 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
561 /* LCOV_EXCL_START */
562 private_client = (tdm_private_client*)client;
564 pthread_mutex_lock(&private_client->lock);
566 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
567 pthread_mutex_unlock(&private_client->lock);
568 return TDM_ERROR_PROTOCOL_ERROR;
571 if (private_client->enable_ttrace)
572 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
574 wl_display_dispatch(private_client->display);
576 if (private_client->enable_ttrace)
577 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
579 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
580 pthread_mutex_unlock(&private_client->lock);
581 return TDM_ERROR_PROTOCOL_ERROR;
584 pthread_mutex_unlock(&private_client->lock);
586 return TDM_ERROR_NONE;
591 _tdm_client_poll(struct wl_display *display, short int events, int timeout)
594 struct pollfd pfd[1];
596 pfd[0].fd = wl_display_get_fd(display);
597 pfd[0].events = events;
599 ret = poll(pfd, 1, timeout);
600 } while (ret == -1 && errno == EINTR);
606 _tdm_client_dispatch_timeout(tdm_private_client *private_client, int timeout)
609 struct wl_display *display = private_client->display;
611 if (wl_display_prepare_read(display) == -1) {
612 if (wl_display_dispatch_pending(display) > 0)
613 return TDM_ERROR_NONE;
615 return TDM_ERROR_OPERATION_FAILED;
619 ret = wl_display_flush(display);
621 if (ret != -1 || errno != EAGAIN)
624 if (_tdm_client_poll(display, POLLOUT, -1) == -1) {
625 wl_display_cancel_read(display);
626 TDM_ERR("_tdm_client_poll failed");
627 return TDM_ERROR_OPERATION_FAILED;
631 /* Don't stop if flushing hits an EPIPE; continue so we can read any
632 * protocol error that may have triggered it. */
633 if (ret < 0 && errno != EPIPE) {
634 TDM_ERR("ret(%d) errno(%d)", ret, errno);
635 wl_display_cancel_read(display);
636 return TDM_ERROR_OPERATION_FAILED;
639 ret = _tdm_client_poll(display, POLLIN, timeout);
641 wl_display_cancel_read(display);
643 TDM_ERR("_tdm_client_poll timeout.");
644 return TDM_ERROR_TIMEOUT;
646 TDM_ERR("_tdm_client_poll failed. (ret:%d)", ret);
647 return TDM_ERROR_OPERATION_FAILED;
651 if (wl_display_read_events(display) == -1) {
652 TDM_ERR("wl_display_read_events failed");
653 return TDM_ERROR_OPERATION_FAILED;
656 ret = wl_display_dispatch_pending(display);
659 TDM_ERR("_tdm_client_dispatch_timeout failed");
660 return TDM_ERROR_OPERATION_FAILED;
663 return TDM_ERROR_NONE;
667 tdm_client_handle_events_timeout(tdm_client *client, int ms_timeout)
669 tdm_private_client *private_client;
671 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
673 private_client = (tdm_private_client*)client;
675 pthread_mutex_lock(&private_client->lock);
677 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
678 pthread_mutex_unlock(&private_client->lock);
679 return TDM_ERROR_PROTOCOL_ERROR;
682 if (private_client->enable_ttrace)
683 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
685 ret = _tdm_client_dispatch_timeout(private_client, ms_timeout);
687 if (private_client->enable_ttrace)
688 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
690 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
691 pthread_mutex_unlock(&private_client->lock);
692 return TDM_ERROR_PROTOCOL_ERROR;
695 pthread_mutex_unlock(&private_client->lock);
700 typedef struct _tdm_client_vblank_temp {
701 tdm_client_vblank_handler2 func;
703 } tdm_client_vblank_temp;
705 /* LCOV_EXCL_START */
707 _tdm_client_vblank_handler_temp(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
708 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
710 tdm_client_vblank_temp *vblank_temp = user_data;
712 TDM_RETURN_IF_FAIL(vblank_temp != NULL);
713 TDM_RETURN_IF_FAIL(vblank != NULL);
715 if (vblank_temp->func)
716 vblank_temp->func(sequence, tv_sec, tv_usec, vblank_temp->user_data);
722 /* LCOV_EXCL_START */ /* deprecated */
724 tdm_client_wait_vblank(tdm_client *client, char *name,
725 int sw_timer, int interval, int sync,
726 tdm_client_vblank_handler2 func, void *user_data)
728 tdm_private_client *private_client = (tdm_private_client*)client;
729 tdm_client_output *output;
730 tdm_client_vblank_temp *vblank_temp;
733 TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
734 TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
735 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
737 if (CHECK_WL_PROTOCOL_ERROR(private_client))
738 return TDM_ERROR_PROTOCOL_ERROR;
740 if (!private_client->temp_vblank) {
741 output = tdm_client_get_output(client, name, &ret);
742 TDM_RETURN_VAL_IF_FAIL(output != NULL, ret);
744 private_client->temp_vblank = tdm_client_output_create_vblank(output, &ret);
745 TDM_RETURN_VAL_IF_FAIL(private_client->temp_vblank != NULL, ret);
748 tdm_client_vblank_set_enable_fake(private_client->temp_vblank, sw_timer);
749 tdm_client_vblank_set_sync(private_client->temp_vblank, sync);
751 vblank_temp = calloc(1, sizeof *vblank_temp);
752 TDM_RETURN_VAL_IF_FAIL(vblank_temp != NULL, TDM_ERROR_OUT_OF_MEMORY);
754 vblank_temp->func = func;
755 vblank_temp->user_data = user_data;
757 return tdm_client_vblank_wait(private_client->temp_vblank, interval, _tdm_client_vblank_handler_temp, vblank_temp);
762 tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
764 tdm_private_client *private_client;
765 tdm_private_client_output *private_output = NULL;
766 struct wl_proxy *wrapper;
769 *error = TDM_ERROR_NONE;
772 TDM_ERR("'!client' failed");
774 *error = TDM_ERROR_INVALID_PARAMETER;
778 private_client = (tdm_private_client*)client;
780 pthread_mutex_lock(&private_client->lock);
782 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
784 *error = TDM_ERROR_PROTOCOL_ERROR;
785 pthread_mutex_unlock(&private_client->lock);
791 } else if (strncmp(name, "primary", 7) && strncmp(name, "default", 7)) {
793 *error = TDM_ERROR_INVALID_PARAMETER;
794 pthread_mutex_unlock(&private_client->lock);
798 LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
799 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
800 pthread_mutex_unlock(&private_client->lock);
801 return (tdm_client_output*)private_output;
805 wrapper = wl_proxy_create_wrapper(private_client->tdm);
807 TDM_ERR("create output_wrapper failed");
809 *error = TDM_ERROR_OUT_OF_MEMORY;
810 pthread_mutex_unlock(&private_client->lock);
814 wl_proxy_set_queue(wrapper, private_client->queue);
816 private_output = calloc(1, sizeof *private_output);
817 if (!private_output) {
818 /* LCOV_EXCL_START */
819 wl_proxy_wrapper_destroy(wrapper);
820 TDM_ERR("alloc failed");
822 *error = TDM_ERROR_OUT_OF_MEMORY;
823 pthread_mutex_unlock(&private_client->lock);
829 private_output->private_client = private_client;
831 snprintf(private_output->name, TDM_NAME_LEN, "%s", name);
832 private_output->output = wl_tdm_create_output((struct wl_tdm *)wrapper, private_output->name);
833 wl_proxy_wrapper_destroy(wrapper);
834 if (!private_output->output) {
835 /* LCOV_EXCL_START */
837 TDM_ERR("couldn't create output resource");
838 free(private_output);
840 *error = TDM_ERROR_OUT_OF_MEMORY;
841 pthread_mutex_unlock(&private_client->lock);
847 LIST_INITHEAD(&private_output->vblank_list);
848 LIST_INITHEAD(&private_output->change_handler_list);
850 wl_tdm_output_add_listener(private_output->output,
851 &tdm_client_output_listener, private_output);
852 wl_display_roundtrip_queue(private_client->display, private_client->queue);
854 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
856 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
857 wl_tdm_output_destroy(private_output->output);
858 free(private_output);
860 *error = TDM_ERROR_PROTOCOL_ERROR;
861 pthread_mutex_unlock(&private_client->lock);
865 LIST_ADDTAIL(&private_output->link, &private_client->output_list);
867 pthread_mutex_unlock(&private_client->lock);
869 return (tdm_client_output*)private_output;
873 tdm_client_output_add_change_handler(tdm_client_output *output,
874 tdm_client_output_change_handler func,
877 tdm_private_client_output *private_output;
878 tdm_private_client *private_client;
879 tdm_client_output_handler_info *h = NULL;
881 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
882 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
884 private_output = (tdm_private_client_output*)output;
885 private_client = private_output->private_client;
887 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
888 if (h->func == func && h->user_data == user_data) {
889 TDM_ERR("can't add twice");
890 return TDM_ERROR_BAD_REQUEST;
894 h = calloc(1, sizeof *h);
895 TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
897 pthread_mutex_lock(&private_client->lock);
899 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
901 pthread_mutex_unlock(&private_client->lock);
902 return TDM_ERROR_PROTOCOL_ERROR;
905 if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
906 wl_tdm_output_watch_output_changes(private_output->output, 1);
907 wl_display_roundtrip_queue(private_client->display, private_client->queue);
909 /* TODO: this is very tricky.
910 * If a client adds the change_handler, we might be able to guess that
911 * the client will watch the tdm client's fd and handle tdm events in
912 * event loop. Otherwise, we CAN'T make sure if a client has event loop
913 * which handles tdm events.
915 private_output->watch_output_changes = 1;
918 h->private_output = private_output;
920 h->user_data = user_data;
921 LIST_ADDTAIL(&h->link, &private_output->change_handler_list);
922 LIST_INITHEAD(&h->call_link);
924 pthread_mutex_unlock(&private_client->lock);
926 return TDM_ERROR_NONE;
930 tdm_client_output_remove_change_handler(tdm_client_output *output,
931 tdm_client_output_change_handler func,
934 tdm_private_client_output *private_output;
935 tdm_private_client *private_client;
936 tdm_client_output_handler_info *h = NULL;
938 TDM_RETURN_IF_FAIL(output != NULL);
939 TDM_RETURN_IF_FAIL(func != NULL);
941 private_output = (tdm_private_client_output*)output;
942 private_client = private_output->private_client;
944 pthread_mutex_lock(&private_client->lock);
946 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
947 if (h->func != func || h->user_data != user_data)
953 if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
954 private_output->watch_output_changes = 0;
955 if (!CHECK_WL_PROTOCOL_ERROR(private_client)) {
956 wl_tdm_output_watch_output_changes(private_output->output, 0);
957 wl_display_roundtrip_queue(private_client->display, private_client->queue);
961 pthread_mutex_unlock(&private_client->lock);
966 pthread_mutex_unlock(&private_client->lock);
970 tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refresh)
972 tdm_private_client_output *private_output;
973 tdm_private_client *private_client;
975 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
976 TDM_RETURN_VAL_IF_FAIL(refresh != NULL, TDM_ERROR_INVALID_PARAMETER);
978 private_output = (tdm_private_client_output*)output;
979 private_client = private_output->private_client;
981 pthread_mutex_lock(&private_client->lock);
983 if (private_output->watch_output_changes) {
984 *refresh = private_output->refresh;
985 pthread_mutex_unlock(&private_client->lock);
986 return TDM_ERROR_NONE;
989 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
990 pthread_mutex_unlock(&private_client->lock);
991 return TDM_ERROR_PROTOCOL_ERROR;
994 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
995 wl_tdm_output_get_mode(private_output->output);
996 wl_display_roundtrip_queue(private_client->display, private_client->queue);
997 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
999 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1000 pthread_mutex_unlock(&private_client->lock);
1001 return TDM_ERROR_PROTOCOL_ERROR;
1004 *refresh = private_output->refresh;
1006 pthread_mutex_unlock(&private_client->lock);
1008 return TDM_ERROR_NONE;
1012 tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_status *status)
1014 tdm_private_client_output *private_output;
1015 tdm_private_client *private_client;
1017 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1018 TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
1020 private_output = (tdm_private_client_output*)output;
1021 private_client = private_output->private_client;
1023 pthread_mutex_lock(&private_client->lock);
1025 if (private_output->watch_output_changes) {
1026 *status = private_output->connection;
1027 pthread_mutex_unlock(&private_client->lock);
1028 return TDM_ERROR_NONE;
1031 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1032 pthread_mutex_unlock(&private_client->lock);
1033 return TDM_ERROR_PROTOCOL_ERROR;
1036 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1037 wl_tdm_output_get_connection(private_output->output);
1038 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1039 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1041 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1042 pthread_mutex_unlock(&private_client->lock);
1043 return TDM_ERROR_PROTOCOL_ERROR;
1046 *status = private_output->connection;
1048 pthread_mutex_unlock(&private_client->lock);
1050 return TDM_ERROR_NONE;
1054 tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
1056 tdm_private_client_output *private_output;
1057 tdm_private_client *private_client;
1059 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1060 TDM_RETURN_VAL_IF_FAIL(dpms != NULL, TDM_ERROR_INVALID_PARAMETER);
1062 private_output = (tdm_private_client_output*)output;
1063 private_client = private_output->private_client;
1065 if (private_output->watch_output_changes) {
1066 *dpms = private_output->dpms;
1067 return TDM_ERROR_NONE;
1070 pthread_mutex_lock(&private_client->lock);
1072 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1073 pthread_mutex_unlock(&private_client->lock);
1074 return TDM_ERROR_PROTOCOL_ERROR;
1077 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1078 wl_tdm_output_get_dpms(private_output->output);
1079 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1080 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1082 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1083 pthread_mutex_unlock(&private_client->lock);
1084 return TDM_ERROR_PROTOCOL_ERROR;
1087 *dpms = private_output->dpms;
1089 pthread_mutex_unlock(&private_client->lock);
1091 return TDM_ERROR_NONE;
1095 tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
1097 tdm_private_client *private_client;
1098 tdm_private_client_output *private_output;
1099 tdm_private_client_vblank *private_vblank;
1100 struct wl_proxy *wrapper;
1103 *error = TDM_ERROR_NONE;
1106 TDM_ERR("'!output' failed");
1108 *error = TDM_ERROR_INVALID_PARAMETER;
1112 private_output = (tdm_private_client_output*)output;
1113 private_client = private_output->private_client;
1115 pthread_mutex_lock(&private_client->lock);
1117 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1119 *error = TDM_ERROR_PROTOCOL_ERROR;
1120 pthread_mutex_unlock(&private_client->lock);
1124 wrapper = wl_proxy_create_wrapper(private_output->output);
1126 TDM_ERR("create output_wrapper failed");
1128 *error = TDM_ERROR_OUT_OF_MEMORY;
1129 pthread_mutex_unlock(&private_client->lock);
1133 wl_proxy_set_queue(wrapper, private_client->queue);
1135 private_vblank = calloc(1, sizeof *private_vblank);
1136 if (!private_vblank) {
1137 /* LCOV_EXCL_START */
1139 TDM_ERR("alloc failed");
1140 wl_proxy_wrapper_destroy(wrapper);
1142 *error = TDM_ERROR_OUT_OF_MEMORY;
1143 pthread_mutex_unlock(&private_client->lock);
1146 /* LCOV_EXCL_STOP */
1149 private_vblank->private_output = private_output;
1151 private_vblank->vblank = wl_tdm_output_create_vblank((struct wl_tdm_output*)wrapper);
1152 wl_proxy_wrapper_destroy(wrapper);
1153 if (!private_vblank->vblank) {
1154 /* LCOV_EXCL_START */
1156 TDM_ERR("couldn't create vblank resource");
1157 free(private_vblank);
1159 *error = TDM_ERROR_OUT_OF_MEMORY;
1160 pthread_mutex_unlock(&private_client->lock);
1163 /* LCOV_EXCL_STOP */
1167 private_vblank->fps = private_output->refresh;
1168 private_vblank->offset = 0;
1169 private_vblank->enable_fake = 0;
1171 LIST_INITHEAD(&private_vblank->wait_list);
1173 wl_tdm_vblank_add_listener(private_vblank->vblank,
1174 &tdm_client_vblank_listener, private_vblank);
1175 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1177 wl_proxy_set_queue((struct wl_proxy *)private_vblank->vblank, NULL);
1179 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1180 wl_tdm_vblank_destroy(private_vblank->vblank);
1181 free(private_vblank);
1183 *error = TDM_ERROR_PROTOCOL_ERROR;
1184 pthread_mutex_unlock(&private_client->lock);
1188 LIST_ADDTAIL(&private_vblank->link, &private_output->vblank_list);
1190 pthread_mutex_unlock(&private_client->lock);
1192 return (tdm_client_vblank*)private_vblank;
1196 tdm_client_vblank_destroy(tdm_client_vblank *vblank)
1198 tdm_private_client_vblank *private_vblank;
1199 tdm_private_client *private_client;
1200 tdm_client_wait_info *w = NULL, *ww = NULL;
1202 TDM_RETURN_IF_FAIL(vblank != NULL);
1204 private_vblank = vblank;
1205 private_client = private_vblank->private_output->private_client;
1207 pthread_mutex_lock(&private_client->lock);
1209 LIST_DEL(&private_vblank->link);
1211 LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
1216 wl_tdm_vblank_destroy(private_vblank->vblank);
1218 free(private_vblank);
1220 pthread_mutex_unlock(&private_client->lock);
1224 tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name)
1226 tdm_private_client_vblank *private_vblank;
1227 tdm_private_client *private_client;
1229 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1231 private_vblank = vblank;
1232 private_client = private_vblank->private_output->private_client;
1234 pthread_mutex_lock(&private_client->lock);
1236 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1237 pthread_mutex_unlock(&private_client->lock);
1238 return TDM_ERROR_PROTOCOL_ERROR;
1242 name = TDM_VBLANK_DEFAULT_NAME;
1244 strncpy(private_vblank->name, name, TDM_NAME_LEN - 1);
1245 private_vblank->name[TDM_NAME_LEN - 1] = '\0';
1247 wl_tdm_vblank_set_name(private_vblank->vblank, private_vblank->name);
1249 pthread_mutex_unlock(&private_client->lock);
1251 return TDM_ERROR_NONE;
1255 tdm_client_vblank_set_sync(tdm_client_vblank *vblank, unsigned int sync)
1257 tdm_private_client_vblank *private_vblank;
1258 tdm_private_client *private_client;
1260 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1262 private_vblank = vblank;
1263 private_client = private_vblank->private_output->private_client;
1265 pthread_mutex_lock(&private_client->lock);
1266 private_vblank->sync = sync;
1267 pthread_mutex_unlock(&private_client->lock);
1269 return TDM_ERROR_NONE;
1273 tdm_client_vblank_set_fps(tdm_client_vblank *vblank, unsigned int fps)
1275 tdm_private_client_vblank *private_vblank;
1276 tdm_private_client *private_client;
1278 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1279 TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER);
1281 private_vblank = vblank;
1282 private_client = private_vblank->private_output->private_client;
1284 pthread_mutex_lock(&private_client->lock);
1286 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1287 pthread_mutex_unlock(&private_client->lock);
1288 return TDM_ERROR_PROTOCOL_ERROR;
1291 if (private_vblank->fps == fps) {
1292 pthread_mutex_unlock(&private_client->lock);
1293 return TDM_ERROR_NONE;
1296 private_vblank->fps = fps;
1298 wl_tdm_vblank_set_fps(private_vblank->vblank, fps);
1300 pthread_mutex_unlock(&private_client->lock);
1302 return TDM_ERROR_NONE;
1306 tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms)
1308 tdm_private_client_vblank *private_vblank;
1309 tdm_private_client *private_client;
1311 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1313 private_vblank = vblank;
1314 TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
1316 private_client = private_vblank->private_output->private_client;
1318 pthread_mutex_lock(&private_client->lock);
1320 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1321 pthread_mutex_unlock(&private_client->lock);
1322 return TDM_ERROR_PROTOCOL_ERROR;
1325 if (private_vblank->offset == offset_ms) {
1326 pthread_mutex_unlock(&private_client->lock);
1327 return TDM_ERROR_NONE;
1330 private_vblank->offset = offset_ms;
1332 wl_tdm_vblank_set_offset(private_vblank->vblank, offset_ms);
1334 pthread_mutex_unlock(&private_client->lock);
1336 return TDM_ERROR_NONE;
1340 tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable_fake)
1342 tdm_private_client_vblank *private_vblank;
1343 tdm_private_client *private_client;
1345 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1347 private_vblank = vblank;
1348 private_client = private_vblank->private_output->private_client;
1350 pthread_mutex_lock(&private_client->lock);
1352 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1353 pthread_mutex_unlock(&private_client->lock);
1354 return TDM_ERROR_PROTOCOL_ERROR;
1357 if (private_vblank->enable_fake == enable_fake) {
1358 pthread_mutex_unlock(&private_client->lock);
1359 return TDM_ERROR_NONE;
1362 private_vblank->enable_fake = enable_fake;
1364 wl_tdm_vblank_set_enable_fake(private_vblank->vblank, enable_fake);
1366 pthread_mutex_unlock(&private_client->lock);
1368 return TDM_ERROR_NONE;
1372 tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_client_vblank_handler func, void *user_data)
1374 tdm_private_client *private_client;
1375 tdm_private_client_output *private_output;
1376 tdm_private_client_vblank *private_vblank;
1377 tdm_client_wait_info *w;
1379 unsigned int req_sec, req_usec;
1382 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1383 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1384 /* can't support "interval 0" and "getting current_msc" things because
1385 * there is a socket communication between TDM client and server. It's impossible
1386 * to return the current msc or sequence immediately.
1388 TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
1390 private_vblank = vblank;
1391 private_output = private_vblank->private_output;
1392 private_client = private_output->private_client;
1394 pthread_mutex_lock(&private_client->lock);
1396 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1397 pthread_mutex_unlock(&private_client->lock);
1398 return TDM_ERROR_PROTOCOL_ERROR;
1401 if (!private_vblank->started)
1402 private_vblank->started = 1;
1404 if (!private_vblank->enable_fake) {
1405 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1406 TDM_ERR("output disconnected");
1407 pthread_mutex_unlock(&private_client->lock);
1408 return TDM_ERROR_OUTPUT_DISCONNECTED;
1410 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1411 TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1412 pthread_mutex_unlock(&private_client->lock);
1413 return TDM_ERROR_DPMS_OFF;
1417 w = calloc(1, sizeof *w);
1419 /* LCOV_EXCL_START */
1421 TDM_ERR("alloc failed");
1422 pthread_mutex_unlock(&private_client->lock);
1423 return TDM_ERROR_OUT_OF_MEMORY;
1425 /* LCOV_EXCL_STOP */
1428 w->private_vblank = private_vblank;
1430 w->user_data = user_data;
1432 LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1433 LIST_INITHEAD(&w->call_link);
1435 clock_gettime(CLOCK_MONOTONIC, &tp);
1436 req_sec = (unsigned int)tp.tv_sec;
1437 req_usec = (unsigned int)(tp.tv_nsec / 1000);
1439 w->req_id = ++private_output->req_id;
1440 w->req_time = TDM_TIME(req_sec, req_usec);
1441 w->need_free = (private_vblank->sync) ? 0 : 1;
1443 wl_tdm_vblank_wait_vblank(private_vblank->vblank, interval, w->req_id, req_sec, req_usec);
1445 if (private_vblank->enable_ttrace)
1446 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1448 TDM_DBG("vblank(%p) interval(%u) req_id(%d) req(%.6f)",
1449 vblank, interval, w->req_id, w->req_time);
1451 private_vblank->req_time = w->req_time;
1453 if (private_vblank->last_time >= w->req_time)
1454 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1456 if (!private_vblank->sync) {
1457 wl_display_flush(private_client->display);
1458 pthread_mutex_unlock(&private_client->lock);
1459 return TDM_ERROR_NONE;
1462 /* LCOV_EXCL_START */
1464 while (ret != -1 && !w->need_free)
1465 ret = wl_display_dispatch(private_client->display);
1467 clock_gettime(CLOCK_MONOTONIC, &tp);
1468 TDM_DBG("block during %d us",
1469 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1470 - (req_sec * 1000000 + req_usec));
1475 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1476 pthread_mutex_unlock(&private_client->lock);
1477 return TDM_ERROR_PROTOCOL_ERROR;
1480 pthread_mutex_unlock(&private_client->lock);
1482 return TDM_ERROR_NONE;
1484 /* LCOV_EXCL_STOP */
1488 tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
1489 tdm_client_vblank_handler func, void *user_data)
1491 tdm_private_client *private_client;
1492 tdm_private_client_output *private_output;
1493 tdm_private_client_vblank *private_vblank;
1494 tdm_client_wait_info *w;
1496 unsigned int req_sec, req_usec;
1499 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1500 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1502 private_vblank = vblank;
1503 private_output = private_vblank->private_output;
1504 private_client = private_output->private_client;
1506 pthread_mutex_lock(&private_client->lock);
1508 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1509 pthread_mutex_unlock(&private_client->lock);
1510 return TDM_ERROR_PROTOCOL_ERROR;
1513 if (!private_vblank->started)
1514 private_vblank->started = 1;
1516 if (!private_vblank->enable_fake) {
1517 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1518 TDM_ERR("output disconnected");
1519 pthread_mutex_unlock(&private_client->lock);
1520 return TDM_ERROR_OUTPUT_DISCONNECTED;
1522 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1523 TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1524 pthread_mutex_unlock(&private_client->lock);
1525 return TDM_ERROR_DPMS_OFF;
1529 w = calloc(1, sizeof *w);
1531 /* LCOV_EXCL_START */
1533 TDM_ERR("alloc failed");
1534 pthread_mutex_unlock(&private_client->lock);
1535 return TDM_ERROR_OUT_OF_MEMORY;
1537 /* LCOV_EXCL_STOP */
1540 w->private_vblank = private_vblank;
1542 w->user_data = user_data;
1544 LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1545 LIST_INITHEAD(&w->call_link);
1547 clock_gettime(CLOCK_MONOTONIC, &tp);
1548 req_sec = (unsigned int)tp.tv_sec;
1549 req_usec = (unsigned int)(tp.tv_nsec / 1000);
1551 w->req_id = ++private_output->req_id;
1552 w->req_time = TDM_TIME(req_sec, req_usec);
1553 w->need_free = (private_vblank->sync) ? 0 : 1;
1555 wl_tdm_vblank_wait_vblank_seq(private_vblank->vblank, sequence, w->req_id, req_sec, req_usec);
1557 if (private_vblank->enable_ttrace)
1558 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1560 TDM_DBG("vblank(%p) sequence(%u) req_id(%d) req(%.6f)",
1561 vblank, sequence, w->req_id, w->req_time);
1563 private_vblank->req_time = w->req_time;
1565 if (private_vblank->last_time >= w->req_time)
1566 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1568 if (!private_vblank->sync) {
1569 wl_display_flush(private_client->display);
1570 pthread_mutex_unlock(&private_client->lock);
1571 return TDM_ERROR_NONE;
1574 /* LCOV_EXCL_START */
1576 while (ret != -1 && !w->need_free)
1577 ret = wl_display_dispatch(private_client->display);
1579 clock_gettime(CLOCK_MONOTONIC, &tp);
1580 TDM_DBG("block during %d us",
1581 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1582 - (req_sec * 1000000 + req_usec));
1587 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1588 pthread_mutex_unlock(&private_client->lock);
1589 return TDM_ERROR_PROTOCOL_ERROR;
1592 pthread_mutex_unlock(&private_client->lock);
1594 return TDM_ERROR_NONE;
1596 /* LCOV_EXCL_STOP */
1600 tdm_client_vblank_is_waiting(tdm_client_vblank *vblank)
1602 tdm_private_client_vblank *private_vblank;
1604 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, 0);
1606 private_vblank = vblank;
1608 return (LIST_LENGTH(&private_vblank->wait_list) > 0) ? 1 : 0;
1612 tdm_client_voutput_cb_ack_message(void *data, struct wl_tdm_voutput *wl_voutput, uint32_t msg)
1614 tdm_private_client_voutput *private_voutput = data;
1616 private_voutput->msg = msg;
1619 static const struct wl_tdm_voutput_listener tdm_client_voutput_lisntener = {
1620 tdm_client_voutput_cb_ack_message
1623 tdm_client_voutput *
1624 tdm_client_create_voutput(tdm_client *client, const char *name, tdm_error *error)
1626 tdm_private_client *private_client;
1627 tdm_private_client_output *private_output;
1628 tdm_private_client_voutput *private_voutput;
1629 struct wl_proxy *wrapper;
1632 *error = TDM_ERROR_NONE;
1635 TDM_ERR("'!client' failed");
1637 *error = TDM_ERROR_INVALID_PARAMETER;
1642 TDM_ERR("'!name' failed");
1644 *error = TDM_ERROR_INVALID_PARAMETER;
1648 private_client = (tdm_private_client *)client;
1650 pthread_mutex_lock(&private_client->lock);
1652 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1654 *error = TDM_ERROR_PROTOCOL_ERROR;
1655 pthread_mutex_unlock(&private_client->lock);
1659 LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
1660 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
1662 *error = TDM_ERROR_INVALID_PARAMETER; // FIXME define new error type.
1663 pthread_mutex_unlock(&private_client->lock);
1668 wrapper = wl_proxy_create_wrapper(private_client->tdm);
1670 TDM_ERR("create virtual output wrapper failed");
1672 *error = TDM_ERROR_OUT_OF_MEMORY;
1673 pthread_mutex_unlock(&private_client->lock);
1677 wl_proxy_set_queue(wrapper, private_client->queue);
1679 private_voutput = calloc(1, sizeof *private_voutput);
1680 if (!private_voutput) {
1681 /* LOCV_EXCL_START */
1682 wl_proxy_wrapper_destroy(wrapper);
1683 TDM_ERR("alloc failed");
1685 *error = TDM_ERROR_OUT_OF_MEMORY;
1687 /* LOCV_EXCL_STOP */
1690 private_voutput->base.private_client = private_client;
1692 private_voutput->wl_voutput = wl_tdm_create_voutput((struct wl_tdm *)wrapper, private_voutput->base.name);
1693 wl_proxy_wrapper_destroy(wrapper);
1694 if (!private_voutput->wl_voutput) {
1695 /* LCOV_EXCL_START */
1696 TDM_ERR("couldn't create voutput resource");
1697 free(private_voutput);
1699 *error = TDM_ERROR_OUT_OF_MEMORY;
1700 pthread_mutex_unlock(&private_client->lock);
1702 /* LCOV_EXCL_STOP */
1705 wl_tdm_voutput_add_listener(private_voutput->wl_voutput,
1706 &tdm_client_voutput_lisntener, private_voutput);
1707 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1709 wl_proxy_set_queue((struct wl_proxy *)private_voutput->wl_voutput, NULL);
1711 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1712 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
1713 free(private_voutput);
1715 *error = TDM_ERROR_PROTOCOL_ERROR;
1716 pthread_mutex_unlock(&private_client->lock);
1720 if (private_voutput->msg != WL_TDM_VOUTPUT_MESSAGE_ADDED)
1722 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
1723 free(private_voutput);
1725 *error = TDM_ERROR_PROTOCOL_ERROR; // FIXME add new error type.
1726 pthread_mutex_unlock(&private_client->lock);
1730 pthread_mutex_unlock(&private_client->lock);
1732 return (tdm_client_voutput *)private_voutput;
1736 tdm_client_voutput_destroy(tdm_client_voutput *voutput)
1738 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)voutput;
1740 if (!private_voutput)
1743 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
1745 free(private_voutput);
1749 tdm_client_voutput_set_available_modes(tdm_client_voutput *voutput, const tdm_client_output_mode *modes, int count)
1751 tdm_private_client_voutput *private_voutput;
1753 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
1755 if ((count > 0) && (modes == NULL))
1756 return TDM_ERROR_INVALID_PARAMETER;
1758 private_voutput = (tdm_private_client_voutput *)voutput;
1760 if (private_voutput->base.connection == TDM_OUTPUT_CONN_STATUS_CONNECTED)
1761 return TDM_ERROR_BAD_REQUEST;
1763 if (private_voutput->available_modes.modes)
1764 free(private_voutput->available_modes.modes);
1766 private_voutput->available_modes.count = count;
1770 private_voutput->available_modes.modes = calloc(count, sizeof(tdm_client_output_mode));
1771 memcpy(private_voutput->available_modes.modes, modes, sizeof(tdm_client_output_mode) * count);
1774 return TDM_ERROR_NONE;
1778 tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, unsigned int mmWidth, unsigned int mmHeight)
1780 tdm_private_client_voutput *private_voutput;
1782 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
1783 TDM_RETURN_VAL_IF_FAIL(mmWidth != 0, TDM_ERROR_INVALID_PARAMETER);
1784 TDM_RETURN_VAL_IF_FAIL(mmHeight != 0, TDM_ERROR_INVALID_PARAMETER);
1786 private_voutput = (tdm_private_client_voutput *)voutput;
1788 if (private_voutput->base.connection == TDM_OUTPUT_CONN_STATUS_CONNECTED)
1789 return TDM_ERROR_BAD_REQUEST;
1791 private_voutput->mmwidth = mmWidth;
1792 private_voutput->mmheight = mmHeight;
1794 return TDM_ERROR_NONE;
1798 tdm_client_voutput_get_client_output(tdm_client_voutput *voutput, tdm_error *error)
1800 tdm_private_client_voutput *private_voutput;
1803 *error = TDM_ERROR_NONE;
1807 TDM_ERR("'!voutput' failed");
1809 *error = TDM_ERROR_INVALID_PARAMETER;
1813 private_voutput = (tdm_private_client_voutput *)voutput;
1815 return &private_voutput->base;
1819 tdm_client_output_get_available_modes(tdm_client_output *output, tdm_client_output_mode **modes, int *count)
1821 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1822 TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER);
1823 TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
1825 return TDM_ERROR_NONE;
1829 tdm_client_output_set_mode(tdm_client_output *output, const tdm_client_output_mode *mode)
1831 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1832 TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER);
1834 return TDM_ERROR_NONE;
1838 tdm_client_output_connect(tdm_client_output *output)
1840 tdm_private_client_output *private_output;
1841 tdm_private_client_voutput *private_voutput;
1842 tdm_client_output_mode *modes;
1845 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1847 private_output = (tdm_private_client_output *)output;
1848 private_voutput = (tdm_private_client_voutput *)output;
1850 TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_CONNECTED,
1851 TDM_ERROR_BAD_REQUEST);
1853 private_output->connection = TDM_OUTPUT_CONN_STATUS_CONNECTED;
1855 modes = private_voutput->available_modes.modes;
1856 for (i = 0; i < private_voutput->available_modes.count; i++) {
1857 wl_tdm_voutput_set_available_modes(private_voutput->wl_voutput, i,
1858 modes[i].clock, modes[i].hdisplay,
1859 modes[i].hsync_start, modes[i].hsync_end,
1860 modes[i].htotal, modes[i].hskew,
1861 modes[i].vdisplay, modes[i].vsync_start,
1862 modes[i].vsync_end, modes[i].vtotal,
1863 modes[i].vscan, modes[i].vrefresh,
1864 modes[i].flags, modes[i].type,
1867 wl_tdm_voutput_set_physical_size(private_voutput->wl_voutput, private_voutput->mmwidth, private_voutput->mmheight);
1869 wl_tdm_voutput_connect(private_voutput->wl_voutput);
1871 return TDM_ERROR_NONE;
1875 tdm_client_output_disconnect(tdm_client_output *output)
1877 tdm_private_client_voutput *private_voutput;
1878 tdm_private_client_output *private_output;
1880 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1882 private_output = (tdm_private_client_output *)output;
1883 private_voutput = (tdm_private_client_voutput *)output;
1885 TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED,
1886 TDM_ERROR_BAD_REQUEST);
1888 private_output->connection = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
1890 wl_tdm_voutput_disconnect(private_voutput->wl_voutput);
1892 return TDM_ERROR_NONE;