egl: Unify the eglx and eglnative backends

Without actually consolidating the two backends this patch brings their
code within a cats whisker of each other in preparation for
consolidation.
This commit is contained in:
Robert Bragg 2010-06-17 22:26:12 +01:00
parent 53bf95466b
commit a84ecf3919
7 changed files with 1318 additions and 244 deletions

View File

@ -1,3 +1,30 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
* Authors:
* Matthew Allum
* Emmanuele Bassi
* Robert Bragg
* Neil Roberts
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@ -5,21 +32,28 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "clutter-backend-egl.h"
#include "clutter-stage-egl.h"
#include "clutter-egl.h"
#include "../clutter-private.h"
#include "../clutter-main.h"
#include "../clutter-debug.h"
#include "../clutter-version.h"
static ClutterBackendEGL *backend_singleton = NULL;
static const gchar *clutter_fb_device = NULL;
#ifdef COGL_HAS_X11_SUPPORT
G_DEFINE_TYPE (ClutterBackendEGL, clutter_backend_egl, CLUTTER_TYPE_BACKEND_X11);
#else
G_DEFINE_TYPE (ClutterBackendEGL, clutter_backend_egl, CLUTTER_TYPE_BACKEND);
#endif
static void
clutter_backend_at_exit (void)
@ -33,6 +67,13 @@ clutter_backend_egl_pre_parse (ClutterBackend *backend,
GError **error)
{
const gchar *env_string;
#ifdef COGL_HAS_X11_SUPPORT
ClutterBackendClass *backend_x11_class =
CLUTTER_BACKEND_CLASS (clutter_backend_egl_parent_class);
if (!backend_x11_class->pre_parse (backend, error))
return FALSE;
#endif
env_string = g_getenv ("CLUTTER_FB_DEVICE");
if (env_string != NULL && env_string[0] != '\0')
@ -45,15 +86,35 @@ static gboolean
clutter_backend_egl_post_parse (ClutterBackend *backend,
GError **error)
{
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL(backend);
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
#ifdef COGL_HAS_X11_SUPPORT
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterBackendClass *backend_x11_class =
CLUTTER_BACKEND_CLASS (clutter_backend_egl_parent_class);
#endif
EGLBoolean status;
#ifdef COGL_HAS_X11_SUPPORT
if (!backend_x11_class->post_parse (backend, error))
return FALSE;
#ifndef COGL_HAS_XLIB_SUPPORT
#error "Clutter's EGL on X11 support currently only works with xlib Displays"
#endif
backend_egl->edpy =
eglGetDisplay ((NativeDisplayType) backend_x11->xdpy);
status = eglInitialize (backend_egl->edpy,
&backend_egl->egl_version_major,
&backend_egl->egl_version_minor);
#else
backend_egl->edpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
status = eglInitialize (backend_egl->edpy,
&backend_egl->egl_version_major,
status = eglInitialize (backend_egl->edpy,
&backend_egl->egl_version_major,
&backend_egl->egl_version_minor);
#endif
g_atexit (clutter_backend_at_exit);
if (status != EGL_TRUE)
@ -65,88 +126,168 @@ clutter_backend_egl_post_parse (ClutterBackend *backend,
}
CLUTTER_NOTE (BACKEND, "EGL Reports version %i.%i",
backend_egl->egl_version_major,
backend_egl->egl_version_major,
backend_egl->egl_version_minor);
return TRUE;
}
static void
clutter_backend_egl_ensure_context (ClutterBackend *backend,
ClutterStage *stage)
{
/* not doing anything since we only have one context and
* it is permanently made current
*/
}
static gboolean
clutter_backend_egl_create_context (ClutterBackend *backend,
GError **error)
{
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
EGLConfig configs[2];
EGLint config_count;
EGLBoolean status;
EGLint cfg_attribs[] = {
EGL_BUFFER_SIZE, EGL_DONT_CARE,
EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 6,
EGL_BLUE_SIZE, 5,
EGL_DEPTH_SIZE, 16,
EGL_ALPHA_SIZE, EGL_DONT_CARE,
#ifdef COGL_HAS_X11_SUPPORT
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
#endif
EGLConfig config;
EGLint config_count = 0;
EGLBoolean status;
EGLint cfg_attribs[] = {
/* NB: This must be the first attribute, since we may
* try and fallback to no stencil buffer */
EGL_STENCIL_SIZE, 2,
#ifdef HAVE_COGL_GLES2
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_ALPHA_SIZE, EGL_DONT_CARE,
EGL_DEPTH_SIZE, 1,
EGL_BUFFER_SIZE, EGL_DONT_CARE,
#if defined (HAVE_COGL_GLES2)
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
#else /* HAVE_COGL_GLES2 */
#else
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
#endif
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
#endif /* HAVE_COGL_GLES2 */
EGL_NONE
};
EGLDisplay edpy;
gint retry_cookie = 0;
const char *error_message = NULL;
#ifdef COGL_HAS_XLIB_SUPPORT
XVisualInfo *xvisinfo;
XSetWindowAttributes attrs;
#endif
if (backend_egl->egl_context)
if (backend_egl->egl_context != EGL_NO_CONTEXT)
return TRUE;
status = eglGetConfigs (backend_egl->edpy,
configs,
2,
&config_count);
edpy = clutter_egl_display ();
if (status != EGL_TRUE)
/* XXX: we should get rid of this goto yukkyness, there is a fail:
* goto at the end and this retry: goto at the top, but we should just
* have a try_create_context() function and call it in a loop that
* tries a different fallback each iteration */
retry:
/* Here we can change the attributes depending on the fallback count... */
/* Some GLES hardware can't support a stencil buffer: */
if (retry_cookie == 1)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"No EGL configurations found");
return FALSE;
g_warning ("Trying with stencil buffer disabled...");
cfg_attribs[1 /* EGL_STENCIL_SIZE */] = 0;
}
status = eglChooseConfig (backend_egl->edpy,
/* XXX: at this point we only have one fallback */
status = eglChooseConfig (edpy,
cfg_attribs,
configs,
G_N_ELEMENTS (configs),
&config, 1,
&config_count);
if (status != EGL_TRUE)
if (status != EGL_TRUE || config_count == 0)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Unable to select a valid EGL configuration");
error_message = "Unable to select a valid EGL configuration";
goto fail;
}
if (backend_egl->egl_context == EGL_NO_CONTEXT)
{
#ifdef HAVE_COGL_GLES2
static const EGLint attribs[] =
{ EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
backend_egl->egl_context = eglCreateContext (edpy,
config,
EGL_NO_CONTEXT,
attribs);
#else
backend_egl->egl_context = eglCreateContext (edpy,
config,
EGL_NO_CONTEXT,
NULL);
#endif
if (backend_egl->egl_context == EGL_NO_CONTEXT)
{
error_message = "Unable to create a suitable EGL context";
goto fail;
}
#ifdef COGL_HAS_XLIB_SUPPORT
backend_egl->egl_config = config;
#endif
CLUTTER_NOTE (GL, "Created EGL Context");
}
#ifdef COGL_HAS_XLIB_SUPPORT
/* COGL assumes that there is always a GL context selected; in order
* to make sure that an EGL context exists and is made current, we use
* a dummy, offscreen override-redirect window to which we can always
* fall back if no stage is available */
xvisinfo = clutter_backend_x11_get_visual_info (backend_x11);
if (xvisinfo == NULL)
{
g_critical ("Unable to find suitable GL visual.");
return FALSE;
}
CLUTTER_NOTE (BACKEND, "Got %i configs", config_count);
attrs.override_redirect = True;
attrs.colormap = XCreateColormap (backend_x11->xdpy,
backend_x11->xwin_root,
xvisinfo->visual,
AllocNone);
attrs.border_pixel = 0;
if (G_UNLIKELY (backend_egl->egl_surface != EGL_NO_SURFACE))
backend_egl->dummy_xwin = XCreateWindow (backend_x11->xdpy,
backend_x11->xwin_root,
-100, -100, 1, 1,
0,
xvisinfo->depth,
CopyFromParent,
xvisinfo->visual,
CWOverrideRedirect |
CWColormap |
CWBorderPixel,
&attrs);
XFree (xvisinfo);
backend_egl->dummy_surface =
eglCreateWindowSurface (edpy,
backend_egl->egl_config,
(NativeWindowType) backend_egl->dummy_xwin,
NULL);
if (backend_egl->dummy_surface == EGL_NO_SURFACE)
{
eglDestroySurface (backend_egl->edpy, backend_egl->egl_surface);
backend_egl->egl_surface = EGL_NO_SURFACE;
g_critical ("Unable to create an EGL surface");
return FALSE;
}
if (G_UNLIKELY (backend_egl->egl_context != NULL))
{
eglDestroyContext (backend_egl->edpy, backend_egl->egl_context);
backend_egl->egl_context = NULL;
}
eglMakeCurrent (edpy,
backend_egl->dummy_surface,
backend_egl->dummy_surface,
backend_egl->egl_context);
#else /* COGL_HAS_XLIB_SUPPORT */
if (clutter_fb_device != NULL)
{
@ -168,17 +309,17 @@ clutter_backend_egl_create_context (ClutterBackend *backend,
backend_egl->fb_device_id = fd;
backend_egl->egl_surface =
eglCreateWindowSurface (backend_egl->edpy,
configs[0],
eglCreateWindowSurface (edpy,
config,
(NativeWindowType) backend_egl->fb_device_id,
NULL);
}
else
{
backend_egl->egl_surface =
eglCreateWindowSurface (backend_egl->edpy,
configs[0],
NULL,
eglCreateWindowSurface (edpy,
config,
(NativeWindowType) NULL,
NULL);
}
@ -191,42 +332,13 @@ clutter_backend_egl_create_context (ClutterBackend *backend,
return FALSE;
}
#ifdef HAVE_COGL_GLES2
{
static const EGLint attribs[3] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
backend_egl->egl_context = eglCreateContext (backend_egl->edpy,
configs[0],
EGL_NO_CONTEXT,
attribs);
}
#else
/* Seems some GLES implementations 1.x do not like attribs... */
backend_egl->egl_context = eglCreateContext (backend_egl->edpy,
configs[0],
EGL_NO_CONTEXT,
NULL);
#endif
if (backend_egl->egl_context == EGL_NO_CONTEXT)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Unable to create a suitable EGL context");
return FALSE;
}
CLUTTER_NOTE (GL, "Created EGL Context");
CLUTTER_NOTE (BACKEND, "Setting context");
/* eglnative can have only one stage, so we store the EGL surface
* in the backend itself, instead of the StageWindow implementation,
* and we make it current immediately to make sure the Cogl and
* Clutter can query the EGL context for features.
/* Without X we assume we can have only one stage, so we
* store the EGL surface in the backend itself, instead
* of the StageWindow implementation, and we make it
* current immediately to make sure the Cogl and Clutter
* can query the EGL context for features.
*/
status = eglMakeCurrent (backend_egl->edpy,
backend_egl->egl_surface,
@ -247,70 +359,127 @@ clutter_backend_egl_create_context (ClutterBackend *backend,
backend_egl->surface_width,
backend_egl->surface_height);
#endif /* COGL_HAS_XLIB_SUPPORT */
return TRUE;
fail:
/* NB: We currently only support a single fallback option */
if (retry_cookie == 0)
{
retry_cookie = 1;
goto retry;
}
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"%s", error_message);
return FALSE;
}
static void
clutter_backend_egl_ensure_context (ClutterBackend *backend,
ClutterStage *stage)
{
#ifndef COGL_HAS_XLIB_SUPPORT
/* Without X we only have one EGL surface to worry about
* so we can assume it is permanently made current and
* don't have to do anything here. */
#else
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterStageWindow *impl;
if (stage == NULL ||
(CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_IN_DESTRUCTION) ||
((impl = _clutter_stage_get_window (stage)) == NULL))
{
CLUTTER_NOTE (BACKEND, "Clearing EGL context");
eglMakeCurrent (backend_egl->edpy,
EGL_NO_SURFACE,
EGL_NO_SURFACE,
EGL_NO_CONTEXT);
}
else
{
ClutterStageEGL *stage_egl;
ClutterStageX11 *stage_x11;
g_assert (impl != NULL);
CLUTTER_NOTE (MULTISTAGE, "Setting context for stage of type %s [%p]",
g_type_name (G_OBJECT_TYPE (impl)),
impl);
stage_egl = CLUTTER_STAGE_EGL (impl);
stage_x11 = CLUTTER_STAGE_X11 (impl);
if (backend_egl->egl_context == EGL_NO_CONTEXT)
return;
clutter_x11_trap_x_errors ();
/* we might get here inside the final dispose cycle, so we
* need to handle this gracefully
*/
if (stage_x11->xwin == None ||
stage_egl->egl_surface == EGL_NO_SURFACE)
{
CLUTTER_NOTE (MULTISTAGE,
"Received a stale stage, clearing all context");
if (backend_egl->dummy_surface == EGL_NO_SURFACE)
eglMakeCurrent (backend_egl->edpy,
EGL_NO_SURFACE,
EGL_NO_SURFACE,
EGL_NO_CONTEXT);
else
eglMakeCurrent (backend_egl->edpy,
backend_egl->dummy_surface,
backend_egl->dummy_surface,
backend_egl->egl_context);
}
else
{
CLUTTER_NOTE (MULTISTAGE, "Setting real surface current");
eglMakeCurrent (backend_egl->edpy,
stage_egl->egl_surface,
stage_egl->egl_surface,
backend_egl->egl_context);
}
if (clutter_x11_untrap_x_errors ())
g_critical ("Unable to make the stage window 0x%x the current "
"EGLX drawable",
(int) stage_x11->xwin);
}
#endif /* COGL_HAS_XLIB_SUPPORT */
}
static void
clutter_backend_egl_redraw (ClutterBackend *backend,
ClutterStage *stage)
{
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterStageEGL *stage_egl;
ClutterStageWindow *impl;
impl = _clutter_stage_get_window (stage);
if (impl == NULL)
if (!impl)
return;
g_assert (CLUTTER_IS_STAGE_EGL (impl));
stage_egl = CLUTTER_STAGE_EGL (impl);
eglWaitNative (EGL_CORE_NATIVE_ENGINE);
clutter_actor_paint (CLUTTER_ACTOR (stage_egl->wrapper));
cogl_flush ();
eglWaitGL();
eglSwapBuffers (backend_egl->edpy, backend_egl->egl_surface);
}
static ClutterStageWindow *
clutter_backend_egl_create_stage (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error)
{
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterStageEGL *stage_egl;
ClutterStageWindow *stage;
if (G_UNLIKELY (backend_egl->stage != NULL))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"The EGL native backend does not support multiple stages");
return backend_egl->stage;
}
stage = g_object_new (CLUTTER_TYPE_STAGE_EGL, NULL);
stage_egl = CLUTTER_STAGE_EGL (stage);
stage_egl->backend = backend_egl;
stage_egl->wrapper = wrapper;
backend_egl->stage = stage;
return stage;
clutter_stage_egl_redraw (CLUTTER_STAGE_EGL (impl), stage);
}
#ifdef HAVE_TSLIB
static void
clutter_backend_egl_init_events (ClutterBackend *backend)
{
/* XXX: This should be renamed to _clutter_events_tslib_init */
_clutter_events_egl_init (CLUTTER_BACKEND_EGL (backend));
}
static const GOptionEntry entries[] =
{
{ NULL }
};
#endif
static void
clutter_backend_egl_finalize (GObject *gobject)
@ -325,29 +494,59 @@ static void
clutter_backend_egl_dispose (GObject *gobject)
{
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (gobject);
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (backend_egl->stage);
#ifdef COGL_HAS_X11_SUPPORT
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (gobject);
#else
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (backend_egl->stage);
#endif
/* We chain up before disposing our own resources so that
ClutterBackendX11 will destroy all of the stages before we
destroy the egl context. Otherwise the actors may try to make GL
calls during destruction which causes a crash */
G_OBJECT_CLASS (clutter_backend_egl_parent_class)->dispose (gobject);
#ifdef HAVE_TSLIB
/* XXX: This should be renamed to _clutter_events_tslib_uninit */
_clutter_events_egl_uninit (backend_egl);
#endif
if (backend_egl->stage != NULL)
#ifdef COGL_HAS_XLIB_SUPPORT
if (backend_egl->dummy_surface != EGL_NO_SURFACE)
{
clutter_actor_destroy (CLUTTER_ACTOR (stage_egl->wrapper));
backend_egl->stage = NULL;
eglDestroySurface (backend_egl->edpy, backend_egl->dummy_surface);
backend_egl->dummy_surface = EGL_NO_SURFACE;
}
if (backend_egl->dummy_xwin)
{
XDestroyWindow (backend_x11->xdpy, backend_egl->dummy_xwin);
backend_egl->dummy_xwin = None;
}
#else /* COGL_HAS_XLIB_SUPPORT */
if (backend_egl->egl_surface != EGL_NO_SURFACE)
{
eglDestroySurface (backend_egl->edpy, backend_egl->egl_surface);
backend_egl->egl_surface = EGL_NO_SURFACE;
}
if (backend_egl->stage != NULL)
{
clutter_actor_destroy (CLUTTER_ACTOR (stage_egl->wrapper));
backend_egl->stage = NULL;
}
if (backend_egl->fb_device_id != -1)
{
close (backend_egl->fb_device_id);
backend_egl->fb_device_id = -1;
}
if (backend_egl->egl_context != NULL)
#endif /* COGL_HAS_XLIB_SUPPORT */
if (backend_egl->egl_context)
{
eglDestroyContext (backend_egl->edpy, backend_egl->egl_context);
backend_egl->egl_context = NULL;
@ -359,13 +558,13 @@ clutter_backend_egl_dispose (GObject *gobject)
backend_egl->edpy = 0;
}
#ifdef HAVE_TSLIB
if (backend_egl->event_timer != NULL)
{
g_timer_destroy (backend_egl->event_timer);
backend_egl->event_timer = NULL;
}
G_OBJECT_CLASS (clutter_backend_egl_parent_class)->dispose (gobject);
#endif
}
static GObject *
@ -388,17 +587,25 @@ clutter_backend_egl_constructor (GType gtype,
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_egl_get_features (ClutterBackend *backend)
{
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterFeatureFlags flags;
g_assert (backend_egl->egl_context != NULL);
#ifdef COGL_HAS_XLIB_SUPPORT
flags = clutter_backend_x11_get_features (backend);
flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
#else
flags = CLUTTER_FEATURE_STAGE_STATIC;
#endif
CLUTTER_NOTE (BACKEND, "Checking features\n"
"GL_VENDOR: %s\n"
"GL_RENDERER: %s\n"
@ -413,41 +620,163 @@ clutter_backend_egl_get_features (ClutterBackend *backend)
eglQueryString (backend_egl->edpy, EGL_VERSION),
eglQueryString (backend_egl->edpy, EGL_EXTENSIONS));
return CLUTTER_FEATURE_STAGE_STATIC;
return flags;
}
static ClutterStageWindow *
clutter_backend_egl_create_stage (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error)
{
#ifdef COGL_HAS_XLIB_SUPPORT
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterStageWindow *stage;
ClutterStageX11 *stage_x11;
CLUTTER_NOTE (BACKEND, "Creating stage of type '%s'",
g_type_name (CLUTTER_STAGE_TYPE));
stage = g_object_new (CLUTTER_TYPE_STAGE_EGL, NULL);
/* copy backend data into the stage */
stage_x11 = CLUTTER_STAGE_X11 (stage);
stage_x11->wrapper = wrapper;
CLUTTER_NOTE (MISC, "EGLX stage created (display:%p, screen:%d, root:%u)",
backend_x11->xdpy,
backend_x11->xscreen_num,
(unsigned int) backend_x11->xwin_root);
#else /* COGL_HAS_XLIB_SUPPORT */
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterStageWindow *stage;
ClutterStageEGL *stage_egl;
if (G_UNLIKELY (backend_egl->stage != NULL))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"The EGL native backend does not support multiple stages");
return backend_egl->stage;
}
stage = g_object_new (CLUTTER_TYPE_STAGE_EGL, NULL);
stage_egl = CLUTTER_STAGE_EGL (stage);
stage_egl->backend = backend_egl;
stage_egl->wrapper = wrapper;
backend_egl->stage = stage;
#endif /* COGL_HAS_XLIB_SUPPORT */
return stage;
}
#ifdef COGL_HAS_XLIB_SUPPORT
static XVisualInfo *
clutter_backend_egl_get_visual_info (ClutterBackendX11 *backend_x11)
{
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend_x11);
XVisualInfo visinfo_template;
int template_mask = 0;
XVisualInfo *visinfo = NULL;
int visinfos_count;
EGLint visualid, red_size, green_size, blue_size, alpha_size;
if (!clutter_backend_egl_create_context (CLUTTER_BACKEND (backend_x11), NULL))
return NULL;
visinfo_template.screen = backend_x11->xscreen_num;
template_mask |= VisualScreenMask;
eglGetConfigAttrib (backend_egl->edpy, backend_egl->egl_config,
EGL_NATIVE_VISUAL_ID, &visualid);
if (visualid != 0)
{
visinfo_template.visualid = visualid;
template_mask |= VisualIDMask;
}
else
{
/* some EGL drivers don't implement the EGL_NATIVE_VISUAL_ID
* attribute, so attempt to find the closest match. */
eglGetConfigAttrib (backend_egl->edpy, backend_egl->egl_config,
EGL_RED_SIZE, &red_size);
eglGetConfigAttrib (backend_egl->edpy, backend_egl->egl_config,
EGL_GREEN_SIZE, &green_size);
eglGetConfigAttrib (backend_egl->edpy, backend_egl->egl_config,
EGL_BLUE_SIZE, &blue_size);
eglGetConfigAttrib (backend_egl->edpy, backend_egl->egl_config,
EGL_ALPHA_SIZE, &alpha_size);
visinfo_template.depth = red_size + green_size + blue_size + alpha_size;
template_mask |= VisualDepthMask;
}
visinfo = XGetVisualInfo (backend_x11->xdpy,
template_mask,
&visinfo_template,
&visinfos_count);
return visinfo;
}
#endif
static void
clutter_backend_egl_class_init (ClutterBackendEGLClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
#ifdef COGL_HAS_X11_SUPPORT
ClutterBackendX11Class *backendx11_class = CLUTTER_BACKEND_X11_CLASS (klass);
#endif
gobject_class->constructor = clutter_backend_egl_constructor;
gobject_class->dispose = clutter_backend_egl_dispose;
gobject_class->finalize = clutter_backend_egl_finalize;
gobject_class->dispose = clutter_backend_egl_dispose;
gobject_class->finalize = clutter_backend_egl_finalize;
backend_class->pre_parse = clutter_backend_egl_pre_parse;
backend_class->post_parse = clutter_backend_egl_post_parse;
backend_class->get_features = clutter_backend_egl_get_features;
#ifdef HAVE_TSLIB
backend_class->init_events = clutter_backend_egl_init_events;
#endif
backend_class->create_stage = clutter_backend_egl_create_stage;
backend_class->create_context = clutter_backend_egl_create_context;
backend_class->ensure_context = clutter_backend_egl_ensure_context;
backend_class->redraw = clutter_backend_egl_redraw;
backend_class->get_features = clutter_backend_egl_get_features;
#ifdef COGL_HAS_XLIB_SUPPORT
backendx11_class->get_visual_info = clutter_backend_egl_get_visual_info;
#endif
}
static void
clutter_backend_egl_init (ClutterBackendEGL *backend_egl)
{
#ifndef COGL_HAS_XLIB_SUPPORT
ClutterBackend *backend = CLUTTER_BACKEND (backend_egl);
clutter_backend_set_resolution (backend, 96.0);
clutter_backend_set_double_click_time (backend, 250);
clutter_backend_set_double_click_distance (backend, 5);
#ifdef HAVE_TSLIB
backend_egl->event_timer = g_timer_new ();
#endif
backend_egl->fb_device_id = -1;
#else
backend_egl->egl_context = EGL_NO_CONTEXT;
backend_egl->dummy_surface = EGL_NO_SURFACE;
#endif
}
GType
@ -456,6 +785,23 @@ _clutter_backend_impl_get_type (void)
return clutter_backend_egl_get_type ();
}
#ifdef COGL_HAS_XLIB_SUPPORT
/**
* clutter_eglx_display:
*
* Retrieves the <structname>EGLDisplay</structname> used by Clutter
*
* Return value: the EGL display
*
* Since: 0.4
*/
EGLDisplay
clutter_eglx_display (void)
{
return backend_singleton->edpy;
}
#endif /* COGL_HAS_XLIB_SUPPORT */
/**
* clutter_egl_display:
*
@ -468,3 +814,4 @@ clutter_egl_display (void)
{
return backend_singleton->edpy;
}

View File

@ -1,8 +1,6 @@
/* Clutter.
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006, 2007, 2008 OpenedHand
* Copyright (C) 2009, 2010 Intel Corp
*
@ -19,16 +17,24 @@
* 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
*/
#ifndef __CLUTTER_BACKEND_EGL_H__
#define __CLUTTER_BACKEND_EGL_H__
#include <glib-object.h>
#include <clutter/clutter-event.h>
#include <clutter/clutter-backend.h>
#ifdef COGL_HAS_XLIB_SUPPORT
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#endif
#include "clutter-egl-headers.h"
#include <glib-object.h>
#include <clutter/clutter-backend.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_BACKEND_EGL (clutter_backend_egl_get_type ())
@ -43,6 +49,19 @@ typedef struct _ClutterBackendEGLClass ClutterBackendEGLClass;
struct _ClutterBackendEGL
{
#ifdef COGL_HAS_XLIB_SUPPORT
ClutterBackendX11 parent_instance;
/* EGL Specific */
EGLDisplay edpy;
EGLContext egl_context;
EGLConfig egl_config;
Window dummy_xwin;
EGLSurface dummy_surface;
#else /* COGL_HAS_X11_SUPPORT */
ClutterBackend parent_instance;
/* EGL Specific */
@ -54,9 +73,6 @@ struct _ClutterBackendEGL
gint surface_width;
gint surface_height;
gint egl_version_major;
gint egl_version_minor;
/* main stage singleton */
ClutterStageWindow *stage;
@ -69,12 +85,19 @@ struct _ClutterBackendEGL
/* FB device */
gint fb_device_id;
/*< private >*/
#endif /* COGL_HAS_X11_SUPPORT */
gint egl_version_major;
gint egl_version_minor;
};
struct _ClutterBackendEGLClass
{
#ifdef COGL_HAS_XLIB_SUPPORT
ClutterBackendX11Class parent_class;
#else
ClutterBackendClass parent_class;
#endif
};
GType clutter_backend_egl_get_type (void) G_GNUC_CONST;

