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 **************************************************************************/
36 #define WL_HIDE_DEPRECATED
49 #include <tdm-client-protocol.h>
51 #include "tdm_client.h"
53 #include "tdm_macro.h"
56 #include "tdm_private.h"
57 #include <tbm_surface_internal.h>
59 #define TDM_ARRAY_NTH_DATA(array, type, n) (((type*)((array)->data)) + n)
61 typedef struct _tdm_private_client_vblank tdm_private_client_vblank;
62 typedef struct _tdm_private_client_voutput tdm_private_client_voutput;
64 typedef struct _tdm_private_client {
67 struct wl_display *display;
68 struct wl_event_queue *queue;
69 struct wl_registry *registry;
71 struct list_head output_list;
72 struct list_head voutput_list;
74 unsigned int enable_ttrace;
77 tdm_private_client_vblank *temp_vblank;
80 typedef struct _tdm_private_client_output {
81 struct list_head link;
83 tdm_private_client *private_client;
85 char name[TDM_NAME_LEN];
86 struct wl_tdm_output *output;
90 tdm_output_conn_status connection;
92 struct list_head vblank_list;
93 struct list_head change_handler_list;
96 unsigned int watch_output_changes;
98 tdm_private_client_voutput *voutput;
99 } tdm_private_client_output;
101 typedef struct _tdm_private_client_buffer {
102 struct list_head link;
103 struct wl_buffer *wl_buffer;
104 } tdm_private_client_buffer;
106 struct _tdm_private_client_voutput {
107 struct list_head link;
108 struct wl_tdm_voutput *wl_voutput;
109 struct list_head commit_handler_list;
113 tdm_client_output_mode *modes;
116 unsigned int mmwidth;
117 unsigned int mmheight;
121 struct list_head buffer_list;
123 tdm_private_client_buffer *attach_buffer;
125 tdm_private_client *private_client;
126 tdm_private_client_output *private_output;
127 char name[TDM_NAME_LEN];
131 struct _tdm_private_client_vblank {
132 tdm_private_client_output *private_output;
134 struct wl_tdm_vblank *vblank;
135 struct list_head wait_list;
137 char name[TDM_NAME_LEN];
141 unsigned int enable_fake;
142 unsigned int enable_ttrace;
144 unsigned int started;
150 struct list_head link;
153 typedef struct _tdm_client_output_handler_info {
154 tdm_private_client_output *private_output;
156 tdm_client_output_change_handler func;
159 struct list_head link;
160 struct list_head call_link;
161 } tdm_client_output_handler_info;
163 typedef struct _tdm_client_wait_info {
164 tdm_private_client_vblank *private_vblank;
166 tdm_client_vblank_handler func;
173 struct list_head link;
174 struct list_head call_link;
175 } tdm_client_wait_info;
177 typedef struct _tdm_client_voutput_commit_handler_info
179 tdm_private_client_voutput *private_voutput;
181 tdm_client_voutput_commit_handler func;
184 struct list_head link;
185 struct list_head call_link;
186 } tdm_client_voutput_commit_handler_info;
189 _tdm_client_check_wl_error(tdm_private_client *private_client, const char *func, int line)
192 const struct wl_interface *intf;
195 err = wl_display_get_error(private_client->display);
199 if (err == EINVAL || err == ENOMEM || err == EFAULT || err == EPROTO) {
200 ec = wl_display_get_protocol_error(private_client->display, &intf, &id);
201 TDM_ERR("[%s,%d] errno(%d) Got protocol error '%u' on interface '%s' (object '%u')",
202 func, line, err, ec, (intf) ? intf->name : "destroyed", id);
204 TDM_ERR("[%s,%d] errno(%d)", func, line, err);
210 #define CHECK_WL_PROTOCOL_ERROR(pc) _tdm_client_check_wl_error(pc, __FUNCTION__, __LINE__)
213 _tdm_client_vblank_cb_stamp(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t stamp)
215 tdm_private_client_vblank *private_vblank = data;
216 tdm_private_client *private_client;
218 TDM_RETURN_IF_FAIL(private_vblank != NULL);
220 private_vblank->stamp = stamp;
222 TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
223 private_client = private_vblank->private_output->private_client;
225 private_client->stamp = stamp;
228 /* LCOV_EXCL_START */
230 _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank,
231 uint32_t req_id, uint32_t sequence, uint32_t tv_sec,
232 uint32_t tv_usec, uint32_t error)
234 tdm_private_client_vblank *private_vblank = data;
235 tdm_private_client *private_client;
236 tdm_client_wait_info *w = NULL, *wait_info = NULL;
238 TDM_RETURN_IF_FAIL(private_vblank != NULL);
240 private_client = private_vblank->private_output->private_client;
242 private_vblank->last_time = TDM_TIME(tv_sec, tv_usec);
244 TDM_DBG("vblank(%p) req_id(%u) sequence(%u) time(%.6f)",
245 private_vblank, req_id, sequence, TDM_TIME(tv_sec, tv_usec));
247 LIST_FOR_EACH_ENTRY(w, &private_vblank->wait_list, link) {
248 if (w->req_id != req_id)
256 TDM_ERR("no wait infomation for req_id(%d)", req_id);
260 if (private_vblank->enable_ttrace)
261 TDM_TRACE_ASYNC_END((int)wait_info->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
263 if (wait_info->req_time >= private_vblank->last_time)
264 TDM_WRN("'req(%.6f) < last(%.6f)' failed. error(%d)", wait_info->req_time, private_vblank->last_time, error);
266 if (wait_info->need_free)
267 LIST_DEL(&wait_info->link);
269 if (wait_info->func) {
270 pthread_mutex_unlock(&private_client->lock);
271 wait_info->func(private_vblank, error, sequence, tv_sec, tv_usec, wait_info->user_data);
272 pthread_mutex_lock(&private_client->lock);
275 if (wait_info->need_free)
278 wait_info->need_free = 1;
282 /* LCOV_EXCL_START */
284 _tdm_client_vblank_cb_ttrace(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t enable)
286 tdm_private_client_vblank *private_vblank = data;
287 tdm_private_client *private_client;
289 TDM_RETURN_IF_FAIL(private_vblank != NULL);
291 private_vblank->enable_ttrace = enable;
293 TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
294 private_client = private_vblank->private_output->private_client;
296 private_client->enable_ttrace = enable;
300 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
301 _tdm_client_vblank_cb_stamp,
302 _tdm_client_vblank_cb_done,
303 _tdm_client_vblank_cb_ttrace,
307 _tdm_client_output_destroy(tdm_private_client_output *private_output)
309 tdm_private_client_vblank *v = NULL, *vv = NULL;
310 tdm_client_output_handler_info *h = NULL, *hh = NULL;
312 LIST_DEL(&private_output->link);
314 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_list, link) {
315 TDM_ERR("vblanks SHOULD be destroyed first!");
317 v->private_output = NULL;
320 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list, link) {
325 wl_tdm_output_destroy(private_output->output);
327 free(private_output);
331 _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output,
332 uint32_t width, uint32_t height, uint32_t refresh, uint32_t error)
334 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
336 TDM_RETURN_IF_FAIL(private_output != NULL);
338 private_output->width = width;
339 private_output->height = height;
340 private_output->refresh = refresh;
342 if (error != TDM_ERROR_NONE)
343 TDM_INFO("mode event error: %d", error);
345 TDM_DBG("private_output(%p) wl_tbm_output@%d width(%d) height(%d) refresh(%d)",
346 private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output),
347 width, height, refresh);
351 _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
353 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
354 tdm_private_client *private_client;
355 tdm_client_output_handler_info *h = NULL, *hh = NULL;
357 struct list_head call_list;
359 TDM_RETURN_IF_FAIL(private_output != NULL);
361 private_client = private_output->private_client;
363 if (private_output->connection == value)
366 private_output->connection = value;
368 if (error != TDM_ERROR_NONE)
369 TDM_INFO("connection event error: %d", error);
371 TDM_DBG("private_output(%p) wl_tbm_output@%d connection(%d)",
373 wl_proxy_get_id((struct wl_proxy*)private_output->output),
376 LIST_INITHEAD(&call_list);
378 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
379 LIST_ADDTAIL(&h->call_link, &call_list);
383 pthread_mutex_unlock(&private_client->lock);
384 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
386 h->func(private_output, TDM_OUTPUT_CHANGE_CONNECTION, v, h->user_data);
388 pthread_mutex_lock(&private_client->lock);
392 _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
394 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
395 tdm_private_client *private_client;
396 tdm_client_output_handler_info *h = NULL, *hh = NULL;
398 struct list_head call_list;
400 TDM_RETURN_IF_FAIL(private_output != NULL);
402 private_client = private_output->private_client;
404 /* If value is extended value, we handle it as DPMS on in client side
405 * The extended DPMS value is valid only in server side.
406 * Or, need to export to client side also?
408 if (value > TDM_OUTPUT_DPMS_OFF)
409 value = TDM_OUTPUT_DPMS_ON;
411 if (private_output->dpms == value)
414 private_output->dpms = value;
416 if (error != TDM_ERROR_NONE)
417 TDM_INFO("dpms event error: %d", error);
419 TDM_DBG("private_output(%p) wl_tbm_output@%d dpms(%d)",
421 wl_proxy_get_id((struct wl_proxy*)private_output->output),
424 LIST_INITHEAD(&call_list);
426 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
427 LIST_ADDTAIL(&h->call_link, &call_list);
431 pthread_mutex_unlock(&private_client->lock);
432 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
434 h->func(private_output, TDM_OUTPUT_CHANGE_DPMS, v, h->user_data);
436 pthread_mutex_lock(&private_client->lock);
439 static const struct wl_tdm_output_listener tdm_client_output_listener = {
440 _tdm_client_output_cb_mode,
441 _tdm_client_output_cb_connection,
442 _tdm_client_output_cb_dpms,
446 _tdm_client_cb_global(void *data, struct wl_registry *registry,
447 uint32_t name, const char *interface,
450 tdm_private_client *private_client = data;
452 if (strncmp(interface, "wl_tdm", 6) == 0) {
453 private_client->tdm =
454 wl_registry_bind(registry, name, &wl_tdm_interface, version);
455 TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
457 wl_display_flush(private_client->display);
461 /* LCOV_EXCL_START */
463 _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
468 static const struct wl_registry_listener tdm_client_registry_listener = {
469 _tdm_client_cb_global,
470 _tdm_client_cb_global_remove
474 tdm_client_create(tdm_error *error)
476 tdm_private_client *private_client;
478 private_client = calloc(1, sizeof *private_client);
479 if (!private_client) {
480 /* LCOV_EXCL_START */
482 TDM_ERR("alloc failed");
484 *error = TDM_ERROR_OUT_OF_MEMORY;
490 if (pthread_mutex_init(&private_client->lock, NULL)) {
491 TDM_ERR("mutex init failed: %m");
492 free(private_client);
494 *error = TDM_ERROR_OUT_OF_MEMORY;
498 LIST_INITHEAD(&private_client->output_list);
499 LIST_INITHEAD(&private_client->voutput_list);
501 private_client->display = wl_display_connect("tdm-socket");
502 TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed);
504 private_client->queue = wl_display_create_queue(private_client->display);
505 TDM_GOTO_IF_FAIL(private_client->queue != NULL, create_failed);
507 private_client->registry = wl_display_get_registry(private_client->display);
508 TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed);
510 wl_registry_add_listener(private_client->registry,
511 &tdm_client_registry_listener, private_client);
512 wl_display_roundtrip(private_client->display);
514 if (CHECK_WL_PROTOCOL_ERROR(private_client))
517 /* check global objects */
518 TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed);
521 *error = TDM_ERROR_NONE;
523 return (tdm_client*)private_client;
525 tdm_client_destroy((tdm_client*)private_client);
527 *error = TDM_ERROR_OPERATION_FAILED;
532 tdm_client_destroy(tdm_client *client)
534 tdm_private_client *private_client = (tdm_private_client*)client;
535 tdm_private_client_output *o = NULL, *oo = NULL;
536 tdm_private_client_voutput *vo = NULL, *voo = NULL;
541 pthread_mutex_lock(&private_client->lock);
543 if (private_client->temp_vblank) {
544 pthread_mutex_unlock(&private_client->lock);
545 tdm_client_vblank_destroy(private_client->temp_vblank);
546 pthread_mutex_lock(&private_client->lock);
549 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_client->output_list, link) {
550 _tdm_client_output_destroy(o);
553 LIST_FOR_EACH_ENTRY_SAFE(vo, voo, &private_client->voutput_list, link) {
554 tdm_client_voutput_destroy(vo);
557 if (private_client->tdm)
558 wl_tdm_destroy(private_client->tdm);
559 if (private_client->registry)
560 wl_registry_destroy(private_client->registry);
561 if (private_client->queue)
562 wl_event_queue_destroy(private_client->queue);
563 if (private_client->display)
564 wl_display_disconnect(private_client->display);
566 pthread_mutex_unlock(&private_client->lock);
567 pthread_mutex_destroy(&private_client->lock);
569 free(private_client);
573 tdm_client_get_fd(tdm_client *client, int *fd)
575 tdm_private_client *private_client;
577 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
578 TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_ERROR_INVALID_PARAMETER);
580 private_client = (tdm_private_client*)client;
582 pthread_mutex_lock(&private_client->lock);
584 *fd = wl_display_get_fd(private_client->display);
586 pthread_mutex_unlock(&private_client->lock);
589 return TDM_ERROR_OPERATION_FAILED;
591 return TDM_ERROR_NONE;
595 tdm_client_handle_events(tdm_client *client)
597 tdm_private_client *private_client;
599 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
601 /* LCOV_EXCL_START */
602 private_client = (tdm_private_client*)client;
604 pthread_mutex_lock(&private_client->lock);
606 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
607 pthread_mutex_unlock(&private_client->lock);
608 return TDM_ERROR_PROTOCOL_ERROR;
611 if (private_client->enable_ttrace)
612 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
614 wl_display_dispatch(private_client->display);
616 if (private_client->enable_ttrace)
617 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
619 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
620 pthread_mutex_unlock(&private_client->lock);
621 return TDM_ERROR_PROTOCOL_ERROR;
624 pthread_mutex_unlock(&private_client->lock);
626 return TDM_ERROR_NONE;
631 _tdm_client_poll(struct wl_display *display, short int events, int timeout)
634 struct pollfd pfd[1];
636 pfd[0].fd = wl_display_get_fd(display);
637 pfd[0].events = events;
639 ret = poll(pfd, 1, timeout);
640 } while (ret == -1 && errno == EINTR);
646 _tdm_client_dispatch_timeout(tdm_private_client *private_client, int timeout)
649 struct wl_display *display = private_client->display;
651 if (wl_display_prepare_read(display) == -1) {
652 if (wl_display_dispatch_pending(display) > 0)
653 return TDM_ERROR_NONE;
655 return TDM_ERROR_OPERATION_FAILED;
659 ret = wl_display_flush(display);
661 if (ret != -1 || errno != EAGAIN)
664 if (_tdm_client_poll(display, POLLOUT, -1) == -1) {
665 wl_display_cancel_read(display);
666 TDM_ERR("_tdm_client_poll failed");
667 return TDM_ERROR_OPERATION_FAILED;
671 /* Don't stop if flushing hits an EPIPE; continue so we can read any
672 * protocol error that may have triggered it. */
673 if (ret < 0 && errno != EPIPE) {
674 TDM_ERR("ret(%d) errno(%d)", ret, errno);
675 wl_display_cancel_read(display);
676 return TDM_ERROR_OPERATION_FAILED;
679 ret = _tdm_client_poll(display, POLLIN, timeout);
681 wl_display_cancel_read(display);
683 TDM_ERR("_tdm_client_poll timeout.");
684 return TDM_ERROR_TIMEOUT;
686 TDM_ERR("_tdm_client_poll failed. (ret:%d)", ret);
687 return TDM_ERROR_OPERATION_FAILED;
691 if (wl_display_read_events(display) == -1) {
692 TDM_ERR("wl_display_read_events failed");
693 return TDM_ERROR_OPERATION_FAILED;
696 ret = wl_display_dispatch_pending(display);
699 TDM_ERR("_tdm_client_dispatch_timeout failed");
700 return TDM_ERROR_OPERATION_FAILED;
703 return TDM_ERROR_NONE;
707 tdm_client_handle_events_timeout(tdm_client *client, int ms_timeout)
709 tdm_private_client *private_client;
711 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
713 private_client = (tdm_private_client*)client;
715 pthread_mutex_lock(&private_client->lock);
717 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
718 pthread_mutex_unlock(&private_client->lock);
719 return TDM_ERROR_PROTOCOL_ERROR;
722 if (private_client->enable_ttrace)
723 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
725 ret = _tdm_client_dispatch_timeout(private_client, ms_timeout);
727 if (private_client->enable_ttrace)
728 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
730 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
731 pthread_mutex_unlock(&private_client->lock);
732 return TDM_ERROR_PROTOCOL_ERROR;
735 pthread_mutex_unlock(&private_client->lock);
740 typedef struct _tdm_client_vblank_temp {
741 tdm_client_vblank_handler2 func;
743 } tdm_client_vblank_temp;
745 /* LCOV_EXCL_START */
747 _tdm_client_vblank_handler_temp(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
748 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
750 tdm_client_vblank_temp *vblank_temp = user_data;
752 TDM_RETURN_IF_FAIL(vblank_temp != NULL);
753 TDM_RETURN_IF_FAIL(vblank != NULL);
755 if (vblank_temp->func)
756 vblank_temp->func(sequence, tv_sec, tv_usec, vblank_temp->user_data);
762 /* LCOV_EXCL_START */ /* deprecated */
764 tdm_client_wait_vblank(tdm_client *client, char *name,
765 int sw_timer, int interval, int sync,
766 tdm_client_vblank_handler2 func, void *user_data)
768 tdm_private_client *private_client = (tdm_private_client*)client;
769 tdm_client_output *output;
770 tdm_client_vblank_temp *vblank_temp;
773 TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
774 TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
775 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
777 if (CHECK_WL_PROTOCOL_ERROR(private_client))
778 return TDM_ERROR_PROTOCOL_ERROR;
780 if (!private_client->temp_vblank) {
781 output = tdm_client_get_output(client, name, &ret);
782 TDM_RETURN_VAL_IF_FAIL(output != NULL, ret);
784 private_client->temp_vblank = tdm_client_output_create_vblank(output, &ret);
785 TDM_RETURN_VAL_IF_FAIL(private_client->temp_vblank != NULL, ret);
788 tdm_client_vblank_set_enable_fake(private_client->temp_vblank, sw_timer);
789 tdm_client_vblank_set_sync(private_client->temp_vblank, sync);
791 vblank_temp = calloc(1, sizeof *vblank_temp);
792 TDM_RETURN_VAL_IF_FAIL(vblank_temp != NULL, TDM_ERROR_OUT_OF_MEMORY);
794 vblank_temp->func = func;
795 vblank_temp->user_data = user_data;
797 return tdm_client_vblank_wait(private_client->temp_vblank, interval, _tdm_client_vblank_handler_temp, vblank_temp);
802 tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
804 tdm_private_client *private_client;
805 tdm_private_client_output *private_output = NULL;
806 struct wl_proxy *wrapper;
809 *error = TDM_ERROR_NONE;
812 TDM_ERR("'!client' failed");
814 *error = TDM_ERROR_INVALID_PARAMETER;
818 private_client = (tdm_private_client*)client;
820 pthread_mutex_lock(&private_client->lock);
822 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
824 *error = TDM_ERROR_PROTOCOL_ERROR;
825 pthread_mutex_unlock(&private_client->lock);
831 } else if (!strncmp(name, "primary", 7) || !strncmp(name, "default", 7)) {
832 TDM_DBG("get primary or default output");
834 tdm_private_client_voutput *private_voutput = NULL;
837 LIST_FOR_EACH_ENTRY(private_voutput, &private_client->voutput_list, link) {
838 if (!strncmp(private_voutput->name, name, TDM_NAME_LEN)) {
845 *error = TDM_ERROR_INVALID_PARAMETER;
846 pthread_mutex_unlock(&private_client->lock);
851 LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
852 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
853 pthread_mutex_unlock(&private_client->lock);
854 return (tdm_client_output*)private_output;
858 wrapper = wl_proxy_create_wrapper(private_client->tdm);
860 TDM_ERR("create output_wrapper failed");
862 *error = TDM_ERROR_OUT_OF_MEMORY;
863 pthread_mutex_unlock(&private_client->lock);
867 wl_proxy_set_queue(wrapper, private_client->queue);
869 private_output = calloc(1, sizeof *private_output);
870 if (!private_output) {
871 /* LCOV_EXCL_START */
872 wl_proxy_wrapper_destroy(wrapper);
873 TDM_ERR("alloc failed");
875 *error = TDM_ERROR_OUT_OF_MEMORY;
876 pthread_mutex_unlock(&private_client->lock);
882 private_output->private_client = private_client;
884 snprintf(private_output->name, TDM_NAME_LEN, "%s", name);
885 private_output->output = wl_tdm_create_output((struct wl_tdm *)wrapper, private_output->name);
886 wl_proxy_wrapper_destroy(wrapper);
887 if (!private_output->output) {
888 /* LCOV_EXCL_START */
890 TDM_ERR("couldn't create output resource");
891 free(private_output);
893 *error = TDM_ERROR_OUT_OF_MEMORY;
894 pthread_mutex_unlock(&private_client->lock);
900 LIST_INITHEAD(&private_output->vblank_list);
901 LIST_INITHEAD(&private_output->change_handler_list);
903 wl_tdm_output_add_listener(private_output->output,
904 &tdm_client_output_listener, private_output);
905 wl_display_roundtrip_queue(private_client->display, private_client->queue);
907 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
909 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
910 wl_tdm_output_destroy(private_output->output);
911 free(private_output);
913 *error = TDM_ERROR_PROTOCOL_ERROR;
914 pthread_mutex_unlock(&private_client->lock);
918 LIST_ADDTAIL(&private_output->link, &private_client->output_list);
920 pthread_mutex_unlock(&private_client->lock);
922 return (tdm_client_output*)private_output;
926 tdm_client_output_add_change_handler(tdm_client_output *output,
927 tdm_client_output_change_handler func,
930 tdm_private_client_output *private_output;
931 tdm_private_client *private_client;
932 tdm_client_output_handler_info *h = NULL;
934 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
935 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
937 private_output = (tdm_private_client_output*)output;
938 private_client = private_output->private_client;
940 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
941 if (h->func == func && h->user_data == user_data) {
942 TDM_ERR("can't add twice");
943 return TDM_ERROR_BAD_REQUEST;
947 h = calloc(1, sizeof *h);
948 TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
950 pthread_mutex_lock(&private_client->lock);
952 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
954 pthread_mutex_unlock(&private_client->lock);
955 return TDM_ERROR_PROTOCOL_ERROR;
958 if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
959 wl_tdm_output_watch_output_changes(private_output->output, 1);
960 wl_display_roundtrip_queue(private_client->display, private_client->queue);
962 /* TODO: this is very tricky.
963 * If a client adds the change_handler, we might be able to guess that
964 * the client will watch the tdm client's fd and handle tdm events in
965 * event loop. Otherwise, we CAN'T make sure if a client has event loop
966 * which handles tdm events.
968 private_output->watch_output_changes = 1;
971 h->private_output = private_output;
973 h->user_data = user_data;
974 LIST_ADDTAIL(&h->link, &private_output->change_handler_list);
975 LIST_INITHEAD(&h->call_link);
977 pthread_mutex_unlock(&private_client->lock);
979 return TDM_ERROR_NONE;
983 tdm_client_output_remove_change_handler(tdm_client_output *output,
984 tdm_client_output_change_handler func,
987 tdm_private_client_output *private_output;
988 tdm_private_client *private_client;
989 tdm_client_output_handler_info *h = NULL;
991 TDM_RETURN_IF_FAIL(output != NULL);
992 TDM_RETURN_IF_FAIL(func != NULL);
994 private_output = (tdm_private_client_output*)output;
995 private_client = private_output->private_client;
997 pthread_mutex_lock(&private_client->lock);
999 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
1000 if (h->func != func || h->user_data != user_data)
1006 if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
1007 private_output->watch_output_changes = 0;
1008 if (!CHECK_WL_PROTOCOL_ERROR(private_client)) {
1009 wl_tdm_output_watch_output_changes(private_output->output, 0);
1010 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1014 pthread_mutex_unlock(&private_client->lock);
1019 pthread_mutex_unlock(&private_client->lock);
1023 tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refresh)
1025 tdm_private_client_output *private_output;
1026 tdm_private_client *private_client;
1028 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1029 TDM_RETURN_VAL_IF_FAIL(refresh != NULL, TDM_ERROR_INVALID_PARAMETER);
1031 private_output = (tdm_private_client_output*)output;
1032 private_client = private_output->private_client;
1034 pthread_mutex_lock(&private_client->lock);
1036 if (private_output->watch_output_changes) {
1037 *refresh = private_output->refresh;
1038 pthread_mutex_unlock(&private_client->lock);
1039 return TDM_ERROR_NONE;
1042 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1043 pthread_mutex_unlock(&private_client->lock);
1044 return TDM_ERROR_PROTOCOL_ERROR;
1047 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1048 wl_tdm_output_get_mode(private_output->output);
1049 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1050 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1052 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1053 pthread_mutex_unlock(&private_client->lock);
1054 return TDM_ERROR_PROTOCOL_ERROR;
1057 *refresh = private_output->refresh;
1059 pthread_mutex_unlock(&private_client->lock);
1061 return TDM_ERROR_NONE;
1065 tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_status *status)
1067 tdm_private_client_output *private_output;
1068 tdm_private_client *private_client;
1070 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1071 TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
1073 private_output = (tdm_private_client_output*)output;
1074 private_client = private_output->private_client;
1076 pthread_mutex_lock(&private_client->lock);
1078 if (private_output->watch_output_changes) {
1079 *status = private_output->connection;
1080 pthread_mutex_unlock(&private_client->lock);
1081 return TDM_ERROR_NONE;
1084 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1085 pthread_mutex_unlock(&private_client->lock);
1086 return TDM_ERROR_PROTOCOL_ERROR;
1089 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1090 wl_tdm_output_get_connection(private_output->output);
1091 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1092 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1094 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1095 pthread_mutex_unlock(&private_client->lock);
1096 return TDM_ERROR_PROTOCOL_ERROR;
1099 *status = private_output->connection;
1101 pthread_mutex_unlock(&private_client->lock);
1103 return TDM_ERROR_NONE;
1107 tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
1109 tdm_private_client_output *private_output;
1110 tdm_private_client *private_client;
1112 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1113 TDM_RETURN_VAL_IF_FAIL(dpms != NULL, TDM_ERROR_INVALID_PARAMETER);
1115 private_output = (tdm_private_client_output*)output;
1116 private_client = private_output->private_client;
1118 if (private_output->watch_output_changes) {
1119 *dpms = private_output->dpms;
1120 return TDM_ERROR_NONE;
1123 pthread_mutex_lock(&private_client->lock);
1125 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1126 pthread_mutex_unlock(&private_client->lock);
1127 return TDM_ERROR_PROTOCOL_ERROR;
1130 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1131 wl_tdm_output_get_dpms(private_output->output);
1132 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1133 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1135 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1136 pthread_mutex_unlock(&private_client->lock);
1137 return TDM_ERROR_PROTOCOL_ERROR;
1140 *dpms = private_output->dpms;
1142 pthread_mutex_unlock(&private_client->lock);
1144 return TDM_ERROR_NONE;
1148 tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
1150 tdm_private_client *private_client;
1151 tdm_private_client_output *private_output;
1152 tdm_private_client_vblank *private_vblank;
1153 struct wl_proxy *wrapper;
1156 *error = TDM_ERROR_NONE;
1159 TDM_ERR("'!output' failed");
1161 *error = TDM_ERROR_INVALID_PARAMETER;
1165 private_output = (tdm_private_client_output*)output;
1166 private_client = private_output->private_client;
1168 pthread_mutex_lock(&private_client->lock);
1170 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1172 *error = TDM_ERROR_PROTOCOL_ERROR;
1173 pthread_mutex_unlock(&private_client->lock);
1177 wrapper = wl_proxy_create_wrapper(private_output->output);
1179 TDM_ERR("create output_wrapper failed");
1181 *error = TDM_ERROR_OUT_OF_MEMORY;
1182 pthread_mutex_unlock(&private_client->lock);
1186 wl_proxy_set_queue(wrapper, private_client->queue);
1188 private_vblank = calloc(1, sizeof *private_vblank);
1189 if (!private_vblank) {
1190 /* LCOV_EXCL_START */
1192 TDM_ERR("alloc failed");
1193 wl_proxy_wrapper_destroy(wrapper);
1195 *error = TDM_ERROR_OUT_OF_MEMORY;
1196 pthread_mutex_unlock(&private_client->lock);
1199 /* LCOV_EXCL_STOP */
1202 private_vblank->private_output = private_output;
1204 private_vblank->vblank = wl_tdm_output_create_vblank((struct wl_tdm_output*)wrapper);
1205 wl_proxy_wrapper_destroy(wrapper);
1206 if (!private_vblank->vblank) {
1207 /* LCOV_EXCL_START */
1209 TDM_ERR("couldn't create vblank resource");
1210 free(private_vblank);
1212 *error = TDM_ERROR_OUT_OF_MEMORY;
1213 pthread_mutex_unlock(&private_client->lock);
1216 /* LCOV_EXCL_STOP */
1220 private_vblank->fps = private_output->refresh;
1221 private_vblank->offset = 0;
1222 private_vblank->enable_fake = 0;
1224 LIST_INITHEAD(&private_vblank->wait_list);
1226 wl_tdm_vblank_add_listener(private_vblank->vblank,
1227 &tdm_client_vblank_listener, private_vblank);
1228 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1230 wl_proxy_set_queue((struct wl_proxy *)private_vblank->vblank, NULL);
1232 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1233 wl_tdm_vblank_destroy(private_vblank->vblank);
1234 free(private_vblank);
1236 *error = TDM_ERROR_PROTOCOL_ERROR;
1237 pthread_mutex_unlock(&private_client->lock);
1241 LIST_ADDTAIL(&private_vblank->link, &private_output->vblank_list);
1243 pthread_mutex_unlock(&private_client->lock);
1245 return (tdm_client_vblank*)private_vblank;
1249 tdm_client_vblank_destroy(tdm_client_vblank *vblank)
1251 tdm_private_client_vblank *private_vblank;
1252 tdm_private_client *private_client;
1253 tdm_client_wait_info *w = NULL, *ww = NULL;
1255 TDM_RETURN_IF_FAIL(vblank != NULL);
1257 private_vblank = vblank;
1258 private_client = private_vblank->private_output->private_client;
1260 pthread_mutex_lock(&private_client->lock);
1262 LIST_DEL(&private_vblank->link);
1264 LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
1269 wl_tdm_vblank_destroy(private_vblank->vblank);
1271 free(private_vblank);
1273 pthread_mutex_unlock(&private_client->lock);
1277 tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name)
1279 tdm_private_client_vblank *private_vblank;
1280 tdm_private_client *private_client;
1282 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1284 private_vblank = vblank;
1285 private_client = private_vblank->private_output->private_client;
1287 pthread_mutex_lock(&private_client->lock);
1289 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1290 pthread_mutex_unlock(&private_client->lock);
1291 return TDM_ERROR_PROTOCOL_ERROR;
1295 name = TDM_VBLANK_DEFAULT_NAME;
1297 strncpy(private_vblank->name, name, TDM_NAME_LEN - 1);
1298 private_vblank->name[TDM_NAME_LEN - 1] = '\0';
1300 wl_tdm_vblank_set_name(private_vblank->vblank, private_vblank->name);
1302 pthread_mutex_unlock(&private_client->lock);
1304 return TDM_ERROR_NONE;
1308 tdm_client_vblank_set_sync(tdm_client_vblank *vblank, unsigned int sync)
1310 tdm_private_client_vblank *private_vblank;
1311 tdm_private_client *private_client;
1313 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1315 private_vblank = vblank;
1316 private_client = private_vblank->private_output->private_client;
1318 pthread_mutex_lock(&private_client->lock);
1319 private_vblank->sync = sync;
1320 pthread_mutex_unlock(&private_client->lock);
1322 return TDM_ERROR_NONE;
1326 tdm_client_vblank_set_fps(tdm_client_vblank *vblank, unsigned int fps)
1328 tdm_private_client_vblank *private_vblank;
1329 tdm_private_client *private_client;
1331 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1332 TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER);
1334 private_vblank = vblank;
1335 private_client = private_vblank->private_output->private_client;
1337 pthread_mutex_lock(&private_client->lock);
1339 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1340 pthread_mutex_unlock(&private_client->lock);
1341 return TDM_ERROR_PROTOCOL_ERROR;
1344 if (private_vblank->fps == fps) {
1345 pthread_mutex_unlock(&private_client->lock);
1346 return TDM_ERROR_NONE;
1349 private_vblank->fps = fps;
1351 wl_tdm_vblank_set_fps(private_vblank->vblank, fps);
1353 pthread_mutex_unlock(&private_client->lock);
1355 return TDM_ERROR_NONE;
1359 tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms)
1361 tdm_private_client_vblank *private_vblank;
1362 tdm_private_client *private_client;
1364 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1366 private_vblank = vblank;
1367 TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
1369 private_client = private_vblank->private_output->private_client;
1371 pthread_mutex_lock(&private_client->lock);
1373 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1374 pthread_mutex_unlock(&private_client->lock);
1375 return TDM_ERROR_PROTOCOL_ERROR;
1378 if (private_vblank->offset == offset_ms) {
1379 pthread_mutex_unlock(&private_client->lock);
1380 return TDM_ERROR_NONE;
1383 private_vblank->offset = offset_ms;
1385 wl_tdm_vblank_set_offset(private_vblank->vblank, offset_ms);
1387 pthread_mutex_unlock(&private_client->lock);
1389 return TDM_ERROR_NONE;
1393 tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable_fake)
1395 tdm_private_client_vblank *private_vblank;
1396 tdm_private_client *private_client;
1398 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1400 private_vblank = vblank;
1401 private_client = private_vblank->private_output->private_client;
1403 pthread_mutex_lock(&private_client->lock);
1405 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1406 pthread_mutex_unlock(&private_client->lock);
1407 return TDM_ERROR_PROTOCOL_ERROR;
1410 if (private_vblank->enable_fake == enable_fake) {
1411 pthread_mutex_unlock(&private_client->lock);
1412 return TDM_ERROR_NONE;
1415 private_vblank->enable_fake = enable_fake;
1417 wl_tdm_vblank_set_enable_fake(private_vblank->vblank, enable_fake);
1419 pthread_mutex_unlock(&private_client->lock);
1421 return TDM_ERROR_NONE;
1425 tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_client_vblank_handler func, void *user_data)
1427 tdm_private_client *private_client;
1428 tdm_private_client_output *private_output;
1429 tdm_private_client_vblank *private_vblank;
1430 tdm_client_wait_info *w;
1432 unsigned int req_sec, req_usec;
1435 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1436 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1437 /* can't support "interval 0" and "getting current_msc" things because
1438 * there is a socket communication between TDM client and server. It's impossible
1439 * to return the current msc or sequence immediately.
1441 TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
1443 private_vblank = vblank;
1444 private_output = private_vblank->private_output;
1445 private_client = private_output->private_client;
1447 pthread_mutex_lock(&private_client->lock);
1449 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1450 pthread_mutex_unlock(&private_client->lock);
1451 return TDM_ERROR_PROTOCOL_ERROR;
1454 if (!private_vblank->started)
1455 private_vblank->started = 1;
1457 if (!private_vblank->enable_fake) {
1458 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1459 TDM_ERR("output disconnected");
1460 pthread_mutex_unlock(&private_client->lock);
1461 return TDM_ERROR_OUTPUT_DISCONNECTED;
1463 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1464 TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1465 pthread_mutex_unlock(&private_client->lock);
1466 return TDM_ERROR_DPMS_OFF;
1470 w = calloc(1, sizeof *w);
1472 /* LCOV_EXCL_START */
1474 TDM_ERR("alloc failed");
1475 pthread_mutex_unlock(&private_client->lock);
1476 return TDM_ERROR_OUT_OF_MEMORY;
1478 /* LCOV_EXCL_STOP */
1481 w->private_vblank = private_vblank;
1483 w->user_data = user_data;
1485 LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1486 LIST_INITHEAD(&w->call_link);
1488 clock_gettime(CLOCK_MONOTONIC, &tp);
1489 req_sec = (unsigned int)tp.tv_sec;
1490 req_usec = (unsigned int)(tp.tv_nsec / 1000);
1492 w->req_id = ++private_output->req_id;
1493 w->req_time = TDM_TIME(req_sec, req_usec);
1494 w->need_free = (private_vblank->sync) ? 0 : 1;
1496 wl_tdm_vblank_wait_vblank(private_vblank->vblank, interval, w->req_id, req_sec, req_usec);
1498 if (private_vblank->enable_ttrace)
1499 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1501 TDM_DBG("vblank(%p) interval(%u) req_id(%d) req(%.6f)",
1502 vblank, interval, w->req_id, w->req_time);
1504 private_vblank->req_time = w->req_time;
1506 if (private_vblank->last_time >= w->req_time)
1507 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1509 if (!private_vblank->sync) {
1510 wl_display_flush(private_client->display);
1511 pthread_mutex_unlock(&private_client->lock);
1512 return TDM_ERROR_NONE;
1515 /* LCOV_EXCL_START */
1517 while (ret != -1 && !w->need_free)
1518 ret = wl_display_dispatch(private_client->display);
1520 clock_gettime(CLOCK_MONOTONIC, &tp);
1521 TDM_DBG("block during %d us",
1522 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1523 - (req_sec * 1000000 + req_usec));
1528 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1529 pthread_mutex_unlock(&private_client->lock);
1530 return TDM_ERROR_PROTOCOL_ERROR;
1533 pthread_mutex_unlock(&private_client->lock);
1535 return TDM_ERROR_NONE;
1537 /* LCOV_EXCL_STOP */
1541 tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
1542 tdm_client_vblank_handler func, void *user_data)
1544 tdm_private_client *private_client;
1545 tdm_private_client_output *private_output;
1546 tdm_private_client_vblank *private_vblank;
1547 tdm_client_wait_info *w;
1549 unsigned int req_sec, req_usec;
1552 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1553 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1555 private_vblank = vblank;
1556 private_output = private_vblank->private_output;
1557 private_client = private_output->private_client;
1559 pthread_mutex_lock(&private_client->lock);
1561 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1562 pthread_mutex_unlock(&private_client->lock);
1563 return TDM_ERROR_PROTOCOL_ERROR;
1566 if (!private_vblank->started)
1567 private_vblank->started = 1;
1569 if (!private_vblank->enable_fake) {
1570 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1571 TDM_ERR("output disconnected");
1572 pthread_mutex_unlock(&private_client->lock);
1573 return TDM_ERROR_OUTPUT_DISCONNECTED;
1575 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1576 TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1577 pthread_mutex_unlock(&private_client->lock);
1578 return TDM_ERROR_DPMS_OFF;
1582 w = calloc(1, sizeof *w);
1584 /* LCOV_EXCL_START */
1586 TDM_ERR("alloc failed");
1587 pthread_mutex_unlock(&private_client->lock);
1588 return TDM_ERROR_OUT_OF_MEMORY;
1590 /* LCOV_EXCL_STOP */
1593 w->private_vblank = private_vblank;
1595 w->user_data = user_data;
1597 LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1598 LIST_INITHEAD(&w->call_link);
1600 clock_gettime(CLOCK_MONOTONIC, &tp);
1601 req_sec = (unsigned int)tp.tv_sec;
1602 req_usec = (unsigned int)(tp.tv_nsec / 1000);
1604 w->req_id = ++private_output->req_id;
1605 w->req_time = TDM_TIME(req_sec, req_usec);
1606 w->need_free = (private_vblank->sync) ? 0 : 1;
1608 wl_tdm_vblank_wait_vblank_seq(private_vblank->vblank, sequence, w->req_id, req_sec, req_usec);
1610 if (private_vblank->enable_ttrace)
1611 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1613 TDM_DBG("vblank(%p) sequence(%u) req_id(%d) req(%.6f)",
1614 vblank, sequence, w->req_id, w->req_time);
1616 private_vblank->req_time = w->req_time;
1618 if (private_vblank->last_time >= w->req_time)
1619 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1621 if (!private_vblank->sync) {
1622 wl_display_flush(private_client->display);
1623 pthread_mutex_unlock(&private_client->lock);
1624 return TDM_ERROR_NONE;
1627 /* LCOV_EXCL_START */
1629 while (ret != -1 && !w->need_free)
1630 ret = wl_display_dispatch(private_client->display);
1632 clock_gettime(CLOCK_MONOTONIC, &tp);
1633 TDM_DBG("block during %d us",
1634 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1635 - (req_sec * 1000000 + req_usec));
1640 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1641 pthread_mutex_unlock(&private_client->lock);
1642 return TDM_ERROR_PROTOCOL_ERROR;
1645 pthread_mutex_unlock(&private_client->lock);
1647 return TDM_ERROR_NONE;
1649 /* LCOV_EXCL_STOP */
1653 tdm_client_vblank_is_waiting(tdm_client_vblank *vblank)
1655 tdm_private_client_vblank *private_vblank;
1657 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, 0);
1659 private_vblank = vblank;
1661 return (LIST_LENGTH(&private_vblank->wait_list) > 0) ? 1 : 0;
1664 static tbm_surface_h
1665 _tdm_client_voutput_create_surface_from_param(tbm_bufmgr bufmgr,
1673 struct wl_array *plane_buf_idx,
1674 struct wl_array *plane_offset,
1675 struct wl_array *plane_stride,
1676 struct wl_array *plane_size,
1683 int32_t names[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1};
1684 tbm_surface_info_s info = { 0, };
1685 tbm_bo bos[TBM_SURF_PLANE_MAX];
1686 int i, numPlane, numName;
1687 tbm_surface_h tbm_surface;
1689 numPlane = tbm_surface_internal_get_num_planes(format);
1690 TDM_RETURN_VAL_IF_FAIL(numPlane == num_plane, NULL);
1693 info.height = height;
1694 info.format = format;
1697 info.num_planes = numPlane;
1700 for (i = 0; i < numPlane; i++) {
1701 info.planes[i].offset = *TDM_ARRAY_NTH_DATA(plane_offset, int32_t, i);
1702 info.planes[i].stride = *TDM_ARRAY_NTH_DATA(plane_stride, int32_t, i);
1703 info.planes[i].size = *TDM_ARRAY_NTH_DATA(plane_size, int32_t, i);
1712 for (i = 0; i < numName; i++) {
1714 bos[i] = tbm_bo_import_fd(bufmgr, names[i]);
1716 bos[i] = tbm_bo_import(bufmgr, names[i]);
1719 tbm_surface = tbm_surface_internal_create_with_bos(&info, bos, numName);
1720 if (tbm_surface == NULL) {
1735 for (i = 0; i < numName; i++)
1736 tbm_bo_unref(bos[i]);
1741 tdm_client_voutput_cb_buffer_import_with_id(void *data,
1742 struct wl_tdm_voutput *wl_voutput,
1743 struct wl_buffer *wl_buffer,
1750 struct wl_array *plane_buf_idx,
1751 struct wl_array *plane_offset,
1752 struct wl_array *plane_stride,
1753 struct wl_array *plane_size,
1760 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1761 tdm_private_client_buffer *buffer = NULL;
1762 tbm_surface_h tbm_surface;
1764 TDM_RETURN_IF_FAIL(private_voutput != NULL);
1766 buffer = calloc(1, sizeof *buffer);
1767 TDM_RETURN_IF_FAIL(buffer != NULL);
1769 tbm_surface = _tdm_client_voutput_create_surface_from_param(private_voutput->bufmgr, 0,
1770 width, height, format, bpp, size,
1772 plane_buf_idx, plane_offset, plane_stride, plane_size,
1776 TDM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
1778 tbm_surface_internal_ref(tbm_surface);
1779 wl_buffer_set_user_data(wl_buffer, tbm_surface);
1781 buffer->wl_buffer = wl_buffer;
1783 LIST_ADDTAIL(&buffer->link, &private_voutput->buffer_list);
1792 wl_buffer_destroy(wl_buffer);
1796 tdm_client_voutput_cb_buffer_import_with_fd(void *data,
1797 struct wl_tdm_voutput *wl_voutput,
1798 struct wl_buffer *wl_buffer,
1805 struct wl_array *plane_buf_idx,
1806 struct wl_array *plane_offset,
1807 struct wl_array *plane_stride,
1808 struct wl_array *plane_size,
1815 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1816 tdm_private_client_buffer *buffer = NULL;
1817 tbm_surface_h tbm_surface;
1819 TDM_RETURN_IF_FAIL(private_voutput != NULL);
1821 buffer = calloc(1, sizeof *buffer);
1822 TDM_RETURN_IF_FAIL(buffer != NULL);
1824 tbm_surface = _tdm_client_voutput_create_surface_from_param(private_voutput->bufmgr, 1,
1825 width, height, format, bpp, size,
1827 plane_buf_idx, plane_offset, plane_stride, plane_size,
1831 TDM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
1833 tbm_surface_internal_ref(tbm_surface);
1834 wl_buffer_set_user_data(wl_buffer, tbm_surface);
1836 buffer->wl_buffer = wl_buffer;
1838 LIST_ADDTAIL(&buffer->link, &private_voutput->buffer_list);
1847 wl_buffer_destroy(wl_buffer);
1851 tdm_client_voutput_cb_buffer_destroy(void *data,
1852 struct wl_tdm_voutput *wl_voutput,
1853 struct wl_buffer *wl_buffer)
1855 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1856 tdm_private_client_buffer *cb = NULL, *cbb = NULL;
1857 tbm_surface_h tbm_surface = NULL;
1859 TDM_RETURN_IF_FAIL(private_voutput != NULL);
1861 LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
1862 if (wl_buffer == cb->wl_buffer) {
1863 LIST_DEL(&cb->link);
1865 tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(wl_buffer);
1867 tbm_surface_internal_unref(tbm_surface);
1869 wl_buffer_set_user_data(wl_buffer, NULL);
1870 wl_buffer_destroy(wl_buffer);
1882 tdm_client_voutput_cb_attach_buffer(void *data,
1883 struct wl_tdm_voutput *wl_voutput,
1884 struct wl_buffer *wl_buffer)
1886 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1887 tdm_private_client_buffer *cb = NULL, *cbb = NULL;
1889 TDM_RETURN_IF_FAIL(private_voutput != NULL);
1891 LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
1892 if (wl_buffer == cb->wl_buffer) {
1893 private_voutput->attach_buffer = cb;
1902 tdm_client_voutput_cb_commit(void *data, struct wl_tdm_voutput *wl_voutput)
1904 tdm_private_client_voutput *private_voutput;
1905 tdm_private_client *private_client;
1906 tbm_surface_h buffer = NULL;
1907 tdm_client_voutput_commit_handler_info *h = NULL, *hh = NULL;
1908 struct list_head call_list;
1910 private_voutput = (tdm_private_client_voutput *)data;
1911 TDM_RETURN_IF_FAIL(private_voutput != NULL);
1912 TDM_RETURN_IF_FAIL(private_voutput->attach_buffer != NULL);
1914 buffer = (tbm_surface_h)wl_buffer_get_user_data(private_voutput->attach_buffer->wl_buffer);
1915 TDM_RETURN_IF_FAIL(buffer != NULL);
1917 tbm_surface_internal_ref(buffer);
1919 private_client = private_voutput->private_client;
1921 LIST_INITHEAD(&call_list);
1923 LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
1924 LIST_ADDTAIL(&h->call_link, &call_list);
1927 pthread_mutex_unlock(&private_client->lock);
1928 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
1930 h->func(private_voutput, buffer, h->user_data);
1932 pthread_mutex_lock(&private_client->lock);
1934 /* if no added commit_handler call commit done immediately */
1935 if (LIST_IS_EMPTY(&private_voutput->commit_handler_list))
1936 tdm_client_voutput_commit_done(private_voutput);
1940 tdm_client_voutput_cb_ack_message(void *data, struct wl_tdm_voutput *wl_voutput, uint32_t msg)
1942 tdm_private_client_voutput *private_voutput = data;
1944 private_voutput->msg = msg;
1947 static const struct wl_tdm_voutput_listener tdm_client_voutput_lisntener = {
1948 tdm_client_voutput_cb_buffer_import_with_id,
1949 tdm_client_voutput_cb_buffer_import_with_fd,
1950 tdm_client_voutput_cb_buffer_destroy,
1951 tdm_client_voutput_cb_attach_buffer,
1952 tdm_client_voutput_cb_commit,
1953 tdm_client_voutput_cb_ack_message
1956 tdm_client_voutput *
1957 tdm_client_create_voutput(tdm_client *client, const char *name, tdm_error *error)
1959 tdm_private_client *private_client;
1960 tdm_private_client_output *private_output;
1961 tdm_private_client_voutput *private_voutput;
1962 struct wl_proxy *wrapper;
1965 *error = TDM_ERROR_NONE;
1968 TDM_ERR("'!client' failed");
1970 *error = TDM_ERROR_INVALID_PARAMETER;
1975 TDM_ERR("'!name' failed");
1977 *error = TDM_ERROR_INVALID_PARAMETER;
1981 private_client = (tdm_private_client *)client;
1983 pthread_mutex_lock(&private_client->lock);
1985 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1987 *error = TDM_ERROR_PROTOCOL_ERROR;
1988 pthread_mutex_unlock(&private_client->lock);
1992 LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
1993 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
1995 *error = TDM_ERROR_INVALID_PARAMETER; // FIXME define new error type.
1996 pthread_mutex_unlock(&private_client->lock);
2001 wrapper = wl_proxy_create_wrapper(private_client->tdm);
2003 TDM_ERR("create virtual output wrapper failed");
2005 *error = TDM_ERROR_OUT_OF_MEMORY;
2006 pthread_mutex_unlock(&private_client->lock);
2010 wl_proxy_set_queue(wrapper, private_client->queue);
2012 private_voutput = calloc(1, sizeof *private_voutput);
2013 if (!private_voutput) {
2014 /* LOCV_EXCL_START */
2015 wl_proxy_wrapper_destroy(wrapper);
2016 TDM_ERR("alloc failed");
2018 *error = TDM_ERROR_OUT_OF_MEMORY;
2019 pthread_mutex_unlock(&private_client->lock);
2021 /* LOCV_EXCL_STOP */
2024 private_voutput->bufmgr = tbm_bufmgr_init(-1);
2025 if (private_voutput->bufmgr == NULL) {
2026 /* LCOV_EXCL_START */
2027 TDM_ERR("fail tbm_bufmgr_init");
2028 free(private_voutput);
2030 *error = TDM_ERROR_OUT_OF_MEMORY;
2031 pthread_mutex_unlock(&private_client->lock);
2033 /* LCOV_EXCL_STOP */
2036 LIST_INITHEAD(&private_voutput->commit_handler_list);
2037 LIST_INITHEAD(&private_voutput->buffer_list);
2039 private_voutput->private_client = private_client;
2040 strncpy(private_voutput->name, name, TDM_NAME_LEN);
2042 private_voutput->wl_voutput = wl_tdm_create_voutput((struct wl_tdm *)wrapper, name);
2043 wl_proxy_wrapper_destroy(wrapper);
2044 if (!private_voutput->wl_voutput) {
2045 /* LCOV_EXCL_START */
2046 TDM_ERR("couldn't create voutput resource");
2047 free(private_voutput);
2049 *error = TDM_ERROR_OUT_OF_MEMORY;
2050 pthread_mutex_unlock(&private_client->lock);
2052 /* LCOV_EXCL_STOP */
2055 wl_tdm_voutput_add_listener(private_voutput->wl_voutput,
2056 &tdm_client_voutput_lisntener, private_voutput);
2057 wl_display_roundtrip_queue(private_client->display, private_client->queue);
2059 wl_proxy_set_queue((struct wl_proxy *)private_voutput->wl_voutput, NULL);
2061 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2062 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2063 free(private_voutput);
2065 *error = TDM_ERROR_PROTOCOL_ERROR;
2066 pthread_mutex_unlock(&private_client->lock);
2070 if (private_voutput->msg != WL_TDM_VOUTPUT_MESSAGE_ADDED)
2072 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2073 free(private_voutput);
2075 *error = TDM_ERROR_PROTOCOL_ERROR; // FIXME add new error type.
2076 pthread_mutex_unlock(&private_client->lock);
2080 LIST_ADDTAIL(&private_voutput->link, &private_client->voutput_list);
2082 pthread_mutex_unlock(&private_client->lock);
2084 return (tdm_client_voutput *)private_voutput;
2088 tdm_client_voutput_destroy(tdm_client_voutput *voutput)
2090 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)voutput;
2091 tdm_client_voutput_commit_handler_info *h = NULL, *hh = NULL;
2093 if (!private_voutput)
2096 if (!(LIST_IS_EMPTY(&private_voutput->buffer_list))) {
2097 tdm_private_client_buffer *cb = NULL, *cbb = NULL;
2099 LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
2100 tbm_surface_h tbm_surface = NULL;
2104 LIST_DEL(&cb->link);
2106 tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(cb->wl_buffer);
2108 tbm_surface_internal_unref(tbm_surface);
2110 wl_buffer_set_user_data(cb->wl_buffer, NULL);
2111 wl_buffer_destroy(cb->wl_buffer);
2117 if (private_voutput->bufmgr)
2118 tbm_bufmgr_deinit(private_voutput->bufmgr);
2120 if (private_voutput->available_modes.modes)
2121 free(private_voutput->available_modes.modes);
2123 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_voutput->commit_handler_list, link) {
2128 if (private_voutput->get_output)
2129 _tdm_client_output_destroy(private_voutput->private_output);
2131 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2133 LIST_DEL(&private_voutput->link);
2135 free(private_voutput);
2139 tdm_client_voutput_set_available_modes(tdm_client_voutput *voutput, const tdm_client_output_mode *modes, int count)
2141 tdm_private_client_voutput *private_voutput;
2143 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2145 if ((count > 0) && (modes == NULL))
2146 return TDM_ERROR_INVALID_PARAMETER;
2148 private_voutput = (tdm_private_client_voutput *)voutput;
2150 if (private_voutput->private_output->connection == TDM_OUTPUT_CONN_STATUS_CONNECTED)
2151 return TDM_ERROR_BAD_REQUEST;
2153 if (private_voutput->available_modes.modes)
2154 free(private_voutput->available_modes.modes);
2156 private_voutput->available_modes.count = count;
2160 private_voutput->available_modes.modes = calloc(count, sizeof(tdm_client_output_mode));
2161 memcpy(private_voutput->available_modes.modes, modes, sizeof(tdm_client_output_mode) * count);
2164 return TDM_ERROR_NONE;
2168 tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, unsigned int mmWidth, unsigned int mmHeight)
2170 tdm_private_client_voutput *private_voutput;
2172 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2173 TDM_RETURN_VAL_IF_FAIL(mmWidth != 0, TDM_ERROR_INVALID_PARAMETER);
2174 TDM_RETURN_VAL_IF_FAIL(mmHeight != 0, TDM_ERROR_INVALID_PARAMETER);
2176 private_voutput = (tdm_private_client_voutput *)voutput;
2178 if (private_voutput->private_output->connection == TDM_OUTPUT_CONN_STATUS_CONNECTED)
2179 return TDM_ERROR_BAD_REQUEST;
2181 private_voutput->mmwidth = mmWidth;
2182 private_voutput->mmheight = mmHeight;
2184 return TDM_ERROR_NONE;
2188 tdm_client_voutput_add_commit_handler(tdm_client_voutput *voutput,
2189 tdm_client_voutput_commit_handler func,
2192 tdm_private_client_voutput *private_voutput;
2193 tdm_private_client *private_client;
2194 tdm_client_voutput_commit_handler_info *h = NULL;
2196 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2197 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
2199 private_voutput = (tdm_private_client_voutput *)voutput;
2200 private_client = private_voutput->private_client;
2202 LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2203 if (h->func == func && h->user_data == user_data) {
2204 TDM_ERR("can't add twice");
2205 return TDM_ERROR_BAD_REQUEST;
2209 h = calloc(1, sizeof *h);
2210 TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
2212 pthread_mutex_lock(&private_client->lock);
2214 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2216 pthread_mutex_unlock(&private_client->lock);
2217 return TDM_ERROR_PROTOCOL_ERROR;
2220 h->private_voutput = private_voutput;
2222 h->user_data = user_data;
2223 LIST_ADDTAIL(&h->link, &private_voutput->commit_handler_list);
2224 LIST_INITHEAD(&h->call_link);
2226 pthread_mutex_unlock(&private_client->lock);
2228 return TDM_ERROR_NONE;
2232 tdm_client_voutput_remove_commit_handler(tdm_client_voutput *voutput,
2233 tdm_client_voutput_commit_handler func,
2236 tdm_private_client_voutput *private_voutput;
2237 tdm_private_client *private_client;
2238 tdm_client_voutput_commit_handler_info *h = NULL;
2240 TDM_RETURN_IF_FAIL(voutput != NULL);
2241 TDM_RETURN_IF_FAIL(func != NULL);
2243 private_voutput = (tdm_private_client_voutput *)voutput;
2244 private_client = private_voutput->private_client;
2246 pthread_mutex_lock(&private_client->lock);
2248 LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2249 if (h->func != func || h->user_data != user_data)
2255 pthread_mutex_unlock(&private_client->lock);
2258 pthread_mutex_unlock(&private_client->lock);
2262 tdm_client_voutput_commit_done(tdm_client_voutput *voutput)
2264 tdm_private_client_voutput *private_voutput;
2265 tbm_surface_h buffer = NULL;
2267 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2269 private_voutput = (tdm_private_client_voutput *)voutput;
2270 buffer = (tbm_surface_h)wl_buffer_get_user_data(private_voutput->attach_buffer->wl_buffer);
2271 tbm_surface_internal_unref(buffer);
2272 private_voutput->attach_buffer = NULL;
2273 wl_tdm_voutput_commit_done(private_voutput->wl_voutput);
2275 return TDM_ERROR_NONE;
2279 tdm_client_voutput_get_client_output(tdm_client_voutput *voutput, tdm_error *error)
2281 tdm_private_client_voutput *private_voutput;
2282 tdm_private_client_output *private_output = NULL;
2283 tdm_error ret = TDM_ERROR_NONE;
2286 *error = TDM_ERROR_NONE;
2289 TDM_ERR("'!voutput' failed");
2291 *error = TDM_ERROR_INVALID_PARAMETER;
2295 private_voutput = (tdm_private_client_voutput *)voutput;
2297 if (private_voutput->get_output)
2298 return private_voutput->private_output;
2300 private_output = (tdm_private_client_output *)tdm_client_get_output(private_voutput->private_client, private_voutput->name, &ret);
2301 if (!private_output) {
2302 TDM_ERR("tdm_client_voutput_get_client_output get private_output fail");
2307 private_output->voutput = private_voutput;
2308 private_voutput->private_output = private_output;
2309 private_voutput->get_output = 1;
2311 return private_output;
2315 tdm_client_output_get_available_modes(tdm_client_output *output, tdm_client_output_mode **modes, int *count)
2317 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2318 TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER);
2319 TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
2321 return TDM_ERROR_NONE;
2325 tdm_client_output_set_mode(tdm_client_output *output, const tdm_client_output_mode *mode)
2327 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2328 TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER);
2330 return TDM_ERROR_NONE;
2334 _tdm_client_voutput_send_available_modes(tdm_private_client_voutput *private_voutput)
2336 tdm_client_output_mode *modes, *mode;
2337 struct wl_array array;
2340 modes = private_voutput->available_modes.modes;
2341 size = sizeof(tdm_client_output_mode);
2343 wl_array_init(&array);
2344 for (i = 0; i < private_voutput->available_modes.count; i++) {
2345 mode = wl_array_add(&array, size);
2346 memcpy(mode, &modes[i], size);
2348 wl_tdm_voutput_set_available_modes(private_voutput->wl_voutput, &array);
2349 wl_array_release(&array);
2353 tdm_client_output_connect(tdm_client_output *output)
2355 tdm_private_client_output *private_output;
2356 tdm_private_client_voutput *private_voutput = NULL;
2358 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2360 private_output = (tdm_private_client_output *)output;
2361 if (!private_output->voutput) return TDM_ERROR_INVALID_PARAMETER;
2362 private_voutput = private_output->voutput;
2364 TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_CONNECTED,
2365 TDM_ERROR_BAD_REQUEST);
2367 if (!private_output->watch_output_changes)
2368 private_output->connection = TDM_OUTPUT_CONN_STATUS_CONNECTED;
2370 _tdm_client_voutput_send_available_modes(private_voutput);
2372 wl_tdm_voutput_set_physical_size(private_voutput->wl_voutput, private_voutput->mmwidth, private_voutput->mmheight);
2374 /* To Do : change voutput to output */
2375 wl_tdm_voutput_connect(private_voutput->wl_voutput);
2377 return TDM_ERROR_NONE;
2381 tdm_client_output_disconnect(tdm_client_output *output)
2383 tdm_private_client_output *private_output;
2384 tdm_private_client_voutput *private_voutput = NULL;
2386 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2388 private_output = (tdm_private_client_output *)output;
2389 if (!private_output->voutput) return TDM_ERROR_INVALID_PARAMETER;
2390 private_voutput = private_output->voutput;
2392 TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED,
2393 TDM_ERROR_BAD_REQUEST);
2395 if (!private_output->watch_output_changes)
2396 private_output->connection = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
2398 /* To Do : change voutput to output */
2399 wl_tdm_voutput_disconnect(private_voutput->wl_voutput);
2401 return TDM_ERROR_NONE;