implement for sync fo tdm_client_wait_vblank
[platform/core/uifw/libtdm.git] / src / tdm_server.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 "tdm.h"
41 #include "tdm_private.h"
42 #include "tdm_list.h"
43 #include "tdm-server-protocol.h"
44
45 /* CAUTION:
46  * - tdm server doesn't care about thread things.
47  * - DO NOT use the TDM internal functions here.
48  */
49
50 struct _tdm_private_server {
51         struct list_head vblank_list;
52 };
53
54 typedef struct _tdm_server_vblank_info {
55         struct list_head link;
56         struct wl_resource *resource;
57         tdm_private_server *private_server;
58 } tdm_server_vblank_info;
59
60 static tdm_private_server *keep_private_server;
61 static int tdm_debug_server;
62
63 static void
64 _tdm_server_cb_output_vblank(tdm_output *output, unsigned int sequence,
65                              unsigned int tv_sec, unsigned int tv_usec,
66                              void *user_data)
67 {
68         tdm_server_vblank_info *vblank_info = (tdm_server_vblank_info*)user_data;
69         tdm_server_vblank_info *found;
70
71         if (!keep_private_server)
72                 return;
73
74         LIST_FIND_ITEM(vblank_info, &keep_private_server->vblank_list,
75                        tdm_server_vblank_info, link, found);
76         if (!found) {
77                 TDM_DBG("vblank_info(%p) is destroyed", vblank_info);
78                 return;
79         }
80
81         if (tdm_debug_server) {
82                 unsigned long curr = tdm_helper_get_time_in_micros();
83                 unsigned long vtime = (tv_sec * 1000000) + tv_usec;
84                 if (curr - vtime > 1000) /* 1ms */
85                         TDM_WRN("delay: %d us", (int)(curr - vtime));
86         }
87
88         TDM_DBG("wl_tdm_vblank@%d done", wl_resource_get_id(vblank_info->resource));
89
90         wl_tdm_vblank_send_done(vblank_info->resource, sequence, tv_sec, tv_usec);
91         wl_resource_destroy(vblank_info->resource);
92 }
93
94 static void
95 destroy_vblank_callback(struct wl_resource *resource)
96 {
97         tdm_server_vblank_info *vblank_info = wl_resource_get_user_data(resource);
98         LIST_DEL(&vblank_info->link);
99         free(vblank_info);
100 }
101
102 static void
103 _tdm_server_cb_wait_vblank(struct wl_client *client,
104                            struct wl_resource *resource,
105                            uint32_t id, const char *name, int32_t sw_timer,
106                            int32_t interval, uint32_t req_sec, uint32_t req_usec)
107 {
108         tdm_private_loop *private_loop = wl_resource_get_user_data(resource);
109         tdm_private_server *private_server = private_loop->private_server;
110         tdm_server_vblank_info *vblank_info;
111         struct wl_resource *vblank_resource;
112         tdm_output *found = NULL;
113         tdm_output_dpms dpms_value = TDM_OUTPUT_DPMS_ON;
114         int count = 0, i;
115         tdm_error ret;
116
117         TDM_DBG("The tdm client requests vblank");
118
119         if (tdm_debug_server) {
120                 unsigned long curr = tdm_helper_get_time_in_micros();
121                 unsigned long reqtime = (req_sec * 1000000) + req_usec;
122                 if (curr - reqtime > 1000) /* 1ms */
123                         TDM_WRN("delay(req): %d us", (int)(curr - reqtime));
124         }
125
126         tdm_display_get_output_count(private_loop->dpy, &count);
127
128         for (i = 0; i < count; i++) {
129                 tdm_output *output= tdm_display_get_output(private_loop->dpy, i, NULL);
130                 tdm_output_conn_status status;
131                 const char *model = NULL;
132
133                 ret = tdm_output_get_conn_status(output, &status);
134                 if (ret || status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
135                         continue;
136
137                 ret = tdm_output_get_model_info(output, NULL, &model, NULL);
138                 if (ret || !model)
139                         continue;
140
141                 if (strncmp(model, name, TDM_NAME_LEN))
142                         continue;
143
144                 found = output;
145                 break;
146         }
147
148         if (!found) {
149                 wl_resource_post_error(resource, WL_TDM_ERROR_INVALID_NAME,
150                                        "There is no '%s' output", name);
151                 TDM_ERR("There is no '%s' output", name);
152                 return;
153         }
154
155         tdm_output_get_dpms(found, &dpms_value);
156
157         if (dpms_value != TDM_OUTPUT_DPMS_ON && !sw_timer) {
158                 wl_resource_post_error(resource, WL_TDM_ERROR_DPMS_OFF,
159                                        "dpms '%s'", tdm_get_dpms_str(dpms_value));
160                 TDM_ERR("dpms '%s'", tdm_get_dpms_str(dpms_value));
161                 return;
162         }
163
164         vblank_info = calloc(1, sizeof *vblank_info);
165         if (!vblank_info) {
166                 wl_resource_post_no_memory(resource);
167                 TDM_ERR("alloc failed");
168                 return;
169         }
170
171         TDM_DBG("wl_tdm_vblank@%d output(%s) interval(%d)", id, name, interval);
172
173         vblank_resource =
174                 wl_resource_create(client, &wl_tdm_vblank_interface,
175                                    wl_resource_get_version(resource), id);
176         if (!vblank_resource) {
177                 wl_resource_post_no_memory(resource);
178                 TDM_ERR("wl_resource_create failed");
179                 goto free_info;
180         }
181
182         if (dpms_value == TDM_OUTPUT_DPMS_ON) {
183                 ret = tdm_output_wait_vblank(found, interval, 0,
184                                              _tdm_server_cb_output_vblank, vblank_info);
185                 if (ret != TDM_ERROR_NONE) {
186                         wl_resource_post_error(resource, WL_TDM_ERROR_OPERATION_FAILED,
187                                                "couldn't wait vblank for %s", name);
188                         TDM_ERR("couldn't wait vblank for %s", name);
189                         goto destroy_resource;
190                 }
191         } else if (sw_timer) {
192                 /* TODO: need to implement things related with sw_timer */
193                 if (ret != TDM_ERROR_NONE) {
194                         wl_resource_post_error(resource, WL_TDM_ERROR_OPERATION_FAILED,
195                                                "not implemented yet");
196                         TDM_ERR("not implemented yet");
197                         goto destroy_resource;
198                 }
199         } else {
200                 wl_resource_post_error(resource, WL_TDM_ERROR_OPERATION_FAILED,
201                                        "bad implementation");
202                 TDM_NEVER_GET_HERE();
203                 goto destroy_resource;
204         }
205
206         vblank_info->resource = vblank_resource;
207         vblank_info->private_server = private_server;
208
209         wl_resource_set_implementation(vblank_resource, NULL, vblank_info,
210                                        destroy_vblank_callback);
211
212         LIST_ADDTAIL(&vblank_info->link, &private_server->vblank_list);
213         return;
214 destroy_resource:
215         wl_resource_destroy(vblank_resource);
216 free_info:
217         free(vblank_info);
218 }
219
220 static const struct wl_tdm_interface tdm_implementation = {
221         _tdm_server_cb_wait_vblank,
222 };
223
224 static void
225 _tdm_server_bind(struct wl_client *client, void *data,
226                  uint32_t version, uint32_t id)
227 {
228         struct wl_resource *resource;
229
230         resource = wl_resource_create(client, &wl_tdm_interface, version, id);
231         if (!resource) {
232                 wl_client_post_no_memory(client);
233                 return;
234         }
235
236         TDM_DBG("tdm server binding");
237
238         wl_resource_set_implementation(resource, &tdm_implementation, data, NULL);
239 }
240
241 INTERN tdm_error
242 tdm_server_init(tdm_private_loop *private_loop)
243 {
244         tdm_private_server *private_server;
245         const char *debug;
246
247         debug = getenv("TDM_DEBUG_SERVER");
248         if (debug && (strstr(debug, "1")))
249                 tdm_debug_server = 1;
250
251         if (private_loop->private_server)
252                 return TDM_ERROR_NONE;
253
254         TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_OPERATION_FAILED);
255         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display, TDM_ERROR_OPERATION_FAILED);
256
257         if(wl_display_add_socket(private_loop->wl_display, "tdm-socket")) {
258                 TDM_ERR("createing a tdm-socket failed");
259                 return TDM_ERROR_OPERATION_FAILED;
260         }
261
262         private_server = calloc(1, sizeof *private_server);
263         if (!private_server) {
264                 TDM_ERR("alloc failed");
265                 return TDM_ERROR_OUT_OF_MEMORY;
266         }
267
268         LIST_INITHEAD(&private_server->vblank_list);
269
270         if (!wl_global_create(private_loop->wl_display, &wl_tdm_interface, 1,
271                               private_loop, _tdm_server_bind)) {
272                 TDM_ERR("creating a global resource failed");
273                 free(private_server);
274                 return TDM_ERROR_OUT_OF_MEMORY;
275         }
276
277         private_loop->private_server = private_server;
278         keep_private_server = private_server;
279
280         return TDM_ERROR_NONE;
281 }
282
283 INTERN void
284 tdm_server_deinit(tdm_private_loop *private_loop)
285 {
286         tdm_server_vblank_info *v = NULL, *vv = NULL;
287         tdm_private_server *private_server;
288
289         if (!private_loop->private_server)
290                 return;
291
292         private_server = private_loop->private_server;
293
294         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_server->vblank_list, link) {
295                 wl_resource_destroy(v->resource);
296         }
297
298         free(private_server);
299         private_loop->private_server = NULL;
300         keep_private_server = NULL;
301 }