raster pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=2d63a704222fa27d61a53d6b7248cd7e01ebb100

commit 2d63a704222fa27d61a53d6b7248cd7e01ebb100
Author: Carsten Haitzler (Rasterman) <[email protected]>
Date:   Sun Jul 27 14:22:27 2014 +0900

    ecore x vsync animator support - add a glx based vsync ticker
    
    this adds a slave process that is useful on nvidia drivers as there
    isn't another way to get vsync evenys (that i know about). i need to
    make another slave process to that includes a dri2 protocol
    implementation since mesa has now hidden its dri2 symbols.
---
 .gitignore                               |   1 +
 data/Makefile.am                         |   6 +
 data/ecore_x/checkme                     |   1 +
 src/Makefile_Ecore_X.am                  |  24 ++-
 src/lib/ecore_x/ecore_x_vsync_tool.c     | 256 ++++++++++++++++++++++++++
 src/lib/ecore_x/ecore_x_vsync_tool_glx.c | 302 +++++++++++++++++++++++++++++++
 src/lib/ecore_x/xlib/ecore_x_vsync.c     | 264 ++++++++++++++++++++++-----
 7 files changed, 808 insertions(+), 46 deletions(-)

diff --git a/.gitignore b/.gitignore
index ad5734a..9ba26f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,3 +64,4 @@ tags
 /ABOUT-NLS
 /config.rpath
 /coverage
+/src/lib/ecore_x/ecore_x_vsync
diff --git a/data/Makefile.am b/data/Makefile.am
index 6d42a09..d498619 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -28,6 +28,12 @@ ecorefiles_DATA = ecore/checkme
 EXTRA_DIST += $(ecorefiles_DATA)
 
 ########################################################################
+# Ecore_X
+ecore_xfilesdir = $(datadir)/ecore_x
+ecore_xfiles_DATA = ecore_x/checkme
+EXTRA_DIST += $(ecore_xfiles_DATA)
+
+########################################################################
 # Ecore_Imf
 ecoreimffilesdir = $(datadir)/ecore_imf
 ecoreimffiles_DATA = ecore_imf/checkme
diff --git a/data/ecore_x/checkme b/data/ecore_x/checkme
new file mode 100644
index 0000000..1688a66
--- /dev/null
+++ b/data/ecore_x/checkme
@@ -0,0 +1 @@
+This is just a test file used to help ecore determine its prefix location.
diff --git a/src/Makefile_Ecore_X.am b/src/Makefile_Ecore_X.am
index fcb4bb4..5cc4ccf 100644
--- a/src/Makefile_Ecore_X.am
+++ b/src/Makefile_Ecore_X.am
@@ -1,5 +1,19 @@
 if HAVE_ECORE_X
 
+ecore_x_vsync_bin_PROGRAMS = lib/ecore_x/ecore_x_vsync
+ecore_x_vsync_bindir = $(libdir)/ecore_x/bin/$(MODULE_ARCH)
+lib_ecore_x_ecore_x_vsync_SOURCES = \
+lib/ecore_x/ecore_x_vsync_tool.c \
+lib/ecore_x/ecore_x_vsync_tool_glx.c
+lib_ecore_x_ecore_x_vsync_CPPFLAGS = \
+-I$(top_builddir)/src/lib/efl \
+@ECORE_CFLAGS@ @ECORE_CON_CFLAGS@ @EINA_CFLAGS@ \
+-DPACKAGE_BIN_DIR=\"$(bindir)\" \
+-DPACKAGE_LIB_DIR=\"$(libdir)\" \
+-DPACKAGE_DATA_DIR=\"$(datadir)/ecore_x\"
+lib_ecore_x_ecore_x_vsync_LDADD = @USE_EINA_LIBS@ @USE_ECORE_LIBS@ 
@USE_ECORE_CON_LIBS@
+lib_ecore_x_ecore_x_vsync_DEPENDENCIES = @EINA_INTERNAL_LIBS@ 
@ECORE_INTERNAL_LIBS@ @ECORE_CON_INTERNAL_LIBS@
+
 ### Library
 
 lib_LTLIBRARIES += lib/ecore_x/libecore_x.la