View File

@ -18,17 +18,189 @@
#include "../clutter-stage.h"
#include "../clutter-stage-window.h"
#ifdef COGL_HAS_X11_SUPPORT
static ClutterStageWindowIface *clutter_stage_egl_parent_iface = NULL;
#endif
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterStageEGL,
clutter_stage_egl,
#ifdef COGL_HAS_X11_SUPPORT
CLUTTER_TYPE_STAGE_X11,
#else
G_TYPE_OBJECT,
#endif
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
clutter_stage_window_iface_init));
#ifdef COGL_HAS_XLIB_SUPPORT
static void
clutter_stage_egl_class_init (ClutterStageEGLClass *klass)
clutter_stage_egl_unrealize (ClutterStageWindow *stage_window)
{
ClutterBackend *backend = clutter_get_default_backend ();
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window);
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
CLUTTER_NOTE (BACKEND, "Unrealizing stage");
clutter_x11_trap_x_errors ();
if (!stage_x11->is_foreign_xwin && stage_x11->xwin != None)
{
XDestroyWindow (backend_x11->xdpy, stage_x11->xwin);
stage_x11->xwin = None;
}
else
stage_x11->xwin = None;
if (stage_egl->egl_surface != EGL_NO_SURFACE)
{
eglDestroySurface (clutter_eglx_display (), stage_egl->egl_surface);
stage_egl->egl_surface = EGL_NO_SURFACE;
}
XSync (backend_x11->xdpy, False);
clutter_x11_untrap_x_errors ();
}
static gboolean
clutter_stage_egl_realize (ClutterStageWindow *stage_window)
{
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window);
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
ClutterBackend *backend;
ClutterBackendEGL *backend_egl;
ClutterBackendX11 *backend_x11;
EGLDisplay edpy;
CLUTTER_NOTE (BACKEND, "Realizing main stage");
backend = clutter_get_default_backend ();
backend_egl = CLUTTER_BACKEND_EGL (backend);
backend_x11 = CLUTTER_BACKEND_X11 (backend);
edpy = clutter_eglx_display ();
if (stage_x11->xwin == None)
{
XSetWindowAttributes xattr;
unsigned long mask;
XVisualInfo *xvisinfo;
gfloat width, height;
CLUTTER_NOTE (MISC, "Creating stage X window");
xvisinfo = clutter_backend_x11_get_visual_info (backend_x11);
if (xvisinfo == NULL)
{
g_critical ("Unable to find suitable GL visual.");
return FALSE;
}
/* window attributes */
xattr.background_pixel = WhitePixel (backend_x11->xdpy,
backend_x11->xscreen_num);
xattr.border_pixel = 0;
xattr.colormap = XCreateColormap (backend_x11->xdpy,
backend_x11->xwin_root,
xvisinfo->visual,
AllocNone);
mask = CWBorderPixel | CWColormap;
/* Call get_size - this will either get the geometry size (which
* before we create the window is set to 640x480), or if a size
* is set, it will get that. This lets you set a size on the
* stage before it's realized.
*/
clutter_actor_get_size (CLUTTER_ACTOR (stage_x11->wrapper),
&width,
&height);
stage_x11->xwin_width = (gint)width;
stage_x11->xwin_height = (gint)height;
stage_x11->xwin = XCreateWindow (backend_x11->xdpy,
backend_x11->xwin_root,
0, 0,
stage_x11->xwin_width,
stage_x11->xwin_height,
0,
xvisinfo->depth,
InputOutput,
xvisinfo->visual,
mask, &xattr);
CLUTTER_NOTE (BACKEND, "Stage [%p], window: 0x%x, size: %dx%d",
stage_window,
(unsigned int) stage_x11->xwin,
stage_x11->xwin_width,
stage_x11->xwin_height);
XFree (xvisinfo);
}
if (stage_egl->egl_surface == EGL_NO_SURFACE)
{
stage_egl->egl_surface =
eglCreateWindowSurface (edpy,
backend_egl->egl_config,
(NativeWindowType) stage_x11->xwin,
NULL);
}
if (stage_egl->egl_surface == EGL_NO_SURFACE)
g_warning ("Unable to create an EGL surface");
if (clutter_x11_has_event_retrieval ())
{
if (clutter_x11_has_xinput ())
{
XSelectInput (backend_x11->xdpy, stage_x11->xwin,
StructureNotifyMask |
FocusChangeMask |
ExposureMask |
EnterWindowMask | LeaveWindowMask |
PropertyChangeMask);
#ifdef USE_XINPUT
_clutter_x11_select_events (stage_x11->xwin);
#endif
}
else
XSelectInput (backend_x11->xdpy, stage_x11->xwin,
StructureNotifyMask |
FocusChangeMask |
ExposureMask |
PointerMotionMask |
KeyPressMask | KeyReleaseMask |
ButtonPressMask | ButtonReleaseMask |
EnterWindowMask | LeaveWindowMask |
PropertyChangeMask);
}
/* no user resize... */
clutter_stage_x11_fix_window_size (stage_x11,
stage_x11->xwin_width,
stage_x11->xwin_height);
clutter_stage_x11_set_wm_protocols (stage_x11);
return clutter_stage_egl_parent_iface->realize (stage_window);
}
#else /* COGL_HAS_XLIB_SUPPORT */
static void
clutter_stage_egl_unrealize (ClutterStageWindow *stage_window)
{
}
static gboolean
clutter_stage_egl_realize (ClutterStageWindow *stage_window)
{
/* the EGL surface is created by the backend */
return TRUE;
}
static void
@ -78,18 +250,6 @@ clutter_stage_egl_hide (ClutterStageWindow *stage_window)
clutter_actor_unmap (CLUTTER_ACTOR (stage_egl->wrapper));
}
static void
clutter_stage_egl_unrealize (ClutterStageWindow *stage_window)
{
}
static gboolean
clutter_stage_egl_realize (ClutterStageWindow *stage_window)
{
/* the EGL surface is created by the backend */
return TRUE;
}
static void
clutter_stage_egl_get_geometry (ClutterStageWindow *stage_window,
ClutterGeometry *geometry)
@ -113,22 +273,94 @@ clutter_stage_egl_resize (ClutterStageWindow *stage_window,
{
}
#endif /* COGL_HAS_XLIB_SUPPORT */
static void
clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
{
#ifdef COGL_HAS_X11_SUPPORT
clutter_stage_egl_parent_iface = g_type_interface_peek_parent (iface);
iface->realize = clutter_stage_egl_realize;
iface->unrealize = clutter_stage_egl_unrealize;
/* the rest is inherited from ClutterStageX11 */
#else /* COGL_HAS_X11_SUPPORT */
iface->realize = clutter_stage_egl_realize;
iface->unrealize = clutter_stage_egl_unrealize;
iface->set_fullscreen = clutter_stage_egl_set_fullscreen;
iface->set_title = clutter_stage_egl_set_title;
iface->set_cursor_visible = clutter_stage_egl_set_cursor_visible;
iface->get_wrapper = clutter_stage_egl_get_wrapper;
iface->realize = clutter_stage_egl_realize;
iface->unrealize = clutter_stage_egl_unrealize;
iface->get_geometry = clutter_stage_egl_get_geometry;
iface->resize = clutter_stage_egl_resize;
iface->show = clutter_stage_egl_show;
iface->hide = clutter_stage_egl_hide;
#endif /* COGL_HAS_X11_SUPPORT */
}
#ifdef COGL_HAS_X11_SUPPORT
static void
clutter_stage_egl_dispose (GObject *gobject)
{
G_OBJECT_CLASS (clutter_stage_egl_parent_class)->dispose (gobject);
}
static void
clutter_stage_egl_class_init (ClutterStageEGLClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = clutter_stage_egl_dispose;
}
static void
clutter_stage_egl_init (ClutterStageEGL *stage)
{
stage->egl_surface = EGL_NO_SURFACE;
}
#else /* COGL_HAS_X11_SUPPORT */
static void
clutter_stage_egl_class_init (ClutterStageEGLClass *klass)
{
}
static void
clutter_stage_egl_init (ClutterStageEGL *stage)
{
/* Without X we only support one surface and that is associated
* with the backend directly instead of the stage */
}
#endif /* COGL_HAS_X11_SUPPORT */
void
clutter_stage_egl_redraw (ClutterStageEGL *stage_egl,
ClutterStage *stage)
{
ClutterBackend *backend = clutter_get_default_backend ();
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterActor *wrapper;
EGLSurface egl_surface;
#ifdef COGL_HAS_X11_SUPPORT
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_egl);
wrapper = CLUTTER_ACTOR (stage_x11->wrapper);
egl_surface = stage_egl->egl_surface;
#else
wrapper = CLUTTER_ACTOR (stage_egl->wrapper);
/* Without X we only support one surface and that is associated
* with the backend directly instead of the stage */
egl_surface = backend_egl->egl_surface;
#endif
clutter_actor_paint (wrapper);
cogl_flush ();
eglSwapBuffers (backend_egl->edpy, egl_surface);
}

