summaryrefslogtreecommitdiff
path: root/clutter/clutter-feature.c
diff options
context:
space:
mode:
authorMatthew Allum <mallum@openedhand.com>2006-11-15 21:19:01 +0000
committerMatthew Allum <mallum@openedhand.com>2006-11-15 21:19:01 +0000
commit5ca4d3718d61805b1e4ee52758801d824e8517fa (patch)
tree0c73a971e38245b1cbe71fa7f8b66a5aeb4b2b46 /clutter/clutter-feature.c
parent3f62c72d077b46415aeb4f1dd4a51a2934aa5a7b (diff)
downloadclutter-5ca4d3718d61805b1e4ee52758801d824e8517fa.tar.gz
2006-11-15 Matthew Allum <mallum@openedhand.com>
* clutter/clutter-actor.h: * clutter/clutter-actor.c: Add new API clutter_actor_move_by(), clutter_actor_get_size() * clutter/clutter-alpha.c: * clutter/clutter-alpha.h: Add clutter alpha sine func * clutter/clutter-behaviours.h: * clutter/clutter-behaviours.c: Add a basic scale behaviour (needs work) * examples/behave.c: (main): More playing with new behaviour functionality * clutter/clutter-feature.c: * clutter/clutter-feature.h: * clutter/clutter-main.c: Add new experimental sync to vblank code Set env CLUTTER_VBLANK=none to disable.
Diffstat (limited to 'clutter/clutter-feature.c')
-rw-r--r--clutter/clutter-feature.c229
1 files changed, 217 insertions, 12 deletions
diff --git a/clutter/clutter-feature.c b/clutter/clutter-feature.c
index 4ff4c04bc..fe395edf4 100644
--- a/clutter/clutter-feature.c
+++ b/clutter/clutter-feature.c
@@ -31,21 +31,102 @@
*/
#include "config.h"
+#include "clutter-main.h"
#include "clutter-feature.h"
-#include "string.h"
-static ClutterFeatureFlags __features = -1;
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+
+ #include <dlfcn.h>
+
+typedef void (*FuncPtr) (void);
+typedef int (*GLXGetVideoSyncProc) (unsigned int *count);
+typedef int (*GLXWaitVideoSyncProc) (int divisor,
+ int remainder,
+ unsigned int *count);
+typedef FuncPtr (*GLXGetProcAddressProc) (const guint8 *procName);
+
+typedef struct ClutterFeatureFuncs
+{
+ GLXGetVideoSyncProc get_video_sync;
+ GLXWaitVideoSyncProc wait_video_sync;
+
+} ClutterFeatureFuncs;
+
+typedef enum ClutterVBlankType
+{
+ CLUTTER_VBLANK_NONE = 0,
+ CLUTTER_VBLANK_GLX,
+ CLUTTER_VBLANK_DRI
+
+} ClutterVBlankType;
+
+typedef struct ClutterFeatures
+{
+ ClutterFeatureFlags flags;
+ ClutterFeatureFuncs funcs;
+ gint dri_fd;
+ ClutterVBlankType vblank_type;
+
+} ClutterFeatures;
+
+static ClutterFeatures* __features = NULL;
+
+/* #ifdef linux */
+#define DRM_VBLANK_RELATIVE 0x1;
+
+struct drm_wait_vblank_request {
+ int type;
+ unsigned int sequence;
+ unsigned long signal;
+};
+
+struct drm_wait_vblank_reply {
+ int type;
+ unsigned int sequence;
+ long tval_sec;
+ long tval_usec;
+};
+
+typedef union drm_wait_vblank {
+ struct drm_wait_vblank_request request;
+ struct drm_wait_vblank_reply reply;
+} drm_wait_vblank_t;
+
+#define DRM_IOCTL_BASE 'd'
+#define DRM_IOWR(nr,type) _IOWR(DRM_IOCTL_BASE,nr,type)
+#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t)
+
+static int drm_wait_vblank(int fd, drm_wait_vblank_t *vbl)
+{
+ int ret, rc;
+
+ do
+ {
+ ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
+ vbl->request.type &= ~DRM_VBLANK_RELATIVE;
+ rc = errno;
+ }
+ while (ret && rc == EINTR);
+
+ return rc;
+}
+
+/* #endif */
+
/* Note must be called after context created */
static gboolean
-check_gl_extension (const gchar *name)
+check_gl_extension (const gchar *name, const gchar *ext)
{
- const gchar *ext;
gchar *end;
gint name_len, n;
- ext = (const gchar*)glGetString(GL_EXTENSIONS);
-
if (name == NULL || ext == NULL)
return FALSE;
@@ -65,20 +146,117 @@ check_gl_extension (const gchar *name)
return FALSE;
}
+static FuncPtr
+get_proc_address (const gchar *name)
+{
+ static GLXGetProcAddressProc get_proc_func = NULL;
+ static void *dlhand = NULL;
+
+ if (get_proc_func == NULL && dlhand == NULL)
+ {
+ dlhand = dlopen (NULL, RTLD_LAZY);
+
+ if (dlhand)
+ {
+ dlerror ();
+ get_proc_func
+ = (GLXGetProcAddressProc) dlsym (dlhand, "glXGetProcAddress");
+ if (dlerror () != NULL)
+ get_proc_func
+ = (GLXGetProcAddressProc) dlsym (dlhand, "glXGetProcAddressARB");
+ if (dlerror () != NULL)
+ {
+ get_proc_func = NULL;
+ g_warning
+ ("failed to bind GLXGetProcAddress or GLXGetProcAddressARB");
+ }
+ }
+ }
+
+ if (get_proc_func)
+ return get_proc_func ((unsigned char*)name);
+
+ return NULL;
+}
+
+
+static gboolean
+check_vblank_env (const char *name)
+{
+ const char *val;
+
+ val = getenv("CLUTTER_VBLANK");
+
+ if (val && !strcasecmp(val, name))
+ return TRUE;
+
+ return FALSE;
+}
+
void
clutter_feature_init (void)
{
- if (__features != -1)
+ const gchar *gl_extensions, *glx_extensions;
+
+ if (__features != NULL)
{
g_warning ("You should never call clutter_feature_init() "
"more than once.");
return;
}
- __features = 0;
+ __features = g_new0 (ClutterFeatures, 1);
+ memset(&__features->funcs, 0, sizeof(ClutterFeatureFuncs));
+
+ gl_extensions = (const gchar*)glGetString(GL_EXTENSIONS);
+ glx_extensions = glXQueryExtensionsString (clutter_xdisplay(),
+ clutter_xscreen());
+
+ if (check_gl_extension ("GL_ARB_texture_rectangle", gl_extensions))
+ __features->flags |= CLUTTER_FEATURE_TEXTURE_RECTANGLE;
+
+ /* vblank */
- if (check_gl_extension ("GL_ARB_texture_rectangle"))
- __features |= CLUTTER_FEATURE_TEXTURE_RECTANGLE;
+ __features->vblank_type = CLUTTER_VBLANK_NONE;
+
+ if (getenv("__GL_SYNC_TO_VBLANK") || check_vblank_env("none"))
+ {
+ CLUTTER_DBG("vblank sync: disabled at user request");
+ }
+ else
+ {
+ if (!check_vblank_env("dri")
+ && check_gl_extension ("GLX_SGI_video_sync", glx_extensions))
+ {
+ __features->funcs.get_video_sync =
+ (GLXGetVideoSyncProc) get_proc_address ("glXGetVideoSyncSGI");
+
+ __features->funcs.wait_video_sync =
+ (GLXWaitVideoSyncProc) get_proc_address ("glXWaitVideoSyncSGI");
+
+ if (__features->funcs.get_video_sync != NULL
+ && __features->funcs.wait_video_sync != NULL)
+ {
+ CLUTTER_DBG("vblank sync: using glx");
+ __features->vblank_type = CLUTTER_VBLANK_GLX;
+ __features->flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
+ }
+ }
+
+ if (!(__features->flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
+ {
+ __features->dri_fd = open("/dev/dri/card0", O_RDWR);
+ if (__features->dri_fd >= 0)
+ {
+ CLUTTER_DBG("vblank sync: using dri");
+ __features->vblank_type = CLUTTER_VBLANK_DRI;
+ __features->flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
+ }
+ }
+
+ if (!(__features->flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
+ CLUTTER_DBG("vblank sync: no use-able mechanism found");
+ }
}
/**
@@ -95,7 +273,7 @@ clutter_feature_init (void)
gboolean
clutter_feature_available (ClutterFeatureFlags feature)
{
- return (__features & feature);
+ return (__features->flags & feature);
}
/**
@@ -110,5 +288,32 @@ clutter_feature_available (ClutterFeatureFlags feature)
ClutterFeatureFlags
clutter_feature_all (void)
{
- return __features;
+ return __features->flags;
+}
+
+void
+clutter_feature_wait_for_vblank (void)
+{
+ switch (__features->vblank_type)
+ {
+ case CLUTTER_VBLANK_GLX:
+ {
+ unsigned int retraceCount;
+ __features->funcs.get_video_sync(&retraceCount);
+ __features->funcs.wait_video_sync(2,
+ (retraceCount+1)%2, &retraceCount);
+ }
+ break;
+ case CLUTTER_VBLANK_DRI:
+ {
+ drm_wait_vblank_t blank;
+ blank.request.type = DRM_VBLANK_RELATIVE;
+ blank.request.sequence = 1;
+ drm_wait_vblank (__features->dri_fd, &blank);
+ }
+ break;
+ case CLUTTER_VBLANK_NONE:
+ default:
+ break;
+ }
}