unify egl and glx backends as "cogl" backend

Since GLX and EGL are abstracted by Cogl the two backends are both
implementing everything using the Cogl API and they are almost
identical.

This updates the egl backend to support everything that the glx backend
supports. Now that EGL and GLX are abstracted by Cogl, the plan is that
we will squash the clutter-egl/glx backends into one. Since the EGL
backend in clutter can conditionally not depend on X11 we will use the
EGL backend as the starting point of our common backend.

https://bugzilla.gnome.org/show_bug.cgi?id=649826
This commit is contained in:
Robert Bragg 2011-05-09 00:27:10 +01:00
parent 951cb82ec5
commit 2d8083bab8
18 changed files with 444 additions and 1506 deletions

View File

@ -353,32 +353,37 @@ clutterx11_includedir = $(clutter_includedir)/x11
clutterx11_include_HEADERS = $(x11_source_h) clutterx11_include_HEADERS = $(x11_source_h)
endif # SUPPORT_X11 endif # SUPPORT_X11
# GLX backend rules # Shared cogl backend files
glx_source_c = \ cogl_source_h =
$(srcdir)/glx/clutter-backend-glx.c \
$(srcdir)/glx/clutter-glx-texture-pixmap.c \ cogl_source_c = \
$(srcdir)/glx/clutter-stage-glx.c \ $(srcdir)/cogl/clutter-backend-cogl.c \
$(srcdir)/cogl/clutter-stage-cogl.c \
$(NULL) $(NULL)
glx_source_h = \ cogl_source_h_priv = \
$(srcdir)/glx/clutter-glx-texture-pixmap.h \ $(srcdir)/cogl/clutter-backend-cogl.h \
$(srcdir)/glx/clutter-glx.h \ $(srcdir)/cogl/clutter-stage-cogl.h \
$(NULL) $(NULL)
glx_source_h_priv = \ cogl_source_c_priv =
$(srcdir)/glx/clutter-backend-glx.h \
$(srcdir)/glx/clutter-stage-glx.h \
$(NULL)
if SUPPORT_GLX if SUPPORT_X11
backend_source_h += $(glx_source_h) # For compatability with the old GLX backend
backend_source_c += $(glx_source_c) #
backend_source_h_priv += $(glx_source_h_priv) # Note: there wasn't actually anything GLX specific so we can add
# the compatability if clutter supports x11
# XXX - this is another hack; we installed glx headers under includedir/glx glx_source_c = $(srcdir)/cogl/clutter-glx-texture-pixmap.c
# instead of using the same directory. glx_source_h = $(srcdir)/cogl/clutter-glx-texture-pixmap.h \
$(srcdir)/cogl/clutter-glx.h
clutterglx_includedir = $(clutter_includedir)/glx clutterglx_includedir = $(clutter_includedir)/glx
clutterglx_include_HEADERS = $(glx_source_h) clutterglx_include_HEADERS = $(glx_source_h)
endif
if SUPPORT_GLX
backend_source_h += $(cogl_source_h)
backend_source_c += $(cogl_source_c)
backend_source_h_priv += $(cogl_source_h_priv)
endif # SUPPORT_GLX endif # SUPPORT_GLX
# Windows backend rules # Windows backend rules
@ -429,22 +434,10 @@ EXTRA_DIST += \
# EGL backend rules # EGL backend rules
egl_source_h = \ egl_source_h = \
$(srcdir)/egl/clutter-egl-headers.h \ $(srcdir)/cogl/clutter-egl-headers.h \
$(srcdir)/egl/clutter-egl.h \ $(srcdir)/cogl/clutter-egl.h \
$(NULL) $(NULL)
egl_source_c = \
$(srcdir)/egl/clutter-backend-egl.c \
$(srcdir)/egl/clutter-stage-egl.c \
$(NULL)
egl_source_h_priv = \
$(srcdir)/egl/clutter-backend-egl.h \
$(srcdir)/egl/clutter-stage-egl.h \
$(NULL)
egl_source_c_priv =
egl_tslib_c = $(srcdir)/egl/clutter-event-tslib.c egl_tslib_c = $(srcdir)/egl/clutter-event-tslib.c
evdev_c_priv = \ evdev_c_priv = \
@ -458,29 +451,28 @@ evdev_h_priv = \
$(srcdir)/evdev/clutter-input-device-evdev.h \ $(srcdir)/evdev/clutter-input-device-evdev.h \
$(NULL) $(NULL)
egl_cex_h = egl/clutter-cex100.h cex_h = cogl/clutter-cex100.h
BUILT_SOURCES += egl/clutter-cex100.h BUILT_SOURCES += $(cex_h)
EXTRA_DIST += $(srcdir)/egl/clutter-cex100.h.in EXTRA_DIST += $(srcdir)/$(cex_h).in
if SUPPORT_EGL
if USE_TSLIB if USE_TSLIB
egl_source_c_priv += $(egl_tslib_c) backend_source_c_priv += $(egl_tslib_c)
endif # SUPPORT_TSLIB endif # SUPPORT_TSLIB
if SUPPORT_EVDEV if SUPPORT_EVDEV
egl_source_c_priv += $(evdev_c_priv) backend_source_c_priv += $(evdev_c_priv)
egl_source_h_priv += $(evdev_h_priv) backend_source_h_priv += $(evdev_h_priv)
endif # SUPPORT_EVDEV endif # SUPPORT_EVDEV
if SUPPORT_CEX100 if SUPPORT_CEX100
egl_source_h += $(egl_cex_h) backend_source_h += $(cex_h)
endif # SUPPORT_CEX100 endif # SUPPORT_CEX100
backend_source_h += $(egl_source_h) if SUPPORT_EGL
backend_source_c += $(egl_source_c) backend_source_h += $(cogl_source_h) $(egl_source_h)
backend_source_h_priv += $(egl_source_h_priv) backend_source_c += $(cogl_source_c)
backend_source_c_priv += $(egl_source_c_priv) backend_source_h_priv += $(cogl_source_h_priv)
backend_source_c_priv += $(cogl_source_c_priv)
clutteregl_includedir = $(clutter_includedir)/egl clutteregl_includedir = $(clutter_includedir)/egl
clutteregl_include_HEADERS = $(egl_source_h) clutteregl_include_HEADERS = $(egl_source_h)

View File

