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;
103 } tdm_private_client_voutput;
105 struct _tdm_private_client_vblank {
106 tdm_private_client_output *private_output;
108 struct wl_tdm_vblank *vblank;
109 struct list_head wait_list;
111 char name[TDM_NAME_LEN];
115 unsigned int enable_fake;
116 unsigned int enable_ttrace;
118 unsigned int started;
124 struct list_head link;
127 typedef struct _tdm_client_output_handler_info {
128 tdm_private_client_output *private_output;
130 tdm_client_output_change_handler func;
133 struct list_head link;
134 struct list_head call_link;
135 } tdm_client_output_handler_info;
137 typedef struct _tdm_client_wait_info {
138 tdm_private_client_vblank *private_vblank;
140 tdm_client_vblank_handler func;
147 struct list_head link;
148 struct list_head call_link;
149 } tdm_client_wait_info;
152 _tdm_client_check_wl_error(tdm_private_client *private_client, const char *func, int line)
155 const struct wl_interface *intf;
158 err = wl_display_get_error(private_client->display);
162 if (err == EINVAL || err == ENOMEM || err == EFAULT || err == EPROTO) {
163 ec = wl_display_get_protocol_error(private_client->display, &intf, &id);
164 TDM_ERR("[%s,%d] errno(%d) Got protocol error '%u' on interface '%s' (object '%u')",
165 func, line, err, ec, (intf) ? intf->name : "destroyed", id);
167 TDM_ERR("[%s,%d] errno(%d)", func, line, err);
173 #define CHECK_WL_PROTOCOL_ERROR(pc) _tdm_client_check_wl_error(pc, __FUNCTION__, __LINE__)
176 _tdm_client_vblank_cb_stamp(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t stamp)
178 tdm_private_client_vblank *private_vblank = data;
179 tdm_private_client *private_client;
181 TDM_RETURN_IF_FAIL(private_vblank != NULL);
183 private_vblank->stamp = stamp;
185 TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
186 private_client = private_vblank->private_output->private_client;
188 private_client->stamp = stamp;
191 /* LCOV_EXCL_START */
193 _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank,
194 uint32_t req_id, uint32_t sequence, uint32_t tv_sec,
195 uint32_t tv_usec, uint32_t error)
197 tdm_private_client_vblank *private_vblank = data;
198 tdm_private_client *private_client;
199 tdm_client_wait_info *w = NULL, *wait_info = NULL;
201 TDM_RETURN_IF_FAIL(private_vblank != NULL);
203 private_client = private_vblank->private_output->private_client;
205 private_vblank->last_time = TDM_TIME(tv_sec, tv_usec);
207 TDM_DBG("vblank(%p) req_id(%u) sequence(%u) time(%.6f)",
208 private_vblank, req_id, sequence, TDM_TIME(tv_sec, tv_usec));
210 LIST_FOR_EACH_ENTRY(w, &private_vblank->wait_list, link) {
211 if (w->req_id != req_id)
219 TDM_ERR("no wait infomation for req_id(%d)", req_id);
223 if (private_vblank->enable_ttrace)
224 TDM_TRACE_ASYNC_END((int)wait_info->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
226 if (wait_info->req_time >= private_vblank->last_time)
227 TDM_WRN("'req(%.6f) < last(%.6f)' failed. error(%d)", wait_info->req_time, private_vblank->last_time, error);
229 if (wait_info->need_free)
230 LIST_DEL(&wait_info->link);
232 if (wait_info->func) {
233 pthread_mutex_unlock(&private_client->lock);
234 wait_info->func(private_vblank, error, sequence, tv_sec, tv_usec, wait_info->user_data);
235 pthread_mutex_lock(&private_client->lock);
238 if (wait_info->need_free)
241 wait_info->need_free = 1;
245 /* LCOV_EXCL_START */
247 _tdm_client_vblank_cb_ttrace(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t enable)
249 tdm_private_client_vblank *private_vblank = data;
250 tdm_private_client *private_client;
252 TDM_RETURN_IF_FAIL(private_vblank != NULL);
254 private_vblank->enable_ttrace = enable;
256 TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
257 private_client = private_vblank->private_output->private_client;
259 private_client->enable_ttrace = enable;
263 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
264 _tdm_client_vblank_cb_stamp,
265 _tdm_client_vblank_cb_done,
266 _tdm_client_vblank_cb_ttrace,
270 _tdm_client_output_destroy(tdm_private_client_output *private_output)
272 tdm_private_client_vblank *v = NULL, *vv = NULL;
273 tdm_client_output_handler_info *h = NULL, *hh = NULL;
275 LIST_DEL(&private_output->link);
277 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_list, link) {
278 TDM_ERR("vblanks SHOULD be destroyed first!");
280 v->private_output = NULL;
283 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list, link) {
288 wl_tdm_output_destroy(private_output->output);
290 free(private_output);
294 _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output,
295 uint32_t width, uint32_t height, uint32_t refresh, uint32_t error)
297 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
299 TDM_RETURN_IF_FAIL(private_output != NULL);
301 private_output->width = width;
302 private_output->height = height;
303 private_output->refresh = refresh;
305 if (error != TDM_ERROR_NONE)
306 TDM_INFO("mode event error: %d", error);
308 TDM_DBG("private_output(%p) wl_tbm_output@%d width(%d) height(%d) refresh(%d)",
309 private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output),
310 width, height, refresh);
314 _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
316 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
317 tdm_private_client *private_client;
318 tdm_client_output_handler_info *h = NULL, *hh = NULL;
320 struct list_head call_list;
322 TDM_RETURN_IF_FAIL(private_output != NULL);
324 private_client = private_output->private_client;
326 if (private_output->connection == value)
329 private_output->connection = value;
331 if (error != TDM_ERROR_NONE)
332 TDM_INFO("connection event error: %d", error);
334 TDM_DBG("private_output(%p) wl_tbm_output@%d connection(%d)",
336 wl_proxy_get_id((struct wl_proxy*)private_output->output),
339 LIST_INITHEAD(&call_list);
341 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
342 LIST_ADDTAIL(&h->call_link, &call_list);
346 pthread_mutex_unlock(&private_client->lock);
347 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
349 h->func(private_output, TDM_OUTPUT_CHANGE_CONNECTION, v, h->user_data);
351 pthread_mutex_lock(&private_client->lock);
355 _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
357 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
358 tdm_private_client *private_client;
359 tdm_client_output_handler_info *h = NULL, *hh = NULL;
361 struct list_head call_list;
363 TDM_RETURN_IF_FAIL(private_output != NULL);
365 private_client = private_output->private_client;
367 /* If value is extended value, we handle it as DPMS on in client side
368 * The extended DPMS value is valid only in server side.
369 * Or, need to export to client side also?
371 if (value > TDM_OUTPUT_DPMS_OFF)
372 value = TDM_OUTPUT_DPMS_ON;
374 if (private_output->dpms == value)
377 private_output->dpms = value;
379 if (error != TDM_ERROR_NONE)
380 TDM_INFO("dpms event error: %d", error);
382 TDM_DBG("private_output(%p) wl_tbm_output@%d dpms(%d)",
384 wl_proxy_get_id((struct wl_proxy*)private_output->output),
387 LIST_INITHEAD(&call_list);
389 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
390 LIST_ADDTAIL(&h->call_link, &call_list);
394 pthread_mutex_unlock(&private_client->lock);
395 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
397 h->func(private_output, TDM_OUTPUT_CHANGE_DPMS, v, h->user_data);
399 pthread_mutex_lock(&private_client->lock);
402 static const struct wl_tdm_output_listener tdm_client_output_listener = {
403 _tdm_client_output_cb_mode,
404 _tdm_client_output_cb_connection,
405 _tdm_client_output_cb_dpms,
409 _tdm_client_cb_global(void *data, struct wl_registry *registry,
410 uint32_t name, const char *interface,
413 tdm_private_client *private_client = data;
415 if (strncmp(interface, "wl_tdm", 6) == 0) {
416 private_client->tdm =
417 wl_registry_bind(registry, name, &wl_tdm_interface, version);
418 TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
420 wl_display_flush(private_client->display);
424 /* LCOV_EXCL_START */
426 _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
431 static const struct wl_registry_listener tdm_client_registry_listener = {
432 _tdm_client_cb_global,
433 _tdm_client_cb_global_remove
437 tdm_client_create(tdm_error *error)
439 tdm_private_client *private_client;
441 private_client = calloc(1, sizeof *private_client);
442 if (!private_client) {
443 /* LCOV_EXCL_START */
445 TDM_ERR("alloc failed");
447 *error = TDM_ERROR_OUT_OF_MEMORY;
453 if (pthread_mutex_init(&private_client->lock, NULL)) {
454 TDM_ERR("mutex init failed: %m");
455 free(private_client);
457 *error = TDM_ERROR_OUT_OF_MEMORY;
461 LIST_INITHEAD(&private_client->output_list);
463 private_client->display = wl_display_connect("tdm-socket");
464 TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed);
466 private_client->queue = wl_display_create_queue(private_client->display);
467 TDM_GOTO_IF_FAIL(private_client->queue != NULL, create_failed);
469 private_client->registry = wl_display_get_registry(private_client->display);
470 TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed);
472 wl_registry_add_listener(private_client->registry,
473 &tdm_client_registry_listener, private_client);
474 wl_display_roundtrip(private_client->display);
476 if (CHECK_WL_PROTOCOL_ERROR(private_client))
479 /* check global objects */
480 TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed);
483 *error = TDM_ERROR_NONE;
485 return (tdm_client*)private_client;
487 tdm_client_destroy((tdm_client*)private_client);
489 *error = TDM_ERROR_OPERATION_FAILED;
494 tdm_client_destroy(tdm_client *client)
496 tdm_private_client *private_client = (tdm_private_client*)client;
497 tdm_private_client_output *o = NULL, *oo = NULL;
502 pthread_mutex_lock(&private_client->lock);
504 if (private_client->temp_vblank) {
505 pthread_mutex_unlock(&private_client->lock);
506 tdm_client_vblank_destroy(private_client->temp_vblank);
507 pthread_mutex_lock(&private_client->lock);
510 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_client->output_list, link) {
511 _tdm_client_output_destroy(o);
514 if (private_client->tdm)
515 wl_tdm_destroy(private_client->tdm);
516 if (private_client->registry)
517 wl_registry_destroy(private_client->registry);
518 if (private_client->queue)
519 wl_event_queue_destroy(private_client->queue);
520 if (private_client->display)
521 wl_display_disconnect(private_client->display);
523 pthread_mutex_unlock(&private_client->lock);
524 pthread_mutex_destroy(&private_client->lock);
526 free(private_client);
530 tdm_client_get_fd(tdm_client *client, int *fd)
532 tdm_private_client *private_client;
534 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
535 TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_ERROR_INVALID_PARAMETER);
537 private_client = (tdm_private_client*)client;
539 pthread_mutex_lock(&private_client->lock);
541 *fd = wl_display_get_fd(private_client->display);
543 pthread_mutex_unlock(&private_client->lock);
546 return TDM_ERROR_OPERATION_FAILED;
548 return TDM_ERROR_NONE;
552 tdm_client_handle_events(tdm_client *client)
554 tdm_private_client *private_client;
556 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
558 /* LCOV_EXCL_START */
559 private_client = (tdm_private_client*)client;
561 pthread_mutex_lock(&private_client->lock);
563 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
564 pthread_mutex_unlock(&private_client->lock);
565 return TDM_ERROR_PROTOCOL_ERROR;
568 if (private_client->enable_ttrace)
569 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
571 wl_display_dispatch(private_client->display);
573 if (private_client->enable_ttrace)
574 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
576 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
577 pthread_mutex_unlock(&private_client->lock);
578 return TDM_ERROR_PROTOCOL_ERROR;
581 pthread_mutex_unlock(&private_client->lock);
583 return TDM_ERROR_NONE;
588 _tdm_client_poll(struct wl_display *display, short int events, int timeout)
591 struct pollfd pfd[1];
593 pfd[0].fd = wl_display_get_fd(display);
594 pfd[0].events = events;
596 ret = poll(pfd, 1, timeout);
597 } while (ret == -1 && errno == EINTR);
603 _tdm_client_dispatch_timeout(tdm_private_client *private_client, int timeout)
606 struct wl_display *display = private_client->display;
608 if (wl_display_prepare_read(display) == -1) {
609 if (wl_display_dispatch_pending(display) > 0)
610 return TDM_ERROR_NONE;
612 return TDM_ERROR_OPERATION_FAILED;
616 ret = wl_display_flush(display);
618 if (ret != -1 || errno != EAGAIN)
621 if (_tdm_client_poll(display, POLLOUT, -1) == -1) {
622 wl_display_cancel_read(display);
623 TDM_ERR("_tdm_client_poll failed");
624 return TDM_ERROR_OPERATION_FAILED;
628 /* Don't stop if flushing hits an EPIPE; continue so we can read any
629 * protocol error that may have triggered it. */
630 if (ret < 0 && errno != EPIPE) {
631 TDM_ERR("ret(%d) errno(%d)", ret, errno);
632 wl_display_cancel_read(display);
633 return TDM_ERROR_OPERATION_FAILED;
636 ret = _tdm_client_poll(display, POLLIN, timeout);
638 wl_display_cancel_read(display);
640 TDM_ERR("_tdm_client_poll timeout.");
641 return TDM_ERROR_TIMEOUT;
643 TDM_ERR("_tdm_client_poll failed. (ret:%d)", ret);
644 return TDM_ERROR_OPERATION_FAILED;
648 if (wl_display_read_events(display) == -1) {
649 TDM_ERR("wl_display_read_events failed");
650 return TDM_ERROR_OPERATION_FAILED;
653 ret = wl_display_dispatch_pending(display);
656 TDM_ERR("_tdm_client_dispatch_timeout failed");
657 return TDM_ERROR_OPERATION_FAILED;
660 return TDM_ERROR_NONE;
664 tdm_client_handle_events_timeout(tdm_client *client, int ms_timeout)
666 tdm_private_client *private_client;
668 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
670 private_client = (tdm_private_client*)client;
672 pthread_mutex_lock(&private_client->lock);
674 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
675 pthread_mutex_unlock(&private_client->lock);
676 return TDM_ERROR_PROTOCOL_ERROR;
679 if (private_client->enable_ttrace)
680 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
682 ret = _tdm_client_dispatch_timeout(private_client, ms_timeout);
684 if (private_client->enable_ttrace)
685 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
687 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
688 pthread_mutex_unlock(&private_client->lock);
689 return TDM_ERROR_PROTOCOL_ERROR;
692 pthread_mutex_unlock(&private_client->lock);
697 typedef struct _tdm_client_vblank_temp {
698 tdm_client_vblank_handler2 func;
700 } tdm_client_vblank_temp;
702 /* LCOV_EXCL_START */
704 _tdm_client_vblank_handler_temp(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
705 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
707 tdm_client_vblank_temp *vblank_temp = user_data;
709 TDM_RETURN_IF_FAIL(vblank_temp != NULL);
710 TDM_RETURN_IF_FAIL(vblank != NULL);
712 if (vblank_temp->func)
713 vblank_temp->func(sequence, tv_sec, tv_usec, vblank_temp->user_data);
719 /* LCOV_EXCL_START */ /* deprecated */
721 tdm_client_wait_vblank(tdm_client *client, char *name,
722 int sw_timer, int interval, int sync,
723 tdm_client_vblank_handler2 func, void *user_data)
725 tdm_private_client *private_client = (tdm_private_client*)client;
726 tdm_client_output *output;
727 tdm_client_vblank_temp *vblank_temp;
730 TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
731 TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
732 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
734 if (CHECK_WL_PROTOCOL_ERROR(private_client))
735 return TDM_ERROR_PROTOCOL_ERROR;
737 if (!private_client->temp_vblank) {
738 output = tdm_client_get_output(client, name, &ret);
739 TDM_RETURN_VAL_IF_FAIL(output != NULL, ret);
741 private_client->temp_vblank = tdm_client_output_create_vblank(output, &ret);
742 TDM_RETURN_VAL_IF_FAIL(private_client->temp_vblank != NULL, ret);
745 tdm_client_vblank_set_enable_fake(private_client->temp_vblank, sw_timer);
746 tdm_client_vblank_set_sync(private_client->temp_vblank, sync);
748 vblank_temp = calloc(1, sizeof *vblank_temp);
749 TDM_RETURN_VAL_IF_FAIL(vblank_temp != NULL, TDM_ERROR_OUT_OF_MEMORY);
751 vblank_temp->func = func;
752 vblank_temp->user_data = user_data;
754 return tdm_client_vblank_wait(private_client->temp_vblank, interval, _tdm_client_vblank_handler_temp, vblank_temp);
759 tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
761 tdm_private_client *private_client;
762 tdm_private_client_output *private_output = NULL;
763 struct wl_proxy *wrapper;
766 *error = TDM_ERROR_NONE;
769 TDM_ERR("'!client' failed");
771 *error = TDM_ERROR_INVALID_PARAMETER;
775 private_client = (tdm_private_client*)client;
777 pthread_mutex_lock(&private_client->lock);
779 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
781 *error = TDM_ERROR_PROTOCOL_ERROR;
782 pthread_mutex_unlock(&private_client->lock);
788 } else if (strncmp(name, "primary", 7) && strncmp(name, "default", 7)) {
790 *error = TDM_ERROR_INVALID_PARAMETER;
791 pthread_mutex_unlock(&private_client->lock);
795 LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
796 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
797 pthread_mutex_unlock(&private_client->lock);
798 return (tdm_client_output*)private_output;
802 wrapper = wl_proxy_create_wrapper(private_client->tdm);
804 TDM_ERR("create output_wrapper failed");
806 *error = TDM_ERROR_OUT_OF_MEMORY;
807 pthread_mutex_unlock(&private_client->lock);
811 wl_proxy_set_queue(wrapper, private_client->queue);
813 private_output = calloc(1, sizeof *private_output);
814 if (!private_output) {
815 /* LCOV_EXCL_START */
816 wl_proxy_wrapper_destroy(wrapper);
817 TDM_ERR("alloc failed");
819 *error = TDM_ERROR_OUT_OF_MEMORY;
820 pthread_mutex_unlock(&private_client->lock);
826 private_output->private_client = private_client;
828 snprintf(private_output->name, TDM_NAME_LEN, "%s", name);
829 private_output->output = wl_tdm_create_output((struct wl_tdm *)wrapper, private_output->name);
830 wl_proxy_wrapper_destroy(wrapper);
831 if (!private_output->output) {
832 /* LCOV_EXCL_START */
834 TDM_ERR("couldn't create output resource");
835 free(private_output);
837 *error = TDM_ERROR_OUT_OF_MEMORY;
838 pthread_mutex_unlock(&private_client->lock);
844 LIST_INITHEAD(&private_output->vblank_list);
845 LIST_INITHEAD(&private_output->change_handler_list);
847 wl_tdm_output_add_listener(private_output->output,
848 &tdm_client_output_listener, private_output);
849 wl_display_roundtrip_queue(private_client->display, private_client->queue);
851 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
853 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
854 wl_tdm_output_destroy(private_output->output);
855 free(private_output);
857 *error = TDM_ERROR_PROTOCOL_ERROR;
858 pthread_mutex_unlock(&private_client->lock);
862 LIST_ADDTAIL(&private_output->link, &private_client->output_list);
864 pthread_mutex_unlock(&private_client->lock);
866 return (tdm_client_output*)private_output;
870 tdm_client_output_add_change_handler(tdm_client_output *output,
871 tdm_client_output_change_handler func,
874 tdm_private_client_output *private_output;
875 tdm_private_client *private_client;
876 tdm_client_output_handler_info *h = NULL;
878 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
879 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
881 private_output = (tdm_private_client_output*)output;
882 private_client = private_output->private_client;
884 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
885 if (h->func == func && h->user_data == user_data) {
886 TDM_ERR("can't add twice");
887 return TDM_ERROR_BAD_REQUEST;
891 h = calloc(1, sizeof *h);
892 TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
894 pthread_mutex_lock(&private_client->lock);
896 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
898 pthread_mutex_unlock(&private_client->lock);
899 return TDM_ERROR_PROTOCOL_ERROR;
902 if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
903 wl_tdm_output_watch_output_changes(private_output->output, 1);
904 wl_display_roundtrip_queue(private_client->display, private_client->queue);
906 /* TODO: this is very tricky.
907 * If a client adds the change_handler, we might be able to guess that
908 * the client will watch the tdm client's fd and handle tdm events in
909 * event loop. Otherwise, we CAN'T make sure if a client has event loop
910 * which handles tdm events.
912 private_output->watch_output_changes = 1;
915 h->private_output = private_output;
917 h->user_data = user_data;
918 LIST_ADDTAIL(&h->link, &private_output->change_handler_list);
919 LIST_INITHEAD(&h->call_link);
921 pthread_mutex_unlock(&private_client->lock);
923 return TDM_ERROR_NONE;
927 tdm_client_output_remove_change_handler(tdm_client_output *output,
928 tdm_client_output_change_handler func,
931 tdm_private_client_output *private_output;
932 tdm_private_client *private_client;
933 tdm_client_output_handler_info *h = NULL;
935 TDM_RETURN_IF_FAIL(output != NULL);
936 TDM_RETURN_IF_FAIL(func != NULL);
938 private_output = (tdm_private_client_output*)output;
939 private_client = private_output->private_client;
941 pthread_mutex_lock(&private_client->lock);
943 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
944 if (h->func != func || h->user_data != user_data)
950 if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
951 private_output->watch_output_changes = 0;
952 if (!CHECK_WL_PROTOCOL_ERROR(private_client)) {
953 wl_tdm_output_watch_output_changes(private_output->output, 0);
954 wl_display_roundtrip_queue(private_client->display, private_client->queue);
958 pthread_mutex_unlock(&private_client->lock);
963 pthread_mutex_unlock(&private_client->lock);
967 tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refresh)
969 tdm_private_client_output *private_output;
970 tdm_private_client *private_client;
972 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
973 TDM_RETURN_VAL_IF_FAIL(refresh != NULL, TDM_ERROR_INVALID_PARAMETER);
975 private_output = (tdm_private_client_output*)output;
976 private_client = private_output->private_client;
978 pthread_mutex_lock(&private_client->lock);
980 if (private_output->watch_output_changes) {
981 *refresh = private_output->refresh;
982 pthread_mutex_unlock(&private_client->lock);
983 return TDM_ERROR_NONE;
986 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
987 pthread_mutex_unlock(&private_client->lock);
988 return TDM_ERROR_PROTOCOL_ERROR;
991 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
992 wl_tdm_output_get_mode(private_output->output);
993 wl_display_roundtrip_queue(private_client->display, private_client->queue);
994 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
996 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
997 pthread_mutex_unlock(&private_client->lock);
998 return TDM_ERROR_PROTOCOL_ERROR;
1001 *refresh = private_output->refresh;
1003 pthread_mutex_unlock(&private_client->lock);
1005 return TDM_ERROR_NONE;
1009 tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_status *status)
1011 tdm_private_client_output *private_output;
1012 tdm_private_client *private_client;
1014 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1015 TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
1017 private_output = (tdm_private_client_output*)output;
1018 private_client = private_output->private_client;
1020 pthread_mutex_lock(&private_client->lock);
1022 if (private_output->watch_output_changes) {
1023 *status = private_output->connection;
1024 pthread_mutex_unlock(&private_client->lock);
1025 return TDM_ERROR_NONE;
1028 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1029 pthread_mutex_unlock(&private_client->lock);
1030 return TDM_ERROR_PROTOCOL_ERROR;
1033 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1034 wl_tdm_output_get_connection(private_output->output);
1035 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1036 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1038 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1039 pthread_mutex_unlock(&private_client->lock);
1040 return TDM_ERROR_PROTOCOL_ERROR;
1043 *status = private_output->connection;
1045 pthread_mutex_unlock(&private_client->lock);
1047 return TDM_ERROR_NONE;
1051 tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
1053 tdm_private_client_output *private_output;
1054 tdm_private_client *private_client;
1056 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1057 TDM_RETURN_VAL_IF_FAIL(dpms != NULL, TDM_ERROR_INVALID_PARAMETER);
1059 private_output = (tdm_private_client_output*)output;
1060 private_client = private_output->private_client;
1062 if (private_output->watch_output_changes) {
1063 *dpms = private_output->dpms;
1064 return TDM_ERROR_NONE;
1067 pthread_mutex_lock(&private_client->lock);
1069 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1070 pthread_mutex_unlock(&private_client->lock);
1071 return TDM_ERROR_PROTOCOL_ERROR;
1074 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1075 wl_tdm_output_get_dpms(private_output->output);
1076 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1077 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1079 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1080 pthread_mutex_unlock(&private_client->lock);
1081 return TDM_ERROR_PROTOCOL_ERROR;
1084 *dpms = private_output->dpms;
1086 pthread_mutex_unlock(&private_client->lock);
1088 return TDM_ERROR_NONE;
1092 tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
1094 tdm_private_client *private_client;
1095 tdm_private_client_output *private_output;
1096 tdm_private_client_vblank *private_vblank;
1097 struct wl_proxy *wrapper;
1100 *error = TDM_ERROR_NONE;
1103 TDM_ERR("'!output' failed");
1105 *error = TDM_ERROR_INVALID_PARAMETER;
1109 private_output = (tdm_private_client_output*)output;
1110 private_client = private_output->private_client;
1112 pthread_mutex_lock(&private_client->lock);
1114 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1116 *error = TDM_ERROR_PROTOCOL_ERROR;
1117 pthread_mutex_unlock(&private_client->lock);
1121 wrapper = wl_proxy_create_wrapper(private_output->output);
1123 TDM_ERR("create output_wrapper failed");
1125 *error = TDM_ERROR_OUT_OF_MEMORY;
1126 pthread_mutex_unlock(&private_client->lock);
1130 wl_proxy_set_queue(wrapper, private_client->queue);
1132 private_vblank = calloc(1, sizeof *private_vblank);
1133 if (!private_vblank) {
1134 /* LCOV_EXCL_START */
1136 TDM_ERR("alloc failed");
1137 wl_proxy_wrapper_destroy(wrapper);
1139 *error = TDM_ERROR_OUT_OF_MEMORY;
1140 pthread_mutex_unlock(&private_client->lock);
1143 /* LCOV_EXCL_STOP */
1146 private_vblank->private_output = private_output;
1148 private_vblank->vblank = wl_tdm_output_create_vblank((struct wl_tdm_output*)wrapper);
1149 wl_proxy_wrapper_destroy(wrapper);
1150 if (!private_vblank->vblank) {
1151 /* LCOV_EXCL_START */
1153 TDM_ERR("couldn't create vblank resource");
1154 free(private_vblank);
1156 *error = TDM_ERROR_OUT_OF_MEMORY;
1157 pthread_mutex_unlock(&private_client->lock);
1160 /* LCOV_EXCL_STOP */
1164 private_vblank->fps = private_output->refresh;
1165 private_vblank->offset = 0;
1166 private_vblank->enable_fake = 0;
1168 LIST_INITHEAD(&private_vblank->wait_list);
1170 wl_tdm_vblank_add_listener(private_vblank->vblank,
1171 &tdm_client_vblank_listener, private_vblank);
1172 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1174 wl_proxy_set_queue((struct wl_proxy *)private_vblank->vblank, NULL);
1176 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1177 wl_tdm_vblank_destroy(private_vblank->vblank);
1178 free(private_vblank);
1180 *error = TDM_ERROR_PROTOCOL_ERROR;
1181 pthread_mutex_unlock(&private_client->lock);
1185 LIST_ADDTAIL(&private_vblank->link, &private_output->vblank_list);
1187 pthread_mutex_unlock(&private_client->lock);
1189 return (tdm_client_vblank*)private_vblank;
1193 tdm_client_vblank_destroy(tdm_client_vblank *vblank)
1195 tdm_private_client_vblank *private_vblank;
1196 tdm_private_client *private_client;
1197 tdm_client_wait_info *w = NULL, *ww = NULL;
1199 TDM_RETURN_IF_FAIL(vblank != NULL);
1201 private_vblank = vblank;
1202 private_client = private_vblank->private_output->private_client;
1204 pthread_mutex_lock(&private_client->lock);
1206 LIST_DEL(&private_vblank->link);
1208 LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
1213 wl_tdm_vblank_destroy(private_vblank->vblank);
1215 free(private_vblank);
1217 pthread_mutex_unlock(&private_client->lock);
1221 tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name)
1223 tdm_private_client_vblank *private_vblank;
1224 tdm_private_client *private_client;
1226 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1228 private_vblank = vblank;
1229 private_client = private_vblank->private_output->private_client;
1231 pthread_mutex_lock(&private_client->lock);
1233 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1234 pthread_mutex_unlock(&private_client->lock);
1235 return TDM_ERROR_PROTOCOL_ERROR;
1239 name = TDM_VBLANK_DEFAULT_NAME;
1241 strncpy(private_vblank->name, name, TDM_NAME_LEN - 1);
1242 private_vblank->name[TDM_NAME_LEN - 1] = '\0';
1244 wl_tdm_vblank_set_name(private_vblank->vblank, private_vblank->name);
1246 pthread_mutex_unlock(&private_client->lock);
1248 return TDM_ERROR_NONE;
1252 tdm_client_vblank_set_sync(tdm_client_vblank *vblank, unsigned int sync)
1254 tdm_private_client_vblank *private_vblank;
1255 tdm_private_client *private_client;
1257 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1259 private_vblank = vblank;
1260 private_client = private_vblank->private_output->private_client;
1262 pthread_mutex_lock(&private_client->lock);
1263 private_vblank->sync = sync;
1264 pthread_mutex_unlock(&private_client->lock);
1266 return TDM_ERROR_NONE;
1270 tdm_client_vblank_set_fps(tdm_client_vblank *vblank, unsigned int fps)
1272 tdm_private_client_vblank *private_vblank;
1273 tdm_private_client *private_client;
1275 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1276 TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER);
1278 private_vblank = vblank;
1279 private_client = private_vblank->private_output->private_client;
1281 pthread_mutex_lock(&private_client->lock);
1283 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1284 pthread_mutex_unlock(&private_client->lock);
1285 return TDM_ERROR_PROTOCOL_ERROR;
1288 if (private_vblank->fps == fps) {
1289 pthread_mutex_unlock(&private_client->lock);
1290 return TDM_ERROR_NONE;
1293 private_vblank->fps = fps;
1295 wl_tdm_vblank_set_fps(private_vblank->vblank, fps);
1297 pthread_mutex_unlock(&private_client->lock);
1299 return TDM_ERROR_NONE;
1303 tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms)
1305 tdm_private_client_vblank *private_vblank;
1306 tdm_private_client *private_client;
1308 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1310 private_vblank = vblank;
1311 TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
1313 private_client = private_vblank->private_output->private_client;
1315 pthread_mutex_lock(&private_client->lock);
1317 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1318 pthread_mutex_unlock(&private_client->lock);
1319 return TDM_ERROR_PROTOCOL_ERROR;
1322 if (private_vblank->offset == offset_ms) {
1323 pthread_mutex_unlock(&private_client->lock);
1324 return TDM_ERROR_NONE;
1327 private_vblank->offset = offset_ms;
1329 wl_tdm_vblank_set_offset(private_vblank->vblank, offset_ms);
1331 pthread_mutex_unlock(&private_client->lock);
1333 return TDM_ERROR_NONE;
1337 tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable_fake)
1339 tdm_private_client_vblank *private_vblank;
1340 tdm_private_client *private_client;
1342 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1344 private_vblank = vblank;
1345 private_client = private_vblank->private_output->private_client;
1347 pthread_mutex_lock(&private_client->lock);
1349 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1350 pthread_mutex_unlock(&private_client->lock);
1351 return TDM_ERROR_PROTOCOL_ERROR;
1354 if (private_vblank->enable_fake == enable_fake) {
1355 pthread_mutex_unlock(&private_client->lock);
1356 return TDM_ERROR_NONE;
1359 private_vblank->enable_fake = enable_fake;
1361 wl_tdm_vblank_set_enable_fake(private_vblank->vblank, enable_fake);
1363 pthread_mutex_unlock(&private_client->lock);
1365 return TDM_ERROR_NONE;
1369 tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_client_vblank_handler func, void *user_data)
1371 tdm_private_client *private_client;
1372 tdm_private_client_output *private_output;
1373 tdm_private_client_vblank *private_vblank;
1374 tdm_client_wait_info *w;
1376 unsigned int req_sec, req_usec;
1379 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1380 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1381 /* can't support "interval 0" and "getting current_msc" things because
1382 * there is a socket communication between TDM client and server. It's impossible
1383 * to return the current msc or sequence immediately.
1385 TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
1387 private_vblank = vblank;
1388 private_output = private_vblank->private_output;
1389 private_client = private_output->private_client;
1391 pthread_mutex_lock(&private_client->lock);
1393 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1394 pthread_mutex_unlock(&private_client->lock);
1395 return TDM_ERROR_PROTOCOL_ERROR;
1398 if (!private_vblank->started)
1399 private_vblank->started = 1;
1401 if (!private_vblank->enable_fake) {
1402 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1403 TDM_ERR("output disconnected");
1404 pthread_mutex_unlock(&private_client->lock);
1405 return TDM_ERROR_OUTPUT_DISCONNECTED;
1407 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1408 TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1409 pthread_mutex_unlock(&private_client->lock);
1410 return TDM_ERROR_DPMS_OFF;
1414 w = calloc(1, sizeof *w);
1416 /* LCOV_EXCL_START */
1418 TDM_ERR("alloc failed");
1419 pthread_mutex_unlock(&private_client->lock);
1420 return TDM_ERROR_OUT_OF_MEMORY;
1422 /* LCOV_EXCL_STOP */
1425 w->private_vblank = private_vblank;
1427 w->user_data = user_data;
1429 LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1430 LIST_INITHEAD(&w->call_link);
1432 clock_gettime(CLOCK_MONOTONIC, &tp);
1433 req_sec = (unsigned int)tp.tv_sec;
1434 req_usec = (unsigned int)(tp.tv_nsec / 1000);
1436 w->req_id = ++private_output->req_id;
1437 w->req_time = TDM_TIME(req_sec, req_usec);
1438 w->need_free = (private_vblank->sync) ? 0 : 1;
1440 wl_tdm_vblank_wait_vblank(private_vblank->vblank, interval, w->req_id, req_sec, req_usec);
1442 if (private_vblank->enable_ttrace)
1443 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1445 TDM_DBG("vblank(%p) interval(%u) req_id(%d) req(%.6f)",
1446 vblank, interval, w->req_id, w->req_time);
1448 private_vblank->req_time = w->req_time;
1450 if (private_vblank->last_time >= w->req_time)
1451 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1453 if (!private_vblank->sync) {
1454 wl_display_flush(private_client->display);
1455 pthread_mutex_unlock(&private_client->lock);
1456 return TDM_ERROR_NONE;
1459 /* LCOV_EXCL_START */
1461 while (ret != -1 && !w->need_free)
1462 ret = wl_display_dispatch(private_client->display);
1464 clock_gettime(CLOCK_MONOTONIC, &tp);
1465 TDM_DBG("block during %d us",
1466 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1467 - (req_sec * 1000000 + req_usec));
1472 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1473 pthread_mutex_unlock(&private_client->lock);
1474 return TDM_ERROR_PROTOCOL_ERROR;
1477 pthread_mutex_unlock(&private_client->lock);
1479 return TDM_ERROR_NONE;
1481 /* LCOV_EXCL_STOP */
1485 tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
1486 tdm_client_vblank_handler func, void *user_data)
1488 tdm_private_client *private_client;
1489 tdm_private_client_output *private_output;
1490 tdm_private_client_vblank *private_vblank;
1491 tdm_client_wait_info *w;
1493 unsigned int req_sec, req_usec;
1496 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1497 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1499 private_vblank = vblank;
1500 private_output = private_vblank->private_output;
1501 private_client = private_output->private_client;
1503 pthread_mutex_lock(&private_client->lock);
1505 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1506 pthread_mutex_unlock(&private_client->lock);
1507 return TDM_ERROR_PROTOCOL_ERROR;
1510 if (!private_vblank->started)
1511 private_vblank->started = 1;
1513 if (!private_vblank->enable_fake) {
1514 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1515 TDM_ERR("output disconnected");
1516 pthread_mutex_unlock(&private_client->lock);
1517 return TDM_ERROR_OUTPUT_DISCONNECTED;
1519 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1520 TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1521 pthread_mutex_unlock(&private_client->lock);
1522 return TDM_ERROR_DPMS_OFF;
1526 w = calloc(1, sizeof *w);
1528 /* LCOV_EXCL_START */
1530 TDM_ERR("alloc failed");
1531 pthread_mutex_unlock(&private_client->lock);
1532 return TDM_ERROR_OUT_OF_MEMORY;
1534 /* LCOV_EXCL_STOP */
1537 w->private_vblank = private_vblank;
1539 w->user_data = user_data;
1541 LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1542 LIST_INITHEAD(&w->call_link);
1544 clock_gettime(CLOCK_MONOTONIC, &tp);
1545 req_sec = (unsigned int)tp.tv_sec;
1546 req_usec = (unsigned int)(tp.tv_nsec / 1000);
1548 w->req_id = ++private_output->req_id;
1549 w->req_time = TDM_TIME(req_sec, req_usec);
1550 w->need_free = (private_vblank->sync) ? 0 : 1;
1552 wl_tdm_vblank_wait_vblank_seq(private_vblank->vblank, sequence, w->req_id, req_sec, req_usec);
1554 if (private_vblank->enable_ttrace)
1555 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1557 TDM_DBG("vblank(%p) sequence(%u) req_id(%d) req(%.6f)",
1558 vblank, sequence, w->req_id, w->req_time);
1560 private_vblank->req_time = w->req_time;
1562 if (private_vblank->last_time >= w->req_time)
1563 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1565 if (!private_vblank->sync) {
1566 wl_display_flush(private_client->display);
1567 pthread_mutex_unlock(&private_client->lock);
1568 return TDM_ERROR_NONE;
1571 /* LCOV_EXCL_START */
1573 while (ret != -1 && !w->need_free)
1574 ret = wl_display_dispatch(private_client->display);
1576 clock_gettime(CLOCK_MONOTONIC, &tp);
1577 TDM_DBG("block during %d us",
1578 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1579 - (req_sec * 1000000 + req_usec));
1584 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1585 pthread_mutex_unlock(&private_client->lock);
1586 return TDM_ERROR_PROTOCOL_ERROR;
1589 pthread_mutex_unlock(&private_client->lock);
1591 return TDM_ERROR_NONE;
1593 /* LCOV_EXCL_STOP */
1597 tdm_client_vblank_is_waiting(tdm_client_vblank *vblank)
1599 tdm_private_client_vblank *private_vblank;
1601 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, 0);
1603 private_vblank = vblank;
1605 return (LIST_LENGTH(&private_vblank->wait_list) > 0) ? 1 : 0;
1609 tdm_client_voutput_cb_ack_message(void *data, struct wl_tdm_voutput *wl_voutput, uint32_t msg)
1611 tdm_private_client_voutput *private_voutput = data;
1613 private_voutput->msg = msg;
1616 static const struct wl_tdm_voutput_listener tdm_client_voutput_lisntener = {
1617 tdm_client_voutput_cb_ack_message
1620 tdm_client_voutput *
1621 tdm_client_create_voutput(tdm_client *client, const char *name, tdm_error *error)
1623 tdm_private_client *private_client;
1624 tdm_private_client_output *private_output;
1625 tdm_private_client_voutput *private_voutput;
1626 struct wl_proxy *wrapper;
1629 *error = TDM_ERROR_NONE;
1632 TDM_ERR("'!client' failed");
1634 *error = TDM_ERROR_INVALID_PARAMETER;
1639 TDM_ERR("'!name' failed");
1641 *error = TDM_ERROR_INVALID_PARAMETER;
1645 private_client = (tdm_private_client *)client;
1647 pthread_mutex_lock(&private_client->lock);
1649 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1651 *error = TDM_ERROR_PROTOCOL_ERROR;
1652 pthread_mutex_unlock(&private_client->lock);
1656 LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
1657 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
1659 *error = TDM_ERROR_INVALID_PARAMETER; // FIXME define new error type.
1660 pthread_mutex_unlock(&private_client->lock);
1665 wrapper = wl_proxy_create_wrapper(private_client->tdm);
1667 TDM_ERR("create virtual output wrapper failed");
1669 *error = TDM_ERROR_OUT_OF_MEMORY;
1670 pthread_mutex_unlock(&private_client->lock);
1674 wl_proxy_set_queue(wrapper, private_client->queue);
1676 private_voutput = calloc(1, sizeof *private_voutput);
1677 if (!private_voutput) {
1678 /* LOCV_EXCL_START */
1679 wl_proxy_wrapper_destroy(wrapper);
1680 TDM_ERR("alloc failed");
1682 *error = TDM_ERROR_OUT_OF_MEMORY;
1684 /* LOCV_EXCL_STOP */
1687 private_voutput->base.private_client = private_client;
1689 private_voutput->wl_voutput = wl_tdm_create_voutput((struct wl_tdm *)wrapper, private_voutput->base.name);
1690 wl_proxy_wrapper_destroy(wrapper);
1691 if (!private_voutput->wl_voutput) {
1692 /* LCOV_EXCL_START */
1693 TDM_ERR("couldn't create voutput resource");
1694 free(private_voutput);
1696 *error = TDM_ERROR_OUT_OF_MEMORY;
1697 pthread_mutex_unlock(&private_client->lock);
1699 /* LCOV_EXCL_STOP */
1702 wl_tdm_voutput_add_listener(private_voutput->wl_voutput,
1703 &tdm_client_voutput_lisntener, private_voutput);
1704 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1706 wl_proxy_set_queue((struct wl_proxy *)private_voutput->wl_voutput, NULL);
1708 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1709 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
1710 free(private_voutput);
1712 *error = TDM_ERROR_PROTOCOL_ERROR;
1713 pthread_mutex_unlock(&private_client->lock);
1717 if (private_voutput->msg != WL_TDM_VOUTPUT_MESSAGE_ADDED)
1719 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
1720 free(private_voutput);
1722 *error = TDM_ERROR_PROTOCOL_ERROR; // FIXME add new error type.
1723 pthread_mutex_unlock(&private_client->lock);
1727 pthread_mutex_unlock(&private_client->lock);
1729 return (tdm_client_voutput *)private_voutput;
1733 tdm_client_voutput_destroy(tdm_client_voutput *voutput)
1735 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)voutput;
1737 if (!private_voutput)
1740 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
1742 free(private_voutput);
1746 tdm_client_voutput_set_available_modes(tdm_client_voutput *voutput, const tdm_client_output_mode *modes, int count)
1748 tdm_private_client_voutput *private_voutput;
1750 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
1752 if ((count > 0) && (modes == NULL))
1753 return TDM_ERROR_INVALID_PARAMETER;
1755 private_voutput = (tdm_private_client_voutput *)voutput;
1757 if (private_voutput->base.connection == TDM_OUTPUT_CONN_STATUS_CONNECTED)
1758 return TDM_ERROR_BAD_REQUEST;
1760 if (private_voutput->available_modes.modes)
1761 free(private_voutput->available_modes.modes);
1763 private_voutput->available_modes.count = count;
1767 private_voutput->available_modes.modes = calloc(count, sizeof(tdm_client_output_mode));
1768 memcpy(private_voutput->available_modes.modes, modes, sizeof(tdm_client_output_mode) * count);
1771 return TDM_ERROR_NONE;
1775 tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, int mmWidth, int mmHeight)
1777 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
1778 TDM_RETURN_VAL_IF_FAIL(mmWidth > 0, TDM_ERROR_INVALID_PARAMETER);
1779 TDM_RETURN_VAL_IF_FAIL(mmHeight > 0, TDM_ERROR_INVALID_PARAMETER);
1781 return TDM_ERROR_NONE;
1785 tdm_client_voutput_get_client_output(tdm_client_voutput *voutput, tdm_error *error)
1787 tdm_private_client_voutput *private_voutput;
1790 *error = TDM_ERROR_NONE;
1794 TDM_ERR("'!voutput' failed");
1796 *error = TDM_ERROR_INVALID_PARAMETER;
1800 private_voutput = (tdm_private_client_voutput *)voutput;
1802 return &private_voutput->base;
1806 tdm_client_output_set_buffer_queue(tdm_client_output *output, void *queue, void *func)
1808 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1809 TDM_RETURN_VAL_IF_FAIL(queue != NULL, TDM_ERROR_INVALID_PARAMETER);
1810 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1812 return TDM_ERROR_NONE;
1816 tdm_client_output_get_available_modes(tdm_client_output *output, tdm_client_output_mode **modes, int *count)
1818 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1819 TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER);
1820 TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
1822 return TDM_ERROR_NONE;
1826 tdm_client_output_set_mode(tdm_client_output *output, const tdm_client_output_mode *mode)
1828 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1829 TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER);
1831 return TDM_ERROR_NONE;
1835 tdm_client_output_connect(tdm_client_output *output)
1837 tdm_private_client_output *private_output;
1838 tdm_private_client_voutput *private_voutput;
1839 tdm_client_output_mode *modes;
1842 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1844 private_output = (tdm_private_client_output *)output;
1845 private_voutput = (tdm_private_client_voutput *)output;
1847 TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_CONNECTED,
1848 TDM_ERROR_BAD_REQUEST);
1850 private_output->connection = TDM_OUTPUT_CONN_STATUS_CONNECTED;
1852 modes = private_voutput->available_modes.modes;
1853 for (i = 0; i < private_voutput->available_modes.count; i++)
1855 wl_tdm_voutput_set_available_modes(private_voutput->wl_voutput, i,
1856 modes[i].clock, modes[i].hdisplay,
1857 modes[i].hsync_start, modes[i].hsync_end,
1858 modes[i].htotal, modes[i].hskew,
1859 modes[i].vdisplay, modes[i].vsync_start,
1860 modes[i].vsync_end, modes[i].vtotal,
1861 modes[i].vscan, modes[i].vrefresh,
1862 modes[i].flags, modes[i].type,
1866 wl_tdm_voutput_connect(private_voutput->wl_voutput);
1868 return TDM_ERROR_NONE;
1872 tdm_client_output_disconnect(tdm_client_output *output)
1874 tdm_private_client_voutput *private_voutput;
1875 tdm_private_client_output *private_output;
1877 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1879 private_output = (tdm_private_client_output *)output;
1880 private_voutput = (tdm_private_client_voutput *)output;
1882 TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED,
1883 TDM_ERROR_BAD_REQUEST);
1885 private_output->connection = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
1887 wl_tdm_voutput_disconnect(private_voutput->wl_voutput);
1889 return TDM_ERROR_NONE;