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 {
178 tdm_private_client_voutput *private_voutput;
180 tdm_client_voutput_commit_handler func;
183 struct list_head link;
184 struct list_head call_link;
185 } tdm_client_voutput_commit_handler_info;
188 VBLANK_WAIT_TYPE_INTERVAL,
189 VBLANK_WAIT_TYPE_SEQUENCE,
190 } tdm_client_vblank_wait_type;
193 _tdm_client_check_wl_error(tdm_private_client *private_client, const char *func, int line)
196 const struct wl_interface *intf;
199 err = wl_display_get_error(private_client->display);
203 if (err == EINVAL || err == ENOMEM || err == EFAULT || err == EPROTO) {
204 ec = wl_display_get_protocol_error(private_client->display, &intf, &id);
205 TDM_ERR("[%s,%d] errno(%d) Got protocol error '%u' on interface '%s' (object '%u')",
206 func, line, err, ec, (intf) ? intf->name : "destroyed", id);
208 TDM_ERR("[%s,%d] errno(%d)", func, line, err);
214 #define CHECK_WL_PROTOCOL_ERROR(pc) _tdm_client_check_wl_error(pc, __FUNCTION__, __LINE__)
217 _tdm_client_vblank_cb_stamp(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t stamp)
219 tdm_private_client_vblank *private_vblank = data;
220 tdm_private_client *private_client;
222 TDM_RETURN_IF_FAIL(private_vblank != NULL);
224 private_vblank->stamp = stamp;
226 TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
227 private_client = private_vblank->private_output->private_client;
229 private_client->stamp = stamp;
232 /* LCOV_EXCL_START */
234 _tdm_client_vblank_wait_list_validation_check(tdm_private_client_vblank *private_vblank)
236 if (private_vblank->wait_list.next == NULL || private_vblank->wait_list.prev == NULL) {
237 TDM_ERR("vblank(%p) wait_list broken. prev(%p), next(%p) pid(%d)",
238 private_vblank, private_vblank->wait_list.prev, private_vblank->wait_list.next, getpid());
245 _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank,
246 uint32_t req_id, uint32_t sequence, uint32_t tv_sec,
247 uint32_t tv_usec, uint32_t error)
249 tdm_private_client_vblank *private_vblank = data;
250 tdm_private_client *private_client;
251 tdm_client_wait_info *w = NULL, *wait_info = NULL;
253 TDM_RETURN_IF_FAIL(private_vblank != NULL);
255 private_client = private_vblank->private_output->private_client;
257 private_vblank->last_time = TDM_TIME(tv_sec, tv_usec);
259 TDM_DBG("vblank(%p) req_id(%u) sequence(%u) time(%.6f)",
260 private_vblank, req_id, sequence, TDM_TIME(tv_sec, tv_usec));
262 _tdm_client_vblank_wait_list_validation_check(private_vblank);
264 LIST_FOR_EACH_ENTRY(w, &private_vblank->wait_list, link) {
265 if (w->req_id != req_id)
273 TDM_ERR("no wait infomation for req_id(%d)", req_id);
277 if (private_vblank->enable_ttrace)
278 TDM_TRACE_ASYNC_END((int)wait_info->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
280 if (wait_info->req_time >= private_vblank->last_time)
281 TDM_WRN("'req(%.6f) < last(%.6f)' failed. error(%d)", wait_info->req_time, private_vblank->last_time, error);
283 if (wait_info->need_free)
284 LIST_DEL(&wait_info->link);
286 if (wait_info->func) {
287 pthread_mutex_unlock(&private_client->lock);
288 wait_info->func(private_vblank, error, sequence, tv_sec, tv_usec, wait_info->user_data);
289 pthread_mutex_lock(&private_client->lock);
292 if (wait_info->need_free)
295 wait_info->need_free = 1;
299 /* LCOV_EXCL_START */
301 _tdm_client_vblank_cb_ttrace(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t enable)
303 tdm_private_client_vblank *private_vblank = data;
304 tdm_private_client *private_client;
306 TDM_RETURN_IF_FAIL(private_vblank != NULL);
308 private_vblank->enable_ttrace = enable;
310 TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
311 private_client = private_vblank->private_output->private_client;
313 private_client->enable_ttrace = enable;
317 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
318 _tdm_client_vblank_cb_stamp,
319 _tdm_client_vblank_cb_done,
320 _tdm_client_vblank_cb_ttrace,
324 _tdm_client_output_destroy(tdm_private_client_output *private_output)
326 tdm_private_client_vblank *v = NULL, *vv = NULL;
327 tdm_client_output_handler_info *h = NULL, *hh = NULL;
329 LIST_DEL(&private_output->link);
331 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_list, link) {
332 TDM_ERR("vblanks SHOULD be destroyed first!");
334 v->private_output = NULL;
337 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list, link) {
342 wl_tdm_output_destroy(private_output->output);
344 free(private_output);
348 _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output,
349 uint32_t width, uint32_t height, uint32_t refresh, uint32_t error)
351 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
353 TDM_RETURN_IF_FAIL(private_output != NULL);
355 private_output->width = width;
356 private_output->height = height;
357 private_output->refresh = refresh;
359 if (error != TDM_ERROR_NONE)
360 TDM_INFO("mode event error: %d", error);
362 TDM_DBG("private_output(%p) wl_tbm_output@%d width(%d) height(%d) refresh(%d)",
363 private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output),
364 width, height, refresh);
368 _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
370 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
371 tdm_private_client *private_client;
372 tdm_client_output_handler_info *h = NULL, *hh = NULL;
374 struct list_head call_list;
376 TDM_RETURN_IF_FAIL(private_output != NULL);
378 private_client = private_output->private_client;
380 if (private_output->connection == value && value != TDM_OUTPUT_CONN_STATUS_MODE_SETTED)
383 private_output->connection = value;
385 if (error != TDM_ERROR_NONE)
386 TDM_INFO("connection event error: %d", error);
388 TDM_DBG("private_output(%p) wl_tbm_output@%d connection(%d)",
390 wl_proxy_get_id((struct wl_proxy*)private_output->output),
393 LIST_INITHEAD(&call_list);
395 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
396 LIST_ADDTAIL(&h->call_link, &call_list);
400 pthread_mutex_unlock(&private_client->lock);
401 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
403 h->func(private_output, TDM_OUTPUT_CHANGE_CONNECTION, v, h->user_data);
405 pthread_mutex_lock(&private_client->lock);
409 _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
411 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
412 tdm_private_client *private_client;
413 tdm_client_output_handler_info *h = NULL, *hh = NULL;
415 struct list_head call_list;
417 TDM_RETURN_IF_FAIL(private_output != NULL);
419 private_client = private_output->private_client;
421 /* If value is extended value, we handle it as DPMS on in client side
422 * The extended DPMS value is valid only in server side.
423 * Or, need to export to client side also?
425 if (value > TDM_OUTPUT_DPMS_OFF)
426 value = TDM_OUTPUT_DPMS_ON;
428 if (private_output->dpms == value)
431 private_output->dpms = value;
433 if (error != TDM_ERROR_NONE)
434 TDM_INFO("dpms event error: %d", error);
436 TDM_DBG("private_output(%p) wl_tbm_output@%d dpms(%d)",
438 wl_proxy_get_id((struct wl_proxy*)private_output->output),
441 LIST_INITHEAD(&call_list);
443 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
444 LIST_ADDTAIL(&h->call_link, &call_list);
448 pthread_mutex_unlock(&private_client->lock);
449 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
451 h->func(private_output, TDM_OUTPUT_CHANGE_DPMS, v, h->user_data);
453 pthread_mutex_lock(&private_client->lock);
456 static const struct wl_tdm_output_listener tdm_client_output_listener = {
457 _tdm_client_output_cb_mode,
458 _tdm_client_output_cb_connection,
459 _tdm_client_output_cb_dpms,
463 _tdm_client_cb_global(void *data, struct wl_registry *registry,
464 uint32_t name, const char *interface,
467 tdm_private_client *private_client = data;
469 if (strncmp(interface, "wl_tdm", 6) == 0) {
470 private_client->tdm =
471 wl_registry_bind(registry, name, &wl_tdm_interface, version);
472 TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
474 wl_display_flush(private_client->display);
478 /* LCOV_EXCL_START */
480 _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
485 static const struct wl_registry_listener tdm_client_registry_listener = {
486 _tdm_client_cb_global,
487 _tdm_client_cb_global_remove
491 tdm_client_create(tdm_error *error)
493 tdm_private_client *private_client;
495 private_client = calloc(1, sizeof *private_client);
496 if (!private_client) {
497 /* LCOV_EXCL_START */
499 TDM_ERR("alloc failed");
501 *error = TDM_ERROR_OUT_OF_MEMORY;
507 if (pthread_mutex_init(&private_client->lock, NULL)) {
508 TDM_ERR("mutex init failed: %m");
509 free(private_client);
511 *error = TDM_ERROR_OUT_OF_MEMORY;
515 LIST_INITHEAD(&private_client->output_list);
516 LIST_INITHEAD(&private_client->voutput_list);
518 private_client->display = wl_display_connect("tdm-socket");
519 TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed);
521 private_client->queue = wl_display_create_queue(private_client->display);
522 TDM_GOTO_IF_FAIL(private_client->queue != NULL, create_failed);
524 private_client->registry = wl_display_get_registry(private_client->display);
525 TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed);
527 wl_registry_add_listener(private_client->registry,
528 &tdm_client_registry_listener, private_client);
529 wl_display_roundtrip(private_client->display);
531 if (CHECK_WL_PROTOCOL_ERROR(private_client))
534 /* check global objects */
535 TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed);
538 *error = TDM_ERROR_NONE;
540 return (tdm_client*)private_client;
542 tdm_client_destroy((tdm_client*)private_client);
544 *error = TDM_ERROR_OPERATION_FAILED;
549 tdm_client_destroy(tdm_client *client)
551 tdm_private_client *private_client = (tdm_private_client*)client;
552 tdm_private_client_output *o = NULL, *oo = NULL;
553 tdm_private_client_voutput *vo = NULL, *voo = NULL;
558 pthread_mutex_lock(&private_client->lock);
560 if (private_client->temp_vblank) {
561 pthread_mutex_unlock(&private_client->lock);
562 tdm_client_vblank_destroy(private_client->temp_vblank);
563 pthread_mutex_lock(&private_client->lock);
566 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_client->output_list, link) {
567 _tdm_client_output_destroy(o);
570 LIST_FOR_EACH_ENTRY_SAFE(vo, voo, &private_client->voutput_list, link) {
571 tdm_client_voutput_destroy(vo);
574 if (private_client->tdm)
575 wl_tdm_destroy(private_client->tdm);
576 if (private_client->registry)
577 wl_registry_destroy(private_client->registry);
578 if (private_client->queue)
579 wl_event_queue_destroy(private_client->queue);
580 if (private_client->display)
581 wl_display_disconnect(private_client->display);
583 pthread_mutex_unlock(&private_client->lock);
584 pthread_mutex_destroy(&private_client->lock);
586 free(private_client);
590 tdm_client_get_fd(tdm_client *client, int *fd)
592 tdm_private_client *private_client;
594 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
595 TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_ERROR_INVALID_PARAMETER);
597 private_client = (tdm_private_client*)client;
599 pthread_mutex_lock(&private_client->lock);
601 *fd = wl_display_get_fd(private_client->display);
603 pthread_mutex_unlock(&private_client->lock);
606 return TDM_ERROR_OPERATION_FAILED;
608 return TDM_ERROR_NONE;
612 tdm_client_handle_events(tdm_client *client)
614 tdm_private_client *private_client;
616 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
618 /* LCOV_EXCL_START */
619 private_client = (tdm_private_client*)client;
621 pthread_mutex_lock(&private_client->lock);
623 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
624 pthread_mutex_unlock(&private_client->lock);
625 return TDM_ERROR_PROTOCOL_ERROR;
628 if (private_client->enable_ttrace)
629 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
631 wl_display_dispatch(private_client->display);
633 if (private_client->enable_ttrace)
634 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
636 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
637 pthread_mutex_unlock(&private_client->lock);
638 return TDM_ERROR_PROTOCOL_ERROR;
641 pthread_mutex_unlock(&private_client->lock);
643 return TDM_ERROR_NONE;
648 _tdm_client_poll(struct wl_display *display, short int events, int timeout)
651 struct pollfd pfd[1];
653 pfd[0].fd = wl_display_get_fd(display);
654 pfd[0].events = events;
656 ret = poll(pfd, 1, timeout);
657 } while (ret == -1 && errno == EINTR);
663 _tdm_client_dispatch_timeout(tdm_private_client *private_client, int timeout)
666 struct wl_display *display = private_client->display;
668 if (wl_display_prepare_read(display) == -1) {
669 if (wl_display_dispatch_pending(display) > 0)
670 return TDM_ERROR_NONE;
672 return TDM_ERROR_OPERATION_FAILED;
676 ret = wl_display_flush(display);
678 if (ret != -1 || errno != EAGAIN)
681 if (_tdm_client_poll(display, POLLOUT, -1) == -1) {
682 wl_display_cancel_read(display);
683 TDM_ERR("_tdm_client_poll failed");
684 return TDM_ERROR_OPERATION_FAILED;
688 /* Don't stop if flushing hits an EPIPE; continue so we can read any
689 * protocol error that may have triggered it. */
690 if (ret < 0 && errno != EPIPE) {
691 TDM_ERR("ret(%d) errno(%d)", ret, errno);
692 wl_display_cancel_read(display);
693 return TDM_ERROR_OPERATION_FAILED;
696 ret = _tdm_client_poll(display, POLLIN, timeout);
698 wl_display_cancel_read(display);
700 TDM_ERR("_tdm_client_poll timeout.");
701 return TDM_ERROR_TIMEOUT;
703 TDM_ERR("_tdm_client_poll failed. (ret:%d)", ret);
704 return TDM_ERROR_OPERATION_FAILED;
708 if (wl_display_read_events(display) == -1) {
709 TDM_ERR("wl_display_read_events failed");
710 return TDM_ERROR_OPERATION_FAILED;
713 ret = wl_display_dispatch_pending(display);
716 TDM_ERR("_tdm_client_dispatch_timeout failed");
717 return TDM_ERROR_OPERATION_FAILED;
720 return TDM_ERROR_NONE;
724 tdm_client_handle_events_timeout(tdm_client *client, int ms_timeout)
726 tdm_private_client *private_client;
728 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
730 private_client = (tdm_private_client*)client;
732 pthread_mutex_lock(&private_client->lock);
734 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
735 pthread_mutex_unlock(&private_client->lock);
736 return TDM_ERROR_PROTOCOL_ERROR;
739 if (private_client->enable_ttrace)
740 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
742 ret = _tdm_client_dispatch_timeout(private_client, ms_timeout);
744 if (private_client->enable_ttrace)
745 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
747 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
748 pthread_mutex_unlock(&private_client->lock);
749 return TDM_ERROR_PROTOCOL_ERROR;
752 pthread_mutex_unlock(&private_client->lock);
757 typedef struct _tdm_client_vblank_temp {
758 tdm_client_vblank_handler2 func;
760 } tdm_client_vblank_temp;
762 /* LCOV_EXCL_START */
764 _tdm_client_vblank_handler_temp(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
765 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
767 tdm_client_vblank_temp *vblank_temp = user_data;
769 TDM_RETURN_IF_FAIL(vblank_temp != NULL);
770 TDM_RETURN_IF_FAIL(vblank != NULL);
772 if (vblank_temp->func)
773 vblank_temp->func(sequence, tv_sec, tv_usec, vblank_temp->user_data);
779 /* LCOV_EXCL_START */ /* deprecated */
781 tdm_client_wait_vblank(tdm_client *client, char *name,
782 int sw_timer, int interval, int sync,
783 tdm_client_vblank_handler2 func, void *user_data)
785 tdm_private_client *private_client = (tdm_private_client*)client;
786 tdm_client_output *output;
787 tdm_client_vblank_temp *vblank_temp;
790 TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
791 TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
792 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
794 if (CHECK_WL_PROTOCOL_ERROR(private_client))
795 return TDM_ERROR_PROTOCOL_ERROR;
797 if (!private_client->temp_vblank) {
798 output = tdm_client_get_output(client, name, &ret);
799 TDM_RETURN_VAL_IF_FAIL(output != NULL, ret);
801 private_client->temp_vblank = tdm_client_output_create_vblank(output, &ret);
802 TDM_RETURN_VAL_IF_FAIL(private_client->temp_vblank != NULL, ret);
805 tdm_client_vblank_set_enable_fake(private_client->temp_vblank, sw_timer);
806 tdm_client_vblank_set_sync(private_client->temp_vblank, sync);
808 vblank_temp = calloc(1, sizeof *vblank_temp);
809 TDM_RETURN_VAL_IF_FAIL(vblank_temp != NULL, TDM_ERROR_OUT_OF_MEMORY);
811 vblank_temp->func = func;
812 vblank_temp->user_data = user_data;
814 return tdm_client_vblank_wait(private_client->temp_vblank, interval, _tdm_client_vblank_handler_temp, vblank_temp);
819 tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
821 tdm_private_client *private_client;
822 tdm_private_client_output *private_output = NULL;
823 struct wl_proxy *wrapper;
826 *error = TDM_ERROR_NONE;
829 TDM_ERR("'!client' failed");
831 *error = TDM_ERROR_INVALID_PARAMETER;
835 private_client = (tdm_private_client*)client;
837 pthread_mutex_lock(&private_client->lock);
839 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
841 *error = TDM_ERROR_PROTOCOL_ERROR;
842 pthread_mutex_unlock(&private_client->lock);
848 } else if (!strncmp(name, "primary", 7) || !strncmp(name, "default", 7)) {
849 TDM_DBG("get primary or default output");
851 tdm_private_client_voutput *private_voutput = NULL;
854 LIST_FOR_EACH_ENTRY(private_voutput, &private_client->voutput_list, link) {
855 if (!strncmp(private_voutput->name, name, TDM_NAME_LEN)) {
862 *error = TDM_ERROR_INVALID_PARAMETER;
863 pthread_mutex_unlock(&private_client->lock);
868 LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
869 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
870 pthread_mutex_unlock(&private_client->lock);
871 return (tdm_client_output*)private_output;
875 wrapper = wl_proxy_create_wrapper(private_client->tdm);
877 TDM_ERR("create output_wrapper failed");
879 *error = TDM_ERROR_OUT_OF_MEMORY;
880 pthread_mutex_unlock(&private_client->lock);
884 wl_proxy_set_queue(wrapper, private_client->queue);
886 private_output = calloc(1, sizeof *private_output);
887 if (!private_output) {
888 /* LCOV_EXCL_START */
889 wl_proxy_wrapper_destroy(wrapper);
890 TDM_ERR("alloc failed");
892 *error = TDM_ERROR_OUT_OF_MEMORY;
893 pthread_mutex_unlock(&private_client->lock);
899 private_output->private_client = private_client;
901 snprintf(private_output->name, TDM_NAME_LEN, "%s", name);
902 private_output->output = wl_tdm_create_output((struct wl_tdm *)wrapper, private_output->name);
903 wl_proxy_wrapper_destroy(wrapper);
904 if (!private_output->output) {
905 /* LCOV_EXCL_START */
907 TDM_ERR("couldn't create output resource");
908 free(private_output);
910 *error = TDM_ERROR_OUT_OF_MEMORY;
911 pthread_mutex_unlock(&private_client->lock);
917 LIST_INITHEAD(&private_output->vblank_list);
918 LIST_INITHEAD(&private_output->change_handler_list);
920 wl_tdm_output_add_listener(private_output->output,
921 &tdm_client_output_listener, private_output);
922 wl_display_roundtrip_queue(private_client->display, private_client->queue);
924 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
926 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
927 wl_tdm_output_destroy(private_output->output);
928 free(private_output);
930 *error = TDM_ERROR_PROTOCOL_ERROR;
931 pthread_mutex_unlock(&private_client->lock);
935 LIST_ADDTAIL(&private_output->link, &private_client->output_list);
937 pthread_mutex_unlock(&private_client->lock);
939 return (tdm_client_output*)private_output;
943 tdm_client_output_add_change_handler(tdm_client_output *output,
944 tdm_client_output_change_handler func,
947 tdm_private_client_output *private_output;
948 tdm_private_client *private_client;
949 tdm_client_output_handler_info *h = NULL;
951 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
952 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
954 private_output = (tdm_private_client_output*)output;
955 private_client = private_output->private_client;
957 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
958 if (h->func == func && h->user_data == user_data) {
959 TDM_ERR("can't add twice");
960 return TDM_ERROR_BAD_REQUEST;
964 h = calloc(1, sizeof *h);
965 TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
967 pthread_mutex_lock(&private_client->lock);
969 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
971 pthread_mutex_unlock(&private_client->lock);
972 return TDM_ERROR_PROTOCOL_ERROR;
975 if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
976 wl_tdm_output_watch_output_changes(private_output->output, 1);
977 wl_display_roundtrip_queue(private_client->display, private_client->queue);
979 /* TODO: this is very tricky.
980 * If a client adds the change_handler, we might be able to guess that
981 * the client will watch the tdm client's fd and handle tdm events in
982 * event loop. Otherwise, we CAN'T make sure if a client has event loop
983 * which handles tdm events.
985 private_output->watch_output_changes = 1;
988 h->private_output = private_output;
990 h->user_data = user_data;
991 LIST_ADDTAIL(&h->link, &private_output->change_handler_list);
992 LIST_INITHEAD(&h->call_link);
994 pthread_mutex_unlock(&private_client->lock);
996 return TDM_ERROR_NONE;
1000 tdm_client_output_remove_change_handler(tdm_client_output *output,
1001 tdm_client_output_change_handler func,
1004 tdm_private_client_output *private_output;
1005 tdm_private_client *private_client;
1006 tdm_client_output_handler_info *h = NULL;
1008 TDM_RETURN_IF_FAIL(output != NULL);
1009 TDM_RETURN_IF_FAIL(func != NULL);
1011 private_output = (tdm_private_client_output*)output;
1012 private_client = private_output->private_client;
1014 pthread_mutex_lock(&private_client->lock);
1016 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
1017 if (h->func != func || h->user_data != user_data)
1023 if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
1024 private_output->watch_output_changes = 0;
1025 if (!CHECK_WL_PROTOCOL_ERROR(private_client)) {
1026 wl_tdm_output_watch_output_changes(private_output->output, 0);
1027 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1031 pthread_mutex_unlock(&private_client->lock);
1036 pthread_mutex_unlock(&private_client->lock);
1040 tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refresh)
1042 tdm_private_client_output *private_output;
1043 tdm_private_client *private_client;
1045 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1046 TDM_RETURN_VAL_IF_FAIL(refresh != NULL, TDM_ERROR_INVALID_PARAMETER);
1048 private_output = (tdm_private_client_output*)output;
1049 private_client = private_output->private_client;
1051 pthread_mutex_lock(&private_client->lock);
1053 if (private_output->watch_output_changes) {
1054 *refresh = private_output->refresh;
1055 pthread_mutex_unlock(&private_client->lock);
1056 return TDM_ERROR_NONE;
1059 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1060 pthread_mutex_unlock(&private_client->lock);
1061 return TDM_ERROR_PROTOCOL_ERROR;
1064 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1065 wl_tdm_output_get_mode(private_output->output);
1066 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1067 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1069 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1070 pthread_mutex_unlock(&private_client->lock);
1071 return TDM_ERROR_PROTOCOL_ERROR;
1074 *refresh = private_output->refresh;
1076 pthread_mutex_unlock(&private_client->lock);
1078 return TDM_ERROR_NONE;
1082 tdm_client_output_get_mode(tdm_client_output *output, unsigned int *width, unsigned int *height)
1084 tdm_private_client_output *private_output;
1085 tdm_private_client *private_client;
1087 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1088 TDM_RETURN_VAL_IF_FAIL(width != NULL, TDM_ERROR_INVALID_PARAMETER);
1089 TDM_RETURN_VAL_IF_FAIL(height != NULL, TDM_ERROR_INVALID_PARAMETER);
1091 private_output = (tdm_private_client_output*)output;
1092 private_client = private_output->private_client;
1094 pthread_mutex_lock(&private_client->lock);
1096 if (private_output->watch_output_changes) {
1097 *width = private_output->width;
1098 *height = private_output->height;
1099 pthread_mutex_unlock(&private_client->lock);
1100 return TDM_ERROR_NONE;
1103 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1104 pthread_mutex_unlock(&private_client->lock);
1105 return TDM_ERROR_PROTOCOL_ERROR;
1108 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1109 wl_tdm_output_get_mode(private_output->output);
1110 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1111 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1113 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1114 pthread_mutex_unlock(&private_client->lock);
1115 return TDM_ERROR_PROTOCOL_ERROR;
1118 *width = private_output->width;
1119 *height = private_output->height;
1121 pthread_mutex_unlock(&private_client->lock);
1123 return TDM_ERROR_NONE;
1127 tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_status *status)
1129 tdm_private_client_output *private_output;
1130 tdm_private_client *private_client;
1132 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1133 TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
1135 private_output = (tdm_private_client_output*)output;
1136 private_client = private_output->private_client;
1138 pthread_mutex_lock(&private_client->lock);
1140 if (private_output->watch_output_changes) {
1141 *status = private_output->connection;
1142 pthread_mutex_unlock(&private_client->lock);
1143 return TDM_ERROR_NONE;
1146 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1147 pthread_mutex_unlock(&private_client->lock);
1148 return TDM_ERROR_PROTOCOL_ERROR;
1151 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1152 wl_tdm_output_get_connection(private_output->output);
1153 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1154 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1156 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1157 pthread_mutex_unlock(&private_client->lock);
1158 return TDM_ERROR_PROTOCOL_ERROR;
1161 *status = private_output->connection;
1163 pthread_mutex_unlock(&private_client->lock);
1165 return TDM_ERROR_NONE;
1169 tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
1171 tdm_private_client_output *private_output;
1172 tdm_private_client *private_client;
1174 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1175 TDM_RETURN_VAL_IF_FAIL(dpms != NULL, TDM_ERROR_INVALID_PARAMETER);
1177 private_output = (tdm_private_client_output*)output;
1178 private_client = private_output->private_client;
1180 if (private_output->watch_output_changes) {
1181 *dpms = private_output->dpms;
1182 return TDM_ERROR_NONE;
1185 pthread_mutex_lock(&private_client->lock);
1187 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1188 pthread_mutex_unlock(&private_client->lock);
1189 return TDM_ERROR_PROTOCOL_ERROR;
1192 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1193 wl_tdm_output_get_dpms(private_output->output);
1194 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1195 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1197 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1198 pthread_mutex_unlock(&private_client->lock);
1199 return TDM_ERROR_PROTOCOL_ERROR;
1202 *dpms = private_output->dpms;
1204 pthread_mutex_unlock(&private_client->lock);
1206 return TDM_ERROR_NONE;
1210 tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
1212 tdm_private_client *private_client;
1213 tdm_private_client_output *private_output;
1214 tdm_private_client_vblank *private_vblank;
1215 struct wl_proxy *wrapper;
1218 *error = TDM_ERROR_NONE;
1221 TDM_ERR("'!output' failed");
1223 *error = TDM_ERROR_INVALID_PARAMETER;
1227 private_output = (tdm_private_client_output*)output;
1228 private_client = private_output->private_client;
1230 pthread_mutex_lock(&private_client->lock);
1232 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1234 *error = TDM_ERROR_PROTOCOL_ERROR;
1235 pthread_mutex_unlock(&private_client->lock);
1239 wrapper = wl_proxy_create_wrapper(private_output->output);
1241 TDM_ERR("create output_wrapper failed");
1243 *error = TDM_ERROR_OUT_OF_MEMORY;
1244 pthread_mutex_unlock(&private_client->lock);
1248 wl_proxy_set_queue(wrapper, private_client->queue);
1250 private_vblank = calloc(1, sizeof *private_vblank);
1251 if (!private_vblank) {
1252 /* LCOV_EXCL_START */
1254 TDM_ERR("alloc failed");
1255 wl_proxy_wrapper_destroy(wrapper);
1257 *error = TDM_ERROR_OUT_OF_MEMORY;
1258 pthread_mutex_unlock(&private_client->lock);
1261 /* LCOV_EXCL_STOP */
1264 private_vblank->private_output = private_output;
1266 private_vblank->vblank = wl_tdm_output_create_vblank((struct wl_tdm_output*)wrapper);
1267 wl_proxy_wrapper_destroy(wrapper);
1268 if (!private_vblank->vblank) {
1269 /* LCOV_EXCL_START */
1271 TDM_ERR("couldn't create vblank resource");
1272 free(private_vblank);
1274 *error = TDM_ERROR_OUT_OF_MEMORY;
1275 pthread_mutex_unlock(&private_client->lock);
1278 /* LCOV_EXCL_STOP */
1282 private_vblank->fps = private_output->refresh;
1283 private_vblank->offset = 0;
1284 private_vblank->enable_fake = 0;
1286 LIST_INITHEAD(&private_vblank->wait_list);
1288 wl_tdm_vblank_add_listener(private_vblank->vblank,
1289 &tdm_client_vblank_listener, private_vblank);
1290 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1292 wl_proxy_set_queue((struct wl_proxy *)private_vblank->vblank, NULL);
1294 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1295 wl_tdm_vblank_destroy(private_vblank->vblank);
1296 free(private_vblank);
1298 *error = TDM_ERROR_PROTOCOL_ERROR;
1299 pthread_mutex_unlock(&private_client->lock);
1303 LIST_ADDTAIL(&private_vblank->link, &private_output->vblank_list);
1305 pthread_mutex_unlock(&private_client->lock);
1307 return (tdm_client_vblank*)private_vblank;
1311 tdm_client_vblank_destroy(tdm_client_vblank *vblank)
1313 tdm_private_client_vblank *private_vblank;
1314 tdm_private_client_output *private_output;
1315 tdm_private_client *private_client;
1316 tdm_client_wait_info *w = NULL, *ww = NULL;
1318 TDM_RETURN_IF_FAIL(vblank != NULL);
1320 private_vblank = vblank;
1322 private_output = private_vblank->private_output;
1323 if (!private_output) {
1324 TDM_WRN("private_output is already destroyed.");
1325 free(private_vblank);
1329 private_client = private_output->private_client;
1330 if (!private_client) {
1331 TDM_WRN("private_client is already destroyed.");
1332 free(private_vblank);
1336 pthread_mutex_lock(&private_client->lock);
1338 LIST_DEL(&private_vblank->link);
1340 LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
1345 wl_tdm_vblank_destroy(private_vblank->vblank);
1347 free(private_vblank);
1349 pthread_mutex_unlock(&private_client->lock);
1353 tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name)
1355 tdm_private_client_vblank *private_vblank;
1356 tdm_private_client *private_client;
1358 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1360 private_vblank = vblank;
1361 private_client = private_vblank->private_output->private_client;
1363 pthread_mutex_lock(&private_client->lock);
1365 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1366 pthread_mutex_unlock(&private_client->lock);
1367 return TDM_ERROR_PROTOCOL_ERROR;
1371 name = TDM_VBLANK_DEFAULT_NAME;
1373 strncpy(private_vblank->name, name, TDM_NAME_LEN - 1);
1374 private_vblank->name[TDM_NAME_LEN - 1] = '\0';
1376 wl_tdm_vblank_set_name(private_vblank->vblank, private_vblank->name);
1378 pthread_mutex_unlock(&private_client->lock);
1380 return TDM_ERROR_NONE;
1384 tdm_client_vblank_set_sync(tdm_client_vblank *vblank, unsigned int sync)
1386 tdm_private_client_vblank *private_vblank;
1387 tdm_private_client *private_client;
1389 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1391 private_vblank = vblank;
1392 private_client = private_vblank->private_output->private_client;
1394 pthread_mutex_lock(&private_client->lock);
1395 private_vblank->sync = sync;
1396 pthread_mutex_unlock(&private_client->lock);
1398 return TDM_ERROR_NONE;
1402 tdm_client_vblank_set_fps(tdm_client_vblank *vblank, unsigned int fps)
1404 tdm_private_client_vblank *private_vblank;
1405 tdm_private_client *private_client;
1407 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1408 TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER);
1410 private_vblank = vblank;
1411 private_client = private_vblank->private_output->private_client;
1413 pthread_mutex_lock(&private_client->lock);
1415 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1416 pthread_mutex_unlock(&private_client->lock);
1417 return TDM_ERROR_PROTOCOL_ERROR;
1420 if (private_vblank->fps == fps) {
1421 pthread_mutex_unlock(&private_client->lock);
1422 return TDM_ERROR_NONE;
1425 private_vblank->fps = fps;
1427 wl_tdm_vblank_set_fps(private_vblank->vblank, fps);
1429 pthread_mutex_unlock(&private_client->lock);
1431 return TDM_ERROR_NONE;
1435 tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms)
1437 tdm_private_client_vblank *private_vblank;
1438 tdm_private_client *private_client;
1440 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1442 private_vblank = vblank;
1443 TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
1445 private_client = private_vblank->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->offset == offset_ms) {
1455 pthread_mutex_unlock(&private_client->lock);
1456 return TDM_ERROR_NONE;
1459 private_vblank->offset = offset_ms;
1461 wl_tdm_vblank_set_offset(private_vblank->vblank, offset_ms);
1463 pthread_mutex_unlock(&private_client->lock);
1465 return TDM_ERROR_NONE;
1469 tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable_fake)
1471 tdm_private_client_vblank *private_vblank;
1472 tdm_private_client *private_client;
1474 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1476 private_vblank = vblank;
1477 private_client = private_vblank->private_output->private_client;
1479 pthread_mutex_lock(&private_client->lock);
1481 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1482 pthread_mutex_unlock(&private_client->lock);
1483 return TDM_ERROR_PROTOCOL_ERROR;
1486 if (private_vblank->enable_fake == enable_fake) {
1487 pthread_mutex_unlock(&private_client->lock);
1488 return TDM_ERROR_NONE;
1491 private_vblank->enable_fake = enable_fake;
1493 wl_tdm_vblank_set_enable_fake(private_vblank->vblank, enable_fake);
1495 pthread_mutex_unlock(&private_client->lock);
1497 return TDM_ERROR_NONE;
1501 _tdm_client_vblank_wait(tdm_client_vblank *vblank, tdm_client_vblank_wait_type wait_type, unsigned int wait_value,
1502 tdm_client_vblank_handler func, void *user_data)
1504 tdm_private_client *private_client;
1505 tdm_private_client_output *private_output;
1506 tdm_private_client_vblank *private_vblank;
1507 tdm_client_wait_info *w;
1509 unsigned int req_sec, req_usec;
1512 private_vblank = vblank;
1513 private_output = private_vblank->private_output;
1514 private_client = private_output->private_client;
1516 pthread_mutex_lock(&private_client->lock);
1518 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1519 pthread_mutex_unlock(&private_client->lock);
1520 return TDM_ERROR_PROTOCOL_ERROR;
1523 if (!private_vblank->started)
1524 private_vblank->started = 1;
1526 if (!private_vblank->enable_fake) {
1527 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1528 TDM_ERR("output disconnected");
1529 pthread_mutex_unlock(&private_client->lock);
1530 return TDM_ERROR_OUTPUT_DISCONNECTED;
1532 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1533 TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1534 pthread_mutex_unlock(&private_client->lock);
1535 return TDM_ERROR_DPMS_OFF;
1539 w = calloc(1, sizeof *w);
1541 /* LCOV_EXCL_START */
1543 TDM_ERR("alloc failed");
1544 pthread_mutex_unlock(&private_client->lock);
1545 return TDM_ERROR_OUT_OF_MEMORY;
1547 /* LCOV_EXCL_STOP */
1550 w->private_vblank = private_vblank;
1552 w->user_data = user_data;
1554 LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1555 LIST_INITHEAD(&w->call_link);
1557 clock_gettime(CLOCK_MONOTONIC, &tp);
1558 req_sec = (unsigned int)tp.tv_sec;
1559 req_usec = (unsigned int)(tp.tv_nsec / 1000);
1561 w->req_id = ++private_output->req_id;
1562 w->req_time = TDM_TIME(req_sec, req_usec);
1563 w->need_free = (private_vblank->sync) ? 0 : 1;
1565 if (wait_type == VBLANK_WAIT_TYPE_INTERVAL)
1566 wl_tdm_vblank_wait_vblank(private_vblank->vblank, wait_value, w->req_id, req_sec, req_usec);
1568 wl_tdm_vblank_wait_vblank_seq(private_vblank->vblank, wait_value, w->req_id, req_sec, req_usec);
1570 if (private_vblank->enable_ttrace)
1571 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1573 TDM_DBG("vblank(%p) wait_type(%d) wait_value(%u) req_id(%d) req(%.6f)",
1574 vblank, wait_type, wait_value, w->req_id, w->req_time);
1576 private_vblank->req_time = w->req_time;
1578 if (private_vblank->last_time >= w->req_time)
1579 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1581 if (!private_vblank->sync) {
1582 wl_display_flush(private_client->display);
1583 pthread_mutex_unlock(&private_client->lock);
1584 return TDM_ERROR_NONE;
1587 /* LCOV_EXCL_START */
1589 while (ret != -1 && !w->need_free)
1590 ret = wl_display_dispatch(private_client->display);
1592 clock_gettime(CLOCK_MONOTONIC, &tp);
1593 TDM_DBG("block during %d us",
1594 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1595 - (req_sec * 1000000 + req_usec));
1600 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1601 pthread_mutex_unlock(&private_client->lock);
1602 return TDM_ERROR_PROTOCOL_ERROR;
1605 pthread_mutex_unlock(&private_client->lock);
1607 return TDM_ERROR_NONE;
1609 /* LCOV_EXCL_STOP */
1613 tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_client_vblank_handler func, void *user_data)
1615 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1616 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1618 /* can't support "interval 0" and "getting current_msc" things because
1619 * there is a socket communication between TDM client and server. It's impossible
1620 * to return the current msc or sequence immediately.
1622 TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
1624 return _tdm_client_vblank_wait(vblank, VBLANK_WAIT_TYPE_INTERVAL, interval, func, user_data);
1628 tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
1629 tdm_client_vblank_handler func, void *user_data)
1631 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1632 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1634 return _tdm_client_vblank_wait(vblank, VBLANK_WAIT_TYPE_SEQUENCE, sequence, func, user_data);
1638 tdm_client_vblank_is_waiting(tdm_client_vblank *vblank)
1640 tdm_private_client_vblank *private_vblank;
1642 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, 0);
1644 private_vblank = vblank;
1646 return (LIST_LENGTH(&private_vblank->wait_list) > 0) ? 1 : 0;
1649 static tbm_surface_h
1650 _tdm_client_voutput_create_surface_from_param(tbm_bufmgr bufmgr,
1658 struct wl_array *plane_buf_idx,
1659 struct wl_array *plane_offset,
1660 struct wl_array *plane_stride,
1661 struct wl_array *plane_size,
1668 int32_t names[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1};
1669 tbm_surface_info_s info = { 0, };
1670 tbm_bo bos[TBM_SURF_PLANE_MAX];
1671 int i, numPlane, numName;
1672 tbm_surface_h tbm_surface;
1674 numPlane = tbm_surface_internal_get_num_planes(format);
1675 TDM_RETURN_VAL_IF_FAIL(numPlane == num_plane, NULL);
1678 info.height = height;
1679 info.format = format;
1682 info.num_planes = numPlane;
1685 for (i = 0; i < numPlane; i++) {
1686 info.planes[i].offset = *TDM_ARRAY_NTH_DATA(plane_offset, int32_t, i);
1687 info.planes[i].stride = *TDM_ARRAY_NTH_DATA(plane_stride, int32_t, i);
1688 info.planes[i].size = *TDM_ARRAY_NTH_DATA(plane_size, int32_t, i);
1697 for (i = 0; i < numName; i++) {
1699 bos[i] = tbm_bo_import_fd(bufmgr, names[i]);
1701 bos[i] = tbm_bo_import(bufmgr, names[i]);
1704 tbm_surface = tbm_surface_internal_create_with_bos(&info, bos, numName);
1705 if (tbm_surface == NULL) {
1720 for (i = 0; i < numName; i++)
1721 tbm_bo_unref(bos[i]);
1726 static tdm_private_client_buffer *
1727 _tdm_client_voutput_create_buffer(tdm_private_client_voutput *private_voutput,
1728 tbm_surface_h tbm_surface,
1729 struct wl_buffer *wl_buffer)
1731 tdm_private_client_buffer *buffer = NULL;
1733 buffer = calloc(1, sizeof *buffer);
1734 TDM_RETURN_VAL_IF_FAIL(buffer != NULL, NULL);
1736 tbm_surface_internal_ref(tbm_surface);
1737 wl_buffer_set_user_data(wl_buffer, tbm_surface);
1739 buffer->wl_buffer = wl_buffer;
1741 LIST_ADDTAIL(&buffer->link, &private_voutput->buffer_list);
1747 tdm_client_voutput_cb_buffer_import_with_id(void *data,
1748 struct wl_tdm_voutput *wl_voutput,
1749 struct wl_buffer *wl_buffer,
1756 struct wl_array *plane_buf_idx,
1757 struct wl_array *plane_offset,
1758 struct wl_array *plane_stride,
1759 struct wl_array *plane_size,
1766 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1767 tdm_private_client_buffer *buffer = NULL;
1768 tbm_surface_h tbm_surface;
1770 TDM_RETURN_IF_FAIL(private_voutput != NULL);
1772 tbm_surface = _tdm_client_voutput_create_surface_from_param(private_voutput->bufmgr, 0,
1773 width, height, format, bpp, size,
1775 plane_buf_idx, plane_offset, plane_stride, plane_size,
1779 TDM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
1781 buffer = _tdm_client_voutput_create_buffer(private_voutput, tbm_surface, wl_buffer);
1782 TDM_GOTO_IF_FAIL(buffer != NULL, fail);
1788 wl_buffer_destroy(wl_buffer);
1792 tdm_client_voutput_cb_buffer_import_with_fd(void *data,
1793 struct wl_tdm_voutput *wl_voutput,
1794 struct wl_buffer *wl_buffer,
1801 struct wl_array *plane_buf_idx,
1802 struct wl_array *plane_offset,
1803 struct wl_array *plane_stride,
1804 struct wl_array *plane_size,
1811 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1812 tdm_private_client_buffer *buffer = NULL;
1813 tbm_surface_h tbm_surface;
1815 TDM_RETURN_IF_FAIL(private_voutput != NULL);
1817 tbm_surface = _tdm_client_voutput_create_surface_from_param(private_voutput->bufmgr, 1,
1818 width, height, format, bpp, size,
1820 plane_buf_idx, plane_offset, plane_stride, plane_size,
1824 TDM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
1826 buffer = _tdm_client_voutput_create_buffer(private_voutput, tbm_surface, wl_buffer);
1827 TDM_GOTO_IF_FAIL(buffer != NULL, fail);
1833 wl_buffer_destroy(wl_buffer);
1837 tdm_client_voutput_cb_buffer_destroy(void *data,
1838 struct wl_tdm_voutput *wl_voutput,
1839 struct wl_buffer *wl_buffer)
1841 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1842 tdm_private_client_buffer *cb = NULL, *cbb = NULL;
1843 tbm_surface_h tbm_surface = NULL;
1845 TDM_RETURN_IF_FAIL(private_voutput != NULL);
1847 LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
1848 if (wl_buffer == cb->wl_buffer) {
1849 LIST_DEL(&cb->link);
1851 tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(wl_buffer);
1853 tbm_surface_internal_unref(tbm_surface);
1855 wl_buffer_set_user_data(wl_buffer, NULL);
1856 wl_buffer_destroy(wl_buffer);
1868 tdm_client_voutput_cb_attach_buffer(void *data,
1869 struct wl_tdm_voutput *wl_voutput,
1870 struct wl_buffer *wl_buffer)
1872 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1873 tdm_private_client_buffer *cb = NULL, *cbb = NULL;
1875 TDM_RETURN_IF_FAIL(private_voutput != NULL);
1877 LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
1878 if (wl_buffer == cb->wl_buffer) {
1879 private_voutput->attach_buffer = cb;
1888 tdm_client_voutput_cb_commit(void *data, struct wl_tdm_voutput *wl_voutput)
1890 tdm_private_client_voutput *private_voutput;
1891 tdm_private_client *private_client;
1892 tbm_surface_h buffer = NULL;
1893 tdm_client_voutput_commit_handler_info *h = NULL, *hh = NULL;
1894 struct list_head call_list;
1896 private_voutput = (tdm_private_client_voutput *)data;
1897 TDM_RETURN_IF_FAIL(private_voutput != NULL);
1898 TDM_RETURN_IF_FAIL(private_voutput->attach_buffer != NULL);
1900 buffer = (tbm_surface_h)wl_buffer_get_user_data(private_voutput->attach_buffer->wl_buffer);
1901 TDM_RETURN_IF_FAIL(buffer != NULL);
1903 tbm_surface_internal_ref(buffer);
1905 private_client = private_voutput->private_client;
1907 LIST_INITHEAD(&call_list);
1909 LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
1910 LIST_ADDTAIL(&h->call_link, &call_list);
1913 pthread_mutex_unlock(&private_client->lock);
1914 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
1916 h->func(private_voutput, buffer, h->user_data);
1919 /* if no added commit_handler call commit done immediately */
1920 if (LIST_IS_EMPTY(&private_voutput->commit_handler_list))
1921 tdm_client_voutput_commit_done(private_voutput);
1923 pthread_mutex_lock(&private_client->lock);
1927 tdm_client_voutput_cb_ack_message(void *data, struct wl_tdm_voutput *wl_voutput, uint32_t msg)
1929 tdm_private_client_voutput *private_voutput = data;
1931 private_voutput->msg = msg;
1934 static const struct wl_tdm_voutput_listener tdm_client_voutput_lisntener = {
1935 tdm_client_voutput_cb_buffer_import_with_id,
1936 tdm_client_voutput_cb_buffer_import_with_fd,
1937 tdm_client_voutput_cb_buffer_destroy,
1938 tdm_client_voutput_cb_attach_buffer,
1939 tdm_client_voutput_cb_commit,
1940 tdm_client_voutput_cb_ack_message
1943 tdm_client_voutput *
1944 tdm_client_create_voutput(tdm_client *client, const char *name, tdm_error *error)
1946 tdm_private_client *private_client;
1947 tdm_private_client_output *private_output = NULL;
1948 tdm_private_client_voutput *private_voutput;
1949 struct wl_proxy *wrapper;
1952 *error = TDM_ERROR_NONE;
1955 TDM_ERR("'!client' failed");
1957 *error = TDM_ERROR_INVALID_PARAMETER;
1962 TDM_ERR("'!name' failed");
1964 *error = TDM_ERROR_INVALID_PARAMETER;
1968 private_client = (tdm_private_client *)client;
1970 pthread_mutex_lock(&private_client->lock);
1972 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1974 *error = TDM_ERROR_PROTOCOL_ERROR;
1975 pthread_mutex_unlock(&private_client->lock);
1979 LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
1980 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
1982 *error = TDM_ERROR_INVALID_PARAMETER; // FIXME define new error type.
1983 pthread_mutex_unlock(&private_client->lock);
1988 wrapper = wl_proxy_create_wrapper(private_client->tdm);
1990 TDM_ERR("create virtual output wrapper failed");
1992 *error = TDM_ERROR_OUT_OF_MEMORY;
1993 pthread_mutex_unlock(&private_client->lock);
1997 wl_proxy_set_queue(wrapper, private_client->queue);
1999 private_voutput = calloc(1, sizeof *private_voutput);
2000 if (!private_voutput) {
2001 /* LOCV_EXCL_START */
2002 wl_proxy_wrapper_destroy(wrapper);
2003 TDM_ERR("alloc failed");
2005 *error = TDM_ERROR_OUT_OF_MEMORY;
2006 pthread_mutex_unlock(&private_client->lock);
2008 /* LOCV_EXCL_STOP */
2011 private_voutput->bufmgr = tbm_bufmgr_init(-1);
2012 if (private_voutput->bufmgr == NULL) {
2013 /* LCOV_EXCL_START */
2014 wl_proxy_wrapper_destroy(wrapper);
2015 TDM_ERR("fail tbm_bufmgr_init");
2016 free(private_voutput);
2018 *error = TDM_ERROR_OUT_OF_MEMORY;
2019 pthread_mutex_unlock(&private_client->lock);
2021 /* LCOV_EXCL_STOP */
2024 LIST_INITHEAD(&private_voutput->commit_handler_list);
2025 LIST_INITHEAD(&private_voutput->buffer_list);
2027 private_voutput->private_client = private_client;
2028 strncpy(private_voutput->name, name, TDM_NAME_LEN - 1);
2029 private_voutput->name[TDM_NAME_LEN - 1] = '\0';
2031 private_voutput->wl_voutput = wl_tdm_create_voutput((struct wl_tdm *)wrapper, name);
2032 wl_proxy_wrapper_destroy(wrapper);
2033 if (!private_voutput->wl_voutput) {
2034 /* LCOV_EXCL_START */
2035 TDM_ERR("couldn't create voutput resource");
2036 free(private_voutput);
2038 *error = TDM_ERROR_OUT_OF_MEMORY;
2039 pthread_mutex_unlock(&private_client->lock);
2041 /* LCOV_EXCL_STOP */
2044 wl_tdm_voutput_add_listener(private_voutput->wl_voutput,
2045 &tdm_client_voutput_lisntener, private_voutput);
2046 wl_display_roundtrip_queue(private_client->display, private_client->queue);
2048 wl_proxy_set_queue((struct wl_proxy *)private_voutput->wl_voutput, NULL);
2050 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2051 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2052 free(private_voutput);
2054 *error = TDM_ERROR_PROTOCOL_ERROR;
2055 pthread_mutex_unlock(&private_client->lock);
2059 if (private_voutput->msg != WL_TDM_VOUTPUT_MESSAGE_ADDED) {
2060 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2061 free(private_voutput);
2063 *error = TDM_ERROR_PROTOCOL_ERROR; // FIXME add new error type.
2064 pthread_mutex_unlock(&private_client->lock);
2068 LIST_ADDTAIL(&private_voutput->link, &private_client->voutput_list);
2070 pthread_mutex_unlock(&private_client->lock);
2072 return (tdm_client_voutput *)private_voutput;
2076 tdm_client_voutput_destroy(tdm_client_voutput *voutput)
2078 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)voutput;
2079 tdm_private_client *private_client;
2080 tdm_client_voutput_commit_handler_info *h = NULL, *hh = NULL;
2082 if (!private_voutput)
2084 private_client = private_voutput->private_client;
2086 pthread_mutex_lock(&private_client->lock);
2088 if (!(LIST_IS_EMPTY(&private_voutput->buffer_list))) {
2089 tdm_private_client_buffer *cb = NULL, *cbb = NULL;
2091 LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
2092 tbm_surface_h tbm_surface = NULL;
2094 LIST_DEL(&cb->link);
2096 tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(cb->wl_buffer);
2098 tbm_surface_internal_unref(tbm_surface);
2100 wl_buffer_set_user_data(cb->wl_buffer, NULL);
2101 wl_buffer_destroy(cb->wl_buffer);
2107 if (private_voutput->bufmgr)
2108 tbm_bufmgr_deinit(private_voutput->bufmgr);
2110 if (private_voutput->available_modes.modes)
2111 free(private_voutput->available_modes.modes);
2113 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_voutput->commit_handler_list, link) {
2118 if (private_voutput->get_output)
2119 _tdm_client_output_destroy(private_voutput->private_output);
2121 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2123 LIST_DEL(&private_voutput->link);
2125 free(private_voutput);
2127 pthread_mutex_unlock(&private_client->lock);
2131 tdm_client_voutput_set_available_modes(tdm_client_voutput *voutput, const tdm_client_output_mode *modes, int count)
2133 tdm_private_client_voutput *private_voutput;
2134 tdm_private_client *private_client;
2135 tdm_error ret = TDM_ERROR_NONE;
2137 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2139 if ((count > 0) && (modes == NULL))
2140 return TDM_ERROR_INVALID_PARAMETER;
2142 private_voutput = (tdm_private_client_voutput *)voutput;
2143 private_client = private_voutput->private_client;
2145 if (!private_voutput->private_output) {
2146 private_voutput->private_output = tdm_client_voutput_get_client_output(private_voutput, &ret);
2147 TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, TDM_ERROR_OPERATION_FAILED);
2150 pthread_mutex_lock(&private_client->lock);
2152 if (private_voutput->private_output->connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
2153 pthread_mutex_unlock(&private_client->lock);
2154 return TDM_ERROR_BAD_REQUEST;
2157 if (private_voutput->available_modes.modes)
2158 free(private_voutput->available_modes.modes);
2160 private_voutput->available_modes.count = count;
2163 private_voutput->available_modes.modes = calloc(count, sizeof(tdm_client_output_mode));
2164 if (private_voutput->available_modes.modes == NULL) {
2165 private_voutput->available_modes.count = 0;
2166 pthread_mutex_unlock(&private_client->lock);
2167 return TDM_ERROR_OUT_OF_MEMORY;
2169 memcpy(private_voutput->available_modes.modes, modes, sizeof(tdm_client_output_mode) * count);
2172 pthread_mutex_unlock(&private_client->lock);
2174 return TDM_ERROR_NONE;
2178 tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, unsigned int mmWidth, unsigned int mmHeight)
2180 tdm_private_client_voutput *private_voutput;
2181 tdm_private_client *private_client;
2182 tdm_error ret = TDM_ERROR_NONE;
2184 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2185 TDM_RETURN_VAL_IF_FAIL(mmWidth != 0, TDM_ERROR_INVALID_PARAMETER);
2186 TDM_RETURN_VAL_IF_FAIL(mmHeight != 0, TDM_ERROR_INVALID_PARAMETER);
2188 private_voutput = (tdm_private_client_voutput *)voutput;
2189 private_client = private_voutput->private_client;
2191 if (!private_voutput->private_output) {
2192 private_voutput->private_output = tdm_client_voutput_get_client_output(private_voutput, &ret);
2193 TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, TDM_ERROR_OPERATION_FAILED);
2196 pthread_mutex_lock(&private_client->lock);
2198 if (private_voutput->private_output->connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
2199 pthread_mutex_unlock(&private_client->lock);
2200 return TDM_ERROR_BAD_REQUEST;
2203 private_voutput->mmwidth = mmWidth;
2204 private_voutput->mmheight = mmHeight;
2206 pthread_mutex_unlock(&private_client->lock);
2208 return TDM_ERROR_NONE;
2212 tdm_client_voutput_add_commit_handler(tdm_client_voutput *voutput,
2213 tdm_client_voutput_commit_handler func,
2216 tdm_private_client_voutput *private_voutput;
2217 tdm_private_client *private_client;
2218 tdm_client_voutput_commit_handler_info *h = NULL;
2220 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2221 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
2223 private_voutput = (tdm_private_client_voutput *)voutput;
2224 private_client = private_voutput->private_client;
2226 LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2227 if (h->func == func && h->user_data == user_data) {
2228 TDM_ERR("can't add twice");
2229 return TDM_ERROR_BAD_REQUEST;
2233 h = calloc(1, sizeof *h);
2234 TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
2236 pthread_mutex_lock(&private_client->lock);
2238 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2240 pthread_mutex_unlock(&private_client->lock);
2241 return TDM_ERROR_PROTOCOL_ERROR;
2244 h->private_voutput = private_voutput;
2246 h->user_data = user_data;
2247 LIST_ADDTAIL(&h->link, &private_voutput->commit_handler_list);
2248 LIST_INITHEAD(&h->call_link);
2250 pthread_mutex_unlock(&private_client->lock);
2252 return TDM_ERROR_NONE;
2256 tdm_client_voutput_remove_commit_handler(tdm_client_voutput *voutput,
2257 tdm_client_voutput_commit_handler func,
2260 tdm_private_client_voutput *private_voutput;
2261 tdm_private_client *private_client;
2262 tdm_client_voutput_commit_handler_info *h = NULL;
2264 TDM_RETURN_IF_FAIL(voutput != NULL);
2265 TDM_RETURN_IF_FAIL(func != NULL);
2267 private_voutput = (tdm_private_client_voutput *)voutput;
2268 private_client = private_voutput->private_client;
2270 pthread_mutex_lock(&private_client->lock);
2272 LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2273 if (h->func != func || h->user_data != user_data)
2279 pthread_mutex_unlock(&private_client->lock);
2284 pthread_mutex_unlock(&private_client->lock);
2288 tdm_client_voutput_commit_done(tdm_client_voutput *voutput)
2290 tdm_private_client_voutput *private_voutput;
2291 tdm_private_client *private_client;
2292 tbm_surface_h buffer = NULL;
2294 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2296 private_voutput = (tdm_private_client_voutput *)voutput;
2297 TDM_RETURN_VAL_IF_FAIL(private_voutput->attach_buffer != NULL, TDM_ERROR_NONE);
2299 private_client = private_voutput->private_client;
2301 pthread_mutex_lock(&private_client->lock);
2303 buffer = (tbm_surface_h)wl_buffer_get_user_data(private_voutput->attach_buffer->wl_buffer);
2304 tbm_surface_internal_unref(buffer);
2305 private_voutput->attach_buffer = NULL;
2306 wl_tdm_voutput_commit_done(private_voutput->wl_voutput);
2308 pthread_mutex_unlock(&private_client->lock);
2310 return TDM_ERROR_NONE;
2314 tdm_client_voutput_get_client_output(tdm_client_voutput *voutput, tdm_error *error)
2316 tdm_private_client_voutput *private_voutput;
2317 tdm_private_client_output *private_output = NULL;
2318 tdm_private_client *private_client;
2319 tdm_error ret = TDM_ERROR_NONE;
2322 *error = TDM_ERROR_NONE;
2325 TDM_ERR("'!voutput' failed");
2327 *error = TDM_ERROR_INVALID_PARAMETER;
2331 private_voutput = (tdm_private_client_voutput *)voutput;
2332 private_client = private_voutput->private_client;
2334 pthread_mutex_lock(&private_client->lock);
2336 if (private_voutput->get_output) {
2337 pthread_mutex_unlock(&private_client->lock);
2338 return private_voutput->private_output;
2341 pthread_mutex_unlock(&private_client->lock);
2342 private_output = (tdm_private_client_output *)tdm_client_get_output(private_voutput->private_client, private_voutput->name, &ret);
2343 if (!private_output) {
2344 TDM_ERR("tdm_client_voutput_get_client_output get private_output fail");
2349 pthread_mutex_lock(&private_client->lock);
2350 private_output->voutput = private_voutput;
2351 private_voutput->private_output = private_output;
2352 private_voutput->get_output = 1;
2354 pthread_mutex_unlock(&private_client->lock);
2356 return private_output;
2360 _tdm_client_voutput_send_available_modes(tdm_private_client_voutput *private_voutput)
2362 tdm_client_output_mode *modes, *mode;
2363 struct wl_array array;
2367 modes = private_voutput->available_modes.modes;
2368 size = sizeof(tdm_client_output_mode);
2370 wl_array_init(&array);
2371 for (i = 0; i < private_voutput->available_modes.count; i++) {
2372 mode = wl_array_add(&array, size);
2373 memcpy(mode, &modes[i], size);
2375 wl_tdm_voutput_set_available_modes(private_voutput->wl_voutput, &array);
2376 wl_array_release(&array);
2380 tdm_client_voutput_connect(tdm_client_voutput *voutput)
2382 tdm_private_client_output *private_output = NULL;;
2383 tdm_private_client_voutput *private_voutput = NULL;
2384 tdm_private_client *private_client;
2386 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2388 private_voutput = (tdm_private_client_voutput *)voutput;
2389 private_client = private_voutput->private_client;
2390 private_output = private_voutput->private_output;
2392 pthread_mutex_lock(&private_client->lock);
2394 if (private_output->connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
2395 pthread_mutex_unlock(&private_client->lock);
2396 return TDM_ERROR_NONE;
2399 if (!private_output->watch_output_changes)
2400 private_output->connection = TDM_OUTPUT_CONN_STATUS_CONNECTED;
2402 _tdm_client_voutput_send_available_modes(private_voutput);
2404 wl_tdm_voutput_set_physical_size(private_voutput->wl_voutput, private_voutput->mmwidth, private_voutput->mmheight);
2406 wl_tdm_voutput_connect(private_voutput->wl_voutput);
2408 pthread_mutex_unlock(&private_client->lock);
2410 return TDM_ERROR_NONE;
2414 tdm_client_voutput_disconnect(tdm_client_voutput *voutput)
2416 tdm_private_client_output *private_output = NULL;
2417 tdm_private_client_voutput *private_voutput = NULL;
2418 tdm_private_client *private_client;
2420 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2422 private_voutput = (tdm_private_client_voutput *)voutput;
2423 private_client = private_voutput->private_client;
2424 private_output = private_voutput->private_output;
2426 pthread_mutex_lock(&private_client->lock);
2428 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
2429 pthread_mutex_unlock(&private_client->lock);
2430 return TDM_ERROR_NONE;
2433 if (!private_output->watch_output_changes)
2434 private_output->connection = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
2436 wl_tdm_voutput_disconnect(private_voutput->wl_voutput);
2438 pthread_mutex_unlock(&private_client->lock);
2440 return TDM_ERROR_NONE;
2445 tdm_client_voutput_set_mode(tdm_client_voutput *voutput, int index)
2447 tdm_private_client_output *private_output;
2448 tdm_private_client_voutput *private_voutput = NULL;
2449 tdm_private_client *private_client;
2451 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2452 TDM_RETURN_VAL_IF_FAIL(index >= 0, TDM_ERROR_INVALID_PARAMETER);
2454 private_voutput = (tdm_private_client_voutput *)voutput;
2455 private_client = private_voutput->private_client;
2456 private_output = private_voutput->private_output;
2458 pthread_mutex_lock(&private_client->lock);
2460 if (private_voutput->available_modes.count - 1 < index) {
2461 pthread_mutex_unlock(&private_client->lock);
2462 return TDM_ERROR_INVALID_PARAMETER;
2465 if ((private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) ||
2466 (private_voutput->available_modes.count == 0)) {
2467 pthread_mutex_unlock(&private_client->lock);
2468 return TDM_ERROR_BAD_REQUEST;
2471 TDM_DBG("mode_set request : %d", index);
2473 wl_tdm_voutput_set_mode(private_voutput->wl_voutput, index);
2475 pthread_mutex_unlock(&private_client->lock);
2477 return TDM_ERROR_NONE;