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 #include "cogl-config.h"
34
35 #include "cogl-poll.h"
36 #include "cogl-poll-private.h"
37 #include "cogl-renderer-private.h"
38 #include "winsys/cogl-winsys-private.h"
39
40 struct _CoglPollSource
41 {
42 int fd;
43 CoglPollPrepareCallback prepare;
44 CoglPollDispatchCallback dispatch;
45 void *user_data;
46 };
47
48 int
cogl_poll_renderer_get_info(CoglRenderer * renderer,CoglPollFD ** poll_fds,int * n_poll_fds,int64_t * timeout)49 cogl_poll_renderer_get_info (CoglRenderer *renderer,
50 CoglPollFD **poll_fds,
51 int *n_poll_fds,
52 int64_t *timeout)
53 {
54 GList *l, *next;
55
56 g_return_val_if_fail (cogl_is_renderer (renderer), 0);
57 g_return_val_if_fail (poll_fds != NULL, 0);
58 g_return_val_if_fail (n_poll_fds != NULL, 0);
59 g_return_val_if_fail (timeout != NULL, 0);
60
61 *timeout = -1;
62
63 if (!_cogl_list_empty (&renderer->idle_closures))
64 *timeout = 0;
65
66 /* This loop needs to cope with the prepare callback removing its
67 * own fd */
68 for (l = renderer->poll_sources; l; l = next)
69 {
70 CoglPollSource *source = l->data;
71
72 next = l->next;
73
74 if (source->prepare)
75 {
76 int64_t source_timeout = source->prepare (source->user_data);
77 if (source_timeout >= 0 &&
78 (*timeout == -1 || *timeout > source_timeout))
79 *timeout = source_timeout;
80 }
81 }
82
83 /* This is deliberately set after calling the prepare callbacks in
84 * case one of them removes its fd */
85 *poll_fds = (void *)renderer->poll_fds->data;
86 *n_poll_fds = renderer->poll_fds->len;
87
88 return renderer->poll_fds_age;
89 }
90
91 void
cogl_poll_renderer_dispatch(CoglRenderer * renderer,const CoglPollFD * poll_fds,int n_poll_fds)92 cogl_poll_renderer_dispatch (CoglRenderer *renderer,
93 const CoglPollFD *poll_fds,
94 int n_poll_fds)
95 {
96 GList *l, *next;
97
98 g_return_if_fail (cogl_is_renderer (renderer));
99
100 _cogl_closure_list_invoke_no_args (&renderer->idle_closures);
101
102 /* This loop needs to cope with the dispatch callback removing its
103 * own fd */
104 for (l = renderer->poll_sources; l; l = next)
105 {
106 CoglPollSource *source = l->data;
107 int i;
108
109 next = l->next;
110
111 if (source->fd == -1)
112 {
113 source->dispatch (source->user_data, 0);
114 continue;
115 }
116
117 for (i = 0; i < n_poll_fds; i++)
118 {
119 const CoglPollFD *pollfd = &poll_fds[i];
120
121 if (pollfd->fd == source->fd)
122 {
123 source->dispatch (source->user_data, pollfd->revents);
124 break;
125 }
126 }
127 }
128 }
129
130 static int
find_pollfd(CoglRenderer * renderer,int fd)131 find_pollfd (CoglRenderer *renderer, int fd)
132 {
133 int i;
134
135 for (i = 0; i < renderer->poll_fds->len; i++)
136 {
137 CoglPollFD *pollfd = &g_array_index (renderer->poll_fds, CoglPollFD, i);
138
139 if (pollfd->fd == fd)
140 return i;
141 }
142
143 return -1;
144 }
145
146 void
_cogl_poll_renderer_remove_fd(CoglRenderer * renderer,int fd)147 _cogl_poll_renderer_remove_fd (CoglRenderer *renderer, int fd)
148 {
149 int i = find_pollfd (renderer, fd);
150 GList *l;
151
152 if (i < 0)
153 return;
154
155 g_array_remove_index_fast (renderer->poll_fds, i);
156 renderer->poll_fds_age++;
157
158 for (l = renderer->poll_sources; l; l = l->next)
159 {
160 CoglPollSource *source = l->data;
161 if (source->fd == fd)
162 {
163 renderer->poll_sources =
164 g_list_delete_link (renderer->poll_sources, l);
165 g_free (source);
166 break;
167 }
168 }
169 }
170
171 void
_cogl_poll_renderer_modify_fd(CoglRenderer * renderer,int fd,CoglPollFDEvent events)172 _cogl_poll_renderer_modify_fd (CoglRenderer *renderer,
173 int fd,
174 CoglPollFDEvent events)
175 {
176 int fd_index = find_pollfd (renderer, fd);
177
178 if (fd_index == -1)
179 g_warn_if_reached ();
180 else
181 {
182 CoglPollFD *pollfd =
183 &g_array_index (renderer->poll_sources, CoglPollFD, fd_index);
184
185 pollfd->events = events;
186 renderer->poll_fds_age++;
187 }
188 }
189
190 void
_cogl_poll_renderer_add_fd(CoglRenderer * renderer,int fd,CoglPollFDEvent events,CoglPollPrepareCallback prepare,CoglPollDispatchCallback dispatch,void * user_data)191 _cogl_poll_renderer_add_fd (CoglRenderer *renderer,
192 int fd,
193 CoglPollFDEvent events,
194 CoglPollPrepareCallback prepare,
195 CoglPollDispatchCallback dispatch,
196 void *user_data)
197 {
198 CoglPollFD pollfd = {
199 fd,
200 events
201 };
202 CoglPollSource *source;
203
204 _cogl_poll_renderer_remove_fd (renderer, fd);
205
206 source = g_new0 (CoglPollSource, 1);
207 source->fd = fd;
208 source->prepare = prepare;
209 source->dispatch = dispatch;
210 source->user_data = user_data;
211
212 renderer->poll_sources = g_list_prepend (renderer->poll_sources, source);
213
214 g_array_append_val (renderer->poll_fds, pollfd);
215 renderer->poll_fds_age++;
216 }
217
218 CoglPollSource *
_cogl_poll_renderer_add_source(CoglRenderer * renderer,CoglPollPrepareCallback prepare,CoglPollDispatchCallback dispatch,void * user_data)219 _cogl_poll_renderer_add_source (CoglRenderer *renderer,
220 CoglPollPrepareCallback prepare,
221 CoglPollDispatchCallback dispatch,
222 void *user_data)
223 {
224 CoglPollSource *source;
225
226 source = g_new0 (CoglPollSource, 1);
227 source->fd = -1;
228 source->prepare = prepare;
229 source->dispatch = dispatch;
230 source->user_data = user_data;
231
232 renderer->poll_sources = g_list_prepend (renderer->poll_sources, source);
233
234 return source;
235 }
236
237 void
_cogl_poll_renderer_remove_source(CoglRenderer * renderer,CoglPollSource * source)238 _cogl_poll_renderer_remove_source (CoglRenderer *renderer,
239 CoglPollSource *source)
240 {
241 GList *l;
242
243 for (l = renderer->poll_sources; l; l = l->next)
244 {
245 if (l->data == source)
246 {
247 renderer->poll_sources =
248 g_list_delete_link (renderer->poll_sources, l);
249 g_free (source);
250 break;
251 }
252 }
253 }
254
255 CoglClosure *
_cogl_poll_renderer_add_idle(CoglRenderer * renderer,CoglIdleCallback idle_cb,void * user_data,CoglUserDataDestroyCallback destroy_cb)256 _cogl_poll_renderer_add_idle (CoglRenderer *renderer,
257 CoglIdleCallback idle_cb,
258 void *user_data,
259 CoglUserDataDestroyCallback destroy_cb)
260 {
261 return _cogl_closure_list_add (&renderer->idle_closures,
262 idle_cb,
263 user_data,
264 destroy_cb);
265 }
266