@@ -93,12 +107,17 @@ lib/ecore_x/xlib/ecore_x_gesture.c \
 lib/ecore_x/xlib/ecore_x_private.h
 endif
 
-lib_ecore_x_libecore_x_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl 
@ECORE_X_CFLAGS@
+lib_ecore_x_libecore_x_la_CPPFLAGS = \
+-I$(top_builddir)/src/lib/efl \
+@ECORE_X_CFLAGS@ @ECORE_CON_CFLAGS@ \
+-DPACKAGE_BIN_DIR=\"$(bindir)\" \
+-DPACKAGE_LIB_DIR=\"$(libdir)\" \
+-DPACKAGE_DATA_DIR=\"$(datadir)/ecore_x\"
 if HAVE_ECORE_X_XCB
 lib_ecore_x_libecore_x_la_CPPFLAGS += -I$(top_builddir)/src/lib/ecore_x/xcb
 endif
 
-lib_ecore_x_libecore_x_la_LIBADD = @ECORE_X_LIBS@
+lib_ecore_x_libecore_x_la_LIBADD = @ECORE_X_LIBS@ @USE_ECORE_CON_LIBS@
 lib_ecore_x_libecore_x_la_DEPENDENCIES = @ECORE_X_INTERNAL_LIBS@
 lib_ecore_x_libecore_x_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@
 
@@ -125,4 +144,3 @@ utils_ecore_makekeys_CFLAGS = @ECORE_X_CFLAGS@
 
 endif
 EXTRA_DIST += utils/ecore/mkks.sh
