1 /**************************************************************************
5 * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
7 * Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8 * JinYoung Jeon <jy0.jeon@samsung.com>,
9 * Taeheon Kim <th908.kim@samsung.com>,
10 * YoungJun Cho <yj44.cho@samsung.com>,
11 * SooChan Lim <sc1.lim@samsung.com>,
12 * Boram Park <sc1.lim@samsung.com>
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of this software and associated documentation files (the
16 * "Software"), to deal in the Software without restriction, including
17 * without limitation the rights to use, copy, modify, merge, publish,
18 * distribute, sub license, and/or sell copies of the Software, and to
19 * permit persons to whom the Software is furnished to do so, subject to
20 * the following conditions:
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 **************************************************************************/
45 #include "tdm_client.h"
47 #include "tdm_macro.h"
49 #include "tdm-client-protocol.h"
53 typedef struct _tdm_private_client {
54 struct wl_display *display;
55 struct wl_registry *registry;
57 struct wl_tdm_client *tdm_client;
58 struct list_head vblank_list;
61 typedef struct _tdm_client_vblank_info {
62 struct list_head link;
63 struct wl_tdm_vblank *vblank;
64 tdm_client_vblank_handler func;
66 unsigned int req_usec;
69 } tdm_client_vblank_info;
72 _tdm_client_cb_global(void *data, struct wl_registry *registry,
73 uint32_t name, const char *interface,
76 tdm_private_client *private_client = data;
78 if (strcmp(interface, "wl_tdm") == 0) {
80 wl_registry_bind(registry, name, &wl_tdm_interface, version);
81 TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
83 wl_display_flush(private_client->display);
88 _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
92 static const struct wl_registry_listener tdm_client_registry_listener = {
93 _tdm_client_cb_global,
94 _tdm_client_cb_global_remove
98 tdm_client_create(tdm_client_error *error)
100 tdm_private_client *private_client;
103 debug = getenv("TDM_DEBUG");
104 if (debug && (strstr(debug, "1")))
107 private_client = calloc(1, sizeof * private_client);
108 if (!private_client) {
109 TDM_ERR("alloc failed");
111 *error = TDM_CLIENT_ERROR_OUT_OF_MEMORY;
115 private_client->display = wl_display_connect("tdm-socket");
116 TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed);
118 private_client->registry = wl_display_get_registry(private_client->display);
119 TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed);
121 wl_registry_add_listener(private_client->registry,
122 &tdm_client_registry_listener, private_client);
123 wl_display_roundtrip(private_client->display);
125 /* check global objects */
126 TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed);
128 LIST_INITHEAD(&private_client->vblank_list);
130 private_client->tdm_client = wl_tdm_create_client(private_client->tdm);
131 TDM_GOTO_IF_FAIL(private_client->tdm_client != NULL, create_failed);
134 *error = TDM_CLIENT_ERROR_NONE;
136 return (tdm_client*)private_client;
138 tdm_client_destroy((tdm_client*)private_client);
140 *error = TDM_CLIENT_ERROR_OPERATION_FAILED;
145 tdm_client_destroy(tdm_client *client)
147 tdm_private_client *private_client = (tdm_private_client*)client;
148 tdm_client_vblank_info *v = NULL, *vv = NULL;
153 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_client->vblank_list, link) {
155 wl_tdm_vblank_destroy(v->vblank);
159 if (private_client->tdm_client)
160 wl_tdm_client_destroy(private_client->tdm_client);
161 if (private_client->tdm)
162 wl_tdm_destroy(private_client->tdm);
163 if (private_client->registry)
164 wl_registry_destroy(private_client->registry);
165 if (private_client->display)
166 wl_display_disconnect(private_client->display);
168 free(private_client);
172 tdm_client_get_fd(tdm_client *client, int *fd)
174 tdm_private_client *private_client;
176 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
177 TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
179 private_client = (tdm_private_client*)client;
181 *fd = wl_display_get_fd(private_client->display);
183 return TDM_CLIENT_ERROR_OPERATION_FAILED;
185 return TDM_CLIENT_ERROR_NONE;
189 tdm_client_handle_events(tdm_client *client)
191 tdm_private_client *private_client;
193 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
195 private_client = (tdm_private_client*)client;
197 wl_display_dispatch(private_client->display);
199 return TDM_CLIENT_ERROR_NONE;
203 _tdm_client_cb_vblank_done(void *data, struct wl_tdm_vblank *vblank,
204 uint32_t sequence, uint32_t tv_sec, uint32_t tv_usec)
206 tdm_client_vblank_info *vblank_info = (tdm_client_vblank_info*)data;
208 TDM_RETURN_IF_FAIL(vblank_info != NULL);
210 if (vblank_info->vblank != vblank)
211 TDM_NEVER_GET_HERE();
213 TDM_DBG("vblank_info(%p) wl_tbm_vblank@%d", vblank_info,
214 wl_proxy_get_id((struct wl_proxy *)vblank));
216 if (vblank_info->func)
217 vblank_info->func(sequence, tv_sec, tv_usec, vblank_info->user_data);
219 if (vblank_info->need_free) {
220 LIST_DEL(&vblank_info->link);
223 vblank_info->need_free = 1;
227 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
228 _tdm_client_cb_vblank_done,
232 tdm_client_wait_vblank(tdm_client *client, char *name,
233 int sw_timer, int interval, int sync,
234 tdm_client_vblank_handler func, void *user_data)
236 tdm_private_client *private_client = (tdm_private_client*)client;
237 tdm_client_vblank_info *vblank_info;
241 TDM_RETURN_VAL_IF_FAIL(name != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
242 TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_CLIENT_ERROR_INVALID_PARAMETER);
243 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
244 TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
245 TDM_RETURN_VAL_IF_FAIL(private_client->tdm_client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
247 vblank_info = calloc(1, sizeof * vblank_info);
249 TDM_ERR("alloc failed");
250 return TDM_CLIENT_ERROR_OUT_OF_MEMORY;
253 clock_gettime(CLOCK_MONOTONIC, &tp);
255 vblank_info->req_sec = (unsigned int)tp.tv_sec;
256 vblank_info->req_usec = (unsigned int)(tp.tv_nsec / 1000);
257 vblank_info->need_free = (sync) ? 0 : 1;
259 vblank_info->vblank =
260 wl_tdm_client_wait_vblank(private_client->tdm_client,
261 name, sw_timer, interval,
262 vblank_info->req_sec, vblank_info->req_usec);
263 if (!vblank_info->vblank) {
264 TDM_ERR("couldn't create vblank resource");
266 return TDM_CLIENT_ERROR_OUT_OF_MEMORY;
269 TDM_DBG("vblank_info(%p) wl_tbm_vblank@%d", vblank_info,
270 wl_proxy_get_id((struct wl_proxy *)vblank_info->vblank));
272 wl_tdm_vblank_add_listener(vblank_info->vblank,
273 &tdm_client_vblank_listener, vblank_info);
275 vblank_info->func = func;
276 vblank_info->user_data = user_data;
277 LIST_ADDTAIL(&vblank_info->link, &private_client->vblank_list);
280 wl_display_flush(private_client->display);
281 return TDM_CLIENT_ERROR_NONE;
284 while (ret != -1 && !vblank_info->need_free)
285 ret = wl_display_dispatch(private_client->display);
287 clock_gettime(CLOCK_MONOTONIC, &tp);
288 TDM_DBG("block during %d us",
289 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
290 - (vblank_info->req_sec * 1000000 + vblank_info->req_usec));
292 LIST_DEL(&vblank_info->link);
295 return TDM_CLIENT_ERROR_NONE;