[clutter: 15/19] Moves all GLX code down from Clutter to Cogl
- From: Robert Bragg <rbragg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [clutter: 15/19] Moves all GLX code down from Clutter to Cogl
- Date: Mon, 11 Apr 2011 17:44:57 +0000 (UTC)
commit d6f110a4d26eb5e49e762bcbf51d36af894adcc9
Author: Robert Bragg <robert linux intel com>
Date: Fri Nov 5 12:28:33 2010 +0000
Moves all GLX code down from Clutter to Cogl
This migrates all the GLX window system code down from the Clutter
backend code into a Cogl winsys. Moving OpenGL window system binding
code down from Clutter into Cogl is the biggest blocker to having Cogl
become a standalone 3D graphics library, so this is an important step in
that direction.
clutter/clutter-backend-private.h | 5 +
clutter/clutter-backend.c | 1 +
clutter/clutter-stage.c | 12 -
clutter/cogl/cogl/Makefile.am | 44 +-
clutter/cogl/cogl/cogl-clutter.c | 14 +
clutter/cogl/cogl/cogl-clutter.h | 10 +
clutter/cogl/cogl/cogl-context-private.h | 34 +-
clutter/cogl/cogl/cogl-context.c | 104 +-
clutter/cogl/cogl/cogl-context.h | 7 +-
clutter/cogl/cogl/cogl-debug.h | 1 +
clutter/cogl/cogl/cogl-display-glx-private.h | 57 +
clutter/cogl/cogl/cogl-display-xlib-private.h | 35 +
clutter/cogl/cogl/cogl-display.c | 5 +
clutter/cogl/cogl/cogl-display.h | 12 +-
clutter/cogl/cogl/cogl-feature-private.c | 5 +-
clutter/cogl/cogl/cogl-feature-private.h | 20 +-
clutter/cogl/cogl/cogl-framebuffer-private.h | 39 +-
clutter/cogl/cogl/cogl-framebuffer.c | 235 ++++-
clutter/cogl/cogl/cogl-framebuffer.h | 109 ++
clutter/cogl/cogl/cogl-internal.h | 102 +--
clutter/cogl/cogl/cogl-journal-private.h | 1 +
clutter/cogl/cogl/cogl-private.h | 6 +
clutter/cogl/cogl/cogl-renderer-glx-private.h | 61 +
clutter/cogl/cogl/cogl-renderer-x11-private.h | 32 +
...-winsys-xlib.h => cogl-renderer-xlib-private.h} | 50 +-
clutter/cogl/cogl/cogl-renderer-xlib.c | 288 +++++
clutter/cogl/cogl/cogl-renderer.c | 23 +
clutter/cogl/cogl/cogl-types.h | 87 ++-
clutter/cogl/cogl/cogl-util.c | 1 -
clutter/cogl/cogl/cogl-xlib-private.h | 82 ++
.../{winsys/cogl-winsys-xlib.c => cogl-xlib.c} | 104 ++-
clutter/cogl/cogl/cogl-xlib.h | 84 ++
clutter/cogl/cogl/cogl.c | 10 +-
clutter/cogl/cogl/cogl.h | 52 +-
.../cogl/cogl/driver/gl/cogl-context-driver-gl.h | 53 +
clutter/cogl/cogl/driver/gl/cogl-gl.c | 40 +-
.../cogl/driver/gles/cogl-context-driver-gles.h | 52 +
clutter/cogl/cogl/driver/gles/cogl-gles.c | 46 +-
clutter/cogl/cogl/winsys/cogl-context-winsys.c | 152 ---
clutter/cogl/cogl/winsys/cogl-context-winsys.h | 118 --
clutter/cogl/cogl/winsys/cogl-texture-pixmap-x11.c | 111 +-
.../cogl/winsys/cogl-winsys-feature-functions.h | 45 -
.../winsys/cogl-winsys-glx-feature-functions.h | 105 ++
clutter/cogl/cogl/winsys/cogl-winsys-glx.c | 1262 +++++++++++++++++++-
clutter/cogl/cogl/winsys/cogl-winsys-private.h | 88 ++
clutter/cogl/cogl/winsys/cogl-winsys-stub.c | 114 ++
clutter/cogl/cogl/winsys/cogl-winsys.c | 36 +
clutter/glx/clutter-backend-glx.c | 654 ++---------
clutter/glx/clutter-backend-glx.h | 49 +-
clutter/glx/clutter-stage-glx.c | 385 ++-----
clutter/glx/clutter-stage-glx.h | 5 +-
clutter/x11/clutter-backend-x11.c | 4 +-
clutter/x11/clutter-stage-x11.c | 14 +-
configure.ac | 2 +
54 files changed, 3436 insertions(+), 1631 deletions(-)
---
diff --git a/clutter/clutter-backend-private.h b/clutter/clutter-backend-private.h
index cc88903..3374bbc 100644
--- a/clutter/clutter-backend-private.h
+++ b/clutter/clutter-backend-private.h
@@ -37,6 +37,11 @@ struct _ClutterBackend
{
/*< private >*/
GObject parent_instance;
+
+ CoglRenderer *cogl_renderer;
+ CoglDisplay *cogl_display;
+ CoglContext *cogl_context;
+
ClutterBackendPrivate *priv;
};
diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c
index 93328be..6763247 100644
--- a/clutter/clutter-backend.c
+++ b/clutter/clutter-backend.c
@@ -53,6 +53,7 @@
#include "clutter-version.h"
#include <cogl/cogl.h>
+#include <cogl/cogl-internal.h>
G_DEFINE_ABSTRACT_TYPE (ClutterBackend, clutter_backend, G_TYPE_OBJECT);
diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c
index 723b3a7..43ffd27 100644
--- a/clutter/clutter-stage.c
+++ b/clutter/clutter-stage.c
@@ -672,7 +672,6 @@ clutter_stage_realize (ClutterActor *self)
if (is_realized)
{
ClutterBackend *backend = clutter_get_default_backend ();
- GError *error = NULL;
/* We want to select the context without calling
clutter_backend_ensure_context so that it doesn't call any
@@ -680,17 +679,6 @@ clutter_stage_realize (ClutterActor *self)
before we get a chance to check whether the GL version is
valid */
_clutter_backend_ensure_context_internal (backend, CLUTTER_STAGE (self));
-
- /* Make sure Cogl can support the driver */
- if (!_cogl_check_driver_valid (&error))
- {
- g_critical ("The GL driver is not supported: %s",
- error->message);
- g_clear_error (&error);
- CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
- }
- else
- CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
}
else
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
diff --git a/clutter/cogl/cogl/Makefile.am b/clutter/cogl/cogl/Makefile.am
index 80b5ae5..c4d2f50 100644
--- a/clutter/cogl/cogl/Makefile.am
+++ b/clutter/cogl/cogl/Makefile.am
@@ -78,6 +78,7 @@ cogl_public_h = \
$(srcdir)/cogl-attribute.h \
$(srcdir)/cogl-primitive.h \
$(srcdir)/cogl-clip-state.h \
+ $(srcdir)/cogl-framebuffer.h \
$(srcdir)/cogl-clutter.h \
$(srcdir)/cogl.h \
$(NULL)
@@ -114,10 +115,8 @@ endif # COGL_DRIVER_GLES
# winsys sources, common to all backends
cogl_winsys_common_sources = \
- $(srcdir)/winsys/cogl-winsys-private.h \
- $(srcdir)/winsys/cogl-context-winsys.h \
- $(srcdir)/winsys/cogl-context-winsys.c \
- $(srcdir)/winsys/cogl-winsys-feature-functions.h \
+ $(srcdir)/winsys/cogl-winsys-private.h \
+ $(srcdir)/winsys/cogl-winsys.c \
$(NULL)
# tesselator sources
@@ -295,29 +294,39 @@ cogl_sources_c = \
if SUPPORT_XLIB
cogl_experimental_h += \
- $(srcdir)/winsys/cogl-texture-pixmap-x11.h
+ $(srcdir)/winsys/cogl-texture-pixmap-x11.h \
+ $(srcdir)/cogl-xlib.h
cogl_sources_c += \
- $(srcdir)/winsys/cogl-winsys-xlib.h \
- $(srcdir)/winsys/cogl-winsys-xlib.c \
- $(srcdir)/winsys/cogl-texture-pixmap-x11.c \
- $(srcdir)/winsys/cogl-texture-pixmap-x11-private.h
+ $(srcdir)/cogl-renderer-x11-private.h \
+ $(srcdir)/cogl-renderer-xlib-private.h \
+ $(srcdir)/cogl-renderer-xlib.c \
+ $(srcdir)/cogl-display-xlib-private.h \
+ $(srcdir)/cogl-xlib.c \
+ $(srcdir)/winsys/cogl-texture-pixmap-x11.c \
+ $(srcdir)/winsys/cogl-texture-pixmap-x11-private.h
endif
if SUPPORT_GLX
cogl_sources_c += \
- $(srcdir)/winsys/cogl-winsys-glx.c
+ $(srcdir)/cogl-renderer-glx-private.h \
+ $(srcdir)/cogl-display-glx-private.h \
+ $(srcdir)/winsys/cogl-winsys-glx-feature-functions.h \
+ $(srcdir)/winsys/cogl-winsys-glx.c
endif
if SUPPORT_EGL_PLATFORM_POWERVR_X11
cogl_sources_c += \
- $(srcdir)/winsys/cogl-winsys-egl.c
+ $(srcdir)/winsys/cogl-winsys-egl.c \
+ $(srcdir)/winsys/cogl-winsys-stub.c
endif
if SUPPORT_EGL_PLATFORM_POWERVR_NULL
cogl_sources_c += \
- $(srcdir)/winsys/cogl-winsys-egl.c
+ $(srcdir)/winsys/cogl-winsys-egl.c \
+ $(srcdir)/winsys/cogl-winsys-stub.c
endif
if SUPPORT_EGL_PLATFORM_POWERVR_GDL
cogl_sources_c += \
- $(srcdir)/winsys/cogl-winsys-egl.c
+ $(srcdir)/winsys/cogl-winsys-egl.c \
+ $(srcdir)/winsys/cogl-winsys-stub.c
endif
if SUPPORT_EGL_PLATFORM_FRUITY
cogl_sources_c += \
@@ -325,15 +334,18 @@ cogl_sources_c += \
endif
if SUPPORT_EGL_PLATFORM_DRM_SURFACELESS
cogl_sources_c += \
- $(srcdir)/winsys/cogl-winsys-egl.c
+ $(srcdir)/winsys/cogl-winsys-egl.c \
+ $(srcdir)/winsys/cogl-winsys-stub.c
endif
if SUPPORT_WIN32
cogl_sources_c += \
- $(srcdir)/winsys/cogl-winsys-win32.c
+ $(srcdir)/winsys/cogl-winsys-win32.c \
+ $(srcdir)/winsys/cogl-winsys-stub.c
endif
if SUPPORT_OSX
cogl_sources_c += \
- $(srcdir)/winsys/cogl-winsys-osx.c
+ $(srcdir)/winsys/cogl-winsys-osx.c \
+ $(srcdir)/winsys/cogl-winsys-stub.c
endif
EXTRA_DIST += stb_image.c
diff --git a/clutter/cogl/cogl/cogl-clutter.c b/clutter/cogl/cogl/cogl-clutter.c
index 07f827a..facdeb3 100644
--- a/clutter/cogl/cogl/cogl-clutter.c
+++ b/clutter/cogl/cogl/cogl-clutter.c
@@ -43,6 +43,12 @@ cogl_clutter_check_extension (const char *name, const char *ext)
return _cogl_check_extension (name, ext);
}
+gboolean
+cogl_clutter_winsys_has_feature (CoglWinsysFeature feature)
+{
+ return _cogl_winsys_has_feature (feature);
+}
+
void
cogl_onscreen_clutter_backend_set_size (int width, int height)
{
@@ -57,3 +63,11 @@ cogl_onscreen_clutter_backend_set_size (int width, int height)
_cogl_framebuffer_winsys_update_size (framebuffer, width, height);
}
+
+#ifdef COGL_HAS_XLIB_SUPPORT
+XVisualInfo *
+cogl_clutter_winsys_xlib_get_visual_info (void)
+{
+ return _cogl_winsys_xlib_get_visual_info ();
+}
+#endif
diff --git a/clutter/cogl/cogl/cogl-clutter.h b/clutter/cogl/cogl/cogl-clutter.h
index 023d14f..a121671 100644
--- a/clutter/cogl/cogl/cogl-clutter.h
+++ b/clutter/cogl/cogl/cogl-clutter.h
@@ -38,10 +38,20 @@ G_BEGIN_DECLS
gboolean
cogl_clutter_check_extension (const char *name, const char *ext);
+#define cogl_clutter_winsys_has_feature cogl_clutter_winsys_has_feature_CLUTTER
+gboolean
+cogl_clutter_winsys_has_feature (CoglWinsysFeature feature);
+
#define cogl_onscreen_clutter_backend_set_size cogl_onscreen_clutter_backend_set_size_CLUTTER
void
cogl_onscreen_clutter_backend_set_size (int width, int height);
+#ifdef COGL_HAS_XLIB
+#define cogl_clutter_winsys_xlib_get_visual_info cogl_clutter_winsys_xlib_get_visual_info_CLUTTER
+XVisualInfo *
+cogl_clutter_winsys_xlib_get_visual_info (void);
+#endif
+
G_END_DECLS
#endif /* __COGL_CLUTTER_H__ */
diff --git a/clutter/cogl/cogl/cogl-context-private.h b/clutter/cogl/cogl/cogl-context-private.h
index 83a9ebd..ba54de7 100644
--- a/clutter/cogl/cogl/cogl-context-private.h
+++ b/clutter/cogl/cogl/cogl-context-private.h
@@ -26,6 +26,11 @@
#include "cogl-internal.h"
#include "cogl-context.h"
+#include "cogl-winsys-private.h"
+
+#ifdef COGL_HAS_XLIB_SUPPORT
+#include "cogl-xlib-private.h"
+#endif
#if HAVE_COGL_GL
#include "cogl-context-driver-gl.h"
@@ -35,7 +40,7 @@
#include "cogl-context-driver-gles.h"
#endif
-#include "cogl-context-winsys.h"
+#include "cogl-display-private.h"
#include "cogl-primitives.h"
#include "cogl-clip-stack.h"
#include "cogl-matrix-stack.h"
@@ -55,9 +60,10 @@ struct _CoglContext
{
CoglObject _parent;
+ CoglDisplay *display;
+
/* Features cache */
- CoglFeatureFlags feature_flags;
- CoglFeatureFlagsPrivate feature_flags_private;
+ CoglFeatureFlags feature_flags;
CoglHandle default_pipeline;
CoglHandle default_layer_0;
@@ -70,8 +76,6 @@ struct _CoglContext
gboolean enable_backface_culling;
CoglFrontWinding flushed_front_winding;
- gboolean indirect;
-
/* A few handy matrix constants */
CoglMatrix identity_matrix;
CoglMatrix y_flip_matrix;
@@ -237,8 +241,26 @@ struct _CoglContext
GByteArray *buffer_map_fallback_array;
gboolean buffer_map_fallback_in_use;
+ CoglWinsysRectangleState rectangle_state;
+
+ /* FIXME: remove these when we remove the last xlib based clutter
+ * backend. they should be tracked as part of the renderer but e.g.
+ * the eglx backend doesn't yet have a corresponding Cogl winsys
+ * and so we wont have a renderer in that case. */
+#ifdef COGL_HAS_XLIB_SUPPORT
+ int damage_base;
+ /* List of callback functions that will be given every Xlib event */
+ GSList *event_filters;
+ /* Current top of the XError trap state stack. The actual memory for
+ these is expected to be allocated on the stack by the caller */
+ CoglXlibTrapState *trap_state;
+#endif
+
CoglContextDriver drv;
- CoglContextWinsys winsys;
+
+ CoglBitmask winsys_features;
+ void *winsys;
+ gboolean stub_winsys;
};
CoglContext *
diff --git a/clutter/cogl/cogl/cogl-context.c b/clutter/cogl/cogl/cogl-context.c
index ed950c3..a543baa 100644
--- a/clutter/cogl/cogl/cogl-context.c
+++ b/clutter/cogl/cogl/cogl-context.c
@@ -28,6 +28,8 @@
#include "cogl.h"
#include "cogl-object.h"
#include "cogl-internal.h"
+#include "cogl-private.h"
+#include "cogl-winsys-private.h"
#include "cogl-profile.h"
#include "cogl-util.h"
#include "cogl-context-private.h"
@@ -56,13 +58,8 @@ COGL_OBJECT_DEFINE (Context, context);
extern void
_cogl_create_context_driver (CoglContext *context);
-extern void
-_cogl_create_context_winsys (CoglContext *context);
-extern void
-_cogl_destroy_context_winsys (CoglContext *context);
static CoglContext *_context = NULL;
-static gboolean gl_is_indirect = FALSE;
static void
_cogl_init_feature_overrides (CoglContext *ctx)
@@ -102,15 +99,8 @@ cogl_context_new (CoglDisplay *display,
CoglContext *context;
GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
unsigned long enable_flags = 0;
- CoglHandle window_buffer;
int i;
- /* A NULL display means "please just do something sensible"
- * and since we haven't implemented anything for CoglDisplay
- * yet that's the only kind of context construction we allow
- * for now. */
- g_return_val_if_fail (display == NULL, NULL);
-
#ifdef CLUTTER_ENABLE_PROFILE
/* We need to be absolutely sure that uprof has been initialized
* before calling _cogl_uprof_init. uprof_init (NULL, NULL)
@@ -135,18 +125,21 @@ cogl_context_new (CoglDisplay *display,
* context which it can access via _COGL_GET_CONTEXT() including
* code used to construct a CoglContext. Until all of that code
* has been updated to take an explicit context argument we have
- * to immediatly make our pointer the default context.
+ * to immediately make our pointer the default context.
*/
_context = context;
/* Init default values */
- _context->feature_flags = 0;
- _context->feature_flags_private = 0;
+ context->feature_flags = 0;
context->texture_types = NULL;
context->buffer_types = NULL;
- if (!display)
+ context->rectangle_state = COGL_WINSYS_RECTANGLE_STATE_UNKNOWN;
+
+ _cogl_bitmask_init (&context->winsys_features);
+
+ if (!display)
display = cogl_display_new (NULL, NULL);
else
cogl_object_ref (display);
@@ -158,12 +151,33 @@ cogl_context_new (CoglDisplay *display,
return NULL;
}
+ context->display = display;
+
+#ifdef COGL_HAS_FULL_WINSYS
+ if (!_cogl_winsys_context_init (context, error))
+ {
+ cogl_object_unref (display);
+ g_free (context);
+ return NULL;
+ }
+#else
+ /* In this case Clutter is still responsible for creating a GL
+ * context. */
+ context->stub_winsys = TRUE;
+ if (!_cogl_gl_check_version (error))
+ {
+ g_free (context);
+ return NULL;
+ }
+ _cogl_gl_update_features (context);
+#ifdef COGL_HAS_XLIB_SUPPORT
+ _cogl_xlib_query_damage_extension ();
+#endif
+#endif
+
/* Initialise the driver specific state */
- _cogl_gl_context_init (context);
_cogl_init_feature_overrides (context);
- _cogl_create_context_winsys (context);
-
_cogl_pipeline_init_default_pipeline ();
_cogl_pipeline_init_default_layers ();
_cogl_pipeline_init_state_hash_functions ();
@@ -174,8 +188,6 @@ cogl_context_new (CoglDisplay *display,
context->enable_backface_culling = FALSE;
context->flushed_front_winding = COGL_FRONT_WINDING_COUNTER_CLOCKWISE;
- context->indirect = gl_is_indirect;
-
cogl_matrix_init_identity (&context->identity_matrix);
cogl_matrix_init_identity (&context->y_flip_matrix);
cogl_matrix_scale (&context->y_flip_matrix, 1, -1, 1);
@@ -257,13 +269,18 @@ cogl_context_new (CoglDisplay *display,
context->framebuffer_stack = _cogl_create_framebuffer_stack ();
- _context->current_clip_stack_valid = FALSE;
+ /* XXX: In this case the Clutter backend is still responsible for
+ * the OpenGL binding API and for creating onscreen framebuffers and
+ * so we have to add a dummy framebuffer to represent the backend
+ * owned window... */
+ if (context->stub_winsys)
+ {
+ CoglOnscreen *window = _cogl_onscreen_new ();
+ cogl_set_framebuffer (COGL_FRAMEBUFFER (window));
+ cogl_object_unref (COGL_FRAMEBUFFER (window));
+ }
- window_buffer = _cogl_onscreen_new ();
- cogl_set_framebuffer (window_buffer);
- /* XXX: the deprecated _cogl_set_draw_buffer API expects to
- * find the window buffer here... */
- context->window_buffer = window_buffer;
+ _context->current_clip_stack_valid = FALSE;
context->dirty_bound_framebuffer = TRUE;
context->dirty_gl_viewport = TRUE;
@@ -347,7 +364,7 @@ cogl_context_new (CoglDisplay *display,
static void
_cogl_context_free (CoglContext *context)
{
- _cogl_destroy_context_winsys (context);
+ _cogl_winsys_context_deinit (context);
_cogl_destroy_texture_units ();
@@ -424,6 +441,8 @@ _cogl_context_free (CoglContext *context)
g_byte_array_free (context->buffer_map_fallback_array, TRUE);
+ _cogl_bitmask_destroy (&context->winsys_features);
+
cogl_object_unref (context->display);
g_free (context);
@@ -448,31 +467,12 @@ _cogl_context_get_default (void)
return _context;
}
-/**
- * _cogl_set_indirect_context:
- * @indirect: TRUE if GL context is indirect
- *
- * Advises COGL that the GL context is indirect (commands are sent
- * over a socket). COGL uses this information to try to avoid
- * round-trips in its use of GL, for example.
- *
- * This function cannot be called "on the fly," only before COGL
- * initializes.
- */
void
-_cogl_set_indirect_context (gboolean indirect)
+cogl_set_default_context (CoglContext *context)
{
- /* we get called multiple times if someone creates
- * more than the default stage
- */
- if (_context != NULL)
- {
- if (indirect != _context->indirect)
- g_warning ("Right now all stages will be treated as "
- "either direct or indirect, ignoring attempt "
- "to change to indirect=%d", indirect);
- return;
- }
+ cogl_object_ref (context);
- gl_is_indirect = indirect;
+ if (_context)
+ cogl_object_unref (_context);
+ _context = context;
}
diff --git a/clutter/cogl/cogl/cogl-context.h b/clutter/cogl/cogl/cogl-context.h
index d8cab2a..9394fbf 100644
--- a/clutter/cogl/cogl/cogl-context.h
+++ b/clutter/cogl/cogl/cogl-context.h
@@ -54,7 +54,12 @@ typedef struct _CoglContext CoglContext;
#define cogl_context_new cogl_context_new_EXP
CoglContext *
-cogl_context_new (CoglDisplay *display);
+cogl_context_new (CoglDisplay *display,
+ GError **error);
+
+#define cogl_set_default_context cogl_set_default_context_EXP
+void
+cogl_set_default_context (CoglContext *context);
G_END_DECLS
diff --git a/clutter/cogl/cogl/cogl-debug.h b/clutter/cogl/cogl/cogl-debug.h
index 0cd039f..87f280d 100644
--- a/clutter/cogl/cogl/cogl-debug.h
+++ b/clutter/cogl/cogl/cogl-debug.h
@@ -63,6 +63,7 @@ typedef enum {
COGL_DEBUG_DISABLE_PROGRAM_CACHES,
COGL_DEBUG_DISABLE_FAST_READ_PIXEL,
COGL_DEBUG_CLIPPING,
+ COGL_DEBUG_WINSYS,
COGL_DEBUG_N_FLAGS
} CoglDebugFlags;
diff --git a/clutter/cogl/cogl/cogl-display-glx-private.h b/clutter/cogl/cogl/cogl-display-glx-private.h
new file mode 100644
index 0000000..279b653
--- /dev/null
+++ b/clutter/cogl/cogl/cogl-display-glx-private.h
@@ -0,0 +1,57 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifndef __COGL_DISPLAY_GLX_PRIVATE_H
+#define __COGL_DISPLAY_GLX_PRIVATE_H
+
+#include "cogl-object-private.h"
+#include "cogl-display-xlib-private.h"
+
+typedef struct _CoglGLXCachedConfig
+{
+ /* This will be -1 if there is no cached config in this slot */
+ int depth;
+ gboolean found;
+ GLXFBConfig fb_config;
+ gboolean can_mipmap;
+} CoglGLXCachedConfig;
+
+#define COGL_GLX_N_CACHED_CONFIGS 3
+
+typedef struct _CoglDisplayGLX
+{
+ CoglDisplayXlib _parent;
+
+ CoglGLXCachedConfig glx_cached_configs[COGL_GLX_N_CACHED_CONFIGS];
+
+ gboolean found_fbconfig;
+ gboolean fbconfig_has_rgba_visual;
+ GLXFBConfig fbconfig;
+
+ /* Single context for all wins */
+ GLXContext glx_context;
+ GLXWindow dummy_glxwin;
+} CoglDisplayGLX;
+
+#endif /* __COGL_DISPLAY_GLX_PRIVATE_H */
diff --git a/clutter/cogl/cogl/cogl-display-xlib-private.h b/clutter/cogl/cogl/cogl-display-xlib-private.h
new file mode 100644
index 0000000..6e28388
--- /dev/null
+++ b/clutter/cogl/cogl/cogl-display-xlib-private.h
@@ -0,0 +1,35 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifndef __COGL_DISPLAY_XLIB_PRIVATE_H
+#define __COGL_DISPLAY_XLIB_PRIVATE_H
+
+#include <X11/Xlib.h>
+
+typedef struct _CoglDisplayXlib
+{
+ Window dummy_xwin;
+} CoglDisplayXlib;
+
+#endif /* __COGL_DISPLAY_XLIB_PRIVATE_H */
diff --git a/clutter/cogl/cogl/cogl-display.c b/clutter/cogl/cogl/cogl-display.c
index ebaaafa..a09de18 100644
--- a/clutter/cogl/cogl/cogl-display.c
+++ b/clutter/cogl/cogl/cogl-display.c
@@ -100,6 +100,11 @@ cogl_display_setup (CoglDisplay *display,
if (display->setup)
return TRUE;
+#ifdef COGL_HAS_FULL_WINSYS
+ if (!_cogl_winsys_display_setup (display, error))
+ return FALSE;
+#endif
+
display->setup = TRUE;
return TRUE;
diff --git a/clutter/cogl/cogl/cogl-display.h b/clutter/cogl/cogl/cogl-display.h
index 5dec9db..00ce4fb 100644
--- a/clutter/cogl/cogl/cogl-display.h
+++ b/clutter/cogl/cogl/cogl-display.h
@@ -31,6 +31,9 @@
#ifndef __COGL_DISPLAY_H__
#define __COGL_DISPLAY_H__
+#include <cogl/cogl-renderer.h>
+#include <cogl/cogl-onscreen-template.h>
+
G_BEGIN_DECLS
/**
@@ -69,8 +72,15 @@ typedef struct _CoglDisplay CoglDisplay;
#define COGL_DISPLAY(OBJECT) ((CoglDisplay *)OBJECT)
+#define cogl_display_new cogl_display_new_EXP
CoglDisplay *
-cogl_display_new (CoglDisplay *display);
+cogl_display_new (CoglRenderer *renderer,
+ CoglOnscreenTemplate *onscreen_template);
+
+#define cogl_display_setup cogl_display_setup_EXP
+gboolean
+cogl_display_setup (CoglDisplay *display,
+ GError **error);
G_END_DECLS
diff --git a/clutter/cogl/cogl/cogl-feature-private.c b/clutter/cogl/cogl/cogl-feature-private.c
index deff9fc..d3904b4 100644
--- a/clutter/cogl/cogl/cogl-feature-private.c
+++ b/clutter/cogl/cogl/cogl-feature-private.c
@@ -37,7 +37,8 @@ _cogl_feature_check (const char *driver_prefix,
const CoglFeatureData *data,
unsigned int gl_major,
unsigned int gl_minor,
- const char *extensions_string)
+ const char *extensions_string,
+ void *function_table)
{
const char *suffix = NULL;
@@ -123,7 +124,7 @@ _cogl_feature_check (const char *driver_prefix,
break;
/* Set the function pointer in the context */
- *(void **) ((guint8 *) ctx +
+ *(void **) ((guint8 *) function_table +
data->functions[func_num].pointer_offset) = func;
}
diff --git a/clutter/cogl/cogl/cogl-feature-private.h b/clutter/cogl/cogl/cogl-feature-private.h
index 133d588..5d0101e 100644
--- a/clutter/cogl/cogl/cogl-feature-private.h
+++ b/clutter/cogl/cogl/cogl-feature-private.h
@@ -26,6 +26,8 @@
#include <glib.h>
+#include "cogl-internal.h"
+
#define COGL_CHECK_GL_VERSION(driver_major, driver_minor, \
target_major, target_minor) \
((driver_major) > (target_major) || \
@@ -59,17 +61,21 @@ struct _CoglFeatureData
const char *extension_names;
/* A set of feature flags to enable if the extension is available */
CoglFeatureFlags feature_flags;
- /* A set of private feature flags to enable if the extension is available
- * and for internal use only */
- CoglFeatureFlagsPrivate feature_flags_private;
+ /* FIXME: This is now unused */
+ int padding_feature_flags_private;
+ /* An optional corresponding winsys feature. */
+ CoglWinsysFeature winsys_feature;
/* A list of functions required for this feature. Terminated with a
NULL name */
const CoglFeatureFunction *functions;
};
-gboolean _cogl_feature_check (const char *driver_prefix,
- const CoglFeatureData *data,
- unsigned int gl_major, unsigned int gl_minor,
- const char *extensions_string);
+gboolean
+_cogl_feature_check (const char *driver_prefix,
+ const CoglFeatureData *data,
+ unsigned int gl_major,
+ unsigned int gl_minor,
+ const char *extensions_string,
+ void *function_table);
#endif /* __COGL_FEATURE_PRIVATE_H */
diff --git a/clutter/cogl/cogl/cogl-framebuffer-private.h b/clutter/cogl/cogl/cogl-framebuffer-private.h
index afc8fe1..ee6f3ff 100644
--- a/clutter/cogl/cogl/cogl-framebuffer-private.h
+++ b/clutter/cogl/cogl/cogl-framebuffer-private.h
@@ -24,11 +24,20 @@
#ifndef __COGL_FRAMEBUFFER_PRIVATE_H
#define __COGL_FRAMEBUFFER_PRIVATE_H
-#include "cogl-handle.h"
+#include "cogl-object-private.h"
#include "cogl-matrix-stack.h"
#include "cogl-clip-state-private.h"
#include "cogl-journal-private.h"
+#ifdef COGL_HAS_XLIB_SUPPORT
+#include <X11/Xlib.h>
+#endif
+
+#ifdef COGL_HAS_GLX_SUPPORT
+#include <GL/glx.h>
+#include <GL/glxext.h>
+#endif
+
typedef enum _CoglFramebufferType {
COGL_FRAMEBUFFER_TYPE_ONSCREEN,
COGL_FRAMEBUFFER_TYPE_OFFSCREEN
@@ -37,12 +46,14 @@ typedef enum _CoglFramebufferType {
struct _CoglFramebuffer
{
CoglObject _parent;
+ CoglContext *context;
CoglFramebufferType type;
int width;
int height;
/* Format of the pixels in the framebuffer (including the expected
premult state) */
CoglPixelFormat format;
+ gboolean allocated;
CoglMatrixStack *modelview_stack;
CoglMatrixStack *projection_stack;
@@ -85,8 +96,6 @@ struct _CoglFramebuffer
gboolean clear_clip_dirty;
};
-#define COGL_FRAMEBUFFER(X) ((CoglFramebuffer *)(X))
-
typedef struct _CoglOffscreen
{
CoglFramebuffer _parent;
@@ -103,12 +112,18 @@ typedef enum
#define COGL_OFFSCREEN(X) ((CoglOffscreen *)(X))
-typedef struct _CoglOnscreen
+struct _CoglOnscreen
{
CoglFramebuffer _parent;
-} CoglOnscreen;
-#define COGL_ONSCREEN(X) ((CoglOnscreen *)(X))
+#ifdef COGL_HAS_X11_SUPPORT
+ guint32 foreign_xid;
+#endif
+
+ gboolean swap_throttled;
+
+ void *winsys;
+};
void
_cogl_framebuffer_state_init (void);
@@ -233,7 +248,11 @@ typedef enum _CoglFramebufferFlushFlags
COGL_FRAMEBUFFER_FLUSH_SKIP_MODELVIEW = 1L<<0,
/* Similarly this flag implies you are going to flush the clip state
yourself */
- COGL_FRAMEBUFFER_FLUSH_SKIP_CLIP_STATE = 1L<<1
+ COGL_FRAMEBUFFER_FLUSH_SKIP_CLIP_STATE = 1L<<1,
+ /* When using this all that will be updated is the glBindFramebuffer
+ * state and corresponding winsys state to make the framebuffer
+ * current if it is a CoglOnscreen framebuffer. */
+ COGL_FRAMEBUFFER_FLUSH_BIND_ONLY = 1L<<2
} CoglFramebufferFlushFlags;
void
@@ -241,9 +260,6 @@ _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
CoglFramebuffer *read_buffer,
CoglFramebufferFlushFlags flags);
-CoglHandle
-_cogl_onscreen_new (void);
-
CoglFramebuffer *
_cogl_get_read_framebuffer (void);
@@ -339,5 +355,8 @@ _cogl_blit_framebuffer (unsigned int src_x,
unsigned int width,
unsigned int height);
+CoglOnscreen *
+_cogl_onscreen_new (void);
+
#endif /* __COGL_FRAMEBUFFER_PRIVATE_H */
diff --git a/clutter/cogl/cogl/cogl-framebuffer.c b/clutter/cogl/cogl/cogl-framebuffer.c
index a145994..e67e27b 100644
--- a/clutter/cogl/cogl/cogl-framebuffer.c
+++ b/clutter/cogl/cogl/cogl-framebuffer.c
@@ -36,6 +36,7 @@
#include "cogl-framebuffer-private.h"
#include "cogl-clip-stack.h"
#include "cogl-journal-private.h"
+#include "cogl-winsys-private.h"
#ifndef HAVE_COGL_GLES2
@@ -291,6 +292,8 @@ _cogl_framebuffer_clear4f (CoglFramebuffer *framebuffer,
int scissor_x1;
int scissor_y1;
+ g_return_if_fail (framebuffer->allocated);
+
_cogl_clip_stack_get_bounds (clip_stack,
&scissor_x0, &scissor_y0,
&scissor_x1, &scissor_y1);
@@ -451,6 +454,8 @@ _cogl_framebuffer_clear (CoglFramebuffer *framebuffer,
unsigned long buffers,
const CoglColor *color)
{
+ g_return_if_fail (framebuffer->allocated);
+
_cogl_framebuffer_clear4f (framebuffer, buffers,
cogl_color_get_red_float (color),
cogl_color_get_green_float (color),
@@ -811,8 +816,6 @@ _cogl_offscreen_new_to_texture_full (CoglHandle texhandle,
CoglFramebufferTryFBOData data;
gboolean fbo_created;
- _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
-
if (!cogl_features_available (COGL_FEATURE_OFFSCREEN))
return COGL_INVALID_HANDLE;
@@ -887,8 +890,11 @@ _cogl_offscreen_new_to_texture_full (CoglHandle texhandle,
if (fbo_created)
{
CoglOffscreen *ret;
+ CoglFramebuffer *fb = COGL_FRAMEBUFFER (offscreen);
- _cogl_framebuffer_init (COGL_FRAMEBUFFER (offscreen),
+ _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
+
+ _cogl_framebuffer_init (fb,
ctx,
COGL_FRAMEBUFFER_TYPE_OFFSCREEN,
cogl_texture_get_format (texhandle),
@@ -901,6 +907,8 @@ _cogl_offscreen_new_to_texture_full (CoglHandle texhandle,
ret = _cogl_offscreen_object_new (offscreen);
_cogl_texture_associate_framebuffer (texhandle, COGL_FRAMEBUFFER (ret));
+ fb->allocated = TRUE;
+
return ret;
}
else
@@ -946,16 +954,34 @@ _cogl_offscreen_free (CoglOffscreen *offscreen)
g_free (offscreen);
}
-CoglHandle
+/* XXX: While we still have backend in Clutter we need a dummy object
+ * to represent the CoglOnscreen framebuffer that the backend
+ * creates... */
+CoglOnscreen *
_cogl_onscreen_new (void)
{
- CoglOnscreen *onscreen;
+ CoglOnscreen *onscreen = g_new0 (CoglOnscreen, 1);
_COGL_GET_CONTEXT (ctx, NULL);
- /* XXX: Until we have full winsys support in Cogl then we can't fully
- * implement CoglOnscreen framebuffers, since we can't, e.g. keep track of
- * the window size. */
+ _cogl_framebuffer_init (COGL_FRAMEBUFFER (onscreen),
+ ctx,
+ COGL_FRAMEBUFFER_TYPE_ONSCREEN,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 0xdeadbeef, /* width */
+ 0xdeadbeef); /* height */
+
+ COGL_FRAMEBUFFER (onscreen)->allocated = TRUE;
+
+ /* XXX: Note we don't initialize onscreen->winsys in this case. */
+
+ return _cogl_onscreen_object_new (onscreen);
+}
+
+CoglOnscreen *
+cogl_onscreen_new (CoglContext *ctx, int width, int height)
+{
+ CoglOnscreen *onscreen;
/* FIXME: We are assuming onscreen buffers will always be
premultiplied so we'll set the premult flag on the bitmap
@@ -973,15 +999,41 @@ _cogl_onscreen_new (void)
ctx,
COGL_FRAMEBUFFER_TYPE_ONSCREEN,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
- 0xdeadbeef, /* width */
- 0xdeadbeef); /* height */
+ width, /* width */
+ height); /* height */
+
+ onscreen->swap_throttled = TRUE;
return _cogl_onscreen_object_new (onscreen);
}
+gboolean
+cogl_framebuffer_allocate (CoglFramebuffer *framebuffer,
+ GError **error)
+{
+ CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
+
+ if (framebuffer->allocated)
+ return TRUE;
+
+ /* XXX: with the current cogl_offscreen_new_to_texture() API the
+ * framebuffer is implicitly allocated before returning. */
+ g_return_val_if_fail (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN,
+ TRUE);
+
+ if (!_cogl_winsys_onscreen_init (onscreen, error))
+ return FALSE;
+
+ framebuffer->allocated = TRUE;
+
+ return TRUE;
+}
+
static void
_cogl_onscreen_free (CoglOnscreen *onscreen)
{
+ _cogl_winsys_onscreen_deinit (onscreen);
+
/* Chain up to parent */
_cogl_framebuffer_free (COGL_FRAMEBUFFER (onscreen));
@@ -1059,11 +1111,14 @@ static void
_cogl_set_framebuffers_real (CoglFramebuffer *draw_buffer,
CoglFramebuffer *read_buffer)
{
- CoglContext *ctx = draw_buffer->context;
CoglFramebufferStackEntry *entry;
+ GSList *l;
- g_return_if_fail (context != NULL);
- g_return_if_fail (draw_buffer->context == read_buffer->context);
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ g_return_if_fail (ctx != NULL);
+ g_return_if_fail (draw_buffer && read_buffer ?
+ draw_buffer->context == read_buffer->context : TRUE);
entry = ctx->framebuffer_stack->data;
@@ -1087,9 +1142,26 @@ _cogl_set_framebuffers_real (CoglFramebuffer *draw_buffer,
* projection matrix stacks and clip state so we need to dirty
* them to ensure they get flushed for the next batch of geometry
* we flush */
- _cogl_matrix_stack_dirty (draw_buffer->modelview_stack);
- _cogl_matrix_stack_dirty (draw_buffer->projection_stack);
+ if (draw_buffer)
+ {
+ _cogl_matrix_stack_dirty (draw_buffer->modelview_stack);
+ _cogl_matrix_stack_dirty (draw_buffer->projection_stack);
+ }
+
_cogl_clip_stack_dirty ();
+
+ /* XXX:
+ * To support the deprecated cogl_set_draw_buffer API we keep track
+ * of the last onscreen framebuffer that was pushed so that it can
+ * be restored if the COGL_WINDOW_BUFFER enum is used. */
+ ctx->window_buffer = NULL;
+ for (l = ctx->framebuffer_stack; l; l = l->next)
+ {
+ entry = l->data;
+ if (entry->draw_buffer &&
+ entry->draw_buffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
+ ctx->window_buffer = entry->draw_buffer;
+ }
}
static void
@@ -1182,15 +1254,19 @@ _cogl_push_framebuffers (CoglFramebuffer *draw_buffer,
g_return_if_fail (_cogl_is_framebuffer (read_buffer));
ctx = draw_buffer->context;
- g_return_if_fail (context != NULL);
+ g_return_if_fail (ctx != NULL);
g_return_if_fail (draw_buffer->context == read_buffer->context);
- g_return_if_fail (context->framebuffer_stack != NULL);
+ g_return_if_fail (ctx->framebuffer_stack != NULL);
/* Copy the top of the stack so that when we call cogl_set_framebuffer
it will still know what the old framebuffer was */
- old_draw_buffer = cogl_object_ref (cogl_get_draw_framebuffer ());
- old_read_buffer = cogl_object_ref (_cogl_get_read_framebuffer ());
+ old_draw_buffer = cogl_get_draw_framebuffer ();
+ if (old_draw_buffer)
+ cogl_object_ref (old_draw_buffer);
+ old_read_buffer = _cogl_get_read_framebuffer ();
+ if (old_read_buffer)
+ cogl_object_ref (old_read_buffer);
ctx->framebuffer_stack =
g_slist_prepend (ctx->framebuffer_stack,
create_stack_entry (old_draw_buffer,
@@ -1264,15 +1340,20 @@ cogl_pop_draw_buffer (void)
}
static void
-bind_gl_framebuffer (GLenum target, CoglFramebuffer *framebuffer)
+bind_gl_framebuffer (CoglContext *ctx,
+ GLenum target,
+ CoglFramebuffer *framebuffer)
{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
GE (glBindFramebuffer (target,
COGL_OFFSCREEN (framebuffer)->fbo_handle));
else
- GE (glBindFramebuffer (target, 0));
+ {
+#ifdef COGL_HAS_FULL_WINSYS
+ _cogl_winsys_onscreen_bind (COGL_ONSCREEN (framebuffer));
+#endif
+ GE (glBindFramebuffer (target, 0));
+ }
}
void
@@ -1282,21 +1363,29 @@ _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
{
CoglContext *ctx = draw_buffer->context;
- if (cogl_features_available (COGL_FEATURE_OFFSCREEN) &&
- ctx->dirty_bound_framebuffer)
+ if (ctx->dirty_bound_framebuffer)
{
- if (!cogl_features_available (COGL_FEATURE_OFFSCREEN_BLIT) ||
- draw_buffer == read_buffer)
- bind_gl_framebuffer (GL_FRAMEBUFFER, draw_buffer);
+ if (draw_buffer == read_buffer)
+ bind_gl_framebuffer (ctx, GL_FRAMEBUFFER, draw_buffer);
else
{
- bind_gl_framebuffer (GL_DRAW_FRAMEBUFFER, draw_buffer);
- bind_gl_framebuffer (GL_READ_FRAMEBUFFER, read_buffer);
+ /* NB: Currently we only take advantage of binding separate
+ * read/write buffers for offscreen framebuffer blit
+ * purposes. */
+ g_return_if_fail (cogl_features_available (COGL_FEATURE_OFFSCREEN_BLIT));
+ g_return_if_fail (draw_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN);
+ g_return_if_fail (read_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN);
+
+ bind_gl_framebuffer (ctx, GL_DRAW_FRAMEBUFFER, draw_buffer);
+ bind_gl_framebuffer (ctx, GL_READ_FRAMEBUFFER, read_buffer);
}
-
- ctx->dirty_bound_framebuffer = FALSE;
}
+ ctx->dirty_bound_framebuffer = FALSE;
+
+ if (flags & COGL_FRAMEBUFFER_FLUSH_BIND_ONLY)
+ return;
+
if (ctx->dirty_gl_viewport)
{
float gl_viewport_y;
@@ -1452,6 +1541,8 @@ _cogl_blit_framebuffer (unsigned int src_x,
CoglFramebuffer *read_buffer;
CoglContext *ctx;
+ /* FIXME: this function should take explit src and dst framebuffer
+ * arguments. */
draw_buffer = cogl_get_draw_framebuffer ();
read_buffer = _cogl_get_read_framebuffer ();
ctx = draw_buffer->context;
@@ -1484,3 +1575,83 @@ _cogl_blit_framebuffer (unsigned int src_x,
GL_COLOR_BUFFER_BIT,
GL_NEAREST);
}
+
+void
+cogl_framebuffer_swap_buffers (CoglFramebuffer *framebuffer)
+{
+ /* FIXME: we shouldn't need to flush *all* journals here! */
+ cogl_flush ();
+ if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
+ _cogl_winsys_onscreen_swap_buffers (COGL_ONSCREEN (framebuffer));
+}
+
+void
+cogl_framebuffer_swap_region (CoglFramebuffer *framebuffer,
+ int *rectangles,
+ int n_rectangles)
+{
+ /* FIXME: we shouldn't need to flush *all* journals here! */
+ cogl_flush ();
+ if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
+ _cogl_winsys_onscreen_swap_region (COGL_ONSCREEN (framebuffer),
+ rectangles,
+ n_rectangles);
+}
+
+#ifdef COGL_HAS_X11_SUPPORT
+void
+cogl_onscreen_x11_set_foreign_window_xid (CoglOnscreen *onscreen,
+ guint32 xid)
+{
+ onscreen->foreign_xid = xid;
+}
+
+guint32
+cogl_onscreen_x11_get_window_xid (CoglOnscreen *onscreen)
+{
+ return _cogl_winsys_onscreen_x11_get_window_xid (onscreen);
+}
+
+guint32
+cogl_onscreen_x11_get_visual_xid (CoglOnscreen *onscreen)
+{
+ guint32 id;
+ XVisualInfo *visinfo = _cogl_winsys_xlib_get_visual_info ();
+ id = (guint32)visinfo->visualid;
+ XFree (visinfo);
+ return id;
+}
+#endif /* COGL_HAS_X11_SUPPORT */
+
+unsigned int
+cogl_framebuffer_add_swap_buffers_callback (CoglFramebuffer *framebuffer,
+ CoglSwapBuffersNotify callback,
+ void *user_data)
+{
+ CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
+
+ /* Should this just be cogl_onscreen API instead? */
+ g_return_val_if_fail (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN, 0);
+
+ return _cogl_winsys_onscreen_add_swap_buffers_callback (onscreen,
+ callback,
+ user_data);
+}
+
+void
+cogl_framebuffer_remove_swap_buffers_callback (CoglFramebuffer *framebuffer,
+ unsigned int id)
+{
+ CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
+
+ _cogl_winsys_onscreen_remove_swap_buffers_callback (onscreen, id);
+}
+
+void
+cogl_onscreen_set_swap_throttled (CoglOnscreen *onscreen,
+ gboolean throttled)
+{
+ onscreen->swap_throttled = throttled;
+ if (COGL_FRAMEBUFFER (onscreen)->allocated)
+ _cogl_winsys_onscreen_update_swap_throttled (onscreen);
+}
diff --git a/clutter/cogl/cogl/cogl-framebuffer.h b/clutter/cogl/cogl/cogl-framebuffer.h
new file mode 100644
index 0000000..1e0a300
--- /dev/null
+++ b/clutter/cogl/cogl/cogl-framebuffer.h
@@ -0,0 +1,109 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ * Robert Bragg <robert linux intel com>
+ */
+
+#ifndef __COGL_FRAMEBUFFER_H
+#define __COGL_FRAMEBUFFER_H
+
+#include <glib.h>
+
+
+G_BEGIN_DECLS
+
+#ifdef COGL_ENABLE_EXPERIMENTAL_API
+#define cogl_onscreen_new cogl_onscreen_new_EXP
+
+#define COGL_FRAMEBUFFER(X) ((CoglFramebuffer *)(X))
+
+#define cogl_framebuffer_allocate cogl_framebuffer_allocate_EXP
+gboolean
+cogl_framebuffer_allocate (CoglFramebuffer *framebuffer,
+ GError **error);
+
+#define cogl_framebuffer_swap_buffers cogl_framebuffer_swap_buffers_EXP
+void
+cogl_framebuffer_swap_buffers (CoglFramebuffer *framebuffer);
+
+#define cogl_framebuffer_swap_region cogl_framebuffer_swap_region_EXP
+void
+cogl_framebuffer_swap_region (CoglFramebuffer *framebuffer,
+ int *rectangles,
+ int n_rectangles);
+
+
+typedef void (*CoglSwapBuffersNotify) (CoglFramebuffer *framebuffer,
+ void *user_data);
+
+#define cogl_framebuffer_add_swap_buffers_callback \
+ cogl_framebuffer_add_swap_buffers_callback_EXP
+unsigned int
+cogl_framebuffer_add_swap_buffers_callback (CoglFramebuffer *framebuffer,
+ CoglSwapBuffersNotify callback,
+ void *user_data);
+
+#define cogl_framebuffer_remove_swap_buffers_callback \
+ cogl_framebuffer_remove_swap_buffers_callback_EXP
+void
+cogl_framebuffer_remove_swap_buffers_callback (CoglFramebuffer *framebuffer,
+ unsigned int id);
+
+
+typedef struct _CoglOnscreen CoglOnscreen;
+#define COGL_ONSCREEN(X) ((CoglOnscreen *)(X))
+
+CoglOnscreen *
+cogl_onscreen_new (CoglContext *context, int width, int height);
+
+#ifdef COGL_HAS_X11
+#define cogl_onscreen_x11_set_foreign_window_xid \
+ cogl_onscreen_x11_set_foreign_window_xid_EXP
+void
+cogl_onscreen_x11_set_foreign_window_xid (CoglOnscreen *onscreen,
+ guint32 xid);
+
+#define cogl_onscreen_x11_get_window_xid cogl_onscreen_x11_get_window_xid_EXP
+guint32
+cogl_onscreen_x11_get_window_xid (CoglOnscreen *onscreen);
+
+#define cogl_onscreen_x11_get_visual_xid cogl_onscreen_x11_get_visual_xid_EXP
+guint32
+cogl_onscreen_x11_get_visual_xid (CoglOnscreen *onscreen);
+#endif /* COGL_HAS_X11 */
+
+void
+cogl_onscreen_set_swap_throttled (CoglOnscreen *onscreen,
+ gboolean throttled);
+
+#define cogl_get_draw_framebuffer cogl_get_draw_framebuffer_EXP
+CoglFramebuffer *
+cogl_get_draw_framebuffer (void);
+
+#endif /* COGL_ENABLE_EXPERIMENTAL_API */
+
+G_END_DECLS
+
+#endif /* __COGL_FRAMEBUFFER_H */
+
diff --git a/clutter/cogl/cogl/cogl-internal.h b/clutter/cogl/cogl/cogl-internal.h
index 09f5cbc..eba62bf 100644
--- a/clutter/cogl/cogl/cogl-internal.h
+++ b/clutter/cogl/cogl/cogl-internal.h
@@ -29,7 +29,7 @@
#include "cogl-bitmask.h"
#ifdef COGL_HAS_XLIB_SUPPORT
-#include <X11/Xlib.h>
+#include <X11/Xutil.h>
#endif
typedef enum
@@ -119,99 +119,17 @@ _cogl_transform_point (const CoglMatrix *matrix_mv,
float *x,
float *y);
-#ifdef COGL_HAS_XLIB_SUPPORT
-
-/*
- * CoglX11FilterReturn:
- * @COGL_XLIB_FILTER_CONTINUE: The event was not handled, continues the
- * processing
- * @COGL_XLIB_FILTER_REMOVE: Remove the event, stops the processing
- *
- * Return values for the #CoglX11FilterFunc function.
- */
-typedef enum _CoglXlibFilterReturn {
- COGL_XLIB_FILTER_CONTINUE,
- COGL_XLIB_FILTER_REMOVE
-} CoglXlibFilterReturn;
-
-/*
- * CoglXlibFilterFunc:
- *
- * A callback function that can be registered with
- * _cogl_xlib_add_filter. The function should return
- * %COGL_XLIB_FILTER_REMOVE if it wants to prevent further processing
- * or %COGL_XLIB_FILTER_CONTINUE otherwise.
- */
-typedef CoglXlibFilterReturn (* CoglXlibFilterFunc) (XEvent *xevent,
- gpointer data);
-
-/*
- * cogl_xlib_handle_event:
- * @xevent: pointer to XEvent structure
- *
- * This function processes a single X event; it can be used to hook
- * into external X event retrieval (for example that done by Clutter
- * or GDK).
- *
- * Return value: #CoglXlibFilterReturn. %COGL_XLIB_FILTER_REMOVE
- * indicates that Cogl has internally handled the event and the
- * caller should do no further processing. %COGL_XLIB_FILTER_CONTINUE
- * indicates that Cogl is either not interested in the event,
- * or has used the event to update internal state without taking
- * any exclusive action.
- */
-CoglXlibFilterReturn
-_cogl_xlib_handle_event (XEvent *xevent);
-
-/*
- * _cogl_xlib_get_display:
- *
- * Return value: the Xlib display that will be used by the Xlib winsys
- * backend. The display needs to be set with _cogl_xlib_set_display()
- * before this function is called.
- */
-Display *
-_cogl_xlib_get_display (void);
+#define COGL_DRIVER_ERROR (_cogl_driver_error_quark ())
-/*
- * cogl_xlib_set_display:
- *
- * Sets the Xlib display that Cogl will use for the Xlib winsys
- * backend. This function should eventually go away when Cogl gains a
- * more complete winsys abstraction.
- */
-void
-_cogl_xlib_set_display (Display *display);
-
-/*
- * _cogl_xlib_add_filter:
- *
- * Adds a callback function that will receive all X11 events. The
- * function can stop further processing of the event by return
- * %COGL_XLIB_FILTER_REMOVE.
- */
-void
-_cogl_xlib_add_filter (CoglXlibFilterFunc func,
- gpointer data);
-
-/*
- * _cogl_xlib_remove_filter:
- *
- * Removes a callback that was previously added with
- * _cogl_xlib_add_filter().
- */
-void
-_cogl_xlib_remove_filter (CoglXlibFilterFunc func,
- gpointer data);
-
-#endif /* COGL_HAS_XLIB_SUPPORT */
-
-typedef enum _CoglFeatureFlagsPrivate
-{
- COGL_FEATURE_PRIVATE_PLACE_HOLDER = (1 << 0)
-} CoglFeatureFlagsPrivate;
+typedef enum { /*< prefix=COGL_DRIVER_ERROR >*/
+ COGL_DRIVER_ERROR_UNKNOWN_VERSION,
+ COGL_DRIVER_ERROR_INVALID_VERSION
+} CoglDriverError;
gboolean
-_cogl_features_available_private (CoglFeatureFlagsPrivate features);
+_cogl_check_extension (const char *name, const char *ext);
+
+GQuark
+_cogl_driver_error_quark (void);
#endif /* __COGL_INTERNAL_H */
diff --git a/clutter/cogl/cogl/cogl-journal-private.h b/clutter/cogl/cogl/cogl-journal-private.h
index 44a4af8..7212dca 100644
--- a/clutter/cogl/cogl/cogl-journal-private.h
+++ b/clutter/cogl/cogl/cogl-journal-private.h
@@ -24,6 +24,7 @@
#ifndef __COGL_JOURNAL_PRIVATE_H
#define __COGL_JOURNAL_PRIVATE_H
+#include "cogl.h"
#include "cogl-handle.h"
#include "cogl-clip-stack.h"
diff --git a/clutter/cogl/cogl/cogl-private.h b/clutter/cogl/cogl/cogl-private.h
index 4407b42..bd09f4e 100644
--- a/clutter/cogl/cogl/cogl-private.h
+++ b/clutter/cogl/cogl/cogl-private.h
@@ -27,6 +27,12 @@
G_BEGIN_DECLS
gboolean
+_cogl_gl_check_version (GError **error);
+
+void
+_cogl_gl_update_features (CoglContext *context);
+
+gboolean
_cogl_check_extension (const char *name, const char *ext);
void
diff --git a/clutter/cogl/cogl/cogl-renderer-glx-private.h b/clutter/cogl/cogl/cogl-renderer-glx-private.h
new file mode 100644
index 0000000..aaebc9e
--- /dev/null
+++ b/clutter/cogl/cogl/cogl-renderer-glx-private.h
@@ -0,0 +1,61 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifndef __COGL_RENDERER_GLX_PRIVATE_H
+#define __COGL_RENDERER_GLX_PRIVATE_H
+
+#include "cogl-object-private.h"
+#include "cogl-renderer-xlib-private.h"
+
+typedef struct _CoglRendererGLX
+{
+ CoglRendererXlib _parent;
+
+ int glx_major;
+ int glx_minor;
+
+ int glx_error_base;
+ int glx_event_base;
+
+ gboolean is_direct;
+
+ /* Vblank stuff */
+ int dri_fd;
+
+ /* Function pointers for GLX specific extensions */
+#define COGL_WINSYS_FEATURE_BEGIN(a, b, c, d, e, f)
+
+#define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) \
+ ret (APIENTRY * pf_ ## name) args;
+
+#define COGL_WINSYS_FEATURE_END()
+
+#include "cogl-winsys-glx-feature-functions.h"
+
+#undef COGL_WINSYS_FEATURE_BEGIN
+#undef COGL_WINSYS_FEATURE_FUNCTION
+#undef COGL_WINSYS_FEATURE_END
+} CoglRendererGLX;
+
+#endif /* __COGL_RENDERER_GLX_PRIVATE_H */
diff --git a/clutter/cogl/cogl/cogl-renderer-x11-private.h b/clutter/cogl/cogl/cogl-renderer-x11-private.h
new file mode 100644
index 0000000..5ec56cc
--- /dev/null
+++ b/clutter/cogl/cogl/cogl-renderer-x11-private.h
@@ -0,0 +1,32 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifndef __COGL_RENDERER_X11_PRIVATE_H
+#define __COGL_RENDERER_X11_PRIVATE_H
+
+typedef struct _CoglRendererX11
+{
+ int damage_base;
+} CoglRendererX11;
+
+#endif /* __COGL_RENDERER_X11_PRIVATE_H */
diff --git a/clutter/cogl/cogl/winsys/cogl-winsys-xlib.h b/clutter/cogl/cogl/cogl-renderer-xlib-private.h
similarity index 53%
rename from clutter/cogl/cogl/winsys/cogl-winsys-xlib.h
rename to clutter/cogl/cogl/cogl-renderer-xlib-private.h
index 62a2162..13f9464 100644
--- a/clutter/cogl/cogl/winsys/cogl-winsys-xlib.h
+++ b/clutter/cogl/cogl/cogl-renderer-xlib-private.h
@@ -3,7 +3,7 @@
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
- * Copyright (C) 2010 Intel Corporation.
+ * Copyright (C) 2011 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -15,30 +15,40 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
-#ifndef __COGL_XLIB_H
-#define __COGL_XLIB_H
+#ifndef __COGL_RENDERER_XLIB_PRIVATE_H
+#define __COGL_RENDERER_XLIB_PRIVATE_H
-#include "cogl.h"
-#include "cogl-context-winsys.h"
+#include "cogl-object-private.h"
+#include "cogl-xlib-private.h"
+#include "cogl-renderer-x11-private.h"
-#include <X11/Xlib.h>
+typedef struct _CoglRendererXlib
+{
+ CoglRendererX11 _parent;
-typedef struct _CoglXlibFilterClosure CoglXlibFilterClosure;
+ Display *xdpy;
-struct _CoglXlibFilterClosure
-{
- CoglXlibFilterFunc func;
- gpointer data;
-};
+ /* List of callback functions that will be given every Xlib event */
+ GSList *event_filters;
+ /* Current top of the XError trap state stack. The actual memory for
+ these is expected to be allocated on the stack by the caller */
+ CoglXlibTrapState *trap_state;
+} CoglRendererXlib;
+
+gboolean
+_cogl_renderer_xlib_connect (CoglRenderer *renderer, GError **error);
+
+void
+_cogl_renderer_xlib_disconnect (CoglRenderer *renderer);
/*
- * _cogl_xlib_trap_errors:
+ * cogl_renderer_xlib_trap_errors:
* @state: A temporary place to store data for the trap.
*
* Traps every X error until _cogl_xlib_untrap_errors() called. You
@@ -50,10 +60,11 @@ struct _CoglXlibFilterClosure
* pointers in reverse order.
*/
void
-_cogl_xlib_trap_errors (CoglXlibTrapState *state);
+_cogl_renderer_xlib_trap_errors (CoglRenderer *renderer,
+ CoglXlibTrapState *state);
/*
- * _cogl_xlib_untrap_errors:
+ * cogl_renderer_xlib_untrap_errors:
* @state: The state that was passed to _cogl_xlib_trap_errors().
*
* Removes the X error trap and returns the current status.
@@ -61,6 +72,7 @@ _cogl_xlib_trap_errors (CoglXlibTrapState *state);
* Return value: the trapped error code, or 0 for success
*/
int
-_cogl_xlib_untrap_errors (CoglXlibTrapState *state);
+_cogl_renderer_xlib_untrap_errors (CoglRenderer *renderer,
+ CoglXlibTrapState *state);
-#endif /* __COGL_XLIB_H */
+#endif /* __COGL_RENDERER_XLIB_PRIVATE_H */
diff --git a/clutter/cogl/cogl/cogl-renderer-xlib.c b/clutter/cogl/cogl/cogl-renderer-xlib.c
new file mode 100644
index 0000000..bd2cc2b
--- /dev/null
+++ b/clutter/cogl/cogl/cogl-renderer-xlib.c
@@ -0,0 +1,288 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2008,2009,2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Robert Bragg <robert linux intel com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl.h"
+#include "cogl-internal.h"
+#include "cogl-object.h"
+
+#include "cogl-renderer-private.h"
+#include "cogl-renderer-xlib-private.h"
+#include "cogl-renderer-x11-private.h"
+#include "cogl-winsys-private.h"
+
+#include <X11/Xlib.h>
+#include <X11/extensions/Xdamage.h>
+
+static char *_cogl_x11_display_name = NULL;
+static GList *_cogl_xlib_renderers = NULL;
+
+CoglXlibFilterReturn
+cogl_renderer_xlib_handle_event (CoglRenderer *renderer,
+ XEvent *xevent)
+{
+ CoglRendererXlib *xlib_renderer = renderer->winsys;
+ GSList *l;
+
+ g_return_val_if_fail (xlib_renderer->xdpy != NULL, COGL_XLIB_FILTER_CONTINUE);
+
+ /* XXX: should this be a more graceful check? */
+ g_return_val_if_fail (xlib_renderer != NULL, COGL_XLIB_FILTER_CONTINUE);
+
+ /* Pass the event on to all of the registered filters in turn */
+ for (l = xlib_renderer->event_filters; l; l = l->next)
+ {
+ CoglXlibFilterClosure *closure = l->data;
+
+ if (closure->func (xevent, closure->data) == COGL_XLIB_FILTER_REMOVE)
+ return COGL_XLIB_FILTER_REMOVE;
+ }
+
+ switch (xevent->type)
+ {
+ /* TODO... */
+ default:
+ break;
+ }
+
+ return COGL_XLIB_FILTER_CONTINUE;
+}
+
+void
+cogl_renderer_xlib_add_filter (CoglRenderer *renderer,
+ CoglXlibFilterFunc func,
+ void *data)
+{
+ CoglRendererXlib *xlib_renderer;
+ CoglXlibFilterClosure *closure;
+
+ xlib_renderer = renderer->winsys;
+
+ closure = g_slice_new (CoglXlibFilterClosure);
+ closure->func = func;
+ closure->data = data;
+
+ xlib_renderer->event_filters =
+ g_slist_prepend (xlib_renderer->event_filters, closure);
+}
+
+void
+cogl_renderer_xlib_remove_filter (CoglRenderer *renderer,
+ CoglXlibFilterFunc func,
+ void *data)
+{
+ CoglRendererXlib *xlib_renderer;
+ GSList *l, *prev = NULL;
+
+ xlib_renderer = renderer->winsys;
+
+ for (l = xlib_renderer->event_filters; l; prev = l, l = l->next)
+ {
+ CoglXlibFilterClosure *closure = l->data;
+
+ if (closure->func == func && closure->data == data)
+ {
+ g_slice_free (CoglXlibFilterClosure, closure);
+ if (prev)
+ prev->next = g_slist_delete_link (prev->next, l);
+ else
+ xlib_renderer->event_filters =
+ g_slist_delete_link (xlib_renderer->event_filters, l);
+ break;
+ }
+ }
+}
+
+static void
+register_xlib_renderer (CoglRenderer *renderer)
+{
+ GList *l;
+
+ for (l = _cogl_xlib_renderers; l; l = l->next)
+ if (l->data == renderer)
+ return;
+
+ _cogl_xlib_renderers = g_list_prepend (_cogl_xlib_renderers, renderer);
+}
+
+static void
+unregister_xlib_renderer (CoglRenderer *renderer)
+{
+ _cogl_xlib_renderers = g_list_remove (_cogl_xlib_renderers, renderer);
+}
+
+static CoglRenderer *
+get_renderer_for_xdisplay (Display *xdpy)
+{
+ GList *l;
+
+ for (l = _cogl_xlib_renderers; l; l = l->next)
+ {
+ CoglRenderer *renderer = l->data;
+ CoglRendererXlib *xlib_renderer = renderer->winsys;
+
+ if (xlib_renderer->xdpy == xdpy)
+ return renderer;
+ }
+
+ return NULL;
+}
+
+static int
+error_handler (Display *xdpy,
+ XErrorEvent *error)
+{
+ CoglRenderer *renderer;
+ CoglRendererXlib *xlib_renderer;
+
+ renderer = get_renderer_for_xdisplay (xdpy);
+
+ xlib_renderer = renderer->winsys;
+ g_assert (xlib_renderer->trap_state);
+
+ xlib_renderer->trap_state->trapped_error_code = error->error_code;
+
+ return 0;
+}
+
+void
+_cogl_renderer_xlib_trap_errors (CoglRenderer *renderer,
+ CoglXlibTrapState *state)
+{
+ CoglRendererXlib *xlib_renderer;
+
+ xlib_renderer = renderer->winsys;
+
+ state->trapped_error_code = 0;
+ state->old_error_handler = XSetErrorHandler (error_handler);
+
+ state->old_state = xlib_renderer->trap_state;
+ xlib_renderer->trap_state = state;
+}
+
+int
+_cogl_renderer_xlib_untrap_errors (CoglRenderer *renderer,
+ CoglXlibTrapState *state)
+{
+ CoglRendererXlib *xlib_renderer;
+
+ xlib_renderer = renderer->winsys;
+ g_assert (state == xlib_renderer->trap_state);
+
+ XSetErrorHandler (state->old_error_handler);
+
+ xlib_renderer->trap_state = state->old_state;
+
+ return state->trapped_error_code;
+}
+
+static Display *
+assert_xlib_display (CoglRenderer *renderer, GError **error)
+{
+ Display *xdpy = cogl_renderer_xlib_get_foreign_display (renderer);
+ CoglRendererXlib *xlib_renderer = renderer->winsys;
+
+ /* A foreign display may have already been set... */
+ if (xdpy)
+ {
+ xlib_renderer->xdpy = xdpy;
+ return xdpy;
+ }
+
+ xdpy = XOpenDisplay (_cogl_x11_display_name);
+ if (xdpy == NULL)
+ {
+ g_set_error (error,
+ COGL_RENDERER_ERROR,
+ COGL_RENDERER_ERROR_XLIB_DISPLAY_OPEN,
+ "Failed to open X Display %s", _cogl_x11_display_name);
+ return NULL;
+ }
+
+ xlib_renderer->xdpy = xdpy;
+ return xdpy;
+}
+
+gboolean
+_cogl_renderer_xlib_connect (CoglRenderer *renderer, GError **error)
+{
+ CoglRendererXlib *xlib_renderer = renderer->winsys;
+ CoglRendererX11 *x11_renderer = renderer->winsys;
+ int damage_error;
+
+ if (!assert_xlib_display (renderer, error))
+ return FALSE;
+
+ /* Check whether damage events are supported on this display */
+ if (!XDamageQueryExtension (xlib_renderer->xdpy,
+ &x11_renderer->damage_base,
+ &damage_error))
+ x11_renderer->damage_base = -1;
+
+ xlib_renderer->event_filters = NULL;
+
+ xlib_renderer->trap_state = NULL;
+
+ register_xlib_renderer (renderer);
+
+ return TRUE;
+}
+
+static void
+free_xlib_filter_closure (void *data, void *user_data)
+{
+ g_slice_free (CoglXlibFilterClosure, data);
+}
+
+void
+_cogl_renderer_xlib_disconnect (CoglRenderer *renderer)
+{
+ CoglRendererXlib *xlib_renderer = renderer->winsys;
+
+ g_slist_foreach (xlib_renderer->event_filters,
+ free_xlib_filter_closure, NULL);
+ g_slist_free (xlib_renderer->event_filters);
+
+ if (!renderer->foreign_xdpy)
+ XCloseDisplay (xlib_renderer->xdpy);
+
+ unregister_xlib_renderer (renderer);
+}
+
+Display *
+cogl_renderer_xlib_get_display (CoglRenderer *renderer)
+{
+ CoglRendererXlib *xlib_renderer;
+
+ g_return_val_if_fail (cogl_is_renderer (renderer), NULL);
+
+ xlib_renderer = renderer->winsys;
+
+ return xlib_renderer->xdpy;
+}
diff --git a/clutter/cogl/cogl/cogl-renderer.c b/clutter/cogl/cogl/cogl-renderer.c
index 9eddc9b..2dffb2f 100644
--- a/clutter/cogl/cogl/cogl-renderer.c
+++ b/clutter/cogl/cogl/cogl-renderer.c
@@ -50,6 +50,9 @@ cogl_renderer_error_quark (void)
static void
_cogl_renderer_free (CoglRenderer *renderer)
{
+#ifdef COGL_HAS_FULL_WINSYS
+ _cogl_winsys_renderer_disconnect (renderer);
+#endif
g_free (renderer);
}
@@ -90,6 +93,21 @@ cogl_renderer_check_onscreen_template (CoglRenderer *renderer,
CoglOnscreenTemplate *onscreen_template,
GError **error)
{
+#ifdef COGL_HAS_FULL_WINSYS
+ CoglDisplay *display;
+
+ if (!_cogl_winsys_renderer_connect (renderer, error))
+ return FALSE;
+
+ display = cogl_display_new (renderer, onscreen_template);
+ if (!cogl_display_setup (display, error))
+ {
+ cogl_object_unref (display);
+ return FALSE;
+ }
+
+ cogl_object_unref (display);
+#endif
return TRUE;
}
@@ -101,6 +119,11 @@ cogl_renderer_connect (CoglRenderer *renderer, GError **error)
if (renderer->connected)
return TRUE;
+#ifdef COGL_HAS_FULL_WINSYS
+ if (!_cogl_winsys_renderer_connect (renderer, error))
+ return FALSE;
+#endif
+
renderer->connected = TRUE;
return TRUE;
}
diff --git a/clutter/cogl/cogl/cogl-types.h b/clutter/cogl/cogl/cogl-types.h
index 6b5ff03..1a1aac4 100644
--- a/clutter/cogl/cogl/cogl-types.h
+++ b/clutter/cogl/cogl/cogl-types.h
@@ -30,6 +30,11 @@
#include <glib-object.h>
+#include <cogl/cogl-defines.h>
+#ifdef COGL_HAS_XLIB
+#include <X11/Xlib.h>
+#endif
+
G_BEGIN_DECLS
/* Some structures are meant to be opaque but they have public
@@ -284,7 +289,8 @@ typedef enum
COGL_FEATURE_TEXTURE_3D = (1 << 19),
COGL_FEATURE_SHADERS_ARBFP = (1 << 20),
COGL_FEATURE_MAP_BUFFER_FOR_READ = (1 << 21),
- COGL_FEATURE_MAP_BUFFER_FOR_WRITE = (1 << 22)
+ COGL_FEATURE_MAP_BUFFER_FOR_WRITE = (1 << 22),
+ COGL_FEATURE_ONSCREEN_MULTIPLE = (1 << 23)
} CoglFeatureFlags;
/**
@@ -582,11 +588,84 @@ typedef enum
COGL_DEPTH_TEST_FUNCTION_GEQUAL = 0x0206,
COGL_DEPTH_TEST_FUNCTION_ALWAYS = 0x0207
} CoglDepthTestFunction;
-/* XXX: Note these types are only referenced by experimental API so
- * although they aren't explicitly guarded they are implicitly
- * experimental too. */
/* NB: The above definitions are taken from gl.h equivalents */
+typedef enum { /*< prefix=COGL_RENDERER_ERROR >*/
+ COGL_RENDERER_ERROR_NOT_FOUND,
+ COGL_RENDERER_ERROR_XLIB_DISPLAY_OPEN
+} CoglRendererError;
+
+/*
+ * CoglXlibFilterReturn:
+ * @COGL_XLIB_FILTER_CONTINUE: The event was not handled, continues the
+ * processing
+ * @COGL_XLIB_FILTER_REMOVE: Remove the event, stops the processing
+ *
+ * Return values for the #CoglXlibFilterFunc function.
+ *
+ * Stability: Unstable
+ */
+typedef enum _CoglXlibFilterReturn { /*< prefix=COGL_XLIB_FILTER >*/
+ COGL_XLIB_FILTER_CONTINUE,
+ COGL_XLIB_FILTER_REMOVE
+} CoglXlibFilterReturn;
+
+typedef enum _CoglWinsysFeature
+{
+ COGL_WINSYS_FEATURE_NONE,
+
+ /* Available if the window system can support multiple onscreen
+ * framebuffers at the same time. */
+ COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN,
+
+ /* Available if onscreen framebuffer swaps can be automatically
+ * throttled to the vblank frequency. */
+ COGL_WINSYS_FEATURE_SWAP_THROTTLE,
+
+ /* Available if its possible to query a counter that
+ * increments at each vblank. */
+ COGL_WINSYS_FEATURE_VBLANK_COUNTER,
+
+ /* Available if its possible to wait until the next vertical
+ * blank period */
+ COGL_WINSYS_FEATURE_VBLANK_WAIT,
+
+ /* Available if the window system supports mapping native
+ * pixmaps to textures. */
+ COGL_WINSYS_FEATURE_TEXTURE_FROM_PIXMAP,
+
+ /* Available if the window system supports reporting an event
+ * for swap buffer completions. */
+ COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT,
+
+ /* Available if it's possible to swap a list of sub rectangles
+ * from the back buffer to the front buffer */
+ COGL_WINSYS_FEATURE_SWAP_REGION,
+
+ /* Available if swap_region requests can be automatically throttled
+ * to the vblank frequency. */
+ COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE
+} CoglWinsysFeature;
+
+/* XXX: Note these enum types are only referenced by experimental API
+ * so although they aren't explicitly guarded they are implicitly
+ * experimental too. */
+
+#ifdef COGL_HAS_XLIB
+
+/*
+ * CoglXlibFilterFunc:
+ *
+ * A callback function that can be registered with
+ * _cogl_xlib_add_filter. The function should return
+ * %COGL_XLIB_FILTER_REMOVE if it wants to prevent further processing
+ * or %COGL_XLIB_FILTER_CONTINUE otherwise.
+ */
+typedef CoglXlibFilterReturn (* CoglXlibFilterFunc) (XEvent *xevent,
+ void *data);
+
+#endif /* COGL_HAS_XLIB */
+
G_END_DECLS
#endif /* __COGL_TYPES_H__ */
diff --git a/clutter/cogl/cogl/cogl-util.c b/clutter/cogl/cogl/cogl-util.c
index d38049a..ddee76a 100644
--- a/clutter/cogl/cogl/cogl-util.c
+++ b/clutter/cogl/cogl/cogl-util.c
@@ -37,7 +37,6 @@
#include "cogl-shader.h"
#include "cogl-texture.h"
#include "cogl-types.h"
-#include "cogl-handle.h"
#include "cogl-util.h"
/*
diff --git a/clutter/cogl/cogl/cogl-xlib-private.h b/clutter/cogl/cogl/cogl-xlib-private.h
new file mode 100644
index 0000000..39bfeba
--- /dev/null
+++ b/clutter/cogl/cogl/cogl-xlib-private.h
@@ -0,0 +1,82 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2010,2011 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifndef __COGL_XLIB_PRIVATE_H
+#define __COGL_XLIB_PRIVATE_H
+
+#include "cogl/cogl.h"
+
+#include <X11/Xlib.h>
+
+typedef struct _CoglXlibTrapState CoglXlibTrapState;
+
+struct _CoglXlibTrapState
+{
+ /* These values are intended to be internal to
+ * _cogl_xlib_{un,}trap_errors but they need to be in the header so
+ * that the struct can be allocated on the stack */
+ int (* old_error_handler) (Display *, XErrorEvent *);
+ int trapped_error_code;
+ CoglXlibTrapState *old_state;
+};
+
+typedef struct _CoglXlibFilterClosure
+{
+ CoglXlibFilterFunc func;
+ void *data;
+} CoglXlibFilterClosure;
+
+void
+_cogl_xlib_query_damage_extension (void);
+
+int
+_cogl_xlib_get_damage_base (void);
+
+void
+_cogl_xlib_trap_errors (CoglXlibTrapState *state);
+
+int
+_cogl_xlib_untrap_errors (CoglXlibTrapState *state);
+
+/*
+ * _cogl_xlib_add_filter:
+ *
+ * Adds a callback function that will receive all X11 events. The
+ * function can stop further processing of the event by return
+ * %COGL_XLIB_FILTER_REMOVE.
+ */
+void
+_cogl_xlib_add_filter (CoglXlibFilterFunc func,
+ void *data);
+
+/*
+ * _cogl_xlib_remove_filter:
+ *
+ * Removes a callback that was previously added with
+ * _cogl_xlib_add_filter().
+ */
+void
+_cogl_xlib_remove_filter (CoglXlibFilterFunc func,
+ void *data);
+
+#endif /* __COGL_XLIB_PRIVATE_H */
diff --git a/clutter/cogl/cogl/winsys/cogl-winsys-xlib.c b/clutter/cogl/cogl/cogl-xlib.c
similarity index 56%
rename from clutter/cogl/cogl/winsys/cogl-winsys-xlib.c
rename to clutter/cogl/cogl/cogl-xlib.c
index 636b9fb..ce7fb15 100644
--- a/clutter/cogl/cogl/winsys/cogl-winsys-xlib.c
+++ b/clutter/cogl/cogl/cogl-xlib.c
@@ -3,7 +3,7 @@
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
- * Copyright (C) 2010 Intel Corporation.
+ * Copyright (C) 2010,2011 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -34,24 +34,36 @@
#include <cogl-handle.h>
#include <cogl-context-private.h>
#include <cogl-framebuffer-private.h>
+#include <cogl-display-private.h>
+#include <cogl-renderer-private.h>
+#include <cogl-renderer-xlib-private.h>
#include <X11/Xlib.h>
+#include <X11/extensions/Xdamage.h>
#include "cogl-xlib.h"
+/* FIXME: when we remove the last X11 based Clutter backend then we
+ * will get rid of these functions and instead rely on the equivalent
+ * _cogl_renderer_xlib API
+ */
+
/* This can't be in the Cogl context because it can be set before
context is created */
static Display *_cogl_xlib_display = NULL;
CoglXlibFilterReturn
-_cogl_xlib_handle_event (XEvent *xevent)
+cogl_xlib_handle_event (XEvent *xevent)
{
GSList *l;
_COGL_GET_CONTEXT (ctx, COGL_XLIB_FILTER_CONTINUE);
+ if (!ctx->stub_winsys)
+ return cogl_renderer_xlib_handle_event (ctx->display->renderer, xevent);
+
/* Pass the event on to all of the registered filters in turn */
- for (l = ctx->winsys.event_filters; l; l = l->next)
+ for (l = ctx->event_filters; l; l = l->next)
{
CoglXlibFilterClosure *closure = l->data;
@@ -70,10 +82,13 @@ _cogl_xlib_handle_event (XEvent *xevent)
}
Display *
-_cogl_xlib_get_display (void)
+cogl_xlib_get_display (void)
{
_COGL_GET_CONTEXT (ctx, NULL);
+ if (!ctx->stub_winsys)
+ return cogl_renderer_xlib_get_display (ctx->display->renderer);
+
/* _cogl_xlib_set_display should be called before this function */
g_assert (_cogl_xlib_display != NULL);
@@ -81,7 +96,7 @@ _cogl_xlib_get_display (void)
}
void
-_cogl_xlib_set_display (Display *display)
+cogl_xlib_set_display (Display *display)
{
/* This can only be called once before the Cogl context is created */
g_assert (_cogl_xlib_display == NULL);
@@ -91,29 +106,43 @@ _cogl_xlib_set_display (Display *display)
void
_cogl_xlib_add_filter (CoglXlibFilterFunc func,
- gpointer data)
+ void *data)
{
CoglXlibFilterClosure *closure;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ if (!ctx->stub_winsys)
+ {
+ cogl_renderer_xlib_add_filter (ctx->display->renderer,
+ func, data);
+ return;
+ }
+
closure = g_slice_new (CoglXlibFilterClosure);
closure->func = func;
closure->data = data;
- ctx->winsys.event_filters =
- g_slist_prepend (ctx->winsys.event_filters, closure);
+ ctx->event_filters =
+ g_slist_prepend (ctx->event_filters, closure);
}
void
_cogl_xlib_remove_filter (CoglXlibFilterFunc func,
- gpointer data)
+ void *data)
{
GSList *l, *prev = NULL;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
- for (l = ctx->winsys.event_filters; l; prev = l, l = l->next)
+ if (!ctx->stub_winsys)
+ {
+ cogl_renderer_xlib_remove_filter (ctx->display->renderer,
+ func, data);
+ return;
+ }
+
+ for (l = ctx->event_filters; l; prev = l, l = l->next)
{
CoglXlibFilterClosure *closure = l->data;
@@ -123,8 +152,8 @@ _cogl_xlib_remove_filter (CoglXlibFilterFunc func,
if (prev)
prev->next = g_slist_delete_link (prev->next, l);
else
- ctx->winsys.event_filters =
- g_slist_delete_link (ctx->winsys.event_filters, l);
+ ctx->event_filters =
+ g_slist_delete_link (ctx->event_filters, l);
break;
}
}
@@ -136,9 +165,9 @@ error_handler (Display *xdpy,
{
_COGL_GET_CONTEXT (ctxt, 0);
- g_assert (ctxt->winsys.trap_state);
+ g_assert (ctxt->trap_state);
- ctxt->winsys.trap_state->trapped_error_code = error->error_code;
+ ctxt->trap_state->trapped_error_code = error->error_code;
return 0;
}
@@ -148,11 +177,17 @@ _cogl_xlib_trap_errors (CoglXlibTrapState *state)
{
_COGL_GET_CONTEXT (ctxt, NO_RETVAL);
+ if (!ctxt->stub_winsys)
+ {
+ _cogl_renderer_xlib_trap_errors (ctxt->display->renderer, state);
+ return;
+ }
+
state->trapped_error_code = 0;
state->old_error_handler = XSetErrorHandler (error_handler);
- state->old_state = ctxt->winsys.trap_state;
- ctxt->winsys.trap_state = state;
+ state->old_state = ctxt->trap_state;
+ ctxt->trap_state = state;
}
int
@@ -160,11 +195,44 @@ _cogl_xlib_untrap_errors (CoglXlibTrapState *state)
{
_COGL_GET_CONTEXT (ctxt, 0);
- g_assert (state == ctxt->winsys.trap_state);
+ if (!ctxt->stub_winsys)
+ {
+ return _cogl_renderer_xlib_untrap_errors (ctxt->display->renderer, state);
+ }
+
+ g_assert (state == ctxt->trap_state);
XSetErrorHandler (state->old_error_handler);
- ctxt->winsys.trap_state = state->old_state;
+ ctxt->trap_state = state->old_state;
return state->trapped_error_code;
}
+
+void
+_cogl_xlib_query_damage_extension (void)
+{
+ int damage_error;
+
+ _COGL_GET_CONTEXT (ctxt, NO_RETVAL);
+
+ /* Check whether damage events are supported on this display */
+ if (!XDamageQueryExtension (cogl_xlib_get_display (),
+ &ctxt->damage_base,
+ &damage_error))
+ ctxt->damage_base = -1;
+}
+
+int
+_cogl_xlib_get_damage_base (void)
+{
+ _COGL_GET_CONTEXT (ctxt, -1);
+
+ if (!ctxt->stub_winsys)
+ {
+ CoglRendererX11 *x11_renderer = ctxt->display->renderer->winsys;
+ return x11_renderer->damage_base;
+ }
+ else
+ return ctxt->damage_base;
+}
diff --git a/clutter/cogl/cogl/cogl-xlib.h b/clutter/cogl/cogl/cogl-xlib.h
new file mode 100644
index 0000000..c776ece
--- /dev/null
+++ b/clutter/cogl/cogl/cogl-xlib.h
@@ -0,0 +1,84 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only <cogl/cogl.h> can be included directly."
+#endif
+
+#ifndef __COGL_XLIB_H__
+#define __COGL_XLIB_H__
+
+#include <cogl/cogl-types.h>
+
+#include <X11/Xlib.h>
+
+G_BEGIN_DECLS
+
+/*
+ * cogl_xlib_get_display:
+ *
+ * Return value: the Xlib display that will be used by the Xlib winsys
+ * backend. The display needs to be set with _cogl_xlib_set_display()
+ * before this function is called.
+ *
+ * Stability: Unstable
+ */
+#define cogl_xlib_get_display cogl_xlib_get_display_EXP
+Display *
+cogl_xlib_get_display (void);
+
+/*
+ * cogl_xlib_set_display:
+ *
+ * Sets the Xlib display that Cogl will use for the Xlib winsys
+ * backend. This function should eventually go away when Cogl gains a
+ * more complete winsys abstraction.
+ *
+ * Stability: Unstable
+ */
+#define cogl_xlib_set_display cogl_xlib_set_display_EXP
+void
+cogl_xlib_set_display (Display *display);
+
+/*
+ * cogl_xlib_handle_event:
+ * @xevent: pointer to XEvent structure
+ *
+ * This function processes a single X event; it can be used to hook
+ * into external X event retrieval (for example that done by Clutter
+ * or GDK).
+ *
+ * Return value: #CoglXlibFilterReturn. %COGL_XLIB_FILTER_REMOVE
+ * indicates that Cogl has internally handled the event and the
+ * caller should do no further processing. %COGL_XLIB_FILTER_CONTINUE
+ * indicates that Cogl is either not interested in the event,
+ * or has used the event to update internal state without taking
+ * any exclusive action.
+ *
+ * Stability: Unstable
+ */
+#define cogl_xlib_handle_event cogl_xlib_handle_event_EXP
+CoglXlibFilterReturn
+cogl_xlib_handle_event (XEvent *xevent);
+
+#endif /* __COGL_XLIB_H__ */
diff --git a/clutter/cogl/cogl/cogl.c b/clutter/cogl/cogl/cogl.c
index aa483c9..49882d9 100644
--- a/clutter/cogl/cogl/cogl.c
+++ b/clutter/cogl/cogl/cogl.c
@@ -38,7 +38,7 @@
#include "cogl-context-private.h"
#include "cogl-pipeline-private.h"
#include "cogl-pipeline-opengl-private.h"
-#include "cogl-winsys.h"
+#include "cogl-winsys-private.h"
#include "cogl-framebuffer-private.h"
#include "cogl-matrix-private.h"
#include "cogl-journal-private.h"
@@ -394,14 +394,6 @@ cogl_features_available (CoglFeatureFlags features)
return (ctx->feature_flags & features) == features;
}
-gboolean
-_cogl_features_available_private (CoglFeatureFlagsPrivate features)
-{
- _COGL_GET_CONTEXT (ctx, 0);
-
- return (ctx->feature_flags_private & features) == features;
-}
-
/* XXX: This function should either be replaced with one returning
* integers, or removed/deprecated and make the
* _cogl_framebuffer_get_viewport* functions public.
diff --git a/clutter/cogl/cogl/cogl.h b/clutter/cogl/cogl/cogl.h
index fffc12c..cbd2d0c 100644
--- a/clutter/cogl/cogl/cogl.h
+++ b/clutter/cogl/cogl/cogl.h
@@ -67,7 +67,12 @@
#include <cogl/cogl-deprecated.h>
+typedef struct _CoglFramebuffer CoglFramebuffer;
+
#if defined (COGL_ENABLE_EXPERIMENTAL_API)
+#include <cogl/cogl-swap-chain.h>
+#include <cogl/cogl-renderer.h>
+#include <cogl/cogl-display.h>
#include <cogl/cogl-context.h>
#include <cogl/cogl-buffer.h>
#include <cogl/cogl-pixel-array.h>
@@ -79,6 +84,13 @@
#include <cogl/cogl-attribute.h>
#include <cogl/cogl-primitive.h>
#include <cogl/cogl-pipeline.h>
+#include <cogl/cogl-framebuffer.h>
+#ifdef COGL_HAS_XLIB
+#include <cogl/cogl-xlib.h>
+#endif
+/* XXX: This will definitly go away once all the Clutter winsys
+ * code has been migrated down into Cogl! */
+#include <cogl/cogl-clutter.h>
#endif
G_BEGIN_DECLS
@@ -90,8 +102,6 @@ G_BEGIN_DECLS
* General utility functions for COGL.
*/
-typedef struct _CoglFramebuffer CoglFramebuffer;
-
/**
* cogl_get_option_group:
*
@@ -1245,44 +1255,6 @@ cogl_begin_gl (void);
void
cogl_end_gl (void);
-/*
- * Internal API available only to Clutter.
- *
- * These are typically only to deal with the poor seperation of
- * responsabilities that currently exists between Clutter and Cogl.
- * Eventually a lot of the backend code currently in Clutter will
- * move down into Cogl and these functions will be removed.
- */
-
-void
-_cogl_destroy_context (void);
-
-/*< private >*/
-#define COGL_DRIVER_ERROR (_cogl_driver_error_quark ())
-
-typedef enum { /*< prefix=COGL_DRIVER_ERROR >*/
- COGL_DRIVER_ERROR_UNKNOWN_VERSION,
- COGL_DRIVER_ERROR_INVALID_VERSION
-} CoglDriverError;
-
-gboolean
-_cogl_check_extension (const char *name, const char *ext);
-
-void
-_cogl_set_indirect_context (gboolean indirect);
-
-gboolean
-_cogl_check_driver_valid (GError **error);
-
-GQuark
-_cogl_driver_error_quark (void);
-
-#ifdef COGL_ENABLE_EXPERIMENTAL_API
-#define cogl_get_draw_framebuffer cogl_get_draw_framebuffer_EXP
-CoglFramebuffer *
-cogl_get_draw_framebuffer (void);
-#endif
-
G_END_DECLS
#undef __COGL_H_INSIDE__
diff --git a/clutter/cogl/cogl/driver/gl/cogl-context-driver-gl.h b/clutter/cogl/cogl/driver/gl/cogl-context-driver-gl.h
new file mode 100644
index 0000000..2d8e521
--- /dev/null
+++ b/clutter/cogl/cogl/driver/gl/cogl-context-driver-gl.h
@@ -0,0 +1,53 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2007,2008,2009 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifndef __COGL_CONTEXT_DRIVER_H
+#define __COGL_CONTEXT_DRIVER_H
+
+#include "cogl.h"
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+
+#define COGL_FEATURE_BEGIN(a, b, c, d, e, f, g)
+
+#define COGL_FEATURE_FUNCTION(ret, name, args) \
+ ret (APIENTRY * pf_ ## name) args;
+
+#define COGL_FEATURE_END()
+
+typedef struct _CoglContextDriver
+{
+ /* This defines a list of function pointers */
+#include "cogl-feature-functions-gl.h"
+
+ GLint gl_max_program_temoraries_arb;
+} CoglContextDriver;
+
+#undef COGL_FEATURE_BEGIN
+#undef COGL_FEATURE_FUNCTION
+#undef COGL_FEATURE_END
+
+#endif /* __COGL_CONTEXT_DRIVER_H */
+
diff --git a/clutter/cogl/cogl/driver/gl/cogl-gl.c b/clutter/cogl/cogl/driver/gl/cogl-gl.c
index b26f230..b5a3bee 100644
--- a/clutter/cogl/cogl/driver/gl/cogl-gl.c
+++ b/clutter/cogl/cogl/driver/gl/cogl-gl.c
@@ -29,6 +29,7 @@
#include "cogl.h"
+#include "cogl-private.h"
#include "cogl-internal.h"
#include "cogl-context-private.h"
#include "cogl-feature-private.h"
@@ -95,7 +96,7 @@ _cogl_get_gl_version (int *major_out, int *minor_out)
}
gboolean
-_cogl_check_driver_valid (GError **error)
+_cogl_gl_check_version (GError **error)
{
int major, minor;
const char *gl_extensions;
@@ -161,8 +162,8 @@ _cogl_check_driver_valid (GError **error)
namespaces, extension_names, \
feature_flags, feature_flags_private) \
{ min_gl_major, min_gl_minor, namespaces, \
- extension_names, feature_flags, feature_flags_private, \
- cogl_feature_ ## name ## _funcs },
+ extension_names, feature_flags, feature_flags_private, 0, \
+ cogl_feature_ ## name ## _funcs },
#undef COGL_FEATURE_FUNCTION
#define COGL_FEATURE_FUNCTION(ret, name, args)
#undef COGL_FEATURE_END
@@ -182,23 +183,35 @@ static const CoglFeatureData cogl_feature_data[] =
#define COGL_FEATURE_END()
static void
-initialize_context_driver (CoglContext *context)
+initialize_function_table (CoglContext *context)
{
#include "cogl-feature-functions-gl.h"
}
+/* Query the GL extensions and lookup the corresponding function
+ * pointers. Theoretically the list of extensions can change for
+ * different GL contexts so it is the winsys backend's responsiblity
+ * to know when to re-query the GL extensions. */
void
-_cogl_gl_context_init (CoglContext *context)
+_cogl_gl_update_features (CoglContext *context)
{
CoglFeatureFlags flags = 0;
- CoglFeatureFlagsPrivate flags_private = 0;
const char *gl_extensions;
int max_clip_planes = 0;
int num_stencil_bits = 0;
int gl_major = 0, gl_minor = 0;
int i;
- initialize_context_driver (context);
+ COGL_NOTE (WINSYS,
+ "Checking features\n"
+ " GL_VENDOR: %s\n"
+ " GL_RENDERER: %s\n"
+ " GL_VERSION: %s\n"
+ " GL_EXTENSIONS: %s",
+ glGetString (GL_VENDOR),
+ glGetString (GL_RENDERER),
+ glGetString (GL_VERSION),
+ glGetString (GL_EXTENSIONS));
_cogl_get_gl_version (&gl_major, &gl_minor);
@@ -235,16 +248,15 @@ _cogl_gl_context_init (CoglContext *context)
if (max_clip_planes >= 4)
flags |= COGL_FEATURE_FOUR_CLIP_PLANES;
+ initialize_function_table (context);
+
for (i = 0; i < G_N_ELEMENTS (cogl_feature_data); i++)
if (_cogl_feature_check ("GL", cogl_feature_data + i,
gl_major, gl_minor,
- gl_extensions))
- {
- flags |= cogl_feature_data[i].feature_flags;
- flags_private |= cogl_feature_data[i].feature_flags_private;
- }
+ gl_extensions,
+ context))
+ flags |= cogl_feature_data[i].feature_flags;
/* Cache features */
- context->feature_flags = flags;
- context->feature_flags_private = flags_private;
+ context->feature_flags |= flags;
}
diff --git a/clutter/cogl/cogl/driver/gles/cogl-context-driver-gles.h b/clutter/cogl/cogl/driver/gles/cogl-context-driver-gles.h
new file mode 100644
index 0000000..ca3b1d4
--- /dev/null
+++ b/clutter/cogl/cogl/driver/gles/cogl-context-driver-gles.h
@@ -0,0 +1,52 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2007,2008,2009 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifndef __COGL_CONTEXT_DRIVER_H
+#define __COGL_CONTEXT_DRIVER_H
+
+#include "cogl.h"
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+
+#define COGL_FEATURE_BEGIN(a, b, c, d, e, f, g)
+
+#define COGL_FEATURE_FUNCTION(ret, name, args) \
+ ret (APIENTRY * pf_ ## name) args;
+
+#define COGL_FEATURE_END()
+
+typedef struct _CoglContextDriver
+{
+ /* This defines a list of function pointers */
+#include "cogl-feature-functions-gles.h"
+
+} CoglContextDriver;
+
+#undef COGL_FEATURE_BEGIN
+#undef COGL_FEATURE_FUNCTION
+#undef COGL_FEATURE_END
+
+#endif /* __COGL_CONTEXT_DRIVER_H */
+
diff --git a/clutter/cogl/cogl/driver/gles/cogl-gles.c b/clutter/cogl/cogl/driver/gles/cogl-gles.c
index 304e537..f137925 100644
--- a/clutter/cogl/cogl/driver/gles/cogl-gles.c
+++ b/clutter/cogl/cogl/driver/gles/cogl-gles.c
@@ -33,7 +33,7 @@
#include "cogl-feature-private.h"
gboolean
-_cogl_check_driver_valid (GError **error)
+_cogl_gl_check_version (GError **error)
{
/* The GLES backend doesn't have any particular version requirements */
return TRUE;
@@ -58,8 +58,8 @@ _cogl_check_driver_valid (GError **error)
namespaces, extension_names, \
feature_flags, feature_flags_private) \
{ min_gl_major, min_gl_minor, namespaces, \
- extension_names, feature_flags, feature_flags_private, \
- cogl_feature_ ## name ## _funcs },
+ extension_names, feature_flags, feature_flags_private, 0, \
+ cogl_feature_ ## name ## _funcs },
#undef COGL_FEATURE_FUNCTION
#define COGL_FEATURE_FUNCTION(ret, name, args)
#undef COGL_FEATURE_END
@@ -74,36 +74,44 @@ static const CoglFeatureData cogl_feature_data[] =
#define COGL_FEATURE_BEGIN(a, b, c, d, e, f, g)
#undef COGL_FEATURE_FUNCTION
#define COGL_FEATURE_FUNCTION(ret, name, args) \
- _context->drv.pf_ ## name = NULL;
+ context->drv.pf_ ## name = NULL;
#undef COGL_FEATURE_END
#define COGL_FEATURE_END()
static void
-initialize_context_driver (CoglContext *context)
+initialize_function_table (CoglContext *context)
{
#include "cogl-feature-functions-gles.h"
}
+/* Query the GL extensions and lookup the corresponding function
+ * pointers. Theoretically the list of extensions can change for
+ * different GL contexts so it is the winsys backend's responsiblity
+ * to know when to re-query the GL extensions. */
void
-_cogl_gl_context_init (CoglContext *context)
+_cogl_gl_update_features (CoglContext *context)
{
CoglFeatureFlags flags = 0;
+ const char *gl_extensions;
#ifndef HAVE_COGL_GLES2
int max_clip_planes = 0;
#endif
int num_stencil_bits = 0;
- const char *gl_extensions;
int i;
- initialize_context_driver (context);
+ COGL_NOTE (WINSYS,
+ "Checking features\n"
+ " GL_VENDOR: %s\n"
+ " GL_RENDERER: %s\n"
+ " GL_VERSION: %s\n"
+ " GL_EXTENSIONS: %s",
+ glGetString (GL_VENDOR),
+ glGetString (GL_RENDERER),
+ glGetString (GL_VERSION),
+ glGetString (GL_EXTENSIONS));
gl_extensions = (const char*) glGetString (GL_EXTENSIONS);
- for (i = 0; i < G_N_ELEMENTS (cogl_feature_data); i++)
- if (_cogl_feature_check ("GL", cogl_feature_data + i,
- 0, 0,
- gl_extensions))
- flags |= cogl_feature_data[i].feature_flags;
GE( glGetIntegerv (GL_STENCIL_BITS, &num_stencil_bits) );
/* We need at least three stencil bits to combine clips */
@@ -128,7 +136,15 @@ _cogl_gl_context_init (CoglContext *context)
/* Both GLES 1.1 and GLES 2.0 support point sprites in core */
flags |= COGL_FEATURE_POINT_SPRITE;
+ initialize_function_table (context);
+
+ for (i = 0; i < G_N_ELEMENTS (cogl_feature_data); i++)
+ if (_cogl_feature_check ("GL", cogl_feature_data + i,
+ 0, 0,
+ gl_extensions,
+ context))
+ flags |= cogl_feature_data[i].feature_flags;
+
/* Cache features */
- context->feature_flags = flags;
+ context->feature_flags |= flags;
}
-
diff --git a/clutter/cogl/cogl/winsys/cogl-texture-pixmap-x11.c b/clutter/cogl/cogl/winsys/cogl-texture-pixmap-x11.c
index 98ecf31..9f8ec69 100644
--- a/clutter/cogl/cogl/winsys/cogl-texture-pixmap-x11.c
+++ b/clutter/cogl/cogl/winsys/cogl-texture-pixmap-x11.c
@@ -42,7 +42,11 @@
#include "cogl-texture-rectangle-private.h"
#include "cogl-context-private.h"
#include "cogl-handle.h"
-#include "cogl-winsys-xlib.h"
+#if COGL_HAS_GLX_SUPPORT
+#include "cogl-display-glx-private.h"
+#include "cogl-renderer-private.h"
+#include "cogl-renderer-glx-private.h"
+#endif
#include "cogl-pipeline-opengl-private.h"
#include <X11/Xlib.h>
@@ -55,9 +59,6 @@
#include <string.h>
#include <math.h>
-#define glXBindTexImage ctx->winsys.pf_glXBindTexImage
-#define glXReleaseTexImage ctx->winsys.pf_glXReleaseTexImage
-
static void _cogl_texture_pixmap_x11_free (CoglTexturePixmapX11 *tex_pixmap);
COGL_TEXTURE_DEFINE (TexturePixmapX11, texture_pixmap_x11);
@@ -112,7 +113,7 @@ process_damage_event (CoglTexturePixmapX11 *tex_pixmap,
_COGL_GET_CONTEXT (ctxt, NO_RETVAL);
- display = _cogl_xlib_get_display ();
+ display = cogl_xlib_get_display ();
COGL_NOTE (TEXTURE_PIXMAP, "Damage event received for %p", tex_pixmap);
@@ -206,10 +207,12 @@ static CoglXlibFilterReturn
_cogl_texture_pixmap_x11_filter (XEvent *event, gpointer data)
{
CoglTexturePixmapX11 *tex_pixmap = data;
+ int damage_base;
_COGL_GET_CONTEXT (ctxt, COGL_XLIB_FILTER_CONTINUE);
- if (event->type == ctxt->winsys.damage_base + XDamageNotify)
+ damage_base = _cogl_xlib_get_damage_base ();
+ if (event->type == damage_base + XDamageNotify)
{
XDamageNotifyEvent *damage_event = (XDamageNotifyEvent *) event;
@@ -228,26 +231,28 @@ get_fbconfig_for_depth (unsigned int depth,
gboolean *can_mipmap_ret)
{
GLXFBConfig *fbconfigs;
- int n_elements, i;
- Display *dpy;
- int db, stencil, alpha, mipmap, rgba, value;
- int spare_cache_slot = 0;
- gboolean found = FALSE;
+ int n_elements, i;
+ Display *dpy;
+ int db, stencil, alpha, mipmap, rgba, value;
+ int spare_cache_slot = 0;
+ gboolean found = FALSE;
+ CoglDisplayGLX *glx_display;
_COGL_GET_CONTEXT (ctxt, FALSE);
+ glx_display = ctxt->display->winsys;
/* Check if we've already got a cached config for this depth */
- for (i = 0; i < COGL_WINSYS_N_CACHED_CONFIGS; i++)
- if (ctxt->winsys.glx_cached_configs[i].depth == -1)
+ for (i = 0; i < COGL_GLX_N_CACHED_CONFIGS; i++)
+ if (glx_display->glx_cached_configs[i].depth == -1)
spare_cache_slot = i;
- else if (ctxt->winsys.glx_cached_configs[i].depth == depth)
+ else if (glx_display->glx_cached_configs[i].depth == depth)
{
- *fbconfig_ret = ctxt->winsys.glx_cached_configs[i].fb_config;
- *can_mipmap_ret = ctxt->winsys.glx_cached_configs[i].can_mipmap;
- return ctxt->winsys.glx_cached_configs[i].found;
+ *fbconfig_ret = glx_display->glx_cached_configs[i].fb_config;
+ *can_mipmap_ret = glx_display->glx_cached_configs[i].can_mipmap;
+ return glx_display->glx_cached_configs[i].found;
}
- dpy = _cogl_xlib_get_display ();
+ dpy = cogl_xlib_get_display ();
fbconfigs = glXGetFBConfigs (dpy, DefaultScreen (dpy),
&n_elements);
@@ -349,10 +354,10 @@ get_fbconfig_for_depth (unsigned int depth,
if (n_elements)
XFree (fbconfigs);
- ctxt->winsys.glx_cached_configs[spare_cache_slot].depth = depth;
- ctxt->winsys.glx_cached_configs[spare_cache_slot].found = found;
- ctxt->winsys.glx_cached_configs[spare_cache_slot].fb_config = *fbconfig_ret;
- ctxt->winsys.glx_cached_configs[spare_cache_slot].can_mipmap = mipmap;
+ glx_display->glx_cached_configs[spare_cache_slot].depth = depth;
+ glx_display->glx_cached_configs[spare_cache_slot].found = found;
+ glx_display->glx_cached_configs[spare_cache_slot].fb_config = *fbconfig_ret;
+ glx_display->glx_cached_configs[spare_cache_slot].can_mipmap = mipmap;
return found;
}
@@ -362,7 +367,7 @@ should_use_rectangle (void)
{
_COGL_GET_CONTEXT (ctxt, FALSE);
- if (ctxt->winsys.rectangle_state == COGL_WINSYS_RECTANGLE_STATE_UNKNOWN)
+ if (ctxt->rectangle_state == COGL_WINSYS_RECTANGLE_STATE_UNKNOWN)
{
if (cogl_features_available (COGL_FEATURE_TEXTURE_RECTANGLE))
{
@@ -378,7 +383,7 @@ should_use_rectangle (void)
the env var is set to 'allow' or not set and NPOTs textures
are not available */
- ctxt->winsys.rectangle_state =
+ ctxt->rectangle_state =
cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) ?
COGL_WINSYS_RECTANGLE_STATE_DISABLE :
COGL_WINSYS_RECTANGLE_STATE_ENABLE;
@@ -389,10 +394,10 @@ should_use_rectangle (void)
(rect_env = g_getenv ("CLUTTER_PIXMAP_TEXTURE_RECTANGLE")))
{
if (g_ascii_strcasecmp (rect_env, "force") == 0)
- ctxt->winsys.rectangle_state =
+ ctxt->rectangle_state =
COGL_WINSYS_RECTANGLE_STATE_ENABLE;
else if (g_ascii_strcasecmp (rect_env, "disable") == 0)
- ctxt->winsys.rectangle_state =
+ ctxt->rectangle_state =
COGL_WINSYS_RECTANGLE_STATE_DISABLE;
else if (g_ascii_strcasecmp (rect_env, "allow"))
g_warning ("Unknown value for COGL_PIXMAP_TEXTURE_RECTANGLE, "
@@ -400,10 +405,10 @@ should_use_rectangle (void)
}
}
else
- ctxt->winsys.rectangle_state = COGL_WINSYS_RECTANGLE_STATE_DISABLE;
+ ctxt->rectangle_state = COGL_WINSYS_RECTANGLE_STATE_DISABLE;
}
- return ctxt->winsys.rectangle_state == COGL_WINSYS_RECTANGLE_STATE_ENABLE;
+ return ctxt->rectangle_state == COGL_WINSYS_RECTANGLE_STATE_ENABLE;
}
static void
@@ -425,11 +430,10 @@ try_create_glx_pixmap (CoglTexturePixmapX11 *tex_pixmap,
tex_pixmap->pixmap_bound = FALSE;
tex_pixmap->glx_pixmap = None;
- if ((ctxt->winsys.feature_flags &
- COGL_WINSYS_FEATURE_TEXTURE_FROM_PIXMAP) == 0)
+ if (!_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_TEXTURE_FROM_PIXMAP))
return;
- dpy = _cogl_xlib_get_display ();
+ dpy = cogl_xlib_get_display ();
if (!get_fbconfig_for_depth (tex_pixmap->depth, &fb_config,
&tex_pixmap->glx_can_mipmap))
@@ -507,7 +511,7 @@ set_damage_object_internal (CoglTexturePixmapX11 *tex_pixmap,
if (tex_pixmap->damage_owned)
{
- XDamageDestroy (_cogl_xlib_get_display (), tex_pixmap->damage);
+ XDamageDestroy (cogl_xlib_get_display (), tex_pixmap->damage);
tex_pixmap->damage_owned = FALSE;
}
}
@@ -524,12 +528,13 @@ cogl_texture_pixmap_x11_new (guint32 pixmap,
gboolean automatic_updates)
{
CoglTexturePixmapX11 *tex_pixmap = g_new (CoglTexturePixmapX11, 1);
- Display *display = _cogl_xlib_get_display ();
+ Display *display = cogl_xlib_get_display ();
Window pixmap_root_window;
int pixmap_x, pixmap_y;
unsigned int pixmap_border_width;
CoglTexture *tex = COGL_TEXTURE (tex_pixmap);
XWindowAttributes window_attributes;
+ int damage_base;
_COGL_GET_CONTEXT (ctxt, COGL_INVALID_HANDLE);
@@ -565,7 +570,8 @@ cogl_texture_pixmap_x11_new (guint32 pixmap,
/* If automatic updates are requested and the Xlib connection
supports damage events then we'll register a damage object on the
pixmap */
- if (automatic_updates && ctxt->winsys.damage_base >= 0)
+ damage_base = _cogl_xlib_get_damage_base ();
+ if (automatic_updates && damage_base >= 0)
{
Damage damage = XDamageCreate (display,
pixmap,
@@ -601,7 +607,7 @@ try_alloc_shm (CoglTexturePixmapX11 *tex_pixmap)
XImage *dummy_image;
Display *display;
- display = _cogl_xlib_get_display ();
+ display = cogl_xlib_get_display ();
if (!XShmQueryExtension (display))
return;
@@ -709,13 +715,15 @@ cogl_texture_pixmap_x11_set_damage_object (CoglHandle handle,
report_level)
{
CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (handle);
+ int damage_base;
_COGL_GET_CONTEXT (ctxt, NO_RETVAL);
if (!cogl_is_texture_pixmap_x11 (tex_pixmap))
return;
- if (ctxt->winsys.damage_base >= 0)
+ damage_base = _cogl_xlib_get_damage_base ();
+ if (damage_base >= 0)
set_damage_object_internal (tex_pixmap, damage, report_level);
}
@@ -728,7 +736,7 @@ _cogl_texture_pixmap_x11_update_image_texture (CoglTexturePixmapX11 *tex_pixmap)
int src_x, src_y;
int x, y, width, height;
- display = _cogl_xlib_get_display ();
+ display = cogl_xlib_get_display ();
/* If the damage region is empty then there's nothing to do */
if (tex_pixmap->damage_rect.x2 == tex_pixmap->damage_rect.x1)
@@ -889,12 +897,15 @@ _cogl_texture_pixmap_x11_free_glx_pixmap (CoglTexturePixmapX11 *tex_pixmap)
if (tex_pixmap->glx_pixmap)
{
CoglXlibTrapState trap_state;
+ CoglRendererGLX *glx_renderer;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ glx_renderer = ctx->display->renderer->winsys;
if (tex_pixmap->pixmap_bound)
- glXReleaseTexImage (_cogl_xlib_get_display (), tex_pixmap->glx_pixmap,
- GLX_FRONT_LEFT_EXT);
+ glx_renderer->pf_glXReleaseTexImage (cogl_xlib_get_display (),
+ tex_pixmap->glx_pixmap,
+ GLX_FRONT_LEFT_EXT);
/* FIXME - we need to trap errors and synchronize here because
* of ordering issues between the XPixmap destruction and the
@@ -913,8 +924,8 @@ _cogl_texture_pixmap_x11_free_glx_pixmap (CoglTexturePixmapX11 *tex_pixmap)
* http://bugzilla.clutter-project.org/show_bug.cgi?id=2324
*/
_cogl_xlib_trap_errors (&trap_state);
- glXDestroyPixmap (_cogl_xlib_get_display (), tex_pixmap->glx_pixmap);
- XSync (_cogl_xlib_get_display (), False);
+ glXDestroyPixmap (cogl_xlib_get_display (), tex_pixmap->glx_pixmap);
+ XSync (cogl_xlib_get_display (), False);
_cogl_xlib_untrap_errors (&trap_state);
tex_pixmap->glx_pixmap = None;
@@ -927,8 +938,10 @@ _cogl_texture_pixmap_x11_update_glx_texture (CoglTexturePixmapX11 *tex_pixmap,
gboolean needs_mipmap)
{
gboolean ret = TRUE;
+ CoglRendererGLX *glx_renderer;
_COGL_GET_CONTEXT (ctx, FALSE);
+ glx_renderer = ctx->display->renderer->winsys;
/* If we don't have a GLX pixmap then fallback */
if (tex_pixmap->glx_pixmap == None)
@@ -1031,14 +1044,14 @@ _cogl_texture_pixmap_x11_update_glx_texture (CoglTexturePixmapX11 *tex_pixmap,
GE( _cogl_bind_gl_texture_transient (gl_target, gl_handle, FALSE) );
if (tex_pixmap->pixmap_bound)
- glXReleaseTexImage (_cogl_xlib_get_display (),
- tex_pixmap->glx_pixmap,
- GLX_FRONT_LEFT_EXT);
+ glx_renderer->pf_glXReleaseTexImage (cogl_xlib_get_display (),
+ tex_pixmap->glx_pixmap,
+ GLX_FRONT_LEFT_EXT);
- glXBindTexImage (_cogl_xlib_get_display (),
- tex_pixmap->glx_pixmap,
- GLX_FRONT_LEFT_EXT,
- NULL);
+ glx_renderer->pf_glXBindTexImage (cogl_xlib_get_display (),
+ tex_pixmap->glx_pixmap,
+ GLX_FRONT_LEFT_EXT,
+ NULL);
/* According to the recommended usage in the spec for
GLX_EXT_texture_pixmap we should release the texture after
@@ -1373,7 +1386,7 @@ _cogl_texture_pixmap_x11_free (CoglTexturePixmapX11 *tex_pixmap)
if (tex_pixmap->shm_info.shmid != -1)
{
- XShmDetach (_cogl_xlib_get_display (), &tex_pixmap->shm_info);
+ XShmDetach (cogl_xlib_get_display (), &tex_pixmap->shm_info);
shmdt (tex_pixmap->shm_info.shmaddr);
shmctl (tex_pixmap->shm_info.shmid, IPC_RMID, 0);
}
diff --git a/clutter/cogl/cogl/winsys/cogl-winsys-glx-feature-functions.h b/clutter/cogl/cogl/winsys/cogl-winsys-glx-feature-functions.h
new file mode 100644
index 0000000..50df562
--- /dev/null
+++ b/clutter/cogl/cogl/winsys/cogl-winsys-glx-feature-functions.h
@@ -0,0 +1,105 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+/* This can be included multiple times with different definitions for
+ * the COGL_WINSYS_FEATURE_* functions.
+ */
+
+/* Macro prototypes:
+ * COGL_WINSYS_FEATURE_BEGIN (name, namespaces, extension_names,
+ * implied_public_feature_flags,
+ * implied_private_feature_flags,
+ * implied_winsys_feature)
+ * COGL_WINSYS_FEATURE_FUNCTION (return_type, function_name,
+ * (arguments))
+ * ...
+ * COGL_WINSYS_FEATURE_END ()
+ *
+ * Note: You can list multiple namespace and extension names if the
+ * corresponding _FEATURE_FUNCTIONS have the same semantics accross
+ * the different extension variants.
+ *
+ * XXX: NB: Don't add a trailing semicolon when using these macros
+ */
+
+COGL_WINSYS_FEATURE_BEGIN (texture_from_pixmap,
+ "EXT\0",
+ "texture_from_pixmap\0",
+ 0,
+ 0,
+ COGL_WINSYS_FEATURE_TEXTURE_FROM_PIXMAP)
+COGL_WINSYS_FEATURE_FUNCTION (void, glXBindTexImage,
+ (Display *display,
+ GLXDrawable drawable,
+ int buffer,
+ int *attribList))
+COGL_WINSYS_FEATURE_FUNCTION (void, glXReleaseTexImage,
+ (Display *display,
+ GLXDrawable drawable,
+ int buffer))
+COGL_WINSYS_FEATURE_END ()
+
+COGL_WINSYS_FEATURE_BEGIN (video_sync,
+ "SGI\0",
+ "video_sync\0",
+ 0,
+ 0,
+ COGL_WINSYS_FEATURE_VBLANK_COUNTER)
+COGL_WINSYS_FEATURE_FUNCTION (int, glXGetVideoSync,
+ (unsigned int *count))
+COGL_WINSYS_FEATURE_FUNCTION (int, glXWaitVideoSync,
+ (int divisor,
+ int remainder,
+ unsigned int *count))
+COGL_WINSYS_FEATURE_END ()
+
+COGL_WINSYS_FEATURE_BEGIN (swap_control,
+ "SGI\0",
+ "swap_control\0",
+ 0,
+ 0,
+ COGL_WINSYS_FEATURE_SWAP_THROTTLE)
+COGL_WINSYS_FEATURE_FUNCTION (int, glXSwapInterval,
+ (int interval))
+COGL_WINSYS_FEATURE_END ()
+
+COGL_WINSYS_FEATURE_BEGIN (copy_sub_buffer,
+ "MESA\0",
+ "copy_sub_buffer\0",
+ 0,
+ 0,
+ 0)
+COGL_WINSYS_FEATURE_FUNCTION (void, glXCopySubBuffer,
+ (Display *dpy,
+ GLXDrawable drawable,
+ int x, int y, int width, int height))
+COGL_WINSYS_FEATURE_END ()
+
+COGL_WINSYS_FEATURE_BEGIN (swap_event,
+ "INTEL\0",
+ "swap_event\0",
+ 0,
+ 0,
+ COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT)
+COGL_WINSYS_FEATURE_END ()
diff --git a/clutter/cogl/cogl/winsys/cogl-winsys-glx.c b/clutter/cogl/cogl/winsys/cogl-winsys-glx.c
index c0f6d5c..2a81d3a 100644
--- a/clutter/cogl/cogl/winsys/cogl-winsys-glx.c
+++ b/clutter/cogl/cogl/winsys/cogl-winsys-glx.c
@@ -3,7 +3,7 @@
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
- * Copyright (C) 2007,2008,2009 Intel Corporation.
+ * Copyright (C) 2007,2008,2009,2010,2011 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -16,9 +16,12 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
*
*
+ * Authors:
+ * Robert Bragg <robert linux intel com>
*/
#ifdef HAVE_CONFIG_H
@@ -27,19 +30,102 @@
#include "cogl.h"
-#ifdef HAVE_CLUTTER_GLX
+#include "cogl-winsys-private.h"
+#include "cogl-feature-private.h"
+#include "cogl-context-private.h"
+#include "cogl-framebuffer.h"
+#include "cogl-swap-chain-private.h"
+#include "cogl-renderer-private.h"
+#include "cogl-renderer-glx-private.h"
+#include "cogl-onscreen-template-private.h"
+#include "cogl-display-xlib-private.h"
+#include "cogl-display-glx-private.h"
+#include "cogl-private.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <glib/gi18n-lib.h>
+
#include <dlfcn.h>
#include <GL/glx.h>
+#include <X11/Xlib.h>
typedef CoglFuncPtr (*GLXGetProcAddressProc) (const GLubyte *procName);
+
+#ifdef HAVE_DRM
+#include <drm.h>
+#include <sys/ioctl.h>
+#include <errno.h>
#endif
+typedef struct _CoglContextGLX
+{
+ GLXDrawable current_drawable;
+} CoglContextGLX;
+
+typedef struct _CoglOnscreenXlib
+{
+ Window xwin;
+ gboolean is_foreign_xwin;
+} CoglOnscreenXlib;
+
+typedef struct _CoglOnscreenGLX
+{
+ CoglOnscreenXlib _parent;
+ GLXDrawable glxwin;
+ guint32 last_swap_vsync_counter;
+ GList *swap_callbacks;
+} CoglOnscreenGLX;
+
+typedef struct _CoglSwapBuffersNotifyEntry
+{
+ CoglSwapBuffersNotify callback;
+ void *user_data;
+ unsigned int id;
+} CoglSwapBuffersNotifyEntry;
+
+
+/* Define a set of arrays containing the functions required from GL
+ for each winsys feature */
+#define COGL_WINSYS_FEATURE_BEGIN(name, namespaces, extension_names, \
+ feature_flags, feature_flags_private, \
+ winsys_feature) \
+ static const CoglFeatureFunction \
+ cogl_glx_feature_ ## name ## _funcs[] = {
+#define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) \
+ { G_STRINGIFY (name), G_STRUCT_OFFSET (CoglRendererGLX, pf_ ## name) },
+#define COGL_WINSYS_FEATURE_END() \
+ { NULL, 0 }, \
+ };
+#include "cogl-winsys-glx-feature-functions.h"
+
+/* Define an array of features */
+#undef COGL_WINSYS_FEATURE_BEGIN
+#define COGL_WINSYS_FEATURE_BEGIN(name, namespaces, extension_names, \
+ feature_flags, feature_flags_private, \
+ winsys_feature) \
+ { 255, 255, namespaces, extension_names, \
+ feature_flags, feature_flags_private, \
+ winsys_feature, \
+ cogl_glx_feature_ ## name ## _funcs },
+#undef COGL_WINSYS_FEATURE_FUNCTION
+#define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args)
+#undef COGL_WINSYS_FEATURE_END
+#define COGL_WINSYS_FEATURE_END()
+
+static const CoglFeatureData winsys_feature_data[] =
+ {
+#include "cogl-winsys-glx-feature-functions.h"
+ };
CoglFuncPtr
_cogl_winsys_get_proc_address (const char *name)
{
static GLXGetProcAddressProc get_proc_func = NULL;
- static void *dlhand = NULL;
+ static void *dlhand = NULL;
if (get_proc_func == NULL && dlhand == NULL)
{
@@ -76,3 +162,1171 @@ _cogl_winsys_get_proc_address (const char *name)
return NULL;
}
+#undef COGL_WINSYS_FEATURE_BEGIN
+#define COGL_WINSYS_FEATURE_BEGIN(a, b, c, d, e, f)
+#undef COGL_WINSYS_FEATURE_FUNCTION
+#define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) \
+ glx_renderer->pf_ ## name = NULL;
+#undef COGL_WINSYS_FEATURE_END
+#define COGL_WINSYS_FEATURE_END()
+
+static void
+initialize_function_table (CoglRenderer *renderer)
+{
+ CoglRendererGLX *glx_renderer = renderer->winsys;
+
+#include "cogl-winsys-glx-feature-functions.h"
+}
+
+static CoglOnscreen *
+find_onscreen_for_xid (CoglContext *context, guint32 xid)
+{
+ GList *l;
+
+ for (l = context->framebuffers; l; l = l->next)
+ {
+ CoglFramebuffer *framebuffer = l->data;
+ CoglOnscreenXlib *xlib_onscreen;
+
+ if (!framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
+ continue;
+
+ /* Does the GLXEvent have the GLXDrawable or the X Window? */
+ xlib_onscreen = COGL_ONSCREEN (framebuffer)->winsys;
+ if (xlib_onscreen->xwin == (Window)xid)
+ return COGL_ONSCREEN (framebuffer);
+ }
+
+ return NULL;
+}
+
+static void
+notify_swap_buffers (CoglContext *context, GLXDrawable drawable)
+{
+ CoglOnscreen *onscreen = find_onscreen_for_xid (context, (guint32)drawable);
+ CoglOnscreenGLX *glx_onscreen;
+ GList *l;
+
+ if (!onscreen)
+ return;
+
+ glx_onscreen = onscreen->winsys;
+
+ for (l = glx_onscreen->swap_callbacks; l; l = l->next)
+ {
+ CoglSwapBuffersNotifyEntry *entry = l->data;
+ entry->callback (COGL_FRAMEBUFFER (onscreen), entry->user_data);
+ }
+}
+
+static CoglXlibFilterReturn
+glx_event_filter_cb (XEvent *xevent, void *data)
+{
+ CoglContext *context = data;
+ CoglRendererGLX *glx_renderer = context->display->renderer->winsys;
+
+ if (xevent->type == ConfigureNotify)
+ {
+ CoglOnscreen *onscreen =
+ find_onscreen_for_xid (context, xevent->xconfigure.window);
+
+ if (onscreen)
+ {
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+
+ _cogl_framebuffer_winsys_update_size (framebuffer,
+ xevent->xconfigure.width,
+ xevent->xconfigure.height);
+ }
+ }
+ else if (xevent->type ==
+ (glx_renderer->glx_event_base + GLX_BufferSwapComplete))
+ {
+ GLXBufferSwapComplete *swap_event = (GLXBufferSwapComplete *)xevent;
+ notify_swap_buffers (context, swap_event->drawable);
+ return COGL_XLIB_FILTER_REMOVE;
+ }
+
+ return COGL_XLIB_FILTER_CONTINUE;
+}
+
+gboolean
+_cogl_winsys_renderer_connect (CoglRenderer *renderer,
+ GError **error)
+{
+ CoglRendererGLX *glx_renderer;
+ CoglRendererXlib *xlib_renderer;
+
+ renderer->winsys = g_slice_new0 (CoglRendererGLX);
+
+ glx_renderer = renderer->winsys;
+ xlib_renderer = renderer->winsys;
+
+ if (!_cogl_renderer_xlib_connect (renderer, error))
+ goto error;
+
+ if (!glXQueryExtension (xlib_renderer->xdpy,
+ &glx_renderer->glx_error_base,
+ &glx_renderer->glx_event_base))
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_INIT,
+ "XServer appears to lack required GLX support");
+ goto error;
+ }
+
+ /* XXX: Note: For a long time Mesa exported a hybrid GLX, exporting
+ * extensions specified to require GLX 1.3, but still reporting 1.2
+ * via glXQueryVersion. */
+ if (!glXQueryVersion (xlib_renderer->xdpy,
+ &glx_renderer->glx_major,
+ &glx_renderer->glx_minor)
+ || !(glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 2))
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_INIT,
+ "XServer appears to lack required GLX 1.2 support");
+ goto error;
+ }
+
+ glx_renderer->dri_fd = -1;
+
+ return TRUE;
+
+error:
+ _cogl_winsys_renderer_disconnect (renderer);
+ return FALSE;
+}
+
+void
+_cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
+{
+ _cogl_renderer_xlib_disconnect (renderer);
+
+ g_slice_free (CoglRendererGLX, renderer->winsys);
+}
+
+void
+update_winsys_features (CoglContext *context)
+{
+ CoglDisplayGLX *glx_display = context->display->winsys;
+ CoglRendererXlib *xlib_renderer = context->display->renderer->winsys;
+ CoglRendererGLX *glx_renderer = context->display->renderer->winsys;
+ const char *glx_extensions;
+ int i;
+
+ g_return_if_fail (glx_display->glx_context);
+
+ _cogl_gl_update_features (context);
+
+ _cogl_bitmask_init (&context->winsys_features);
+
+ glx_extensions =
+ glXQueryExtensionsString (xlib_renderer->xdpy,
+ DefaultScreen (xlib_renderer->xdpy));
+
+ COGL_NOTE (WINSYS, " GLX Extensions: %s", glx_extensions);
+
+ context->feature_flags |= COGL_FEATURE_ONSCREEN_MULTIPLE;
+ _cogl_bitmask_set (&context->winsys_features,
+ COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN,
+ TRUE);
+
+ initialize_function_table (context->display->renderer);
+
+ for (i = 0; i < G_N_ELEMENTS (winsys_feature_data); i++)
+ if (_cogl_feature_check ("GLX", winsys_feature_data + i, 0, 0,
+ glx_extensions,
+ glx_renderer))
+ {
+ context->feature_flags |= winsys_feature_data[i].feature_flags;
+ if (winsys_feature_data[i].winsys_feature)
+ _cogl_bitmask_set (&context->winsys_features,
+ winsys_feature_data[i].winsys_feature,
+ TRUE);
+ }
+
+ /* Note: the GLX_SGI_video_sync spec explicitly states this extension
+ * only works for direct contexts. */
+ if (!glx_renderer->is_direct)
+ {
+ glx_renderer->pf_glXGetVideoSync = NULL;
+ glx_renderer->pf_glXWaitVideoSync = NULL;
+ }
+
+ if (glx_renderer->pf_glXWaitVideoSync)
+ _cogl_bitmask_set (&context->winsys_features,
+ COGL_WINSYS_FEATURE_VBLANK_WAIT,
+ TRUE);
+
+#ifdef HAVE_DRM
+ /* drm is really an extreme fallback -rumoured to work with Via
+ * chipsets... */
+ if (!glx_renderer->pf_glXWaitVideoSync)
+ {
+ if (glx_renderer->dri_fd < 0)
+ glx_renderer->dri_fd = open("/dev/dri/card0", O_RDWR);
+ if (glx_renderer->dri_fd >= 0)
+ _cogl_bitmask_set (&context->winsys_features,
+ COGL_WINSYS_FEATURE_VBLANK_WAIT,
+ TRUE);
+ }
+#endif
+
+ if (glx_renderer->pf_glXCopySubBuffer || context->drv.pf_glBlitFramebuffer)
+ _cogl_bitmask_set (&context->winsys_features,
+ COGL_WINSYS_FEATURE_SWAP_REGION, TRUE);
+
+ /* Note: glXCopySubBuffer and glBlitFramebuffer won't be throttled
+ * by the SwapInterval so we have to throttle swap_region requests
+ * manually... */
+ if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION) &&
+ _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_WAIT))
+ _cogl_bitmask_set (&context->winsys_features,
+ COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, TRUE);
+}
+
+/* It seems the GLX spec never defined an invalid GLXFBConfig that
+ * we could overload as an indication of error, so we have to return
+ * an explicit boolean status. */
+static gboolean
+find_fbconfig (CoglDisplay *display,
+ gboolean with_alpha,
+ GLXFBConfig *config_ret,
+ GError **error)
+{
+ CoglRendererXlib *xlib_renderer = display->renderer->winsys;
+ GLXFBConfig *configs = NULL;
+ int n_configs, i;
+ static const int attributes[] = {
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DOUBLEBUFFER, GL_TRUE,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_ALPHA_SIZE, 1,
+ GLX_DEPTH_SIZE, 1,
+ GLX_STENCIL_SIZE, 1,
+ None
+ };
+ gboolean ret = TRUE;
+ int xscreen_num = DefaultScreen (xlib_renderer->xdpy);
+
+ configs = glXChooseFBConfig (xlib_renderer->xdpy,
+ xscreen_num,
+ attributes,
+ &n_configs);
+ if (!configs || n_configs == 0)
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_CONTEXT,
+ "Failed to find any compatible fbconfigs");
+ ret = FALSE;
+ goto done;
+ }
+
+ if (with_alpha)
+ {
+ for (i = 0; i < n_configs; i++)
+ {
+ XVisualInfo *vinfo;
+
+ vinfo = glXGetVisualFromFBConfig (xlib_renderer->xdpy, configs[i]);
+ if (vinfo == NULL)
+ continue;
+
+ if (vinfo->depth == 32 &&
+ (vinfo->red_mask | vinfo->green_mask | vinfo->blue_mask)
+ != 0xffffffff)
+ {
+ COGL_NOTE (WINSYS, "Found an ARGB FBConfig [index:%d]", i);
+ *config_ret = configs[i];
+ goto done;
+ }
+ }
+
+ /* If we make it here then we didn't find an RGBA config so
+ we'll fall back to using an RGB config */
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_CONTEXT,
+ "Unable to find fbconfig with rgba visual");
+ ret = FALSE;
+ goto done;
+ }
+ else
+ {
+ COGL_NOTE (WINSYS, "Using the first available FBConfig");
+ *config_ret = configs[0];
+ }
+
+done:
+ XFree (configs);
+ return ret;
+}
+
+static gboolean
+create_context (CoglDisplay *display, GError **error)
+{
+ CoglDisplayGLX *glx_display = display->winsys;
+ CoglDisplayXlib *xlib_display = display->winsys;
+ CoglRendererXlib *xlib_renderer = display->renderer->winsys;
+ CoglRendererGLX *glx_renderer = display->renderer->winsys;
+ gboolean support_transparent_windows;
+ GLXFBConfig config;
+ GError *fbconfig_error = NULL;
+ XSetWindowAttributes attrs;
+ XVisualInfo *xvisinfo;
+ GLXDrawable dummy_drawable;
+ CoglXlibTrapState old_state;
+
+ g_return_val_if_fail (glx_display->glx_context == NULL, TRUE);
+
+ if (display->onscreen_template &&
+ display->onscreen_template->swap_chain &&
+ display->onscreen_template->swap_chain->has_alpha)
+ support_transparent_windows = TRUE;
+ else
+ support_transparent_windows = FALSE;
+
+ glx_display->found_fbconfig =
+ find_fbconfig (display, support_transparent_windows, &config,
+ &fbconfig_error);
+ if (!glx_display->found_fbconfig)
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_CONTEXT,
+ "Unable to find suitable fbconfig for the GLX context: %s",
+ fbconfig_error->message);
+ g_error_free (fbconfig_error);
+ return FALSE;
+ }
+
+ glx_display->fbconfig = config;
+ glx_display->fbconfig_has_rgba_visual = support_transparent_windows;
+
+ COGL_NOTE (WINSYS, "Creating GLX Context (display: %p)",
+ xlib_renderer->xdpy);
+
+ glx_display->glx_context = glXCreateNewContext (xlib_renderer->xdpy,
+ config,
+ GLX_RGBA_TYPE,
+ NULL,
+ True);
+ if (glx_display->glx_context == NULL)
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_CONTEXT,
+ "Unable to create suitable GL context");
+ return FALSE;
+ }
+
+ glx_renderer->is_direct =
+ glXIsDirect (xlib_renderer->xdpy, glx_display->glx_context);
+
+ COGL_NOTE (WINSYS, "Setting %s context",
+ glx_renderer->is_direct ? "direct" : "indirect");
+
+ /* XXX: GLX doesn't let us make a context current without a window
+ * so we create a dummy window that we can use while no CoglOnscreen
+ * framebuffer is in use.
+ */
+
+ xvisinfo = glXGetVisualFromFBConfig (xlib_renderer->xdpy, config);
+ if (xvisinfo == NULL)
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_CONTEXT,
+ "Unable to retrieve the X11 visual");
+ return FALSE;
+ }
+
+ _cogl_renderer_xlib_trap_errors (display->renderer, &old_state);
+
+ attrs.override_redirect = True;
+ attrs.colormap = XCreateColormap (xlib_renderer->xdpy,
+ DefaultRootWindow (xlib_renderer->xdpy),
+ xvisinfo->visual,
+ AllocNone);
+ attrs.border_pixel = 0;
+
+ xlib_display->dummy_xwin =
+ XCreateWindow (xlib_renderer->xdpy,
+ DefaultRootWindow (xlib_renderer->xdpy),
+ -100, -100, 1, 1,
+ 0,
+ xvisinfo->depth,
+ CopyFromParent,
+ xvisinfo->visual,
+ CWOverrideRedirect | CWColormap | CWBorderPixel,
+ &attrs);
+
+ /* Try and create a GLXWindow to use with extensions dependent on
+ * GLX versions >= 1.3 that don't accept regular X Windows as GLX
+ * drawables. */
+ if (glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 3)
+ {
+ glx_display->dummy_glxwin = glXCreateWindow (xlib_renderer->xdpy,
+ config,
+ xlib_display->dummy_xwin,
+ NULL);
+ }
+
+ if (glx_display->dummy_glxwin)
+ dummy_drawable = glx_display->dummy_glxwin;
+ else
+ dummy_drawable = xlib_display->dummy_xwin;
+
+ COGL_NOTE (WINSYS, "Selecting dummy 0x%x for the GLX context",
+ (unsigned int) dummy_drawable);
+
+ glXMakeContextCurrent (xlib_renderer->xdpy,
+ dummy_drawable,
+ dummy_drawable,
+ glx_display->glx_context);
+
+ XFree (xvisinfo);
+
+ if (_cogl_renderer_xlib_untrap_errors (display->renderer, &old_state))
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_CONTEXT,
+ "Unable to select the newly created GLX context");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+_cogl_winsys_display_setup (CoglDisplay *display,
+ GError **error)
+{
+ CoglDisplayGLX *glx_display;
+ CoglDisplayXlib *xlib_display;
+ int i;
+
+ g_return_val_if_fail (display->winsys == NULL, FALSE);
+
+ glx_display = g_slice_new0 (CoglDisplayGLX);
+ display->winsys = glx_display;
+
+ xlib_display = display->winsys;
+
+ if (!create_context (display, error))
+ goto error;
+
+ for (i = 0; i < COGL_GLX_N_CACHED_CONFIGS; i++)
+ glx_display->glx_cached_configs[i].depth = -1;
+
+ return TRUE;
+
+error:
+ _cogl_winsys_display_destroy (display);
+ return FALSE;
+}
+
+void
+_cogl_winsys_display_destroy (CoglDisplay *display)
+{
+ CoglDisplayGLX *glx_display = display->winsys;
+ CoglDisplayXlib *xlib_display = display->winsys;
+ CoglRendererXlib *xlib_renderer = display->renderer->winsys;
+
+ g_return_if_fail (glx_display != NULL);
+
+ if (glx_display->glx_context)
+ {
+ glXMakeContextCurrent (xlib_renderer->xdpy, None, None, NULL);
+ glXDestroyContext (xlib_renderer->xdpy, glx_display->glx_context);
+ glx_display->glx_context = NULL;
+ }
+
+ if (glx_display->dummy_glxwin)
+ {
+ glXDestroyWindow (xlib_renderer->xdpy, glx_display->dummy_glxwin);
+ glx_display->dummy_glxwin = None;
+ }
+
+ if (xlib_display->dummy_xwin)
+ {
+ XDestroyWindow (xlib_renderer->xdpy, xlib_display->dummy_xwin);
+ xlib_display->dummy_xwin = None;
+ }
+
+ g_slice_free (CoglDisplayGLX, display->winsys);
+ display->winsys = NULL;
+}
+
+gboolean
+_cogl_winsys_context_init (CoglContext *context, GError **error)
+{
+ context->winsys = g_new0 (CoglContextGLX, 1);
+
+ cogl_renderer_xlib_add_filter (context->display->renderer,
+ glx_event_filter_cb,
+ context);
+ update_winsys_features (context);
+
+ return TRUE;
+}
+
+void
+_cogl_winsys_context_deinit (CoglContext *context)
+{
+ cogl_renderer_xlib_remove_filter (context->display->renderer,
+ glx_event_filter_cb,
+ context);
+ g_free (context->winsys);
+}
+
+gboolean
+_cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
+ GError **error)
+{
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+ CoglContext *context = framebuffer->context;
+ CoglDisplay *display = context->display;
+ CoglDisplayGLX *glx_display = display->winsys;
+ CoglRendererXlib *xlib_renderer = display->renderer->winsys;
+ CoglRendererGLX *glx_renderer = display->renderer->winsys;
+ Window xwin;
+ CoglOnscreenXlib *xlib_onscreen;
+ CoglOnscreenGLX *glx_onscreen;
+
+ g_return_val_if_fail (glx_display->glx_context, FALSE);
+
+ /* FIXME: We need to explicitly Select for ConfigureNotify events.
+ * For foreign windows we need to be careful not to mess up any
+ * existing event mask.
+ * We need to document that for windows we create then toolkits
+ * must be careful not to clear event mask bits that we select.
+ */
+
+ /* XXX: Note we ignore the user's original width/height when
+ * given a foreign X window. */
+ if (onscreen->foreign_xid)
+ {
+ Status status;
+ CoglXlibTrapState state;
+ XWindowAttributes attr;
+ int xerror;
+
+ xwin = onscreen->foreign_xid;
+
+ _cogl_renderer_xlib_trap_errors (display->renderer, &state);
+
+ status = XGetWindowAttributes (xlib_renderer->xdpy, xwin, &attr);
+ XSync (xlib_renderer->xdpy, False);
+ xerror = _cogl_renderer_xlib_untrap_errors (display->renderer, &state);
+ if (status == 0 || xerror)
+ {
+ char message[1000];
+ XGetErrorText (xlib_renderer->xdpy, xerror, message, sizeof(message));
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_ONSCREEN,
+ "Unable to query geometry of foreign xid 0x%08lX: %s",
+ xwin, message);
+ return FALSE;
+ }
+
+ _cogl_framebuffer_winsys_update_size (framebuffer,
+ attr.width, attr.height);
+ }
+ else
+ {
+ int width;
+ int height;
+ CoglXlibTrapState state;
+ XVisualInfo *xvisinfo;
+ XSetWindowAttributes xattr;
+ unsigned long mask;
+ int xerror;
+
+ width = _cogl_framebuffer_get_width (framebuffer);
+ height = _cogl_framebuffer_get_height (framebuffer);
+
+ _cogl_renderer_xlib_trap_errors (display->renderer, &state);
+
+ xvisinfo = glXGetVisualFromFBConfig (xlib_renderer->xdpy,
+ glx_display->fbconfig);
+ if (xvisinfo == NULL)
+ {
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_ONSCREEN,
+ "Unable to retrieve the X11 visual of context's "
+ "fbconfig");
+ return FALSE;
+ }
+
+ /* window attributes */
+ xattr.background_pixel = WhitePixel (xlib_renderer->xdpy,
+ DefaultScreen (xlib_renderer->xdpy));
+ xattr.border_pixel = 0;
+ /* XXX: is this an X resource that we are leakingâ?½... */
+ xattr.colormap = XCreateColormap (xlib_renderer->xdpy,
+ DefaultRootWindow (xlib_renderer->xdpy),
+ xvisinfo->visual,
+ AllocNone);
+ mask = CWBorderPixel | CWColormap;
+
+ xwin = XCreateWindow (xlib_renderer->xdpy,
+ DefaultRootWindow (xlib_renderer->xdpy),
+ 0, 0,
+ width, height,
+ 0,
+ xvisinfo->depth,
+ InputOutput,
+ xvisinfo->visual,
+ mask, &xattr);
+
+ XFree (xvisinfo);
+
+ XSync (xlib_renderer->xdpy, False);
+ xerror = _cogl_renderer_xlib_untrap_errors (display->renderer, &state);
+ if (xerror)
+ {
+ char message[1000];
+ XGetErrorText (xlib_renderer->xdpy, xerror,
+ message, sizeof (message));
+ g_set_error (error, COGL_WINSYS_ERROR,
+ COGL_WINSYS_ERROR_CREATE_ONSCREEN,
+ "X error while creating Window for CoglOnscreen: %s",
+ message);
+ return FALSE;
+ }
+ }
+
+ onscreen->winsys = g_slice_new0 (CoglOnscreenGLX);
+ xlib_onscreen = onscreen->winsys;
+ glx_onscreen = onscreen->winsys;
+
+ xlib_onscreen->xwin = xwin;
+ xlib_onscreen->is_foreign_xwin = onscreen->foreign_xid ? TRUE : FALSE;
+
+ /* Try and create a GLXWindow to use with extensions dependent on
+ * GLX versions >= 1.3 that don't accept regular X Windows as GLX
+ * drawables. */
+ if (glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 3)
+ {
+ glx_onscreen->glxwin =
+ glXCreateWindow (xlib_renderer->xdpy,
+ glx_display->fbconfig,
+ xlib_onscreen->xwin,
+ NULL);
+ }
+
+#ifdef GLX_INTEL_swap_event
+ if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
+ {
+ GLXDrawable drawable =
+ glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin;
+
+ /* similarly to above, we unconditionally select this event
+ * because we rely on it to advance the master clock, and
+ * drive redraw/relayout, animations and event handling.
+ */
+ glXSelectEvent (xlib_renderer->xdpy,
+ drawable,
+ GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK);
+ }
+#endif /* GLX_INTEL_swap_event */
+
+ return TRUE;
+}
+
+void
+_cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
+{
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+ CoglContext *context = framebuffer->context;
+ CoglRendererXlib *xlib_renderer = context->display->renderer->winsys;
+ CoglXlibTrapState old_state;
+ CoglOnscreenXlib *xlib_onscreen = onscreen->winsys;
+ CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
+
+ _cogl_xlib_trap_errors (&old_state);
+
+ if (glx_onscreen->glxwin != None)
+ {
+ glXDestroyWindow (xlib_renderer->xdpy, glx_onscreen->glxwin);
+ glx_onscreen->glxwin = None;
+ }
+
+ if (!xlib_onscreen->is_foreign_xwin && xlib_onscreen->xwin != None)
+ {
+ XDestroyWindow (xlib_renderer->xdpy, xlib_onscreen->xwin);
+ xlib_onscreen->xwin = None;
+ }
+ else
+ xlib_onscreen->xwin = None;
+
+ XSync (xlib_renderer->xdpy, False);
+
+ _cogl_xlib_untrap_errors (&old_state);
+}
+
+void
+_cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
+{
+ CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
+ CoglContextGLX *glx_context = context->winsys;
+ CoglDisplayXlib *xlib_display = context->display->winsys;
+ CoglDisplayGLX *glx_display = context->display->winsys;
+ CoglRendererXlib *xlib_renderer = context->display->renderer->winsys;
+ CoglRendererGLX *glx_renderer = context->display->renderer->winsys;
+ CoglOnscreenXlib *xlib_onscreen = onscreen->winsys;
+ CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
+ CoglXlibTrapState old_state;
+ GLXDrawable drawable;
+
+ if (G_UNLIKELY (!onscreen))
+ {
+ drawable =
+ glx_display->dummy_glxwin ?
+ glx_display->dummy_glxwin : xlib_display->dummy_xwin;
+
+ if (glx_context->current_drawable == drawable)
+ return;
+
+ _cogl_xlib_trap_errors (&old_state);
+
+ glXMakeContextCurrent (xlib_renderer->xdpy,
+ drawable, drawable,
+ glx_display->glx_context);
+ }
+ else
+ {
+ drawable =
+ glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin;
+
+ if (glx_context->current_drawable == drawable)
+ return;
+
+ _cogl_xlib_trap_errors (&old_state);
+
+ COGL_NOTE (WINSYS,
+ "MakeContextCurrent dpy: %p, window: 0x%x (%s), context: %p",
+ xlib_renderer->xdpy,
+ (unsigned int) drawable,
+ xlib_onscreen->is_foreign_xwin ? "foreign" : "native",
+ glx_display->glx_context);
+
+ glXMakeContextCurrent (xlib_renderer->xdpy,
+ drawable,
+ drawable,
+ glx_display->glx_context);
+
+ /* In case we are using GLX_SGI_swap_control for vblank syncing
+ * we need call glXSwapIntervalSGI here to make sure that it
+ * affects the current drawable.
+ *
+ * Note: we explicitly set to 0 when we aren't using the swap
+ * interval to synchronize since some drivers have a default
+ * swap interval of 1. Sadly some drivers even ignore requests
+ * to disable the swap interval.
+ *
+ * NB: glXSwapIntervalSGI applies to the context not the
+ * drawable which is why we can't just do this once when the
+ * framebuffer is allocated.
+ *
+ * FIXME: We should check for GLX_EXT_swap_control which allows
+ * per framebuffer swap intervals. GLX_MESA_swap_control also
+ * allows per-framebuffer swap intervals but the semantics tend
+ * to be more muddled since Mesa drivers tend to expose both the
+ * MESA and SGI extensions which should technically be mutually
+ * exclusive.
+ */
+ if (glx_renderer->pf_glXSwapInterval)
+ {
+ if (onscreen->swap_throttled)
+ glx_renderer->pf_glXSwapInterval (1);
+ else
+ glx_renderer->pf_glXSwapInterval (0);
+ }
+ }
+
+ XSync (xlib_renderer->xdpy, False);
+
+ /* FIXME: We should be reporting a GError here
+ */
+ if (_cogl_xlib_untrap_errors (&old_state))
+ {
+ g_warning ("X Error received while making drawable 0x%08lX current",
+ drawable);
+ return;
+ }
+
+ glx_context->current_drawable = drawable;
+}
+
+#ifdef HAVE_DRM
+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 /* HAVE_DRM */
+
+void
+_cogl_winsys_wait_for_vblank (void)
+{
+ CoglDisplayGLX *glx_display;
+ CoglRendererGLX *glx_renderer;
+
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ glx_display = ctx->display->winsys;
+ glx_renderer = ctx->display->renderer->winsys;
+
+ if (glx_renderer->pf_glXGetVideoSync)
+ {
+ guint32 current_count;
+
+ glx_renderer->pf_glXGetVideoSync (¤t_count);
+ glx_renderer->pf_glXWaitVideoSync (2,
+ (current_count + 1) % 2,
+ ¤t_count);
+ }
+#ifdef HAVE_DRM
+ else
+ {
+ drm_wait_vblank_t blank;
+
+ COGL_NOTE (WINSYS, "Waiting for vblank (drm)");
+ blank.request.type = _DRM_VBLANK_RELATIVE;
+ blank.request.sequence = 1;
+ blank.request.signal = 0;
+ drm_wait_vblank (glx_renderer->dri_fd, &blank);
+ }
+#endif /* HAVE_DRM */
+}
+
+void
+_cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
+ int *rectangles,
+ int n_rectangles)
+{
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+ CoglContext *context = framebuffer->context;
+ CoglRendererXlib *xlib_renderer = context->display->renderer->winsys;
+ CoglRendererGLX *glx_renderer = context->display->renderer->winsys;
+ CoglOnscreenXlib *xlib_onscreen = onscreen->winsys;
+ CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
+ GLXDrawable drawable =
+ glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin;
+ guint32 end_frame_vsync_counter;
+ gboolean have_counter;
+ gboolean can_wait;
+
+ _cogl_framebuffer_flush_state (framebuffer,
+ framebuffer,
+ COGL_FRAMEBUFFER_FLUSH_BIND_ONLY);
+
+ if (onscreen->swap_throttled)
+ {
+ have_counter =
+ _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_COUNTER);
+ can_wait = _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_WAIT);
+ }
+ else
+ {
+ have_counter = FALSE;
+ can_wait = FALSE;
+ }
+
+ /* We need to ensure that all the rendering is done, otherwise
+ * redraw operations that are slower than the framerate can
+ * queue up in the pipeline during a heavy animation, causing a
+ * larger and larger backlog of rendering visible as lag to the
+ * user.
+ *
+ * For an exaggerated example consider rendering at 60fps (so 16ms
+ * per frame) and you have a really slow frame that takes 160ms to
+ * render, even though painting the scene and issuing the commands
+ * to the GPU takes no time at all. If all we did was use the
+ * video_sync extension to throttle the painting done by the CPU
+ * then every 16ms we would have another frame queued up even though
+ * the GPU has only rendered one tenth of the current frame. By the
+ * time the GPU would get to the 2nd frame there would be 9 frames
+ * waiting to be rendered.
+ *
+ * The problem is that we don't currently have a good way to throttle
+ * the GPU, only the CPU so we have to resort to synchronizing the
+ * GPU with the CPU to throttle it.
+ *
+ * Note: since calling glFinish() and synchronizing the CPU with
+ * the GPU is far from ideal, we hope that this is only a short
+ * term solution.
+ * - One idea is to using sync objects to track render
+ * completion so we can throttle the backlog (ideally with an
+ * additional extension that lets us get notifications in our
+ * mainloop instead of having to busy wait for the
+ * completion.)
+ * - Another option is to support clipped redraws by reusing the
+ * contents of old back buffers such that we can flip instead
+ * of using a blit and then we can use GLX_INTEL_swap_events
+ * to throttle. For this though we would still probably want an
+ * additional extension so we can report the limited region of
+ * the window damage to X/compositors.
+ */
+ glFinish ();
+
+ if (have_counter && can_wait)
+ {
+ end_frame_vsync_counter = _cogl_winsys_get_vsync_counter ();
+
+ /* If we have the GLX_SGI_video_sync extension then we can
+ * be a bit smarter about how we throttle blits by avoiding
+ * any waits if we can see that the video sync count has
+ * already progressed. */
+ if (glx_onscreen->last_swap_vsync_counter == end_frame_vsync_counter)
+ _cogl_winsys_wait_for_vblank ();
+ }
+ else if (can_wait)
+ _cogl_winsys_wait_for_vblank ();
+
+ if (glx_renderer->pf_glXCopySubBuffer)
+ {
+ Display *xdpy = xlib_renderer->xdpy;
+ int i;
+ for (i = 0; i < n_rectangles; i++)
+ {
+ int *rect = &rectangles[4 * i];
+ glx_renderer->pf_glXCopySubBuffer (xdpy, drawable,
+ rect[0], rect[1], rect[2], rect[3]);
+ }
+ }
+ else if (context->drv.pf_glBlitFramebuffer)
+ {
+ int i;
+ /* XXX: checkout how this state interacts with the code to use
+ * glBlitFramebuffer in Neil's texture atlasing branch */
+ glDrawBuffer (GL_FRONT);
+ for (i = 0; i < n_rectangles; i++)
+ {
+ int *rect = &rectangles[4 * i];
+ int x2 = rect[0] + rect[2];
+ int y2 = rect[1] + rect[3];
+ context->drv.pf_glBlitFramebuffer (rect[0], rect[1], x2, y2,
+ rect[0], rect[1], x2, y2,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ }
+ glDrawBuffer (GL_BACK);
+ }
+
+ /* NB: unlike glXSwapBuffers, glXCopySubBuffer and
+ * glBlitFramebuffer don't issue an implicit glFlush() so we
+ * have to flush ourselves if we want the request to complete in
+ * a finite amount of time since otherwise the driver can batch
+ * the command indefinitely. */
+ glFlush ();
+
+ /* NB: It's important we save the counter we read before acting on
+ * the swap request since if we are mixing and matching different
+ * swap methods between frames we don't want to read the timer e.g.
+ * after calling glFinish() some times and not for others.
+ *
+ * In other words; this way we consistently save the time at the end
+ * of the applications frame such that the counter isn't muddled by
+ * the varying costs of different swap methods.
+ */
+ if (have_counter)
+ glx_onscreen->last_swap_vsync_counter = end_frame_vsync_counter;
+}
+
+guint32
+_cogl_winsys_get_vsync_counter (void)
+{
+ guint32 video_sync_count;
+ CoglRendererGLX *glx_renderer;
+
+ _COGL_GET_CONTEXT (ctx, 0);
+
+ glx_renderer = ctx->display->renderer->winsys;
+
+ glx_renderer->pf_glXGetVideoSync (&video_sync_count);
+
+ return video_sync_count;
+}
+
+void
+_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
+{
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+ CoglContext *context = framebuffer->context;
+ CoglRendererXlib *xlib_renderer = context->display->renderer->winsys;
+ CoglRendererGLX *glx_renderer = context->display->renderer->winsys;
+ CoglOnscreenXlib *xlib_onscreen = onscreen->winsys;
+ CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
+ gboolean have_counter;
+ GLXDrawable drawable;
+
+ /* XXX: theoretically this shouldn't be necessary but at least with
+ * the Intel drivers we have see that if we don't call
+ * glXMakeContextCurrent for the drawable we are swapping then
+ * we get a BadDrawable error from the X server. */
+ _cogl_framebuffer_flush_state (framebuffer,
+ framebuffer,
+ COGL_FRAMEBUFFER_FLUSH_BIND_ONLY);
+
+ drawable = glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin;
+
+ if (onscreen->swap_throttled)
+ {
+ guint32 end_frame_vsync_counter;
+
+ have_counter =
+ _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_COUNTER);
+
+ /* If the swap_region API is also being used then we need to track
+ * the vsync counter for each swap request so we can manually
+ * throttle swap_region requests. */
+ if (have_counter)
+ end_frame_vsync_counter = _cogl_winsys_get_vsync_counter ();
+
+ if (!glx_renderer->pf_glXSwapInterval)
+ {
+ gboolean can_wait =
+ _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_WAIT);
+
+ /* If we are going to wait for VBLANK manually, we not only
+ * need to flush out pending drawing to the GPU before we
+ * sleep, we need to wait for it to finish. Otherwise, we
+ * may end up with the situation:
+ *
+ * - We finish drawing - GPU drawing continues
+ * - We go to sleep - GPU drawing continues
+ * VBLANK - We call glXSwapBuffers - GPU drawing continues
+ * - GPU drawing continues
+ * - Swap buffers happens
+ *
+ * Producing a tear. Calling glFinish() first will cause us
+ * to properly wait for the next VBLANK before we swap. This
+ * obviously does not happen when we use _GLX_SWAP and let
+ * the driver do the right thing
+ */
+ glFinish ();
+
+ if (have_counter && can_wait)
+ {
+ if (glx_onscreen->last_swap_vsync_counter ==
+ end_frame_vsync_counter)
+ _cogl_winsys_wait_for_vblank ();
+ }
+ else if (can_wait)
+ _cogl_winsys_wait_for_vblank ();
+ }
+ }
+ else
+ have_counter = FALSE;
+
+ glXSwapBuffers (xlib_renderer->xdpy, drawable);
+
+ if (have_counter)
+ glx_onscreen->last_swap_vsync_counter = _cogl_winsys_get_vsync_counter ();
+}
+
+guint32
+_cogl_winsys_onscreen_x11_get_window_xid (CoglOnscreen *onscreen)
+{
+ CoglOnscreenXlib *xlib_onscreen = onscreen->winsys;
+ return xlib_onscreen->xwin;
+}
+
+unsigned int
+_cogl_winsys_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen,
+ CoglSwapBuffersNotify callback,
+ void *user_data)
+{
+ CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
+ CoglSwapBuffersNotifyEntry *entry = g_slice_new0 (CoglSwapBuffersNotifyEntry);
+ static int next_swap_buffers_callback_id = 0;
+
+ entry->callback = callback;
+ entry->user_data = user_data;
+ entry->id = next_swap_buffers_callback_id++;
+
+ glx_onscreen->swap_callbacks =
+ g_list_prepend (glx_onscreen->swap_callbacks, entry);
+
+ return entry->id;
+}
+
+void
+_cogl_winsys_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
+ unsigned int id)
+{
+ CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
+ GList *l;
+
+ for (l = glx_onscreen->swap_callbacks; l; l = l->next)
+ {
+ CoglSwapBuffersNotifyEntry *entry = l->data;
+ if (entry->id == id)
+ {
+ g_slice_free (CoglSwapBuffersNotifyEntry, entry);
+ glx_onscreen->swap_callbacks =
+ g_list_delete_link (glx_onscreen->swap_callbacks, l);
+ return;
+ }
+ }
+}
+
+void
+_cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen)
+{
+ CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
+ CoglContextGLX *glx_context = context->winsys;
+ CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
+ CoglOnscreenXlib *xlib_onscreen = onscreen->winsys;
+ GLXDrawable drawable =
+ glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin;
+
+ if (glx_context->current_drawable != drawable)
+ return;
+
+ glx_context->current_drawable = 0;
+ _cogl_winsys_onscreen_bind (onscreen);
+}
+
+/* FIXME: we should distinguish renderer and context features */
+gboolean
+_cogl_winsys_has_feature (CoglWinsysFeature feature)
+{
+ _COGL_GET_CONTEXT (ctx, FALSE);
+
+ return _cogl_bitmask_get (&ctx->winsys_features, feature);
+}
+
+/* XXX: This is a particularly hacky _cogl_winsys interface... */
+XVisualInfo *
+_cogl_winsys_xlib_get_visual_info (void)
+{
+ CoglDisplayXlib *xlib_display;
+ CoglDisplayGLX *glx_display;
+ CoglRendererXlib *xlib_renderer;
+
+ _COGL_GET_CONTEXT (ctx, NULL);
+
+ g_return_val_if_fail (ctx->display->winsys, FALSE);
+
+ xlib_display = ctx->display->winsys;
+ glx_display = ctx->display->winsys;
+ xlib_renderer = ctx->display->renderer->winsys;
+
+ if (!glx_display->found_fbconfig)
+ return NULL;
+
+ return glXGetVisualFromFBConfig (xlib_renderer->xdpy, glx_display->fbconfig);
+}
diff --git a/clutter/cogl/cogl/winsys/cogl-winsys-private.h b/clutter/cogl/cogl/winsys/cogl-winsys-private.h
index 4cf326e..8d56bea 100644
--- a/clutter/cogl/cogl/winsys/cogl-winsys-private.h
+++ b/clutter/cogl/cogl/winsys/cogl-winsys-private.h
@@ -24,7 +24,95 @@
#ifndef __COGL_WINSYS_PRIVATE_H
#define __COGL_WINSYS_PRIVATE_H
+#include "cogl-framebuffer-private.h"
+
+#ifdef COGL_HAS_XLIB_SUPPORT
+#include <X11/Xutil.h>
+#endif
+
+GQuark
+_cogl_winsys_error_quark (void);
+
+#define COGL_WINSYS_ERROR (_cogl_winsys_error_quark ())
+
+typedef enum { /*< prefix=COGL_WINSYS_ERROR >*/
+ COGL_WINSYS_ERROR_INIT,
+ COGL_WINSYS_ERROR_CREATE_CONTEXT,
+ COGL_WINSYS_ERROR_CREATE_ONSCREEN,
+} CoglWinsysError;
+
+typedef enum
+{
+ COGL_WINSYS_RECTANGLE_STATE_UNKNOWN,
+ COGL_WINSYS_RECTANGLE_STATE_DISABLE,
+ COGL_WINSYS_RECTANGLE_STATE_ENABLE
+} CoglWinsysRectangleState;
+
CoglFuncPtr
_cogl_winsys_get_proc_address (const char *name);
+gboolean
+_cogl_winsys_renderer_connect (CoglRenderer *renderer,
+ GError **error);
+
+void
+_cogl_winsys_renderer_disconnect (CoglRenderer *renderer);
+
+gboolean
+_cogl_winsys_display_setup (CoglDisplay *display,
+ GError **error);
+
+void
+_cogl_winsys_display_destroy (CoglDisplay *display);
+
+gboolean
+_cogl_winsys_context_init (CoglContext *context, GError **error);
+
+void
+_cogl_winsys_context_deinit (CoglContext *context);
+
+gboolean
+_cogl_winsys_has_feature (CoglWinsysFeature feature);
+
+#ifdef COGL_HAS_XLIB_SUPPORT
+XVisualInfo *
+_cogl_winsys_xlib_get_visual_info (void);
+#endif
+
+gboolean
+_cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
+ GError **error);
+
+void
+_cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen);
+
+void
+_cogl_winsys_onscreen_bind (CoglOnscreen *onscreen);
+
+void
+_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen);
+
+void
+_cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
+ int *rectangles,
+ int n_rectangles);
+
+void
+_cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen);
+
+guint32
+_cogl_winsys_onscreen_x11_get_window_xid (CoglOnscreen *onscreen);
+
+guint32
+_cogl_winsys_get_vsync_counter (void);
+
+unsigned int
+_cogl_winsys_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen,
+ CoglSwapBuffersNotify callback,
+ void *user_data);
+
+void
+_cogl_winsys_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
+ unsigned int id);
+
#endif /* __COGL_WINSYS_PRIVATE_H */
diff --git a/clutter/cogl/cogl/winsys/cogl-winsys-stub.c b/clutter/cogl/cogl/winsys/cogl-winsys-stub.c
new file mode 100644
index 0000000..6648150
--- /dev/null
+++ b/clutter/cogl/cogl/winsys/cogl-winsys-stub.c
@@ -0,0 +1,114 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-framebuffer-private.h"
+
+/* This provides a stub winsys implementation for when Clutter still handles
+ * creating an OpenGL context. This is useful so we don't have to guard all
+ * calls into the winsys layer with #ifdef COGL_HAS_FULL_WINSYS
+ */
+
+
+void
+_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
+{
+
+}
+
+void
+_cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
+ int *rectangles,
+ int n_rectangles)
+{
+
+}
+
+void
+_cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen)
+{
+
+}
+
+unsigned int
+_cogl_winsys_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen,
+ CoglSwapBuffersNotify callback,
+ void *user_data)
+{
+ g_assert (0);
+ return 0;
+}
+
+void
+_cogl_winsys_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
+ unsigned int id)
+{
+ g_assert (0);
+}
+
+#ifdef COGL_HAS_XLIB_SUPPORT
+XVisualInfo *
+_cogl_winsys_xlib_get_visual_info (void)
+{
+ g_assert (0);
+ return NULL;
+}
+#endif
+
+gboolean
+_cogl_winsys_has_feature (CoglWinsysFeature feature)
+{
+ g_assert (0);
+ return FALSE;
+}
+
+#ifdef COGL_HAS_X11_SUPPORT
+guint32
+_cogl_winsys_onscreen_x11_get_window_xid (CoglOnscreen *onscreen)
+{
+ g_assert (0);
+ return 0;
+}
+#endif
+
+gboolean
+_cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
+ GError **error)
+{
+ return TRUE;
+}
+
+void
+_cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
+{
+
+}
+
+void
+_cogl_winsys_context_deinit (CoglContext *context)
+{
+
+}
diff --git a/clutter/cogl/cogl/winsys/cogl-winsys.c b/clutter/cogl/cogl/winsys/cogl-winsys.c
new file mode 100644
index 0000000..e59063a
--- /dev/null
+++ b/clutter/cogl/cogl/winsys/cogl-winsys.c
@@ -0,0 +1,36 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2007,2008,2009,2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl.h"
+
+GQuark
+_cogl_winsys_error_quark (void)
+{
+ return g_quark_from_static_string ("cogl-winsys-error-quark");
+}
+
diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c
index 684ad29..38c90ba 100644
--- a/clutter/glx/clutter-backend-glx.c
+++ b/clutter/glx/clutter-backend-glx.c
@@ -49,6 +49,7 @@
#include "clutter-stage-private.h"
#include "cogl/cogl.h"
+#include "cogl/cogl-internal.h"
#define clutter_backend_glx_get_type _clutter_backend_glx_get_type
@@ -57,12 +58,15 @@ G_DEFINE_TYPE (ClutterBackendGLX, clutter_backend_glx, CLUTTER_TYPE_BACKEND_X11)
/* singleton object */
static ClutterBackendGLX *backend_singleton = NULL;
-static gchar *clutter_vblank_name = NULL;
+static gchar *clutter_vblank = NULL;
G_CONST_RETURN gchar*
-_clutter_backend_glx_get_vblank_method (void)
+_clutter_backend_glx_get_vblank (void)
{
- return clutter_vblank_name;
+ if (clutter_vblank && strcmp (clutter_vblank, "0") == 0)
+ return "none";
+ else
+ return clutter_vblank;
}
static gboolean
@@ -76,7 +80,7 @@ clutter_backend_glx_pre_parse (ClutterBackend *backend,
env_string = g_getenv ("CLUTTER_VBLANK");
if (env_string)
{
- clutter_vblank_name = g_strdup (env_string);
+ clutter_vblank = g_strdup (env_string);
env_string = NULL;
}
@@ -87,42 +91,12 @@ static gboolean
clutter_backend_glx_post_parse (ClutterBackend *backend,
GError **error)
{
- ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
- ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
ClutterBackendClass *parent_class =
CLUTTER_BACKEND_CLASS (clutter_backend_glx_parent_class);
- int glx_major, glx_minor;
if (!parent_class->post_parse (backend, error))
return FALSE;
- if (!glXQueryExtension (backend_x11->xdpy,
- &backend_glx->error_base,
- &backend_glx->event_base))
- {
- g_set_error_literal (error, CLUTTER_INIT_ERROR,
- CLUTTER_INIT_ERROR_BACKEND,
- "XServer appears to lack the required GLX support");
-
- return FALSE;
- }
-
- /* XXX: Technically we should require >= GLX 1.3 support but for a long
- * time Mesa has exported a hybrid GLX, exporting extensions specified
- * to require GLX 1.3, but still reporting 1.2 via glXQueryVersion. */
- glx_major = 1;
- glx_minor = 2;
- if (!glXQueryVersion (backend_x11->xdpy, &glx_major, &glx_minor) ||
- !(glx_major == 1 && glx_minor >= 2))
- {
- g_set_error (error, CLUTTER_INIT_ERROR,
- CLUTTER_INIT_ERROR_BACKEND,
- "XServer appears to lack the required GLX "
- "1.2 support (%d.%d reported)",
- glx_major, glx_minor);
- return FALSE;
- }
-
return TRUE;
}
@@ -130,8 +104,9 @@ static const GOptionEntry entries[] =
{
{ "vblank", 0,
0,
- G_OPTION_ARG_STRING, &clutter_vblank_name,
- N_("VBlank method to be used (none, dri or glx)"), "METHOD"
+ G_OPTION_ARG_STRING, &clutter_vblank,
+ N_("Set to 'none' or '0' to disable throttling "
+ "framerate to vblank"), "OPTION"
},
{ NULL }
};
@@ -160,32 +135,20 @@ clutter_backend_glx_finalize (GObject *gobject)
static void
clutter_backend_glx_dispose (GObject *gobject)
{
- ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (gobject);
- ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (gobject);
+ ClutterBackend *backend = CLUTTER_BACKEND (gobject);
/* Unrealize all shaders, since the GL context is going away */
+ /* XXX: Why isn't this done in
+ * clutter-backend.c:clutter_backend_dispose ?
+ */
_clutter_shader_release_all ();
- if (backend_glx->gl_context)
- {
- glXMakeContextCurrent (backend_x11->xdpy, None, None, NULL);
- glXDestroyContext (backend_x11->xdpy, backend_glx->gl_context);
- backend_glx->gl_context = NULL;
- }
-
- if (backend_glx->dummy_glxwin)
- {
- glXDestroyWindow (backend_x11->xdpy, backend_glx->dummy_glxwin);
- backend_glx->dummy_glxwin = None;
- }
-
- if (backend_glx->dummy_xwin)
- {
- XDestroyWindow (backend_x11->xdpy, backend_glx->dummy_xwin);
- backend_glx->dummy_xwin = None;
- }
-
+ /* We chain up before disposing our CoglContext so that we will
+ * destroy all of the stages first. Otherwise the actors may try to
+ * make Cogl calls during destruction which would cause a crash */
G_OBJECT_CLASS (clutter_backend_glx_parent_class)->dispose (gobject);
+
+ cogl_object_unref (backend->cogl_context);
}
static GObject *
@@ -212,197 +175,46 @@ clutter_backend_glx_constructor (GType gtype,
return g_object_ref (backend_singleton);
}
-static gboolean
-check_vblank_env (const char *name)
-{
- if (clutter_vblank_name && !g_ascii_strcasecmp (clutter_vblank_name, name))
- return TRUE;
-
- return FALSE;
-}
-
static ClutterFeatureFlags
clutter_backend_glx_get_features (ClutterBackend *backend)
{
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
ClutterBackendClass *parent_class;
- const gchar *glx_extensions = NULL;
- const gchar *gl_extensions = NULL;
ClutterFeatureFlags flags;
- gboolean use_dri = FALSE;
parent_class = CLUTTER_BACKEND_CLASS (clutter_backend_glx_parent_class);
flags = parent_class->get_features (backend);
- flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
-
- /* this will make sure that the GL context exists */
- g_assert (backend_glx->gl_context != NULL);
- g_assert (glXGetCurrentDrawable () != None);
- CLUTTER_NOTE (BACKEND,
- "Checking features\n"
- " GL_VENDOR: %s\n"
- " GL_RENDERER: %s\n"
- " GL_VERSION: %s\n"
- " GL_EXTENSIONS: %s",
- glGetString (GL_VENDOR),
- glGetString (GL_RENDERER),
- glGetString (GL_VERSION),
- glGetString (GL_EXTENSIONS));
-
- glx_extensions =
- glXQueryExtensionsString (clutter_x11_get_default_display (),
- clutter_x11_get_default_screen ());
-
- CLUTTER_NOTE (BACKEND, " GLX Extensions: %s", glx_extensions);
-
- gl_extensions = (const gchar *)glGetString (GL_EXTENSIONS);
-
- /* When using glBlitFramebuffer or glXCopySubBufferMESA for sub stage
- * redraws, we cannot rely on glXSwapIntervalSGI to throttle the blits
- * so we need to resort to manually synchronizing with the vblank so we
- * always check for the video_sync extension...
- */
- if (_cogl_check_extension ("GLX_SGI_video_sync", glx_extensions) &&
- /* Note: the GLX_SGI_video_sync spec explicitly states this extension
- * only works for direct contexts. */
- glXIsDirect (clutter_x11_get_default_display (),
- backend_glx->gl_context))
+ if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN))
{
- backend_glx->get_video_sync =
- (GetVideoSyncProc) cogl_get_proc_address ("glXGetVideoSyncSGI");
-
- backend_glx->wait_video_sync =
- (WaitVideoSyncProc) cogl_get_proc_address ("glXWaitVideoSyncSGI");
+ CLUTTER_NOTE (BACKEND, "Cogl supports multiple onscreen framebuffers");
+ flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
}
-
- use_dri = check_vblank_env ("dri");
-
- /* First check for explicit disabling or it set elsewhere (eg NVIDIA) */
- if (check_vblank_env ("none"))
+ else
{
- CLUTTER_NOTE (BACKEND, "vblank sync: disabled at user request");
- goto vblank_setup_done;
+ CLUTTER_NOTE (BACKEND, "Cogl only supports one onscreen framebuffer");
+ flags |= CLUTTER_FEATURE_STAGE_STATIC;
}
- if (g_getenv ("__GL_SYNC_TO_VBLANK") != NULL)
+ if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_THROTTLE))
{
- backend_glx->vblank_type = CLUTTER_VBLANK_GLX_SWAP;
+ CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers throttling");
flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
-
- CLUTTER_NOTE (BACKEND, "Using __GL_SYNC_TO_VBLANK hint");
- goto vblank_setup_done;
- }
-
- /* We try two GL vblank syncing mechanisms.
- * glXSwapIntervalSGI is tried first, then glXGetVideoSyncSGI.
- *
- * glXSwapIntervalSGI is known to work with Mesa and in particular
- * the Intel drivers. glXGetVideoSyncSGI has serious problems with
- * Intel drivers causing terrible frame rate so it only tried as a
- * fallback.
- *
- * How well glXGetVideoSyncSGI works with other driver (ATI etc) needs
- * to be investigated. glXGetVideoSyncSGI on ATI at least seems to have
- * no effect.
- */
- if (!use_dri &&
- _cogl_check_extension ("GLX_SGI_swap_control", glx_extensions))
- {
- backend_glx->swap_interval =
- (SwapIntervalProc) cogl_get_proc_address ("glXSwapIntervalSGI");
-
- CLUTTER_NOTE (BACKEND, "attempting glXSwapIntervalSGI vblank setup");
-
- if (backend_glx->swap_interval != NULL &&
- backend_glx->swap_interval (1) == 0)
- {
- backend_glx->vblank_type = CLUTTER_VBLANK_GLX_SWAP;
- flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
-
- CLUTTER_NOTE (BACKEND, "glXSwapIntervalSGI setup success");
-
-#ifdef GLX_INTEL_swap_event
- /* GLX_INTEL_swap_event allows us to avoid blocking the CPU
- * while we wait for glXSwapBuffers to complete, and instead
- * we get an X event notifying us of completion...
- */
- if (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_SWAP_EVENTS) &&
- _cogl_check_extension ("GLX_INTEL_swap_event", glx_extensions))
- {
- flags |= CLUTTER_FEATURE_SWAP_EVENTS;
- }
-#endif /* GLX_INTEL_swap_event */
-
- goto vblank_setup_done;
- }
-
- CLUTTER_NOTE (BACKEND, "glXSwapIntervalSGI vblank setup failed");
- }
-
- if (!use_dri &&
- !(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK) &&
- _cogl_check_extension ("GLX_SGI_video_sync", glx_extensions))
- {
- CLUTTER_NOTE (BACKEND, "attempting glXGetVideoSyncSGI vblank setup");
-
- if ((backend_glx->get_video_sync != NULL) &&
- (backend_glx->wait_video_sync != NULL))
- {
- CLUTTER_NOTE (BACKEND, "glXGetVideoSyncSGI vblank setup success");
-
- backend_glx->vblank_type = CLUTTER_VBLANK_GLX;
- flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
-
- goto vblank_setup_done;
- }
-
- CLUTTER_NOTE (BACKEND, "glXGetVideoSyncSGI vblank setup failed");
}
+ else
+ CLUTTER_NOTE (BACKEND, "Cogl doesn't support swap buffers throttling");
-#ifdef __linux__
- /*
- * DRI is really an extreme fallback -rumoured to work with Via chipsets
- */
- if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
+ if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
{
- CLUTTER_NOTE (BACKEND, "attempting DRI vblank setup");
-
- backend_glx->dri_fd = open("/dev/dri/card0", O_RDWR);
- if (backend_glx->dri_fd >= 0)
- {
- CLUTTER_NOTE (BACKEND, "DRI vblank setup success");
-
- backend_glx->vblank_type = CLUTTER_VBLANK_DRI;
- flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
-
- goto vblank_setup_done;
- }
-
- CLUTTER_NOTE (BACKEND, "DRI vblank setup failed");
+ CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers complete events");
+ flags |= CLUTTER_FEATURE_SWAP_EVENTS;
}
-#endif /* __linux__ */
-
- CLUTTER_NOTE (BACKEND, "no use-able vblank mechanism found");
-vblank_setup_done:
-
- if (_cogl_check_extension ("GLX_MESA_copy_sub_buffer", glx_extensions))
+ if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION))
{
- backend_glx->copy_sub_buffer =
- (CopySubBufferProc) cogl_get_proc_address ("glXCopySubBufferMESA");
+ CLUTTER_NOTE (BACKEND, "Cogl supports swapping buffer regions");
backend_glx->can_blit_sub_buffer = TRUE;
- backend_glx->blit_sub_buffer_is_synchronized = TRUE;
- }
- else if (_cogl_check_extension ("GL_EXT_framebuffer_blit", gl_extensions))
- {
- CLUTTER_NOTE (BACKEND,
- "Using glBlitFramebuffer fallback for sub_buffer copies");
- backend_glx->blit_framebuffer =
- (BlitFramebufferProc) cogl_get_proc_address ("glBlitFramebuffer");
- backend_glx->can_blit_sub_buffer = TRUE;
- backend_glx->blit_sub_buffer_is_synchronized = FALSE;
}
CLUTTER_NOTE (BACKEND, "backend features checked");
@@ -410,375 +222,77 @@ vblank_setup_done:
return flags;
}
-/* It seems the GLX spec never defined an invalid GLXFBConfig that
- * we could overload as an indication of error, so we have to return
- * an explicit boolean status. */
-gboolean
-_clutter_backend_glx_get_fbconfig (ClutterBackendGLX *backend_glx,
- GLXFBConfig *config)
-{
- ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend_glx);
- GLXFBConfig *configs = NULL;
- gboolean use_argb = clutter_x11_get_use_argb_visual ();
- int n_configs, i;
- static const int attributes[] = {
- GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
- GLX_RENDER_TYPE, GLX_RGBA_BIT,
- GLX_DOUBLEBUFFER, GL_TRUE,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_ALPHA_SIZE, 1,
- GLX_DEPTH_SIZE, 1,
- GLX_STENCIL_SIZE, 1,
- None
- };
-
- if (backend_x11->xdpy == NULL || backend_x11->xscreen == NULL)
- return FALSE;
-
- /* If we don't already have a cached config then try to get one */
- if (!backend_glx->found_fbconfig)
- {
- CLUTTER_NOTE (BACKEND,
- "Retrieving GL fbconfig, dpy: %p, xscreen; %p (%d)",
- backend_x11->xdpy,
- backend_x11->xscreen,
- backend_x11->xscreen_num);
-
- configs = glXChooseFBConfig (backend_x11->xdpy,
- backend_x11->xscreen_num,
- attributes,
- &n_configs);
- if (configs)
- {
- if (use_argb)
- {
- for (i = 0; i < n_configs; i++)
- {
- XVisualInfo *vinfo;
-
- vinfo = glXGetVisualFromFBConfig (backend_x11->xdpy,
- configs[i]);
- if (vinfo == NULL)
- continue;
-
- if (vinfo->depth == 32 &&
- (vinfo->red_mask == 0xff0000 &&
- vinfo->green_mask == 0x00ff00 &&
- vinfo->blue_mask == 0x0000ff))
- {
- CLUTTER_NOTE (BACKEND,
- "Found an ARGB FBConfig [index:%d]",
- i);
-
- backend_glx->found_fbconfig = TRUE;
- backend_glx->fbconfig = configs[i];
-
- goto out;
- }
- }
-
- /* If we make it here then we didn't find an RGBA config so
- we'll fall back to using an RGB config */
- CLUTTER_NOTE (BACKEND, "ARGB visual requested, but none found");
- }
-
- if (n_configs >= 1)
- {
- CLUTTER_NOTE (BACKEND, "Using the first available FBConfig");
- backend_glx->found_fbconfig = TRUE;
- backend_glx->fbconfig = configs[0];
- }
-
- out:
- XFree (configs);
- }
- }
-
- if (G_LIKELY (backend_glx->found_fbconfig))
- {
- *config = backend_glx->fbconfig;
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-void
-_clutter_backend_glx_blit_sub_buffer (ClutterBackendGLX *backend_glx,
- GLXDrawable drawable,
- int x,
- int y,
- int width,
- int height)
-{
- ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend_glx);
-
- if (backend_glx->copy_sub_buffer)
- {
- backend_glx->copy_sub_buffer (backend_x11->xdpy, drawable,
- x, y, width, height);
- }
- else if (backend_glx->blit_framebuffer)
- {
- glDrawBuffer (GL_FRONT);
- backend_glx->blit_framebuffer (x, y, x + width, y + height,
- x, y, x + width, y + height,
- GL_COLOR_BUFFER_BIT, GL_NEAREST);
- glDrawBuffer (GL_BACK);
- }
-
- /* NB: unlike glXSwapBuffers, glXCopySubBuffer and
- * glBlitFramebuffer don't issue an implicit glFlush() so we
- * have to flush ourselves if we want the request to complete in
- * finite amount of time since otherwise the driver can batch
- * the command indefinitely. */
- glFlush();
-}
-
static XVisualInfo *
clutter_backend_glx_get_visual_info (ClutterBackendX11 *backend_x11)
{
- ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend_x11);
- GLXFBConfig config;
-
- if (!_clutter_backend_glx_get_fbconfig (backend_glx, &config))
- return NULL;
-
- return glXGetVisualFromFBConfig (backend_x11->xdpy, config);
+ return cogl_clutter_winsys_xlib_get_visual_info ();
}
static gboolean
clutter_backend_glx_create_context (ClutterBackend *backend,
GError **error)
{
- ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
- GLXFBConfig config;
- gboolean is_direct;
- Window root_xwin;
- XSetWindowAttributes attrs;
- XVisualInfo *xvisinfo;
- Display *xdisplay;
- int major;
- int minor;
- GLXDrawable dummy_drawable;
-
- if (backend_glx->gl_context != NULL)
- return TRUE;
-
- xdisplay = clutter_x11_get_default_display ();
- root_xwin = clutter_x11_get_root_window ();
-
- if (!_clutter_backend_glx_get_fbconfig (backend_glx, &config))
- {
- g_set_error_literal (error, CLUTTER_INIT_ERROR,
- CLUTTER_INIT_ERROR_BACKEND,
- "Unable to find suitable fbconfig for the GLX context");
- return FALSE;
- }
+ CoglSwapChain *swap_chain = NULL;
+ CoglOnscreenTemplate *onscreen_template = NULL;
- CLUTTER_NOTE (BACKEND, "Creating GLX Context (display: %p)", xdisplay);
+ if (backend->cogl_context)
+ return TRUE;
- backend_glx->gl_context = glXCreateNewContext (xdisplay,
- config,
- GLX_RGBA_TYPE,
- NULL,
- True);
- if (backend_glx->gl_context == NULL)
- {
- g_set_error_literal (error, CLUTTER_INIT_ERROR,
- CLUTTER_INIT_ERROR_BACKEND,
- "Unable to create suitable GL context");
- return FALSE;
- }
+ backend->cogl_renderer = cogl_renderer_new ();
+ cogl_renderer_xlib_set_foreign_display (backend->cogl_renderer,
+ backend_x11->xdpy);
+ if (!cogl_renderer_connect (backend->cogl_renderer, error))
+ goto error;
- is_direct = glXIsDirect (xdisplay, backend_glx->gl_context);
-
- CLUTTER_NOTE (GL, "Setting %s context",
- is_direct ? "direct"
- : "indirect");
- _cogl_set_indirect_context (!is_direct);
-
- /* COGL assumes that there is always a GL context selected; in order
- * to make sure that a GLX context exists and is made current, we use
- * a dummy, offscreen override-redirect window to which we can always
- * fall back if no stage is available
- *
- * XXX - we need to do this dance because GLX does not allow creating
- * a context and querying it for basic information (even the function
- * pointers) unless it's made current to a real Drawable. it should be
- * possible to avoid this in future releases of Mesa and X11, but right
- * now this is the best solution available.
- */
- xvisinfo = glXGetVisualFromFBConfig (xdisplay, config);
- if (xvisinfo == NULL)
- {
- g_set_error_literal (error, CLUTTER_INIT_ERROR,
- CLUTTER_INIT_ERROR_BACKEND,
- "Unable to retrieve the X11 visual");
- return FALSE;
- }
+ swap_chain = cogl_swap_chain_new ();
+ cogl_swap_chain_set_has_alpha (swap_chain,
+ clutter_x11_get_use_argb_visual ());
- clutter_x11_trap_x_errors ();
-
- attrs.override_redirect = True;
- attrs.colormap = XCreateColormap (xdisplay,
- root_xwin,
- xvisinfo->visual,
- AllocNone);
- attrs.border_pixel = 0;
-
- backend_glx->dummy_xwin = XCreateWindow (xdisplay, root_xwin,
- -100, -100, 1, 1,
- 0,
- xvisinfo->depth,
- CopyFromParent,
- xvisinfo->visual,
- CWOverrideRedirect | CWColormap | CWBorderPixel,
- &attrs);
-
- /* Try and create a GLXWindow to use with extensions dependent on
- * GLX versions >= 1.3 that don't accept regular X Windows as GLX
- * drawables. */
- if (glXQueryVersion (backend_x11->xdpy, &major, &minor) &&
- major == 1 && minor >= 3)
- {
- backend_glx->dummy_glxwin = glXCreateWindow (backend_x11->xdpy,
- config,
- backend_glx->dummy_xwin,
- NULL);
- }
+ onscreen_template = cogl_onscreen_template_new (swap_chain);
+ cogl_object_unref (swap_chain);
- if (backend_glx->dummy_glxwin)
- dummy_drawable = backend_glx->dummy_glxwin;
- else
- dummy_drawable = backend_glx->dummy_xwin;
+ if (!cogl_renderer_check_onscreen_template (backend->cogl_renderer,
+ onscreen_template,
+ error))
+ goto error;
- CLUTTER_NOTE (BACKEND, "Selecting dummy 0x%x for the GLX context",
- (unsigned int) dummy_drawable);
+ backend->cogl_display = cogl_display_new (backend->cogl_renderer,
+ onscreen_template);
+ cogl_object_unref (backend->cogl_renderer);
+ cogl_object_unref (onscreen_template);
- glXMakeContextCurrent (xdisplay,
- dummy_drawable,
- dummy_drawable,
- backend_glx->gl_context);
+ if (!cogl_display_setup (backend->cogl_display, error))
+ goto error;
- XFree (xvisinfo);
+ backend->cogl_context = cogl_context_new (backend->cogl_display, error);
+ if (!backend->cogl_context)
+ goto error;
- if (clutter_x11_untrap_x_errors ())
- {
- g_set_error_literal (error, CLUTTER_INIT_ERROR,
- CLUTTER_INIT_ERROR_BACKEND,
- "Unable to select the newly created GLX context");
- return FALSE;
- }
+ /* XXX: eventually this should go away but a lot of Cogl code still
+ * depends on a global default context. */
+ cogl_set_default_context (backend->cogl_context);
return TRUE;
-}
-/* TODO: remove this interface in favour of
- * _clutter_stage_window_make_current () */
-static void
-clutter_backend_glx_ensure_context (ClutterBackend *backend,
- ClutterStage *stage)
-{
- ClutterStageWindow *impl;
-
- /* if there is no stage, the stage is being destroyed or it has no
- * implementation attached to it then we clear the GL context
- */
- if (stage == NULL ||
- CLUTTER_ACTOR_IN_DESTRUCTION (stage) ||
- ((impl = _clutter_stage_get_window (stage)) == NULL))
+error:
+ if (backend->cogl_display)
{
- ClutterBackendX11 *backend_x11;
+ cogl_object_unref (backend->cogl_display);
+ backend->cogl_display = NULL;
+ }
- backend_x11 = CLUTTER_BACKEND_X11 (backend);
- CLUTTER_NOTE (MULTISTAGE, "Clearing all context");
+ if (onscreen_template)
+ cogl_object_unref (onscreen_template);
+ if (swap_chain)
+ cogl_object_unref (swap_chain);
- glXMakeContextCurrent (backend_x11->xdpy, None, None, NULL);
- }
- else
+ if (backend->cogl_renderer)
{
- ClutterBackendGLX *backend_glx;
- ClutterBackendX11 *backend_x11;
- ClutterStageGLX *stage_glx;
- ClutterStageX11 *stage_x11;
- GLXDrawable drawable;
-
- g_assert (impl != NULL);
-
- stage_glx = CLUTTER_STAGE_GLX (impl);
- stage_x11 = CLUTTER_STAGE_X11 (impl);
- backend_glx = CLUTTER_BACKEND_GLX (backend);
- backend_x11 = CLUTTER_BACKEND_X11 (backend);
-
- drawable = stage_glx->glxwin ? stage_glx->glxwin : stage_x11->xwin;
-
- CLUTTER_NOTE (BACKEND,
- "Setting context for stage of type %s, window: 0x%x",
- G_OBJECT_TYPE_NAME (impl),
- (unsigned int) drawable);
-
- /* no GL context to set */
- if (backend_glx->gl_context == NULL)
- return;
-
- clutter_x11_trap_x_errors ();
-
- /* we might get here inside the final dispose cycle, so we
- * need to handle this gracefully
- */
- if (drawable == None)
- {
- GLXDrawable dummy_drawable;
-
- CLUTTER_NOTE (BACKEND,
- "Received a stale stage, clearing all context");
-
- if (backend_glx->dummy_glxwin)
- dummy_drawable = backend_glx->dummy_glxwin;
- else
- dummy_drawable = backend_glx->dummy_xwin;
-
- if (dummy_drawable == None)
- glXMakeContextCurrent (backend_x11->xdpy, None, None, NULL);
- else
- {
- glXMakeContextCurrent (backend_x11->xdpy,
- dummy_drawable,
- dummy_drawable,
- backend_glx->gl_context);
- }
- }
- else
- {
- CLUTTER_NOTE (BACKEND,
- "MakeContextCurrent dpy: %p, window: 0x%x (%s), context: %p",
- backend_x11->xdpy,
- (unsigned int) drawable,
- stage_x11->is_foreign_xwin ? "foreign" : "native",
- backend_glx->gl_context);
-
- glXMakeContextCurrent (backend_x11->xdpy,
- drawable,
- drawable,
- backend_glx->gl_context);
- /*
- * In case we are using GLX_SGI_swap_control for vblank syncing we need call
- * glXSwapIntervalSGI here to make sure that it affects the current drawable.
- */
- if (backend_glx->vblank_type == CLUTTER_VBLANK_GLX_SWAP && backend_glx->swap_interval != NULL)
- backend_glx->swap_interval (1);
- }
-
- if (clutter_x11_untrap_x_errors ())
- g_critical ("Unable to make the stage window 0x%x the current "
- "GLX drawable",
- (unsigned int) drawable);
+ cogl_object_unref (backend->cogl_renderer);
+ backend->cogl_renderer = NULL;
}
+ return FALSE;
}
static ClutterStageWindow *
@@ -813,6 +327,16 @@ clutter_backend_glx_create_stage (ClutterBackend *backend,
}
static void
+clutter_backend_glx_ensure_context (ClutterBackend *backend,
+ ClutterStage *stage)
+{
+ ClutterStageGLX *stage_glx =
+ CLUTTER_STAGE_GLX (_clutter_stage_get_window (stage));
+
+ cogl_set_framebuffer (COGL_FRAMEBUFFER (stage_glx->onscreen));
+}
+
+static void
clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
diff --git a/clutter/glx/clutter-backend-glx.h b/clutter/glx/clutter-backend-glx.h
index 195b19a..a1d6eae 100644
--- a/clutter/glx/clutter-backend-glx.h
+++ b/clutter/glx/clutter-backend-glx.h
@@ -47,30 +47,11 @@ typedef struct _ClutterBackendGLXClass ClutterBackendGLXClass;
typedef enum ClutterGLXVBlankType {
CLUTTER_VBLANK_NONE = 0,
- CLUTTER_VBLANK_GLX_SWAP,
- CLUTTER_VBLANK_GLX,
- CLUTTER_VBLANK_DRI
+ CLUTTER_VBLANK_AUTOMATIC_THROTTLE,
+ CLUTTER_VBLANK_VBLANK_COUNTER,
+ CLUTTER_VBLANK_MANUAL_WAIT
} ClutterGLXVBlankType;
-typedef int (*GetVideoSyncProc) (unsigned int *count);
-typedef int (*WaitVideoSyncProc) (int divisor,
- int remainder,
- unsigned int *count);
-typedef int (*SwapIntervalProc) (int interval);
-typedef void (*CopySubBufferProc)(Display *dpy,
- GLXDrawable drawable,
- int x, int y, int width, int height);
-typedef void (*BlitFramebufferProc) (GLint srcX0,
- GLint srcY0,
- GLint srcX1,
- GLint srcY1,
- GLint dstX0,
- GLint dstY0,
- GLint dstX1,
- GLint dstY1,
- GLbitfield mask,
- GLenum filter);
-
struct _ClutterBackendGLX
{
ClutterBackendX11 parent_instance;
@@ -78,25 +59,13 @@ struct _ClutterBackendGLX
int error_base;
int event_base;
- /* Single context for all wins */
- gboolean found_fbconfig;
- GLXFBConfig fbconfig;
- GLXContext gl_context;
- Window dummy_xwin;
- GLXWindow dummy_glxwin;
+ CoglContext *cogl_context;
/* Vblank stuff */
- GetVideoSyncProc get_video_sync;
- WaitVideoSyncProc wait_video_sync;
- SwapIntervalProc swap_interval;
- gint dri_fd;
ClutterGLXVBlankType vblank_type;
unsigned int last_video_sync_count;
gboolean can_blit_sub_buffer;
- CopySubBufferProc copy_sub_buffer;
- BlitFramebufferProc blit_framebuffer;
- gboolean blit_sub_buffer_is_synchronized;
/* props */
Atom atom_WM_STATE;
@@ -110,14 +79,8 @@ struct _ClutterBackendGLXClass
GType _clutter_backend_glx_get_type (void) G_GNUC_CONST;
-gboolean
-_clutter_backend_glx_get_fbconfig (ClutterBackendGLX *backend_x11,
- GLXFBConfig *config);
-
-void
-_clutter_backend_glx_blit_sub_buffer (ClutterBackendGLX *backend_glx,
- GLXDrawable drawable,
- int x, int y, int width, int height);
+G_CONST_RETURN gchar*
+_clutter_backend_glx_get_vblank (void);
G_END_DECLS
diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c
index 76d11f6..60e0002 100644
--- a/clutter/glx/clutter-stage-glx.c
+++ b/clutter/glx/clutter-stage-glx.c
@@ -53,10 +53,8 @@
#endif
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
-static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface);
static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL;
-static ClutterEventTranslatorIface *clutter_event_translator_parent_iface = NULL;
#define clutter_stage_glx_get_type _clutter_stage_glx_get_type
@@ -64,33 +62,37 @@ G_DEFINE_TYPE_WITH_CODE (ClutterStageGLX,
clutter_stage_glx,
CLUTTER_TYPE_STAGE_X11,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
- clutter_stage_window_iface_init)
- G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR,
- clutter_event_translator_iface_init));
+ clutter_stage_window_iface_init));
static void
clutter_stage_glx_unrealize (ClutterStageWindow *stage_window)
{
- ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
- ClutterBackendX11 *backend_x11 = stage_x11->backend;
/* Note unrealize should free up any backend stage related resources */
CLUTTER_NOTE (BACKEND, "Unrealizing GLX stage [%p]", stage_glx);
- clutter_x11_trap_x_errors ();
-
- if (stage_glx->glxwin != None)
- {
- glXDestroyWindow (backend_x11->xdpy, stage_glx->glxwin);
- stage_glx->glxwin = None;
- }
-
- _clutter_stage_x11_destroy_window_untrapped (stage_x11);
+ cogl_object_unref (stage_glx->onscreen);
+ stage_glx->onscreen = NULL;
+}
- XSync (backend_x11->xdpy, False);
+static void
+handle_swap_complete_cb (CoglFramebuffer *framebuffer,
+ void *user_data)
+{
+ ClutterStageGLX *stage_glx = user_data;
- clutter_x11_untrap_x_errors ();
+ /* Early versions of the swap_event implementation in Mesa
+ * deliver BufferSwapComplete event when not selected for,
+ * so if we get a swap event we aren't expecting, just ignore it.
+ *
+ * https://bugs.freedesktop.org/show_bug.cgi?id=27962
+ *
+ * FIXME: This issue can be hidden inside Cogl so we shouldn't
+ * need to care about this bug here.
+ */
+ if (stage_glx->pending_swaps > 0)
+ stage_glx->pending_swaps--;
}
static gboolean
@@ -98,56 +100,53 @@ clutter_stage_glx_realize (ClutterStageWindow *stage_window)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
- ClutterBackendX11 *backend_x11;
+ ClutterBackend *backend;
ClutterBackendGLX *backend_glx;
+ CoglFramebuffer *framebuffer;
+ GError *error = NULL;
+ gfloat width;
+ gfloat height;
+ const char *clutter_vblank;
CLUTTER_NOTE (ACTOR, "Realizing stage '%s' [%p]",
G_OBJECT_TYPE_NAME (stage_window),
stage_window);
- if (!_clutter_stage_x11_create_window (stage_x11))
- return FALSE;
+ backend = CLUTTER_BACKEND (stage_x11->backend);
+ backend_glx = CLUTTER_BACKEND_GLX (stage_x11->backend);
- backend_x11 = stage_x11->backend;
- backend_glx = CLUTTER_BACKEND_GLX (backend_x11);
+ clutter_actor_get_size (CLUTTER_ACTOR (stage_x11->wrapper), &width, &height);
- if (stage_glx->glxwin == None)
- {
- int major;
- int minor;
- GLXFBConfig config;
+ stage_glx->onscreen = cogl_onscreen_new (backend->cogl_context,
+ width, height);
+ if (stage_x11->xwin != None)
+ cogl_onscreen_x11_set_foreign_window_xid (stage_glx->onscreen,
+ stage_x11->xwin);
- /* Try and create a GLXWindow to use with extensions dependent on
- * GLX versions >= 1.3 that don't accept regular X Windows as GLX
- * drawables.
- */
- if (glXQueryVersion (backend_x11->xdpy, &major, &minor) &&
- major == 1 && minor >= 3 &&
- _clutter_backend_glx_get_fbconfig (backend_glx, &config))
- {
- stage_glx->glxwin = glXCreateWindow (backend_x11->xdpy,
- config,
- stage_x11->xwin,
- NULL);
- }
- }
+ clutter_vblank = _clutter_backend_glx_get_vblank ();
+ if (clutter_vblank && strcmp (clutter_vblank, "none") == 0)
+ cogl_onscreen_set_swap_throttled (stage_glx->onscreen, FALSE);
-#ifdef GLX_INTEL_swap_event
- if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS))
+ framebuffer = COGL_FRAMEBUFFER (stage_glx->onscreen);
+ if (!cogl_framebuffer_allocate (framebuffer, &error))
{
- GLXDrawable drawable = stage_glx->glxwin
- ? stage_glx->glxwin
- : stage_x11->xwin;
+ g_warning ("Failed to allocate stage: %s", error->message);
+ g_error_free (error);
+ cogl_object_unref (stage_glx->onscreen);
+ stage_glx->onscreen = NULL;
+ return FALSE;
+ }
- /* we unconditionally select this event because we rely on it to
- * advance the master clock, and drive redraw/relayout, animations
- * and event handling.
- */
- glXSelectEvent (backend_x11->xdpy,
- drawable,
- GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK);
+ if (stage_x11->xwin == None)
+ stage_x11->xwin = cogl_onscreen_x11_get_window_xid (stage_glx->onscreen);
+
+ if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
+ {
+ stage_glx->swap_callback_id =
+ cogl_framebuffer_add_swap_buffers_callback (framebuffer,
+ handle_swap_complete_cb,
+ stage_glx);
}
-#endif /* GLX_INTEL_swap_event */
/* chain up to the StageX11 implementation */
return clutter_stage_window_parent_iface->realize (stage_window);
@@ -311,65 +310,12 @@ clutter_stage_glx_add_redraw_clip (ClutterStageWindow *stage_window,
stage_glx->initialized_redraw_clip = TRUE;
}
-#ifdef HAVE_DRM
-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 /* HAVE_DRM */
-
-static void
-wait_for_vblank (ClutterBackendGLX *backend_glx)
-{
- if (backend_glx->vblank_type == CLUTTER_VBLANK_NONE)
- return;
-
- if (backend_glx->wait_video_sync)
- {
- unsigned int retraceCount;
-
- CLUTTER_NOTE (BACKEND, "Waiting for vblank (wait_video_sync)");
- backend_glx->get_video_sync (&retraceCount);
- backend_glx->wait_video_sync (2,
- (retraceCount + 1) % 2,
- &retraceCount);
- }
- else
- {
-#ifdef HAVE_DRM
- drm_wait_vblank_t blank;
-
- CLUTTER_NOTE (BACKEND, "Waiting for vblank (drm)");
- blank.request.type = _DRM_VBLANK_RELATIVE;
- blank.request.sequence = 1;
- blank.request.signal = 0;
- drm_wait_vblank (backend_glx->dri_fd, &blank);
-#else
- CLUTTER_NOTE (BACKEND, "No vblank mechanism found");
-#endif /* HAVE_DRM */
- }
-}
-
static void
clutter_stage_glx_redraw (ClutterStageWindow *stage_window)
{
- ClutterBackendX11 *backend_x11;
ClutterBackendGLX *backend_glx;
ClutterStageX11 *stage_x11;
ClutterStageGLX *stage_glx;
- GLXDrawable drawable;
- unsigned int video_sync_count;
gboolean may_use_clipped_redraw;
gboolean use_clipped_redraw;
@@ -395,8 +341,7 @@ clutter_stage_glx_redraw (ClutterStageWindow *stage_window)
stage_glx = CLUTTER_STAGE_GLX (stage_window);
- backend_x11 = stage_x11->backend;
- backend_glx = CLUTTER_BACKEND_GLX (backend_x11);
+ backend_glx = CLUTTER_BACKEND_GLX (stage_x11->backend);
CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer);
@@ -502,173 +447,75 @@ clutter_stage_glx_redraw (ClutterStageWindow *stage_window)
cogl_object_unref (vbo);
}
- cogl_flush ();
CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer);
- drawable = stage_glx->glxwin
- ? stage_glx->glxwin
- : stage_x11->xwin;
-
- /* If we might ever use _clutter_backend_glx_blit_sub_buffer then we
- * always need to keep track of the video_sync_count so that we can
- * throttle blits.
- *
- * Note: we get the count *before* we issue any glXCopySubBuffer or
- * blit_sub_buffer request in case the count would go up before
- * returning control to us.
- */
- if (backend_glx->can_blit_sub_buffer && backend_glx->get_video_sync)
- backend_glx->get_video_sync (&video_sync_count);
-
/* push on the screen */
if (use_clipped_redraw)
{
ClutterGeometry *clip = &stage_glx->bounding_redraw_clip;
- ClutterGeometry copy_area;
+ int copy_area[4];
ClutterActor *actor;
- CLUTTER_NOTE (BACKEND,
- "_glx_blit_sub_buffer (window: 0x%lx, "
- "x: %d, y: %d, "
- "width: %d, height: %d)",
- (unsigned long) drawable,
- stage_glx->bounding_redraw_clip.x,
- stage_glx->bounding_redraw_clip.y,
- stage_glx->bounding_redraw_clip.width,
- stage_glx->bounding_redraw_clip.height);
-
/* XXX: It seems there will be a race here in that the stage
- * window may be resized before glXCopySubBufferMESA is handled
- * and so we may copy the wrong region. I can't really see how
- * we can handle this with the current state of X but at least
- * in this case a full redraw should be queued by the resize
- * anyway so it should only exhibit temporary artefacts.
+ * window may be resized before the cogl_framebuffer_swap_region
+ * is handled and so we may copy the wrong region. I can't
+ * really see how we can handle this with the current state of X
+ * but at least in this case a full redraw should be queued by
+ * the resize anyway so it should only exhibit temporary
+ * artefacts.
*/
+
actor = CLUTTER_ACTOR (stage_x11->wrapper);
- copy_area.y = clutter_actor_get_height (actor)
- - clip->y
- - clip->height;
- copy_area.x = clip->x;
- copy_area.width = clip->width;
- copy_area.height = clip->height;
-
- /* We need to ensure that all the rendering is done, otherwise
- * redraw operations that are slower than the framerate can
- * queue up in the pipeline during a heavy animation, causing a
- * larger and larger backlog of rendering visible as lag to the
- * user.
- *
- * Note: since calling glFinish() and sycnrhonizing the CPU with
- * the GPU is far from ideal, we hope that this is only a short
- * term solution.
- * - One idea is to using sync objects to track render
- * completion so we can throttle the backlog (ideally with an
- * additional extension that lets us get notifications in our
- * mainloop instead of having to busy wait for the
- * completion.)
- * - Another option is to support clipped redraws by reusing the
- * contents of old back buffers such that we can flip instead
- * of using a blit and then we can use GLX_INTEL_swap_events
- * to throttle. For this though we would still probably want an
- * additional extension so we can report the limited region of
- * the window damage to X/compositors.
- */
- glFinish ();
- /* glXCopySubBufferMESA and glBlitFramebuffer are not integrated
- * with the glXSwapIntervalSGI mechanism which we usually use to
- * throttle the Clutter framerate to the vertical refresh and so
- * we have to manually wait for the vblank period...
- */
+ copy_area[0] = clip->x;
+ copy_area[1] = clutter_actor_get_height (actor) - clip->y - clip->height;
+ copy_area[2] = clip->width;
+ copy_area[3] = clip->height;
- /* Here 'is_synchronized' only means that the blit won't cause a
- * tear, ie it won't prevent multiple blits per retrace if they
- * can all be performed in the blanking period. If that's the
- * case then we still want to use the vblank sync menchanism but
- * we only need it to throttle redraws.
- */
- if (!backend_glx->blit_sub_buffer_is_synchronized)
- {
- /* XXX: note that glXCopySubBuffer, at least for Intel, is
- * synchronized with the vblank but glBlitFramebuffer may
- * not be so we use the same scheme we do when calling
- * glXSwapBuffers without the swap_control extension and
- * call glFinish () before waiting for the vblank period.
- *
- * See where we call glXSwapBuffers for more details.
- */
- wait_for_vblank (backend_glx);
- }
- else if (backend_glx->get_video_sync)
- {
- /* If we have the GLX_SGI_video_sync extension then we can
- * be a bit smarter about how we throttle blits by avoiding
- * any waits if we can see that the video sync count has
- * already progressed. */
- if (backend_glx->last_video_sync_count == video_sync_count)
- wait_for_vblank (backend_glx);
- }
- else
- wait_for_vblank (backend_glx);
+ CLUTTER_NOTE (BACKEND,
+ "cogl_framebuffer_swap_region (onscreen: %p, "
+ "x: %d, y: %d, "
+ "width: %d, height: %d)",
+ stage_glx->onscreen,
+ copy_area[0], copy_area[1], copy_area[2], copy_area[3]);
CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer);
- _clutter_backend_glx_blit_sub_buffer (backend_glx,
- drawable,
- copy_area.x,
- copy_area.y,
- copy_area.width,
- copy_area.height);
+
+ cogl_framebuffer_swap_region (COGL_FRAMEBUFFER (stage_glx->onscreen),
+ copy_area, 1);
+
CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer);
}
else
{
- CLUTTER_NOTE (BACKEND, "glXSwapBuffers (display: %p, window: 0x%lx)",
- backend_x11->xdpy,
- (unsigned long) drawable);
+ CLUTTER_NOTE (BACKEND, "cogl_framebuffer_swap_buffers (onscreen: %p)",
+ stage_glx->onscreen);
- /* If we have GLX swap buffer events then glXSwapBuffers will return
- * immediately and we need to track that there is a swap in
- * progress... */
+ /* If we have swap buffer events then
+ * cogl_framebuffer_swap_buffers will return immediately and we
+ * need to track that there is a swap in progress... */
if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS))
stage_glx->pending_swaps++;
- if (backend_glx->vblank_type != CLUTTER_VBLANK_GLX_SWAP &&
- backend_glx->vblank_type != CLUTTER_VBLANK_NONE)
- {
- /* If we are going to wait for VBLANK manually, we not only
- * need to flush out pending drawing to the GPU before we
- * sleep, we need to wait for it to finish. Otherwise, we
- * may end up with the situation:
- *
- * - We finish drawing - GPU drawing continues
- * - We go to sleep - GPU drawing continues
- * VBLANK - We call glXSwapBuffers - GPU drawing continues
- * - GPU drawing continues
- * - Swap buffers happens
- *
- * Producing a tear. Calling glFinish() first will cause us
- * to properly wait for the next VBLANK before we swap. This
- * obviously does not happen when we use _GLX_SWAP and let
- * the driver do the right thing
- */
- glFinish ();
-
- wait_for_vblank (backend_glx);
- }
-
CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer);
- glXSwapBuffers (backend_x11->xdpy, drawable);
+ cogl_framebuffer_swap_buffers (COGL_FRAMEBUFFER (stage_glx->onscreen));
CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer);
}
- backend_glx->last_video_sync_count = video_sync_count;
-
/* reset the redraw clipping for the next paint... */
stage_glx->initialized_redraw_clip = FALSE;
stage_glx->frame_count++;
}
+static CoglFramebuffer *
+clutter_stage_glx_get_active_framebuffer (ClutterStageWindow *stage_window)
+{
+ ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
+
+ return COGL_FRAMEBUFFER (stage_glx->onscreen);
+}
+
static void
clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
{
@@ -682,55 +529,7 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
iface->has_redraw_clips = clutter_stage_glx_has_redraw_clips;
iface->ignoring_redraw_clips = clutter_stage_glx_ignoring_redraw_clips;
iface->redraw = clutter_stage_glx_redraw;
+ iface->get_active_framebuffer = clutter_stage_glx_get_active_framebuffer;
/* the rest is inherited from ClutterStageX11 */
}
-
-static ClutterTranslateReturn
-clutter_stage_glx_translate_event (ClutterEventTranslator *translator,
- gpointer native,
- ClutterEvent *event)
-{
-#ifdef GLX_INTEL_swap_event
- ClutterBackendGLX *backend_glx;
- XEvent *xevent = native;
-
- backend_glx = CLUTTER_BACKEND_GLX (clutter_get_default_backend ());
-
- if (xevent->type == (backend_glx->event_base + GLX_BufferSwapComplete))
- {
- ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (translator);
- ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (translator);
- GLXBufferSwapComplete *swap_complete_event;
-
- swap_complete_event = (GLXBufferSwapComplete *) xevent;
-
- if (stage_x11->xwin == swap_complete_event->drawable)
- {
- /* Early versions of the swap_event implementation in Mesa
- * deliver BufferSwapComplete event when not selected for,
- * so if we get a swap event we aren't expecting, just ignore it.
- *
- * https://bugs.freedesktop.org/show_bug.cgi?id=27962
- */
- if (stage_glx->pending_swaps > 0)
- stage_glx->pending_swaps--;
-
- return CLUTTER_TRANSLATE_REMOVE;
- }
- }
-#endif
-
- /* chain up to the common X11 implementation */
- return clutter_event_translator_parent_iface->translate_event (translator,
- native,
- event);
-}
-
-static void
-clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface)
-{
- clutter_event_translator_parent_iface = g_type_interface_peek_parent (iface);
-
- iface->translate_event = clutter_stage_glx_translate_event;
-}
diff --git a/clutter/glx/clutter-stage-glx.h b/clutter/glx/clutter-stage-glx.h
index 9baa0f3..43e8d16 100644
--- a/clutter/glx/clutter-stage-glx.h
+++ b/clutter/glx/clutter-stage-glx.h
@@ -50,8 +50,9 @@ struct _ClutterStageGLX
gint pending_swaps;
- GLXPixmap glxpixmap;
- GLXWindow glxwin;
+ CoglOnscreen *onscreen;
+
+ unsigned int swap_callback_id;
/* We only enable clipped redraws after 2 frames, since we've seen
* a lot of drivers can struggle to get going and may output some
diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c
index c029500..4b04123 100644
--- a/clutter/x11/clutter-backend-x11.c
+++ b/clutter/x11/clutter-backend-x11.c
@@ -134,7 +134,7 @@ cogl_xlib_filter (XEvent *xevent,
ClutterX11FilterReturn retval;
CoglXlibFilterReturn ret;
- ret = _cogl_xlib_handle_event (xevent);
+ ret = cogl_xlib_handle_event (xevent);
switch (ret)
{
case COGL_XLIB_FILTER_REMOVE:
@@ -390,7 +390,7 @@ _clutter_backend_x11_post_parse (ClutterBackend *backend,
/* Cogl needs to know the Xlib display connection for
CoglTexturePixmapX11 */
- _cogl_xlib_set_display (backend_x11->xdpy);
+ cogl_xlib_set_display (backend_x11->xdpy);
/* add event filter for Cogl events */
clutter_x11_add_filter (cogl_xlib_filter, NULL);
diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c
index a587c31..5421742 100644
--- a/clutter/x11/clutter-stage-x11.c
+++ b/clutter/x11/clutter-stage-x11.c
@@ -379,6 +379,13 @@ clutter_stage_x11_realize (ClutterStageWindow *stage_window)
ClutterDeviceManager *device_manager;
int event_flags;
+ if (clutter_stages_by_xid == NULL)
+ clutter_stages_by_xid = g_hash_table_new (NULL, NULL);
+
+ g_hash_table_insert (clutter_stages_by_xid,
+ GINT_TO_POINTER (stage_x11->xwin),
+ stage_x11);
+
set_wm_pid (stage_x11);
set_wm_title (stage_x11);
set_cursor_visible (stage_x11);
@@ -1436,13 +1443,6 @@ _clutter_stage_x11_create_window (ClutterStageX11 *stage_x11)
XFree (xvisinfo);
- if (clutter_stages_by_xid == NULL)
- clutter_stages_by_xid = g_hash_table_new (NULL, NULL);
-
- g_hash_table_insert (clutter_stages_by_xid,
- GINT_TO_POINTER (stage_x11->xwin),
- stage_x11);
-
return TRUE;
}
diff --git a/configure.ac b/configure.ac
index 40f88ec..6642412 100644
--- a/configure.ac
+++ b/configure.ac
@@ -447,6 +447,8 @@ AS_IF([test "x$SUPPORT_GLX" = "x1"],
[
AC_DEFINE([COGL_HAS_GLX_SUPPORT], [1], [Cogl supports OpenGL using the GLX API])
+ AC_DEFINE([COGL_HAS_FULL_WINSYS], [1], [Cogl can create its own OpenGL context])
+
AC_DEFINE([HAVE_CLUTTER_GLX], [1], [Have the GLX backend])
AC_CHECK_HEADERS([GL/glx.h],
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]