1 /*
2 * Cogl
3 *
4 * A Low Level GPU Graphics and Utilities API
5 *
6 * Copyright (C) 2012 Intel Corporation.
7 *
8 * Permission is hereby granted, free of charge, to any person
9 * obtaining a copy of this software and associated documentation
10 * files (the "Software"), to deal in the Software without
11 * restriction, including without limitation the rights to use, copy,
12 * modify, merge, publish, distribute, sublicense, and/or sell copies
13 * of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 *
28 *
29 * Authors:
30 * Neil Roberts <neil@linux.intel.com>
31 */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include "cogl-poll.h"
38 #include "cogl-poll-private.h"
39 #include "cogl-winsys-private.h"
40 #include "cogl-renderer-private.h"
41
42 struct _CoglPollSource
43 {
44 int fd;
45 CoglPollPrepareCallback prepare;
46 CoglPollDispatchCallback dispatch;
47 void *user_data;
48 };
49
50 int
cogl_poll_renderer_get_info(CoglRenderer * renderer,CoglPollFD ** poll_fds,int * n_poll_fds,int64_t * timeout)51 cogl_poll_renderer_get_info (CoglRenderer *renderer,
52 CoglPollFD **poll_fds,
53 int *n_poll_fds,
54 int64_t *timeout)
55 {
56 GList *l, *next;
57
58 _COGL_RETURN_VAL_IF_FAIL (cogl_is_renderer (renderer), 0);
59 _COGL_RETURN_VAL_IF_FAIL (poll_fds != NULL, 0);
60 _COGL_RETURN_VAL_IF_FAIL (n_poll_fds != NULL, 0);
61 _COGL_RETURN_VAL_IF_FAIL (timeout != NULL, 0);
62
63 *timeout = -1;
64
65 if (!_cogl_list_empty (&renderer->idle_closures))
66 *timeout = 0;
67
68 /* This loop needs to cope with the prepare callback removing its
69 * own fd */
70 for (l = renderer->poll_sources; l; l = next)
71 {
72 CoglPollSource *source = l->data;
73
74 next = l->next;
75
76 if (source->prepare)
77 {
78 int64_t source_timeout = source->prepare (source->user_data);
79 if (source_timeout >= 0 &&
80 (*timeout == -1 || *timeout > source_timeout))
81 *timeout = source_timeout;
82 }
83 }
84
85 /* This is deliberately set after calling the prepare callbacks in
86 * case one of them removes its fd */
87 *poll_fds = (void *)renderer->poll_fds->data;
88 *n_poll_fds = renderer->poll_fds->len;
89
90 return renderer->poll_fds_age;
91 }
92
93 void
cogl_poll_renderer_dispatch(CoglRenderer * renderer,const CoglPollFD * poll_fds,int n_poll_fds)94 cogl_poll_renderer_dispatch (CoglRenderer *renderer,
95 const CoglPollFD *poll_fds,
96 int n_poll_fds)
97 {
98 GList *l, *next;
99
100 _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer));
101
102 _cogl_closure_list_invoke_no_args (&renderer->idle_closures);
103
104 /* This loop needs to cope with the dispatch callback removing its
105 * own fd */
106 for (l = renderer->poll_sources; l; l = next)
107 {
108 CoglPollSource *source = l->data;
109 int i;
110
111 next = l->next;
112
113 if (source->fd == -1)
114 {
115 source->dispatch (source->user_data, 0);
116 continue;
117 }
118
119 for (i = 0; i < n_poll_fds; i++)
120 {
121 const CoglPollFD *pollfd = &poll_fds[i];
122
123 if (pollfd->fd == source->fd)
124 {
125 source->dispatch (source->user_data, pollfd->revents);
126 break;
127 }
128 }
129 }
130 }
131
132 static int
find_pollfd(CoglRenderer * renderer,int fd)133 find_pollfd (CoglRenderer *renderer, int fd)
134 {
135 int i;
136
137 for (i = 0; i < renderer->poll_fds->len; i++)
138 {
139 CoglPollFD *pollfd = &g_array_index (renderer->poll_fds, CoglPollFD, i);
140
141 if (pollfd->fd == fd)
142 return i;
143 }
144
145 return -1;
146 }
147
148 void
_cogl_poll_renderer_remove_fd(CoglRenderer * renderer,int fd)149 _cogl_poll_renderer_remove_fd (CoglRenderer *renderer, int fd)
150 {
151 int i = find_pollfd (renderer, fd);
152 GList *l;
153
154 if (i < 0)
155 return;
156
157 g_array_remove_index_fast (renderer->poll_fds, i);
158 renderer->poll_fds_age++;
159
160 for (l = renderer->poll_sources; l; l = l->next)
161 {
162 CoglPollSource *source = l->data;
163 if (source->fd == fd)
164 {
165 renderer->poll_sources =
166 g_list_delete_link (renderer->poll_sources, l);
167 g_slice_free (CoglPollSource, source);
168 break;
169 }
170 }
171 }
172
173 void
_cogl_poll_renderer_modify_fd(CoglRenderer * renderer,int fd,CoglPollFDEvent events)174 _cogl_poll_renderer_modify_fd (CoglRenderer *renderer,
175 int fd,
176 CoglPollFDEvent events)
177 {
178 int fd_index = find_pollfd (renderer, fd);
179
180 if (fd_index == -1)
181 g_warn_if_reached ();
182 else
183 {
184 CoglPollFD *pollfd =
185 &g_array_index (renderer->poll_sources, CoglPollFD, fd_index);
186
187 pollfd->events = events;
188 renderer->poll_fds_age++;
189 }
190 }
191
192 void
_cogl_poll_renderer_add_fd(CoglRenderer * renderer,int fd,CoglPollFDEvent events,CoglPollPrepareCallback prepare,CoglPollDispatchCallback dispatch,void * user_data)193 _cogl_poll_renderer_add_fd (CoglRenderer *renderer,
194 int fd,
195 CoglPollFDEvent events,
196 CoglPollPrepareCallback prepare,
197 CoglPollDispatchCallback dispatch,
198 void *user_data)
199 {
200 CoglPollFD pollfd = {
201 fd,
202 events
203 };
204 CoglPollSource *source;
205
206 _cogl_poll_renderer_remove_fd (renderer, fd);
207
208 source = g_slice_new0 (CoglPollSource);
209 source->fd = fd;
210 source->prepare = prepare;
211 source->dispatch = dispatch;
212 source->user_data = user_data;
213
214 renderer->poll_sources = g_list_prepend (renderer->poll_sources, source);
215
216 g_array_append_val (renderer->poll_fds, pollfd);
217 renderer->poll_fds_age++;
218 }
219
220 CoglPollSource *
_cogl_poll_renderer_add_source(CoglRenderer * renderer,CoglPollPrepareCallback prepare,CoglPollDispatchCallback dispatch,void * user_data)221 _cogl_poll_renderer_add_source (CoglRenderer *renderer,
222 CoglPollPrepareCallback prepare,
223 CoglPollDispatchCallback dispatch,
224 void *user_data)
225 {
226 CoglPollSource *source;
227
228 source = g_slice_new0 (CoglPollSource);
229 source->fd = -1;
230 source->prepare = prepare;
231 source->dispatch = dispatch;
232 source->user_data = user_data;
233
234 renderer->poll_sources = g_list_prepend (renderer->poll_sources, source);
235
236 return source;
237 }
238
239 void
_cogl_poll_renderer_remove_source(CoglRenderer * renderer,CoglPollSource * source)240 _cogl_poll_renderer_remove_source (CoglRenderer *renderer,
241 CoglPollSource *source)
242 {
243 GList *l;
244
245 for (l = renderer->poll_sources; l; l = l->next)
246 {
247 if (l->data == source)
248 {
249 renderer->poll_sources =
250 g_list_delete_link (renderer->poll_sources, l);
251 g_slice_free (CoglPollSource, source);
252 break;
253 }
254 }
255 }
256
257 CoglClosure *
_cogl_poll_renderer_add_idle(CoglRenderer * renderer,CoglIdleCallback idle_cb,void * user_data,CoglUserDataDestroyCallback destroy_cb)258 _cogl_poll_renderer_add_idle (CoglRenderer *renderer,
259 CoglIdleCallback idle_cb,
260 void *user_data,
261 CoglUserDataDestroyCallback destroy_cb)
262 {
263 return _cogl_closure_list_add (&renderer->idle_closures,
264 idle_cb,
265 user_data,
266 destroy_cb);
267 }
268