2007-05-16 Matthew Allum <mallum@openedhand.com>
* clutter/clutter-backend.c: * clutter/clutter-backend.h: * clutter/clutter-feature.c: * clutter/clutter-feature.h: * clutter/clutter-main.c: * clutter/clutter-main.h: * clutter/clutter-private.h: * clutter/clutter-stage.c: * clutter/cogl/cogl.h: * clutter/cogl/gl/cogl.c: * clutter/cogl/gles/cogl.c: * clutter/glx/clutter-backend-glx.c: * clutter/glx/clutter-backend-glx.h: * clutter/glx/clutter-glx.h: * clutter/glx/clutter-stage-glx.c: * clutter/glx/clutter-stage-glx.h: Rejig the features() foo, moving mostly into backends/cogl.
This commit is contained in:
parent
aab511d319
commit
ee928107cb
20
ChangeLog
20
ChangeLog
@ -1,3 +1,23 @@
|
||||
2007-05-16 Matthew Allum <mallum@openedhand.com>
|
||||
|
||||
* clutter/clutter-backend.c:
|
||||
* clutter/clutter-backend.h:
|
||||
* clutter/clutter-feature.c:
|
||||
* clutter/clutter-feature.h:
|
||||
* clutter/clutter-main.c:
|
||||
* clutter/clutter-main.h:
|
||||
* clutter/clutter-private.h:
|
||||
* clutter/clutter-stage.c:
|
||||
* clutter/cogl/cogl.h:
|
||||
* clutter/cogl/gl/cogl.c:
|
||||
* clutter/cogl/gles/cogl.c:
|
||||
* clutter/glx/clutter-backend-glx.c:
|
||||
* clutter/glx/clutter-backend-glx.h:
|
||||
* clutter/glx/clutter-glx.h:
|
||||
* clutter/glx/clutter-stage-glx.c:
|
||||
* clutter/glx/clutter-stage-glx.h:
|
||||
Rejig the features() foo, moving mostly into backends/cogl.
|
||||
|
||||
2007-05-15 Tomas Frydrych <tf@openedhand.com>
|
||||
|
||||
* clutter/clutter-actor.c:
|
||||
|
@ -143,16 +143,18 @@ _clutter_backend_init_stage (ClutterBackend *backend,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_backend_init_features (ClutterBackend *backend)
|
||||
ClutterFeatureFlags
|
||||
_clutter_backend_get_features (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendClass *klass;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_BACKEND (backend));
|
||||
|
||||
klass = CLUTTER_BACKEND_GET_CLASS (backend);
|
||||
if (klass->init_features)
|
||||
klass->init_features (backend);
|
||||
if (klass->get_features)
|
||||
return klass->get_features (backend);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <glib-object.h>
|
||||
#include <clutter/clutter-actor.h>
|
||||
#include <clutter/clutter-event.h>
|
||||
#include <clutter/clutter-feature.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -66,6 +67,7 @@ struct _ClutterBackendClass
|
||||
ClutterActor *(* get_stage) (ClutterBackend *backend);
|
||||
void (* add_options) (ClutterBackend *backend,
|
||||
GOptionGroup *group);
|
||||
ClutterFeatureFlags (* get_features) (ClutterBackend *backend);
|
||||
};
|
||||
|
||||
GType clutter_backend_get_type (void) G_GNUC_CONST;
|
||||
|
@ -35,311 +35,48 @@
|
||||
#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 <GL/glx.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "clutter-feature.h"
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-debug.h"
|
||||
|
||||
#ifdef HAVE_CLUTTER_GLX
|
||||
#include "glx/clutter-glx.h"
|
||||
#endif
|
||||
|
||||
typedef void (*FuncPtr) (void);
|
||||
typedef int (*GetVideoSyncProc) (unsigned int *count);
|
||||
typedef int (*WaitVideoSyncProc) (int divisor,
|
||||
int remainder,
|
||||
unsigned int *count);
|
||||
typedef FuncPtr (*GLXGetProcAddressProc) (const guint8 *procName);
|
||||
|
||||
typedef struct ClutterFeatureFuncs
|
||||
{
|
||||
GetVideoSyncProc get_video_sync;
|
||||
WaitVideoSyncProc wait_video_sync;
|
||||
|
||||
} ClutterFeatureFuncs;
|
||||
|
||||
typedef enum ClutterVBlankType
|
||||
{
|
||||
CLUTTER_VBLANK_NONE = 0,
|
||||
CLUTTER_VBLANK_GLX,
|
||||
CLUTTER_VBLANK_DRI
|
||||
|
||||
} ClutterVBlankType;
|
||||
#include "cogl.h"
|
||||
|
||||
typedef struct ClutterFeatures
|
||||
{
|
||||
ClutterFeatureFlags flags;
|
||||
ClutterFeatureFuncs funcs;
|
||||
gint dri_fd;
|
||||
ClutterVBlankType vblank_type;
|
||||
|
||||
guint features_set : 1;
|
||||
} ClutterFeatures;
|
||||
|
||||
static ClutterFeatures* __features = NULL;
|
||||
G_LOCK_DEFINE_STATIC (__features);
|
||||
|
||||
|
||||
#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)
|
||||
void
|
||||
_clutter_feature_init (void)
|
||||
{
|
||||
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,
|
||||
const gchar *ext)
|
||||
{
|
||||
/* FIXME: move to cogl */
|
||||
gchar *end;
|
||||
gint name_len, n;
|
||||
|
||||
if (name == NULL || ext == NULL)
|
||||
return FALSE;
|
||||
|
||||
end = (gchar*)(ext + strlen(ext));
|
||||
|
||||
name_len = strlen(name);
|
||||
|
||||
while (ext < end)
|
||||
{
|
||||
n = strcspn(ext, " ");
|
||||
|
||||
if ((name_len == n) && (!strncmp(name, ext, n)))
|
||||
return TRUE;
|
||||
ext += (n + 1);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* FIXME: move to cogl */
|
||||
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 = clutter_get_vblank_method ();
|
||||
|
||||
if (val && !strcasecmp(val, name))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* clutter_feature_init:
|
||||
* must be called with the static lock on __features held, to keep it
|
||||
* mt-safe.
|
||||
*
|
||||
* XXX - here we need a bit of weird machinery in place. the features
|
||||
* are checked at run time, each time we try to access them - unless
|
||||
* we already checked them once. unfortunately, we need an open
|
||||
* X display if we want to check them, so ideally we'd need to call
|
||||
* clutter_init() before checking for any feature. the generator for
|
||||
* the api documentation, and more in general every tool relying on the
|
||||
* introspection API provided by GObject, may well not be able to call
|
||||
* clutter_init() (and neither they should be, as we might be running
|
||||
* them on a headless build box). so, we need a way to get the features
|
||||
* without explicitely calling clutter_feature_init() inside clutter_init()
|
||||
* and we also need to have an open X display when we test for the features.
|
||||
* __features is dynamically allocated, and applications tend to badly
|
||||
* crash when trying to access __features components if we did not allocate
|
||||
* it; so when can't use a NULL check to know whether we already invoked
|
||||
* clutter_feature_init() once; hence, we must allocate it anyway, and have
|
||||
* a flag to let us know when the features have been set - that is when
|
||||
* clutter_feature_init() has been successfully completed with an open
|
||||
* X display.
|
||||
*/
|
||||
static void
|
||||
clutter_feature_init (void)
|
||||
{
|
||||
const gchar *gl_extensions, *glx_extensions = NULL;
|
||||
ClutterMainContext *context;
|
||||
|
||||
CLUTTER_NOTE (MISC, "checking features");
|
||||
|
||||
if (!__features)
|
||||
{
|
||||
CLUTTER_NOTE (MISC, "allocating features data");
|
||||
|
||||
__features = g_new0 (ClutterFeatures, 1);
|
||||
memset(&__features->funcs, 0, sizeof (ClutterFeatureFuncs));
|
||||
__features->features_set = FALSE; /* don't rely on zero-ing */
|
||||
}
|
||||
|
||||
#ifdef HAVE_CLUTTER_GLX
|
||||
if (!clutter_glx_get_default_display ())
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (__features->features_set)
|
||||
return;
|
||||
|
||||
#ifdef HAVE_CLUTTER_GLX
|
||||
glx_extensions
|
||||
= glXQueryExtensionsString (clutter_glx_get_default_display (),
|
||||
clutter_glx_get_default_screen ());
|
||||
#endif
|
||||
context = clutter_context_get_default ();
|
||||
|
||||
gl_extensions = (const gchar*) glGetString (GL_EXTENSIONS);
|
||||
|
||||
if (check_gl_extension ("GL_ARB_texture_rectangle", gl_extensions) ||
|
||||
check_gl_extension ("GL_EXT_texture_rectangle", gl_extensions))
|
||||
{
|
||||
__features->flags |= CLUTTER_FEATURE_TEXTURE_RECTANGLE;
|
||||
}
|
||||
|
||||
/* vblank */
|
||||
|
||||
__features->vblank_type = CLUTTER_VBLANK_NONE;
|
||||
|
||||
if (getenv("__GL_SYNC_TO_VBLANK") || check_vblank_env ("none"))
|
||||
{
|
||||
CLUTTER_NOTE (MISC, "vblank sync: disabled at user request");
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_CLUTTER_GLX
|
||||
if (!check_vblank_env ("dri") &&
|
||||
check_gl_extension ("GLX_SGI_video_sync", glx_extensions))
|
||||
{
|
||||
__features->funcs.get_video_sync =
|
||||
(GetVideoSyncProc) get_proc_address ("glXGetVideoSyncSGI");
|
||||
|
||||
__features->funcs.wait_video_sync =
|
||||
(WaitVideoSyncProc) get_proc_address ("glXWaitVideoSyncSGI");
|
||||
|
||||
if ((__features->funcs.get_video_sync != NULL) &&
|
||||
(__features->funcs.wait_video_sync != NULL))
|
||||
{
|
||||
CLUTTER_NOTE (MISC, "vblank sync: using glx");
|
||||
|
||||
__features->vblank_type = CLUTTER_VBLANK_GLX;
|
||||
__features->flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
if (!(__features->flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
|
||||
{
|
||||
__features->dri_fd = open("/dev/dri/card0", O_RDWR);
|
||||
if (__features->dri_fd >= 0)
|
||||
{
|
||||
CLUTTER_NOTE (MISC, "vblank sync: using dri");
|
||||
|
||||
__features->vblank_type = CLUTTER_VBLANK_DRI;
|
||||
__features->flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!(__features->flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
|
||||
{
|
||||
CLUTTER_NOTE (MISC,
|
||||
"vblank sync: no use-able mechanism found");
|
||||
}
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (MISC, "features checked");
|
||||
__features->flags = cogl_get_features()
|
||||
|_clutter_backend_get_features (context->backend);
|
||||
|
||||
__features->features_set = TRUE;
|
||||
}
|
||||
|
||||
static inline void
|
||||
clutter_feature_do_init (void)
|
||||
{
|
||||
if (G_UNLIKELY (__features == NULL) ||
|
||||
G_UNLIKELY (__features->features_set == FALSE))
|
||||
{
|
||||
G_LOCK (__features);
|
||||
clutter_feature_init ();
|
||||
G_UNLOCK (__features);
|
||||
}
|
||||
CLUTTER_NOTE (MISC, "features checked");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -356,9 +93,7 @@ clutter_feature_do_init (void)
|
||||
gboolean
|
||||
clutter_feature_available (ClutterFeatureFlags feature)
|
||||
{
|
||||
clutter_feature_do_init ();
|
||||
|
||||
return (__features->flags & feature);
|
||||
return (__features->flags & feature);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -373,49 +108,6 @@ clutter_feature_available (ClutterFeatureFlags feature)
|
||||
ClutterFeatureFlags
|
||||
clutter_feature_get_all (void)
|
||||
{
|
||||
clutter_feature_do_init ();
|
||||
|
||||
return __features->flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_feature_wait_for_vblank:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Since: 0.2
|
||||
*/
|
||||
void
|
||||
clutter_feature_wait_for_vblank (void)
|
||||
{
|
||||
clutter_feature_do_init ();
|
||||
|
||||
switch (__features->vblank_type)
|
||||
{
|
||||
case CLUTTER_VBLANK_GLX:
|
||||
#ifdef HAVE_CLUTTER_GLX
|
||||
{
|
||||
unsigned int retraceCount;
|
||||
__features->funcs.get_video_sync (&retraceCount);
|
||||
__features->funcs.wait_video_sync (2,
|
||||
(retraceCount + 1) % 2,
|
||||
&retraceCount);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case CLUTTER_VBLANK_DRI:
|
||||
#ifdef __linux__
|
||||
{
|
||||
drm_wait_vblank_t blank;
|
||||
blank.request.type = DRM_VBLANK_RELATIVE;
|
||||
blank.request.sequence = 1;
|
||||
blank.request.signal = 0;
|
||||
drm_wait_vblank (__features->dri_fd, &blank);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case CLUTTER_VBLANK_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -39,13 +39,13 @@ G_BEGIN_DECLS
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CLUTTER_FEATURE_TEXTURE_RECTANGLE = (1 << 1),
|
||||
CLUTTER_FEATURE_SYNC_TO_VBLANK = (1 << 2)
|
||||
CLUTTER_FEATURE_TEXTURE_RECTANGLE = (1 << 1),
|
||||
CLUTTER_FEATURE_SYNC_TO_VBLANK = (1 << 2),
|
||||
CLUTTER_FEATURE_TEXTURE_READ_PIXELS = (1 << 3)
|
||||
} ClutterFeatureFlags;
|
||||
|
||||
gboolean clutter_feature_available (ClutterFeatureFlags feature);
|
||||
ClutterFeatureFlags clutter_feature_get_all (void);
|
||||
void clutter_feature_wait_for_vblank (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -51,7 +51,6 @@ static ClutterMainContext *ClutterCntx = NULL;
|
||||
static gboolean clutter_is_initialized = FALSE;
|
||||
static gboolean clutter_show_fps = FALSE;
|
||||
static gboolean clutter_fatal_warnings = FALSE;
|
||||
static gchar *clutter_vblank_name = NULL;
|
||||
|
||||
guint clutter_debug_flags = 0; /* global clutter debug flag */
|
||||
|
||||
@ -85,20 +84,6 @@ clutter_get_show_fps (void)
|
||||
return clutter_show_fps;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_get_vblank_method:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
G_CONST_RETURN gchar *
|
||||
clutter_get_vblank_method (void)
|
||||
{
|
||||
return clutter_vblank_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_redraw:
|
||||
@ -330,8 +315,6 @@ clutter_arg_no_debug_cb (const char *key,
|
||||
static GOptionEntry clutter_args[] = {
|
||||
{ "clutter-show-fps", 0, 0, G_OPTION_ARG_NONE, &clutter_show_fps,
|
||||
"Show frames per second", NULL },
|
||||
{ "clutter-vblank", 0, 0, G_OPTION_ARG_STRING, &clutter_vblank_name,
|
||||
"VBlank method to be used (none, dri or glx)", "METHOD" },
|
||||
{ "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &clutter_fatal_warnings,
|
||||
"Make all warnings fatal", NULL },
|
||||
#ifdef CLUTTER_ENABLE_DEBUG
|
||||
@ -382,12 +365,6 @@ pre_parse_hook (GOptionContext *context,
|
||||
}
|
||||
#endif /* CLUTTER_ENABLE_DEBUG */
|
||||
|
||||
env_string = g_getenv ("CLUTTER_VBLANK");
|
||||
if (env_string)
|
||||
{
|
||||
clutter_vblank_name = g_strdup (env_string);
|
||||
env_string = NULL;
|
||||
}
|
||||
|
||||
env_string = g_getenv ("CLUTTER_SHOW_FPS");
|
||||
if (env_string)
|
||||
@ -555,6 +532,8 @@ clutter_init_with_args (int *argc,
|
||||
|
||||
_clutter_backend_init_events (clutter_context->backend);
|
||||
|
||||
_clutter_feature_init ();
|
||||
|
||||
return CLUTTER_INIT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -615,14 +594,21 @@ clutter_init (int *argc,
|
||||
|
||||
g_type_init ();
|
||||
|
||||
/* parse_args will trigger backend creation and things like
|
||||
* DISPLAY connection etc.
|
||||
*/
|
||||
if (clutter_parse_args (argc, argv) == FALSE)
|
||||
{
|
||||
CLUTTER_NOTE (MISC, "failed to parse arguments.");
|
||||
return CLUTTER_INIT_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
/* Note, creates backend if not already existing (though parse args will
|
||||
* have likely created it)
|
||||
*/
|
||||
context = clutter_context_get_default ();
|
||||
|
||||
/* Stage will give us a GL Context etc */
|
||||
stage_error = NULL;
|
||||
if (!_clutter_backend_init_stage (context->backend, &stage_error))
|
||||
{
|
||||
@ -632,8 +618,12 @@ clutter_init (int *argc,
|
||||
return CLUTTER_INIT_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
/* Initiate event collection */
|
||||
_clutter_backend_init_events (context->backend);
|
||||
|
||||
/* finally features - will call to backend and cogl */
|
||||
_clutter_feature_init ();
|
||||
|
||||
return CLUTTER_INIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,6 @@ void clutter_redraw (void);
|
||||
|
||||
gboolean clutter_get_debug_enabled (void);
|
||||
gboolean clutter_get_show_fps (void);
|
||||
G_CONST_RETURN gchar *clutter_get_vblank_method (void);
|
||||
|
||||
void clutter_threads_enter (void);
|
||||
void clutter_threads_leave (void);
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "clutter-event.h"
|
||||
#include "clutter-backend.h"
|
||||
#include "clutter-stage.h"
|
||||
#include "clutter-feature.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -103,12 +104,14 @@ gboolean _clutter_backend_init_stage (ClutterBackend *backend,
|
||||
GError **error);
|
||||
void _clutter_backend_init_events (ClutterBackend *backend);
|
||||
|
||||
void _clutter_backend_init_features (ClutterBackend *backend);
|
||||
ClutterFeatureFlags _clutter_backend_get_features (ClutterBackend *backend);
|
||||
|
||||
/* backend helpers */
|
||||
void _clutter_event_button_generate (ClutterBackend *backend,
|
||||
ClutterEvent *event);
|
||||
|
||||
void _clutter_feature_init (void);
|
||||
|
||||
/* FIXME: move elsewhere via ClutterAudience */
|
||||
void _clutter_stage_sync_viewport (ClutterStage *stage);
|
||||
|
||||
|
@ -151,9 +151,9 @@ clutter_stage_set_property (GObject *object,
|
||||
|
||||
static void
|
||||
clutter_stage_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ClutterStage *stage;
|
||||
ClutterStagePrivate *priv;
|
||||
|
@ -178,6 +178,8 @@ void
|
||||
cogl_alpha_func (COGLenum func,
|
||||
ClutterFixed ref);
|
||||
|
||||
ClutterFeatureFlags
|
||||
cogl_get_features ();
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -84,11 +84,56 @@ error_string(GLenum errorCode)
|
||||
#define GE(x) (x);
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
check_gl_extension (const gchar *name,
|
||||
const gchar *ext)
|
||||
{
|
||||
gchar *end;
|
||||
gint name_len, n;
|
||||
|
||||
if (name == NULL || ext == NULL)
|
||||
return FALSE;
|
||||
|
||||
end = (gchar*)(ext + strlen(ext));
|
||||
|
||||
name_len = strlen(name);
|
||||
|
||||
while (ext < end)
|
||||
{
|
||||
n = strcspn(ext, " ");
|
||||
|
||||
if ((name_len == n) && (!strncmp(name, ext, n)))
|
||||
return TRUE;
|
||||
ext += (n + 1);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_gl_version_at_least_12 (void)
|
||||
{
|
||||
/* FIXME: This likely needs to live elsewhere in features or cogl */
|
||||
return
|
||||
(g_ascii_strtod ((const gchar*) glGetString (GL_VERSION), NULL) >= 1.2);
|
||||
|
||||
#if 0
|
||||
/* At least GL 1.2 is needed for CLAMP_TO_EDGE */
|
||||
/* FIXME: move to cogl... */
|
||||
if (!is_gl_version_at_least_12 ())
|
||||
{
|
||||
g_set_error (error, CLUTTER_INIT_ERROR,
|
||||
CLUTTER_INIT_ERROR_BACKEND,
|
||||
"Clutter needs at least version 1.2 of OpenGL");
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CoglFuncPtr
|
||||
cogl_get_proc_address (const gchar* name)
|
||||
{
|
||||
return NULL;
|
||||
/* FIXME */
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -527,3 +572,24 @@ cogl_setup_viewport (guint width,
|
||||
1.0f / width) );
|
||||
GE( glTranslatef (0.0f, -1.0 * height, 0.0f) );
|
||||
}
|
||||
|
||||
ClutterFeatureFlags
|
||||
cogl_get_features ()
|
||||
{
|
||||
ClutterFeatureFlags flags = 0;
|
||||
const gchar *gl_extensions;
|
||||
|
||||
flags = CLUTTER_FEATURE_TEXTURE_READ_PIXELS;
|
||||
|
||||
gl_extensions = (const gchar*) glGetString (GL_EXTENSIONS);
|
||||
|
||||
|
||||
if (check_gl_extension ("GL_ARB_texture_rectangle", gl_extensions) ||
|
||||
check_gl_extension ("GL_EXT_texture_rectangle", gl_extensions))
|
||||
{
|
||||
flags |= CLUTTER_FEATURE_TEXTURE_RECTANGLE;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
@ -515,5 +515,11 @@ cogl_setup_viewport (guint w,
|
||||
CFX_ONE / width));
|
||||
|
||||
GE( glTranslatex (0, -CFX_ONE * height, 0) );
|
||||
|
||||
}
|
||||
|
||||
ClutterFeatureFlags
|
||||
cogl_get_features ()
|
||||
{
|
||||
/* Suck */
|
||||
return 0;
|
||||
}
|
||||
|
@ -29,16 +29,31 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <GL/glx.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "clutter-backend-glx.h"
|
||||
#include "clutter-stage-glx.h"
|
||||
#include "clutter-glx.h"
|
||||
|
||||
#include "../clutter-event.h"
|
||||
#include "../clutter-main.h"
|
||||
#include "../clutter-debug.h"
|
||||
#include "../clutter-private.h"
|
||||
|
||||
#include "cogl.h"
|
||||
|
||||
G_DEFINE_TYPE (ClutterBackendGlx, clutter_backend_glx, CLUTTER_TYPE_BACKEND);
|
||||
|
||||
typedef CoglFuncPtr (*GLXGetProcAddressProc) (const guint8 *procName);
|
||||
|
||||
/* singleton object */
|
||||
static ClutterBackendGlx *backend_singleton = NULL;
|
||||
|
||||
@ -50,6 +65,56 @@ static gint clutter_screen = 0;
|
||||
static int TrappedErrorCode = 0;
|
||||
static int (* old_error_handler) (Display *, XErrorEvent *);
|
||||
|
||||
static gchar *clutter_vblank_name = 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
|
||||
|
||||
G_CONST_RETURN gchar*
|
||||
clutter_backend_glx_get_vblank_method (void)
|
||||
{
|
||||
return clutter_vblank_name;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_backend_glx_pre_parse (ClutterBackend *backend,
|
||||
GError **error)
|
||||
@ -66,6 +131,13 @@ clutter_backend_glx_pre_parse (ClutterBackend *backend,
|
||||
env_string = NULL;
|
||||
}
|
||||
|
||||
env_string = g_getenv ("CLUTTER_VBLANK");
|
||||
if (env_string)
|
||||
{
|
||||
clutter_vblank_name = g_strdup (env_string);
|
||||
env_string = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -120,13 +192,6 @@ clutter_backend_glx_post_parse (ClutterBackend *backend,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_gl_version_at_least_12 (void)
|
||||
{
|
||||
/* FIXME: This likely needs to live elsewhere in features or cogl */
|
||||
return
|
||||
(g_ascii_strtod ((const gchar*) glGetString (GL_VERSION), NULL) >= 1.2);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_backend_glx_init_stage (ClutterBackend *backend,
|
||||
@ -146,6 +211,7 @@ clutter_backend_glx_init_stage (ClutterBackend *backend,
|
||||
stage_glx->xdpy = backend_glx->xdpy;
|
||||
stage_glx->xwin_root = backend_glx->xwin_root;
|
||||
stage_glx->xscreen = backend_glx->xscreen_num;
|
||||
stage_glx->backend = backend_glx;
|
||||
|
||||
CLUTTER_NOTE (MISC, "GLX stage created (display:%p, screen:%d, root:%u)",
|
||||
stage_glx->xdpy,
|
||||
@ -166,16 +232,6 @@ clutter_backend_glx_init_stage (ClutterBackend *backend,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* At least GL 1.2 is needed for CLAMP_TO_EDGE */
|
||||
/* FIXME: move to cogl... */
|
||||
if (!is_gl_version_at_least_12 ())
|
||||
{
|
||||
g_set_error (error, CLUTTER_INIT_ERROR,
|
||||
CLUTTER_INIT_ERROR_BACKEND,
|
||||
"Clutter needs at least version 1.2 of OpenGL");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -209,6 +265,11 @@ static const GOptionEntry entries[] =
|
||||
G_OPTION_ARG_INT, &clutter_screen,
|
||||
"X screen to use", "SCREEN"
|
||||
},
|
||||
{ "vblank", 0,
|
||||
G_OPTION_FLAG_IN_MAIN,
|
||||
G_OPTION_ARG_STRING, &clutter_vblank_name,
|
||||
"VBlank method to be used (none, dri or glx)", "METHOD"
|
||||
},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -274,6 +335,115 @@ clutter_backend_glx_constructor (GType gtype,
|
||||
return g_object_ref (backend_singleton);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_vblank_env (const char *name)
|
||||
{
|
||||
if (clutter_vblank_name && !strcasecmp(clutter_vblank_name, name))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static CoglFuncPtr
|
||||
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 ClutterFeatureFlags
|
||||
clutter_backend_glx_get_features (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendGlx *backend_glx = CLUTTER_BACKEND_GLX (backend);
|
||||
const gchar *glx_extensions = NULL;
|
||||
ClutterFeatureFlags flags = 0;
|
||||
|
||||
/* FIXME: we really need to check if gl context is set */
|
||||
|
||||
glx_extensions
|
||||
= glXQueryExtensionsString (clutter_glx_get_default_display (),
|
||||
clutter_glx_get_default_screen ());
|
||||
|
||||
if (getenv("__GL_SYNC_TO_VBLANK") || check_vblank_env ("none"))
|
||||
{
|
||||
CLUTTER_NOTE (MISC, "vblank sync: disabled at user request");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!check_vblank_env ("dri") &&
|
||||
cogl_check_extension ("GLX_SGI_video_sync", glx_extensions))
|
||||
{
|
||||
backend_glx->get_video_sync =
|
||||
(GetVideoSyncProc) get_proc_address ("glXGetVideoSyncSGI");
|
||||
|
||||
backend_glx->wait_video_sync =
|
||||
(WaitVideoSyncProc) get_proc_address ("glXWaitVideoSyncSGI");
|
||||
|
||||
if ((backend_glx->get_video_sync != NULL) &&
|
||||
(backend_glx->wait_video_sync != NULL))
|
||||
{
|
||||
CLUTTER_NOTE (MISC, "vblank sync: using glx");
|
||||
|
||||
backend_glx->vblank_type = CLUTTER_VBLANK_GLX;
|
||||
flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
|
||||
}
|
||||
}
|
||||
#ifdef __linux__
|
||||
if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
|
||||
{
|
||||
backend_glx->dri_fd = open("/dev/dri/card0", O_RDWR);
|
||||
if (backend_glx->dri_fd >= 0)
|
||||
{
|
||||
CLUTTER_NOTE (MISC, "vblank sync: using dri");
|
||||
|
||||
backend_glx->vblank_type = CLUTTER_VBLANK_DRI;
|
||||
flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
|
||||
{
|
||||
CLUTTER_NOTE (MISC,
|
||||
"vblank sync: no use-able mechanism found");
|
||||
}
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (MISC, "backend features checked");
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_glx_class_init (ClutterBackendGlxClass *klass)
|
||||
{
|
||||
@ -290,6 +460,7 @@ clutter_backend_glx_class_init (ClutterBackendGlxClass *klass)
|
||||
backend_class->init_events = clutter_backend_glx_init_events;
|
||||
backend_class->get_stage = clutter_backend_glx_get_stage;
|
||||
backend_class->add_options = clutter_backend_glx_add_options;
|
||||
backend_class->get_features = clutter_backend_glx_get_features;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -317,6 +488,38 @@ error_handler(Display *xdpy,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
clutter_backend_glx_wait_for_vblank (ClutterBackendGlx *backend_glx)
|
||||
{
|
||||
switch (backend_glx->vblank_type)
|
||||
{
|
||||
case CLUTTER_VBLANK_GLX:
|
||||
{
|
||||
unsigned int retraceCount;
|
||||
backend_glx->get_video_sync (&retraceCount);
|
||||
backend_glx->wait_video_sync (2,
|
||||
(retraceCount + 1) % 2,
|
||||
&retraceCount);
|
||||
}
|
||||
break;
|
||||
case CLUTTER_VBLANK_DRI:
|
||||
#ifdef __linux__
|
||||
{
|
||||
drm_wait_vblank_t blank;
|
||||
blank.request.type = DRM_VBLANK_RELATIVE;
|
||||
blank.request.sequence = 1;
|
||||
blank.request.signal = 0;
|
||||
drm_wait_vblank (backend_glx->dri_fd, &blank);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case CLUTTER_VBLANK_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* clutter_glx_trap_x_errors:
|
||||
*
|
||||
@ -378,16 +581,16 @@ clutter_glx_get_default_display (void)
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
Screen *
|
||||
int
|
||||
clutter_glx_get_default_screen (void)
|
||||
{
|
||||
if (!backend_singleton)
|
||||
{
|
||||
g_critical ("GLX backend has not been initialised");
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return backend_singleton->xscreen;
|
||||
return backend_singleton->xscreen_num;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -42,6 +42,19 @@ G_BEGIN_DECLS
|
||||
typedef struct _ClutterBackendGlx ClutterBackendGlx;
|
||||
typedef struct _ClutterBackendGlxClass ClutterBackendGlxClass;
|
||||
|
||||
typedef enum ClutterGLXVBlankType
|
||||
{
|
||||
CLUTTER_VBLANK_NONE = 0,
|
||||
CLUTTER_VBLANK_GLX,
|
||||
CLUTTER_VBLANK_DRI
|
||||
|
||||
} ClutterGLXVBlankType;
|
||||
|
||||
typedef int (*GetVideoSyncProc) (unsigned int *count);
|
||||
typedef int (*WaitVideoSyncProc) (int divisor,
|
||||
int remainder,
|
||||
unsigned int *count);
|
||||
|
||||
struct _ClutterBackendGlx
|
||||
{
|
||||
ClutterBackend parent_instance;
|
||||
@ -57,6 +70,12 @@ struct _ClutterBackendGlx
|
||||
|
||||
/* event source */
|
||||
GSource *event_source;
|
||||
|
||||
/* Vblank stuff */
|
||||
GetVideoSyncProc get_video_sync;
|
||||
WaitVideoSyncProc wait_video_sync;
|
||||
gint dri_fd;
|
||||
ClutterGLXVBlankType vblank_type;
|
||||
};
|
||||
|
||||
struct _ClutterBackendGlxClass
|
||||
@ -67,6 +86,8 @@ struct _ClutterBackendGlxClass
|
||||
void _clutter_backend_glx_events_init (ClutterBackend *backend);
|
||||
void _clutter_backend_glx_events_uninit (ClutterBackend *backend);
|
||||
|
||||
void clutter_backend_glx_wait_for_vblank (ClutterBackendGlx *backend_glx);
|
||||
|
||||
GType clutter_backend_glx_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -37,7 +37,7 @@ void clutter_glx_trap_x_errors (void);
|
||||
gint clutter_glx_untrap_x_errors (void);
|
||||
|
||||
Display *clutter_glx_get_default_display (void);
|
||||
Screen * clutter_glx_get_default_screen (void);
|
||||
int clutter_glx_get_default_screen (void);
|
||||
Window clutter_glx_get_root_window (void);
|
||||
|
||||
Window clutter_glx_get_stage_window (ClutterStage *stage);
|
||||
@ -46,6 +46,7 @@ XVisualInfo *clutter_glx_get_stage_visual (ClutterStage *stage);
|
||||
gboolean clutter_glx_set_stage_foreign (ClutterStage *stage,
|
||||
Window xwindow);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_GLX_H__ */
|
||||
|
@ -331,7 +331,7 @@ clutter_stage_glx_paint (ClutterActor *self)
|
||||
*/
|
||||
if (stage_glx->xwin)
|
||||
{
|
||||
clutter_feature_wait_for_vblank ();
|
||||
clutter_backend_glx_wait_for_vblank (stage_glx->backend);
|
||||
glXSwapBuffers (stage_glx->xdpy, stage_glx->xwin);
|
||||
}
|
||||
else
|
||||
@ -373,7 +373,6 @@ clutter_stage_glx_request_coords (ClutterActor *self,
|
||||
ClutterStageGlx *stage_glx = CLUTTER_STAGE_GLX (self);
|
||||
gint new_width, new_height;
|
||||
|
||||
/* FIXME: some how have X configure_notfiys call this ? */
|
||||
new_width = ABS (box->x2 - box->x1);
|
||||
new_height = ABS (box->y2 - box->y1);
|
||||
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include <GL/glx.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
#include "clutter-backend-glx.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_STAGE_GLX (clutter_stage_glx_get_type ())
|
||||
@ -60,6 +62,9 @@ struct _ClutterStageGlx
|
||||
GLXContext gl_context;
|
||||
|
||||
guint is_foreign_xwin : 1;
|
||||
|
||||
ClutterBackendGlx *backend;
|
||||
|
||||
};
|
||||
|
||||
struct _ClutterStageGlxClass
|
||||
|
Loading…
Reference in New Issue
Block a user