diff options
Diffstat (limited to 'libraries/ecore/src/lib/ecore_x/xlib/ecore_x_vsync.c')
-rw-r--r-- | libraries/ecore/src/lib/ecore_x/xlib/ecore_x_vsync.c | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/libraries/ecore/src/lib/ecore_x/xlib/ecore_x_vsync.c b/libraries/ecore/src/lib/ecore_x/xlib/ecore_x_vsync.c new file mode 100644 index 0000000..f054298 --- /dev/null +++ b/libraries/ecore/src/lib/ecore_x/xlib/ecore_x_vsync.c | |||
@@ -0,0 +1,351 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include <config.h> | ||
3 | #endif /* ifdef HAVE_CONFIG_H */ | ||
4 | |||
5 | #include "Ecore.h" | ||
6 | #include "ecore_x_private.h" | ||
7 | #include "Ecore_X.h" | ||
8 | |||
9 | #include <string.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | #include <unistd.h> | ||
13 | #include <dlfcn.h> | ||
14 | #include <sys/types.h> | ||
15 | #include <sys/stat.h> | ||
16 | #include <fcntl.h> | ||
17 | |||
18 | #define ECORE_X_VSYNC_DRI2 1 | ||
19 | |||
20 | #ifdef ECORE_X_VSYNC_DRI2 | ||
21 | // relevant header bits of dri/drm inlined here to avoid needing external | ||
22 | // headers to build | ||
23 | /// drm | ||
24 | typedef unsigned int drm_magic_t; | ||
25 | |||
26 | typedef enum | ||
27 | { | ||
28 | DRM_VBLANK_ABSOLUTE = 0x00000000, | ||
29 | DRM_VBLANK_RELATIVE = 0x00000001, | ||
30 | DRM_VBLANK_EVENT = 0x04000000, | ||
31 | DRM_VBLANK_FLIP = 0x08000000, | ||
32 | DRM_VBLANK_NEXTONMISS = 0x10000000, | ||
33 | DRM_VBLANK_SECONDARY = 0x20000000, | ||
34 | DRM_VBLANK_SIGNAL = 0x40000000 | ||
35 | } | ||
36 | drmVBlankSeqType; | ||
37 | |||
38 | typedef struct _drmVBlankReq | ||
39 | { | ||
40 | drmVBlankSeqType type; | ||
41 | unsigned int sequence; | ||
42 | unsigned long signal; | ||
43 | } drmVBlankReq; | ||
44 | |||
45 | typedef struct _drmVBlankReply | ||
46 | { | ||
47 | drmVBlankSeqType type; | ||
48 | unsigned int sequence; | ||
49 | long tval_sec; | ||
50 | long tval_usec; | ||
51 | } drmVBlankReply; | ||
52 | |||
53 | typedef union _drmVBlank | ||
54 | { | ||
55 | drmVBlankReq request; | ||
56 | drmVBlankReply reply; | ||
57 | } drmVBlank; | ||
58 | |||
59 | #define DRM_EVENT_CONTEXT_VERSION 2 | ||
60 | |||
61 | typedef struct _drmEventContext | ||
62 | { | ||
63 | int version; | ||
64 | void (*vblank_handler)(int fd, | ||
65 | unsigned int sequence, | ||
66 | unsigned int tv_sec, | ||
67 | unsigned int tv_usec, | ||
68 | void *user_data); | ||
69 | void (*page_flip_handler)(int fd, | ||
70 | unsigned int sequence, | ||
71 | unsigned int tv_sec, | ||
72 | unsigned int tv_usec, | ||
73 | void *user_data); | ||
74 | } drmEventContext; | ||
75 | |||
76 | static int (*sym_drmClose)(int fd) = NULL; | ||
77 | static int (*sym_drmGetMagic)(int fd, | ||
78 | drm_magic_t *magic) = NULL; | ||
79 | static int (*sym_drmWaitVBlank)(int fd, | ||
80 | drmVBlank *vbl) = NULL; | ||
81 | static int (*sym_drmHandleEvent)(int fd, | ||
82 | drmEventContext *evctx) = NULL; | ||
83 | |||
84 | //// dri | ||
85 | |||
86 | static Bool (*sym_DRI2QueryExtension)(Display *display, | ||
87 | int *eventBase, | ||
88 | int *errorBase) = NULL; | ||
89 | static Bool (*sym_DRI2QueryVersion)(Display *display, | ||
90 | int *major, | ||
91 | int *minor) = NULL; | ||
92 | static Bool (*sym_DRI2Connect)(Display *display, | ||
93 | XID window, | ||
94 | char **driverName, | ||
95 | char **deviceName) = NULL; | ||
96 | static Bool (*sym_DRI2Authenticate)(Display *display, | ||
97 | XID window, | ||
98 | drm_magic_t magic) = NULL; | ||
99 | |||
100 | //// dri/drm data needed | ||
101 | static int dri2_event = 0; | ||
102 | static int dri2_error = 0; | ||
103 | static int dri2_major = 0; | ||
104 | static int dri2_minor = 0; | ||
105 | static char *device_name = 0; | ||
106 | static char *driver_name = 0; | ||
107 | static drm_magic_t drm_magic; | ||
108 | |||
109 | static int drm_fd = -1; | ||
110 | static int drm_event_is_busy = 0; | ||
111 | static int drm_animators_interval = 1; | ||
112 | static drmEventContext drm_evctx; | ||
113 | static Ecore_Fd_Handler *dri_drm_fdh = NULL; | ||
114 | |||
115 | static void *dri_lib = NULL; | ||
116 | static void *drm_lib = NULL; | ||
117 | |||
118 | static Window dri_drm_vsync_root = 0; | ||
119 | |||
120 | static void | ||
121 | _dri_drm_tick_schedule(void) | ||
122 | { | ||
123 | drmVBlank vbl; | ||
124 | |||
125 | vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; | ||
126 | vbl.request.sequence = drm_animators_interval; | ||
127 | vbl.request.signal = 0; | ||
128 | sym_drmWaitVBlank(drm_fd, &vbl); | ||
129 | } | ||
130 | |||
131 | static void | ||
132 | _dri_drm_tick_begin(void *data __UNUSED__) | ||
133 | { | ||
134 | drm_event_is_busy = 1; | ||
135 | _dri_drm_tick_schedule(); | ||
136 | } | ||
137 | |||
138 | static void | ||
139 | _dri_drm_tick_end(void *data __UNUSED__) | ||
140 | { | ||
141 | drm_event_is_busy = 0; | ||
142 | } | ||
143 | |||
144 | static void | ||
145 | _dri_drm_vblank_handler(int fd __UNUSED__, | ||
146 | unsigned int frame __UNUSED__, | ||
147 | unsigned int sec __UNUSED__, | ||
148 | unsigned int usec __UNUSED__, | ||
149 | void *data __UNUSED__) | ||
150 | { | ||
151 | ecore_animator_custom_tick(); | ||
152 | if (drm_event_is_busy) _dri_drm_tick_schedule(); | ||
153 | } | ||
154 | |||
155 | static Eina_Bool | ||
156 | _dri_drm_cb(void *data __UNUSED__, | ||
157 | Ecore_Fd_Handler *fd_handler __UNUSED__) | ||
158 | { | ||
159 | sym_drmHandleEvent(drm_fd, &drm_evctx); | ||
160 | return ECORE_CALLBACK_RENEW; | ||
161 | } | ||
162 | |||
163 | // yes. most evil. we dlopen libdrm and libGL etc. to manually find smbols | ||
164 | // so we can be as compatible as possible given the whole mess of the | ||
165 | // gl/dri/drm etc. world. and handle graceful failure at runtime not | ||
166 | // compile time | ||
167 | static int | ||
168 | _dri_drm_link(void) | ||
169 | { | ||
170 | const char *drm_libs[] = | ||
171 | { | ||
172 | "libdrm.so.2", | ||
173 | "libdrm.so.1", | ||
174 | "libdrm.so.0", | ||
175 | "libdrm.so", | ||
176 | NULL, | ||
177 | }; | ||
178 | const char *dri_libs[] = | ||
179 | { | ||
180 | "libdri2.so.2", | ||
181 | "libdri2.so.1", | ||
182 | "libdri2.so.0", | ||
183 | "libdri2.so", | ||
184 | "libGL.so.4", | ||
185 | "libGL.so.3", | ||
186 | "libGL.so.2", | ||
187 | "libGL.so.1", | ||
188 | "libGL.so.0", | ||
189 | "libGL.so", | ||
190 | NULL, | ||
191 | }; | ||
192 | int i, fail; | ||
193 | #define SYM(lib, xx) \ | ||
194 | do { \ | ||
195 | sym_ ## xx = dlsym(lib, #xx); \ | ||
196 | if (!(sym_ ## xx)) { \ | ||
197 | fprintf(stderr, "%s\n", dlerror()); \ | ||
198 | fail = 1; \ | ||
199 | } \ | ||
200 | } while (0) | ||
201 | |||
202 | if (dri_lib) return 1; | ||
203 | for (i = 0; drm_libs[i]; i++) | ||
204 | { | ||
205 | drm_lib = dlopen(drm_libs[i], RTLD_LOCAL | RTLD_LAZY); | ||
206 | if (drm_lib) | ||
207 | { | ||
208 | fail = 0; | ||
209 | SYM(drm_lib, drmClose); | ||
210 | SYM(drm_lib, drmWaitVBlank); | ||
211 | SYM(drm_lib, drmHandleEvent); | ||
212 | if (fail) | ||
213 | { | ||
214 | dlclose(drm_lib); | ||
215 | drm_lib = NULL; | ||
216 | } | ||
217 | else break; | ||
218 | } | ||
219 | } | ||
220 | if (!drm_lib) return 0; | ||
221 | for (i = 0; dri_libs[i]; i++) | ||
222 | { | ||
223 | dri_lib = dlopen(dri_libs[i], RTLD_LOCAL | RTLD_LAZY); | ||
224 | if (dri_lib) | ||
225 | { | ||
226 | fail = 0; | ||
227 | SYM(dri_lib, DRI2QueryExtension); | ||
228 | SYM(dri_lib, DRI2QueryVersion); | ||
229 | SYM(dri_lib, DRI2Connect); | ||
230 | SYM(dri_lib, DRI2Authenticate); | ||
231 | if (fail) | ||
232 | { | ||
233 | dlclose(dri_lib); | ||
234 | dri_lib = NULL; | ||
235 | } | ||
236 | else break; | ||
237 | } | ||
238 | } | ||
239 | if (!dri_lib) | ||
240 | { | ||
241 | dlclose(drm_lib); | ||
242 | drm_lib = NULL; | ||
243 | return 0; | ||
244 | } | ||
245 | return 1; | ||
246 | } | ||
247 | |||
248 | static int | ||
249 | _dri_drm_init(void) | ||
250 | { | ||
251 | if (!sym_DRI2QueryExtension(_ecore_x_disp, &dri2_event, &dri2_error)) | ||
252 | return 0; | ||
253 | if (!sym_DRI2QueryVersion(_ecore_x_disp, &dri2_major, &dri2_minor)) | ||
254 | return 0; | ||
255 | if (dri2_major < 2) | ||
256 | return 0; | ||
257 | if (!sym_DRI2Connect(_ecore_x_disp, dri_drm_vsync_root, &driver_name, &device_name)) | ||
258 | return 0; | ||
259 | drm_fd = open(device_name, O_RDWR); | ||
260 | if (drm_fd < 0) | ||
261 | return 0; | ||
262 | sym_drmGetMagic(drm_fd, &drm_magic); | ||
263 | if (!sym_DRI2Authenticate(_ecore_x_disp, dri_drm_vsync_root, drm_magic)) | ||
264 | { | ||
265 | close(drm_fd); | ||
266 | drm_fd = -1; | ||
267 | return 0; | ||
268 | } | ||
269 | memset(&drm_evctx, 0, sizeof(drm_evctx)); | ||
270 | drm_evctx.version = DRM_EVENT_CONTEXT_VERSION; | ||
271 | drm_evctx.vblank_handler = _dri_drm_vblank_handler; | ||
272 | drm_evctx.page_flip_handler = NULL; | ||
273 | |||
274 | dri_drm_fdh = ecore_main_fd_handler_add(drm_fd, ECORE_FD_READ, | ||
275 | _dri_drm_cb, NULL, NULL, NULL); | ||
276 | if (!dri_drm_fdh) | ||
277 | { | ||
278 | close(drm_fd); | ||
279 | drm_fd = -1; | ||
280 | return 0; | ||
281 | } | ||
282 | return 1; | ||
283 | } | ||
284 | |||
285 | static void | ||
286 | _dri_drm_shutdown(void) | ||
287 | { | ||
288 | if (drm_fd >= 0) | ||
289 | { | ||
290 | close(drm_fd); | ||
291 | drm_fd = -1; | ||
292 | } | ||
293 | if (dri_drm_fdh) | ||
294 | { | ||
295 | ecore_main_fd_handler_del(dri_drm_fdh); | ||
296 | dri_drm_fdh = NULL; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | #endif | ||
301 | |||
302 | EAPI Eina_Bool | ||
303 | ecore_x_vsync_animator_tick_source_set(Ecore_X_Window win) | ||
304 | { | ||
305 | #ifdef ECORE_X_VSYNC_DRI2 | ||
306 | Ecore_X_Window root; | ||
307 | |||
308 | root = ecore_x_window_root_get(win); | ||
309 | if (root != dri_drm_vsync_root) | ||
310 | { | ||
311 | dri_drm_vsync_root = root; | ||
312 | if (dri_drm_vsync_root) | ||
313 | { | ||
314 | if (!_dri_drm_link()) | ||
315 | { | ||
316 | ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER); | ||
317 | return EINA_FALSE; | ||
318 | } | ||
319 | _dri_drm_shutdown(); | ||
320 | if (!_dri_drm_init()) | ||
321 | { | ||
322 | dri_drm_vsync_root = 0; | ||
323 | ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER); | ||
324 | return EINA_FALSE; | ||
325 | } | ||
326 | ecore_animator_custom_source_tick_begin_callback_set | ||
327 | (_dri_drm_tick_begin, NULL); | ||
328 | ecore_animator_custom_source_tick_end_callback_set | ||
329 | (_dri_drm_tick_end, NULL); | ||
330 | ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM); | ||
331 | } | ||
332 | else | ||
333 | { | ||
334 | if (drm_fd >= 0) | ||
335 | { | ||
336 | _dri_drm_shutdown(); | ||
337 | ecore_animator_custom_source_tick_begin_callback_set | ||
338 | (NULL, NULL); | ||
339 | ecore_animator_custom_source_tick_end_callback_set | ||
340 | (NULL, NULL); | ||
341 | ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER); | ||
342 | } | ||
343 | } | ||
344 | } | ||
345 | return EINA_TRUE; | ||
346 | #else | ||
347 | return EINA_FALSE; | ||
348 | win = 0; | ||
349 | #endif | ||
350 | } | ||
351 | |||