diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_vsync.c | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_vsync.c b/libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_vsync.c new file mode 100644 index 0000000..47efefc --- /dev/null +++ b/libraries/ecore/src/lib/ecore_x/xcb/ecore_xcb_vsync.c | |||
@@ -0,0 +1,375 @@ | |||
1 | #include "ecore_xcb_private.h" | ||
2 | # include <fcntl.h> | ||
3 | # include <dlfcn.h> | ||
4 | # include <X11/Xlib-xcb.h> | ||
5 | |||
6 | #define ECORE_XCB_VSYNC_DRI2 1 | ||
7 | #define DRM_EVENT_CONTEXT_VERSION 2 | ||
8 | |||
9 | #ifdef ECORE_XCB_VSYNC_DRI2 | ||
10 | |||
11 | /* relevant header bits of dri/drm inlined here to avoid needing external */ | ||
12 | /* headers to build drm */ | ||
13 | typedef unsigned int drm_magic_t; | ||
14 | |||
15 | typedef enum | ||
16 | { | ||
17 | DRM_VBLANK_ABSOLUTE = 0x00000000, | ||
18 | DRM_VBLANK_RELATIVE = 0x00000001, | ||
19 | DRM_VBLANK_EVENT = 0x04000000, | ||
20 | DRM_VBLANK_FLIP = 0x08000000, | ||
21 | DRM_VBLANK_NEXTONMISS = 0x10000000, | ||
22 | DRM_VBLANK_SECONDARY = 0x20000000, | ||
23 | DRM_VBLANK_SIGNAL = 0x40000000 | ||
24 | } drmVBlankSeqType; | ||
25 | |||
26 | typedef struct _drmVBlankReq | ||
27 | { | ||
28 | drmVBlankSeqType type; | ||
29 | unsigned int sequence; | ||
30 | unsigned long signal; | ||
31 | } drmVBlankReq; | ||
32 | |||
33 | typedef struct _drmVBlankReply | ||
34 | { | ||
35 | drmVBlankSeqType type; | ||
36 | unsigned int sequence; | ||
37 | long tval_sec, tval_usec; | ||
38 | } drmVBlankReply; | ||
39 | |||
40 | typedef union _drmVBlank | ||
41 | { | ||
42 | drmVBlankReq request; | ||
43 | drmVBlankReply reply; | ||
44 | } drmVBlank; | ||
45 | |||
46 | typedef struct _drmEventContext | ||
47 | { | ||
48 | int version; | ||
49 | void (*vblank_handler)(int fd, | ||
50 | unsigned int sequence, | ||
51 | unsigned int tv_sec, | ||
52 | unsigned int tv_usec, | ||
53 | void *user_data); | ||
54 | void (*page_flip_handler)(int fd, | ||
55 | unsigned int sequence, | ||
56 | unsigned int tv_sec, | ||
57 | unsigned int tv_usec, | ||
58 | void *user_data); | ||
59 | } drmEventContext; | ||
60 | |||
61 | static int (*sym_drmClose)(int fd) = NULL; | ||
62 | static int (*sym_drmGetMagic)(int fd, | ||
63 | drm_magic_t *magic) = NULL; | ||
64 | static int (*sym_drmWaitVBlank)(int fd, | ||
65 | drmVBlank *vbl) = NULL; | ||
66 | static int (*sym_drmHandleEvent)(int fd, | ||
67 | drmEventContext *evctx) = NULL; | ||
68 | |||
69 | /* dri */ | ||
70 | static Bool (*sym_DRI2QueryExtension)(Display *display, | ||
71 | int *eventBase, | ||
72 | int *errorBase) = NULL; | ||
73 | static Bool (*sym_DRI2QueryVersion)(Display *display, | ||
74 | int *major, | ||
75 | int *minor) = NULL; | ||
76 | static Bool (*sym_DRI2Connect)(Display *display, | ||
77 | XID window, | ||
78 | char **driverName, | ||
79 | char **deviceName) = NULL; | ||
80 | static Bool (*sym_DRI2Authenticate)(Display *display, | ||
81 | XID window, | ||
82 | drm_magic_t magic) = NULL; | ||
83 | |||
84 | /* local function prototypes */ | ||
85 | static Eina_Bool _ecore_xcb_dri_link(void); | ||
86 | static Eina_Bool _ecore_xcb_dri_start(void); | ||
87 | static void _ecore_xcb_dri_shutdown(void); | ||
88 | |||
89 | static Eina_Bool _ecore_xcb_dri_cb(void *data __UNUSED__, | ||
90 | Ecore_Fd_Handler *fdh __UNUSED__); | ||
91 | static void _ecore_xcb_dri_tick_begin(void *data __UNUSED__); | ||
92 | static void _ecore_xcb_dri_tick_end(void *data __UNUSED__); | ||
93 | static void _ecore_xcb_dri_tick_schedule(void); | ||
94 | static void _ecore_xcb_dri_vblank_handler(int fd __UNUSED__, | ||
95 | unsigned int frame __UNUSED__, | ||
96 | unsigned int sec __UNUSED__, | ||
97 | unsigned int usec __UNUSED__, | ||
98 | void *data __UNUSED__); | ||
99 | |||
100 | /* local variables */ | ||
101 | static Ecore_X_Window _vsync_root = 0; | ||
102 | static int _drm_fd = -1; | ||
103 | static Ecore_Fd_Handler *_drm_fdh = NULL; | ||
104 | static unsigned int _drm_magic = 0; | ||
105 | static Eina_Bool _drm_event_busy = EINA_FALSE; | ||
106 | static void *_drm_lib = NULL; | ||
107 | static void *_dri_lib = NULL; | ||
108 | static drmEventContext _drm_evctx; | ||
109 | #endif | ||
110 | |||
111 | void | ||
112 | _ecore_xcb_dri_init(void) | ||
113 | { | ||
114 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
115 | } | ||
116 | |||
117 | void | ||
118 | _ecore_xcb_dri_finalize(void) | ||
119 | { | ||
120 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
121 | } | ||
122 | |||
123 | EAPI Eina_Bool | ||
124 | ecore_x_vsync_animator_tick_source_set(Ecore_X_Window win) | ||
125 | { | ||
126 | #ifdef ECORE_XCB_VSYNC_DRI2 | ||
127 | Ecore_X_Window root; | ||
128 | #endif | ||
129 | |||
130 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
131 | CHECK_XCB_CONN; | ||
132 | |||
133 | #ifdef ECORE_XCB_VSYNC_DRI2 | ||
134 | root = ecore_x_window_root_get(win); | ||
135 | if (root != _vsync_root) | ||
136 | { | ||
137 | _vsync_root = root; | ||
138 | if (_vsync_root) | ||
139 | { | ||
140 | if (!_ecore_xcb_dri_link()) | ||
141 | { | ||
142 | ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER); | ||
143 | return EINA_FALSE; | ||
144 | } | ||
145 | _ecore_xcb_dri_shutdown(); | ||
146 | if (!_ecore_xcb_dri_start()) | ||
147 | { | ||
148 | _vsync_root = 0; | ||
149 | ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER); | ||
150 | return EINA_FALSE; | ||
151 | } | ||
152 | ecore_animator_custom_source_tick_begin_callback_set | ||
153 | (_ecore_xcb_dri_tick_begin, NULL); | ||
154 | ecore_animator_custom_source_tick_end_callback_set | ||
155 | (_ecore_xcb_dri_tick_end, NULL); | ||
156 | ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM); | ||
157 | } | ||
158 | else | ||
159 | { | ||
160 | if (_drm_fd >= 0) | ||
161 | { | ||
162 | _ecore_xcb_dri_shutdown(); | ||
163 | ecore_animator_custom_source_tick_begin_callback_set | ||
164 | (NULL, NULL); | ||
165 | ecore_animator_custom_source_tick_end_callback_set | ||
166 | (NULL, NULL); | ||
167 | ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER); | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | return EINA_TRUE; | ||
172 | #else | ||
173 | return EINA_FALSE; | ||
174 | win = 0; | ||
175 | #endif | ||
176 | } | ||
177 | |||
178 | /* local functions */ | ||
179 | #ifdef ECORE_XCB_VSYNC_DRI2 | ||
180 | static Eina_Bool | ||
181 | _ecore_xcb_dri_link(void) | ||
182 | { | ||
183 | const char *_drm_libs[] = | ||
184 | { | ||
185 | "libdrm.so.2", | ||
186 | "libdrm.so.1", | ||
187 | "libdrm.so.0", | ||
188 | "libdrm.so", | ||
189 | NULL, | ||
190 | }; | ||
191 | const char *_dri_libs[] = | ||
192 | { | ||
193 | "libdri2.so.2", | ||
194 | "libdri2.so.1", | ||
195 | "libdri2.so.0", | ||
196 | "libdri2.so", | ||
197 | "libGL.so.4", | ||
198 | "libGL.so.3", | ||
199 | "libGL.so.2", | ||
200 | "libGL.so.1", | ||
201 | "libGL.so.0", | ||
202 | "libGL.so", | ||
203 | NULL, | ||
204 | }; | ||
205 | int i = 0, fail = 0; | ||
206 | |||
207 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
208 | |||
209 | # define SYM(lib, xx) \ | ||
210 | do { \ | ||
211 | sym_## xx = dlsym(lib, #xx); \ | ||
212 | if (!(sym_## xx)) { \ | ||
213 | fprintf(stderr, "%s\n", dlerror()); \ | ||
214 | fail = 1; \ | ||
215 | } \ | ||
216 | } while (0); | ||
217 | |||
218 | if (_drm_lib) return EINA_TRUE; | ||
219 | |||
220 | for (i = 0; _drm_libs[i]; i++) | ||
221 | { | ||
222 | _drm_lib = dlopen(_drm_libs[i], (RTLD_LOCAL | RTLD_LAZY)); | ||
223 | if (_drm_lib) | ||
224 | { | ||
225 | fail = 0; | ||
226 | SYM(_drm_lib, drmClose); | ||
227 | SYM(_drm_lib, drmGetMagic); | ||
228 | SYM(_drm_lib, drmWaitVBlank); | ||
229 | SYM(_drm_lib, drmHandleEvent); | ||
230 | if (fail) | ||
231 | { | ||
232 | dlclose(_drm_lib); | ||
233 | _drm_lib = NULL; | ||
234 | } | ||
235 | else | ||
236 | break; | ||
237 | } | ||
238 | } | ||
239 | if (!_drm_lib) return EINA_FALSE; | ||
240 | for (i = 0; _dri_libs[i]; i++) | ||
241 | { | ||
242 | if ((_dri_lib = dlopen(_dri_libs[i], (RTLD_LOCAL | RTLD_LAZY)))) | ||
243 | { | ||
244 | fail = 0; | ||
245 | SYM(_dri_lib, DRI2QueryExtension); | ||
246 | SYM(_dri_lib, DRI2QueryVersion); | ||
247 | SYM(_dri_lib, DRI2Connect); | ||
248 | SYM(_dri_lib, DRI2Authenticate); | ||
249 | if (fail) | ||
250 | { | ||
251 | dlclose(_dri_lib); | ||
252 | _dri_lib = NULL; | ||
253 | } | ||
254 | else | ||
255 | break; | ||
256 | } | ||
257 | } | ||
258 | if (!_dri_lib) | ||
259 | { | ||
260 | dlclose(_drm_lib); | ||
261 | _drm_lib = NULL; | ||
262 | return EINA_FALSE; | ||
263 | } | ||
264 | |||
265 | return EINA_TRUE; | ||
266 | } | ||
267 | |||
268 | static Eina_Bool | ||
269 | _ecore_xcb_dri_start(void) | ||
270 | { | ||
271 | Ecore_X_Display *disp; | ||
272 | int _dri2_event = 0, _dri2_error = 0; | ||
273 | int _dri2_major = 0, _dri2_minor = 0; | ||
274 | char *device = NULL, *driver = NULL; | ||
275 | |||
276 | disp = ecore_x_display_get(); | ||
277 | if (!sym_DRI2QueryExtension(disp, &_dri2_event, &_dri2_error)) | ||
278 | return 0; | ||
279 | if (!sym_DRI2QueryVersion(disp, &_dri2_major, &_dri2_minor)) | ||
280 | return 0; | ||
281 | if (_dri2_major < 2) return 0; | ||
282 | if (!sym_DRI2Connect(disp, _vsync_root, &driver, &device)) | ||
283 | return 0; | ||
284 | |||
285 | _drm_fd = open(device, O_RDWR); | ||
286 | if (_drm_fd < 0) return 0; | ||
287 | |||
288 | sym_drmGetMagic(_drm_fd, &_drm_magic); | ||
289 | if (!sym_DRI2Authenticate(disp, _vsync_root, _drm_magic)) | ||
290 | { | ||
291 | close(_drm_fd); | ||
292 | _drm_fd = -1; | ||
293 | return EINA_FALSE; | ||
294 | } | ||
295 | |||
296 | memset(&_drm_evctx, 0, sizeof(_drm_evctx)); | ||
297 | _drm_evctx.version = DRM_EVENT_CONTEXT_VERSION; | ||
298 | _drm_evctx.vblank_handler = _ecore_xcb_dri_vblank_handler; | ||
299 | _drm_evctx.page_flip_handler = NULL; | ||
300 | |||
301 | _drm_fdh = ecore_main_fd_handler_add(_drm_fd, ECORE_FD_READ, | ||
302 | _ecore_xcb_dri_cb, NULL, NULL, NULL); | ||
303 | if (!_drm_fdh) | ||
304 | { | ||
305 | close(_drm_fd); | ||
306 | _drm_fd = -1; | ||
307 | return EINA_FALSE; | ||
308 | } | ||
309 | |||
310 | return EINA_TRUE; | ||
311 | } | ||
312 | |||
313 | static void | ||
314 | _ecore_xcb_dri_shutdown(void) | ||
315 | { | ||
316 | if (_drm_fd >= 0) | ||
317 | { | ||
318 | close(_drm_fd); | ||
319 | _drm_fd = -1; | ||
320 | } | ||
321 | if (_drm_fdh) | ||
322 | { | ||
323 | ecore_main_fd_handler_del(_drm_fdh); | ||
324 | _drm_fdh = NULL; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | static Eina_Bool | ||
329 | _ecore_xcb_dri_cb(void *data __UNUSED__, | ||
330 | Ecore_Fd_Handler *fdh __UNUSED__) | ||
331 | { | ||
332 | sym_drmHandleEvent(_drm_fd, &_drm_evctx); | ||
333 | return ECORE_CALLBACK_RENEW; | ||
334 | } | ||
335 | |||
336 | static void | ||
337 | _ecore_xcb_dri_tick_begin(void *data __UNUSED__) | ||
338 | { | ||
339 | _drm_event_busy = EINA_TRUE; | ||
340 | _ecore_xcb_dri_tick_schedule(); | ||
341 | } | ||
342 | |||
343 | static void | ||
344 | _ecore_xcb_dri_tick_end(void *data __UNUSED__) | ||
345 | { | ||
346 | _drm_event_busy = EINA_FALSE; | ||
347 | } | ||
348 | |||
349 | static void | ||
350 | _ecore_xcb_dri_tick_schedule(void) | ||
351 | { | ||
352 | drmVBlank vbl; | ||
353 | |||
354 | LOGFN(__FILE__, __LINE__, __FUNCTION__); | ||
355 | CHECK_XCB_CONN; | ||
356 | |||
357 | vbl.request.type = (DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT); | ||
358 | vbl.request.sequence = 1; | ||
359 | vbl.request.signal = 0; | ||
360 | |||
361 | sym_drmWaitVBlank(_drm_fd, &vbl); | ||
362 | } | ||
363 | |||
364 | static void | ||
365 | _ecore_xcb_dri_vblank_handler(int fd __UNUSED__, | ||
366 | unsigned int frame __UNUSED__, | ||
367 | unsigned int sec __UNUSED__, | ||
368 | unsigned int usec __UNUSED__, | ||
369 | void *data __UNUSED__) | ||
370 | { | ||
371 | ecore_animator_custom_tick(); | ||
372 | if (_drm_event_busy) _ecore_xcb_dri_tick_schedule(); | ||
373 | } | ||
374 | |||
375 | #endif | ||