View File

@ -35,4 +35,7 @@ struct _ClutterStageEGLClass
GType clutter_stage_egl_get_type (void) G_GNUC_CONST;
void clutter_stage_egl_redraw (ClutterStageEGL *stage_egl,
ClutterStage *stage);
#endif /* __CLUTTER_STAGE_EGL_H__ */

View File

@ -1,9 +1,45 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
* Authors:
* Matthew Allum
* Emmanuele Bassi
* Robert Bragg
* Neil Roberts
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "clutter-backend-egl.h"
#include "clutter-stage-egl.h"
#include "clutter-eglx.h"
#include "../clutter-private.h"
#include "../clutter-main.h"
#include "../clutter-debug.h"
@ -11,7 +47,13 @@
static ClutterBackendEGL *backend_singleton = NULL;
static const gchar *clutter_fb_device = NULL;
#ifdef COGL_HAS_X11_SUPPORT
G_DEFINE_TYPE (ClutterBackendEGL, clutter_backend_egl, CLUTTER_TYPE_BACKEND_X11);
#else
G_DEFINE_TYPE (ClutterBackendEGL, clutter_backend_egl, CLUTTER_TYPE_BACKEND);
#endif
static void
clutter_backend_at_exit (void)
@ -20,34 +62,67 @@ clutter_backend_at_exit (void)
g_object_run_dispose (G_OBJECT (backend_singleton));
}
static gboolean
clutter_backend_egl_pre_parse (ClutterBackend *backend,
GError **error)
{
const gchar *env_string;
#ifdef COGL_HAS_X11_SUPPORT
ClutterBackendClass *backend_x11_class =
CLUTTER_BACKEND_CLASS (clutter_backend_egl_parent_class);
if (!backend_x11_class->pre_parse (backend, error))
return FALSE;
#endif
env_string = g_getenv ("CLUTTER_FB_DEVICE");
if (env_string != NULL && env_string[0] != '\0')
clutter_fb_device = g_strdup (env_string);
return TRUE;
}
static gboolean
clutter_backend_egl_post_parse (ClutterBackend *backend,
GError **error)
{
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
#ifdef COGL_HAS_X11_SUPPORT
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterBackendClass *backend_x11_class =
CLUTTER_BACKEND_CLASS (clutter_backend_egl_parent_class);
#endif
EGLBoolean status;
if (clutter_backend_x11_post_parse (backend, error))
#ifdef COGL_HAS_X11_SUPPORT
if (!backend_x11_class->post_parse (backend, error))
return FALSE;
#ifndef COGL_HAS_XLIB_SUPPORT
#error "Clutter's EGL on X11 support currently only works with xlib Displays"
#endif
backend_egl->edpy =
eglGetDisplay ((NativeDisplayType) backend_x11->xdpy);
status = eglInitialize (backend_egl->edpy,
&backend_egl->egl_version_major,
&backend_egl->egl_version_minor);
#else
backend_egl->edpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
status = eglInitialize (backend_egl->edpy,
&backend_egl->egl_version_major,
&backend_egl->egl_version_minor);
#endif
g_atexit (clutter_backend_at_exit);
if (status != EGL_TRUE)
{
EGLBoolean status;
backend_egl->edpy =
eglGetDisplay ((NativeDisplayType) backend_x11->xdpy);
status = eglInitialize (backend_egl->edpy,
&backend_egl->egl_version_major,
&backend_egl->egl_version_minor);
g_atexit (clutter_backend_at_exit);
if (status != EGL_TRUE)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Unable to Initialize EGL");
return FALSE;
}
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Unable to Initialize EGL");
return FALSE;
}
CLUTTER_NOTE (BACKEND, "EGL Reports version %i.%i",
@ -61,45 +136,54 @@ static gboolean
clutter_backend_egl_create_context (ClutterBackend *backend,
GError **error)
{
ClutterBackendEGL *backend_egl;
ClutterBackendX11 *backend_x11;
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
#ifdef COGL_HAS_X11_SUPPORT
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
#endif
EGLConfig config;
EGLint config_count = 0;
EGLBoolean status;
EGLint cfg_attribs[] = {
/* NB: This must be the first attribute, since we may
* try and fallback to no stencil buffer */
EGL_STENCIL_SIZE, 8,
EGL_STENCIL_SIZE, 2,
EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 6,
EGL_BLUE_SIZE, 5,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_ALPHA_SIZE, EGL_DONT_CARE,
EGL_BUFFER_SIZE, EGL_DONT_CARE,
EGL_DEPTH_SIZE, 1,
#ifdef HAVE_COGL_GLES2
EGL_BUFFER_SIZE, EGL_DONT_CARE,
#if defined (HAVE_COGL_GLES2)
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
#else /* HAVE_COGL_GLES2 */
#else
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
#endif
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
#endif /* HAVE_COGL_GLES2 */
EGL_NONE
};
EGLDisplay edpy;
gint retry_cookie = 0;
const char *error_message = NULL;
#ifdef COGL_HAS_XLIB_SUPPORT
XVisualInfo *xvisinfo;
XSetWindowAttributes attrs;
backend = clutter_get_default_backend ();
backend_egl = CLUTTER_BACKEND_EGL (backend);
#endif
if (backend_egl->egl_context != EGL_NO_CONTEXT)
return TRUE;
backend_x11 = CLUTTER_BACKEND_X11 (backend);
edpy = clutter_eglx_display ();
/* XXX: we should get rid of this goto yukkyness, there is a fail:
* goto at the end and this retry: goto at the top, but we should just
* have a try_create_context() function and call it in a loop that
* tries a different fallback each iteration */
retry:
/* Here we can change the attributes depending on the fallback count... */
@ -118,37 +202,41 @@ retry:
&config_count);
if (status != EGL_TRUE || config_count == 0)
{
g_warning ("eglChooseConfig failed");
error_message = "Unable to select a valid EGL configuration";
goto fail;
}
if (G_UNLIKELY (backend_egl->egl_context == EGL_NO_CONTEXT))
if (backend_egl->egl_context == EGL_NO_CONTEXT)
{
#ifdef HAVE_COGL_GLES2
static const EGLint attribs[3]
= { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
static const EGLint attribs[] =
{ EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
backend_egl->egl_context = eglCreateContext (edpy,
config,
EGL_NO_CONTEXT,
attribs);
#else
/* Seems some GLES implementations 1.x do not like attribs... */
backend_egl->egl_context = eglCreateContext (edpy,
config,
EGL_NO_CONTEXT,
NULL);
#endif
if (backend_egl->egl_context == EGL_NO_CONTEXT)
{
g_warning ("Unable to create a suitable EGL context");
error_message = "Unable to create a suitable EGL context";
goto fail;
}
#ifdef COGL_HAS_XLIB_SUPPORT
backend_egl->egl_config = config;
#endif
CLUTTER_NOTE (GL, "Created EGL Context");
}
#ifdef COGL_HAS_XLIB_SUPPORT
/* COGL assumes that there is always a GL context selected; in order
* to make sure that an EGL context exists and is made current, we use
* a dummy, offscreen override-redirect window to which we can always
@ -199,6 +287,80 @@ retry:
backend_egl->dummy_surface,
backend_egl->egl_context);
#else /* COGL_HAS_XLIB_SUPPORT */
if (clutter_fb_device != NULL)
{
int fd = open (clutter_fb_device, O_RDWR);
if (fd < 0)
{
int errno_save = errno;
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Unable to open the framebuffer device '%s': %s",
clutter_fb_device,
g_strerror (errno_save));
return FALSE;
}
else
backend_egl->fb_device_id = fd;
backend_egl->egl_surface =
eglCreateWindowSurface (edpy,
config,
(NativeWindowType) backend_egl->fb_device_id,
NULL);
}
else
{
backend_egl->egl_surface =
eglCreateWindowSurface (edpy,
config,
(NativeWindowType) NULL,
NULL);
}
if (backend_egl->egl_surface == EGL_NO_SURFACE)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Unable to create EGL window surface");
return FALSE;
}
CLUTTER_NOTE (BACKEND, "Setting context");
/* Without X we assume we can have only one stage, so we
* store the EGL surface in the backend itself, instead
* of the StageWindow implementation, and we make it
* current immediately to make sure the Cogl and Clutter
* can query the EGL context for features.
*/
status = eglMakeCurrent (backend_egl->edpy,
backend_egl->egl_surface,
backend_egl->egl_surface,
backend_egl->egl_context);
eglQuerySurface (backend_egl->edpy,
backend_egl->egl_surface,
EGL_WIDTH,
&backend_egl->surface_width);
eglQuerySurface (backend_egl->edpy,
backend_egl->egl_surface,
EGL_HEIGHT,
&backend_egl->surface_height);
CLUTTER_NOTE (BACKEND, "EGL surface is %ix%i",
backend_egl->surface_width,
backend_egl->surface_height);
#endif /* COGL_HAS_XLIB_SUPPORT */
return TRUE;
fail:
@ -210,6 +372,10 @@ fail:
goto retry;
}
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"%s", error_message);
return FALSE;
}
@ -217,6 +383,11 @@ static void
clutter_backend_egl_ensure_context (ClutterBackend *backend,
ClutterStage *stage)
{
#ifndef COGL_HAS_XLIB_SUPPORT
/* Without X we only have one EGL surface to worry about
* so we can assume it is permanently made current and
* don't have to do anything here. */
#else
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterStageWindow *impl;
@ -283,6 +454,7 @@ clutter_backend_egl_ensure_context (ClutterBackend *backend,
"EGLX drawable",
(int) stage_x11->xwin);
}
#endif /* COGL_HAS_XLIB_SUPPORT */
}
static void
@ -300,6 +472,15 @@ clutter_backend_egl_redraw (ClutterBackend *backend,
clutter_stage_egl_redraw (CLUTTER_STAGE_EGL (impl), stage);
}
#ifdef HAVE_TSLIB
static void
clutter_backend_egl_init_events (ClutterBackend *backend)
{
/* XXX: This should be renamed to _clutter_events_tslib_init */
_clutter_events_egl_init (CLUTTER_BACKEND_EGL (backend));
}
#endif
static void
clutter_backend_egl_finalize (GObject *gobject)
{
@ -313,7 +494,11 @@ static void
clutter_backend_egl_dispose (GObject *gobject)
{
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (gobject);
#ifdef COGL_HAS_X11_SUPPORT
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (gobject);
#else
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (backend_egl->stage);
#endif
/* We chain up before disposing our own resources so that
ClutterBackendX11 will destroy all of the stages before we
@ -321,6 +506,12 @@ clutter_backend_egl_dispose (GObject *gobject)
calls during destruction which causes a crash */
G_OBJECT_CLASS (clutter_backend_egl_parent_class)->dispose (gobject);
#ifdef HAVE_TSLIB
/* XXX: This should be renamed to _clutter_events_tslib_uninit */
_clutter_events_egl_uninit (backend_egl);
#endif
#ifdef COGL_HAS_XLIB_SUPPORT
if (backend_egl->dummy_surface != EGL_NO_SURFACE)
{
eglDestroySurface (backend_egl->edpy, backend_egl->dummy_surface);
@ -333,6 +524,28 @@ clutter_backend_egl_dispose (GObject *gobject)
backend_egl->dummy_xwin = None;
}
#else /* COGL_HAS_XLIB_SUPPORT */
if (backend_egl->egl_surface != EGL_NO_SURFACE)
{
eglDestroySurface (backend_egl->edpy, backend_egl->egl_surface);
backend_egl->egl_surface = EGL_NO_SURFACE;
}
if (backend_egl->stage != NULL)
{
clutter_actor_destroy (CLUTTER_ACTOR (stage_egl->wrapper));
backend_egl->stage = NULL;
}
if (backend_egl->fb_device_id != -1)
{
close (backend_egl->fb_device_id);
backend_egl->fb_device_id = -1;
}
#endif /* COGL_HAS_XLIB_SUPPORT */
if (backend_egl->egl_context)
{
eglDestroyContext (backend_egl->edpy, backend_egl->egl_context);
@ -344,6 +557,14 @@ clutter_backend_egl_dispose (GObject *gobject)
eglTerminate (backend_egl->edpy);
backend_egl->edpy = 0;
}
#ifdef HAVE_TSLIB
if (backend_egl->event_timer != NULL)
{
g_timer_destroy (backend_egl->event_timer);
backend_egl->event_timer = NULL;
}
#endif
}
static GObject *
@ -376,8 +597,14 @@ clutter_backend_egl_get_features (ClutterBackend *backend)
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterFeatureFlags flags;
g_assert (backend_egl->egl_context != NULL);
#ifdef COGL_HAS_XLIB_SUPPORT
flags = clutter_backend_x11_get_features (backend);
flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
#else
flags = CLUTTER_FEATURE_STAGE_STATIC;
#endif
CLUTTER_NOTE (BACKEND, "Checking features\n"
"GL_VENDOR: %s\n"
@ -401,27 +628,53 @@ clutter_backend_egl_create_stage (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error)
{
#ifdef COGL_HAS_XLIB_SUPPORT
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterStageX11 *stage_x11;
ClutterStageWindow *stage;
ClutterStageX11 *stage_x11;
CLUTTER_NOTE (BACKEND, "Creating stage of type '%s'",
g_type_name (CLUTTER_STAGE_TYPE));
stage = g_object_new (CLUTTER_TYPE_STAGE_EGL, NULL);
/* copy backend data into the stage */
stage_x11 = CLUTTER_STAGE_X11 (stage);
stage_x11->wrapper = wrapper;
CLUTTER_NOTE (MISC, "EGLX stage created (display:%p, screen:%d, root:%u)",
backend_x11->xdpy,
backend_x11->xscreen_num,
(unsigned int) backend_x11->xwin_root);
#else /* COGL_HAS_XLIB_SUPPORT */
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterStageWindow *stage;
ClutterStageEGL *stage_egl;
if (G_UNLIKELY (backend_egl->stage != NULL))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"The EGL native backend does not support multiple stages");
return backend_egl->stage;
}
stage = g_object_new (CLUTTER_TYPE_STAGE_EGL, NULL);
stage_egl = CLUTTER_STAGE_EGL (stage);
stage_egl->backend = backend_egl;
stage_egl->wrapper = wrapper;
backend_egl->stage = stage;
#endif /* COGL_HAS_XLIB_SUPPORT */
return stage;
}
#ifdef COGL_HAS_XLIB_SUPPORT
static XVisualInfo *
clutter_backend_egl_get_visual_info (ClutterBackendX11 *backend_x11)
{
@ -471,32 +724,59 @@ clutter_backend_egl_get_visual_info (ClutterBackendX11 *backend_x11)
return visinfo;
}
#endif
static void
clutter_backend_egl_class_init (ClutterBackendEGLClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
#ifdef COGL_HAS_X11_SUPPORT
ClutterBackendX11Class *backendx11_class = CLUTTER_BACKEND_X11_CLASS (klass);
#endif
gobject_class->constructor = clutter_backend_egl_constructor;
gobject_class->dispose = clutter_backend_egl_dispose;
gobject_class->finalize = clutter_backend_egl_finalize;
backend_class->post_parse = clutter_backend_egl_post_parse;
backend_class->redraw = clutter_backend_egl_redraw;
backend_class->get_features = clutter_backend_egl_get_features;
backend_class->create_stage = clutter_backend_egl_create_stage;
backend_class->ensure_context = clutter_backend_egl_ensure_context;
backend_class->create_context = clutter_backend_egl_create_context;
backend_class->pre_parse = clutter_backend_egl_pre_parse;
backend_class->post_parse = clutter_backend_egl_post_parse;
backend_class->get_features = clutter_backend_egl_get_features;
#ifdef HAVE_TSLIB
backend_class->init_events = clutter_backend_egl_init_events;
#endif
backend_class->create_stage = clutter_backend_egl_create_stage;
backend_class->create_context = clutter_backend_egl_create_context;
backend_class->ensure_context = clutter_backend_egl_ensure_context;
backend_class->redraw = clutter_backend_egl_redraw;
#ifdef COGL_HAS_XLIB_SUPPORT
backendx11_class->get_visual_info = clutter_backend_egl_get_visual_info;
#endif
}
static void
clutter_backend_egl_init (ClutterBackendEGL *backend_egl)
{
#ifndef COGL_HAS_XLIB_SUPPORT
ClutterBackend *backend = CLUTTER_BACKEND (backend_egl);
clutter_backend_set_resolution (backend, 96.0);
clutter_backend_set_double_click_time (backend, 250);
clutter_backend_set_double_click_distance (backend, 5);
#ifdef HAVE_TSLIB
backend_egl->event_timer = g_timer_new ();
#endif
backend_egl->fb_device_id = -1;
#else
backend_egl->egl_context = EGL_NO_CONTEXT;
backend_egl->dummy_surface = EGL_NO_SURFACE;
#endif
}
GType
@ -505,12 +785,13 @@ _clutter_backend_impl_get_type (void)
return clutter_backend_egl_get_type ();
}
#ifdef COGL_HAS_XLIB_SUPPORT
/**
* clutter_eglx_display:
*
* Gets the current EGLDisplay.
* Retrieves the <structname>EGLDisplay</structname> used by Clutter
*
* Return value: an EGLDisplay
* Return value: the EGL display
*
* Since: 0.4
*/
@ -519,3 +800,18 @@ clutter_eglx_display (void)
{
return backend_singleton->edpy;
}
#endif /* COGL_HAS_XLIB_SUPPORT */
/**
* clutter_egl_display:
*
* Retrieves the <structname>EGLDisplay</structname> used by Clutter
*
* Return value: the EGL display
*/
EGLDisplay
clutter_egl_display (void)
{
return backend_singleton->edpy;
}

