diff --git a/.gitignore b/.gitignore index ad5734a129..9ba26f070d 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 6d42a099de..d4986193d0 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -27,6 +27,12 @@ ecorefilesdir = $(datadir)/ecore 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 diff --git a/data/ecore_x/checkme b/data/ecore_x/checkme new file mode 100644 index 0000000000..1688a66696 --- /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 fcb4bb4a8b..5cc4ccf138 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 0000000000..34c93403ef --- /dev/null +++ b/src/lib/ecore_x/ecore_x_vsync_tool.c @@ -0,0 +1,256 @@ +#include +#include +#include + +#include + +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 0000000000..1d5b347e33 --- /dev/null +++ b/src/lib/ecore_x/ecore_x_vsync_tool_glx.c @@ -0,0 +1,302 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*-------------------------------------------------------------------------*/ + +#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 799ccfea91..a228e9e046 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 #include @@ -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) } } +static Eina_Bool +_dri_animator_tick_source_set(void) +{ + if (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) + { + _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); + } + } + 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) + { + _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; +} + +// 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) { -#ifdef ECORE_X_VSYNC_DRI2 Ecore_X_Window root; root = ecore_x_window_root_get(win); - if (root != dri_drm_vsync_root) + if (root != 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()) - { - 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); - ecore_animator_custom_source_tick_end_callback_set - (_dri_drm_tick_end, NULL); - ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM); - } + _vsync_init(); + vsync_root = root; +#ifdef ECORE_X_VSYNC_DRI2 + if (mode == 1) return _dri_animator_tick_source_set(); else - { - 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); - } - } +#endif + if (mode == 2) return _glvsync_animator_tick_source_set(); + else return EINA_FALSE; } return EINA_TRUE; -#else - return EINA_FALSE; - win = 0; -#endif } -