-
diff --git a/src/lib/ecore_x/ecore_x_vsync_tool.c 
b/src/lib/ecore_x/ecore_x_vsync_tool.c
new file mode 100644
index 0000000..34c9340
--- /dev/null
+++ b/src/lib/ecore_x/ecore_x_vsync_tool.c
@@ -0,0 +1,256 @@
+#include <Eina.h>
+#include <Ecore.h>
+#include <Ecore_Con.h>
+
+#include <unistd.h>
+
+enum
+{
+   MODE_NONE,
+   MODE_GLX
+};
+
+int _vsync_init_glx(void);
+double _vsync_wait_glx(void);
+
+static void _svr_broadcast_time(double t);
+
+static int _vsync_mode = MODE_NONE;
+
+static int
+_vsync_init(void)
+{
+   if (_vsync_init_glx()) _vsync_mode = MODE_GLX;
+   else return 0;
+   return 1;
+}
+
+static double
+_vsync_wait(void)
+{
+   if (_vsync_mode == MODE_GLX) return _vsync_wait_glx();
+   return 0.0;
+}
+
+typedef struct
+{
+   Eina_Thread_Queue_Msg head;
+   char val;
+} Msg;
+
+static int tick = 0;
+static Eina_Thread_Queue *thq = NULL;
+
+static void
+_tick_core(void *data EINA_UNUSED, Ecore_Thread *thread)
+{
+   Msg *msg;
+   void *ref;
+
+   for (;;)
+     {
+        if (!tick)
+          {
+             msg = eina_thread_queue_wait(thq, &ref);
+             if (msg)
+               {
+                  tick = msg->val;
+                  eina_thread_queue_wait_done(thq, ref);
+               }
+          }
+        else
+          {
+again:
+             msg = eina_thread_queue_poll(thq, &ref);
+             if (msg)
+               {
+                  tick = msg->val;
+                  eina_thread_queue_wait_done(thq, ref);
+               }
+             if (msg) goto again;
+          }
+        if (tick == -1) exit(0);
+        if (tick)
+          {
+             double *t;
+
+             t = malloc(sizeof(*t));
+             if (t)
+               {
+                  *t = _vsync_wait();
+                  ecore_thread_feedback(thread, t);
+               }
+          }
+     }
+}
+
+static void
+_tick_notify(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED, void 
*msg)
+{
+   double *t = msg;
+
+   if (t)
+     {
+        _svr_broadcast_time(*t);
+        free(t);
+     }
+}
+
+static void
+_tick_init(void)
+{
+   thq = eina_thread_queue_new();
+   ecore_thread_feedback_run(_tick_core, _tick_notify,
+                             NULL, NULL, NULL, EINA_TRUE);
+}
+
+static void
+_tick_send(char val)
+{
+   Msg *msg;
+   void *ref;
+   msg = eina_thread_queue_send(thq, sizeof(Msg), &ref);
+   msg->val = val;
+   eina_thread_queue_send_done(thq, ref);
+}
+
+static void
+_tick_start(void)
+{
+   tick++;
+   if (tick > 1) return;
+   _tick_send(1);
+}
+
+static void
+_tick_end(void)
+{
+   tick--;
+   if (tick > 0) return;
+   _tick_send(0);
+}
+
+/*--------------------------------------------------------------------*/
+
+typedef struct
+{
+   Ecore_Con_Client *client;
+   Eina_Bool enabled : 1;
+} Clientdata;
+
+static Ecore_Con_Server *svr = NULL;
+static Eina_List *clients = NULL;
+
+static void
+_svr_broadcast_time(double t)
+{
+   Eina_List *l;
+   Clientdata *cdat;
+
+   EINA_LIST_FOREACH(clients, l, cdat)
+     {
+        ecore_con_client_send(cdat->client, &t, sizeof(t));
+     }
+}
+
+static Eina_Bool
+_svr_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+   Ecore_Con_Event_Client_Add *ev = event;
+   if (svr != ecore_con_client_server_get(ev->client)) return EINA_TRUE;
+   Clientdata *cdat = calloc(1, sizeof(Clientdata));
+   if (cdat)
+     {
+        cdat->client = ev->client;
+        clients = eina_list_append(clients, cdat);
+        ecore_con_client_data_set(ev->client, cdat);
+     }
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_svr_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+   Ecore_Con_Event_Client_Del *ev = event;
+   if (svr != ecore_con_client_server_get(ev->client)) return EINA_TRUE;
+   Clientdata *cdat = ecore_con_client_data_get(ev->client);
+   if (cdat)
+     {
+        clients = eina_list_remove(clients, cdat);
+        if (cdat->enabled) _tick_end();
+        free(cdat);
+     }
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_svr_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+   Ecore_Con_Event_Client_Data *ev = event;
+   if (svr != ecore_con_client_server_get(ev->client)) return EINA_TRUE;
+   Clientdata *cdat = ecore_con_client_data_get(ev->client);
+   if (cdat)
+     {
+        char *dat = ev->data;
+
+        if (ev->size > 0)
+          {
+             if (dat[ev->size - 1])
+               {
+                  if (!cdat->enabled)
+                    {
+                       _tick_start();
+                       cdat->enabled = EINA_TRUE;
+                    }
+               }
+             else
+               {
+                  if (cdat->enabled)
+                    {
+                       _tick_end();
+                       cdat->enabled = EINA_FALSE;
+                    }
+               }
+          }
+     }
+   return EINA_FALSE;
+}
+
+static void
+_svr_init(void)
+{
+   char buf[4096], *disp, *s;
+
+   disp = getenv("DISPLAY");
+   if (disp) disp = ":0";
+   snprintf(buf, sizeof(buf), "ecore-x-vsync-%s", disp);
+   for (s = buf; *s; s++)
+     {
+        if (*s == ':') *s = '=';
+     }
+   svr = ecore_con_server_add(ECORE_CON_LOCAL_USER, buf, 1, NULL);
+   if (!svr) exit(0);
+   ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, _svr_add, NULL);
+   ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, _svr_del, NULL);
+   ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA, _svr_data, NULL);
+}
+
+/*--------------------------------------------------------------------*/
+
+int
+main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
+{
+   eina_init();
+   ecore_app_no_system_modules();
+   ecore_init();
+   ecore_con_init();
+
+   if (!_vsync_init()) return 7;
+   _svr_init();
+   _tick_init();
+
+    ecore_main_loop_begin();
+   _tick_send(-1);
+   pause();
+   return 0;
+}
diff --git a/src/lib/ecore_x/ecore_x_vsync_tool_glx.c 
b/src/lib/ecore_x/ecore_x_vsync_tool_glx.c
new file mode 100644
index 0000000..1d5b347
--- /dev/null
+++ b/src/lib/ecore_x/ecore_x_vsync_tool_glx.c
@@ -0,0 +1,302 @@
+#include <Eina.h>
+#include <Ecore.h>
+#include <string.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/*-------------------------------------------------------------------------*/
+
+#define SYM(lib, xx)                         \
+   do {                                      \
+      sym_ ## xx = dlsym(lib, #xx);          \
+      if (!(sym_ ## xx)) {                   \
+         fail = 1;                           \
+      }                                      \
+   } while (0)
+
+#define GLX_DRAWABLE_TYPE 0x8010
+#define GLX_WINDOW_BIT 0x00000001
+#define GLX_RENDER_TYPE 0x8011
+#define GLX_RGBA_BIT 0x00000001
+#define GLX_DOUBLEBUFFER 5
+#define GLX_RED_SIZE 8
+#define GLX_GREEN_SIZE 9
+#define GLX_BLUE_SIZE 10
+#define GLX_RGBA_TYPE 0x8014
+typedef struct __GLXFBConfigRec *GLXFBConfig;
+
+typedef struct
+{
+   void *visual;
+   long visualid;
+   int screen;
+   int depth;
+   int c_class;
+   unsigned long red_mask;
+   unsigned long green_mask;
+   unsigned long blue_mask;
+   int colormap_size;
+   int bits_per_rgb;
+} XVisualInfo;
+
+typedef struct
+{
+   long background_pixmap;
+   unsigned long background_pixel;
+   long border_pixmap;
+   unsigned long border_pixel;
+   int bit_gravity;
+   int win_gravity;
+   int backing_store;
+   unsigned long backing_planes;
+   unsigned long backing_pixel;
+   int save_under;
+   long event_mask;
+   long do_not_propagate_mask;
+   int override_redirect;
+   long colormap;
+   long cursor;
+} XSetWindowAttributes;
+
+typedef struct {
+   void *ext_data;
+   void *display;
+   long root;
+   int width, height;
+   int mwidth, mheight;
+   int ndepths;
+   void *depths;
+   int root_depth;
+   void *root_visual;
+   long default_gc;
+   long cmap;
+   unsigned long white_pixel;
+   unsigned long black_pixel;
+   int max_maps, min_maps;
+   int backing_store;
+   int save_unders;
+   long root_input_mask;
+} Screen;
+
+typedef struct
+{
+   void *ext_data;
+   void *private1;
+   int fd;
+   int private2;
+   int proto_major_version;
+   int proto_minor_version;
+   char *vendor;
+   long private3;
+   long private4;
+   long private5;
+   int private6;
+   long (*resource_alloc)(void *);
+   int byte_order;
+   int bitmap_unit;
+   int bitmap_pad;
+   int bitmap_bit_order;
+   int nformats;
+   void *pixmap_format;
+   int private8;
+   int release;
+   void *private9, *private10;
+   int qlen;
+   unsigned long last_request_read;
+   unsigned long request;
+   char *private11;
+   char *private12;
+   char *private13;
+   char *private14;
+   unsigned max_request_size;
+   void *db;
+   int (*private15)(void *);
+   char *display_name;
+   int default_screen;
+   int nscreens;
+   Screen *screens;
+   unsigned long motion_buffer;
+   unsigned long private16;
+   int min_keycode;
+   int max_keycode;
+   char *private17;
+   char *private18;
+   int private19;
+   char *xdefaults;
+} *_XPrivDisplay;
+
+#define InputOutput 1
+#define RootWindow(dpy, scr) (ScreenOfDisplay(dpy,scr)->root)
+#define ScreenOfDisplay(dpy, scr) (&((_XPrivDisplay)dpy)->screens[scr])
+#define CWBorderPixel (1L<<3)
+#define CWColormap (1L<<13)
+#define CWOverrideRedirect (1L<<9)
+#define AllocNone 0
+
+/*-------------------------------------------------------------------------*/
+
+static const char *lib_x11_files[] =
+{
+   "libX11.so.6",
+   "libX11.so.5",
+   "libX11.so.4",
+   "libX11.so",
+   NULL
+};
+static void *lib_x11 = NULL;
+static void * (*sym_XOpenDisplay) (char *name) = NULL;
+static long (*sym_XCreateColormap) (void *d, long w, void *vis, int alloc) = 
NULL;
+static long (*sym_XCreateWindow) (void *d, long par, int x, int y, unsigned 
int w, unsigned int h, unsigned int bd, int depth, unsigned int clas, void 
*vis, unsigned long valmask, void *attr) = NULL;
+static int (*sym_XCloseDisplay) (void *d) = NULL;
+//static void * (*sym_) () = NULL;
+
+static const char *lib_gl_files[] =
+{
+   "libGL.so.9",
+   "libGL.so.8",
+   "libGL.so.7",
+   "libGL.so.6",
+   "libGL.so.5",
+   "libGL.so.4",
+   "libGL.so.3",
+   "libGL.so.2",
+   "libGL.so.1",
+   "libGL.so",
+   NULL
+};
+static void *lib_gl = NULL;
+static GLXFBConfig * (*sym_glXChooseFBConfig) (void *d, int sc, const int 
*att, int *n) = NULL;
+static void * (*sym_glXGetVisualFromFBConfig) (void *d, GLXFBConfig fbconfig) 
= NULL;
+static void *(*sym_glXCreateNewContext) (void *d, GLXFBConfig config, int 
rtype, void *shr, int direct) = NULL;
+static long (*sym_glXCreateWindow) (void *d, GLXFBConfig config, long win, 
const int *attr) = NULL;
+static int (*sym_glXMakeContextCurrent) (void *d, long draw, long draw2, void 
*context) = NULL;
+static void (*sym_glXSwapBuffers) (void *d, long draw) = NULL;
+static const char * (*sym_glXQueryExtensionsString) (void *d, int ival) = NULL;
+static void * (*sym_glXGetProcAddressARB) (const char *sym) = NULL;
+static int (*sym_glXGetVideoSyncSGI) (unsigned int *cnt) = NULL;
+static int (*sym_glXWaitVideoSyncSGI) (int divisor, int remainder, unsigned 
int *cnt) = NULL;
+//static void * (*sym_) () = NULL;
+
+/*-------------------------------------------------------------------------*/
+
+static void *disp = NULL;
+static long gwin = 0;
+static void *context = NULL;
+
+static void *
+lib_load(const char *files[])
+{
+   int i;
+   void *lib = NULL;
+
+   for (i = 0; files[i]; i++)
+     {
+        lib = dlopen(files[i], RTLD_LOCAL | RTLD_LAZY);
+        if (lib) return lib;
+     }
+   return NULL;
+}
+
+int
+_vsync_init_glx(void)
+{
+   int fail = 0;
+   GLXFBConfig *fbconfigs;
+   int num = 0;
+   int attr[] =
+     {
+        GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+        GLX_RENDER_TYPE,   GLX_RGBA_BIT,
+        GLX_DOUBLEBUFFER,  1,
+        GLX_RED_SIZE,      1,
+        GLX_GREEN_SIZE,    1,
+        GLX_BLUE_SIZE,     1,
+        0
+     };
+   XVisualInfo *vi;
+   XSetWindowAttributes wa;
+   long win;
+   const char *extns;
+
+   /*---------------------------*/
+   lib_x11 = lib_load(lib_x11_files);
+   if (!lib_x11) goto err;
+
+   SYM(lib_x11, XOpenDisplay);
+   SYM(lib_x11, XCreateColormap);
+   SYM(lib_x11, XCreateWindow);
+   SYM(lib_x11, XCloseDisplay);
+   if (fail) goto err;
+
+   /*---------------------------*/
+   lib_gl = lib_load(lib_gl_files);
+   if (!lib_gl)
+     {
+        dlclose(lib_x11);
+        return 0;
+     }
+
+   SYM(lib_gl, glXChooseFBConfig);
+   SYM(lib_gl, glXGetVisualFromFBConfig);
+   SYM(lib_gl, glXCreateNewContext);
+   SYM(lib_gl, glXCreateWindow);
+   SYM(lib_gl, glXMakeContextCurrent);
+   SYM(lib_gl, glXSwapBuffers);
+   SYM(lib_gl, glXQueryExtensionsString);
+   SYM(lib_gl, glXGetProcAddressARB);
+   if (fail) goto err;
+
+   /*---------------------------*/
+   disp = sym_XOpenDisplay(NULL);
+   if (!disp) goto err;
+   fbconfigs = sym_glXChooseFBConfig(disp, 0, attr, &num);
+   if (!fbconfigs) goto err;
+   vi = sym_glXGetVisualFromFBConfig(disp, fbconfigs[0]);
+   if (!vi) goto err;
+   wa.override_redirect = 1;
+   wa.border_pixel = 0;
+   wa.colormap = sym_XCreateColormap(disp, RootWindow(disp, vi->screen),
+                                     vi->visual, AllocNone);
+   if (!wa.colormap) goto err;
+   win = sym_XCreateWindow(disp, RootWindow(disp, vi->screen),
+                           -77, -777, 1, 1, 0, vi->depth, InputOutput,
+                           vi->visual,
+                           CWBorderPixel | CWColormap | CWOverrideRedirect, 
&wa);
+   if (!win) goto err;
+   context = sym_glXCreateNewContext(disp, fbconfigs[0], GLX_RGBA_TYPE,
+                                     NULL, 1);
+   if (!context) goto err;
+   gwin = sym_glXCreateWindow(disp, fbconfigs[0], win, NULL);
+   if (!gwin) goto err;
+   extns = sym_glXQueryExtensionsString(disp, 0);
+   if (!extns) goto err;
+   if (!strstr(extns, "GLX_SGI_swap_control")) goto err;
+   sym_glXGetVideoSyncSGI = sym_glXGetProcAddressARB("glXGetVideoSyncSGI");
+   sym_glXWaitVideoSyncSGI = sym_glXGetProcAddressARB("glXWaitVideoSyncSGI");
+   if ((!sym_glXGetVideoSyncSGI) || (!sym_glXWaitVideoSyncSGI)) goto err;
+
+   return 1;
+err:
+   if (disp) sym_XCloseDisplay(disp);
+   if (lib_gl) dlclose(lib_gl);
+   if (lib_x11) dlclose(lib_x11);
+   return 0;
+}
+
+double
+_vsync_wait_glx(void)
+{
+   double t;
+   unsigned int rc = 0;
+
+   sym_glXMakeContextCurrent(disp, gwin, gwin, context);
+   sym_glXGetVideoSyncSGI(&rc);
+   sym_glXWaitVideoSyncSGI(1, 0, &rc);
+   t = ecore_time_get();
+   return t;
+}
diff --git a/src/lib/ecore_x/xlib/ecore_x_vsync.c 
b/src/lib/ecore_x/xlib/ecore_x_vsync.c
index 799ccfe..a228e9e 100644
--- a/src/lib/ecore_x/xlib/ecore_x_vsync.c
+++ b/src/lib/ecore_x/xlib/ecore_x_vsync.c
@@ -5,6 +5,7 @@
 #include "Ecore.h"
 #include "ecore_x_private.h"
 #include "Ecore_X.h"
+#include "Ecore_Con.h"
 
 #include <string.h>
 #include <stdlib.h>
@@ -17,6 +18,12 @@
 
 #define ECORE_X_VSYNC_DRI2 1
 
+static Ecore_X_Window vsync_root = 0;
+
+
+
+
+
 #ifdef ECORE_X_VSYNC_DRI2
 // relevant header bits of dri/drm inlined here to avoid needing external
 // headers to build
@@ -115,8 +122,6 @@ static Ecore_Fd_Handler *dri_drm_fdh = NULL;
 static void *dri_lib = NULL;
 static void *drm_lib = NULL;
 
-static Window dri_drm_vsync_root = 0;
-
 static Eina_Bool
 _dri_drm_tick_schedule(void)
 {
@@ -151,6 +156,7 @@ _dri_drm_vblank_handler(int fd EINA_UNUSED,
 {
    if (drm_event_is_busy)
      {
+        // XXX: set looptime
         ecore_animator_custom_tick();
         _dri_drm_tick_schedule();
      }
@@ -257,13 +263,13 @@ _dri_drm_init(void)
      return 0;
    if (dri2_major < 2)
      return 0;
-   if (!sym_DRI2Connect(_ecore_x_disp, dri_drm_vsync_root, &driver_name, 
&device_name))
+   if (!sym_DRI2Connect(_ecore_x_disp, vsync_root, &driver_name, &device_name))
      return 0;
    drm_fd = open(device_name, O_RDWR);
    if (drm_fd < 0)
      return 0;
    sym_drmGetMagic(drm_fd, &drm_magic);
-   if (!sym_DRI2Authenticate(_ecore_x_disp, dri_drm_vsync_root, drm_magic))
+   if (!sym_DRI2Authenticate(_ecore_x_disp, vsync_root, drm_magic))
      {
         close(drm_fd);
         drm_fd = -1;
@@ -280,7 +286,7 @@ _dri_drm_init(void)
         drm_fd = -1;
         return 0;
      }
-   
+
    dri_drm_fdh = ecore_main_fd_handler_add(drm_fd, ECORE_FD_READ,
                                            _dri_drm_cb, NULL, NULL, NULL);
    if (!dri_drm_fdh)
@@ -307,55 +313,227 @@ _dri_drm_shutdown(void)
      }
 }
 
-#endif
-
-EAPI Eina_Bool
-ecore_x_vsync_animator_tick_source_set(Ecore_X_Window win)
+static Eina_Bool
+_dri_animator_tick_source_set(void)
 {
-#ifdef ECORE_X_VSYNC_DRI2
-   Ecore_X_Window root;
-
-   root = ecore_x_window_root_get(win);
-   if (root != dri_drm_vsync_root)
+   if (vsync_root)
      {
-        dri_drm_vsync_root = root;
-        if (dri_drm_vsync_root)
+        if (!_dri_drm_link())
+          {
+             ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
+             return EINA_FALSE;
+          }
+        _dri_drm_shutdown();
+        if (!_dri_drm_init())
+          {
+             vsync_root = 0;
+             ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
+             return EINA_FALSE;
+          }
+        ecore_animator_custom_source_tick_begin_callback_set
+          (_dri_drm_tick_begin, NULL);
+        ecore_animator_custom_source_tick_end_callback_set
+          (_dri_drm_tick_end, NULL);
+        ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM);
+     }
+   else
+     {
+        if (drm_fd >= 0)
           {
-             if (!_dri_drm_link())
-               {
-                  ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
-                  return EINA_FALSE;
-               }
              _dri_drm_shutdown();
-             if (!_dri_drm_init())
-               {
-                  dri_drm_vsync_root = 0;
-                  ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
-                  return EINA_FALSE;
-               }
              ecore_animator_custom_source_tick_begin_callback_set
-               (_dri_drm_tick_begin, NULL);
+               (NULL, NULL);
              ecore_animator_custom_source_tick_end_callback_set
-               (_dri_drm_tick_end, NULL);
-             ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM);
+               (NULL, NULL);
+             ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
           }
-        else
+     }
+   return EINA_TRUE;
+}
+#endif
+
+
+
+
+
+
+
+
+
+static Ecore_Con_Server *vsync_server = NULL;
+static Eina_Bool handlers = EINA_FALSE;
+static Eina_Prefix *_prefix = NULL;
+
+static Eina_Bool
+vsync_server_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+   Ecore_Con_Event_Server_Add *ev = event;
+   if (ev->server != vsync_server) return EINA_TRUE;
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+vsync_server_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+   Ecore_Con_Event_Server_Del *ev = event;
+   if (ev->server != vsync_server) return EINA_TRUE;
+   if (vsync_server)
+     {
+        ecore_con_server_del(vsync_server);
+        vsync_server = NULL;
+        ecore_animator_custom_source_tick_begin_callback_set(NULL, NULL);
+        ecore_animator_custom_source_tick_end_callback_set(NULL, NULL);
+        ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
+     }
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+vsync_server_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+   Ecore_Con_Event_Server_Data *ev = event;
+   int i;
+   double t;
+   char *d;
+   if (ev->server != vsync_server) return EINA_TRUE;
+   d = ev->data;;
+   for (i = 0; i < ev->size - (int)(sizeof(double) - 1); i++)
+     {
+        memcpy(&t, &(d[i]), sizeof(double));
+        ecore_loop_time_set(t);
+        ecore_animator_custom_tick();
+     }
+   return EINA_FALSE;
+}
+
+static void
+vsync_tick_begin(void *data EINA_UNUSED)
+{
+   char val = 1;
+   ecore_con_server_send(vsync_server, &val, 1);
+}
+
+static void
+vsync_tick_end(void *data EINA_UNUSED)
+{
+   char val = 0;
+   ecore_con_server_send(vsync_server, &val, 1);
+}
+
+static Eina_Bool
+_glvsync_animator_tick_source_set(void)
+{
+   if (!vsync_server)
+     {
+        char buf[4096], *disp, *s;
+        int tries = 0;
+
+        if (!handlers)
           {
-             if (drm_fd >= 0)
-               {
-                  _dri_drm_shutdown();
-                  ecore_animator_custom_source_tick_begin_callback_set
-                    (NULL, NULL);
-                  ecore_animator_custom_source_tick_end_callback_set
-                    (NULL, NULL);
-                  ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
-               }
+             _prefix = eina_prefix_new(NULL, 
ecore_x_vsync_animator_tick_source_set,
+                                       "ECORE_X", "ecore_x", "checkme",
+                                       PACKAGE_BIN_DIR, PACKAGE_LIB_DIR,
+                                       PACKAGE_DATA_DIR, PACKAGE_DATA_DIR);
+             ecore_con_init();
           }
+        disp = getenv("DISPLAY");
+        if (disp) disp = ":0";
+        snprintf(buf, sizeof(buf), "ecore-x-vsync-%s", disp);
+        for (s = buf; *s; s++)
+          {
+             if (*s == ':') *s = '=';
+          }
+        vsync_server = ecore_con_server_connect(ECORE_CON_LOCAL_USER, buf, 1, 
NULL);
+        while (!vsync_server)
+          {
+             tries++;
+             if (tries > 50) return EINA_FALSE;
+             snprintf(buf, sizeof(buf), "%s/ecore_x/bin/%s/ecore_x_vsync",
+                      eina_prefix_lib_get(_prefix), MODULE_ARCH);
+             ecore_exe_run(buf, NULL);
+             usleep(10000);
+             vsync_server = ecore_con_server_connect(ECORE_CON_LOCAL_USER, 
buf, 0, NULL);
+          }
+        if (!handlers)
+          {
+             ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, 
vsync_server_add, NULL);
+             ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL, 
vsync_server_del, NULL);
+             ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA, 
vsync_server_data, NULL);
+             handlers = EINA_FALSE;
+          }
+     }
+   if (vsync_root)
+     {
+        ecore_animator_custom_source_tick_begin_callback_set(vsync_tick_begin, 
NULL);
+        ecore_animator_custom_source_tick_end_callback_set(vsync_tick_end, 
NULL);
+        ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM);
+     }
+   else
+     {
+        if (vsync_server)
+          {
+             ecore_con_server_del(vsync_server);
+             vsync_server = NULL;
+          }
+        ecore_animator_custom_source_tick_begin_callback_set(NULL, NULL);
+        ecore_animator_custom_source_tick_end_callback_set(NULL, NULL);
+        ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
      }
    return EINA_TRUE;