View File

@ -1,7 +1,8 @@
/* Clutter.
* An OpenGL based 'interactive canvas' library.
* Authored By Matthew Allum <mallum@openedhand.com>
* Copyright (C) 2006-2007 OpenedHand
*
* Copyright (C) 2006, 2007 OpenedHand
* Copyright (C) 2010 Intel Corp
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -16,7 +17,9 @@
* 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
*/
#ifndef __CLUTTER_BACKEND_EGL_H__
@ -25,12 +28,17 @@
#include <glib-object.h>
#include <clutter/clutter-event.h>
#include <clutter/clutter-backend.h>
#ifdef COGL_HAS_XLIB_SUPPORT
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#endif
#include "clutter-egl-headers.h"
#ifdef COGL_HAS_X11_SUPPORT
#include "../x11/clutter-backend-x11.h"
#endif
#include "clutter-eglx.h"
G_BEGIN_DECLS
@ -47,27 +55,62 @@ typedef struct _ClutterBackendEGLClass ClutterBackendEGLClass;
struct _ClutterBackendEGL
{
#ifdef COGL_HAS_XLIB_SUPPORT
ClutterBackendX11 parent_instance;
/* EGL Specific */
EGLDisplay edpy;
EGLContext egl_context;
EGLConfig egl_config;
Window dummy_xwin;
EGLSurface dummy_surface;
#else /* COGL_HAS_X11_SUPPORT */
ClutterBackend parent_instance;
/* EGL Specific */
EGLDisplay edpy;
EGLSurface egl_surface;
EGLContext egl_context;
/* from the backend */
gint surface_width;
gint surface_height;
/* main stage singleton */
ClutterStageWindow *stage;
/* event source */
GSource *event_source;
/* event timer */
GTimer *event_timer;
/* FB device */
gint fb_device_id;
#endif /* COGL_HAS_X11_SUPPORT */
gint egl_version_major;
gint egl_version_minor;
};
struct _ClutterBackendEGLClass
{
#ifdef COGL_HAS_XLIB_SUPPORT
ClutterBackendX11Class parent_class;
#else
ClutterBackendClass parent_class;
#endif
};
GType clutter_backend_egl_get_type (void) G_GNUC_CONST;
void _clutter_events_egl_init (ClutterBackendEGL *backend);
void _clutter_events_egl_uninit (ClutterBackendEGL *backend);
G_END_DECLS
#endif /* __CLUTTER_BACKEND_EGL_H__ */

