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.
This commit is contained in:
Robert Bragg 2010-11-05 12:28:33 +00:00
parent aa1a2cb661
commit d6f110a4d2
54 changed files with 3443 additions and 1638 deletions

View File

@ -37,6 +37,11 @@ struct _ClutterBackend
{ {
/*< private >*/ /*< private >*/
GObject parent_instance; GObject parent_instance;
CoglRenderer *cogl_renderer;
CoglDisplay *cogl_display;
CoglContext *cogl_context;
ClutterBackendPrivate *priv; ClutterBackendPrivate *priv;
}; };

View File

@ -53,6 +53,7 @@
#include "clutter-version.h" #include "clutter-version.h"
#include <cogl/cogl.h> #include <cogl/cogl.h>
#include <cogl/cogl-internal.h>
G_DEFINE_ABSTRACT_TYPE (ClutterBackend, clutter_backend, G_TYPE_OBJECT); G_DEFINE_ABSTRACT_TYPE (ClutterBackend, clutter_backend, G_TYPE_OBJECT);

View File

@ -672,7 +672,6 @@ clutter_stage_realize (ClutterActor *self)
if (is_realized) if (is_realized)
{ {
ClutterBackend *backend = clutter_get_default_backend (); ClutterBackend *backend = clutter_get_default_backend ();
GError *error = NULL;
/* We want to select the context without calling /* We want to select the context without calling
clutter_backend_ensure_context so that it doesn't call any clutter_backend_ensure_context so that it doesn't call any
@ -680,17 +679,6 @@ clutter_stage_realize (ClutterActor *self)
before we get a chance to check whether the GL version is before we get a chance to check whether the GL version is
valid */ valid */
_clutter_backend_ensure_context_internal (backend, CLUTTER_STAGE (self)); _clutter_backend_ensure_context_internal (backend, CLUTTER_STAGE (self));
/* Make sure Cogl can support the driver */
if (!_cogl_check_driver_valid (&error))
{
g_critical ("The GL driver is not supported: %s",
error->message);
g_clear_error (&error);
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
}
else
CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
} }
else else
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED); CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);

View File

@ -78,6 +78,7 @@ cogl_public_h = \
$(srcdir)/cogl-attribute.h \ $(srcdir)/cogl-attribute.h \
$(srcdir)/cogl-primitive.h \ $(srcdir)/cogl-primitive.h \
$(srcdir)/cogl-clip-state.h \ $(srcdir)/cogl-clip-state.h \
$(srcdir)/cogl-framebuffer.h \
$(srcdir)/cogl-clutter.h \ $(srcdir)/cogl-clutter.h \
$(srcdir)/cogl.h \ $(srcdir)/cogl.h \
$(NULL) $(NULL)
@ -114,10 +115,8 @@ endif # COGL_DRIVER_GLES
# winsys sources, common to all backends # winsys sources, common to all backends
cogl_winsys_common_sources = \ cogl_winsys_common_sources = \
$(srcdir)/winsys/cogl-winsys-private.h \ $(srcdir)/winsys/cogl-winsys-private.h \
$(srcdir)/winsys/cogl-context-winsys.h \ $(srcdir)/winsys/cogl-winsys.c \
$(srcdir)/winsys/cogl-context-winsys.c \
$(srcdir)/winsys/cogl-winsys-feature-functions.h \
$(NULL) $(NULL)
# tesselator sources # tesselator sources
@ -295,29 +294,39 @@ cogl_sources_c = \
if SUPPORT_XLIB if SUPPORT_XLIB
cogl_experimental_h += \ cogl_experimental_h += \
$(srcdir)/winsys/cogl-texture-pixmap-x11.h $(srcdir)/winsys/cogl-texture-pixmap-x11.h \
$(srcdir)/cogl-xlib.h
cogl_sources_c += \ cogl_sources_c += \
$(srcdir)/winsys/cogl-winsys-xlib.h \ $(srcdir)/cogl-renderer-x11-private.h \
$(srcdir)/winsys/cogl-winsys-xlib.c \ $(srcdir)/cogl-renderer-xlib-private.h \
$(srcdir)/winsys/cogl-texture-pixmap-x11.c \ $(srcdir)/cogl-renderer-xlib.c \
$(srcdir)/winsys/cogl-texture-pixmap-x11-private.h $(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 endif
if SUPPORT_GLX if SUPPORT_GLX
cogl_sources_c += \ 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 endif
if SUPPORT_EGL_PLATFORM_POWERVR_X11 if SUPPORT_EGL_PLATFORM_POWERVR_X11
cogl_sources_c += \ cogl_sources_c += \
$(srcdir)/winsys/cogl-winsys-egl.c $(srcdir)/winsys/cogl-winsys-egl.c \
$(srcdir)/winsys/cogl-winsys-stub.c
endif endif
if SUPPORT_EGL_PLATFORM_POWERVR_NULL if SUPPORT_EGL_PLATFORM_POWERVR_NULL
cogl_sources_c += \ cogl_sources_c += \
$(srcdir)/winsys/cogl-winsys-egl.c $(srcdir)/winsys/cogl-winsys-egl.c \
$(srcdir)/winsys/cogl-winsys-stub.c
endif endif
if SUPPORT_EGL_PLATFORM_POWERVR_GDL if SUPPORT_EGL_PLATFORM_POWERVR_GDL
cogl_sources_c += \ cogl_sources_c += \
$(srcdir)/winsys/cogl-winsys-egl.c $(srcdir)/winsys/cogl-winsys-egl.c \
$(srcdir)/winsys/cogl-winsys-stub.c
endif endif
if SUPPORT_EGL_PLATFORM_FRUITY if SUPPORT_EGL_PLATFORM_FRUITY
cogl_sources_c += \ cogl_sources_c += \
@ -325,15 +334,18 @@ cogl_sources_c += \
endif endif
if SUPPORT_EGL_PLATFORM_DRM_SURFACELESS if SUPPORT_EGL_PLATFORM_DRM_SURFACELESS
cogl_sources_c += \ cogl_sources_c += \
$(srcdir)/winsys/cogl-winsys-egl.c $(srcdir)/winsys/cogl-winsys-egl.c \
$(srcdir)/winsys/cogl-winsys-stub.c
endif endif
if SUPPORT_WIN32 if SUPPORT_WIN32
cogl_sources_c += \ cogl_sources_c += \
$(srcdir)/winsys/cogl-winsys-win32.c $(srcdir)/winsys/cogl-winsys-win32.c \
$(srcdir)/winsys/cogl-winsys-stub.c
endif endif
if SUPPORT_OSX if SUPPORT_OSX
cogl_sources_c += \ cogl_sources_c += \
$(srcdir)/winsys/cogl-winsys-osx.c $(srcdir)/winsys/cogl-winsys-osx.c \
$(srcdir)/winsys/cogl-winsys-stub.c
endif endif
EXTRA_DIST += stb_image.c EXTRA_DIST += stb_image.c

View File

@ -43,6 +43,12 @@ cogl_clutter_check_extension (const char *name, const char *ext)
return _cogl_check_extension (name, ext); return _cogl_check_extension (name, ext);
} }
gboolean
cogl_clutter_winsys_has_feature (CoglWinsysFeature feature)
{
return _cogl_winsys_has_feature (feature);
}
void void
cogl_onscreen_clutter_backend_set_size (int width, int height) 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); _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

View File

@ -38,10 +38,20 @@ G_BEGIN_DECLS
gboolean gboolean
cogl_clutter_check_extension (const char *name, const char *ext); 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 #define cogl_onscreen_clutter_backend_set_size cogl_onscreen_clutter_backend_set_size_CLUTTER
void void
cogl_onscreen_clutter_backend_set_size (int width, int height); 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 G_END_DECLS
#endif /* __COGL_CLUTTER_H__ */ #endif /* __COGL_CLUTTER_H__ */

View File

@ -26,6 +26,11 @@
#include "cogl-internal.h" #include "cogl-internal.h"
#include "cogl-context.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 #if HAVE_COGL_GL
#include "cogl-context-driver-gl.h" #include "cogl-context-driver-gl.h"
@ -35,7 +40,7 @@
#include "cogl-context-driver-gles.h" #include "cogl-context-driver-gles.h"
#endif #endif
#include "cogl-context-winsys.h" #include "cogl-display-private.h"
#include "cogl-primitives.h" #include "cogl-primitives.h"
#include "cogl-clip-stack.h" #include "cogl-clip-stack.h"
#include "cogl-matrix-stack.h" #include "cogl-matrix-stack.h"
@ -55,9 +60,10 @@ struct _CoglContext
{ {
CoglObject _parent; CoglObject _parent;
CoglDisplay *display;
/* Features cache */ /* Features cache */
CoglFeatureFlags feature_flags; CoglFeatureFlags feature_flags;
CoglFeatureFlagsPrivate feature_flags_private;
CoglHandle default_pipeline; CoglHandle default_pipeline;
CoglHandle default_layer_0; CoglHandle default_layer_0;
@ -70,8 +76,6 @@ struct _CoglContext
gboolean enable_backface_culling; gboolean enable_backface_culling;
CoglFrontWinding flushed_front_winding; CoglFrontWinding flushed_front_winding;
gboolean indirect;
/* A few handy matrix constants */ /* A few handy matrix constants */
CoglMatrix identity_matrix; CoglMatrix identity_matrix;
CoglMatrix y_flip_matrix; CoglMatrix y_flip_matrix;
@ -237,8 +241,26 @@ struct _CoglContext
GByteArray *buffer_map_fallback_array; GByteArray *buffer_map_fallback_array;
gboolean buffer_map_fallback_in_use; 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; CoglContextDriver drv;
CoglContextWinsys winsys;
CoglBitmask winsys_features;
void *winsys;
gboolean stub_winsys;
}; };
CoglContext * CoglContext *

View File

