ee43406ab554615910e52b03cb1b551abf23d0fd
[platform/upstream/efl.git] / src / lib / ecore_x / xlib / ecore_x_vsync.c
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 #include "Ecore_Con.h"
9
10 #include <string.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <dlfcn.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <sys/select.h>
18 #include <fcntl.h>
19
20 #ifdef HAVE_PRCTL
21 # include <sys/prctl.h>
22 #endif
23
24 #define ECORE_X_VSYNC_DRM 1
25
26 static Ecore_X_Window vsync_root = 0;
27
28 int _ecore_x_image_shm_check(void);
29
30 static int _vsync_log_dom = -1;
31
32 #undef ERR
33 #define ERR(...) EINA_LOG_DOM_ERR(_vsync_log_dom, __VA_ARGS__)
34
35 #undef DBG
36 #define DBG(...) EINA_LOG_DOM_DBG(_vsync_log_dom, __VA_ARGS__)
37
38 #undef INF
39 #define INF(...) EINA_LOG_DOM_INFO(_vsync_log_dom, __VA_ARGS__)
40
41 #undef WRN
42 #define WRN(...) EINA_LOG_DOM_WARN(_vsync_log_dom, __VA_ARGS__)
43
44 #undef CRI
45 #define CRI(...) EINA_LOG_DOM_CRIT(_vsync_log_dom, __VA_ARGS__)
46
47
48
49 #ifdef ECORE_X_VSYNC_DRM
50 // relevant header bits of dri/drm inlined here to avoid needing external
51 // headers to build
52 /// drm
53 typedef enum
54 {
55    DRM_VBLANK_ABSOLUTE = 0x00000000,
56    DRM_VBLANK_RELATIVE = 0x00000001,
57    DRM_VBLANK_EVENT = 0x04000000,
58    DRM_VBLANK_FLIP = 0x08000000,
59    DRM_VBLANK_NEXTONMISS = 0x10000000,
60    DRM_VBLANK_SECONDARY = 0x20000000,
61    DRM_VBLANK_SIGNAL = 0x40000000
62 }
63 drmVBlankSeqType;
64
65 typedef struct _drmVBlankReq
66 {
67    drmVBlankSeqType type;
68    unsigned int     sequence;
69    unsigned long    signal;
70 } drmVBlankReq;
71
72 typedef struct _drmVBlankReply
73 {
74    drmVBlankSeqType type;
75    unsigned int     sequence;
76    long             tval_sec;
77    long             tval_usec;
78 } drmVBlankReply;
79
80 typedef union _drmVBlank
81 {
82    drmVBlankReq   request;
83    drmVBlankReply reply;
84 } drmVBlank;
85
86 #define DRM_EVENT_CONTEXT_VERSION 2
87
88 typedef struct _drmEventContext
89 {
90    int version;
91    void (*vblank_handler)(int fd,
92                           unsigned int sequence,
93                           unsigned int tv_sec,
94                           unsigned int tv_usec,
95                           void *user_data);
96    void (*page_flip_handler)(int fd,
97                              unsigned int sequence,
98                              unsigned int tv_sec,
99                              unsigned int tv_usec,
100                              void *user_data);
101 } drmEventContext;
102
103 typedef struct _drmVersionBroken
104 {
105    int version_major;
106    int version_minor;
107 //   int version_patchlevel;
108    size_t name_len;
109    // WARNING! this does NOT match the system drm.h headers because
110    // literally drm.h is wrong. the below is correct. drm hapily
111    // broke its ABI at some point.
112    char *name;
113    size_t date_len;
114    char *date;
115    size_t desc_len;
116    char *desc;
117 } drmVersionBroken;
118
119 typedef struct _drmVersion
120 {
121    int version_major;
122    int version_minor;
123    int version_patchlevel;
124    size_t name_len;
125    // WARNING! this does NOT match the system drm.h headers because
126    // literally drm.h is wrong. the below is correct. drm hapily
127    // broke its ABI at some point.
128    char *name;
129    size_t date_len;
130    char *date;
131    size_t desc_len;
132    char *desc;
133 } drmVersion;
134
135 static int (*sym_drmClose)(int fd) = NULL;
136 static int (*sym_drmWaitVBlank)(int fd,
137                                 drmVBlank *vbl) = NULL;
138 static int (*sym_drmHandleEvent)(int fd,
139                                  drmEventContext *evctx) = NULL;
140 static void *(*sym_drmGetVersion)(int fd) = NULL;
141 static void (*sym_drmFreeVersion)(void *drmver) = NULL;
142 static int drm_fd = -1;
143 static volatile int drm_event_is_busy = 0;
144 static int drm_animators_interval = 1;
145 static drmEventContext drm_evctx;
146 static double _drm_fail_time = 0.1;
147 static double _drm_fail_time2 = 1.0 / 60.0;
148 static int _drm_fail_count = 0;
149
150 static void *drm_lib = NULL;
151
152 static Eina_Thread_Queue *thq = NULL;
153 static Ecore_Thread *drm_thread = NULL;
154 static Eina_Spinlock tick_queue_lock;
155 static int           tick_queue_count = 0;
156 static Eina_Bool     tick_skip = EINA_FALSE;
157
158 typedef struct
159 {
160    Eina_Thread_Queue_Msg head;
161    char val;
162 } Msg;
163
164 #if 0
165 # define D(args...) fprintf(stderr, ##args)
166 #else
167 # define D(args...)
168 #endif
169
170 static Eina_Bool
171 _drm_tick_schedule(void)
172 {
173    drmVBlank vbl;
174
175    DBG("sched...");
176    vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
177    vbl.request.sequence = drm_animators_interval;
178    vbl.request.signal = 0;
179    if (sym_drmWaitVBlank(drm_fd, &vbl) < 0) return EINA_FALSE;
180    return EINA_TRUE;
181 }
182
183 static void
184 _tick_send(char val)
185 {
186    Msg *msg;
187    void *ref;
188    DBG("_tick_send(%i)", val);
189    msg = eina_thread_queue_send(thq, sizeof(Msg), &ref);
190    msg->val = val;
191    eina_thread_queue_send_done(thq, ref);
192 }
193
194 static void
195 _drm_tick_begin(void *data EINA_UNUSED)
196 {
197    _drm_fail_count = 0;
198    drm_event_is_busy = 1;
199    _tick_send(1);
200 }
201
202 static void
203 _drm_tick_end(void *data EINA_UNUSED)
204 {
205    _drm_fail_count = 0;
206    drm_event_is_busy = 0;
207    _tick_send(0);
208 }
209
210 static void
211 _drm_send_time(double t)
212 {
213    double *tim = malloc(sizeof(*tim));
214    if (tim)
215      {
216         *tim = t;
217         DBG("   ... send %1.8f", t);
218         D("    @%1.5f   ... send %1.8f\n", ecore_time_get(), t);
219         eina_spinlock_take(&tick_queue_lock);
220         tick_queue_count++;
221         eina_spinlock_release(&tick_queue_lock);
222         ecore_thread_feedback(drm_thread, tim);
223      }
224 }
225
226 static void
227 _drm_vblank_handler(int fd EINA_UNUSED,
228                     unsigned int frame,
229                     unsigned int sec,
230                     unsigned int usec,
231                     void *data EINA_UNUSED)
232 {
233    if (drm_event_is_busy)
234      {
235         static unsigned int pframe = 0;
236
237         DBG("vblank %i", frame);
238         D("    @%1.5f vblank %i\n", ecore_time_get(), frame);
239         if (pframe != frame)
240           {
241 #define DELTA_COUNT 10
242              double t = (double)sec + ((double)usec / 1000000);
243              double tnow = ecore_time_get();
244              static double tdelta[DELTA_COUNT];
245              static double tdelta_avg = 0.0;
246              static int tdelta_n = 0;
247
248              if (t > tnow)
249                {
250                   if (tdelta_n > DELTA_COUNT)
251                     {
252                        t = t + tdelta_avg;
253                     }
254                   else if (tdelta_n < DELTA_COUNT)
255                     {
256                        tdelta[tdelta_n] = tnow - t;
257                        tdelta_n++;
258                        t = tnow;
259                     }
260                   else if (tdelta_n == DELTA_COUNT)
261                     {
262                        int i;
263
264                        for (i = 0; i < DELTA_COUNT; i++)
265                          tdelta_avg += tdelta[i];
266                        tdelta_avg /= (double)(DELTA_COUNT);
267                        tdelta_n++;
268                     }
269                }
270              else
271                {
272                   tdelta_avg = 0.0;
273                   tdelta_n = 0;
274                }
275              _drm_send_time(t);
276              pframe = frame;
277           }
278      }
279    else
280      {
281         D("    @%1.5f vblank drm event when not busy!\n", ecore_time_get());
282      }
283 }
284
285 static void
286 _drm_tick_core(void *data EINA_UNUSED, Ecore_Thread *thread)
287 {
288    Msg *msg;
289    void *ref;
290    int tick = 0;
291
292    eina_thread_name_set(eina_thread_self(), "Eanimator-vsync");
293 #ifdef HAVE_PRCTL
294    prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
295 #endif
296    while (!ecore_thread_check(thread))
297      {
298         DBG("------- drm_event_is_busy=%i", drm_event_is_busy);
299         D("    @%1.5f ------- drm_event_is_busy=%i\n", ecore_time_get(), drm_event_is_busy);
300         if (!drm_event_is_busy)
301           {
302              DBG("wait...");
303              D("    @1.5f wait...\n", ecore_time_get());
304              msg = eina_thread_queue_wait(thq, &ref);
305              if (msg)
306                {
307                   tick = msg->val;
308                   eina_thread_queue_wait_done(thq, ref);
309                }
310           }
311         else
312           {
313              do
314                {
315                   DBG("poll...");
316                   D("    @%1.5f poll...\n", ecore_time_get());
317                   msg = eina_thread_queue_poll(thq, &ref);
318                   if (msg)
319                     {
320                        tick = msg->val;
321                        eina_thread_queue_wait_done(thq, ref);
322                     }
323                }
324              while (msg);
325           }
326         DBG("tick = %i", tick);
327         D("    @%1.5f tick = %i\n", ecore_time_get(), tick);
328         if (tick == -1)
329           {
330              drm_thread = NULL;
331              eina_thread_queue_free(thq);
332              thq = NULL;
333              return;
334           }
335         else if (tick)
336           {
337              fd_set rfds, wfds, exfds;
338              int max_fd;
339              int ret;
340              struct timeval tv;
341
342              if (!_drm_tick_schedule())
343                {
344                   D("    @%1.5f schedule fail\n", ecore_time_get());
345                   _drm_fail_count = 999999;
346                }
347              max_fd = 0;
348              FD_ZERO(&rfds);
349              FD_ZERO(&wfds);
350              FD_ZERO(&exfds);
351              FD_SET(drm_fd, &rfds);
352              max_fd = drm_fd;
353              tv.tv_sec = 0;
354              if (_drm_fail_count >= 10)
355                tv.tv_usec = _drm_fail_time2 * 1000000;
356              else
357                tv.tv_usec = _drm_fail_time * 1000000;
358              D("    @%1.5f wait %ims\n", ecore_time_get(), (int)(tv.tv_usec /1000));
359              ret = select(max_fd + 1, &rfds, &wfds, &exfds, &tv);
360              if ((ret == 1) && (FD_ISSET(drm_fd, &rfds)))
361                {
362                   D("    @%1.5f have event\n", ecore_time_get());
363                   sym_drmHandleEvent(drm_fd, &drm_evctx);
364                   _drm_fail_count = 0;
365                }
366              else if (ret == 0)
367                {
368                   // timeout
369                   _drm_send_time(ecore_time_get());
370                   _drm_fail_count++;
371                   D("    @%1.5f fail count %i\n", ecore_time_get(), _drm_fail_count);
372                }
373           }
374      }
375 }
376
377 static void
378 _drm_tick_notify(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED, void *msg)
379 {
380    int tick_queued;
381
382    eina_spinlock_take(&tick_queue_lock);
383    tick_queued = tick_queue_count;
384    tick_queue_count--;
385    eina_spinlock_release(&tick_queue_lock);
386    DBG("notify.... %3.3f %i", *((double *)msg), drm_event_is_busy);
387    D("notify.... %3.3f %i\n", *((double *)msg), drm_event_is_busy);
388    if (drm_event_is_busy)
389      {
390         double *t = msg;
391         static double pt = 0.0;
392
393         DBG("VSYNC %1.8f = delt %1.8f", *t, *t - pt);
394         D("VSYNC %1.8f = delt %1.8f\n", *t, *t - pt);
395         if ((!tick_skip) || (tick_queued == 1))
396           {
397              ecore_loop_time_set(*t);
398              ecore_animator_custom_tick();
399           }
400         pt = *t;
401      }
402    free(msg);
403 }
404
405 // yes. most evil. we dlopen libdrm and libGL etc. to manually find smbols
406 // so we can be as compatible as possible given the whole mess of the
407 // gl/dri/drm etc. world. and handle graceful failure at runtime not
408 // compile time
409 static int
410 _drm_link(void)
411 {
412    const char *drm_libs[] =
413    {
414       "libdrm.so.2",
415       "libdrm.so.1",
416       "libdrm.so.0",
417       "libdrm.so",
418       NULL,
419    };
420    int i, fail;
421 #define SYM(lib, xx)                         \
422    do {                                      \
423       sym_ ## xx = dlsym(lib, #xx);          \
424       if (!(sym_ ## xx)) {                   \
425          fail = 1;                           \
426       }                                      \
427    } while (0)
428
429    if (drm_lib) return 1;
430    for (i = 0; drm_libs[i]; i++)
431      {
432         drm_lib = dlopen(drm_libs[i], RTLD_LOCAL | RTLD_LAZY);
433         if (drm_lib)
434           {
435              fail = 0;
436              SYM(drm_lib, drmClose);
437              SYM(drm_lib, drmWaitVBlank);
438              SYM(drm_lib, drmHandleEvent);
439              SYM(drm_lib, drmGetVersion);
440              SYM(drm_lib, drmFreeVersion);
441              if (fail)
442                {
443                   dlclose(drm_lib);
444                   drm_lib = NULL;
445                }
446              else break;
447           }
448      }
449    if (!drm_lib) return 0;
450    return 1;
451 }
452
453 #define DRM_HAVE_NVIDIA 1
454
455 static int
456 _drm_init(int *flags)
457 {
458    struct stat st;
459    char buf[512];
460    Eina_Bool ok = EINA_FALSE;
461    int vmaj = 0, vmin = 0;
462
463    // vboxvideo 4.3.14 is crashing when calls drmWaitVBlank()
464    // https://www.virtualbox.org/ticket/13265
465    // also affects 4.3.12
466    if (stat("/sys/module/vboxvideo", &st) == 0)
467      {
468 /*
469         FILE *fp = fopen("/sys/module/vboxvideo/version", "rb");
470         if (fp)
471           {
472              if (fgets(buf, sizeof(buf), fp))
473                {
474                   if (eina_str_has_prefix(buf, "4.3.14"))
475                     {
476                        fclose(fp);
477                        return 0;
478                     }
479                }
480              fclose(fp);
481           }
482  */
483         return 0;
484      }
485    // only do this on new kernels = let's say 3.14 and up. 3.16 definitely
486    // works
487      {
488         FILE *fp = fopen("/proc/sys/kernel/osrelease", "rb");
489         if (fp)
490           {
491              if (fgets(buf, sizeof(buf), fp))
492                {
493                   if (sscanf(buf, "%i.%i.%*s", &vmaj, &vmin) == 2)
494                     {
495                        if (vmaj >= 3) ok = EINA_TRUE;
496                     }
497                }
498              fclose(fp);
499           }
500         if (!ok) return 0;
501      }
502    ok = EINA_FALSE;
503
504    snprintf(buf, sizeof(buf), "/dev/dri/card1");
505    if (stat(buf, &st) == 0)
506      {
507         // XXX: 2 dri cards - ambiguous. unknown device for screen
508         return 0;
509      }
510    snprintf(buf, sizeof(buf), "/dev/dri/card0");
511    if (stat(buf, &st) != 0) return 0;
512    drm_fd = open(buf, O_RDWR | O_CLOEXEC);
513    if (drm_fd < 0) return 0;
514
515    if (!getenv("ECORE_VSYNC_DRM_ALL"))
516      {
517         drmVersion *drmver;
518         drmVersionBroken *drmverbroken;
519
520         drmver = sym_drmGetVersion(drm_fd);
521         drmverbroken = (drmVersionBroken *)drmver;
522         if (!drmver)
523           {
524              close(drm_fd);
525              return 0;
526           }
527         // sanity check the drm version structure due to public versions
528         // not matching the real memory layout, check drm version
529         // is recent (1.6+) and name and sec ptrs exist AND their lengths are
530         // not garbage (within a sensible range)
531         if (getenv("ECORE_VSYNC_DRM_VERSION_DEBUG"))
532           {
533              if ((drmverbroken->name > (char *)4000L) &&
534                  (drmverbroken->date_len < 200))
535               fprintf(stderr,
536                       "!BROKEN DRM! Do FIXUP of ABI\n"
537                       "DRM Version: %i.%i\n"
538                       "Name:        '%s'\n"
539                       "Date:        '%s'\n"
540                       "Desc:        '%s'\n",
541                       drmverbroken->version_major, drmverbroken->version_minor,
542                       drmverbroken->name, drmverbroken->date, drmverbroken->desc);
543              else
544                fprintf(stderr,
545                        "OK DRM\n"
546                        "DRM Version: %i.%i\n"
547                        "Name:        '%s'\n"
548                        "Date:        '%s'\n"
549                        "Desc:        '%s'\n",
550                        drmver->version_major, drmver->version_minor,
551                        drmver->name, drmver->date, drmver->desc);
552           }
553         if ((((drmver->version_major == 1) &&
554               (drmver->version_minor >= 6)) ||
555              (drmver->version_major > 1)) &&
556             (drmver->name > (char *)4000L) &&
557             (drmver->date_len < 200))
558           {
559              // whitelist of known-to-work drivers
560              if ((!strcmp(drmver->name, "exynos")) &&
561                  (strstr(drmver->desc, "Samsung")))
562                {
563                   if (((vmaj >= 3) && (vmin >= 0)) || (vmaj >= 4))
564                     {
565                        if (getenv("ECORE_VSYNC_DRM_VERSION_DEBUG"))
566                          fprintf(stderr, "Whitelisted exynos OK\n");
567                        ok = EINA_TRUE;
568                        goto checkdone;
569                     }
570                }
571              if ((!strcmp(drmver->name, "i915")) &&
572                  (strstr(drmver->desc, "Intel Graphics")))
573                {
574                   if (((vmaj >= 3) && (vmin >= 14)) || (vmaj >= 4))
575                     {
576                        if (getenv("ECORE_VSYNC_DRM_VERSION_DEBUG"))
577                          fprintf(stderr, "Whitelisted intel OK\n");
578                        ok = EINA_TRUE;
579                        goto checkdone;
580                     }
581                }
582              if ((!strcmp(drmver->name, "radeon")) &&
583                  (strstr(drmver->desc, "Radeon")) &&
584                  (((drmver->version_major == 2) &&
585                    (drmver->version_minor >= 39)) ||
586                   (drmver->version_major > 2)))
587                {
588                   if (((vmaj >= 3) && (vmin >= 14)) || (vmaj >= 4))
589                     {
590                        if (getenv("ECORE_VSYNC_DRM_VERSION_DEBUG"))
591                          fprintf(stderr, "Whitelisted radeon OK\n");
592                        ok = EINA_TRUE;
593                        goto checkdone;
594                     }
595                }
596           }
597         if ((((drmverbroken->version_major == 1) &&
598               (drmverbroken->version_minor >= 6)) ||
599              (drmverbroken->version_major > 1)) &&
600             (drmverbroken->name > (char *)4000L) &&
601             (drmverbroken->date_len < 200))
602           {
603              // whitelist of known-to-work drivers
604              if ((!strcmp(drmverbroken->name, "exynos")) &&
605                  (strstr(drmverbroken->desc, "Samsung")))
606                {
607                   if (((vmaj >= 3) && (vmin >= 0)) || (vmaj >= 4))
608                     {
609                        if (getenv("ECORE_VSYNC_DRM_VERSION_DEBUG"))
610                          fprintf(stderr, "Whitelisted exynos OK\n");
611                        ok = EINA_TRUE;
612                        goto checkdone;
613                     }
614                }
615              if ((!strcmp(drmverbroken->name, "i915")) &&
616                  (strstr(drmverbroken->desc, "Intel Graphics")))
617                {
618                   if (((vmaj >= 3) && (vmin >= 14)) || (vmaj >= 4))
619                     {
620                        if (getenv("ECORE_VSYNC_DRM_VERSION_DEBUG"))
621                          fprintf(stderr, "Whitelisted intel OK\n");
622                        ok = EINA_TRUE;
623                        goto checkdone;
624                     }
625                }
626              if ((!strcmp(drmverbroken->name, "radeon")) &&
627                  (strstr(drmverbroken->desc, "Radeon")) &&
628                  (((drmver->version_major == 2) &&
629                    (drmver->version_minor >= 39)) ||
630                   (drmver->version_major > 2)))
631                {
632                   if (((vmaj >= 3) && (vmin >= 14)) || (vmaj >= 4))
633                     {
634                        if (getenv("ECORE_VSYNC_DRM_VERSION_DEBUG"))
635                          fprintf(stderr, "Whitelisted radeon OK\n");
636                        ok = EINA_TRUE;
637                        goto checkdone;
638                     }
639                }
640           }
641         if ((drmver->version_major >= 0) &&
642             (drmver->version_minor >= 0) &&
643             (drmver->name > (char *)4000L) &&
644             (drmver->date_len < 200))
645           {
646              if ((!strcmp(drmver->name, "nvidia-drm")) &&
647                  (strstr(drmver->desc, "NVIDIA DRM driver")))
648                {
649                   if (((vmaj >= 3) && (vmin >= 14)) || (vmaj >= 4))
650                     {
651                        *flags |= DRM_HAVE_NVIDIA;
652                        goto checkdone;
653                     }
654                }
655           }
656         if ((drmverbroken->version_major >= 0) &&
657             (drmverbroken->version_minor >= 0) &&
658             (drmverbroken->name > (char *)4000L) &&
659             (drmverbroken->date_len < 200))
660           {
661              if ((!strcmp(drmverbroken->name, "nvidia-drm")) &&
662                  (strstr(drmverbroken->desc, "NVIDIA DRM driver")))
663                {
664                   if (((vmaj >= 3) && (vmin >= 14)) || (vmaj >= 4))
665                     {
666                        *flags |= DRM_HAVE_NVIDIA;
667                        goto checkdone;
668                     }
669                }
670           }
671 checkdone:
672         sym_drmFreeVersion(drmver);
673         if (!ok)
674           {
675              close(drm_fd);
676              return 0;
677           }
678      }
679
680    memset(&drm_evctx, 0, sizeof(drm_evctx));
681    drm_evctx.version = DRM_EVENT_CONTEXT_VERSION;
682    drm_evctx.vblank_handler = _drm_vblank_handler;
683    drm_evctx.page_flip_handler = NULL;
684
685    if (!_drm_tick_schedule())
686      {
687         close(drm_fd);
688         drm_fd = -1;
689         return 0;
690      }
691
692    if (getenv("ECORE_ANIMATOR_SKIP")) tick_skip = EINA_TRUE;
693    tick_queue_count = 0;
694    eina_spinlock_new(&tick_queue_lock);
695    thq = eina_thread_queue_new();
696    drm_thread = ecore_thread_feedback_run(_drm_tick_core, _drm_tick_notify,
697                                           NULL, NULL, NULL, EINA_TRUE);
698    return 1;
699 }
700
701 static Eina_Bool
702 _drm_animator_tick_source_set(void)
703 {
704    if (vsync_root)
705      {
706         ecore_animator_custom_source_tick_begin_callback_set
707           (_drm_tick_begin, NULL);
708         ecore_animator_custom_source_tick_end_callback_set
709           (_drm_tick_end, NULL);
710         ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM);
711      }
712    else
713      {
714         if (drm_fd >= 0)
715           {
716              _drm_tick_end(NULL);
717              ecore_animator_custom_source_tick_begin_callback_set
718                (NULL, NULL);
719              ecore_animator_custom_source_tick_end_callback_set
720                (NULL, NULL);
721              ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
722           }
723      }
724    return EINA_TRUE;
725 }
726 #endif
727
728
729
730
731
732
733
734 // XXX: missing mode 3 == separate x connection with compiled in dri2 proto
735 // handling ala mesa (taken from mesa likely)
736
737 static int mode = 0;
738
739 static void
740 _vsync_init(void)
741 {
742    static int done = 0;
743    struct stat stb;
744    int flags = 0;
745
746    if (done) return;
747
748    _vsync_log_dom = eina_log_domain_register("ecore_x_vsync", EINA_COLOR_LIGHTRED);
749    if (_ecore_x_image_shm_check())
750      {
751 #ifdef ECORE_X_VSYNC_DRM
752         // preferred inline drm if possible
753         if (!stat("/dev/dri/card0", &stb))
754           {
755              if (_drm_link())
756                {
757                   if (_drm_init(&flags)) mode = 1;
758                }
759           }
760 #endif
761      }
762    done = 1;
763 }
764
765 EAPI Eina_Bool
766 ecore_x_vsync_animator_tick_source_set(Ecore_X_Window win)
767 {
768    Ecore_X_Window root;
769    static int vsync_veto = -1;
770
771    if (vsync_veto == -1)
772      {
773         char buf[4096];
774         const char *home;
775         struct stat st;
776
777         home = eina_environment_home_get();
778         if (!home) eina_environment_tmp_get();
779         snprintf(buf, sizeof(buf), "%s/.ecore-no-vsync", home);
780         if (getenv("ECORE_NO_VSYNC")) vsync_veto = 1;
781         else if (stat(buf, &st) == 0) vsync_veto = 1;
782         else if (stat("/etc/.ecore-no-vsync", &st) == 0) vsync_veto = 1;
783         else vsync_veto = 0;
784      }
785    if (vsync_veto == 1) return EINA_FALSE;
786
787    root = ecore_x_window_root_get(win);
788    if (root != vsync_root)
789      {
790         _vsync_init();
791         vsync_root = root;
792 #ifdef ECORE_X_VSYNC_DRM
793         if (mode == 1) return _drm_animator_tick_source_set();
794 #endif
795      }
796    return EINA_TRUE;
797 }