View File

@ -2,9 +2,9 @@
#include "config.h"
#endif
#include "clutter-backend-egl.h"
#include "clutter-stage-egl.h"
#include "clutter-eglx.h"
#include "clutter-backend-egl.h"
#include "../clutter-main.h"
#include "../clutter-feature.h"
@ -15,20 +15,27 @@
#include "../clutter-private.h"
#include "../clutter-debug.h"
#include "../clutter-units.h"
#include "../clutter-container.h"
#include "../clutter-stage.h"
#include "../clutter-stage-window.h"
#ifdef COGL_HAS_X11_SUPPORT
static ClutterStageWindowIface *clutter_stage_egl_parent_iface = NULL;
#endif
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterStageEGL,
clutter_stage_egl,
#ifdef COGL_HAS_X11_SUPPORT
CLUTTER_TYPE_STAGE_X11,
#else
G_TYPE_OBJECT,
#endif
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
clutter_stage_window_iface_init));
#ifdef COGL_HAS_XLIB_SUPPORT
static void
clutter_stage_egl_unrealize (ClutterStageWindow *stage_window)
{
@ -182,21 +189,124 @@ clutter_stage_egl_realize (ClutterStageWindow *stage_window)
return clutter_stage_egl_parent_iface->realize (stage_window);
}
#else /* COGL_HAS_XLIB_SUPPORT */
static void
clutter_stage_egl_dispose (GObject *gobject)
clutter_stage_egl_unrealize (ClutterStageWindow *stage_window)
{
G_OBJECT_CLASS (clutter_stage_egl_parent_class)->dispose (gobject);
}
static gboolean
clutter_stage_egl_realize (ClutterStageWindow *stage_window)
{
/* the EGL surface is created by the backend */
return TRUE;
}
static void
clutter_stage_egl_set_fullscreen (ClutterStageWindow *stage_window,
gboolean fullscreen)
{
g_warning ("Stage of type '%s' do not support ClutterStage::set_fullscreen",
G_OBJECT_TYPE_NAME (stage_window));
}
static void
clutter_stage_egl_set_title (ClutterStageWindow *stage_window,
const gchar *title)
{
g_warning ("Stage of type '%s' do not support ClutterStage::set_title",
G_OBJECT_TYPE_NAME (stage_window));
}
static void
clutter_stage_egl_set_cursor_visible (ClutterStageWindow *stage_window,
gboolean cursor_visible)
{
g_warning ("Stage of type '%s' do not support ClutterStage::set_cursor_visible",
G_OBJECT_TYPE_NAME (stage_window));
}
static ClutterActor *
clutter_stage_egl_get_wrapper (ClutterStageWindow *stage_window)
{
return CLUTTER_ACTOR (CLUTTER_STAGE_EGL (stage_window)->wrapper);
}
static void
clutter_stage_egl_show (ClutterStageWindow *stage_window,
gboolean do_raise)
{
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window);
clutter_actor_map (CLUTTER_ACTOR (stage_egl->wrapper));
}
static void
clutter_stage_egl_hide (ClutterStageWindow *stage_window)
{
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window);
clutter_actor_unmap (CLUTTER_ACTOR (stage_egl->wrapper));
}
static void
clutter_stage_egl_get_geometry (ClutterStageWindow *stage_window,
ClutterGeometry *geometry)
{
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window);
ClutterBackendEGL *backend_egl = stage_egl->backend;
if (geometry)
{
geometry->x = geometry->y = 0;
geometry->width = backend_egl->surface_width;
geometry->height = backend_egl->surface_height;
}
}
static void
clutter_stage_egl_resize (ClutterStageWindow *stage_window,
gint width,
gint height)
{
}
#endif /* COGL_HAS_XLIB_SUPPORT */
static void
clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
{
#ifdef COGL_HAS_X11_SUPPORT
clutter_stage_egl_parent_iface = g_type_interface_peek_parent (iface);
iface->realize = clutter_stage_egl_realize;
iface->unrealize = clutter_stage_egl_unrealize;
/* the rest is inherited from ClutterStageX11 */
#else /* COGL_HAS_X11_SUPPORT */
iface->realize = clutter_stage_egl_realize;
iface->unrealize = clutter_stage_egl_unrealize;
iface->set_fullscreen = clutter_stage_egl_set_fullscreen;
iface->set_title = clutter_stage_egl_set_title;
iface->set_cursor_visible = clutter_stage_egl_set_cursor_visible;
iface->get_wrapper = clutter_stage_egl_get_wrapper;
iface->get_geometry = clutter_stage_egl_get_geometry;
iface->resize = clutter_stage_egl_resize;
iface->show = clutter_stage_egl_show;
iface->hide = clutter_stage_egl_hide;
#endif /* COGL_HAS_X11_SUPPORT */
}
#ifdef COGL_HAS_X11_SUPPORT
static void
clutter_stage_egl_dispose (GObject *gobject)
{
G_OBJECT_CLASS (clutter_stage_egl_parent_class)->dispose (gobject);
}
static void
@ -213,24 +323,44 @@ clutter_stage_egl_init (ClutterStageEGL *stage)
stage->egl_surface = EGL_NO_SURFACE;
}
#else /* COGL_HAS_X11_SUPPORT */
static void
clutter_stage_egl_class_init (ClutterStageEGLClass *klass)
{
}
static void
clutter_stage_egl_init (ClutterStageEGL *stage)
{
/* Without X we only support one surface and that is associated
* with the backend directly instead of the stage */
}
#endif /* COGL_HAS_X11_SUPPORT */
void
clutter_stage_egl_redraw (ClutterStageEGL *stage_egl,
ClutterStage *stage)
{
ClutterBackend *backend = clutter_get_default_backend ();
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterActor *wrapper;
EGLSurface egl_surface;
#ifdef COGL_HAS_X11_SUPPORT
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_egl);
ClutterStageWindow *impl;
impl = _clutter_stage_get_window (stage);
if (impl == NULL)
return;
wrapper = CLUTTER_ACTOR (stage_x11->wrapper);
egl_surface = stage_egl->egl_surface;
#else
wrapper = CLUTTER_ACTOR (stage_egl->wrapper);
/* Without X we only support one surface and that is associated
* with the backend directly instead of the stage */
egl_surface = backend_egl->egl_surface;
#endif
g_assert (CLUTTER_IS_STAGE_EGL (impl));
stage_egl = CLUTTER_STAGE_EGL (impl);
clutter_actor_paint (CLUTTER_ACTOR (stage_x11->wrapper));
clutter_actor_paint (wrapper);
cogl_flush ();
eglSwapBuffers (backend_egl->edpy, stage_egl->egl_surface);
eglSwapBuffers (backend_egl->edpy, egl_surface);
}