@ -28,6 +28,8 @@
#include "cogl.h" #include "cogl.h"
#include "cogl-object.h" #include "cogl-object.h"
#include "cogl-internal.h" #include "cogl-internal.h"
#include "cogl-private.h"
#include "cogl-winsys-private.h"
#include "cogl-profile.h" #include "cogl-profile.h"
#include "cogl-util.h" #include "cogl-util.h"
#include "cogl-context-private.h" #include "cogl-context-private.h"
@ -56,13 +58,8 @@ COGL_OBJECT_DEFINE (Context, context);
extern void extern void
_cogl_create_context_driver (CoglContext *context); _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 CoglContext *_context = NULL;
static gboolean gl_is_indirect = FALSE;
static void static void
_cogl_init_feature_overrides (CoglContext *ctx) _cogl_init_feature_overrides (CoglContext *ctx)
@ -102,15 +99,8 @@ cogl_context_new (CoglDisplay *display,
CoglContext *context; CoglContext *context;
GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 }; GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
unsigned long enable_flags = 0; unsigned long enable_flags = 0;
CoglHandle window_buffer;
int i; 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 #ifdef CLUTTER_ENABLE_PROFILE
/* We need to be absolutely sure that uprof has been initialized /* We need to be absolutely sure that uprof has been initialized
* before calling _cogl_uprof_init. uprof_init (NULL, NULL) * 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 * context which it can access via _COGL_GET_CONTEXT() including
* code used to construct a CoglContext. Until all of that code * code used to construct a CoglContext. Until all of that code
* has been updated to take an explicit context argument we have * 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; _context = context;
/* Init default values */ /* Init default values */
_context->feature_flags = 0; context->feature_flags = 0;
_context->feature_flags_private = 0;
context->texture_types = NULL; context->texture_types = NULL;
context->buffer_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); display = cogl_display_new (NULL, NULL);
else else
cogl_object_ref (display); cogl_object_ref (display);
@ -158,11 +151,32 @@ cogl_context_new (CoglDisplay *display,
return NULL; return NULL;
} }
/* Initialise the driver specific state */ context->display = display;
_cogl_gl_context_init (context);
_cogl_init_feature_overrides (context);
_cogl_create_context_winsys (context); #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_init_feature_overrides (context);
_cogl_pipeline_init_default_pipeline (); _cogl_pipeline_init_default_pipeline ();
_cogl_pipeline_init_default_layers (); _cogl_pipeline_init_default_layers ();
@ -174,8 +188,6 @@ cogl_context_new (CoglDisplay *display,
context->enable_backface_culling = FALSE; context->enable_backface_culling = FALSE;
context->flushed_front_winding = COGL_FRONT_WINDING_COUNTER_CLOCKWISE; 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->identity_matrix);
cogl_matrix_init_identity (&context->y_flip_matrix); cogl_matrix_init_identity (&context->y_flip_matrix);
cogl_matrix_scale (&context->y_flip_matrix, 1, -1, 1); 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->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 (); _context->current_clip_stack_valid = FALSE;
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->dirty_bound_framebuffer = TRUE; context->dirty_bound_framebuffer = TRUE;
context->dirty_gl_viewport = TRUE; context->dirty_gl_viewport = TRUE;
@ -347,7 +364,7 @@ cogl_context_new (CoglDisplay *display,
static void static void
_cogl_context_free (CoglContext *context) _cogl_context_free (CoglContext *context)
{ {
_cogl_destroy_context_winsys (context); _cogl_winsys_context_deinit (context);
_cogl_destroy_texture_units (); _cogl_destroy_texture_units ();
@ -424,6 +441,8 @@ _cogl_context_free (CoglContext *context)
g_byte_array_free (context->buffer_map_fallback_array, TRUE); g_byte_array_free (context->buffer_map_fallback_array, TRUE);
_cogl_bitmask_destroy (&context->winsys_features);
cogl_object_unref (context->display); cogl_object_unref (context->display);
g_free (context); g_free (context);
@ -448,31 +467,12 @@ _cogl_context_get_default (void)
return _context; 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 void
_cogl_set_indirect_context (gboolean indirect) cogl_set_default_context (CoglContext *context)
{ {
/* we get called multiple times if someone creates cogl_object_ref (context);
* 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;
}
gl_is_indirect = indirect; if (_context)
cogl_object_unref (_context);
_context = context;
} }

View File

@ -54,7 +54,12 @@ typedef struct _CoglContext CoglContext;
#define cogl_context_new cogl_context_new_EXP #define cogl_context_new cogl_context_new_EXP
CoglContext * 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 G_END_DECLS

View File

@ -63,6 +63,7 @@ typedef enum {
COGL_DEBUG_DISABLE_PROGRAM_CACHES, COGL_DEBUG_DISABLE_PROGRAM_CACHES,
COGL_DEBUG_DISABLE_FAST_READ_PIXEL, COGL_DEBUG_DISABLE_FAST_READ_PIXEL,
COGL_DEBUG_CLIPPING, COGL_DEBUG_CLIPPING,
COGL_DEBUG_WINSYS,
COGL_DEBUG_N_FLAGS COGL_DEBUG_N_FLAGS
} CoglDebugFlags; } CoglDebugFlags;

View File

@ -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 */

View File

@ -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 */

View File

@ -100,6 +100,11 @@ cogl_display_setup (CoglDisplay *display,
if (display->setup) if (display->setup)
return TRUE; return TRUE;
#ifdef COGL_HAS_FULL_WINSYS
if (!_cogl_winsys_display_setup (display, error))
return FALSE;
#endif
display->setup = TRUE; display->setup = TRUE;
return TRUE; return TRUE;

View File

@ -31,6 +31,9 @@
#ifndef __COGL_DISPLAY_H__ #ifndef __COGL_DISPLAY_H__
#define __COGL_DISPLAY_H__ #define __COGL_DISPLAY_H__
#include <cogl/cogl-renderer.h>
#include <cogl/cogl-onscreen-template.h>
G_BEGIN_DECLS G_BEGIN_DECLS
/** /**
@ -69,8 +72,15 @@ typedef struct _CoglDisplay CoglDisplay;
#define COGL_DISPLAY(OBJECT) ((CoglDisplay *)OBJECT) #define COGL_DISPLAY(OBJECT) ((CoglDisplay *)OBJECT)
#define cogl_display_new cogl_display_new_EXP
CoglDisplay * 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 G_END_DECLS

View File

@ -37,7 +37,8 @@ _cogl_feature_check (const char *driver_prefix,
const CoglFeatureData *data, const CoglFeatureData *data,
unsigned int gl_major, unsigned int gl_major,
unsigned int gl_minor, unsigned int gl_minor,
const char *extensions_string) const char *extensions_string,
void *function_table)
{ {
const char *suffix = NULL; const char *suffix = NULL;
@ -123,7 +124,7 @@ _cogl_feature_check (const char *driver_prefix,
break; break;
/* Set the function pointer in the context */ /* Set the function pointer in the context */
*(void **) ((guint8 *) ctx + *(void **) ((guint8 *) function_table +
data->functions[func_num].pointer_offset) = func; data->functions[func_num].pointer_offset) = func;
} }

View File

@ -26,6 +26,8 @@
#include <glib.h> #include <glib.h>
#include "cogl-internal.h"
#define COGL_CHECK_GL_VERSION(driver_major, driver_minor, \ #define COGL_CHECK_GL_VERSION(driver_major, driver_minor, \
target_major, target_minor) \ target_major, target_minor) \
((driver_major) > (target_major) || \ ((driver_major) > (target_major) || \
@ -59,17 +61,21 @@ struct _CoglFeatureData
const char *extension_names; const char *extension_names;
/* A set of feature flags to enable if the extension is available */ /* A set of feature flags to enable if the extension is available */
CoglFeatureFlags feature_flags; CoglFeatureFlags feature_flags;
/* A set of private feature flags to enable if the extension is available /* FIXME: This is now unused */
* and for internal use only */ int padding_feature_flags_private;
CoglFeatureFlagsPrivate feature_flags_private; /* An optional corresponding winsys feature. */
CoglWinsysFeature winsys_feature;
/* A list of functions required for this feature. Terminated with a /* A list of functions required for this feature. Terminated with a
NULL name */ NULL name */
const CoglFeatureFunction *functions; const CoglFeatureFunction *functions;
}; };
gboolean _cogl_feature_check (const char *driver_prefix, gboolean
const CoglFeatureData *data, _cogl_feature_check (const char *driver_prefix,
unsigned int gl_major, unsigned int gl_minor, const CoglFeatureData *data,
const char *extensions_string); unsigned int gl_major,
unsigned int gl_minor,
const char *extensions_string,
void *function_table);
#endif /* __COGL_FEATURE_PRIVATE_H */ #endif /* __COGL_FEATURE_PRIVATE_H */

View File

@ -24,11 +24,20 @@
#ifndef __COGL_FRAMEBUFFER_PRIVATE_H #ifndef __COGL_FRAMEBUFFER_PRIVATE_H
#define __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-matrix-stack.h"
#include "cogl-clip-state-private.h" #include "cogl-clip-state-private.h"
#include "cogl-journal-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 { typedef enum _CoglFramebufferType {
COGL_FRAMEBUFFER_TYPE_ONSCREEN, COGL_FRAMEBUFFER_TYPE_ONSCREEN,
COGL_FRAMEBUFFER_TYPE_OFFSCREEN COGL_FRAMEBUFFER_TYPE_OFFSCREEN
@ -37,12 +46,14 @@ typedef enum _CoglFramebufferType {
struct _CoglFramebuffer struct _CoglFramebuffer
{ {
CoglObject _parent; CoglObject _parent;
CoglContext *context;
CoglFramebufferType type; CoglFramebufferType type;
int width; int width;
int height; int height;
/* Format of the pixels in the framebuffer (including the expected /* Format of the pixels in the framebuffer (including the expected
premult state) */ premult state) */
CoglPixelFormat format; CoglPixelFormat format;
gboolean allocated;
CoglMatrixStack *modelview_stack; CoglMatrixStack *modelview_stack;
CoglMatrixStack *projection_stack; CoglMatrixStack *projection_stack;
@ -85,8 +96,6 @@ struct _CoglFramebuffer
gboolean clear_clip_dirty; gboolean clear_clip_dirty;
}; };
#define COGL_FRAMEBUFFER(X) ((CoglFramebuffer *)(X))
typedef struct _CoglOffscreen typedef struct _CoglOffscreen
{ {
CoglFramebuffer _parent; CoglFramebuffer _parent;
@ -103,12 +112,18 @@ typedef enum
#define COGL_OFFSCREEN(X) ((CoglOffscreen *)(X)) #define COGL_OFFSCREEN(X) ((CoglOffscreen *)(X))
typedef struct _CoglOnscreen struct _CoglOnscreen
{ {
CoglFramebuffer _parent; CoglFramebuffer _parent;
} CoglOnscreen;
#define COGL_ONSCREEN(X) ((CoglOnscreen *)(X)) #ifdef COGL_HAS_X11_SUPPORT
guint32 foreign_xid;
#endif
gboolean swap_throttled;
void *winsys;
};
void void
_cogl_framebuffer_state_init (void); _cogl_framebuffer_state_init (void);
@ -233,7 +248,11 @@ typedef enum _CoglFramebufferFlushFlags
COGL_FRAMEBUFFER_FLUSH_SKIP_MODELVIEW = 1L<<0, COGL_FRAMEBUFFER_FLUSH_SKIP_MODELVIEW = 1L<<0,
/* Similarly this flag implies you are going to flush the clip state /* Similarly this flag implies you are going to flush the clip state
yourself */ 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; } CoglFramebufferFlushFlags;
void void
@ -241,9 +260,6 @@ _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
CoglFramebuffer *read_buffer, CoglFramebuffer *read_buffer,
CoglFramebufferFlushFlags flags); CoglFramebufferFlushFlags flags);
CoglHandle
_cogl_onscreen_new (void);
CoglFramebuffer * CoglFramebuffer *
_cogl_get_read_framebuffer (void); _cogl_get_read_framebuffer (void);
@ -339,5 +355,8 @@ _cogl_blit_framebuffer (unsigned int src_x,
unsigned int width, unsigned int width,
unsigned int height); unsigned int height);
CoglOnscreen *
_cogl_onscreen_new (void);
#endif /* __COGL_FRAMEBUFFER_PRIVATE_H */ #endif /* __COGL_FRAMEBUFFER_PRIVATE_H */

View File

