implement for sync fo tdm_client_wait_vblank
[platform/core/uifw/libtdm.git] / client / tdm_client.c
1 /**************************************************************************
2
3 libtdm
4
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6
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>
13
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:
21
22 The above copyright notice and this permission notice (including the
23 next paragraph) shall be included in all copies or substantial portions
24 of the Software.
25
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.
33
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <time.h>
44
45 #include "tdm_client.h"
46 #include "tdm_log.h"
47 #include "tdm_macro.h"
48 #include "tdm_list.h"
49 #include "tdm-client-protocol.h"
50
51 int tdm_debug;
52
53 typedef struct _tdm_private_client {
54         struct wl_display *display;
55         struct wl_registry *registry;
56         struct wl_tdm *tdm;
57
58         struct list_head vblank_list;
59 } tdm_private_client;
60
61 typedef struct _tdm_client_vblank_info {
62         struct list_head link;
63         struct wl_tdm_vblank *vblank;
64         tdm_client_vblank_handler func;
65         unsigned int req_sec;
66         unsigned int req_usec;
67         void *user_data;
68         int need_free;
69 } tdm_client_vblank_info;
70
71 static void
72 _tdm_client_cb_global(void *data, struct wl_registry *registry,
73                       uint32_t name, const char *interface,
74                       uint32_t version)
75 {
76         tdm_private_client *private_client = data;
77
78         if (strcmp(interface, "wl_tdm") == 0) {
79                 private_client->tdm =
80                         wl_registry_bind(registry, name, &wl_tdm_interface, version);
81                 TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
82
83                 wl_display_flush(private_client->display);
84         }
85 }
86
87 static void
88 _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
89 {
90 }
91
92 static const struct wl_registry_listener tdm_client_registry_listener =
93 {
94     _tdm_client_cb_global,
95     _tdm_client_cb_global_remove
96 };
97
98 tdm_client*
99 tdm_client_create(tdm_client_error *error)
100 {
101         tdm_private_client *private_client;
102         const char *debug;
103
104         debug = getenv("TDM_DEBUG");
105         if (debug && (strstr(debug, "1")))
106                 tdm_debug = 1;
107
108         private_client = calloc(1, sizeof *private_client);
109         if (!private_client) {
110                 TDM_ERR("alloc failed");
111                 if (error)
112                         *error = TDM_CLIENT_ERROR_OUT_OF_MEMORY;
113                 return NULL;
114         }
115
116         private_client->display = wl_display_connect("tdm-socket");
117         TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed);
118
119         private_client->registry = wl_display_get_registry(private_client->display);
120         TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed);
121
122         wl_registry_add_listener(private_client->registry,
123                                  &tdm_client_registry_listener, private_client);
124         wl_display_roundtrip(private_client->display);
125
126         /* check global objects */
127         TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed);
128
129         LIST_INITHEAD(&private_client->vblank_list);
130
131         if (error)
132                 *error = TDM_CLIENT_ERROR_NONE;
133
134         return (tdm_client*)private_client;
135 create_failed:
136         tdm_client_destroy((tdm_client*)private_client);
137         if (error)
138                 *error = TDM_CLIENT_ERROR_OPERATION_FAILED;
139         return NULL;
140 }
141
142 void
143 tdm_client_destroy(tdm_client *client)
144 {
145         tdm_private_client *private_client = (tdm_private_client*)client;
146         tdm_client_vblank_info *v = NULL, *vv = NULL;
147
148         if (!private_client)
149                 return;
150
151         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_client->vblank_list, link) {
152                 LIST_DEL(&v->link);
153                 wl_tdm_vblank_destroy(v->vblank);
154                 free(v);
155         }
156
157         if (private_client->tdm)
158                 wl_tdm_destroy(private_client->tdm);
159         if (private_client->registry)
160                 wl_registry_destroy(private_client->registry);
161         if (private_client->display)
162                 wl_display_disconnect(private_client->display);
163
164         free(private_client);
165 }
166
167 tdm_client_error
168 tdm_client_get_fd(tdm_client *client, int *fd)
169 {
170         tdm_private_client *private_client;
171
172         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
173         TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
174
175         private_client = (tdm_private_client*)client;
176
177         *fd = wl_display_get_fd(private_client->display);
178         if (*fd < 0)
179                 return TDM_CLIENT_ERROR_OPERATION_FAILED;
180
181         return TDM_CLIENT_ERROR_NONE;
182 }
183
184 tdm_client_error
185 tdm_client_handle_events(tdm_client *client)
186 {
187         tdm_private_client *private_client;
188
189         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
190
191         private_client = (tdm_private_client*)client;
192
193         wl_display_dispatch(private_client->display);
194
195         return TDM_CLIENT_ERROR_NONE;
196 }
197
198 static void
199 _tdm_client_cb_vblank_done(void *data, struct wl_tdm_vblank *vblank,
200                            uint32_t sequence, uint32_t tv_sec, uint32_t tv_usec)
201 {
202         tdm_client_vblank_info *vblank_info = (tdm_client_vblank_info*)data;
203
204         TDM_RETURN_IF_FAIL(vblank_info != NULL);
205
206         if (vblank_info->vblank != vblank)
207                 TDM_NEVER_GET_HERE();
208
209         TDM_DBG("vblank_info(%p) wl_tbm_vblank@%d", vblank_info,
210                 wl_proxy_get_id((struct wl_proxy *)vblank));
211
212         if (vblank_info->func) {
213                 vblank_info->func(sequence, tv_sec, tv_usec, vblank_info->user_data);
214         }
215
216         if (vblank_info->need_free) {
217                 LIST_DEL(&vblank_info->link);
218                 free(vblank_info);
219         } else {
220                 vblank_info->need_free = 1;
221         }
222 }
223
224 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
225         _tdm_client_cb_vblank_done,
226 };
227
228 tdm_client_error
229 tdm_client_wait_vblank(tdm_client *client, char *name,
230                        int sw_timer, int interval, int sync,
231                        tdm_client_vblank_handler func, void *user_data)
232 {
233         tdm_private_client *private_client = (tdm_private_client*)client;
234         tdm_client_vblank_info *vblank_info;
235         struct timespec tp;
236         int ret = 0;
237
238         TDM_RETURN_VAL_IF_FAIL(name != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
239         TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_CLIENT_ERROR_INVALID_PARAMETER);
240         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
241         TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
242         TDM_RETURN_VAL_IF_FAIL(private_client->tdm != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
243
244         vblank_info = calloc(1, sizeof *vblank_info);
245         if (!vblank_info) {
246                 TDM_ERR("alloc failed");
247                 return TDM_CLIENT_ERROR_OUT_OF_MEMORY;
248         }
249
250         clock_gettime(CLOCK_MONOTONIC, &tp);
251
252         vblank_info->req_sec = (unsigned int)tp.tv_sec;
253         vblank_info->req_usec = (unsigned int)(tp.tv_nsec/1000L);
254         vblank_info->need_free = (sync) ? 0 : 1;
255
256         vblank_info->vblank =
257                 wl_tdm_wait_vblank(private_client->tdm, name, sw_timer, interval,
258                                    vblank_info->req_sec, vblank_info->req_usec);
259         if (!vblank_info->vblank) {
260                 TDM_ERR("couldn't create vblank resource");
261                 free(vblank_info);
262                 return TDM_CLIENT_ERROR_OUT_OF_MEMORY;
263         }
264
265         TDM_DBG("vblank_info(%p) wl_tbm_vblank@%d", vblank_info,
266                 wl_proxy_get_id((struct wl_proxy *)vblank_info->vblank));
267
268         wl_tdm_vblank_add_listener(vblank_info->vblank,
269                                    &tdm_client_vblank_listener, vblank_info);
270
271         vblank_info->func = func;
272         vblank_info->user_data = user_data;
273         LIST_ADDTAIL(&vblank_info->link, &private_client->vblank_list);
274
275         if (!sync) {
276                 wl_display_flush(private_client->display);
277                 return TDM_CLIENT_ERROR_NONE;
278         }
279
280         while (ret != -1 && !vblank_info->need_free)
281                 ret = wl_display_dispatch(private_client->display);
282
283         clock_gettime(CLOCK_MONOTONIC, &tp);
284         TDM_DBG("block during %d us",
285                 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec/1000L))
286                 - (vblank_info->req_sec * 1000000 + vblank_info->req_usec));
287
288         LIST_DEL(&vblank_info->link);
289         free(vblank_info);
290
291         return TDM_CLIENT_ERROR_NONE;
292 }