@ -3,7 +3,7 @@
* *
* An OpenGL based 'interactive canvas' library. * An OpenGL based 'interactive canvas' library.
* *
* Copyright (C) 2010 Intel Corporation. * Copyright (C) 2010,2011 Intel Corporation.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -36,9 +36,8 @@
#include <errno.h> #include <errno.h>
#include "clutter-backend-egl.h" #include "clutter-backend-cogl.h"
#include "clutter-stage-egl.h" #include "clutter-stage-cogl.h"
#include "clutter-egl.h"
#ifdef HAVE_EVDEV #ifdef HAVE_EVDEV
#include "clutter-device-manager-evdev.h" #include "clutter-device-manager-evdev.h"
@ -48,12 +47,15 @@
#include "clutter-private.h" #include "clutter-private.h"
#include "clutter-main.h" #include "clutter-main.h"
#include "clutter-stage-private.h" #include "clutter-stage-private.h"
/* FIXME: We should have CLUTTER_ define for this... */
#ifdef COGL_HAS_EGL_SUPPORT
#include "clutter-egl.h"
#endif
#ifdef COGL_HAS_EGL_PLATFORM_GDL_SUPPORT #ifdef COGL_HAS_EGL_PLATFORM_GDL_SUPPORT
#include "clutter-cex100.h" #include "clutter-cex100.h"
#endif #endif
static ClutterBackendEGL *backend_singleton = NULL; static ClutterBackendCogl *backend_singleton = NULL;
static gchar *clutter_vblank = NULL; static gchar *clutter_vblank = NULL;
@ -64,9 +66,9 @@ static guint gdl_n_buffers = CLUTTER_CEX100_TRIPLE_BUFFERING;
#endif #endif
#ifdef COGL_HAS_X11_SUPPORT #ifdef COGL_HAS_X11_SUPPORT
G_DEFINE_TYPE (ClutterBackendEGL, _clutter_backend_egl, CLUTTER_TYPE_BACKEND_X11); G_DEFINE_TYPE (ClutterBackendCogl, _clutter_backend_cogl, CLUTTER_TYPE_BACKEND_X11);
#else #else
G_DEFINE_TYPE (ClutterBackendEGL, _clutter_backend_egl, CLUTTER_TYPE_BACKEND); G_DEFINE_TYPE (ClutterBackendCogl, _clutter_backend_cogl, CLUTTER_TYPE_BACKEND);
#endif #endif
static void static void
@ -77,7 +79,7 @@ clutter_backend_at_exit (void)
} }
const gchar* const gchar*
_clutter_backend_egl_get_vblank (void) _clutter_backend_cogl_get_vblank (void)
{ {
if (clutter_vblank && strcmp (clutter_vblank, "0") == 0) if (clutter_vblank && strcmp (clutter_vblank, "0") == 0)
return "none"; return "none";
@ -86,13 +88,13 @@ _clutter_backend_egl_get_vblank (void)
} }
static gboolean static gboolean
clutter_backend_egl_pre_parse (ClutterBackend *backend, clutter_backend_cogl_pre_parse (ClutterBackend *backend,
GError **error) GError **error)
{ {
const gchar *env_string; const gchar *env_string;
#ifdef COGL_HAS_X11_SUPPORT #ifdef COGL_HAS_X11_SUPPORT
ClutterBackendClass *parent_class = ClutterBackendClass *parent_class =
CLUTTER_BACKEND_CLASS (_clutter_backend_egl_parent_class); CLUTTER_BACKEND_CLASS (_clutter_backend_cogl_parent_class);
if (!parent_class->pre_parse (backend, error)) if (!parent_class->pre_parse (backend, error))
return FALSE; return FALSE;
@ -109,12 +111,12 @@ clutter_backend_egl_pre_parse (ClutterBackend *backend,
} }
static gboolean static gboolean
clutter_backend_egl_post_parse (ClutterBackend *backend, clutter_backend_cogl_post_parse (ClutterBackend *backend,
GError **error) GError **error)
{ {
#ifdef COGL_HAS_X11_SUPPORT #ifdef COGL_HAS_X11_SUPPORT
ClutterBackendClass *parent_class = ClutterBackendClass *parent_class =
CLUTTER_BACKEND_CLASS (_clutter_backend_egl_parent_class); CLUTTER_BACKEND_CLASS (_clutter_backend_cogl_parent_class);
if (!parent_class->post_parse (backend, error)) if (!parent_class->post_parse (backend, error))
return FALSE; return FALSE;
@ -129,62 +131,62 @@ clutter_backend_egl_post_parse (ClutterBackend *backend,
#ifndef COGL_HAS_XLIB_SUPPORT #ifndef COGL_HAS_XLIB_SUPPORT
static ClutterDeviceManager * static ClutterDeviceManager *
clutter_backend_egl_get_device_manager (ClutterBackend *backend) clutter_backend_cogl_get_device_manager (ClutterBackend *backend)
{ {
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend); ClutterBackendCogl *backend_cogl = CLUTTER_BACKEND_COGL (backend);
if (G_UNLIKELY (backend_egl->device_manager == NULL)) if (G_UNLIKELY (backend_cogl->device_manager == NULL))
{ {
#ifdef HAVE_EVDEV #ifdef HAVE_EVDEV
backend_egl->device_manager = backend_cogl->device_manager =
g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_EVDEV, g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_EVDEV,
"backend", backend_egl, "backend", backend_cogl,
NULL); NULL);
#endif #endif
} }
return backend_egl->device_manager; return backend_cogl->device_manager;
} }
#endif #endif
static void static void
clutter_backend_egl_init_events (ClutterBackend *backend) clutter_backend_cogl_init_events (ClutterBackend *backend)
{ {
#ifdef HAVE_TSLIB #ifdef HAVE_TSLIB
/* XXX: This should be renamed to _clutter_events_tslib_init */ /* XXX: This should be renamed to _clutter_events_tslib_init */
_clutter_events_egl_init (CLUTTER_BACKEND_EGL (backend)); _clutter_events_tslib_init (CLUTTER_BACKEND_COGL (backend));
#endif #endif
#ifdef HAVE_EVDEV #ifdef HAVE_EVDEV
_clutter_events_evdev_init (CLUTTER_BACKEND (backend)); _clutter_events_evdev_init (CLUTTER_BACKEND (backend));
#endif #endif
#ifdef COGL_HAS_X11_SUPPORT #ifdef COGL_HAS_X11_SUPPORT
/* Chain up to the X11 backend */ /* Chain up to the X11 backend */
CLUTTER_BACKEND_CLASS (_clutter_backend_egl_parent_class)-> CLUTTER_BACKEND_CLASS (_clutter_backend_cogl_parent_class)->
init_events (backend); init_events (backend);
#endif #endif
} }
static void static void
clutter_backend_egl_finalize (GObject *gobject) clutter_backend_cogl_finalize (GObject *gobject)
{ {
if (backend_singleton) if (backend_singleton)
backend_singleton = NULL; backend_singleton = NULL;
G_OBJECT_CLASS (_clutter_backend_egl_parent_class)->finalize (gobject); G_OBJECT_CLASS (_clutter_backend_cogl_parent_class)->finalize (gobject);
} }
static void static void
clutter_backend_egl_dispose (GObject *gobject) clutter_backend_cogl_dispose (GObject *gobject)
{ {
ClutterBackend *backend = CLUTTER_BACKEND (gobject); ClutterBackend *backend = CLUTTER_BACKEND (gobject);
#ifdef HAVE_TSLIB #ifdef HAVE_TSLIB
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (gobject); ClutterBackendCogl *backend_cogl = CLUTTER_BACKEND_COGL (gobject);
#endif #endif
/* We chain up before disposing our CoglContext so that we will /* We chain up before disposing our CoglContext so that we will
* destroy all of the stages first. Otherwise the actors may try to * destroy all of the stages first. Otherwise the actors may try to
* make Cogl calls during destruction which would cause a crash */ * make Cogl calls during destruction which would cause a crash */
G_OBJECT_CLASS (_clutter_backend_egl_parent_class)->dispose (gobject); G_OBJECT_CLASS (_clutter_backend_cogl_parent_class)->dispose (gobject);
if (backend->cogl_context) if (backend->cogl_context)
{ {
@ -194,30 +196,30 @@ clutter_backend_egl_dispose (GObject *gobject)
#ifdef HAVE_TSLIB #ifdef HAVE_TSLIB
/* XXX: This should be renamed to _clutter_events_tslib_uninit */ /* XXX: This should be renamed to _clutter_events_tslib_uninit */
_clutter_events_egl_uninit (backend_egl); _clutter_events_egl_uninit (backend_cogl);
if (backend_egl->event_timer != NULL) if (backend_cogl->event_timer != NULL)
{ {
g_timer_destroy (backend_egl->event_timer); g_timer_destroy (backend_cogl->event_timer);
backend_egl->event_timer = NULL; backend_cogl->event_timer = NULL;
} }
#endif #endif
} }
static GObject * static GObject *
clutter_backend_egl_constructor (GType gtype, clutter_backend_cogl_constructor (GType gtype,
guint n_params, guint n_params,
GObjectConstructParam *params) GObjectConstructParam *params)
{ {
GObjectClass *parent_class; GObjectClass *parent_class;
GObject *retval; GObject *retval;
if (!backend_singleton) if (!backend_singleton)
{ {
parent_class = G_OBJECT_CLASS (_clutter_backend_egl_parent_class); parent_class = G_OBJECT_CLASS (_clutter_backend_cogl_parent_class);
retval = parent_class->constructor (gtype, n_params, params); retval = parent_class->constructor (gtype, n_params, params);
backend_singleton = CLUTTER_BACKEND_EGL (retval); backend_singleton = CLUTTER_BACKEND_COGL (retval);
return retval; return retval;
} }
@ -229,16 +231,16 @@ clutter_backend_egl_constructor (GType gtype,
} }
static ClutterFeatureFlags static ClutterFeatureFlags
clutter_backend_egl_get_features (ClutterBackend *backend) clutter_backend_cogl_get_features (ClutterBackend *backend)
{ {
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend); ClutterBackendCogl *backend_cogl = CLUTTER_BACKEND_COGL (backend);
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
ClutterBackendClass *parent_class; ClutterBackendClass *parent_class;
#endif #endif
ClutterFeatureFlags flags = 0; ClutterFeatureFlags flags = 0;
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
parent_class = CLUTTER_BACKEND_CLASS (_clutter_backend_egl_parent_class); parent_class = CLUTTER_BACKEND_CLASS (_clutter_backend_cogl_parent_class);
flags = parent_class->get_features (backend); flags = parent_class->get_features (backend);
#endif #endif
@ -271,7 +273,7 @@ clutter_backend_egl_get_features (ClutterBackend *backend)
if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION)) if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION))
{ {
CLUTTER_NOTE (BACKEND, "Cogl supports swapping buffer regions"); CLUTTER_NOTE (BACKEND, "Cogl supports swapping buffer regions");
backend_egl->can_blit_sub_buffer = TRUE; backend_cogl->can_blit_sub_buffer = TRUE;
} }
return flags; return flags;
@ -279,15 +281,15 @@ clutter_backend_egl_get_features (ClutterBackend *backend)
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
static XVisualInfo * static XVisualInfo *
clutter_backend_egl_get_visual_info (ClutterBackendX11 *backend_x11) clutter_backend_cogl_get_visual_info (ClutterBackendX11 *backend_x11)
{ {
return cogl_clutter_winsys_xlib_get_visual_info (); return cogl_clutter_winsys_xlib_get_visual_info ();
} }
#endif #endif
static gboolean static gboolean
clutter_backend_egl_create_context (ClutterBackend *backend, clutter_backend_cogl_create_context (ClutterBackend *backend,
GError **error) GError **error)
{ {
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
@ -372,9 +374,9 @@ error:
} }
static ClutterStageWindow * static ClutterStageWindow *
clutter_backend_egl_create_stage (ClutterBackend *backend, clutter_backend_cogl_create_stage (ClutterBackend *backend,
ClutterStage *wrapper, ClutterStage *wrapper,
GError **error) GError **error)
{ {
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
@ -382,7 +384,7 @@ clutter_backend_egl_create_stage (ClutterBackend *backend,
ClutterStageWindow *stage; ClutterStageWindow *stage;
ClutterStageX11 *stage_x11; ClutterStageX11 *stage_x11;
stage = g_object_new (CLUTTER_TYPE_STAGE_EGL, NULL); stage = g_object_new (CLUTTER_TYPE_STAGE_COGL, NULL);
/* copy backend data into the stage */ /* copy backend data into the stage */
stage_x11 = CLUTTER_STAGE_X11 (stage); stage_x11 = CLUTTER_STAGE_X11 (stage);
@ -392,33 +394,33 @@ clutter_backend_egl_create_stage (ClutterBackend *backend,
translator = CLUTTER_EVENT_TRANSLATOR (stage_x11); translator = CLUTTER_EVENT_TRANSLATOR (stage_x11);
_clutter_backend_add_event_translator (backend, translator); _clutter_backend_add_event_translator (backend, translator);
CLUTTER_NOTE (MISC, "EGLX stage created (display:%p, screen:%d, root:%u)", CLUTTER_NOTE (MISC, "Cogl stage created (display:%p, screen:%d, root:%u)",
backend_x11->xdpy, backend_x11->xdpy,
backend_x11->xscreen_num, backend_x11->xscreen_num,
(unsigned int) backend_x11->xwin_root); (unsigned int) backend_x11->xwin_root);
#else /* COGL_HAS_XLIB_SUPPORT */ #else /* COGL_HAS_XLIB_SUPPORT */
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend); ClutterBackendCogl *backend_cogl = CLUTTER_BACKEND_COGL (backend);
ClutterStageWindow *stage; ClutterStageWindow *stage;
ClutterStageEGL *stage_egl; ClutterStageCogl *stage_cogl;
if (G_UNLIKELY (backend_egl->stage != NULL)) if (G_UNLIKELY (backend_cogl->stage != NULL))
{ {
g_set_error (error, CLUTTER_INIT_ERROR, g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND, CLUTTER_INIT_ERROR_BACKEND,
"The Cogl backend does not support multiple " "The Cogl backend does not support multiple "
"onscreen windows"); "onscreen windows");
return backend_egl->stage; return backend_cogl->stage;
} }
stage = g_object_new (CLUTTER_TYPE_STAGE_EGL, NULL); stage = g_object_new (CLUTTER_TYPE_STAGE_COGL, NULL);
stage_egl = CLUTTER_STAGE_EGL (stage); stage_cogl = CLUTTER_STAGE_COGL (stage);
stage_egl->backend = backend_egl; stage_cogl->backend = backend_cogl;
stage_egl->wrapper = wrapper; stage_cogl->wrapper = wrapper;
backend_egl->stage = stage; backend_cogl->stage = stage;
#endif /* COGL_HAS_XLIB_SUPPORT */ #endif /* COGL_HAS_XLIB_SUPPORT */
@ -426,17 +428,23 @@ clutter_backend_egl_create_stage (ClutterBackend *backend,
} }
static void static void
clutter_backend_egl_ensure_context (ClutterBackend *backend, clutter_backend_cogl_ensure_context (ClutterBackend *backend,
ClutterStage *stage) ClutterStage *stage)
{ {
ClutterStageEGL *stage_egl = ClutterStageCogl *stage_cogl;
CLUTTER_STAGE_EGL (_clutter_stage_get_window (stage));
cogl_set_framebuffer (COGL_FRAMEBUFFER (stage_egl->onscreen)); /* ignore ensuring the context on an empty stage */
if (stage == NULL)
return;
stage_cogl =
CLUTTER_STAGE_COGL (_clutter_stage_get_window (stage));
cogl_set_framebuffer (COGL_FRAMEBUFFER (stage_cogl->onscreen));
} }
static void static void
_clutter_backend_egl_class_init (ClutterBackendEGLClass *klass) _clutter_backend_cogl_class_init (ClutterBackendCoglClass *klass)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass); ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
@ -444,40 +452,41 @@ _clutter_backend_egl_class_init (ClutterBackendEGLClass *klass)
ClutterBackendX11Class *backendx11_class = CLUTTER_BACKEND_X11_CLASS (klass); ClutterBackendX11Class *backendx11_class = CLUTTER_BACKEND_X11_CLASS (klass);
#endif #endif
gobject_class->constructor = clutter_backend_egl_constructor; gobject_class->constructor = clutter_backend_cogl_constructor;
gobject_class->dispose = clutter_backend_egl_dispose; gobject_class->dispose = clutter_backend_cogl_dispose;
gobject_class->finalize = clutter_backend_egl_finalize; gobject_class->finalize = clutter_backend_cogl_finalize;
backend_class->pre_parse = clutter_backend_egl_pre_parse; backend_class->pre_parse = clutter_backend_cogl_pre_parse;
backend_class->post_parse = clutter_backend_egl_post_parse; backend_class->post_parse = clutter_backend_cogl_post_parse;
backend_class->get_features = clutter_backend_egl_get_features; backend_class->get_features = clutter_backend_cogl_get_features;
#ifndef COGL_HAS_XLIB_SUPPORT #ifndef COGL_HAS_XLIB_SUPPORT
backend_class->get_device_manager = clutter_backend_egl_get_device_manager; backend_class->get_device_manager = clutter_backend_cogl_get_device_manager;
#endif #endif
backend_class->init_events = clutter_backend_egl_init_events; backend_class->init_events = clutter_backend_cogl_init_events;
backend_class->create_stage = clutter_backend_egl_create_stage; backend_class->create_stage = clutter_backend_cogl_create_stage;
backend_class->create_context = clutter_backend_egl_create_context; backend_class->create_context = clutter_backend_cogl_create_context;
backend_class->ensure_context = clutter_backend_egl_ensure_context; backend_class->ensure_context = clutter_backend_cogl_ensure_context;
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
backendx11_class->get_visual_info = clutter_backend_egl_get_visual_info; backendx11_class->get_visual_info = clutter_backend_cogl_get_visual_info;
#endif #endif
} }
static void static void
_clutter_backend_egl_init (ClutterBackendEGL *backend_egl) _clutter_backend_cogl_init (ClutterBackendCogl *backend_cogl)
{ {
#ifdef HAVE_TSLIB #ifdef HAVE_TSLIB
backend_egl->event_timer = g_timer_new (); backend_cogl->event_timer = g_timer_new ();
#endif #endif
} }
GType GType
_clutter_backend_impl_get_type (void) _clutter_backend_impl_get_type (void)
{ {
return _clutter_backend_egl_get_type (); return _clutter_backend_cogl_get_type ();
} }
#ifdef COGL_HAS_EGL_SUPPORT
EGLDisplay EGLDisplay
clutter_eglx_display (void) clutter_eglx_display (void)
{ {
@ -501,6 +510,7 @@ clutter_egl_get_egl_display (void)
return cogl_context_egl_get_egl_display (backend_singleton->cogl_context); return cogl_context_egl_get_egl_display (backend_singleton->cogl_context);
} }
#endif
/* FIXME we should have a CLUTTER_ define for this */ /* FIXME we should have a CLUTTER_ define for this */
#ifdef COGL_HAS_EGL_PLATFORM_GDL_SUPPORT #ifdef COGL_HAS_EGL_PLATFORM_GDL_SUPPORT