@ -36,6 +36,7 @@
#include "cogl-framebuffer-private.h" #include "cogl-framebuffer-private.h"
#include "cogl-clip-stack.h" #include "cogl-clip-stack.h"
#include "cogl-journal-private.h" #include "cogl-journal-private.h"
#include "cogl-winsys-private.h"
#ifndef HAVE_COGL_GLES2 #ifndef HAVE_COGL_GLES2
@ -291,6 +292,8 @@ _cogl_framebuffer_clear4f (CoglFramebuffer *framebuffer,
int scissor_x1; int scissor_x1;
int scissor_y1; int scissor_y1;
g_return_if_fail (framebuffer->allocated);
_cogl_clip_stack_get_bounds (clip_stack, _cogl_clip_stack_get_bounds (clip_stack,
&scissor_x0, &scissor_y0, &scissor_x0, &scissor_y0,
&scissor_x1, &scissor_y1); &scissor_x1, &scissor_y1);
@ -451,6 +454,8 @@ _cogl_framebuffer_clear (CoglFramebuffer *framebuffer,
unsigned long buffers, unsigned long buffers,
const CoglColor *color) const CoglColor *color)
{ {
g_return_if_fail (framebuffer->allocated);
_cogl_framebuffer_clear4f (framebuffer, buffers, _cogl_framebuffer_clear4f (framebuffer, buffers,
cogl_color_get_red_float (color), cogl_color_get_red_float (color),
cogl_color_get_green_float (color), cogl_color_get_green_float (color),
@ -811,8 +816,6 @@ _cogl_offscreen_new_to_texture_full (CoglHandle texhandle,
CoglFramebufferTryFBOData data; CoglFramebufferTryFBOData data;
gboolean fbo_created; gboolean fbo_created;
_COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
if (!cogl_features_available (COGL_FEATURE_OFFSCREEN)) if (!cogl_features_available (COGL_FEATURE_OFFSCREEN))
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
@ -887,8 +890,11 @@ _cogl_offscreen_new_to_texture_full (CoglHandle texhandle,
if (fbo_created) if (fbo_created)
{ {
CoglOffscreen *ret; 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, ctx,
COGL_FRAMEBUFFER_TYPE_OFFSCREEN, COGL_FRAMEBUFFER_TYPE_OFFSCREEN,
cogl_texture_get_format (texhandle), cogl_texture_get_format (texhandle),
@ -901,6 +907,8 @@ _cogl_offscreen_new_to_texture_full (CoglHandle texhandle,
ret = _cogl_offscreen_object_new (offscreen); ret = _cogl_offscreen_object_new (offscreen);
_cogl_texture_associate_framebuffer (texhandle, COGL_FRAMEBUFFER (ret)); _cogl_texture_associate_framebuffer (texhandle, COGL_FRAMEBUFFER (ret));
fb->allocated = TRUE;
return ret; return ret;
} }
else else
@ -946,16 +954,34 @@ _cogl_offscreen_free (CoglOffscreen *offscreen)
g_free (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) _cogl_onscreen_new (void)
{ {
CoglOnscreen *onscreen; CoglOnscreen *onscreen = g_new0 (CoglOnscreen, 1);
_COGL_GET_CONTEXT (ctx, NULL); _COGL_GET_CONTEXT (ctx, NULL);
/* XXX: Until we have full winsys support in Cogl then we can't fully _cogl_framebuffer_init (COGL_FRAMEBUFFER (onscreen),
* implement CoglOnscreen framebuffers, since we can't, e.g. keep track of ctx,
* the window size. */ 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 /* FIXME: We are assuming onscreen buffers will always be
premultiplied so we'll set the premult flag on the bitmap premultiplied so we'll set the premult flag on the bitmap
@ -973,15 +999,41 @@ _cogl_onscreen_new (void)
ctx, ctx,
COGL_FRAMEBUFFER_TYPE_ONSCREEN, COGL_FRAMEBUFFER_TYPE_ONSCREEN,
COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_PIXEL_FORMAT_RGBA_8888_PRE,
0xdeadbeef, /* width */ width, /* width */
0xdeadbeef); /* height */ height); /* height */
onscreen->swap_throttled = TRUE;
return _cogl_onscreen_object_new (onscreen); 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 static void
_cogl_onscreen_free (CoglOnscreen *onscreen) _cogl_onscreen_free (CoglOnscreen *onscreen)
{ {
_cogl_winsys_onscreen_deinit (onscreen);
/* Chain up to parent */ /* Chain up to parent */
_cogl_framebuffer_free (COGL_FRAMEBUFFER (onscreen)); _cogl_framebuffer_free (COGL_FRAMEBUFFER (onscreen));
@ -1059,11 +1111,14 @@ static void
_cogl_set_framebuffers_real (CoglFramebuffer *draw_buffer, _cogl_set_framebuffers_real (CoglFramebuffer *draw_buffer,
CoglFramebuffer *read_buffer) CoglFramebuffer *read_buffer)
{ {
CoglContext *ctx = draw_buffer->context;
CoglFramebufferStackEntry *entry; CoglFramebufferStackEntry *entry;
GSList *l;
g_return_if_fail (context != NULL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
g_return_if_fail (draw_buffer->context == read_buffer->context);
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; 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 * projection matrix stacks and clip state so we need to dirty
* them to ensure they get flushed for the next batch of geometry * them to ensure they get flushed for the next batch of geometry
* we flush */ * we flush */
_cogl_matrix_stack_dirty (draw_buffer->modelview_stack); if (draw_buffer)
_cogl_matrix_stack_dirty (draw_buffer->projection_stack); {
_cogl_matrix_stack_dirty (draw_buffer->modelview_stack);
_cogl_matrix_stack_dirty (draw_buffer->projection_stack);
}
_cogl_clip_stack_dirty (); _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 static void
@ -1182,15 +1254,19 @@ _cogl_push_framebuffers (CoglFramebuffer *draw_buffer,
g_return_if_fail (_cogl_is_framebuffer (read_buffer)); g_return_if_fail (_cogl_is_framebuffer (read_buffer));
ctx = draw_buffer->context; 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 (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 /* Copy the top of the stack so that when we call cogl_set_framebuffer
it will still know what the old framebuffer was */ it will still know what the old framebuffer was */
old_draw_buffer = cogl_object_ref (cogl_get_draw_framebuffer ()); old_draw_buffer = cogl_get_draw_framebuffer ();
old_read_buffer = cogl_object_ref (_cogl_get_read_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 = ctx->framebuffer_stack =
g_slist_prepend (ctx->framebuffer_stack, g_slist_prepend (ctx->framebuffer_stack,
create_stack_entry (old_draw_buffer, create_stack_entry (old_draw_buffer,
@ -1264,15 +1340,20 @@ cogl_pop_draw_buffer (void)
} }
static 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) if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
GE (glBindFramebuffer (target, GE (glBindFramebuffer (target,
COGL_OFFSCREEN (framebuffer)->fbo_handle)); COGL_OFFSCREEN (framebuffer)->fbo_handle));
else else
GE (glBindFramebuffer (target, 0)); {
#ifdef COGL_HAS_FULL_WINSYS
_cogl_winsys_onscreen_bind (COGL_ONSCREEN (framebuffer));
#endif
GE (glBindFramebuffer (target, 0));
}
} }
void void
@ -1282,21 +1363,29 @@ _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
{ {
CoglContext *ctx = draw_buffer->context; CoglContext *ctx = draw_buffer->context;
if (cogl_features_available (COGL_FEATURE_OFFSCREEN) && if (ctx->dirty_bound_framebuffer)
ctx->dirty_bound_framebuffer)
{ {
if (!cogl_features_available (COGL_FEATURE_OFFSCREEN_BLIT) || if (draw_buffer == read_buffer)
draw_buffer == read_buffer) bind_gl_framebuffer (ctx, GL_FRAMEBUFFER, draw_buffer);
bind_gl_framebuffer (GL_FRAMEBUFFER, draw_buffer);
else else
{ {
bind_gl_framebuffer (GL_DRAW_FRAMEBUFFER, draw_buffer); /* NB: Currently we only take advantage of binding separate
bind_gl_framebuffer (GL_READ_FRAMEBUFFER, read_buffer); * 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);
ctx->dirty_bound_framebuffer = FALSE; bind_gl_framebuffer (ctx, GL_DRAW_FRAMEBUFFER, draw_buffer);
bind_gl_framebuffer (ctx, GL_READ_FRAMEBUFFER, read_buffer);
}
} }
ctx->dirty_bound_framebuffer = FALSE;
if (flags & COGL_FRAMEBUFFER_FLUSH_BIND_ONLY)
return;
if (ctx->dirty_gl_viewport) if (ctx->dirty_gl_viewport)
{ {
float gl_viewport_y; float gl_viewport_y;
@ -1452,6 +1541,8 @@ _cogl_blit_framebuffer (unsigned int src_x,
CoglFramebuffer *read_buffer; CoglFramebuffer *read_buffer;
CoglContext *ctx; CoglContext *ctx;
/* FIXME: this function should take explit src and dst framebuffer
* arguments. */
draw_buffer = cogl_get_draw_framebuffer (); draw_buffer = cogl_get_draw_framebuffer ();
read_buffer = _cogl_get_read_framebuffer (); read_buffer = _cogl_get_read_framebuffer ();
ctx = draw_buffer->context; ctx = draw_buffer->context;
@ -1484,3 +1575,83 @@ _cogl_blit_framebuffer (unsigned int src_x,
GL_COLOR_BUFFER_BIT, GL_COLOR_BUFFER_BIT,
GL_NEAREST); 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);
}

View File

@ -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 */

View File

@ -29,7 +29,7 @@
#include "cogl-bitmask.h" #include "cogl-bitmask.h"
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
#include <X11/Xlib.h> #include <X11/Xutil.h>
#endif #endif
typedef enum typedef enum
@ -119,99 +119,17 @@ _cogl_transform_point (const CoglMatrix *matrix_mv,
float *x, float *x,
float *y); float *y);
#ifdef COGL_HAS_XLIB_SUPPORT #define COGL_DRIVER_ERROR (_cogl_driver_error_quark ())
/* typedef enum { /*< prefix=COGL_DRIVER_ERROR >*/
* CoglX11FilterReturn: COGL_DRIVER_ERROR_UNKNOWN_VERSION,
* @COGL_XLIB_FILTER_CONTINUE: The event was not handled, continues the COGL_DRIVER_ERROR_INVALID_VERSION
* processing } CoglDriverError;
* @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);
/*
* 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;
gboolean 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 */ #endif /* __COGL_INTERNAL_H */

View File

@ -24,6 +24,7 @@
#ifndef __COGL_JOURNAL_PRIVATE_H #ifndef __COGL_JOURNAL_PRIVATE_H
#define __COGL_JOURNAL_PRIVATE_H #define __COGL_JOURNAL_PRIVATE_H
#include "cogl.h"
#include "cogl-handle.h" #include "cogl-handle.h"
#include "cogl-clip-stack.h" #include "cogl-clip-stack.h"

View File

@ -26,6 +26,12 @@
G_BEGIN_DECLS G_BEGIN_DECLS
gboolean
_cogl_gl_check_version (GError **error);
void
_cogl_gl_update_features (CoglContext *context);
gboolean gboolean
_cogl_check_extension (const char *name, const char *ext); _cogl_check_extension (const char *name, const char *ext);

View File

@ -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 */

View File

@ -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 */

View File

@ -3,7 +3,7 @@
* *
* An object oriented GL/GLES Abstraction/Utility Layer * 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * 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 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public License
* License along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
* *
* *
*/ */
#ifndef __COGL_XLIB_H #ifndef __COGL_RENDERER_XLIB_PRIVATE_H
#define __COGL_XLIB_H #define __COGL_RENDERER_XLIB_PRIVATE_H
#include "cogl.h" #include "cogl-object-private.h"
#include "cogl-context-winsys.h" #include "cogl-xlib-private.h"
#include "cogl-renderer-x11-private.h"
#include <X11/Xlib.h> typedef struct _CoglRendererXlib
typedef struct _CoglXlibFilterClosure CoglXlibFilterClosure;
struct _CoglXlibFilterClosure
{ {
CoglXlibFilterFunc func; CoglRendererX11 _parent;
gpointer data;
}; Display *xdpy;
/* 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. * @state: A temporary place to store data for the trap.
* *
* Traps every X error until _cogl_xlib_untrap_errors() called. You * Traps every X error until _cogl_xlib_untrap_errors() called. You
@ -50,10 +60,11 @@ struct _CoglXlibFilterClosure
* pointers in reverse order. * pointers in reverse order.
*/ */
void 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(). * @state: The state that was passed to _cogl_xlib_trap_errors().
* *
* Removes the X error trap and returns the current status. * 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 * Return value: the trapped error code, or 0 for success
*/ */
int 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 */

View File

@ -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;
}

View File

@ -50,6 +50,9 @@ cogl_renderer_error_quark (void)
static void static void
_cogl_renderer_free (CoglRenderer *renderer) _cogl_renderer_free (CoglRenderer *renderer)
{ {
#ifdef COGL_HAS_FULL_WINSYS
_cogl_winsys_renderer_disconnect (renderer);
#endif
g_free (renderer); g_free (renderer);
} }
@ -90,6 +93,21 @@ cogl_renderer_check_onscreen_template (CoglRenderer *renderer,
CoglOnscreenTemplate *onscreen_template, CoglOnscreenTemplate *onscreen_template,
GError **error) 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; return TRUE;
} }
@ -101,6 +119,11 @@ cogl_renderer_connect (CoglRenderer *renderer, GError **error)
if (renderer->connected) if (renderer->connected)
return TRUE; return TRUE;
#ifdef COGL_HAS_FULL_WINSYS
if (!_cogl_winsys_renderer_connect (renderer, error))
return FALSE;
#endif
renderer->connected = TRUE; renderer->connected = TRUE;
return TRUE; return TRUE;
} }

View File

@ -30,6 +30,11 @@
#include <glib-object.h> #include <glib-object.h>
#include <cogl/cogl-defines.h>
#ifdef COGL_HAS_XLIB
#include <X11/Xlib.h>
#endif
G_BEGIN_DECLS G_BEGIN_DECLS
/* Some structures are meant to be opaque but they have public /* 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_TEXTURE_3D = (1 << 19),
COGL_FEATURE_SHADERS_ARBFP = (1 << 20), COGL_FEATURE_SHADERS_ARBFP = (1 << 20),
COGL_FEATURE_MAP_BUFFER_FOR_READ = (1 << 21), 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; } CoglFeatureFlags;
/** /**
@ -582,11 +588,84 @@ typedef enum
COGL_DEPTH_TEST_FUNCTION_GEQUAL = 0x0206, COGL_DEPTH_TEST_FUNCTION_GEQUAL = 0x0206,
COGL_DEPTH_TEST_FUNCTION_ALWAYS = 0x0207 COGL_DEPTH_TEST_FUNCTION_ALWAYS = 0x0207
} CoglDepthTestFunction; } 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 */ /* 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 G_END_DECLS
#endif /* __COGL_TYPES_H__ */ #endif /* __COGL_TYPES_H__ */

View File

@ -37,7 +37,6 @@
#include "cogl-shader.h" #include "cogl-shader.h"
#include "cogl-texture.h" #include "cogl-texture.h"
#include "cogl-types.h" #include "cogl-types.h"
#include "cogl-handle.h"
#include "cogl-util.h" #include "cogl-util.h"
/* /*

View File

@ -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 */

View File

@ -3,7 +3,7 @@
* *
* An object oriented GL/GLES Abstraction/Utility Layer * 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -34,24 +34,36 @@
#include <cogl-handle.h> #include <cogl-handle.h>
#include <cogl-context-private.h> #include <cogl-context-private.h>
#include <cogl-framebuffer-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/Xlib.h>
#include <X11/extensions/Xdamage.h>
#include "cogl-xlib.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 /* This can't be in the Cogl context because it can be set before
context is created */ context is created */
static Display *_cogl_xlib_display = NULL; static Display *_cogl_xlib_display = NULL;
CoglXlibFilterReturn CoglXlibFilterReturn
_cogl_xlib_handle_event (XEvent *xevent) cogl_xlib_handle_event (XEvent *xevent)
{ {
GSList *l; GSList *l;
_COGL_GET_CONTEXT (ctx, COGL_XLIB_FILTER_CONTINUE); _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 */ /* 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; CoglXlibFilterClosure *closure = l->data;
@ -70,10 +82,13 @@ _cogl_xlib_handle_event (XEvent *xevent)
} }
Display * Display *
_cogl_xlib_get_display (void) cogl_xlib_get_display (void)
{ {
_COGL_GET_CONTEXT (ctx, NULL); _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 */ /* _cogl_xlib_set_display should be called before this function */
g_assert (_cogl_xlib_display != NULL); g_assert (_cogl_xlib_display != NULL);
@ -81,7 +96,7 @@ _cogl_xlib_get_display (void)
} }
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 */ /* This can only be called once before the Cogl context is created */
g_assert (_cogl_xlib_display == NULL); g_assert (_cogl_xlib_display == NULL);
@ -91,29 +106,43 @@ _cogl_xlib_set_display (Display *display)
void void
_cogl_xlib_add_filter (CoglXlibFilterFunc func, _cogl_xlib_add_filter (CoglXlibFilterFunc func,
gpointer data) void *data)
{ {
CoglXlibFilterClosure *closure; CoglXlibFilterClosure *closure;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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 = g_slice_new (CoglXlibFilterClosure);
closure->func = func; closure->func = func;
closure->data = data; closure->data = data;
ctx->winsys.event_filters = ctx->event_filters =
g_slist_prepend (ctx->winsys.event_filters, closure); g_slist_prepend (ctx->event_filters, closure);
} }
void void
_cogl_xlib_remove_filter (CoglXlibFilterFunc func, _cogl_xlib_remove_filter (CoglXlibFilterFunc func,
gpointer data) void *data)
{ {
GSList *l, *prev = NULL; GSList *l, *prev = NULL;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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; CoglXlibFilterClosure *closure = l->data;
@ -123,8 +152,8 @@ _cogl_xlib_remove_filter (CoglXlibFilterFunc func,
if (prev) if (prev)
prev->next = g_slist_delete_link (prev->next, l); prev->next = g_slist_delete_link (prev->next, l);
else else
ctx->winsys.event_filters = ctx->event_filters =
g_slist_delete_link (ctx->winsys.event_filters, l); g_slist_delete_link (ctx->event_filters, l);
break; break;
} }
} }
@ -136,9 +165,9 @@ error_handler (Display *xdpy,
{ {
_COGL_GET_CONTEXT (ctxt, 0); _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; return 0;
} }
@ -148,11 +177,17 @@ _cogl_xlib_trap_errors (CoglXlibTrapState *state)
{ {
_COGL_GET_CONTEXT (ctxt, NO_RETVAL); _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->trapped_error_code = 0;
state->old_error_handler = XSetErrorHandler (error_handler); state->old_error_handler = XSetErrorHandler (error_handler);
state->old_state = ctxt->winsys.trap_state; state->old_state = ctxt->trap_state;
ctxt->winsys.trap_state = state; ctxt->trap_state = state;
} }
int int
@ -160,11 +195,44 @@ _cogl_xlib_untrap_errors (CoglXlibTrapState *state)
{ {
_COGL_GET_CONTEXT (ctxt, 0); _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); XSetErrorHandler (state->old_error_handler);
ctxt->winsys.trap_state = state->old_state; ctxt->trap_state = state->old_state;
return state->trapped_error_code; 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;
}

View File

@ -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__ */

View File

@ -38,7 +38,7 @@
#include "cogl-context-private.h" #include "cogl-context-private.h"
#include "cogl-pipeline-private.h" #include "cogl-pipeline-private.h"
#include "cogl-pipeline-opengl-private.h" #include "cogl-pipeline-opengl-private.h"
#include "cogl-winsys.h" #include "cogl-winsys-private.h"
#include "cogl-framebuffer-private.h" #include "cogl-framebuffer-private.h"
#include "cogl-matrix-private.h" #include "cogl-matrix-private.h"
#include "cogl-journal-private.h" #include "cogl-journal-private.h"
@ -394,14 +394,6 @@ cogl_features_available (CoglFeatureFlags features)
return (ctx->feature_flags & features) == 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 /* XXX: This function should either be replaced with one returning
* integers, or removed/deprecated and make the * integers, or removed/deprecated and make the
* _cogl_framebuffer_get_viewport* functions public. * _cogl_framebuffer_get_viewport* functions public.

View File

@ -67,7 +67,12 @@
#include <cogl/cogl-deprecated.h> #include <cogl/cogl-deprecated.h>
typedef struct _CoglFramebuffer CoglFramebuffer;
#if defined (COGL_ENABLE_EXPERIMENTAL_API) #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-context.h>
#include <cogl/cogl-buffer.h> #include <cogl/cogl-buffer.h>
#include <cogl/cogl-pixel-array.h> #include <cogl/cogl-pixel-array.h>
@ -79,6 +84,13 @@
#include <cogl/cogl-attribute.h> #include <cogl/cogl-attribute.h>
#include <cogl/cogl-primitive.h> #include <cogl/cogl-primitive.h>
#include <cogl/cogl-pipeline.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 #endif
G_BEGIN_DECLS G_BEGIN_DECLS
@ -90,8 +102,6 @@ G_BEGIN_DECLS
* General utility functions for COGL. * General utility functions for COGL.
*/ */
typedef struct _CoglFramebuffer CoglFramebuffer;
/** /**
* cogl_get_option_group: * cogl_get_option_group:
* *
@ -1245,44 +1255,6 @@ cogl_begin_gl (void);
void void
cogl_end_gl (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 G_END_DECLS
#undef __COGL_H_INSIDE__ #undef __COGL_H_INSIDE__

View File

@ -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 */

View File

@ -29,6 +29,7 @@
#include "cogl.h" #include "cogl.h"
#include "cogl-private.h"
#include "cogl-internal.h" #include "cogl-internal.h"
#include "cogl-context-private.h" #include "cogl-context-private.h"
#include "cogl-feature-private.h" #include "cogl-feature-private.h"
@ -95,7 +96,7 @@ _cogl_get_gl_version (int *major_out, int *minor_out)
} }
gboolean gboolean
_cogl_check_driver_valid (GError **error) _cogl_gl_check_version (GError **error)
{ {
int major, minor; int major, minor;
const char *gl_extensions; const char *gl_extensions;
@ -161,8 +162,8 @@ _cogl_check_driver_valid (GError **error)
namespaces, extension_names, \ namespaces, extension_names, \
feature_flags, feature_flags_private) \ feature_flags, feature_flags_private) \
{ min_gl_major, min_gl_minor, namespaces, \ { min_gl_major, min_gl_minor, namespaces, \
extension_names, feature_flags, feature_flags_private, \ extension_names, feature_flags, feature_flags_private, 0, \
cogl_feature_ ## name ## _funcs }, cogl_feature_ ## name ## _funcs },
#undef COGL_FEATURE_FUNCTION #undef COGL_FEATURE_FUNCTION
#define COGL_FEATURE_FUNCTION(ret, name, args) #define COGL_FEATURE_FUNCTION(ret, name, args)
#undef COGL_FEATURE_END #undef COGL_FEATURE_END
@ -182,23 +183,35 @@ static const CoglFeatureData cogl_feature_data[] =
#define COGL_FEATURE_END() #define COGL_FEATURE_END()
static void static void
initialize_context_driver (CoglContext *context) initialize_function_table (CoglContext *context)
{ {
#include "cogl-feature-functions-gl.h" #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 void
_cogl_gl_context_init (CoglContext *context) _cogl_gl_update_features (CoglContext *context)
{ {
CoglFeatureFlags flags = 0; CoglFeatureFlags flags = 0;
CoglFeatureFlagsPrivate flags_private = 0;
const char *gl_extensions; const char *gl_extensions;
int max_clip_planes = 0; int max_clip_planes = 0;
int num_stencil_bits = 0; int num_stencil_bits = 0;
int gl_major = 0, gl_minor = 0; int gl_major = 0, gl_minor = 0;
int i; 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); _cogl_get_gl_version (&gl_major, &gl_minor);
@ -235,16 +248,15 @@ _cogl_gl_context_init (CoglContext *context)
if (max_clip_planes >= 4) if (max_clip_planes >= 4)
flags |= COGL_FEATURE_FOUR_CLIP_PLANES; flags |= COGL_FEATURE_FOUR_CLIP_PLANES;
initialize_function_table (context);
for (i = 0; i < G_N_ELEMENTS (cogl_feature_data); i++) for (i = 0; i < G_N_ELEMENTS (cogl_feature_data); i++)
if (_cogl_feature_check ("GL", cogl_feature_data + i, if (_cogl_feature_check ("GL", cogl_feature_data + i,
gl_major, gl_minor, gl_major, gl_minor,
gl_extensions)) gl_extensions,
{ context))
flags |= cogl_feature_data[i].feature_flags; flags |= cogl_feature_data[i].feature_flags;
flags_private |= cogl_feature_data[i].feature_flags_private;
}
/* Cache features */ /* Cache features */
context->feature_flags = flags; context->feature_flags |= flags;
context->feature_flags_private = flags_private;
} }

View File

@ -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 */

View File

@ -33,7 +33,7 @@
#include "cogl-feature-private.h" #include "cogl-feature-private.h"
gboolean gboolean
_cogl_check_driver_valid (GError **error) _cogl_gl_check_version (GError **error)
{ {
/* The GLES backend doesn't have any particular version requirements */ /* The GLES backend doesn't have any particular version requirements */
return TRUE; return TRUE;
@ -58,8 +58,8 @@ _cogl_check_driver_valid (GError **error)
namespaces, extension_names, \ namespaces, extension_names, \
feature_flags, feature_flags_private) \ feature_flags, feature_flags_private) \
{ min_gl_major, min_gl_minor, namespaces, \ { min_gl_major, min_gl_minor, namespaces, \
extension_names, feature_flags, feature_flags_private, \ extension_names, feature_flags, feature_flags_private, 0, \
cogl_feature_ ## name ## _funcs }, cogl_feature_ ## name ## _funcs },
#undef COGL_FEATURE_FUNCTION #undef COGL_FEATURE_FUNCTION
#define COGL_FEATURE_FUNCTION(ret, name, args) #define COGL_FEATURE_FUNCTION(ret, name, args)
#undef COGL_FEATURE_END #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) #define COGL_FEATURE_BEGIN(a, b, c, d, e, f, g)
#undef COGL_FEATURE_FUNCTION #undef COGL_FEATURE_FUNCTION
#define COGL_FEATURE_FUNCTION(ret, name, args) \ #define COGL_FEATURE_FUNCTION(ret, name, args) \
_context->drv.pf_ ## name = NULL; context->drv.pf_ ## name = NULL;
#undef COGL_FEATURE_END #undef COGL_FEATURE_END
#define COGL_FEATURE_END() #define COGL_FEATURE_END()
static void static void
initialize_context_driver (CoglContext *context) initialize_function_table (CoglContext *context)
{ {
#include "cogl-feature-functions-gles.h" #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 void
_cogl_gl_context_init (CoglContext *context) _cogl_gl_update_features (CoglContext *context)
{ {
CoglFeatureFlags flags = 0; CoglFeatureFlags flags = 0;
const char *gl_extensions;
#ifndef HAVE_COGL_GLES2 #ifndef HAVE_COGL_GLES2
int max_clip_planes = 0; int max_clip_planes = 0;
#endif #endif
int num_stencil_bits = 0; int num_stencil_bits = 0;
const char *gl_extensions;
int i; 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); 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) ); GE( glGetIntegerv (GL_STENCIL_BITS, &num_stencil_bits) );
/* We need at least three stencil bits to combine clips */ /* 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 */ /* Both GLES 1.1 and GLES 2.0 support point sprites in core */
flags |= COGL_FEATURE_POINT_SPRITE; flags |= COGL_FEATURE_POINT_SPRITE;
/* Cache features */ initialize_function_table (context);
context->feature_flags = flags;
}
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;
}

View File

@ -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
}

View File

@ -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 */

View File

@ -42,7 +42,11 @@
#include "cogl-texture-rectangle-private.h" #include "cogl-texture-rectangle-private.h"
#include "cogl-context-private.h" #include "cogl-context-private.h"
#include "cogl-handle.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 "cogl-pipeline-opengl-private.h"
#include <X11/Xlib.h> #include <X11/Xlib.h>
@ -55,9 +59,6 @@
#include <string.h> #include <string.h>
#include <math.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); static void _cogl_texture_pixmap_x11_free (CoglTexturePixmapX11 *tex_pixmap);
COGL_TEXTURE_DEFINE (TexturePixmapX11, texture_pixmap_x11); COGL_TEXTURE_DEFINE (TexturePixmapX11, texture_pixmap_x11);
@ -112,7 +113,7 @@ process_damage_event (CoglTexturePixmapX11 *tex_pixmap,
_COGL_GET_CONTEXT (ctxt, NO_RETVAL); _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); 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) _cogl_texture_pixmap_x11_filter (XEvent *event, gpointer data)
{ {
CoglTexturePixmapX11 *tex_pixmap = data; CoglTexturePixmapX11 *tex_pixmap = data;
int damage_base;
_COGL_GET_CONTEXT (ctxt, COGL_XLIB_FILTER_CONTINUE); _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; XDamageNotifyEvent *damage_event = (XDamageNotifyEvent *) event;
@ -228,26 +231,28 @@ get_fbconfig_for_depth (unsigned int depth,
gboolean *can_mipmap_ret) gboolean *can_mipmap_ret)
{ {
GLXFBConfig *fbconfigs; GLXFBConfig *fbconfigs;
int n_elements, i; int n_elements, i;
Display *dpy; Display *dpy;
int db, stencil, alpha, mipmap, rgba, value; int db, stencil, alpha, mipmap, rgba, value;
int spare_cache_slot = 0; int spare_cache_slot = 0;
gboolean found = FALSE; gboolean found = FALSE;
CoglDisplayGLX *glx_display;
_COGL_GET_CONTEXT (ctxt, FALSE); _COGL_GET_CONTEXT (ctxt, FALSE);
glx_display = ctxt->display->winsys;
/* Check if we've already got a cached config for this depth */ /* Check if we've already got a cached config for this depth */
for (i = 0; i < COGL_WINSYS_N_CACHED_CONFIGS; i++) for (i = 0; i < COGL_GLX_N_CACHED_CONFIGS; i++)
if (ctxt->winsys.glx_cached_configs[i].depth == -1) if (glx_display->glx_cached_configs[i].depth == -1)
spare_cache_slot = i; 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; *fbconfig_ret = glx_display->glx_cached_configs[i].fb_config;
*can_mipmap_ret = ctxt->winsys.glx_cached_configs[i].can_mipmap; *can_mipmap_ret = glx_display->glx_cached_configs[i].can_mipmap;
return ctxt->winsys.glx_cached_configs[i].found; return glx_display->glx_cached_configs[i].found;
} }
dpy = _cogl_xlib_get_display (); dpy = cogl_xlib_get_display ();
fbconfigs = glXGetFBConfigs (dpy, DefaultScreen (dpy), fbconfigs = glXGetFBConfigs (dpy, DefaultScreen (dpy),
&n_elements); &n_elements);
@ -349,10 +354,10 @@ get_fbconfig_for_depth (unsigned int depth,
if (n_elements) if (n_elements)
XFree (fbconfigs); XFree (fbconfigs);
ctxt->winsys.glx_cached_configs[spare_cache_slot].depth = depth; glx_display->glx_cached_configs[spare_cache_slot].depth = depth;
ctxt->winsys.glx_cached_configs[spare_cache_slot].found = found; glx_display->glx_cached_configs[spare_cache_slot].found = found;
ctxt->winsys.glx_cached_configs[spare_cache_slot].fb_config = *fbconfig_ret; glx_display->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].can_mipmap = mipmap;
return found; return found;
} }
@ -362,7 +367,7 @@ should_use_rectangle (void)
{ {
_COGL_GET_CONTEXT (ctxt, FALSE); _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)) 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 the env var is set to 'allow' or not set and NPOTs textures
are not available */ are not available */
ctxt->winsys.rectangle_state = ctxt->rectangle_state =
cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) ? cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) ?
COGL_WINSYS_RECTANGLE_STATE_DISABLE : COGL_WINSYS_RECTANGLE_STATE_DISABLE :
COGL_WINSYS_RECTANGLE_STATE_ENABLE; COGL_WINSYS_RECTANGLE_STATE_ENABLE;
@ -389,10 +394,10 @@ should_use_rectangle (void)
(rect_env = g_getenv ("CLUTTER_PIXMAP_TEXTURE_RECTANGLE"))) (rect_env = g_getenv ("CLUTTER_PIXMAP_TEXTURE_RECTANGLE")))
{ {
if (g_ascii_strcasecmp (rect_env, "force") == 0) if (g_ascii_strcasecmp (rect_env, "force") == 0)
ctxt->winsys.rectangle_state = ctxt->rectangle_state =
COGL_WINSYS_RECTANGLE_STATE_ENABLE; COGL_WINSYS_RECTANGLE_STATE_ENABLE;
else if (g_ascii_strcasecmp (rect_env, "disable") == 0) else if (g_ascii_strcasecmp (rect_env, "disable") == 0)
ctxt->winsys.rectangle_state = ctxt->rectangle_state =
COGL_WINSYS_RECTANGLE_STATE_DISABLE; COGL_WINSYS_RECTANGLE_STATE_DISABLE;
else if (g_ascii_strcasecmp (rect_env, "allow")) else if (g_ascii_strcasecmp (rect_env, "allow"))
g_warning ("Unknown value for COGL_PIXMAP_TEXTURE_RECTANGLE, " g_warning ("Unknown value for COGL_PIXMAP_TEXTURE_RECTANGLE, "
@ -400,10 +405,10 @@ should_use_rectangle (void)
} }
} }
else 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 static void
@ -425,11 +430,10 @@ try_create_glx_pixmap (CoglTexturePixmapX11 *tex_pixmap,
tex_pixmap->pixmap_bound = FALSE; tex_pixmap->pixmap_bound = FALSE;
tex_pixmap->glx_pixmap = None; tex_pixmap->glx_pixmap = None;
if ((ctxt->winsys.feature_flags & if (!_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_TEXTURE_FROM_PIXMAP))
COGL_WINSYS_FEATURE_TEXTURE_FROM_PIXMAP) == 0)
return; return;
dpy = _cogl_xlib_get_display (); dpy = cogl_xlib_get_display ();
if (!get_fbconfig_for_depth (tex_pixmap->depth, &fb_config, if (!get_fbconfig_for_depth (tex_pixmap->depth, &fb_config,
&tex_pixmap->glx_can_mipmap)) &tex_pixmap->glx_can_mipmap))
@ -507,7 +511,7 @@ set_damage_object_internal (CoglTexturePixmapX11 *tex_pixmap,
if (tex_pixmap->damage_owned) 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; tex_pixmap->damage_owned = FALSE;
} }
} }
@ -524,12 +528,13 @@ cogl_texture_pixmap_x11_new (guint32 pixmap,
gboolean automatic_updates) gboolean automatic_updates)
{ {
CoglTexturePixmapX11 *tex_pixmap = g_new (CoglTexturePixmapX11, 1); CoglTexturePixmapX11 *tex_pixmap = g_new (CoglTexturePixmapX11, 1);
Display *display = _cogl_xlib_get_display (); Display *display = cogl_xlib_get_display ();
Window pixmap_root_window; Window pixmap_root_window;
int pixmap_x, pixmap_y; int pixmap_x, pixmap_y;
unsigned int pixmap_border_width; unsigned int pixmap_border_width;
CoglTexture *tex = COGL_TEXTURE (tex_pixmap); CoglTexture *tex = COGL_TEXTURE (tex_pixmap);
XWindowAttributes window_attributes; XWindowAttributes window_attributes;
int damage_base;
_COGL_GET_CONTEXT (ctxt, COGL_INVALID_HANDLE); _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 /* If automatic updates are requested and the Xlib connection
supports damage events then we'll register a damage object on the supports damage events then we'll register a damage object on the
pixmap */ 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, Damage damage = XDamageCreate (display,
pixmap, pixmap,
@ -601,7 +607,7 @@ try_alloc_shm (CoglTexturePixmapX11 *tex_pixmap)
XImage *dummy_image; XImage *dummy_image;
Display *display; Display *display;
display = _cogl_xlib_get_display (); display = cogl_xlib_get_display ();
if (!XShmQueryExtension (display)) if (!XShmQueryExtension (display))
return; return;
@ -709,13 +715,15 @@ cogl_texture_pixmap_x11_set_damage_object (CoglHandle handle,
report_level) report_level)
{ {
CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (handle); CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (handle);
int damage_base;
_COGL_GET_CONTEXT (ctxt, NO_RETVAL); _COGL_GET_CONTEXT (ctxt, NO_RETVAL);
if (!cogl_is_texture_pixmap_x11 (tex_pixmap)) if (!cogl_is_texture_pixmap_x11 (tex_pixmap))
return; 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); 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 src_x, src_y;
int x, y, width, height; 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 the damage region is empty then there's nothing to do */
if (tex_pixmap->damage_rect.x2 == tex_pixmap->damage_rect.x1) 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) if (tex_pixmap->glx_pixmap)
{ {
CoglXlibTrapState trap_state; CoglXlibTrapState trap_state;
CoglRendererGLX *glx_renderer;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
glx_renderer = ctx->display->renderer->winsys;
if (tex_pixmap->pixmap_bound) if (tex_pixmap->pixmap_bound)
glXReleaseTexImage (_cogl_xlib_get_display (), tex_pixmap->glx_pixmap, glx_renderer->pf_glXReleaseTexImage (cogl_xlib_get_display (),
GLX_FRONT_LEFT_EXT); tex_pixmap->glx_pixmap,
GLX_FRONT_LEFT_EXT);
/* FIXME - we need to trap errors and synchronize here because /* FIXME - we need to trap errors and synchronize here because
* of ordering issues between the XPixmap destruction and the * 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 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2324
*/ */
_cogl_xlib_trap_errors (&trap_state); _cogl_xlib_trap_errors (&trap_state);
glXDestroyPixmap (_cogl_xlib_get_display (), tex_pixmap->glx_pixmap); glXDestroyPixmap (cogl_xlib_get_display (), tex_pixmap->glx_pixmap);
XSync (_cogl_xlib_get_display (), False); XSync (cogl_xlib_get_display (), False);
_cogl_xlib_untrap_errors (&trap_state); _cogl_xlib_untrap_errors (&trap_state);
tex_pixmap->glx_pixmap = None; tex_pixmap->glx_pixmap = None;
@ -927,8 +938,10 @@ _cogl_texture_pixmap_x11_update_glx_texture (CoglTexturePixmapX11 *tex_pixmap,
gboolean needs_mipmap) gboolean needs_mipmap)
{ {
gboolean ret = TRUE; gboolean ret = TRUE;
CoglRendererGLX *glx_renderer;
_COGL_GET_CONTEXT (ctx, FALSE); _COGL_GET_CONTEXT (ctx, FALSE);
glx_renderer = ctx->display->renderer->winsys;
/* If we don't have a GLX pixmap then fallback */ /* If we don't have a GLX pixmap then fallback */
if (tex_pixmap->glx_pixmap == None) 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) ); GE( _cogl_bind_gl_texture_transient (gl_target, gl_handle, FALSE) );
if (tex_pixmap->pixmap_bound) if (tex_pixmap->pixmap_bound)
glXReleaseTexImage (_cogl_xlib_get_display (), glx_renderer->pf_glXReleaseTexImage (cogl_xlib_get_display (),
tex_pixmap->glx_pixmap, tex_pixmap->glx_pixmap,
GLX_FRONT_LEFT_EXT); GLX_FRONT_LEFT_EXT);
glXBindTexImage (_cogl_xlib_get_display (), glx_renderer->pf_glXBindTexImage (cogl_xlib_get_display (),
tex_pixmap->glx_pixmap, tex_pixmap->glx_pixmap,
GLX_FRONT_LEFT_EXT, GLX_FRONT_LEFT_EXT,
NULL); NULL);
/* According to the recommended usage in the spec for /* According to the recommended usage in the spec for
GLX_EXT_texture_pixmap we should release the texture after 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) 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); shmdt (tex_pixmap->shm_info.shmaddr);
shmctl (tex_pixmap->shm_info.shmid, IPC_RMID, 0); shmctl (tex_pixmap->shm_info.shmid, IPC_RMID, 0);
} }

View File

@ -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

View File

@ -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 ()

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,95 @@
#ifndef __COGL_WINSYS_PRIVATE_H #ifndef __COGL_WINSYS_PRIVATE_H
#define __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 CoglFuncPtr
_cogl_winsys_get_proc_address (const char *name); _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 */ #endif /* __COGL_WINSYS_PRIVATE_H */

View File

@ -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)
{
}

View File

@ -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");
}

View File

@ -49,6 +49,7 @@
#include "clutter-stage-private.h" #include "clutter-stage-private.h"
#include "cogl/cogl.h" #include "cogl/cogl.h"
#include "cogl/cogl-internal.h"
#define clutter_backend_glx_get_type _clutter_backend_glx_get_type #define clutter_backend_glx_get_type _clutter_backend_glx_get_type
@ -57,12 +58,15 @@ G_DEFINE_TYPE (ClutterBackendGLX, clutter_backend_glx, CLUTTER_TYPE_BACKEND_X11)
/* singleton object */ /* singleton object */
static ClutterBackendGLX *backend_singleton = NULL; static ClutterBackendGLX *backend_singleton = NULL;
static gchar *clutter_vblank_name = NULL; static gchar *clutter_vblank = NULL;
G_CONST_RETURN gchar* G_CONST_RETURN gchar*
_clutter_backend_glx_get_vblank_method (void) _clutter_backend_glx_get_vblank (void)
{ {
return clutter_vblank_name; if (clutter_vblank && strcmp (clutter_vblank, "0") == 0)
return "none";
else
return clutter_vblank;
} }
static gboolean static gboolean
@ -76,7 +80,7 @@ clutter_backend_glx_pre_parse (ClutterBackend *backend,
env_string = g_getenv ("CLUTTER_VBLANK"); env_string = g_getenv ("CLUTTER_VBLANK");
if (env_string) if (env_string)
{ {
clutter_vblank_name = g_strdup (env_string); clutter_vblank = g_strdup (env_string);
env_string = NULL; env_string = NULL;
} }
@ -87,42 +91,12 @@ static gboolean
clutter_backend_glx_post_parse (ClutterBackend *backend, clutter_backend_glx_post_parse (ClutterBackend *backend,
GError **error) GError **error)
{ {
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
ClutterBackendClass *parent_class = ClutterBackendClass *parent_class =
CLUTTER_BACKEND_CLASS (clutter_backend_glx_parent_class); CLUTTER_BACKEND_CLASS (clutter_backend_glx_parent_class);
int glx_major, glx_minor;
if (!parent_class->post_parse (backend, error)) if (!parent_class->post_parse (backend, error))
return FALSE; return FALSE;
if (!glXQueryExtension (backend_x11->xdpy,
&backend_glx->error_base,
&backend_glx->event_base))
{
g_set_error_literal (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"XServer appears to lack the required GLX support");
return FALSE;
}
/* XXX: Technically we should require >= GLX 1.3 support but for a long
* time Mesa has exported a hybrid GLX, exporting extensions specified
* to require GLX 1.3, but still reporting 1.2 via glXQueryVersion. */
glx_major = 1;
glx_minor = 2;
if (!glXQueryVersion (backend_x11->xdpy, &glx_major, &glx_minor) ||
!(glx_major == 1 && glx_minor >= 2))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"XServer appears to lack the required GLX "
"1.2 support (%d.%d reported)",
glx_major, glx_minor);
return FALSE;
}
return TRUE; return TRUE;
} }
@ -130,8 +104,9 @@ static const GOptionEntry entries[] =
{ {
{ "vblank", 0, { "vblank", 0,
0, 0,
G_OPTION_ARG_STRING, &clutter_vblank_name, G_OPTION_ARG_STRING, &clutter_vblank,
N_("VBlank method to be used (none, dri or glx)"), "METHOD" N_("Set to 'none' or '0' to disable throttling "
"framerate to vblank"), "OPTION"
}, },
{ NULL } { NULL }
}; };
@ -160,32 +135,20 @@ clutter_backend_glx_finalize (GObject *gobject)
static void static void
clutter_backend_glx_dispose (GObject *gobject) clutter_backend_glx_dispose (GObject *gobject)
{ {
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (gobject); ClutterBackend *backend = CLUTTER_BACKEND (gobject);
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (gobject);
/* Unrealize all shaders, since the GL context is going away */ /* Unrealize all shaders, since the GL context is going away */
/* XXX: Why isn't this done in
* clutter-backend.c:clutter_backend_dispose ?
*/
_clutter_shader_release_all (); _clutter_shader_release_all ();
if (backend_glx->gl_context) /* We chain up before disposing our CoglContext so that we will
{ * destroy all of the stages first. Otherwise the actors may try to
glXMakeContextCurrent (backend_x11->xdpy, None, None, NULL); * make Cogl calls during destruction which would cause a crash */
glXDestroyContext (backend_x11->xdpy, backend_glx->gl_context);
backend_glx->gl_context = NULL;
}
if (backend_glx->dummy_glxwin)
{
glXDestroyWindow (backend_x11->xdpy, backend_glx->dummy_glxwin);
backend_glx->dummy_glxwin = None;
}
if (backend_glx->dummy_xwin)
{
XDestroyWindow (backend_x11->xdpy, backend_glx->dummy_xwin);
backend_glx->dummy_xwin = None;
}
G_OBJECT_CLASS (clutter_backend_glx_parent_class)->dispose (gobject); G_OBJECT_CLASS (clutter_backend_glx_parent_class)->dispose (gobject);
cogl_object_unref (backend->cogl_context);
} }
static GObject * static GObject *
@ -212,197 +175,46 @@ clutter_backend_glx_constructor (GType gtype,
return g_object_ref (backend_singleton); return g_object_ref (backend_singleton);
} }
static gboolean
check_vblank_env (const char *name)
{
if (clutter_vblank_name && !g_ascii_strcasecmp (clutter_vblank_name, name))
return TRUE;
return FALSE;
}
static ClutterFeatureFlags static ClutterFeatureFlags
clutter_backend_glx_get_features (ClutterBackend *backend) clutter_backend_glx_get_features (ClutterBackend *backend)
{ {
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend); ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
ClutterBackendClass *parent_class; ClutterBackendClass *parent_class;
const gchar *glx_extensions = NULL;
const gchar *gl_extensions = NULL;
ClutterFeatureFlags flags; ClutterFeatureFlags flags;
gboolean use_dri = FALSE;
parent_class = CLUTTER_BACKEND_CLASS (clutter_backend_glx_parent_class); parent_class = CLUTTER_BACKEND_CLASS (clutter_backend_glx_parent_class);
flags = parent_class->get_features (backend); flags = parent_class->get_features (backend);
flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
/* this will make sure that the GL context exists */ if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN))
g_assert (backend_glx->gl_context != NULL);
g_assert (glXGetCurrentDrawable () != None);
CLUTTER_NOTE (BACKEND,
"Checking features\n"
" GL_VENDOR: %s\n"
" GL_RENDERER: %s\n"
" GL_VERSION: %s\n"
" GL_EXTENSIONS: %s",
glGetString (GL_VENDOR),
glGetString (GL_RENDERER),
glGetString (GL_VERSION),
glGetString (GL_EXTENSIONS));
glx_extensions =
glXQueryExtensionsString (clutter_x11_get_default_display (),
clutter_x11_get_default_screen ());
CLUTTER_NOTE (BACKEND, " GLX Extensions: %s", glx_extensions);
gl_extensions = (const gchar *)glGetString (GL_EXTENSIONS);
/* When using glBlitFramebuffer or glXCopySubBufferMESA for sub stage
* redraws, we cannot rely on glXSwapIntervalSGI to throttle the blits
* so we need to resort to manually synchronizing with the vblank so we
* always check for the video_sync extension...
*/
if (_cogl_check_extension ("GLX_SGI_video_sync", glx_extensions) &&
/* Note: the GLX_SGI_video_sync spec explicitly states this extension
* only works for direct contexts. */
glXIsDirect (clutter_x11_get_default_display (),
backend_glx->gl_context))
{ {
backend_glx->get_video_sync = CLUTTER_NOTE (BACKEND, "Cogl supports multiple onscreen framebuffers");
(GetVideoSyncProc) cogl_get_proc_address ("glXGetVideoSyncSGI"); flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
}
backend_glx->wait_video_sync = else
(WaitVideoSyncProc) cogl_get_proc_address ("glXWaitVideoSyncSGI"); {
CLUTTER_NOTE (BACKEND, "Cogl only supports one onscreen framebuffer");
flags |= CLUTTER_FEATURE_STAGE_STATIC;
} }
use_dri = check_vblank_env ("dri"); if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_THROTTLE))
/* First check for explicit disabling or it set elsewhere (eg NVIDIA) */
if (check_vblank_env ("none"))
{ {
CLUTTER_NOTE (BACKEND, "vblank sync: disabled at user request"); CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers throttling");
goto vblank_setup_done;
}
if (g_getenv ("__GL_SYNC_TO_VBLANK") != NULL)
{
backend_glx->vblank_type = CLUTTER_VBLANK_GLX_SWAP;
flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK; flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
}
else
CLUTTER_NOTE (BACKEND, "Cogl doesn't support swap buffers throttling");
CLUTTER_NOTE (BACKEND, "Using __GL_SYNC_TO_VBLANK hint"); if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
goto vblank_setup_done; {
CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers complete events");
flags |= CLUTTER_FEATURE_SWAP_EVENTS;
} }
/* We try two GL vblank syncing mechanisms. if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION))
* glXSwapIntervalSGI is tried first, then glXGetVideoSyncSGI.
*
* glXSwapIntervalSGI is known to work with Mesa and in particular
* the Intel drivers. glXGetVideoSyncSGI has serious problems with
* Intel drivers causing terrible frame rate so it only tried as a
* fallback.
*
* How well glXGetVideoSyncSGI works with other driver (ATI etc) needs
* to be investigated. glXGetVideoSyncSGI on ATI at least seems to have
* no effect.
*/
if (!use_dri &&
_cogl_check_extension ("GLX_SGI_swap_control", glx_extensions))
{ {
backend_glx->swap_interval = CLUTTER_NOTE (BACKEND, "Cogl supports swapping buffer regions");
(SwapIntervalProc) cogl_get_proc_address ("glXSwapIntervalSGI");
CLUTTER_NOTE (BACKEND, "attempting glXSwapIntervalSGI vblank setup");
if (backend_glx->swap_interval != NULL &&
backend_glx->swap_interval (1) == 0)
{
backend_glx->vblank_type = CLUTTER_VBLANK_GLX_SWAP;
flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
CLUTTER_NOTE (BACKEND, "glXSwapIntervalSGI setup success");
#ifdef GLX_INTEL_swap_event
/* GLX_INTEL_swap_event allows us to avoid blocking the CPU
* while we wait for glXSwapBuffers to complete, and instead
* we get an X event notifying us of completion...
*/
if (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_SWAP_EVENTS) &&
_cogl_check_extension ("GLX_INTEL_swap_event", glx_extensions))
{
flags |= CLUTTER_FEATURE_SWAP_EVENTS;
}
#endif /* GLX_INTEL_swap_event */
goto vblank_setup_done;
}
CLUTTER_NOTE (BACKEND, "glXSwapIntervalSGI vblank setup failed");
}
if (!use_dri &&
!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK) &&
_cogl_check_extension ("GLX_SGI_video_sync", glx_extensions))
{
CLUTTER_NOTE (BACKEND, "attempting glXGetVideoSyncSGI vblank setup");
if ((backend_glx->get_video_sync != NULL) &&
(backend_glx->wait_video_sync != NULL))
{
CLUTTER_NOTE (BACKEND, "glXGetVideoSyncSGI vblank setup success");
backend_glx->vblank_type = CLUTTER_VBLANK_GLX;
flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
goto vblank_setup_done;
}
CLUTTER_NOTE (BACKEND, "glXGetVideoSyncSGI vblank setup failed");
}
#ifdef __linux__
/*
* DRI is really an extreme fallback -rumoured to work with Via chipsets
*/
if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
{
CLUTTER_NOTE (BACKEND, "attempting DRI vblank setup");
backend_glx->dri_fd = open("/dev/dri/card0", O_RDWR);
if (backend_glx->dri_fd >= 0)
{
CLUTTER_NOTE (BACKEND, "DRI vblank setup success");
backend_glx->vblank_type = CLUTTER_VBLANK_DRI;
flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
goto vblank_setup_done;
}
CLUTTER_NOTE (BACKEND, "DRI vblank setup failed");
}
#endif /* __linux__ */
CLUTTER_NOTE (BACKEND, "no use-able vblank mechanism found");
vblank_setup_done:
if (_cogl_check_extension ("GLX_MESA_copy_sub_buffer", glx_extensions))
{
backend_glx->copy_sub_buffer =
(CopySubBufferProc) cogl_get_proc_address ("glXCopySubBufferMESA");
backend_glx->can_blit_sub_buffer = TRUE; backend_glx->can_blit_sub_buffer = TRUE;
backend_glx->blit_sub_buffer_is_synchronized = TRUE;
}
else if (_cogl_check_extension ("GL_EXT_framebuffer_blit", gl_extensions))
{
CLUTTER_NOTE (BACKEND,
"Using glBlitFramebuffer fallback for sub_buffer copies");
backend_glx->blit_framebuffer =
(BlitFramebufferProc) cogl_get_proc_address ("glBlitFramebuffer");
backend_glx->can_blit_sub_buffer = TRUE;
backend_glx->blit_sub_buffer_is_synchronized = FALSE;
} }
CLUTTER_NOTE (BACKEND, "backend features checked"); CLUTTER_NOTE (BACKEND, "backend features checked");
@ -410,375 +222,77 @@ vblank_setup_done:
return flags; return flags;
} }
/* It seems the GLX spec never defined an invalid GLXFBConfig that
* we could overload as an indication of error, so we have to return
* an explicit boolean status. */
gboolean
_clutter_backend_glx_get_fbconfig (ClutterBackendGLX *backend_glx,
GLXFBConfig *config)
{
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend_glx);
GLXFBConfig *configs = NULL;
gboolean use_argb = clutter_x11_get_use_argb_visual ();
int n_configs, i;
static const int attributes[] = {
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DOUBLEBUFFER, GL_TRUE,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_ALPHA_SIZE, 1,
GLX_DEPTH_SIZE, 1,
GLX_STENCIL_SIZE, 1,
None
};
if (backend_x11->xdpy == NULL || backend_x11->xscreen == NULL)
return FALSE;
/* If we don't already have a cached config then try to get one */
if (!backend_glx->found_fbconfig)
{
CLUTTER_NOTE (BACKEND,
"Retrieving GL fbconfig, dpy: %p, xscreen; %p (%d)",
backend_x11->xdpy,
backend_x11->xscreen,
backend_x11->xscreen_num);
configs = glXChooseFBConfig (backend_x11->xdpy,
backend_x11->xscreen_num,
attributes,
&n_configs);
if (configs)
{
if (use_argb)
{
for (i = 0; i < n_configs; i++)
{
XVisualInfo *vinfo;
vinfo = glXGetVisualFromFBConfig (backend_x11->xdpy,
configs[i]);
if (vinfo == NULL)
continue;
if (vinfo->depth == 32 &&
(vinfo->red_mask == 0xff0000 &&
vinfo->green_mask == 0x00ff00 &&
vinfo->blue_mask == 0x0000ff))
{
CLUTTER_NOTE (BACKEND,
"Found an ARGB FBConfig [index:%d]",
i);
backend_glx->found_fbconfig = TRUE;
backend_glx->fbconfig = configs[i];
goto out;
}
}
/* If we make it here then we didn't find an RGBA config so
we'll fall back to using an RGB config */
CLUTTER_NOTE (BACKEND, "ARGB visual requested, but none found");
}
if (n_configs >= 1)
{
CLUTTER_NOTE (BACKEND, "Using the first available FBConfig");
backend_glx->found_fbconfig = TRUE;
backend_glx->fbconfig = configs[0];
}
out:
XFree (configs);
}
}
if (G_LIKELY (backend_glx->found_fbconfig))
{
*config = backend_glx->fbconfig;
return TRUE;
}
return FALSE;
}
void
_clutter_backend_glx_blit_sub_buffer (ClutterBackendGLX *backend_glx,
GLXDrawable drawable,
int x,
int y,
int width,
int height)
{
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend_glx);
if (backend_glx->copy_sub_buffer)
{
backend_glx->copy_sub_buffer (backend_x11->xdpy, drawable,
x, y, width, height);
}
else if (backend_glx->blit_framebuffer)
{
glDrawBuffer (GL_FRONT);
backend_glx->blit_framebuffer (x, y, x + width, y + height,
x, y, x + width, y + height,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glDrawBuffer (GL_BACK);
}
/* NB: unlike glXSwapBuffers, glXCopySubBuffer and
* glBlitFramebuffer don't issue an implicit glFlush() so we
* have to flush ourselves if we want the request to complete in
* finite amount of time since otherwise the driver can batch
* the command indefinitely. */
glFlush();
}
static XVisualInfo * static XVisualInfo *
clutter_backend_glx_get_visual_info (ClutterBackendX11 *backend_x11) clutter_backend_glx_get_visual_info (ClutterBackendX11 *backend_x11)
{ {
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend_x11); return cogl_clutter_winsys_xlib_get_visual_info ();
GLXFBConfig config;
if (!_clutter_backend_glx_get_fbconfig (backend_glx, &config))
return NULL;
return glXGetVisualFromFBConfig (backend_x11->xdpy, config);
} }
static gboolean static gboolean
clutter_backend_glx_create_context (ClutterBackend *backend, clutter_backend_glx_create_context (ClutterBackend *backend,
GError **error) GError **error)
{ {
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
GLXFBConfig config; CoglSwapChain *swap_chain = NULL;
gboolean is_direct; CoglOnscreenTemplate *onscreen_template = NULL;
Window root_xwin;
XSetWindowAttributes attrs;
XVisualInfo *xvisinfo;
Display *xdisplay;
int major;
int minor;
GLXDrawable dummy_drawable;
if (backend_glx->gl_context != NULL) if (backend->cogl_context)
return TRUE; return TRUE;
xdisplay = clutter_x11_get_default_display (); backend->cogl_renderer = cogl_renderer_new ();
root_xwin = clutter_x11_get_root_window (); cogl_renderer_xlib_set_foreign_display (backend->cogl_renderer,
backend_x11->xdpy);
if (!cogl_renderer_connect (backend->cogl_renderer, error))
goto error;
if (!_clutter_backend_glx_get_fbconfig (backend_glx, &config)) swap_chain = cogl_swap_chain_new ();
{ cogl_swap_chain_set_has_alpha (swap_chain,
g_set_error_literal (error, CLUTTER_INIT_ERROR, clutter_x11_get_use_argb_visual ());
CLUTTER_INIT_ERROR_BACKEND,
"Unable to find suitable fbconfig for the GLX context");
return FALSE;
}
CLUTTER_NOTE (BACKEND, "Creating GLX Context (display: %p)", xdisplay); onscreen_template = cogl_onscreen_template_new (swap_chain);
cogl_object_unref (swap_chain);
backend_glx->gl_context = glXCreateNewContext (xdisplay, if (!cogl_renderer_check_onscreen_template (backend->cogl_renderer,
config, onscreen_template,
GLX_RGBA_TYPE, error))
NULL, goto error;
True);
if (backend_glx->gl_context == NULL)
{
g_set_error_literal (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Unable to create suitable GL context");
return FALSE;
}
is_direct = glXIsDirect (xdisplay, backend_glx->gl_context); backend->cogl_display = cogl_display_new (backend->cogl_renderer,
onscreen_template);
cogl_object_unref (backend->cogl_renderer);
cogl_object_unref (onscreen_template);
CLUTTER_NOTE (GL, "Setting %s context", if (!cogl_display_setup (backend->cogl_display, error))
is_direct ? "direct" goto error;
: "indirect");
_cogl_set_indirect_context (!is_direct);
/* COGL assumes that there is always a GL context selected; in order backend->cogl_context = cogl_context_new (backend->cogl_display, error);
* to make sure that a GLX context exists and is made current, we use if (!backend->cogl_context)
* a dummy, offscreen override-redirect window to which we can always goto error;
* fall back if no stage is available
*
* XXX - we need to do this dance because GLX does not allow creating
* a context and querying it for basic information (even the function
* pointers) unless it's made current to a real Drawable. it should be
* possible to avoid this in future releases of Mesa and X11, but right
* now this is the best solution available.
*/
xvisinfo = glXGetVisualFromFBConfig (xdisplay, config);
if (xvisinfo == NULL)
{
g_set_error_literal (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Unable to retrieve the X11 visual");
return FALSE;
}
clutter_x11_trap_x_errors (); /* XXX: eventually this should go away but a lot of Cogl code still
* depends on a global default context. */
attrs.override_redirect = True; cogl_set_default_context (backend->cogl_context);
attrs.colormap = XCreateColormap (xdisplay,
root_xwin,
xvisinfo->visual,
AllocNone);
attrs.border_pixel = 0;
backend_glx->dummy_xwin = XCreateWindow (xdisplay, root_xwin,
-100, -100, 1, 1,
0,
xvisinfo->depth,
CopyFromParent,
xvisinfo->visual,
CWOverrideRedirect | CWColormap | CWBorderPixel,
&attrs);
/* Try and create a GLXWindow to use with extensions dependent on
* GLX versions >= 1.3 that don't accept regular X Windows as GLX
* drawables. */
if (glXQueryVersion (backend_x11->xdpy, &major, &minor) &&
major == 1 && minor >= 3)
{
backend_glx->dummy_glxwin = glXCreateWindow (backend_x11->xdpy,
config,
backend_glx->dummy_xwin,
NULL);
}
if (backend_glx->dummy_glxwin)
dummy_drawable = backend_glx->dummy_glxwin;
else
dummy_drawable = backend_glx->dummy_xwin;
CLUTTER_NOTE (BACKEND, "Selecting dummy 0x%x for the GLX context",
(unsigned int) dummy_drawable);
glXMakeContextCurrent (xdisplay,
dummy_drawable,
dummy_drawable,
backend_glx->gl_context);
XFree (xvisinfo);
if (clutter_x11_untrap_x_errors ())
{
g_set_error_literal (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Unable to select the newly created GLX context");
return FALSE;
}
return TRUE; return TRUE;
}
/* TODO: remove this interface in favour of error:
* _clutter_stage_window_make_current () */ if (backend->cogl_display)
static void
clutter_backend_glx_ensure_context (ClutterBackend *backend,
ClutterStage *stage)
{
ClutterStageWindow *impl;
/* if there is no stage, the stage is being destroyed or it has no
* implementation attached to it then we clear the GL context
*/
if (stage == NULL ||
CLUTTER_ACTOR_IN_DESTRUCTION (stage) ||
((impl = _clutter_stage_get_window (stage)) == NULL))
{ {
ClutterBackendX11 *backend_x11; cogl_object_unref (backend->cogl_display);
backend->cogl_display = NULL;
backend_x11 = CLUTTER_BACKEND_X11 (backend);
CLUTTER_NOTE (MULTISTAGE, "Clearing all context");
glXMakeContextCurrent (backend_x11->xdpy, None, None, NULL);
} }
else
if (onscreen_template)
cogl_object_unref (onscreen_template);
if (swap_chain)
cogl_object_unref (swap_chain);
if (backend->cogl_renderer)
{ {
ClutterBackendGLX *backend_glx; cogl_object_unref (backend->cogl_renderer);
ClutterBackendX11 *backend_x11; backend->cogl_renderer = NULL;
ClutterStageGLX *stage_glx;
ClutterStageX11 *stage_x11;
GLXDrawable drawable;
g_assert (impl != NULL);
stage_glx = CLUTTER_STAGE_GLX (impl);
stage_x11 = CLUTTER_STAGE_X11 (impl);
backend_glx = CLUTTER_BACKEND_GLX (backend);
backend_x11 = CLUTTER_BACKEND_X11 (backend);
drawable = stage_glx->glxwin ? stage_glx->glxwin : stage_x11->xwin;
CLUTTER_NOTE (BACKEND,
"Setting context for stage of type %s, window: 0x%x",
G_OBJECT_TYPE_NAME (impl),
(unsigned int) drawable);
/* no GL context to set */
if (backend_glx->gl_context == NULL)
return;
clutter_x11_trap_x_errors ();
/* we might get here inside the final dispose cycle, so we
* need to handle this gracefully
*/
if (drawable == None)
{
GLXDrawable dummy_drawable;
CLUTTER_NOTE (BACKEND,
"Received a stale stage, clearing all context");
if (backend_glx->dummy_glxwin)
dummy_drawable = backend_glx->dummy_glxwin;
else
dummy_drawable = backend_glx->dummy_xwin;
if (dummy_drawable == None)
glXMakeContextCurrent (backend_x11->xdpy, None, None, NULL);
else
{
glXMakeContextCurrent (backend_x11->xdpy,
dummy_drawable,
dummy_drawable,
backend_glx->gl_context);
}
}
else
{
CLUTTER_NOTE (BACKEND,
"MakeContextCurrent dpy: %p, window: 0x%x (%s), context: %p",
backend_x11->xdpy,
(unsigned int) drawable,
stage_x11->is_foreign_xwin ? "foreign" : "native",
backend_glx->gl_context);
glXMakeContextCurrent (backend_x11->xdpy,
drawable,
drawable,
backend_glx->gl_context);
/*
* In case we are using GLX_SGI_swap_control for vblank syncing we need call
* glXSwapIntervalSGI here to make sure that it affects the current drawable.
*/
if (backend_glx->vblank_type == CLUTTER_VBLANK_GLX_SWAP && backend_glx->swap_interval != NULL)
backend_glx->swap_interval (1);
}
if (clutter_x11_untrap_x_errors ())
g_critical ("Unable to make the stage window 0x%x the current "
"GLX drawable",
(unsigned int) drawable);
} }
return FALSE;
} }
static ClutterStageWindow * static ClutterStageWindow *
@ -812,6 +326,16 @@ clutter_backend_glx_create_stage (ClutterBackend *backend,
return stage_window; return stage_window;
} }
static void
clutter_backend_glx_ensure_context (ClutterBackend *backend,
ClutterStage *stage)
{
ClutterStageGLX *stage_glx =
CLUTTER_STAGE_GLX (_clutter_stage_get_window (stage));
cogl_set_framebuffer (COGL_FRAMEBUFFER (stage_glx->onscreen));
}
static void static void
clutter_backend_glx_class_init (ClutterBackendGLXClass *klass) clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
{ {

View File

@ -47,30 +47,11 @@ typedef struct _ClutterBackendGLXClass ClutterBackendGLXClass;
typedef enum ClutterGLXVBlankType { typedef enum ClutterGLXVBlankType {
CLUTTER_VBLANK_NONE = 0, CLUTTER_VBLANK_NONE = 0,
CLUTTER_VBLANK_GLX_SWAP, CLUTTER_VBLANK_AUTOMATIC_THROTTLE,
CLUTTER_VBLANK_GLX, CLUTTER_VBLANK_VBLANK_COUNTER,
CLUTTER_VBLANK_DRI CLUTTER_VBLANK_MANUAL_WAIT
} ClutterGLXVBlankType; } ClutterGLXVBlankType;
typedef int (*GetVideoSyncProc) (unsigned int *count);
typedef int (*WaitVideoSyncProc) (int divisor,
int remainder,
unsigned int *count);
typedef int (*SwapIntervalProc) (int interval);
typedef void (*CopySubBufferProc)(Display *dpy,
GLXDrawable drawable,
int x, int y, int width, int height);
typedef void (*BlitFramebufferProc) (GLint srcX0,
GLint srcY0,
GLint srcX1,
GLint srcY1,
GLint dstX0,
GLint dstY0,
GLint dstX1,
GLint dstY1,
GLbitfield mask,
GLenum filter);
struct _ClutterBackendGLX struct _ClutterBackendGLX
{ {
ClutterBackendX11 parent_instance; ClutterBackendX11 parent_instance;
@ -78,25 +59,13 @@ struct _ClutterBackendGLX
int error_base; int error_base;
int event_base; int event_base;
/* Single context for all wins */ CoglContext *cogl_context;
gboolean found_fbconfig;
GLXFBConfig fbconfig;
GLXContext gl_context;
Window dummy_xwin;
GLXWindow dummy_glxwin;
/* Vblank stuff */ /* Vblank stuff */
GetVideoSyncProc get_video_sync;
WaitVideoSyncProc wait_video_sync;
SwapIntervalProc swap_interval;
gint dri_fd;
ClutterGLXVBlankType vblank_type; ClutterGLXVBlankType vblank_type;
unsigned int last_video_sync_count; unsigned int last_video_sync_count;
gboolean can_blit_sub_buffer; gboolean can_blit_sub_buffer;
CopySubBufferProc copy_sub_buffer;
BlitFramebufferProc blit_framebuffer;
gboolean blit_sub_buffer_is_synchronized;
/* props */ /* props */
Atom atom_WM_STATE; Atom atom_WM_STATE;
@ -110,14 +79,8 @@ struct _ClutterBackendGLXClass
GType _clutter_backend_glx_get_type (void) G_GNUC_CONST; GType _clutter_backend_glx_get_type (void) G_GNUC_CONST;
gboolean G_CONST_RETURN gchar*
_clutter_backend_glx_get_fbconfig (ClutterBackendGLX *backend_x11, _clutter_backend_glx_get_vblank (void);
GLXFBConfig *config);
void
_clutter_backend_glx_blit_sub_buffer (ClutterBackendGLX *backend_glx,
GLXDrawable drawable,
int x, int y, int width, int height);
G_END_DECLS G_END_DECLS

View File

@ -53,10 +53,8 @@
#endif #endif
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface); static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface);
static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL; static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL;
static ClutterEventTranslatorIface *clutter_event_translator_parent_iface = NULL;
#define clutter_stage_glx_get_type _clutter_stage_glx_get_type #define clutter_stage_glx_get_type _clutter_stage_glx_get_type
@ -64,33 +62,37 @@ G_DEFINE_TYPE_WITH_CODE (ClutterStageGLX,
clutter_stage_glx, clutter_stage_glx,
CLUTTER_TYPE_STAGE_X11, CLUTTER_TYPE_STAGE_X11,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
clutter_stage_window_iface_init) clutter_stage_window_iface_init));
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR,
clutter_event_translator_iface_init));
static void static void
clutter_stage_glx_unrealize (ClutterStageWindow *stage_window) clutter_stage_glx_unrealize (ClutterStageWindow *stage_window)
{ {
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window); ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
ClutterBackendX11 *backend_x11 = stage_x11->backend;
/* Note unrealize should free up any backend stage related resources */ /* Note unrealize should free up any backend stage related resources */
CLUTTER_NOTE (BACKEND, "Unrealizing GLX stage [%p]", stage_glx); CLUTTER_NOTE (BACKEND, "Unrealizing GLX stage [%p]", stage_glx);
clutter_x11_trap_x_errors (); cogl_object_unref (stage_glx->onscreen);
stage_glx->onscreen = NULL;
}
if (stage_glx->glxwin != None) static void
{ handle_swap_complete_cb (CoglFramebuffer *framebuffer,
glXDestroyWindow (backend_x11->xdpy, stage_glx->glxwin); void *user_data)
stage_glx->glxwin = None; {
} ClutterStageGLX *stage_glx = user_data;
_clutter_stage_x11_destroy_window_untrapped (stage_x11); /* Early versions of the swap_event implementation in Mesa
* deliver BufferSwapComplete event when not selected for,
XSync (backend_x11->xdpy, False); * so if we get a swap event we aren't expecting, just ignore it.
*
clutter_x11_untrap_x_errors (); * https://bugs.freedesktop.org/show_bug.cgi?id=27962
*
* FIXME: This issue can be hidden inside Cogl so we shouldn't
* need to care about this bug here.
*/
if (stage_glx->pending_swaps > 0)
stage_glx->pending_swaps--;
} }
static gboolean static gboolean
@ -98,56 +100,53 @@ clutter_stage_glx_realize (ClutterStageWindow *stage_window)
{ {
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window); ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
ClutterBackendX11 *backend_x11; ClutterBackend *backend;
ClutterBackendGLX *backend_glx; ClutterBackendGLX *backend_glx;
CoglFramebuffer *framebuffer;
GError *error = NULL;
gfloat width;
gfloat height;
const char *clutter_vblank;
CLUTTER_NOTE (ACTOR, "Realizing stage '%s' [%p]", CLUTTER_NOTE (ACTOR, "Realizing stage '%s' [%p]",
G_OBJECT_TYPE_NAME (stage_window), G_OBJECT_TYPE_NAME (stage_window),
stage_window); stage_window);
if (!_clutter_stage_x11_create_window (stage_x11)) backend = CLUTTER_BACKEND (stage_x11->backend);
return FALSE; backend_glx = CLUTTER_BACKEND_GLX (stage_x11->backend);
backend_x11 = stage_x11->backend; clutter_actor_get_size (CLUTTER_ACTOR (stage_x11->wrapper), &width, &height);
backend_glx = CLUTTER_BACKEND_GLX (backend_x11);
if (stage_glx->glxwin == None) stage_glx->onscreen = cogl_onscreen_new (backend->cogl_context,
width, height);
if (stage_x11->xwin != None)
cogl_onscreen_x11_set_foreign_window_xid (stage_glx->onscreen,
stage_x11->xwin);
clutter_vblank = _clutter_backend_glx_get_vblank ();
if (clutter_vblank && strcmp (clutter_vblank, "none") == 0)
cogl_onscreen_set_swap_throttled (stage_glx->onscreen, FALSE);
framebuffer = COGL_FRAMEBUFFER (stage_glx->onscreen);
if (!cogl_framebuffer_allocate (framebuffer, &error))
{ {
int major; g_warning ("Failed to allocate stage: %s", error->message);
int minor; g_error_free (error);
GLXFBConfig config; cogl_object_unref (stage_glx->onscreen);
stage_glx->onscreen = NULL;
/* Try and create a GLXWindow to use with extensions dependent on return FALSE;
* GLX versions >= 1.3 that don't accept regular X Windows as GLX
* drawables.
*/
if (glXQueryVersion (backend_x11->xdpy, &major, &minor) &&
major == 1 && minor >= 3 &&
_clutter_backend_glx_get_fbconfig (backend_glx, &config))
{
stage_glx->glxwin = glXCreateWindow (backend_x11->xdpy,
config,
stage_x11->xwin,
NULL);
}
} }
#ifdef GLX_INTEL_swap_event if (stage_x11->xwin == None)
if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS)) stage_x11->xwin = cogl_onscreen_x11_get_window_xid (stage_glx->onscreen);
{
GLXDrawable drawable = stage_glx->glxwin
? stage_glx->glxwin
: stage_x11->xwin;
/* we unconditionally select this event because we rely on it to if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
* advance the master clock, and drive redraw/relayout, animations {
* and event handling. stage_glx->swap_callback_id =
*/ cogl_framebuffer_add_swap_buffers_callback (framebuffer,
glXSelectEvent (backend_x11->xdpy, handle_swap_complete_cb,
drawable, stage_glx);
GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK);
} }
#endif /* GLX_INTEL_swap_event */
/* chain up to the StageX11 implementation */ /* chain up to the StageX11 implementation */
return clutter_stage_window_parent_iface->realize (stage_window); return clutter_stage_window_parent_iface->realize (stage_window);
@ -311,65 +310,12 @@ clutter_stage_glx_add_redraw_clip (ClutterStageWindow *stage_window,
stage_glx->initialized_redraw_clip = TRUE; stage_glx->initialized_redraw_clip = TRUE;
} }
#ifdef HAVE_DRM
static int
drm_wait_vblank(int fd, drm_wait_vblank_t *vbl)
{
int ret, rc;
do
{
ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
vbl->request.type &= ~_DRM_VBLANK_RELATIVE;
rc = errno;
}
while (ret && rc == EINTR);
return rc;
}
#endif /* HAVE_DRM */
static void
wait_for_vblank (ClutterBackendGLX *backend_glx)
{
if (backend_glx->vblank_type == CLUTTER_VBLANK_NONE)
return;
if (backend_glx->wait_video_sync)
{
unsigned int retraceCount;
CLUTTER_NOTE (BACKEND, "Waiting for vblank (wait_video_sync)");
backend_glx->get_video_sync (&retraceCount);
backend_glx->wait_video_sync (2,
(retraceCount + 1) % 2,
&retraceCount);
}
else
{
#ifdef HAVE_DRM
drm_wait_vblank_t blank;
CLUTTER_NOTE (BACKEND, "Waiting for vblank (drm)");
blank.request.type = _DRM_VBLANK_RELATIVE;
blank.request.sequence = 1;
blank.request.signal = 0;
drm_wait_vblank (backend_glx->dri_fd, &blank);
#else
CLUTTER_NOTE (BACKEND, "No vblank mechanism found");
#endif /* HAVE_DRM */
}
}
static void static void
clutter_stage_glx_redraw (ClutterStageWindow *stage_window) clutter_stage_glx_redraw (ClutterStageWindow *stage_window)
{ {
ClutterBackendX11 *backend_x11;
ClutterBackendGLX *backend_glx; ClutterBackendGLX *backend_glx;
ClutterStageX11 *stage_x11; ClutterStageX11 *stage_x11;
ClutterStageGLX *stage_glx; ClutterStageGLX *stage_glx;
GLXDrawable drawable;
unsigned int video_sync_count;
gboolean may_use_clipped_redraw; gboolean may_use_clipped_redraw;
gboolean use_clipped_redraw; gboolean use_clipped_redraw;
@ -395,8 +341,7 @@ clutter_stage_glx_redraw (ClutterStageWindow *stage_window)
stage_glx = CLUTTER_STAGE_GLX (stage_window); stage_glx = CLUTTER_STAGE_GLX (stage_window);
backend_x11 = stage_x11->backend; backend_glx = CLUTTER_BACKEND_GLX (stage_x11->backend);
backend_glx = CLUTTER_BACKEND_GLX (backend_x11);
CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer); CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer);
@ -502,173 +447,75 @@ clutter_stage_glx_redraw (ClutterStageWindow *stage_window)
cogl_object_unref (vbo); cogl_object_unref (vbo);
} }
cogl_flush ();
CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer); CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer);
drawable = stage_glx->glxwin
? stage_glx->glxwin
: stage_x11->xwin;
/* If we might ever use _clutter_backend_glx_blit_sub_buffer then we
* always need to keep track of the video_sync_count so that we can
* throttle blits.
*
* Note: we get the count *before* we issue any glXCopySubBuffer or
* blit_sub_buffer request in case the count would go up before
* returning control to us.
*/
if (backend_glx->can_blit_sub_buffer && backend_glx->get_video_sync)
backend_glx->get_video_sync (&video_sync_count);
/* push on the screen */ /* push on the screen */
if (use_clipped_redraw) if (use_clipped_redraw)
{ {
ClutterGeometry *clip = &stage_glx->bounding_redraw_clip; ClutterGeometry *clip = &stage_glx->bounding_redraw_clip;
ClutterGeometry copy_area; int copy_area[4];
ClutterActor *actor; ClutterActor *actor;
CLUTTER_NOTE (BACKEND,
"_glx_blit_sub_buffer (window: 0x%lx, "
"x: %d, y: %d, "
"width: %d, height: %d)",
(unsigned long) drawable,
stage_glx->bounding_redraw_clip.x,
stage_glx->bounding_redraw_clip.y,
stage_glx->bounding_redraw_clip.width,
stage_glx->bounding_redraw_clip.height);
/* XXX: It seems there will be a race here in that the stage /* XXX: It seems there will be a race here in that the stage
* window may be resized before glXCopySubBufferMESA is handled * window may be resized before the cogl_framebuffer_swap_region
* and so we may copy the wrong region. I can't really see how * is handled and so we may copy the wrong region. I can't
* we can handle this with the current state of X but at least * really see how we can handle this with the current state of X
* in this case a full redraw should be queued by the resize * but at least in this case a full redraw should be queued by
* anyway so it should only exhibit temporary artefacts. * the resize anyway so it should only exhibit temporary
* artefacts.
*/ */
actor = CLUTTER_ACTOR (stage_x11->wrapper); actor = CLUTTER_ACTOR (stage_x11->wrapper);
copy_area.y = clutter_actor_get_height (actor)
- clip->y
- clip->height;
copy_area.x = clip->x;
copy_area.width = clip->width;
copy_area.height = clip->height;
/* We need to ensure that all the rendering is done, otherwise copy_area[0] = clip->x;
* redraw operations that are slower than the framerate can copy_area[1] = clutter_actor_get_height (actor) - clip->y - clip->height;
* queue up in the pipeline during a heavy animation, causing a copy_area[2] = clip->width;
* larger and larger backlog of rendering visible as lag to the copy_area[3] = clip->height;
* user.
*
* Note: since calling glFinish() and sycnrhonizing the CPU with
* the GPU is far from ideal, we hope that this is only a short
* term solution.
* - One idea is to using sync objects to track render
* completion so we can throttle the backlog (ideally with an
* additional extension that lets us get notifications in our
* mainloop instead of having to busy wait for the
* completion.)
* - Another option is to support clipped redraws by reusing the
* contents of old back buffers such that we can flip instead
* of using a blit and then we can use GLX_INTEL_swap_events
* to throttle. For this though we would still probably want an
* additional extension so we can report the limited region of
* the window damage to X/compositors.
*/
glFinish ();
/* glXCopySubBufferMESA and glBlitFramebuffer are not integrated CLUTTER_NOTE (BACKEND,
* with the glXSwapIntervalSGI mechanism which we usually use to "cogl_framebuffer_swap_region (onscreen: %p, "
* throttle the Clutter framerate to the vertical refresh and so "x: %d, y: %d, "
* we have to manually wait for the vblank period... "width: %d, height: %d)",
*/ stage_glx->onscreen,
copy_area[0], copy_area[1], copy_area[2], copy_area[3]);
/* Here 'is_synchronized' only means that the blit won't cause a
* tear, ie it won't prevent multiple blits per retrace if they
* can all be performed in the blanking period. If that's the
* case then we still want to use the vblank sync menchanism but
* we only need it to throttle redraws.
*/
if (!backend_glx->blit_sub_buffer_is_synchronized)
{
/* XXX: note that glXCopySubBuffer, at least for Intel, is
* synchronized with the vblank but glBlitFramebuffer may
* not be so we use the same scheme we do when calling
* glXSwapBuffers without the swap_control extension and
* call glFinish () before waiting for the vblank period.
*
* See where we call glXSwapBuffers for more details.
*/
wait_for_vblank (backend_glx);
}
else if (backend_glx->get_video_sync)
{
/* If we have the GLX_SGI_video_sync extension then we can
* be a bit smarter about how we throttle blits by avoiding
* any waits if we can see that the video sync count has
* already progressed. */
if (backend_glx->last_video_sync_count == video_sync_count)
wait_for_vblank (backend_glx);
}
else
wait_for_vblank (backend_glx);
CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer); CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer);
_clutter_backend_glx_blit_sub_buffer (backend_glx,
drawable, cogl_framebuffer_swap_region (COGL_FRAMEBUFFER (stage_glx->onscreen),
copy_area.x, copy_area, 1);
copy_area.y,
copy_area.width,
copy_area.height);
CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer); CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer);
} }
else else
{ {
CLUTTER_NOTE (BACKEND, "glXSwapBuffers (display: %p, window: 0x%lx)", CLUTTER_NOTE (BACKEND, "cogl_framebuffer_swap_buffers (onscreen: %p)",
backend_x11->xdpy, stage_glx->onscreen);
(unsigned long) drawable);
/* If we have GLX swap buffer events then glXSwapBuffers will return /* If we have swap buffer events then
* immediately and we need to track that there is a swap in * cogl_framebuffer_swap_buffers will return immediately and we
* progress... */ * need to track that there is a swap in progress... */
if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS)) if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS))
stage_glx->pending_swaps++; stage_glx->pending_swaps++;
if (backend_glx->vblank_type != CLUTTER_VBLANK_GLX_SWAP &&
backend_glx->vblank_type != CLUTTER_VBLANK_NONE)
{
/* If we are going to wait for VBLANK manually, we not only
* need to flush out pending drawing to the GPU before we
* sleep, we need to wait for it to finish. Otherwise, we
* may end up with the situation:
*
* - We finish drawing - GPU drawing continues
* - We go to sleep - GPU drawing continues
* VBLANK - We call glXSwapBuffers - GPU drawing continues
* - GPU drawing continues
* - Swap buffers happens
*
* Producing a tear. Calling glFinish() first will cause us
* to properly wait for the next VBLANK before we swap. This
* obviously does not happen when we use _GLX_SWAP and let
* the driver do the right thing
*/
glFinish ();
wait_for_vblank (backend_glx);
}
CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer); CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer);
glXSwapBuffers (backend_x11->xdpy, drawable); cogl_framebuffer_swap_buffers (COGL_FRAMEBUFFER (stage_glx->onscreen));
CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer); CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer);
} }
backend_glx->last_video_sync_count = video_sync_count;
/* reset the redraw clipping for the next paint... */ /* reset the redraw clipping for the next paint... */
stage_glx->initialized_redraw_clip = FALSE; stage_glx->initialized_redraw_clip = FALSE;
stage_glx->frame_count++; stage_glx->frame_count++;
} }
static CoglFramebuffer *
clutter_stage_glx_get_active_framebuffer (ClutterStageWindow *stage_window)
{
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
return COGL_FRAMEBUFFER (stage_glx->onscreen);
}
static void static void
clutter_stage_window_iface_init (ClutterStageWindowIface *iface) clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
{ {
@ -682,55 +529,7 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
iface->has_redraw_clips = clutter_stage_glx_has_redraw_clips; iface->has_redraw_clips = clutter_stage_glx_has_redraw_clips;
iface->ignoring_redraw_clips = clutter_stage_glx_ignoring_redraw_clips; iface->ignoring_redraw_clips = clutter_stage_glx_ignoring_redraw_clips;
iface->redraw = clutter_stage_glx_redraw; iface->redraw = clutter_stage_glx_redraw;
iface->get_active_framebuffer = clutter_stage_glx_get_active_framebuffer;
/* the rest is inherited from ClutterStageX11 */ /* the rest is inherited from ClutterStageX11 */
} }
static ClutterTranslateReturn
clutter_stage_glx_translate_event (ClutterEventTranslator *translator,
gpointer native,
ClutterEvent *event)
{
#ifdef GLX_INTEL_swap_event
ClutterBackendGLX *backend_glx;
XEvent *xevent = native;
backend_glx = CLUTTER_BACKEND_GLX (clutter_get_default_backend ());
if (xevent->type == (backend_glx->event_base + GLX_BufferSwapComplete))
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (translator);
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (translator);
GLXBufferSwapComplete *swap_complete_event;
swap_complete_event = (GLXBufferSwapComplete *) xevent;
if (stage_x11->xwin == swap_complete_event->drawable)
{
/* Early versions of the swap_event implementation in Mesa
* deliver BufferSwapComplete event when not selected for,
* so if we get a swap event we aren't expecting, just ignore it.
*
* https://bugs.freedesktop.org/show_bug.cgi?id=27962
*/
if (stage_glx->pending_swaps > 0)
stage_glx->pending_swaps--;
return CLUTTER_TRANSLATE_REMOVE;
}
}
#endif
/* chain up to the common X11 implementation */
return clutter_event_translator_parent_iface->translate_event (translator,
native,
event);
}
static void
clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface)
{
clutter_event_translator_parent_iface = g_type_interface_peek_parent (iface);
iface->translate_event = clutter_stage_glx_translate_event;
}