-#else
-   return EINA_FALSE;
-   win = 0;
+}
+
+// XXX: missing mode 3 == separate x connection with compiled in dri2 proto
+// handling ala mesa (taken from mesa likely)
+
+static int mode = 0;
+
+static void
+_vsync_init(void)
+{
+   static int done = 0;
+
+   if (done) return;
+
+#ifdef ECORE_X_VSYNC_DRI2
+   // preferred inline dri/drm if possible
+   if (_dri_drm_link())
+     {
+        _dri_drm_shutdown();
+        if (_dri_drm_init())
+          {
+             mode = 1;
+          }
+     }
 #endif
+   // nvidia gl vsync slave mode
+   if (mode == 0)
+     {
+        struct stat stb;
+
+        if (!stat("/dev/nvidiactl", &stb))
+          {
+             mode = 2;
+          }
+     }
+   done = 1;
 }
 
+EAPI Eina_Bool
+ecore_x_vsync_animator_tick_source_set(Ecore_X_Window win)
+{
+   Ecore_X_Window root;
+
+   root = ecore_x_window_root_get(win);
+   if (root != vsync_root)
+     {
+        _vsync_init();
+        vsync_root = root;
+#ifdef ECORE_X_VSYNC_DRI2
+        if (mode == 1) return _dri_animator_tick_source_set();
+        else
+#endif
+        if (mode == 2) return _glvsync_animator_tick_source_set();
+        else return EINA_FALSE;
+     }
+   return EINA_TRUE;
+}

-- 


Reply via email to