View File

@ -22,8 +22,8 @@
* Robert Bragg * Robert Bragg
*/ */
#ifndef __CLUTTER_BACKEND_EGL_H__ #ifndef __CLUTTER_BACKEND_COGL_H__
#define __CLUTTER_BACKEND_EGL_H__ #define __CLUTTER_BACKEND_COGL_H__
#include <glib-object.h> #include <glib-object.h>
#include <clutter/clutter-event.h> #include <clutter/clutter-event.h>
@ -37,8 +37,6 @@
#include "clutter-backend-private.h" #include "clutter-backend-private.h"
#include "clutter-egl-headers.h"
#ifdef COGL_HAS_X11_SUPPORT #ifdef COGL_HAS_X11_SUPPORT
#include "../x11/clutter-backend-x11.h" #include "../x11/clutter-backend-x11.h"
#endif #endif
@ -47,17 +45,17 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define CLUTTER_TYPE_BACKEND_EGL (_clutter_backend_egl_get_type ()) #define CLUTTER_TYPE_BACKEND_COGL (_clutter_backend_cogl_get_type ())
#define CLUTTER_BACKEND_EGL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BACKEND_EGL, ClutterBackendEGL)) #define CLUTTER_BACKEND_COGL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BACKEND_COGL, ClutterBackendCogl))
#define CLUTTER_IS_BACKEND_EGL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BACKEND_EGL)) #define CLUTTER_IS_BACKEND_COGL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BACKEND_COGL))
#define CLUTTER_BACKEND_EGL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND_EGL, ClutterBackendEGLClass)) #define CLUTTER_BACKEND_COGL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND_COGL, ClutterBackendCoglClass))
#define CLUTTER_IS_BACKEND_EGL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BACKEND_EGL)) #define CLUTTER_IS_BACKEND_COGL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BACKEND_COGL))
#define CLUTTER_BACKEND_EGL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BACKEND_EGL, ClutterBackendEGLClass)) #define CLUTTER_BACKEND_COGL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BACKEND_COGL, ClutterBackendCoglClass))
typedef struct _ClutterBackendEGL ClutterBackendEGL; typedef struct _ClutterBackendCogl ClutterBackendCogl;
typedef struct _ClutterBackendEGLClass ClutterBackendEGLClass; typedef struct _ClutterBackendCoglClass ClutterBackendCoglClass;
struct _ClutterBackendEGL struct _ClutterBackendCogl
{ {
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
ClutterBackendX11 parent_instance; ClutterBackendX11 parent_instance;
@ -84,7 +82,7 @@ struct _ClutterBackendEGL
gboolean can_blit_sub_buffer; gboolean can_blit_sub_buffer;
}; };
struct _ClutterBackendEGLClass struct _ClutterBackendCoglClass
{ {
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
ClutterBackendX11Class parent_class; ClutterBackendX11Class parent_class;
@ -93,13 +91,15 @@ struct _ClutterBackendEGLClass
#endif #endif
}; };
GType _clutter_backend_egl_get_type (void) G_GNUC_CONST; GType _clutter_backend_cogl_get_type (void) G_GNUC_CONST;
void _clutter_events_egl_init (ClutterBackendEGL *backend); #ifdef HAVE_TSLIB
void _clutter_events_egl_uninit (ClutterBackendEGL *backend); void _clutter_events_tslib_init (ClutterBackendCogl *backend);
void _clutter_events_tslib_uninit (ClutterBackendCogl *backend);
#endif
const gchar *_clutter_backend_egl_get_vblank (void); const gchar *_clutter_backend_egl_get_vblank (void);
G_END_DECLS G_END_DECLS
#endif /* __CLUTTER_BACKEND_EGL_H__ */ #endif /* __CLUTTER_BACKEND_COGL_H__ */

View File