View File

@ -50,8 +50,9 @@ struct _ClutterStageGLX
gint pending_swaps; gint pending_swaps;
GLXPixmap glxpixmap; CoglOnscreen *onscreen;
GLXWindow glxwin;
unsigned int swap_callback_id;
/* We only enable clipped redraws after 2 frames, since we've seen /* We only enable clipped redraws after 2 frames, since we've seen
* a lot of drivers can struggle to get going and may output some * a lot of drivers can struggle to get going and may output some

View File

@ -134,7 +134,7 @@ cogl_xlib_filter (XEvent *xevent,
ClutterX11FilterReturn retval; ClutterX11FilterReturn retval;
CoglXlibFilterReturn ret; CoglXlibFilterReturn ret;
ret = _cogl_xlib_handle_event (xevent); ret = cogl_xlib_handle_event (xevent);
switch (ret) switch (ret)
{ {
case COGL_XLIB_FILTER_REMOVE: case COGL_XLIB_FILTER_REMOVE:
@ -390,7 +390,7 @@ _clutter_backend_x11_post_parse (ClutterBackend *backend,
/* Cogl needs to know the Xlib display connection for /* Cogl needs to know the Xlib display connection for
CoglTexturePixmapX11 */ CoglTexturePixmapX11 */
_cogl_xlib_set_display (backend_x11->xdpy); cogl_xlib_set_display (backend_x11->xdpy);
/* add event filter for Cogl events */ /* add event filter for Cogl events */
clutter_x11_add_filter (cogl_xlib_filter, NULL); clutter_x11_add_filter (cogl_xlib_filter, NULL);

