summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Bragg <robert@linux.intel.com>2010-11-05 12:28:33 +0000
committerRobert Bragg <robert@linux.intel.com>2011-04-11 17:54:36 +0100
commitd40cdfa3e1c0fd43660002418ce5594b81d80bc1 (patch)
tree7d6de9cac0afdbb67e7f53ef3a87fc12b9424983
parentbcd97f35ead2efc48b905e43ed981cd4d5850229 (diff)
downloadcogl-d40cdfa3e1c0fd43660002418ce5594b81d80bc1.tar.gz
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.
-rw-r--r--cogl/Makefile.am44
-rw-r--r--cogl/cogl-clutter.c14
-rw-r--r--cogl/cogl-clutter.h10
-rw-r--r--cogl/cogl-context-private.h34
-rw-r--r--cogl/cogl-context.c104
-rw-r--r--cogl/cogl-context.h7
-rw-r--r--cogl/cogl-debug.h1
-rw-r--r--cogl/cogl-display-glx-private.h57
-rw-r--r--cogl/cogl-display-xlib-private.h35
-rw-r--r--cogl/cogl-display.c5
-rw-r--r--cogl/cogl-display.h12
-rw-r--r--cogl/cogl-feature-private.c5
-rw-r--r--cogl/cogl-feature-private.h20
-rw-r--r--cogl/cogl-framebuffer-private.h39
-rw-r--r--cogl/cogl-framebuffer.c235
-rw-r--r--cogl/cogl-framebuffer.h109
-rw-r--r--cogl/cogl-internal.h102
-rw-r--r--cogl/cogl-journal-private.h1
-rw-r--r--cogl/cogl-private.h6
-rw-r--r--cogl/cogl-renderer-glx-private.h61
-rw-r--r--cogl/cogl-renderer-x11-private.h32
-rw-r--r--cogl/cogl-renderer-xlib-private.h (renamed from cogl/winsys/cogl-winsys-xlib.h)50
-rw-r--r--cogl/cogl-renderer-xlib.c288
-rw-r--r--cogl/cogl-renderer.c23
-rw-r--r--cogl/cogl-types.h87
-rw-r--r--cogl/cogl-util.c1
-rw-r--r--cogl/cogl-xlib-private.h82
-rw-r--r--cogl/cogl-xlib.c (renamed from cogl/winsys/cogl-winsys-xlib.c)104
-rw-r--r--cogl/cogl-xlib.h84
-rw-r--r--cogl/cogl.c10
-rw-r--r--cogl/cogl.h52
-rw-r--r--cogl/driver/gl/cogl-context-driver-gl.h53
-rw-r--r--cogl/driver/gl/cogl-gl.c40
-rw-r--r--cogl/driver/gles/cogl-context-driver-gles.h52
-rw-r--r--cogl/driver/gles/cogl-gles.c46
-rw-r--r--cogl/winsys/cogl-context-winsys.c152
-rw-r--r--cogl/winsys/cogl-context-winsys.h118
-rw-r--r--cogl/winsys/cogl-texture-pixmap-x11.c111
-rw-r--r--cogl/winsys/cogl-winsys-feature-functions.h45
-rw-r--r--cogl/winsys/cogl-winsys-glx-feature-functions.h105
-rw-r--r--cogl/winsys/cogl-winsys-glx.c1262
-rw-r--r--cogl/winsys/cogl-winsys-private.h88
-rw-r--r--cogl/winsys/cogl-winsys-stub.c114
-rw-r--r--cogl/winsys/cogl-winsys.c36
44 files changed, 3229 insertions, 707 deletions
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 80b5ae5d..c4d2f50b 100644
--- a/cogl/Makefile.am
+++ b/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/cogl/cogl-clutter.c b/cogl/cogl-clutter.c
index 07f827af..facdeb31 100644
--- a/cogl/cogl-clutter.c
+++ b/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/cogl/cogl-clutter.h b/cogl/cogl-clutter.h
index 023d14fd..a1216718 100644
--- a/cogl/cogl-clutter.h
+++ b/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/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
index 83a9ebde..ba54de74 100644
--- a/cogl/cogl-context-private.h
+++ b/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/cogl/cogl-context.c b/cogl/cogl-context.c
index ed950c30..a543baa1 100644
--- a/cogl/cogl-context.c
+++ b/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/cogl/cogl-context.h b/cogl/cogl-context.h
index d8cab2a2..9394fbfa 100644
--- a/cogl/cogl-context.h
+++ b/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/cogl/cogl-debug.h b/cogl/cogl-debug.h
index 0cd039f2..87f280db 100644
--- a/cogl/cogl-debug.h
+++ b/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/cogl/cogl-display-glx-private.h b/cogl/cogl-display-glx-private.h
new file mode 100644
index 00000000..279b653a
--- /dev/null
+++ b/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/cogl/cogl-display-xlib-private.h b/cogl/cogl-display-xlib-private.h
new file mode 100644
index 00000000..6e283880
--- /dev/null
+++ b/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/cogl/cogl-display.c b/cogl/cogl-display.c
index ebaaafa9..a09de181 100644
--- a/cogl/cogl-display.c
+++ b/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/cogl/cogl-display.h b/cogl/cogl-display.h
index 5dec9db9..00ce4fb0 100644
--- a/cogl/cogl-display.h
+++ b/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/cogl/cogl-feature-private.c b/cogl/cogl-feature-private.c
index deff9fc3..d3904b48 100644
--- a/cogl/cogl-feature-private.c
+++ b/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/cogl/cogl-feature-private.h b/cogl/cogl-feature-private.h
index 133d588e..5d0101e4 100644
--- a/cogl/cogl-feature-private.h
+++ b/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/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h
index afc8fe19..ee6f3fff 100644
--- a/cogl/cogl-framebuffer-private.h
+++ b/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/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index a1459942..e67e27bf 100644
--- a/cogl/cogl-framebuffer.c
+++ b/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/cogl/cogl-framebuffer.h b/cogl/cogl-framebuffer.h
new file mode 100644
index 00000000..1e0a300d
--- /dev/null
+++ b/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/cogl/cogl-internal.h b/cogl/cogl-internal.h
index 09f5cbcd..eba62bf7 100644
--- a/cogl/cogl-internal.h
+++ b/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/cogl/cogl-journal-private.h b/cogl/cogl-journal-private.h
index 44a4af85..7212dca4 100644
--- a/cogl/cogl-journal-private.h
+++ b/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/cogl/cogl-private.h b/cogl/cogl-private.h
index 4407b421..bd09f4ed 100644
--- a/cogl/cogl-private.h
+++ b/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/cogl/cogl-renderer-glx-private.h b/cogl/cogl-renderer-glx-private.h
new file mode 100644
index 00000000..aaebc9ea
--- /dev/null
+++ b/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/cogl/cogl-renderer-x11-private.h b/cogl/cogl-renderer-x11-private.h
new file mode 100644
index 00000000..5ec56cc8
--- /dev/null
+++ b/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/cogl/winsys/cogl-winsys-xlib.h b/cogl/cogl-renderer-xlib-private.h
index 62a21621..13f94641 100644
--- a/cogl/winsys/cogl-winsys-xlib.h
+++ b/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/cogl/cogl-renderer-xlib.c b/cogl/cogl-renderer-xlib.c
new file mode 100644
index 00000000..bd2cc2b8
--- /dev/null
+++ b/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/cogl/cogl-renderer.c b/cogl/cogl-renderer.c
index 9eddc9b4..2dffb2f2 100644
--- a/cogl/cogl-renderer.c
+++ b/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/cogl/cogl-types.h b/cogl/cogl-types.h
index 6b5ff036..1a1aac4b 100644
--- a/cogl/cogl-types.h
+++ b/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/cogl/cogl-util.c b/cogl/cogl-util.c
index d38049a9..ddee76a5 100644
--- a/cogl/cogl-util.c
+++ b/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/cogl/cogl-xlib-private.h b/cogl/cogl-xlib-private.h
new file mode 100644
index 00000000..39bfeba6
--- /dev/null
+++ b/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/cogl/winsys/cogl-winsys-xlib.c b/cogl/cogl-xlib.c
index 636b9fb9..ce7fb159 100644
--- a/cogl/winsys/cogl-winsys-xlib.c
+++ b/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/cogl/cogl-xlib.h b/cogl/cogl-xlib.h
new file mode 100644
index 00000000..c776ece2
--- /dev/null
+++ b/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/cogl/cogl.c b/cogl/cogl.c
index aa483c9c..49882d9c 100644
--- a/cogl/cogl.c
+++ b/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/cogl/cogl.h b/cogl/cogl.h
index fffc12c6..cbd2d0c0 100644
--- a/cogl/cogl.h
+++ b/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/cogl/driver/gl/cogl-context-driver-gl.h b/cogl/driver/gl/cogl-context-driver-gl.h
new file mode 100644
index 00000000..2d8e5213
--- /dev/null
+++ b/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/cogl/driver/gl/cogl-gl.c b/cogl/driver/gl/cogl-gl.c
index b26f230a..b5a3bee8 100644
--- a/cogl/driver/gl/cogl-gl.c
+++ b/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/cogl/driver/gles/cogl-context-driver-gles.h b/cogl/driver/gles/cogl-context-driver-gles.h
new file mode 100644
index 00000000..ca3b1d4b
--- /dev/null
+++ b/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/cogl/driver/gles/cogl-gles.c b/cogl/driver/gles/cogl-gles.c
index 304e5378..f137925b 100644
--- a/cogl/driver/gles/cogl-gles.c
+++ b/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/cogl/winsys/cogl-context-winsys.c b/cogl/winsys/cogl-context-winsys.c
deleted file mode 100644
index ad7a96d9..00000000
--- a/cogl/winsys/cogl-context-winsys.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * 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
-
-#ifdef COGL_HAS_GLX_SUPPORT
-#include <GL/glx.h>
-#endif
-
-#include "cogl-context-private.h"
-#include "cogl-feature-private.h"
-
-/* 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) \
- static const CoglFeatureFunction \
- cogl_winsys_feature_ ## name ## _funcs[] = {
-#define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) \
- { G_STRINGIFY (name), G_STRUCT_OFFSET (CoglContext, winsys.pf_ ## name) },
-#define COGL_WINSYS_FEATURE_END() \
- { NULL, 0 }, \
- };
-#include "cogl-winsys-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) \
- { 255, 255, namespaces, extension_names, \
- feature_flags, feature_flags_private, \
- cogl_winsys_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 cogl_winsys_feature_data[] =
- {
-#include "cogl-winsys-feature-functions.h"
-
- /* This stub is just here so that if the header is empty then we
- won't end up declaring an empty array */
- { 0, }
- };
-
-#define COGL_WINSYS_N_FEATURES (G_N_ELEMENTS (cogl_winsys_feature_data) - 1)
-
-static const char *
-_cogl_get_winsys_extensions (void)
-{
-#ifdef COGL_HAS_GLX_SUPPORT
- Display *display = _cogl_xlib_get_display ();
-
- return glXQueryExtensionsString (display, DefaultScreen (display));
-#else
- return "";
-#endif
-}
-
-static void
-_cogl_winsys_features_init (CoglContext *context)
-{
- CoglWinsysFeatureFlags flags = 0;
- const char *extensions = _cogl_get_winsys_extensions ();
- int i;
-
- for (i = 0; i < COGL_WINSYS_N_FEATURES; i++)
- if (_cogl_feature_check ("GLX", cogl_winsys_feature_data + i, 0, 0,
- extensions))
- flags |= cogl_winsys_feature_data[i].feature_flags;
-
- context->winsys.feature_flags = flags;
-}
-
-void
-_cogl_create_context_winsys (CoglContext *context)
-{
-#ifdef COGL_HAS_XLIB_SUPPORT
- {
- Display *display = _cogl_xlib_get_display ();
- int damage_error;
-
- /* Check whether damage events are supported on this display */
- if (!XDamageQueryExtension (display,
- &context->winsys.damage_base,
- &damage_error))
- context->winsys.damage_base = -1;
-
- context->winsys.event_filters = NULL;
-
- context->winsys.trap_state = NULL;
- }
-#endif
-
-#ifdef COGL_HAS_GLX_SUPPORT
- {
- int i;
-
- for (i = 0; i < COGL_WINSYS_N_CACHED_CONFIGS; i++)
- context->winsys.glx_cached_configs[i].depth = -1;
-
- context->winsys.rectangle_state = COGL_WINSYS_RECTANGLE_STATE_UNKNOWN;
- }
-#endif
-
- _cogl_winsys_features_init (context);
-}
-
-#ifdef COGL_HAS_XLIB_SUPPORT
-
-#include "cogl-xlib.h"
-
-static void
-free_xlib_filter_closure (gpointer data, gpointer user_data)
-{
- g_slice_free (CoglXlibFilterClosure, data);
-}
-
-#endif
-
-void
-_cogl_destroy_context_winsys (CoglContext *context)
-{
-#ifdef COGL_HAS_XLIB_SUPPORT
- g_slist_foreach (context->winsys.event_filters,
- free_xlib_filter_closure, NULL);
- g_slist_free (context->winsys.event_filters);
-#endif
-}
diff --git a/cogl/winsys/cogl-context-winsys.h b/cogl/winsys/cogl-context-winsys.h
deleted file mode 100644
index a0189e8e..00000000
--- a/cogl/winsys/cogl-context-winsys.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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/>.
- *
- *
- */
-
-#ifndef __COGL_CONTEXT_WINSYS_H
-#define __COGL_CONTEXT_WINSYS_H
-
-#ifdef COGL_HAS_XLIB_SUPPORT
-#include <X11/extensions/Xdamage.h>
-#include <X11/Xlib.h>
-#endif
-
-#ifdef COGL_HAS_GLX_SUPPORT
-#include <GL/glx.h>
-#endif
-
-typedef enum
-{
- COGL_WINSYS_FEATURE_TEXTURE_FROM_PIXMAP = 1
-} CoglWinsysFeatureFlags;
-
-#ifdef COGL_HAS_XLIB_SUPPORT
-
-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;
-};
-
-#endif /* COGL_HAS_XLIB_SUPPORT */
-
-#ifdef COGL_HAS_GLX_SUPPORT
-
-typedef struct
-{
- /* This will be -1 if there is no cached config in this slot */
- int depth;
- gboolean found;
- GLXFBConfig fb_config;
- gboolean can_mipmap;
-} CoglWinsysCachedConfig;
-
-#define COGL_WINSYS_N_CACHED_CONFIGS 3
-
-typedef enum
-{
- COGL_WINSYS_RECTANGLE_STATE_UNKNOWN,
- COGL_WINSYS_RECTANGLE_STATE_DISABLE,
- COGL_WINSYS_RECTANGLE_STATE_ENABLE
-} CoglWinsysRectangleState;
-
-#endif /* COGL_HAS_GLX_SUPPORT */
-
-typedef struct
-{
- /* These are specific to winsys backends supporting Xlib. This
- should probably eventually be moved into a separate file specific
- to Xlib when Cogl gains a more complete winsys abstraction */
-#ifdef COGL_HAS_XLIB_SUPPORT
- /* This will be -1 if the damage extension is not support, or it
- will be the event number offset for damage events if it is */
- 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
-
-#ifdef COGL_HAS_GLX_SUPPORT
- CoglWinsysCachedConfig glx_cached_configs[COGL_WINSYS_N_CACHED_CONFIGS];
- /* Whether the texture rectangle extension should be used */
- CoglWinsysRectangleState rectangle_state;
-#endif
-
- /* Function pointers for winsys specific extensions */
-#define COGL_WINSYS_FEATURE_BEGIN(a, b, c, d, e)
-
-#define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) \
- ret (APIENTRY * pf_ ## name) args;
-
-#define COGL_WINSYS_FEATURE_END()
-
-#include "cogl-winsys-feature-functions.h"
-
-#undef COGL_WINSYS_FEATURE_BEGIN
-#undef COGL_WINSYS_FEATURE_FUNCTION
-#undef COGL_WINSYS_FEATURE_END
-
- CoglWinsysFeatureFlags feature_flags;
-} CoglContextWinsys;
-
-#endif /* __COGL_CONTEXT_WINSYS_H */
diff --git a/cogl/winsys/cogl-texture-pixmap-x11.c b/cogl/winsys/cogl-texture-pixmap-x11.c
index 98ecf314..9f8ec698 100644
--- a/cogl/winsys/cogl-texture-pixmap-x11.c
+++ b/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/cogl/winsys/cogl-winsys-feature-functions.h b/cogl/winsys/cogl-winsys-feature-functions.h
deleted file mode 100644
index 6bfe973c..00000000
--- a/cogl/winsys/cogl-winsys-feature-functions.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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 */
-
-#ifdef COGL_HAS_GLX_SUPPORT
-
-COGL_WINSYS_FEATURE_BEGIN (texture_from_pixmap,
- "EXT\0",
- "texture_from_pixmap\0",
- COGL_WINSYS_FEATURE_TEXTURE_FROM_PIXMAP,
- 0)
-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 ()
-
-#endif
diff --git a/cogl/winsys/cogl-winsys-glx-feature-functions.h b/cogl/winsys/cogl-winsys-glx-feature-functions.h
new file mode 100644
index 00000000..50df5628
--- /dev/null
+++ b/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/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c
index c0f6d5c2..2a81d3ac 100644
--- a/cogl/winsys/cogl-winsys-glx.c
+++ b/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 (&current_count);
+ glx_renderer->pf_glXWaitVideoSync (2,
+ (current_count + 1) % 2,
+ &current_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/cogl/winsys/cogl-winsys-private.h b/cogl/winsys/cogl-winsys-private.h
index 4cf326e3..8d56bea4 100644
--- a/cogl/winsys/cogl-winsys-private.h
+++ b/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/cogl/winsys/cogl-winsys-stub.c b/cogl/winsys/cogl-winsys-stub.c
new file mode 100644
index 00000000..66481506
--- /dev/null
+++ b/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/cogl/winsys/cogl-winsys.c b/cogl/winsys/cogl-winsys.c
new file mode 100644
index 00000000..e59063a5
--- /dev/null
+++ b/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");
+}
+