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