View File

@ -379,6 +379,13 @@ clutter_stage_x11_realize (ClutterStageWindow *stage_window)
ClutterDeviceManager *device_manager; ClutterDeviceManager *device_manager;
int event_flags; int event_flags;
if (clutter_stages_by_xid == NULL)
clutter_stages_by_xid = g_hash_table_new (NULL, NULL);
g_hash_table_insert (clutter_stages_by_xid,
GINT_TO_POINTER (stage_x11->xwin),
stage_x11);
set_wm_pid (stage_x11); set_wm_pid (stage_x11);
set_wm_title (stage_x11); set_wm_title (stage_x11);
set_cursor_visible (stage_x11); set_cursor_visible (stage_x11);
@ -1436,13 +1443,6 @@ _clutter_stage_x11_create_window (ClutterStageX11 *stage_x11)
XFree (xvisinfo); XFree (xvisinfo);
if (clutter_stages_by_xid == NULL)
clutter_stages_by_xid = g_hash_table_new (NULL, NULL);
g_hash_table_insert (clutter_stages_by_xid,
GINT_TO_POINTER (stage_x11->xwin),
stage_x11);
return TRUE; return TRUE;
} }

View File

@ -447,6 +447,8 @@ AS_IF([test "x$SUPPORT_GLX" = "x1"],
[ [
AC_DEFINE([COGL_HAS_GLX_SUPPORT], [1], [Cogl supports OpenGL using the GLX API]) AC_DEFINE([COGL_HAS_GLX_SUPPORT], [1], [Cogl supports OpenGL using the GLX API])
AC_DEFINE([COGL_HAS_FULL_WINSYS], [1], [Cogl can create its own OpenGL context])
AC_DEFINE([HAVE_CLUTTER_GLX], [1], [Have the GLX backend]) AC_DEFINE([HAVE_CLUTTER_GLX], [1], [Have the GLX backend])
AC_CHECK_HEADERS([GL/glx.h], AC_CHECK_HEADERS([GL/glx.h],