add wl_tdm_client interface
[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         struct wl_tdm_client *tdm_client;
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         private_client->tdm_client = wl_tdm_create_client(private_client->tdm);
132         TDM_GOTO_IF_FAIL(private_client->tdm_client != NULL, create_failed);
133
134         if (error)
135                 *error = TDM_CLIENT_ERROR_NONE;
136
137         return (tdm_client*)private_client;
138 create_failed:
139         tdm_client_destroy((tdm_client*)private_client);
140         if (error)
141                 *error = TDM_CLIENT_ERROR_OPERATION_FAILED;
142         return NULL;
143 }
144
145 void
146 tdm_client_destroy(tdm_client *client)
147 {
148         tdm_private_client *private_client = (tdm_private_client*)client;
149         tdm_client_vblank_info *v = NULL, *vv = NULL;
150
151         if (!private_client)
152                 return;
153
154         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_client->vblank_list, link) {
155                 LIST_DEL(&v->link);
156                 wl_tdm_vblank_destroy(v->vblank);
157                 free(v);
158         }
159
160         if (private_client->tdm_client)
161                 wl_tdm_client_destroy(private_client->tdm_client);
162         if (private_client->tdm)
163                 wl_tdm_destroy(private_client->tdm);
164         if (private_client->registry)
165                 wl_registry_destroy(private_client->registry);
166         if (private_client->display)
167                 wl_display_disconnect(private_client->display);
168
169         free(private_client);
170 }
171
172 tdm_client_error
173 tdm_client_get_fd(tdm_client *client, int *fd)
174 {
175         tdm_private_client *private_client;
176
177         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
178         TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
179
180         private_client = (tdm_private_client*)client;
181
182         *fd = wl_display_get_fd(private_client->display);
183         if (*fd < 0)
184                 return TDM_CLIENT_ERROR_OPERATION_FAILED;
185
186         return TDM_CLIENT_ERROR_NONE;
187 }
188
189 tdm_client_error
190 tdm_client_handle_events(tdm_client *client)
191 {
192         tdm_private_client *private_client;
193
194         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
195
196         private_client = (tdm_private_client*)client;
197
198         wl_display_dispatch(private_client->display);
199
200         return TDM_CLIENT_ERROR_NONE;
201 }
202
203 static void
204 _tdm_client_cb_vblank_done(void *data, struct wl_tdm_vblank *vblank,
205                            uint32_t sequence, uint32_t tv_sec, uint32_t tv_usec)
206 {
207         tdm_client_vblank_info *vblank_info = (tdm_client_vblank_info*)data;
208
209         TDM_RETURN_IF_FAIL(vblank_info != NULL);
210
211         if (vblank_info->vblank != vblank)
212                 TDM_NEVER_GET_HERE();
213
214         TDM_DBG("vblank_info(%p) wl_tbm_vblank@%d", vblank_info,
215                 wl_proxy_get_id((struct wl_proxy *)vblank));
216
217         if (vblank_info->func) {
218                 vblank_info->func(sequence, tv_sec, tv_usec, vblank_info->user_data);
219         }
220
221         if (vblank_info->need_free) {
222                 LIST_DEL(&vblank_info->link);
223                 free(vblank_info);
224         } else {
225                 vblank_info->need_free = 1;
226         }
227 }
228
229 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
230         _tdm_client_cb_vblank_done,
231 };
232
233 tdm_client_error
234 tdm_client_wait_vblank(tdm_client *client, char *name,
235                        int sw_timer, int interval, int sync,
236                        tdm_client_vblank_handler func, void *user_data)
237 {
238         tdm_private_client *private_client = (tdm_private_client*)client;
239         tdm_client_vblank_info *vblank_info;
240         struct timespec tp;
241         int ret = 0;
242
243         TDM_RETURN_VAL_IF_FAIL(name != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
244         TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_CLIENT_ERROR_INVALID_PARAMETER);
245         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
246         TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
247         TDM_RETURN_VAL_IF_FAIL(private_client->tdm_client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
248
249         vblank_info = calloc(1, sizeof *vblank_info);
250         if (!vblank_info) {
251                 TDM_ERR("alloc failed");
252                 return TDM_CLIENT_ERROR_OUT_OF_MEMORY;
253         }
254
255         clock_gettime(CLOCK_MONOTONIC, &tp);
256
257         vblank_info->req_sec = (unsigned int)tp.tv_sec;
258         vblank_info->req_usec = (unsigned int)(tp.tv_nsec/1000L);
259         vblank_info->need_free = (sync) ? 0 : 1;
260
261         vblank_info->vblank =
262                 wl_tdm_client_wait_vblank(private_client->tdm_client,
263                                           name, sw_timer, interval,
264                                           vblank_info->req_sec, vblank_info->req_usec);
265         if (!vblank_info->vblank) {
266                 TDM_ERR("couldn't create vblank resource");
267                 free(vblank_info);
268                 return TDM_CLIENT_ERROR_OUT_OF_MEMORY;
269         }
270
271         TDM_DBG("vblank_info(%p) wl_tbm_vblank@%d", vblank_info,
272                 wl_proxy_get_id((struct wl_proxy *)vblank_info->vblank));
273
274         wl_tdm_vblank_add_listener(vblank_info->vblank,
275                                    &tdm_client_vblank_listener, vblank_info);
276
277         vblank_info->func = func;
278         vblank_info->user_data = user_data;
279         LIST_ADDTAIL(&vblank_info->link, &private_client->vblank_list);
280
281         if (!sync) {
282                 wl_display_flush(private_client->display);
283                 return TDM_CLIENT_ERROR_NONE;
284         }
285
286         while (ret != -1 && !vblank_info->need_free)
287                 ret = wl_display_dispatch(private_client->display);
288
289         clock_gettime(CLOCK_MONOTONIC, &tp);
290         TDM_DBG("block during %d us",
291                 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec/1000L))
292                 - (vblank_info->req_sec * 1000000 + vblank_info->req_usec));
293
294         LIST_DEL(&vblank_info->link);
295         free(vblank_info);
296
297         return TDM_CLIENT_ERROR_NONE;
298 }