@ -96,7 +96,7 @@ get_backend_time (void)
#endif #endif
void void
_clutter_events_egl_init (ClutterBackendEGL *backend_egl) _clutter_events_tslib_init (ClutterBackendEGL *backend_egl)
{ {
#ifdef HAVE_TSLIB #ifdef HAVE_TSLIB
ClutterEventSource *event_source; ClutterEventSource *event_source;

View File

@ -1,10 +1,37 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* 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
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
* Authors:
* Matthew Allum
* Robert Bragg
* Neil Roberts
* Emmanuele Bassi
*/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "clutter-stage-egl.h" #include "clutter-stage-cogl.h"
#include "clutter-egl.h" #include "clutter-backend-cogl.h"
#include "clutter-backend-egl.h"
#include "clutter-debug.h" #include "clutter-debug.h"
#include "clutter-event.h" #include "clutter-event.h"
@ -17,13 +44,13 @@
#include "clutter-util.h" #include "clutter-util.h"
#ifdef COGL_HAS_X11_SUPPORT #ifdef COGL_HAS_X11_SUPPORT
static ClutterStageWindowIface *clutter_stage_egl_parent_iface = NULL; static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL;
#endif #endif
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface); static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterStageEGL, G_DEFINE_TYPE_WITH_CODE (ClutterStageCogl,
_clutter_stage_egl, _clutter_stage_cogl,
#ifdef COGL_HAS_X11_SUPPORT #ifdef COGL_HAS_X11_SUPPORT
CLUTTER_TYPE_STAGE_X11, CLUTTER_TYPE_STAGE_X11,
#else #else
@ -33,30 +60,49 @@ G_DEFINE_TYPE_WITH_CODE (ClutterStageEGL,
clutter_stage_window_iface_init)); clutter_stage_window_iface_init));
static void static void
clutter_stage_egl_unrealize (ClutterStageWindow *stage_window) clutter_stage_cogl_unrealize (ClutterStageWindow *stage_window)
{ {
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
CLUTTER_NOTE (BACKEND, "Unrealizing EGL stage [%p]", stage_egl); CLUTTER_NOTE (BACKEND, "Unrealizing Cogl stage [%p]", stage_cogl);
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
/* chain up to the StageX11 implementation */ /* chain up to the StageX11 implementation */
clutter_stage_window_parent_iface->unrealize (stage_window); clutter_stage_window_parent_iface->unrealize (stage_window);
#endif #endif
cogl_object_unref (stage_egl->onscreen); cogl_object_unref (stage_cogl->onscreen);
stage_egl->onscreen = NULL; stage_cogl->onscreen = NULL;
}
static void
handle_swap_complete_cb (CoglFramebuffer *framebuffer,
void *user_data)
{
ClutterStageCogl *stage_cogl = user_data;
/* 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_cogl->pending_swaps > 0)
stage_cogl->pending_swaps--;
} }
static gboolean static gboolean
clutter_stage_egl_realize (ClutterStageWindow *stage_window) clutter_stage_cogl_realize (ClutterStageWindow *stage_window)
{ {
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
#endif #endif
ClutterBackend *backend; ClutterBackend *backend;
ClutterBackendEGL *backend_egl; ClutterBackendCogl *backend_cogl;
CoglFramebuffer *framebuffer; CoglFramebuffer *framebuffer;
GError *error = NULL; GError *error = NULL;
gfloat width = 800; gfloat width = 800;
@ -64,23 +110,23 @@ clutter_stage_egl_realize (ClutterStageWindow *stage_window)
const char *clutter_vblank; const char *clutter_vblank;
CLUTTER_NOTE (BACKEND, "Realizing stage '%s' [%p]", CLUTTER_NOTE (BACKEND, "Realizing stage '%s' [%p]",
G_OBJECT_TYPE_NAME (stage_egl), G_OBJECT_TYPE_NAME (stage_cogl),
stage_egl); stage_cogl);
backend = clutter_get_default_backend (); backend = clutter_get_default_backend ();
backend_egl = CLUTTER_BACKEND_EGL (backend); backend_cogl = CLUTTER_BACKEND_COGL (backend);
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
clutter_actor_get_size (CLUTTER_ACTOR (stage_x11->wrapper), &width, &height); clutter_actor_get_size (CLUTTER_ACTOR (stage_x11->wrapper), &width, &height);
#endif #endif
stage_egl->onscreen = cogl_onscreen_new (backend->cogl_context, stage_cogl->onscreen = cogl_onscreen_new (backend->cogl_context,
width, height); width, height);
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
if (stage_x11->xwin != None) if (stage_x11->xwin != None)
{ {
cogl_onscreen_x11_set_foreign_window_xid ( cogl_onscreen_x11_set_foreign_window_xid (
stage_egl->onscreen, stage_cogl->onscreen,
stage_x11->xwin, stage_x11->xwin,
_clutter_stage_x11_update_foreign_event_mask, _clutter_stage_x11_update_foreign_event_mask,
stage_x11); stage_x11);
@ -88,39 +134,55 @@ clutter_stage_egl_realize (ClutterStageWindow *stage_window)
} }
#endif #endif
clutter_vblank = _clutter_backend_egl_get_vblank (); clutter_vblank = _clutter_backend_cogl_get_vblank ();
if (clutter_vblank && strcmp (clutter_vblank, "none") == 0) if (clutter_vblank && strcmp (clutter_vblank, "none") == 0)
cogl_onscreen_set_swap_throttled (stage_egl->onscreen, FALSE); cogl_onscreen_set_swap_throttled (stage_cogl->onscreen, FALSE);
framebuffer = COGL_FRAMEBUFFER (stage_egl->onscreen); framebuffer = COGL_FRAMEBUFFER (stage_cogl->onscreen);
if (!cogl_framebuffer_allocate (framebuffer, &error)) if (!cogl_framebuffer_allocate (framebuffer, &error))
{ {
g_warning ("Failed to allocate stage: %s", error->message); g_warning ("Failed to allocate stage: %s", error->message);
g_error_free (error); g_error_free (error);
cogl_object_unref (stage_egl->onscreen); cogl_object_unref (stage_cogl->onscreen);
stage_egl->onscreen = NULL; stage_cogl->onscreen = NULL;
return FALSE; return FALSE;
} }
/* FIXME: for fullscreen EGL platforms then the size we gave above /* FIXME: for fullscreen Cogl platforms then the size we gave above
* will be ignored, so we need to make sure the stage size is * will be ignored, so we need to make sure the stage size is
* updated to this size. */ * updated to this size. */
if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
{
stage_cogl->swap_callback_id =
cogl_framebuffer_add_swap_buffers_callback (framebuffer,
handle_swap_complete_cb,
stage_cogl);
}
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
if (stage_x11->xwin == None) if (stage_x11->xwin == None)
stage_x11->xwin = cogl_onscreen_x11_get_window_xid (stage_egl->onscreen); stage_x11->xwin = cogl_onscreen_x11_get_window_xid (stage_cogl->onscreen);
return clutter_stage_egl_parent_iface->realize (stage_window); return clutter_stage_window_parent_iface->realize (stage_window);
#else #else
return TRUE; return TRUE;
#endif #endif
} }
static int
clutter_stage_cogl_get_pending_swaps (ClutterStageWindow *stage_window)
{
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
return stage_cogl->pending_swaps;
}
#ifndef COGL_HAS_XLIB_SUPPORT #ifndef COGL_HAS_XLIB_SUPPORT
/* FIXME: Move this warnings up into clutter-stage.c */ /* FIXME: Move this warnings up into clutter-stage.c */
static void static void
clutter_stage_egl_set_fullscreen (ClutterStageWindow *stage_window, clutter_stage_cogl_set_fullscreen (ClutterStageWindow *stage_window,
gboolean fullscreen) gboolean fullscreen)
{ {
g_warning ("Stage of type '%s' do not support ClutterStage::set_fullscreen", g_warning ("Stage of type '%s' do not support ClutterStage::set_fullscreen",
@ -128,7 +190,7 @@ clutter_stage_egl_set_fullscreen (ClutterStageWindow *stage_window,
} }
static void static void
clutter_stage_egl_set_title (ClutterStageWindow *stage_window, clutter_stage_cogl_set_title (ClutterStageWindow *stage_window,
const gchar *title) const gchar *title)
{ {
g_warning ("Stage of type '%s' do not support ClutterStage::set_title", g_warning ("Stage of type '%s' do not support ClutterStage::set_title",
@ -136,7 +198,7 @@ clutter_stage_egl_set_title (ClutterStageWindow *stage_window,
} }
static void static void
clutter_stage_egl_set_cursor_visible (ClutterStageWindow *stage_window, clutter_stage_cogl_set_cursor_visible (ClutterStageWindow *stage_window,
gboolean cursor_visible) gboolean cursor_visible)
{ {
g_warning ("Stage of type '%s' do not support ClutterStage::set_cursor_visible", g_warning ("Stage of type '%s' do not support ClutterStage::set_cursor_visible",
@ -144,40 +206,40 @@ clutter_stage_egl_set_cursor_visible (ClutterStageWindow *stage_window,
} }
static ClutterActor * static ClutterActor *
clutter_stage_egl_get_wrapper (ClutterStageWindow *stage_window) clutter_stage_cogl_get_wrapper (ClutterStageWindow *stage_window)
{ {
return CLUTTER_ACTOR (CLUTTER_STAGE_EGL (stage_window)->wrapper); return CLUTTER_ACTOR (CLUTTER_STAGE_COGL (stage_window)->wrapper);
} }
static void static void
clutter_stage_egl_show (ClutterStageWindow *stage_window, clutter_stage_cogl_show (ClutterStageWindow *stage_window,
gboolean do_raise) gboolean do_raise)
{ {
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
clutter_actor_map (CLUTTER_ACTOR (stage_egl->wrapper)); clutter_actor_map (CLUTTER_ACTOR (stage_cogl->wrapper));
} }
static void static void
clutter_stage_egl_hide (ClutterStageWindow *stage_window) clutter_stage_cogl_hide (ClutterStageWindow *stage_window)
{ {
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
clutter_actor_unmap (CLUTTER_ACTOR (stage_egl->wrapper)); clutter_actor_unmap (CLUTTER_ACTOR (stage_cogl->wrapper));
} }
static void static void
clutter_stage_egl_get_geometry (ClutterStageWindow *stage_window, clutter_stage_cogl_get_geometry (ClutterStageWindow *stage_window,
ClutterGeometry *geometry) ClutterGeometry *geometry)
{ {
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
if (geometry) if (geometry)
{ {
if (stage_egl->onscreen) if (stage_cogl->onscreen)
{ {
CoglFramebuffer *framebuffer = CoglFramebuffer *framebuffer =
COGL_FRAMEBUFFER (stage_egl->onscreen); COGL_FRAMEBUFFER (stage_cogl->onscreen);
geometry->x = geometry->y = 0; geometry->x = geometry->y = 0;
@ -194,7 +256,7 @@ clutter_stage_egl_get_geometry (ClutterStageWindow *stage_window,
} }
static void static void
clutter_stage_egl_resize (ClutterStageWindow *stage_window, clutter_stage_cogl_resize (ClutterStageWindow *stage_window,
gint width, gint width,
gint height) gint height)
{ {
@ -203,9 +265,9 @@ clutter_stage_egl_resize (ClutterStageWindow *stage_window,
#endif /* COGL_HAS_XLIB_SUPPORT */ #endif /* COGL_HAS_XLIB_SUPPORT */
static gboolean static gboolean
clutter_stage_egl_has_redraw_clips (ClutterStageWindow *stage_window) clutter_stage_cogl_has_redraw_clips (ClutterStageWindow *stage_window)
{ {
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
/* NB: at the start of each new frame there is an implied clip that /* NB: at the start of each new frame there is an implied clip that
* clips everything (i.e. nothing would be drawn) so we need to make * clips everything (i.e. nothing would be drawn) so we need to make
@ -214,22 +276,22 @@ clutter_stage_egl_has_redraw_clips (ClutterStageWindow *stage_window)
* NB: a clip width of 0 means a full stage redraw has been queued * NB: a clip width of 0 means a full stage redraw has been queued
* so we effectively don't have any redraw clips in that case. * so we effectively don't have any redraw clips in that case.
*/ */
if (!stage_egl->initialized_redraw_clip || if (!stage_cogl->initialized_redraw_clip ||
(stage_egl->initialized_redraw_clip && (stage_cogl->initialized_redraw_clip &&
stage_egl->bounding_redraw_clip.width != 0)) stage_cogl->bounding_redraw_clip.width != 0))
return TRUE; return TRUE;
else else
return FALSE; return FALSE;
} }
static gboolean static gboolean
clutter_stage_egl_ignoring_redraw_clips (ClutterStageWindow *stage_window) clutter_stage_cogl_ignoring_redraw_clips (ClutterStageWindow *stage_window)
{ {
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
/* NB: a clip width of 0 means a full stage redraw is required */ /* NB: a clip width of 0 means a full stage redraw is required */
if (stage_egl->initialized_redraw_clip && if (stage_cogl->initialized_redraw_clip &&
stage_egl->bounding_redraw_clip.width == 0) stage_cogl->bounding_redraw_clip.width == 0)
return TRUE; return TRUE;
else else
return FALSE; return FALSE;
@ -238,7 +300,7 @@ clutter_stage_egl_ignoring_redraw_clips (ClutterStageWindow *stage_window)
/* A redraw clip represents (in stage coordinates) the bounding box of /* A redraw clip represents (in stage coordinates) the bounding box of
* something that needs to be redraw. Typically they are added to the * something that needs to be redraw. Typically they are added to the
* StageWindow as a result of clutter_actor_queue_clipped_redraw() by * StageWindow as a result of clutter_actor_queue_clipped_redraw() by
* actors such as ClutterEGLTexturePixmap. All redraw clips are * actors such as ClutterGLXTexturePixmap. All redraw clips are
* discarded after the next paint. * discarded after the next paint.
* *
* A NULL stage_clip means the whole stage needs to be redrawn. * A NULL stage_clip means the whole stage needs to be redrawn.
@ -250,22 +312,22 @@ clutter_stage_egl_ignoring_redraw_clips (ClutterStageWindow *stage_window)
* buffer. * buffer.
*/ */
static void static void
clutter_stage_egl_add_redraw_clip (ClutterStageWindow *stage_window, clutter_stage_cogl_add_redraw_clip (ClutterStageWindow *stage_window,
ClutterGeometry *stage_clip) ClutterGeometry *stage_clip)
{ {
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
/* If we are already forced to do a full stage redraw then bail early */ /* If we are already forced to do a full stage redraw then bail early */
if (clutter_stage_egl_ignoring_redraw_clips (stage_window)) if (clutter_stage_cogl_ignoring_redraw_clips (stage_window))
return; return;
/* A NULL stage clip means a full stage redraw has been queued and /* A NULL stage clip means a full stage redraw has been queued and
* we keep track of this by setting a zero width * we keep track of this by setting a zero width
* stage_egl->bounding_redraw_clip */ * stage_cogl->bounding_redraw_clip */
if (stage_clip == NULL) if (stage_clip == NULL)
{ {
stage_egl->bounding_redraw_clip.width = 0; stage_cogl->bounding_redraw_clip.width = 0;
stage_egl->initialized_redraw_clip = TRUE; stage_cogl->initialized_redraw_clip = TRUE;
return; return;
} }
@ -273,30 +335,30 @@ clutter_stage_egl_add_redraw_clip (ClutterStageWindow *stage_window,
if (stage_clip->width == 0 || stage_clip->height == 0) if (stage_clip->width == 0 || stage_clip->height == 0)
return; return;
if (!stage_egl->initialized_redraw_clip) if (!stage_cogl->initialized_redraw_clip)
{ {
stage_egl->bounding_redraw_clip.x = stage_clip->x; stage_cogl->bounding_redraw_clip.x = stage_clip->x;
stage_egl->bounding_redraw_clip.y = stage_clip->y; stage_cogl->bounding_redraw_clip.y = stage_clip->y;
stage_egl->bounding_redraw_clip.width = stage_clip->width; stage_cogl->bounding_redraw_clip.width = stage_clip->width;
stage_egl->bounding_redraw_clip.height = stage_clip->height; stage_cogl->bounding_redraw_clip.height = stage_clip->height;
} }
else if (stage_egl->bounding_redraw_clip.width > 0) else if (stage_cogl->bounding_redraw_clip.width > 0)
{ {
clutter_geometry_union (&stage_egl->bounding_redraw_clip, stage_clip, clutter_geometry_union (&stage_cogl->bounding_redraw_clip, stage_clip,
&stage_egl->bounding_redraw_clip); &stage_cogl->bounding_redraw_clip);
} }
stage_egl->initialized_redraw_clip = TRUE; stage_cogl->initialized_redraw_clip = TRUE;
} }
/* XXX: This is basically identical to clutter_stage_glx_redraw */ /* XXX: This is basically identical to clutter_stage_glx_redraw */
static void static void
clutter_stage_egl_redraw (ClutterStageWindow *stage_window) clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
{ {
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
ClutterActor *wrapper; ClutterActor *wrapper;
ClutterBackend *backend; ClutterBackend *backend;
ClutterBackendEGL *backend_egl; ClutterBackendCogl *backend_cogl;
gboolean may_use_clipped_redraw; gboolean may_use_clipped_redraw;
gboolean use_clipped_redraw; gboolean use_clipped_redraw;
@ -317,27 +379,27 @@ clutter_stage_egl_redraw (ClutterStageWindow *stage_window)
0 /* no application private data */); 0 /* no application private data */);
#ifdef COGL_HAS_X11_SUPPORT #ifdef COGL_HAS_X11_SUPPORT
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_egl); ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_cogl);
wrapper = CLUTTER_ACTOR (stage_x11->wrapper); wrapper = CLUTTER_ACTOR (stage_x11->wrapper);
#else #else
wrapper = CLUTTER_ACTOR (stage_egl->wrapper); wrapper = CLUTTER_ACTOR (stage_cogl->wrapper);
#endif #endif
if (!stage_egl->onscreen) if (!stage_cogl->onscreen)
return; return;
backend = clutter_get_default_backend (); backend = clutter_get_default_backend ();
backend_egl = CLUTTER_BACKEND_EGL (backend); backend_cogl = CLUTTER_BACKEND_COGL (backend);
CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer); CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer);
if (G_LIKELY (backend_egl->can_blit_sub_buffer) && if (G_LIKELY (backend_cogl->can_blit_sub_buffer) &&
/* NB: a zero width redraw clip == full stage redraw */ /* NB: a zero width redraw clip == full stage redraw */
stage_egl->bounding_redraw_clip.width != 0 && stage_cogl->bounding_redraw_clip.width != 0 &&
/* some drivers struggle to get going and produce some junk /* some drivers struggle to get going and produce some junk
* frames when starting up... */ * frames when starting up... */
G_LIKELY (stage_egl->frame_count > 3) G_LIKELY (stage_cogl->frame_count > 3)
#ifdef COGL_HAS_X11_SUPPORT #ifdef COGL_HAS_X11_SUPPORT
/* While resizing a window clipped redraws are disabled to avoid /* While resizing a window clipped redraws are disabled to avoid
* artefacts. See clutter-event-x11.c:event_translate for a * artefacts. See clutter-event-x11.c:event_translate for a
@ -360,22 +422,42 @@ clutter_stage_egl_redraw (ClutterStageWindow *stage_window)
if (use_clipped_redraw) if (use_clipped_redraw)
{ {
cogl_clip_push_window_rectangle (stage_egl->bounding_redraw_clip.x, CLUTTER_NOTE (CLIPPING,
stage_egl->bounding_redraw_clip.y, "Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n",
stage_egl->bounding_redraw_clip.width, stage_cogl->bounding_redraw_clip.x,
stage_egl->bounding_redraw_clip.height); stage_cogl->bounding_redraw_clip.y,
stage_cogl->bounding_redraw_clip.width,
stage_cogl->bounding_redraw_clip.height);
cogl_clip_push_window_rectangle (stage_cogl->bounding_redraw_clip.x,
stage_cogl->bounding_redraw_clip.y,
stage_cogl->bounding_redraw_clip.width,
stage_cogl->bounding_redraw_clip.height);
_clutter_stage_do_paint (CLUTTER_STAGE (wrapper), _clutter_stage_do_paint (CLUTTER_STAGE (wrapper),
&stage_egl->bounding_redraw_clip); &stage_cogl->bounding_redraw_clip);
cogl_clip_pop (); cogl_clip_pop ();
} }
else else
_clutter_stage_do_paint (CLUTTER_STAGE (wrapper), NULL); {
CLUTTER_NOTE (CLIPPING, "Unclipped stage paint\n");
/* If we are trying to debug redraw issues then we want to pass
* the bounding_redraw_clip so it can be visualized */
if (G_UNLIKELY (clutter_paint_debug_flags &
CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS) &&
may_use_clipped_redraw)
{
_clutter_stage_do_paint (CLUTTER_STAGE (wrapper),
&stage_cogl->bounding_redraw_clip);
}
else
_clutter_stage_do_paint (CLUTTER_STAGE (wrapper), NULL);
}
if (may_use_clipped_redraw && if (may_use_clipped_redraw &&
G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))) G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS)))
{ {
static CoglMaterial *outline = NULL; static CoglMaterial *outline = NULL;
ClutterGeometry *clip = &stage_egl->bounding_redraw_clip; ClutterGeometry *clip = &stage_cogl->bounding_redraw_clip;
ClutterActor *actor = CLUTTER_ACTOR (wrapper); ClutterActor *actor = CLUTTER_ACTOR (wrapper);
CoglHandle vbo; CoglHandle vbo;
float x_1 = clip->x; float x_1 = clip->x;
@ -422,7 +504,7 @@ clutter_stage_egl_redraw (ClutterStageWindow *stage_window)
/* push on the screen */ /* push on the screen */
if (use_clipped_redraw) if (use_clipped_redraw)
{ {
ClutterGeometry *clip = &stage_egl->bounding_redraw_clip; ClutterGeometry *clip = &stage_cogl->bounding_redraw_clip;
int copy_area[4]; int copy_area[4];
ClutterActor *actor; ClutterActor *actor;
@ -445,13 +527,13 @@ clutter_stage_egl_redraw (ClutterStageWindow *stage_window)
"cogl_framebuffer_swap_region (onscreen: %p, " "cogl_framebuffer_swap_region (onscreen: %p, "
"x: %d, y: %d, " "x: %d, y: %d, "
"width: %d, height: %d)", "width: %d, height: %d)",
stage_egl->onscreen, stage_cogl->onscreen,
copy_area[0], copy_area[1], copy_area[2], copy_area[3]); copy_area[0], copy_area[1], copy_area[2], copy_area[3]);
CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer); CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer);
cogl_framebuffer_swap_region (COGL_FRAMEBUFFER (stage_egl->onscreen), cogl_framebuffer_swap_region (COGL_FRAMEBUFFER (stage_cogl->onscreen),
copy_area, 1); copy_area, 1);
CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer); CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer);
@ -459,73 +541,89 @@ clutter_stage_egl_redraw (ClutterStageWindow *stage_window)
else else
{ {
CLUTTER_NOTE (BACKEND, "cogl_framebuffer_swap_buffers (onscreen: %p)", CLUTTER_NOTE (BACKEND, "cogl_framebuffer_swap_buffers (onscreen: %p)",
stage_egl->onscreen); stage_cogl->onscreen);
/* 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_cogl->pending_swaps++;
CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer); CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer);
cogl_framebuffer_swap_buffers (COGL_FRAMEBUFFER (stage_egl->onscreen)); cogl_framebuffer_swap_buffers (COGL_FRAMEBUFFER (stage_cogl->onscreen));
CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer); CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer);
} }
/* reset the redraw clipping for the next paint... */ /* reset the redraw clipping for the next paint... */
stage_egl->initialized_redraw_clip = FALSE; stage_cogl->initialized_redraw_clip = FALSE;
stage_egl->frame_count++; stage_cogl->frame_count++;
}
static CoglFramebuffer *
clutter_stage_cogl_get_active_framebuffer (ClutterStageWindow *stage_window)
{
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
return COGL_FRAMEBUFFER (stage_cogl->onscreen);
} }
static void static void
clutter_stage_window_iface_init (ClutterStageWindowIface *iface) clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
{ {
#ifdef COGL_HAS_X11_SUPPORT #ifdef COGL_HAS_X11_SUPPORT
clutter_stage_egl_parent_iface = g_type_interface_peek_parent (iface); clutter_stage_window_parent_iface = g_type_interface_peek_parent (iface);
iface->realize = clutter_stage_egl_realize; iface->realize = clutter_stage_cogl_realize;
iface->unrealize = clutter_stage_egl_unrealize; iface->unrealize = clutter_stage_cogl_unrealize;
/* the rest is inherited from ClutterStageX11 */ /* the rest is inherited from ClutterStageX11 */
#else /* COGL_HAS_X11_SUPPORT */ #else /* COGL_HAS_X11_SUPPORT */
iface->realize = clutter_stage_egl_realize; iface->realize = clutter_stage_cogl_realize;
iface->unrealize = clutter_stage_egl_unrealize; iface->unrealize = clutter_stage_cogl_unrealize;
iface->set_fullscreen = clutter_stage_egl_set_fullscreen; iface->set_fullscreen = clutter_stage_cogl_set_fullscreen;
iface->set_title = clutter_stage_egl_set_title; iface->set_title = clutter_stage_cogl_set_title;
iface->set_cursor_visible = clutter_stage_egl_set_cursor_visible; iface->set_cursor_visible = clutter_stage_cogl_set_cursor_visible;
iface->get_wrapper = clutter_stage_egl_get_wrapper; iface->get_wrapper = clutter_stage_cogl_get_wrapper;
iface->get_geometry = clutter_stage_egl_get_geometry; iface->get_geometry = clutter_stage_cogl_get_geometry;
iface->resize = clutter_stage_egl_resize; iface->resize = clutter_stage_cogl_resize;
iface->show = clutter_stage_egl_show; iface->show = clutter_stage_cogl_show;
iface->hide = clutter_stage_egl_hide; iface->hide = clutter_stage_cogl_hide;
#endif /* COGL_HAS_X11_SUPPORT */ #endif /* COGL_HAS_X11_SUPPORT */
iface->add_redraw_clip = clutter_stage_egl_add_redraw_clip; iface->get_pending_swaps = clutter_stage_cogl_get_pending_swaps;
iface->has_redraw_clips = clutter_stage_egl_has_redraw_clips; iface->add_redraw_clip = clutter_stage_cogl_add_redraw_clip;
iface->ignoring_redraw_clips = clutter_stage_egl_ignoring_redraw_clips; iface->has_redraw_clips = clutter_stage_cogl_has_redraw_clips;
iface->redraw = clutter_stage_egl_redraw; iface->ignoring_redraw_clips = clutter_stage_cogl_ignoring_redraw_clips;
iface->redraw = clutter_stage_cogl_redraw;
iface->get_active_framebuffer = clutter_stage_cogl_get_active_framebuffer;
} }
#ifdef COGL_HAS_X11_SUPPORT #ifdef COGL_HAS_X11_SUPPORT
static void static void
clutter_stage_egl_dispose (GObject *gobject) clutter_stage_cogl_dispose (GObject *gobject)
{ {
G_OBJECT_CLASS (_clutter_stage_egl_parent_class)->dispose (gobject); G_OBJECT_CLASS (_clutter_stage_cogl_parent_class)->dispose (gobject);
} }
static void static void
_clutter_stage_egl_class_init (ClutterStageEGLClass *klass) _clutter_stage_cogl_class_init (ClutterStageCoglClass *klass)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = clutter_stage_egl_dispose; gobject_class->dispose = clutter_stage_cogl_dispose;
} }
#else #else
static void static void
_clutter_stage_egl_class_init (ClutterStageEGLClass *klass) _clutter_stage_cogl_class_init (ClutterStageCoglClass *klass)
{ {
} }
#endif /* COGL_HAS_X11_SUPPORT */ #endif /* COGL_HAS_X11_SUPPORT */
static void static void
_clutter_stage_egl_init (ClutterStageEGL *stage) _clutter_stage_cogl_init (ClutterStageCogl *stage)
{ {
} }

View File

@ -0,0 +1,78 @@
#ifndef __CLUTTER_STAGE_COGL_H__
#define __CLUTTER_STAGE_COGL_H__
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib-object.h>
#include <clutter/clutter-stage.h>
#ifdef COGL_HAS_X11_SUPPORT
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include "../x11/clutter-stage-x11.h"
#endif
#include "clutter-backend-cogl.h"
G_BEGIN_DECLS
#define CLUTTER_TYPE_STAGE_COGL (_clutter_stage_cogl_get_type ())
#define CLUTTER_STAGE_COGL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_COGL, ClutterStageCogl))
#define CLUTTER_IS_STAGE_COGL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_COGL))
#define CLUTTER_STAGE_COGL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STAGE_COGL, ClutterStageCoglClass))
#define CLUTTER_IS_STAGE_COGL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STAGE_COGL))
#define CLUTTER_STAGE_COGL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STAGE_COGL, ClutterStageCoglClass))
typedef struct _ClutterStageCogl ClutterStageCogl;
typedef struct _ClutterStageCoglClass ClutterStageCoglClass;
struct _ClutterStageCogl
{
#ifdef COGL_HAS_X11_SUPPORT
ClutterStageX11 parent_instance;
#else
GObject parent_instance;
/* the stage wrapper */
ClutterStage *wrapper;
/* back pointer to the backend */
ClutterBackendCogl *backend;
#endif
CoglOnscreen *onscreen;
gint pending_swaps;
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
* junk frames to start with. */
unsigned long frame_count;
ClutterGeometry bounding_redraw_clip;
guint initialized_redraw_clip : 1;
};
struct _ClutterStageCoglClass
{
#ifdef COGL_HAS_X11_SUPPORT
ClutterStageX11Class parent_class;
#else
GObjectClass parent_class;
#endif
};
GType _clutter_stage_cogl_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __CLUTTER_STAGE_COGL_H__ */

View File

@ -1,46 +0,0 @@
/* Clutter.
* An OpenGL based 'interactive canvas' library.
* Authored By Matthew Allum <mallum@openedhand.com>
* Copyright (C) 2006-2007 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#ifndef __CLUTTER_EGL_HEADERS_H__
#define __CLUTTER_EGL_HEADERS_H__
#include <cogl/cogl.h>
#if defined(COGL_HAS_GLES1)
#include <GLES/gl.h>
#include <GLES/egl.h>
#else
#include <EGL/egl.h>
#define NativeDisplayType EGLNativeDisplayType
#define NativeWindowType EGLNativeWindowType
#if defined(COGL_HAS_GLES2)
#include <GLES2/gl2.h>
#elif defined(COGL_HAS_GL)
#include <GL/gl.h>
#else
#error Unknown Cogl backend
#endif
#endif /* !COGL_HAS_GLES1 */
#endif /* __CLUTTER_EGL_HEADERS_H__ */

View File

@ -1,75 +0,0 @@
#ifndef __CLUTTER_STAGE_EGL_H__
#define __CLUTTER_STAGE_EGL_H__
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib-object.h>
#include <clutter/clutter-stage.h>
#ifdef COGL_HAS_X11_SUPPORT
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include "../x11/clutter-stage-x11.h"
#endif
#include "clutter-egl-headers.h"
#include "clutter-backend-egl.h"
G_BEGIN_DECLS
#define CLUTTER_TYPE_STAGE_EGL (_clutter_stage_egl_get_type ())
#define CLUTTER_STAGE_EGL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_EGL, ClutterStageEGL))
#define CLUTTER_IS_STAGE_EGL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_EGL))
#define CLUTTER_STAGE_EGL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STAGE_EGL, ClutterStageEGLClass))
#define CLUTTER_IS_STAGE_EGL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STAGE_EGL))
#define CLUTTER_STAGE_EGL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STAGE_EGL, ClutterStageEGLClass))
typedef struct _ClutterStageEGL ClutterStageEGL;
typedef struct _ClutterStageEGLClass ClutterStageEGLClass;
struct _ClutterStageEGL
{
#ifdef COGL_HAS_X11_SUPPORT
ClutterStageX11 parent_instance;
#else
GObject parent_instance;
/* the stage wrapper */
ClutterStage *wrapper;
/* back pointer to the backend */
ClutterBackendEGL *backend;
#endif
CoglOnscreen *onscreen;
/* 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
* junk frames to start with. */
unsigned long frame_count;
gboolean initialized_redraw_clip;
ClutterGeometry bounding_redraw_clip;
};
struct _ClutterStageEGLClass
{
#ifdef COGL_HAS_X11_SUPPORT
ClutterStageX11Class parent_class;
#else
GObjectClass parent_class;
#endif
};
GType _clutter_stage_egl_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __CLUTTER_STAGE_EGL_H__ */

View File

@ -1,380 +0,0 @@
/* Clutter.
* An OpenGL based 'interactive canvas' library.
* Authored By Matthew Allum <mallum@openedhand.com>
* Copyright (C) 2006-2007 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <glib/gi18n-lib.h>
#include <GL/glx.h>
#include <GL/glxext.h>
#include <GL/gl.h>
#include "clutter-backend-glx.h"
#include "clutter-stage-glx.h"
#include "clutter-glx.h"
#include "clutter-profile.h"
#include "clutter-debug.h"
#include "clutter-event-translator.h"
#include "clutter-event.h"
#include "clutter-main.h"
#include "clutter-private.h"
#include "clutter-stage-private.h"
#include <cogl/cogl.h>
#define clutter_backend_glx_get_type _clutter_backend_glx_get_type
G_DEFINE_TYPE (ClutterBackendGLX, clutter_backend_glx, CLUTTER_TYPE_BACKEND_X11);
/* singleton object */
static ClutterBackendGLX *backend_singleton = NULL;
static gchar *clutter_vblank = NULL;
const gchar *
_clutter_backend_glx_get_vblank (void)
{
if (clutter_vblank && strcmp (clutter_vblank, "0") == 0)
return "none";
else
return clutter_vblank;
}
static gboolean
clutter_backend_glx_pre_parse (ClutterBackend *backend,
GError **error)
{
ClutterBackendClass *parent_class =
CLUTTER_BACKEND_CLASS (clutter_backend_glx_parent_class);
const gchar *env_string;
env_string = g_getenv ("CLUTTER_VBLANK");
if (env_string)
{
clutter_vblank = g_strdup (env_string);
env_string = NULL;
}
return parent_class->pre_parse (backend, error);
}
static gboolean
clutter_backend_glx_post_parse (ClutterBackend *backend,
GError **error)
{
ClutterBackendClass *parent_class =
CLUTTER_BACKEND_CLASS (clutter_backend_glx_parent_class);
if (!parent_class->post_parse (backend, error))
return FALSE;
return TRUE;
}
static const GOptionEntry entries[] =
{
{ "vblank", 0,
0,
G_OPTION_ARG_STRING, &clutter_vblank,
N_("Set to 'none' or '0' to disable throttling "
"framerate to vblank"), "OPTION"
},
{ NULL }
};
static void
clutter_backend_glx_add_options (ClutterBackend *backend,
GOptionGroup *group)
{
ClutterBackendClass *parent_class =
CLUTTER_BACKEND_CLASS (clutter_backend_glx_parent_class);
g_option_group_add_entries (group, entries);
parent_class->add_options (backend, group);
}
static void
clutter_backend_glx_finalize (GObject *gobject)
{
if (backend_singleton)
backend_singleton = NULL;
G_OBJECT_CLASS (clutter_backend_glx_parent_class)->finalize (gobject);
}
static void
clutter_backend_glx_dispose (GObject *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 ();
/* 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);
if (backend->cogl_context)
{
cogl_object_unref (backend->cogl_context);
backend->cogl_context = NULL;
}
}
static GObject *
clutter_backend_glx_constructor (GType gtype,
guint n_params,
GObjectConstructParam *params)
{
GObjectClass *parent_class;
GObject *retval;
if (!backend_singleton)
{
parent_class = G_OBJECT_CLASS (clutter_backend_glx_parent_class);
retval = parent_class->constructor (gtype, n_params, params);
backend_singleton = CLUTTER_BACKEND_GLX (retval);
return retval;
}
g_warning ("Attempting to create a new backend object. This should "
"never happen, so we return the singleton instance.");
return g_object_ref (backend_singleton);
}
static ClutterFeatureFlags
clutter_backend_glx_get_features (ClutterBackend *backend)
{
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
ClutterBackendClass *parent_class;
ClutterFeatureFlags flags;
parent_class = CLUTTER_BACKEND_CLASS (clutter_backend_glx_parent_class);
flags = parent_class->get_features (backend);
if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN))
{
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;
}
if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_THROTTLE))
{
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");
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;
}
if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION))
{
CLUTTER_NOTE (BACKEND, "Cogl supports swapping buffer regions");
backend_glx->can_blit_sub_buffer = TRUE;
}
CLUTTER_NOTE (BACKEND, "backend features checked");
return flags;
}
static XVisualInfo *
clutter_backend_glx_get_visual_info (ClutterBackendX11 *backend_x11)
{
return cogl_clutter_winsys_xlib_get_visual_info ();
}
static gboolean
clutter_backend_glx_create_context (ClutterBackend *backend,
GError **error)
{
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
CoglSwapChain *swap_chain = NULL;
CoglOnscreenTemplate *onscreen_template = NULL;
if (backend->cogl_context)
return TRUE;
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;
swap_chain = cogl_swap_chain_new ();
cogl_swap_chain_set_has_alpha (swap_chain,
clutter_x11_get_use_argb_visual ());
onscreen_template = cogl_onscreen_template_new (swap_chain);
cogl_object_unref (swap_chain);
if (!cogl_renderer_check_onscreen_template (backend->cogl_renderer,
onscreen_template,
error))
goto error;
backend->cogl_display = cogl_display_new (backend->cogl_renderer,
onscreen_template);
cogl_object_unref (backend->cogl_renderer);
cogl_object_unref (onscreen_template);
if (!cogl_display_setup (backend->cogl_display, error))
goto error;
backend->cogl_context = cogl_context_new (backend->cogl_display, error);
if (!backend->cogl_context)
goto error;
/* 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;
error:
if (backend->cogl_display)
{
cogl_object_unref (backend->cogl_display);
backend->cogl_display = NULL;
}
if (onscreen_template)
cogl_object_unref (onscreen_template);
if (swap_chain)
cogl_object_unref (swap_chain);
if (backend->cogl_renderer)
{
cogl_object_unref (backend->cogl_renderer);
backend->cogl_renderer = NULL;
}
return FALSE;
}
static ClutterStageWindow *
clutter_backend_glx_create_stage (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error)
{
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterEventTranslator *translator;
ClutterStageWindow *stage_window;
ClutterStageX11 *stage_x11;
stage_window = g_object_new (CLUTTER_TYPE_STAGE_GLX, NULL);
/* copy backend data into the stage */
stage_x11 = CLUTTER_STAGE_X11 (stage_window);
stage_x11->wrapper = wrapper;
stage_x11->backend = backend_x11;
translator = CLUTTER_EVENT_TRANSLATOR (stage_x11);
_clutter_backend_add_event_translator (backend, translator);
CLUTTER_NOTE (BACKEND,
"GLX stage created[%p] (dpy:%p, screen:%d, root:%u, wrap:%p)",
stage_window,
backend_x11->xdpy,
backend_x11->xscreen_num,
(unsigned int) backend_x11->xwin_root,
wrapper);
return stage_window;
}
static void
clutter_backend_glx_ensure_context (ClutterBackend *backend,
ClutterStage *stage)
{
ClutterStageGLX *stage_glx;
/* ignore ensuring the context on an empty stage */
if (stage == NULL)
return;
stage_glx =
CLUTTER_STAGE_GLX (_clutter_stage_get_window (stage));
cogl_set_framebuffer (COGL_FRAMEBUFFER (stage_glx->onscreen));
}
static void
clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
ClutterBackendX11Class *backendx11_class = CLUTTER_BACKEND_X11_CLASS (klass);
gobject_class->constructor = clutter_backend_glx_constructor;
gobject_class->dispose = clutter_backend_glx_dispose;
gobject_class->finalize = clutter_backend_glx_finalize;
backend_class->pre_parse = clutter_backend_glx_pre_parse;
backend_class->post_parse = clutter_backend_glx_post_parse;
backend_class->create_stage = clutter_backend_glx_create_stage;
backend_class->add_options = clutter_backend_glx_add_options;
backend_class->get_features = clutter_backend_glx_get_features;
backend_class->create_context = clutter_backend_glx_create_context;
backend_class->ensure_context = clutter_backend_glx_ensure_context;
backendx11_class->get_visual_info = clutter_backend_glx_get_visual_info;
}
static void
clutter_backend_glx_init (ClutterBackendGLX *backend_glx)
{
}
/* every backend must implement this function */
GType
_clutter_backend_impl_get_type (void)
{
return _clutter_backend_glx_get_type ();
}

View File

@ -1,75 +0,0 @@
/* Clutter.
* An OpenGL based 'interactive canvas' library.
* Authored By Matthew Allum <mallum@openedhand.com>
* Copyright (C) 2006-2007 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#ifndef __CLUTTER_BACKEND_GLX_H__
#define __CLUTTER_BACKEND_GLX_H__
#include <glib-object.h>
#include <clutter/clutter-event.h>
#include <clutter/clutter-backend.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <GL/glx.h>
#include <GL/gl.h>
#include "../x11/clutter-backend-x11.h"
#include "clutter-glx.h"
G_BEGIN_DECLS
#define CLUTTER_TYPE_BACKEND_GLX (_clutter_backend_glx_get_type ())
#define CLUTTER_BACKEND_GLX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BACKEND_GLX, ClutterBackendGLX))
#define CLUTTER_IS_BACKEND_GLX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BACKEND_GLX))
#define CLUTTER_BACKEND_GLX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND_GLX, ClutterBackendGLXClass))
#define CLUTTER_IS_BACKEND_GLX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BACKEND_GLX))
#define CLUTTER_BACKEND_GLX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BACKEND_GLX, ClutterBackendGLXClass))
typedef struct _ClutterBackendGLX ClutterBackendGLX;
typedef struct _ClutterBackendGLXClass ClutterBackendGLXClass;
typedef enum ClutterGLXVBlankType {
CLUTTER_VBLANK_NONE = 0,
CLUTTER_VBLANK_AUTOMATIC_THROTTLE,
CLUTTER_VBLANK_VBLANK_COUNTER,
CLUTTER_VBLANK_MANUAL_WAIT
} ClutterGLXVBlankType;
struct _ClutterBackendGLX
{
ClutterBackendX11 parent_instance;
CoglContext *cogl_context;
gboolean can_blit_sub_buffer;
};
struct _ClutterBackendGLXClass
{
ClutterBackendX11Class parent_class;
};
GType _clutter_backend_glx_get_type (void) G_GNUC_CONST;
const gchar *_clutter_backend_glx_get_vblank (void);
G_END_DECLS
#endif /* __CLUTTER_BACKEND_GLX_H__ */

View File

@ -1,46 +0,0 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
/**
* SECTION:clutter-glx
* @short_description: GLX specific API
*
* The GLX backend for Clutter provides some specific API for GLX
* related calls.
*
* The ClutterGLX API is available since Clutter 0.4
*/
#ifndef __CLUTTER_GLX_H__
#define __CLUTTER_GLX_H__
#include <glib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <clutter/clutter.h>
#include <clutter/glx/clutter-glx-texture-pixmap.h>
#endif /* __CLUTTER_GLX_H__ */

View File

@ -1,541 +0,0 @@
/* Clutter.
* An OpenGL based 'interactive canvas' library.
* Authored By Matthew Allum <mallum@openedhand.com>
* Copyright (C) 2006-2007 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "clutter-backend-glx.h"
#include "clutter-stage-glx.h"
#include "clutter-glx.h"
#include "clutter-profile.h"
#include "clutter-actor-private.h"
#include "clutter-debug.h"
#include "clutter-device-manager.h"
#include "clutter-event.h"
#include "clutter-enum-types.h"
#include "clutter-feature.h"
#include "clutter-main.h"
#include "clutter-private.h"
#include "clutter-stage-private.h"
#include "cogl/cogl.h"
#include <GL/glx.h>
#include <GL/gl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#ifdef HAVE_DRM
#include <drm.h>
#endif
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL;
#define clutter_stage_glx_get_type _clutter_stage_glx_get_type
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));
static void
clutter_stage_glx_unrealize (ClutterStageWindow *stage_window)
{
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
/* Note unrealize should free up any backend stage related resources */
CLUTTER_NOTE (BACKEND, "Unrealizing GLX stage [%p]", stage_glx);
/* chain up to the StageX11 implementation */
clutter_stage_window_parent_iface->unrealize (stage_window);
cogl_object_unref (stage_glx->onscreen);
stage_glx->onscreen = NULL;
}
static void
handle_swap_complete_cb (CoglFramebuffer *framebuffer,
void *user_data)
{
ClutterStageGLX *stage_glx = user_data;
/* 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
clutter_stage_glx_realize (ClutterStageWindow *stage_window)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
ClutterBackend *backend;
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);
backend = CLUTTER_BACKEND (stage_x11->backend);
clutter_actor_get_size (CLUTTER_ACTOR (stage_x11->wrapper), &width, &height);
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_stage_x11_update_foreign_event_mask,
stage_x11);
}
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))
{
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;
}
if (stage_x11->xwin == None)
stage_x11->xwin = cogl_onscreen_x11_get_window_xid (stage_glx->onscreen);
if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
{
stage_glx->swap_callback_id =
cogl_framebuffer_add_swap_buffers_callback (framebuffer,
handle_swap_complete_cb,
stage_glx);
}
/* chain up to the StageX11 implementation */
return clutter_stage_window_parent_iface->realize (stage_window);
}
static int
clutter_stage_glx_get_pending_swaps (ClutterStageWindow *stage_window)
{
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
return stage_glx->pending_swaps;
}
static void
clutter_stage_glx_class_init (ClutterStageGLXClass *klass)
{
}
static void
clutter_stage_glx_init (ClutterStageGLX *stage)
{
}
static gboolean
clutter_stage_glx_has_redraw_clips (ClutterStageWindow *stage_window)
{
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
/* NB: at the start of each new frame there is an implied clip that
* clips everything (i.e. nothing would be drawn) so we need to make
* sure we return True in the un-initialized case here.
*
* NB: a clip width of 0 means a full stage redraw has been queued
* so we effectively don't have any redraw clips in that case.
*/
if (!stage_glx->initialized_redraw_clip ||
(stage_glx->initialized_redraw_clip &&
stage_glx->bounding_redraw_clip.width != 0))
return TRUE;
else
return FALSE;
}
static gboolean
clutter_stage_glx_ignoring_redraw_clips (ClutterStageWindow *stage_window)
{
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
/* NB: a clip width of 0 means a full stage redraw is required */
if (stage_glx->initialized_redraw_clip &&
stage_glx->bounding_redraw_clip.width == 0)
return TRUE;
else
return FALSE;
}
/* A redraw clip represents (in stage coordinates) the bounding box of
* something that needs to be redraw. Typically they are added to the
* StageWindow as a result of clutter_actor_queue_clipped_redraw() by
* actors such as ClutterGLXTexturePixmap. All redraw clips are
* discarded after the next paint.
*
* A NULL stage_clip means the whole stage needs to be redrawn.
*
* What we do with this information:
* - we keep track of the bounding box for all redraw clips
* - when we come to redraw; if the bounding box is smaller than the
* stage we scissor the redraw to that box and use
* GLX_MESA_copy_sub_buffer to present the redraw to the front
* buffer.
*
* XXX - In theory, we should have some sort of heuristics to promote
* a clipped redraw to a full screen redraw; in reality, it turns out
* that promotion is fairly expensive. See the Clutter bug described
* at: http://bugzilla.clutter-project.org/show_bug.cgi?id=2136 .
*
* TODO - we should use different heuristics depending on whether the
* framebuffer is on screen and not redirected by a compositor VS
* offscreen (either due to compositor redirection or because we are
* rendering to a CoglOffscreen framebuffer)
*
* When not redirected glXCopySubBuffer (on intel hardware at least)
* will block the GPU until the vertical trace is at the optimal point
* so the copy can be done without tearing. In this case we don't want
* to copy tall regions because they increase the average time spent
* blocking the GPU.
*
* When rendering offscreen (CoglOffscreen or redirected by
* compositor) then no extra synchronization is needed before the copy
* can start.
*
* In all cases we need to consider that glXCopySubBuffer implies a
* blit which may be avoided by promoting to a full stage redraw if:
* - the framebuffer is redirected offscreen or a CoglOffscreen.
* - the framebuffer is onscreen and fullscreen.
* By promoting to a full stage redraw we trade off the cost involved
* in rasterizing the extra pixels vs avoiding to use a blit to
* present the back buffer.
*/
static void
clutter_stage_glx_add_redraw_clip (ClutterStageWindow *stage_window,
ClutterGeometry *stage_clip)
{
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
/* If we are already forced to do a full stage redraw then bail early */
if (clutter_stage_glx_ignoring_redraw_clips (stage_window))
return;
/* A NULL stage clip means a full stage redraw has been queued and
* we keep track of this by setting a zero width
* stage_glx->bounding_redraw_clip */
if (stage_clip == NULL)
{
stage_glx->bounding_redraw_clip.width = 0;
stage_glx->initialized_redraw_clip = TRUE;
return;
}
/* Ignore requests to add degenerate/empty clip rectangles */
if (stage_clip->width == 0 || stage_clip->height == 0)
return;
if (!stage_glx->initialized_redraw_clip)
{
stage_glx->bounding_redraw_clip.x = stage_clip->x;
stage_glx->bounding_redraw_clip.y = stage_clip->y;
stage_glx->bounding_redraw_clip.width = stage_clip->width;
stage_glx->bounding_redraw_clip.height = stage_clip->height;
}
else if (stage_glx->bounding_redraw_clip.width > 0)
{
clutter_geometry_union (&stage_glx->bounding_redraw_clip,
stage_clip,
&stage_glx->bounding_redraw_clip);
}
#if 0
redraw_area = (stage_glx->bounding_redraw_clip.width *
stage_glx->bounding_redraw_clip.height);
stage_area = stage_x11->xwin_width * stage_x11->xwin_height;
/* Redrawing and blitting >70% of the stage is assumed to be more
* expensive than redrawing the additional 30% to avoid the blit.
*
* FIXME: This threshold was plucked out of thin air!
*
* The threshold has been disabled after verifying that it indeed
* made redraws more expensive than intended; see bug reference:
*
* http://bugzilla.clutter-project.org/show_bug.cgi?id=2136
*/
if (redraw_area > (stage_area * 0.7f))
{
g_print ("DEBUG: clipped redraw too big, forcing full redraw\n");
/* Set a zero width clip to force a full redraw */
stage_glx->bounding_redraw_clip.width = 0;
}
#endif
stage_glx->initialized_redraw_clip = TRUE;
}
static void
clutter_stage_glx_redraw (ClutterStageWindow *stage_window)
{
ClutterBackendGLX *backend_glx;
ClutterStageX11 *stage_x11;
ClutterStageGLX *stage_glx;
gboolean may_use_clipped_redraw;
gboolean use_clipped_redraw;
CLUTTER_STATIC_TIMER (painting_timer,
"Redrawing", /* parent */
"Painting actors",
"The time spent painting actors",
0 /* no application private data */);
CLUTTER_STATIC_TIMER (swapbuffers_timer,
"Redrawing", /* parent */
"glXSwapBuffers",
"The time spent blocked by glXSwapBuffers",
0 /* no application private data */);
CLUTTER_STATIC_TIMER (blit_sub_buffer_timer,
"Redrawing", /* parent */
"glx_blit_sub_buffer",
"The time spent in _glx_blit_sub_buffer",
0 /* no application private data */);
stage_x11 = CLUTTER_STAGE_X11 (stage_window);
if (stage_x11->xwin == None)
return;
stage_glx = CLUTTER_STAGE_GLX (stage_window);
backend_glx = CLUTTER_BACKEND_GLX (stage_x11->backend);
CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer);
if (G_LIKELY (backend_glx->can_blit_sub_buffer) &&
/* NB: a zero width redraw clip == full stage redraw */
stage_glx->bounding_redraw_clip.width != 0 &&
/* some drivers struggle to get going and produce some junk
* frames when starting up... */
G_LIKELY (stage_glx->frame_count > 3) &&
/* While resizing a window clipped redraws are disabled to avoid
* artefacts. See clutter-event-x11.c:event_translate for a
* detailed explanation */
G_LIKELY (stage_x11->clipped_redraws_cool_off == 0))
{
may_use_clipped_redraw = TRUE;
}
else
may_use_clipped_redraw = FALSE;
if (may_use_clipped_redraw &&
G_LIKELY (!(clutter_paint_debug_flags &
CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
use_clipped_redraw = TRUE;
else
use_clipped_redraw = FALSE;
if (use_clipped_redraw)
{
CLUTTER_NOTE (CLIPPING,
"Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n",
stage_glx->bounding_redraw_clip.x,
stage_glx->bounding_redraw_clip.y,
stage_glx->bounding_redraw_clip.width,
stage_glx->bounding_redraw_clip.height);
cogl_clip_push_window_rectangle (stage_glx->bounding_redraw_clip.x,
stage_glx->bounding_redraw_clip.y,
stage_glx->bounding_redraw_clip.width,
stage_glx->bounding_redraw_clip.height);
_clutter_stage_do_paint (stage_x11->wrapper,
&stage_glx->bounding_redraw_clip);
cogl_clip_pop ();
}
else
{
CLUTTER_NOTE (CLIPPING, "Unclipped stage paint\n");
/* If we are trying to debug redraw issues then we want to pass
* the bounding_redraw_clip so it can be visualized */
if (G_UNLIKELY (clutter_paint_debug_flags &
CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS) &&
may_use_clipped_redraw)
{
_clutter_stage_do_paint (stage_x11->wrapper,
&stage_glx->bounding_redraw_clip);
}
else
_clutter_stage_do_paint (stage_x11->wrapper, NULL);
}
if (may_use_clipped_redraw &&
G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS)))
{
static CoglMaterial *outline = NULL;
ClutterGeometry *clip = &stage_glx->bounding_redraw_clip;
ClutterActor *actor = CLUTTER_ACTOR (stage_x11->wrapper);
CoglHandle vbo;
float x_1 = clip->x;
float x_2 = clip->x + clip->width;
float y_1 = clip->y;
float y_2 = clip->y + clip->height;
float quad[8] = {
x_1, y_1,
x_2, y_1,
x_2, y_2,
x_1, y_2
};
CoglMatrix modelview;
if (outline == NULL)
{
outline = cogl_material_new ();
cogl_material_set_color4ub (outline, 0xff, 0x00, 0x00, 0xff);
}
vbo = cogl_vertex_buffer_new (4);
cogl_vertex_buffer_add (vbo,
"gl_Vertex",
2, /* n_components */
COGL_ATTRIBUTE_TYPE_FLOAT,
FALSE, /* normalized */
0, /* stride */
quad);
cogl_vertex_buffer_submit (vbo);
cogl_push_matrix ();
cogl_matrix_init_identity (&modelview);
_clutter_actor_apply_modelview_transform (actor, &modelview);
cogl_set_modelview_matrix (&modelview);
cogl_set_source (outline);
cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_LINE_LOOP,
0 , 4);
cogl_pop_matrix ();
cogl_object_unref (vbo);
}
CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer);
/* push on the screen */
if (use_clipped_redraw)
{
ClutterGeometry *clip = &stage_glx->bounding_redraw_clip;
int copy_area[4];
ClutterActor *actor;
/* XXX: It seems there will be a race here in that the stage
* 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[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;
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);
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, "cogl_framebuffer_swap_buffers (onscreen: %p)",
stage_glx->onscreen);
/* 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++;
CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer);
cogl_framebuffer_swap_buffers (COGL_FRAMEBUFFER (stage_glx->onscreen));
CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer);
}
/* 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)
{
clutter_stage_window_parent_iface = g_type_interface_peek_parent (iface);
iface->realize = clutter_stage_glx_realize;
iface->unrealize = clutter_stage_glx_unrealize;
iface->get_pending_swaps = clutter_stage_glx_get_pending_swaps;
iface->add_redraw_clip = clutter_stage_glx_add_redraw_clip;
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 */
}

View File

@ -1,77 +0,0 @@
/* Clutter.
* An OpenGL based 'interactive canvas' library.
* Authored By Matthew Allum <mallum@openedhand.com>
* Copyright (C) 2006-2007 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#ifndef __CLUTTER_STAGE_GLX_H__
#define __CLUTTER_STAGE_GLX_H__
#include <glib-object.h>
#include <clutter/clutter-stage.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <GL/glx.h>
#include <GL/gl.h>
#include "clutter-backend-glx.h"
#include "../x11/clutter-stage-x11.h"
G_BEGIN_DECLS
#define CLUTTER_TYPE_STAGE_GLX (_clutter_stage_glx_get_type ())
#define CLUTTER_STAGE_GLX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_GLX, ClutterStageGLX))
#define CLUTTER_IS_STAGE_GLX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_GLX))
#define CLUTTER_STAGE_GLX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STAGE_GLX, ClutterStageGLXClass))
#define CLUTTER_IS_STAGE_GLX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STAGE_GLX))
#define CLUTTER_STAGE_GLX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STAGE_GLX, ClutterStageGLXClass))
typedef struct _ClutterStageGLX ClutterStageGLX;
typedef struct _ClutterStageGLXClass ClutterStageGLXClass;
struct _ClutterStageGLX
{
ClutterStageX11 parent_instance;
gint pending_swaps;
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
* junk frames to start with.
*/
guint frame_count;
ClutterGeometry bounding_redraw_clip;
guint initialized_redraw_clip : 1;
};
struct _ClutterStageGLXClass
{
ClutterStageX11Class parent_class;
};
GType _clutter_stage_glx_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __CLUTTER_STAGE_H__ */

View File

@ -207,7 +207,7 @@ AS_CASE([$CLUTTER_FLAVOUR],
SUPPORT_XLIB=1 SUPPORT_XLIB=1
SUPPORT_GLX=1 SUPPORT_GLX=1
CLUTTER_WINSYS=glx CLUTTER_WINSYS=cogl
CLUTTER_WINSYS_BASE=x11 CLUTTER_WINSYS_BASE=x11
CLUTTER_WINSYS_BASE_LIB="x11/libclutter-x11.la" CLUTTER_WINSYS_BASE_LIB="x11/libclutter-x11.la"
CLUTTER_SONAME_INFIX=glx CLUTTER_SONAME_INFIX=glx
@ -238,7 +238,7 @@ AS_CASE([$CLUTTER_FLAVOUR],
SUPPORT_EGL=1 SUPPORT_EGL=1
SUPPORT_EGL_PLATFORM_POWERVR_X11=1 SUPPORT_EGL_PLATFORM_POWERVR_X11=1
CLUTTER_WINSYS=egl CLUTTER_WINSYS=cogl
CLUTTER_WINSYS_BASE=x11 CLUTTER_WINSYS_BASE=x11
CLUTTER_WINSYS_BASE_LIB="x11/libclutter-x11.la" CLUTTER_WINSYS_BASE_LIB="x11/libclutter-x11.la"
# I think this winsys can be API and ABI compatible with the # I think this winsys can be API and ABI compatible with the
@ -275,7 +275,7 @@ AS_CASE([$CLUTTER_FLAVOUR],
SUPPORT_EGL=1 SUPPORT_EGL=1
SUPPORT_EGL_PLATFORM_POWERVR_X11=1 SUPPORT_EGL_PLATFORM_POWERVR_X11=1
CLUTTER_WINSYS=egl CLUTTER_WINSYS=cogl
CLUTTER_WINSYS_BASE=x11 CLUTTER_WINSYS_BASE=x11
CLUTTER_WINSYS_BASE_LIB="x11/libclutter-x11.la" CLUTTER_WINSYS_BASE_LIB="x11/libclutter-x11.la"
CLUTTER_SONAME_INFIX=eglx CLUTTER_SONAME_INFIX=eglx
@ -310,7 +310,7 @@ AS_CASE([$CLUTTER_FLAVOUR],
FLAVOUR_LIBS="$FLAVOUR_LIBS $TSLIB_LIBS $EVDEV_LIBS" FLAVOUR_LIBS="$FLAVOUR_LIBS $TSLIB_LIBS $EVDEV_LIBS"
FLAVOUR_CFLAGS="$FLAVOUR_CFLAGS $TSLIB_CFLAGS $EVDEV_CFLAGS" FLAVOUR_CFLAGS="$FLAVOUR_CFLAGS $TSLIB_CFLAGS $EVDEV_CFLAGS"
CLUTTER_WINSYS=egl CLUTTER_WINSYS=cogl
CLUTTER_SONAME_INFIX=eglnative CLUTTER_SONAME_INFIX=eglnative
], ],
@ -323,7 +323,7 @@ AS_CASE([$CLUTTER_FLAVOUR],
SUPPORT_EGL_PLATFORM_GDL=1 SUPPORT_EGL_PLATFORM_GDL=1
# The cex100 is a small specialization of the EGL backend # The cex100 is a small specialization of the EGL backend
CLUTTER_WINSYS=egl CLUTTER_WINSYS=cogl
CLUTTER_SONAME_INFIX=cex100 CLUTTER_SONAME_INFIX=cex100
found_gdl=no found_gdl=no
@ -939,7 +939,7 @@ AC_CONFIG_FILES([
clutter/cally/cally-$CLUTTER_API_VERSION.pc:clutter/cally/cally.pc.in clutter/cally/cally-$CLUTTER_API_VERSION.pc:clutter/cally/cally.pc.in
clutter/egl/clutter-cex100.h clutter/cogl/clutter-cex100.h
tests/Makefile tests/Makefile
tests/accessibility/Makefile tests/accessibility/Makefile