Moves all EGL code down from Clutter to Cogl

As was recently done for the GLX window system code, this commit moves
the EGL window system code down from the Clutter backend code into a
Cogl winsys.

Note: currently the cogl/configure.ac is hard coded to only build the GLX
winsys so currently this is only available when building Cogl as part
of Clutter.
This commit is contained in:
Robert Bragg 2011-02-25 00:31:41 +00:00
parent ce0dc2160c
commit c55cffbb6b
17 changed files with 1467 additions and 1300 deletions

View File

@ -471,8 +471,6 @@ evdev_h_priv = \
$(srcdir)/evdev/clutter-input-device-evdev.h \ $(srcdir)/evdev/clutter-input-device-evdev.h \
$(NULL) $(NULL)
egl_cex_c_priv = $(srcdir)/egl/clutter-backend-cex100.c
egl_cex_h_priv = $(srcdir)/egl/clutter-backend-cex100.h
egl_cex_h = $(srcdir)/egl/clutter-cex100.h egl_cex_h = $(srcdir)/egl/clutter-cex100.h
if SUPPORT_EGL if SUPPORT_EGL
@ -487,8 +485,6 @@ egl_source_h_priv += $(evdev_h_priv)
endif # SUPPORT_EVDEV endif # SUPPORT_EVDEV
if SUPPORT_CEX100 if SUPPORT_CEX100
egl_source_c_priv += $(egl_cex_c_priv)
egl_source_h_priv += $(egl_cex_h_priv)
egl_source_h += $(egl_cex_h) egl_source_h += $(egl_cex_h)
endif # SUPPORT_CEX100 endif # SUPPORT_CEX100

View File

@ -332,18 +332,15 @@ cogl_sources_c += \
endif endif
if SUPPORT_EGL_PLATFORM_POWERVR_X11 if SUPPORT_EGL_PLATFORM_POWERVR_X11
cogl_sources_c += \ cogl_sources_c += \
$(srcdir)/winsys/cogl-winsys-egl.c \ $(srcdir)/winsys/cogl-winsys-egl.c
$(srcdir)/winsys/cogl-winsys-stub.c
endif endif
if SUPPORT_EGL_PLATFORM_POWERVR_NULL if SUPPORT_EGL_PLATFORM_POWERVR_NULL
cogl_sources_c += \ cogl_sources_c += \
$(srcdir)/winsys/cogl-winsys-egl.c \ $(srcdir)/winsys/cogl-winsys-egl.c
$(srcdir)/winsys/cogl-winsys-stub.c
endif endif
if SUPPORT_EGL_PLATFORM_POWERVR_GDL if SUPPORT_EGL_PLATFORM_POWERVR_GDL
cogl_sources_c += \ cogl_sources_c += \
$(srcdir)/winsys/cogl-winsys-egl.c \ $(srcdir)/winsys/cogl-winsys-egl.c
$(srcdir)/winsys/cogl-winsys-stub.c
endif endif
if SUPPORT_WIN32 if SUPPORT_WIN32
cogl_sources_c += \ cogl_sources_c += \

View File

@ -475,3 +475,12 @@ cogl_set_default_context (CoglContext *context)
cogl_object_unref (_context); cogl_object_unref (_context);
_context = context; _context = context;
} }
#ifdef COGL_HAS_EGL_SUPPORT
EGLDisplay
cogl_context_egl_get_egl_display (CoglContext *context)
{
return _cogl_winsys_context_egl_get_egl_display (context);
}
#endif

View File

@ -33,6 +33,17 @@
#include <cogl/cogl-display.h> #include <cogl/cogl-display.h>
#ifdef COGL_HAS_EGL_SUPPORT
#ifdef COGL_HAS_GLES1
#include <GLES/gl.h>
#include <GLES/egl.h>
#else
#include <EGL/egl.h>
#define NativeDisplayType EGLNativeDisplayType
#define NativeWindowType EGLNativeWindowType
#endif
#endif
G_BEGIN_DECLS G_BEGIN_DECLS
/** /**
@ -61,6 +72,12 @@ cogl_context_new (CoglDisplay *display,
void void
cogl_set_default_context (CoglContext *context); cogl_set_default_context (CoglContext *context);
#ifdef COGL_HAS_EGL_SUPPORT
#define cogl_context_egl_get_egl_display cogl_context_egl_get_egl_display_EXP
EGLDisplay
cogl_context_egl_get_egl_display (CoglContext *context);
#endif
G_END_DECLS G_END_DECLS
#endif /* __COGL_CONTEXT_H__ */ #endif /* __COGL_CONTEXT_H__ */

View File

@ -0,0 +1,57 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2010 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*
*/
/* This can be included multiple times with different definitions for
* the COGL_WINSYS_FEATURE_* functions.
*/
/* Macro prototypes:
* COGL_WINSYS_FEATURE_BEGIN (name, namespaces, extension_names,
* implied_public_feature_flags,
* implied_private_feature_flags,
* implied_winsys_feature)
* COGL_WINSYS_FEATURE_FUNCTION (return_type, function_name,
* (arguments))
* ...
* COGL_WINSYS_FEATURE_END ()
*
* Note: You can list multiple namespace and extension names if the
* corresponding _FEATURE_FUNCTIONS have the same semantics accross
* the different extension variants.
*
* XXX: NB: Don't add a trailing semicolon when using these macros
*/
COGL_WINSYS_FEATURE_BEGIN (swap_region,
"NOK\0",
"swap_region\0",
0,
0,
COGL_WINSYS_FEATURE_SWAP_REGION)
COGL_WINSYS_FEATURE_FUNCTION (EGLBoolean, eglSwapBuffersRegion,
(EGLDisplay dpy,
EGLSurface surface,
EGLint numRects,
const EGLint *rects))
COGL_WINSYS_FEATURE_END ()

File diff suppressed because it is too large Load Diff

View File

@ -71,6 +71,11 @@ _cogl_winsys_context_init (CoglContext *context, GError **error);
void void
_cogl_winsys_context_deinit (CoglContext *context); _cogl_winsys_context_deinit (CoglContext *context);
#ifdef COGL_HAS_EGL_SUPPORT
EGLDisplay
_cogl_winsys_context_egl_get_egl_display (CoglContext *context);
#endif
gboolean gboolean
_cogl_winsys_has_feature (CoglWinsysFeature feature); _cogl_winsys_has_feature (CoglWinsysFeature feature);

View File

@ -1,369 +0,0 @@
/*
* 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:
* Tao Zhao <tao.zhao@intel.com>
* Damien Lespiau <damien.lespiau@intel.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "clutter-debug.h"
#include "clutter-main.h"
#include "clutter-backend-cex100.h"
#include "clutter-cex100.h"
static gdl_plane_id_t gdl_plane = GDL_PLANE_ID_UPP_C;
static guint gdl_n_buffers = CLUTTER_CEX100_TRIPLE_BUFFERING;
G_DEFINE_TYPE (ClutterBackendCex100,
clutter_backend_cex100,
CLUTTER_TYPE_BACKEND_EGL)
#ifdef CLUTTER_ENABLE_DEBUG
static const gchar *
gdl_get_plane_name (gdl_plane_id_t plane)
{
switch (plane)
{
case GDL_PLANE_ID_UPP_A:
return "UPP_A";
case GDL_PLANE_ID_UPP_B:
return "UPP_B";
case GDL_PLANE_ID_UPP_C:
return "UPP_C";
case GDL_PLANE_ID_UPP_D:
return "UPP_D";
case GDL_PLANE_ID_UPP_E:
return "UPP_E";
default:
g_assert_not_reached ();
}
return NULL; /* never reached */
}
#endif
static gboolean
gdl_plane_init (gdl_display_id_t dpy,
gdl_plane_id_t plane,
gdl_pixel_format_t pixfmt)
{
gboolean ret = TRUE;
gdl_color_space_t colorSpace = GDL_COLOR_SPACE_RGB;
gdl_rectangle_t dstRect;
gdl_display_info_t display_info;
gdl_ret_t rc = GDL_SUCCESS;
if (GDL_DISPLAY_ID_0 != dpy && GDL_DISPLAY_ID_1 != dpy)
{
g_warning ("Invalid display ID, must be GDL_DISPLAY_ID_0 or "
"GDL_DISPLAY_ID_1.");
return FALSE;
}
/* Init GDL library */
rc = gdl_init (NULL);
if (rc != GDL_SUCCESS)
{
g_warning ("GDL initialize failed. %s", gdl_get_error_string (rc));
return FALSE;
}
rc = gdl_get_display_info (dpy, &display_info);
if (rc != GDL_SUCCESS)
{
g_warning ("GDL failed to get display infomation: %s",
gdl_get_error_string (rc));
gdl_close ();
return FALSE;
}
dstRect.origin.x = 0;
dstRect.origin.y = 0;
dstRect.width = display_info.tvmode.width;
dstRect.height = display_info.tvmode.height;
/* Configure the plane attribute. */
rc = gdl_plane_reset (plane);
if (rc == GDL_SUCCESS)
rc = gdl_plane_config_begin (plane);
if (rc == GDL_SUCCESS)
rc = gdl_plane_set_attr (GDL_PLANE_SRC_COLOR_SPACE, &colorSpace);
if (rc == GDL_SUCCESS)
rc = gdl_plane_set_attr (GDL_PLANE_PIXEL_FORMAT, &pixfmt);
if (rc == GDL_SUCCESS)
rc = gdl_plane_set_attr (GDL_PLANE_DST_RECT, &dstRect);
if (rc == GDL_SUCCESS)
rc = gdl_plane_set_uint (GDL_PLANE_NUM_GFX_SURFACES, gdl_n_buffers);
if (rc == GDL_SUCCESS)
rc = gdl_plane_config_end (GDL_FALSE);
else
gdl_plane_config_end (GDL_TRUE);
if (rc != GDL_SUCCESS)
{
g_warning ("GDL configuration failed: %s.", gdl_get_error_string (rc));
ret = FALSE;
}
gdl_close ();
return ret;
}
/*
* ClutterBackendEGL implementation
*/
static gboolean
clutter_backend_cex100_create_context (ClutterBackend *backend,
GError **error)
{
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
EGLConfig configs[2];
EGLint config_count;
EGLBoolean status;
NativeWindowType window;
EGLint cfg_attribs[] = {
EGL_BUFFER_SIZE, EGL_DONT_CARE,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_DEPTH_SIZE, 16,
EGL_ALPHA_SIZE, 8,
EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE,
EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE,
#ifdef HAVE_COGL_GLES2
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
#else /* HAVE_COGL_GLES2 */
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
#endif /* HAVE_COGL_GLES2 */
EGL_NONE
};
if (backend_egl->egl_context != EGL_NO_CONTEXT)
return TRUE;
CLUTTER_NOTE (BACKEND, "Using the %s plane", gdl_get_plane_name (gdl_plane));
/* Start by initializing the GDL plane */
if (!gdl_plane_init (GDL_DISPLAY_ID_0, gdl_plane, GDL_PF_ARGB_32))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Could not initialize the GDL plane");
return FALSE;
}
window = (NativeWindowType) gdl_plane;
status = eglGetConfigs (backend_egl->edpy,
configs,
2,
&config_count);
if (status != EGL_TRUE)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"No EGL configurations found");
return FALSE;
}
status = eglChooseConfig (backend_egl->edpy,
cfg_attribs,
configs,
G_N_ELEMENTS (configs),
&config_count);
if (status != EGL_TRUE)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Unable to select a valid EGL configuration");
return FALSE;
}
CLUTTER_NOTE (BACKEND, "Got %i configs", config_count);
if (status != EGL_TRUE)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Unable to Make Current Context for NULL");
return FALSE;
}
if (G_UNLIKELY (backend_egl->egl_surface != EGL_NO_SURFACE))
{
eglDestroySurface (backend_egl->edpy, backend_egl->egl_surface);
backend_egl->egl_surface = EGL_NO_SURFACE;
}
if (G_UNLIKELY (backend_egl->egl_context != NULL))
{
eglDestroyContext (backend_egl->edpy, backend_egl->egl_context);
backend_egl->egl_context = NULL;
}
backend_egl->egl_surface = eglCreateWindowSurface (backend_egl->edpy,
configs[0],
window,
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;
}
#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.
*/
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);
/*
* For EGL backend, it needs to clear all the back buffers of the window
* surface before drawing anything, otherwise the image will be blinking
* heavily. The default eglWindowSurface has 3 gdl surfaces as the back
* buffer, that's why glClear should be called 3 times.
*/
glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
glClear (GL_COLOR_BUFFER_BIT);
eglSwapBuffers (backend_egl->edpy, backend_egl->egl_surface);
glClear (GL_COLOR_BUFFER_BIT);
eglSwapBuffers (backend_egl->edpy, backend_egl->egl_surface);
glClear (GL_COLOR_BUFFER_BIT);
eglSwapBuffers (backend_egl->edpy, backend_egl->egl_surface);
return TRUE;
}
/*
* GObject implementation
*/
static void
clutter_backend_cex100_class_init (ClutterBackendCex100Class *klass)
{
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
backend_class->create_context = clutter_backend_cex100_create_context;
}
static void
clutter_backend_cex100_init (ClutterBackendCex100 *self)
{
}
/* every backend must implement this function */
GType
_clutter_backend_impl_get_type (void)
{
return clutter_backend_cex100_get_type ();
}
void
clutter_cex100_set_plane (gdl_plane_id_t plane)
{
g_return_if_fail (plane >= GDL_PLANE_ID_UPP_A && plane <= GDL_PLANE_ID_UPP_E);
gdl_plane = plane;
}
void
clutter_cex100_set_buffering_mode (ClutterCex100BufferingMode mode)
{
g_return_if_fail (mode == CLUTTER_CEX100_DOUBLE_BUFFERING ||
mode == CLUTTER_CEX100_TRIPLE_BUFFERING);
gdl_n_buffers = mode;
}

View File

@ -1,60 +0,0 @@
/*
* 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/>.
*
* Author:
* Damien Lespiau <damien.lespiau@intel.com>
*/
#ifndef __CLUTTER_BACKEND_CEX100_H__
#define __CLUTTER_BACKEND_CEX100_H__
#include <libgdl.h>
#include <glib-object.h>
#include <clutter/egl/clutter-backend-egl.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_BACKEND_CEX100 (clutter_backend_cex100_get_type())
#define CLUTTER_BACKEND_CEX100(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BACKEND_CEX100, ClutterBackendCex100))
#define CLUTTER_BACKEND_CEX100_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND_CEX100, ClutterBackendCex100Class))
#define CLUTTER_IS_BACKEND_CEX100(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BACKEND_CEX100))
#define CLUTTER_IS_BACKEND_CEX100_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BACKEND_CEX100))
#define CLUTTER_BACKEND_CEX100_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BACKEND_CEX100, ClutterBackendCex100Class))
typedef struct _ClutterBackendCex100 ClutterBackendCex100;
typedef struct _ClutterBackendCex100Class ClutterBackendCex100Class;
struct _ClutterBackendCex100
{
ClutterBackendEGL parent;
};
struct _ClutterBackendCex100Class
{
ClutterBackendEGLClass parent_class;
};
GType clutter_backend_cex100_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __CLUTTER_BACKEND_CEX100_H__ */

View File

@ -48,12 +48,20 @@
#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_PLATFORM_POWERVR_GDL_SUPPORT
#include "clutter-cex100.h"
#endif
static ClutterBackendEGL *backend_singleton = NULL; static ClutterBackendEGL *backend_singleton = NULL;
static const gchar *clutter_fb_device = NULL; static gchar *clutter_vblank = NULL;
static gchar *clutter_vblank_name = NULL; /* FIXME: We should have CLUTTER_ define for this... */
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_GDL_SUPPORT
static gdl_plane_id_t gdl_plane = GDL_PLANE_ID_UPP_C;
static guint gdl_n_buffers = CLUTTER_CEX100_TRIPLE_BUFFERING;
#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 (ClutterBackendEGL, _clutter_backend_egl, CLUTTER_TYPE_BACKEND_X11);
@ -68,30 +76,35 @@ clutter_backend_at_exit (void)
g_object_run_dispose (G_OBJECT (backend_singleton)); g_object_run_dispose (G_OBJECT (backend_singleton));
} }
G_CONST_RETURN gchar*
_clutter_backend_egl_get_vblank (void)
{
if (clutter_vblank && strcmp (clutter_vblank, "0") == 0)
return "none";
else
return clutter_vblank;
}
static gboolean static gboolean
clutter_backend_egl_pre_parse (ClutterBackend *backend, clutter_backend_egl_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 *backend_x11_class = ClutterBackendClass *parent_class =
CLUTTER_BACKEND_CLASS (_clutter_backend_egl_parent_class); CLUTTER_BACKEND_CLASS (_clutter_backend_egl_parent_class);
if (!backend_x11_class->pre_parse (backend, error)) if (!parent_class->pre_parse (backend, error))
return FALSE; return FALSE;
#endif #endif
env_string = g_getenv ("CLUTTER_VBLANK"); env_string = g_getenv ("CLUTTER_VBLANK");
if (env_string) if (env_string)
{ {
clutter_vblank_name = g_strdup (env_string); clutter_vblank = g_strdup (env_string);
env_string = NULL; env_string = NULL;
} }
env_string = g_getenv ("CLUTTER_FB_DEVICE");
if (env_string != NULL && env_string[0] != '\0')
clutter_fb_device = g_strdup (env_string);
return TRUE; return TRUE;
} }
@ -99,411 +112,21 @@ static gboolean
clutter_backend_egl_post_parse (ClutterBackend *backend, clutter_backend_egl_post_parse (ClutterBackend *backend,
GError **error) GError **error)
{ {
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
#ifdef COGL_HAS_X11_SUPPORT #ifdef COGL_HAS_X11_SUPPORT
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend); ClutterBackendClass *parent_class =
ClutterBackendClass *backend_x11_class =
CLUTTER_BACKEND_CLASS (_clutter_backend_egl_parent_class); CLUTTER_BACKEND_CLASS (_clutter_backend_egl_parent_class);
#endif
EGLBoolean status;
#ifdef COGL_HAS_X11_SUPPORT if (!parent_class->post_parse (backend, error))
if (!backend_x11_class->post_parse (backend, error))
return FALSE; return FALSE;
#ifndef COGL_HAS_XLIB_SUPPORT return TRUE;
#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 #endif
g_atexit (clutter_backend_at_exit); 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;
}
CLUTTER_NOTE (BACKEND, "EGL Reports version %i.%i",
backend_egl->egl_version_major,
backend_egl->egl_version_minor);
return TRUE; return TRUE;
} }
void
_clutter_backend_egl_blit_sub_buffer (ClutterBackendEGL *backend_egl,
EGLSurface drawable,
int x, int y, int width, int height)
{
if (backend_egl->swap_buffers_region)
{
EGLint rect[4] = {
x, y, width, height
};
backend_egl->swap_buffers_region (backend_egl->edpy,
drawable,
1,
rect);
}
#if 0 /* XXX need GL_ARB_draw_buffers */
else if (backend_egl->blit_framebuffer)
{
glDrawBuffer (GL_FRONT);
backend_egl->blit_framebuffer (x, y, x + width, y + height,
x, y, x + width, y + height,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glDrawBuffer (GL_BACK);
glFlush();
}
#endif
}
static gboolean
clutter_backend_egl_create_context (ClutterBackend *backend,
GError **error)
{
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, 2,
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_GL)
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
#elif defined (HAVE_COGL_GLES2)
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
#else
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
#endif
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
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 != EGL_NO_CONTEXT)
return TRUE;
edpy = clutter_egl_get_egl_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... */
/* Some GLES hardware can't support a stencil buffer: */
if (retry_cookie == 1)
{
g_warning ("Trying with stencil buffer disabled...");
cfg_attribs[1 /* EGL_STENCIL_SIZE */] = 0;
}
/* XXX: at this point we only have one fallback */
status = eglChooseConfig (edpy,
cfg_attribs,
&config, 1,
&config_count);
if (status != EGL_TRUE || config_count == 0)
{
error_message = "Unable to select a valid EGL configuration";
goto fail;
}
#ifdef HAVE_COGL_GL
eglBindAPI (EGL_OPENGL_API);
#endif
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;
}
attrs.override_redirect = True;
attrs.colormap = XCreateColormap (backend_x11->xdpy,
backend_x11->xwin_root,
xvisinfo->visual,
AllocNone);
attrs.border_pixel = 0;
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)
{
g_critical ("Unable to create an EGL surface");
return FALSE;
}
eglMakeCurrent (edpy,
backend_egl->dummy_surface,
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:
/* 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_ACTOR_IN_DESTRUCTION (stage) ||
((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 */
}
#ifndef COGL_HAS_XLIB_SUPPORT #ifndef COGL_HAS_XLIB_SUPPORT
static ClutterDeviceManager * static ClutterDeviceManager *
clutter_backend_egl_get_device_manager (ClutterBackend *backend) clutter_backend_egl_get_device_manager (ClutterBackend *backend)
@ -553,72 +176,26 @@ clutter_backend_egl_finalize (GObject *gobject)
static void static void
clutter_backend_egl_dispose (GObject *gobject) clutter_backend_egl_dispose (GObject *gobject)
{ {
ClutterBackend *backend = CLUTTER_BACKEND (gobject);
#ifdef HAVE_TSLIB
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (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 #endif
/* We chain up before disposing our own resources so that /* We chain up before disposing our CoglContext so that we will
ClutterBackendX11 will destroy all of the stages before we * destroy all of the stages first. Otherwise the actors may try to
destroy the egl context. Otherwise the actors may try to make GL * make Cogl calls during destruction which would cause a crash */
calls during destruction which causes a crash */
G_OBJECT_CLASS (_clutter_backend_egl_parent_class)->dispose (gobject); G_OBJECT_CLASS (_clutter_backend_egl_parent_class)->dispose (gobject);
if (backend->cogl_context)
{
cogl_object_unref (backend->cogl_context);
backend->cogl_context = NULL;
}
#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_egl);
#endif
#ifdef COGL_HAS_XLIB_SUPPORT
if (backend_egl->dummy_surface != EGL_NO_SURFACE)
{
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;
}
#endif /* COGL_HAS_XLIB_SUPPORT */
if (backend_egl->egl_context)
{
eglDestroyContext (backend_egl->edpy, backend_egl->egl_context);
backend_egl->egl_context = NULL;
}
if (backend_egl->edpy)
{
eglTerminate (backend_egl->edpy);
backend_egl->edpy = 0;
}
#ifdef HAVE_TSLIB
if (backend_egl->event_timer != NULL) if (backend_egl->event_timer != NULL)
{ {
g_timer_destroy (backend_egl->event_timer); g_timer_destroy (backend_egl->event_timer);
@ -651,87 +228,149 @@ clutter_backend_egl_constructor (GType gtype,
return g_object_ref (backend_singleton); return g_object_ref (backend_singleton);
} }
static gboolean
check_vblank_env (const char *name)
{
if (clutter_vblank_name && !g_ascii_strcasecmp (clutter_vblank_name, name))
return TRUE;
return FALSE;
}
static ClutterFeatureFlags static ClutterFeatureFlags
clutter_backend_egl_get_features (ClutterBackend *backend) clutter_backend_egl_get_features (ClutterBackend *backend)
{ {
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend); ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
const gchar *egl_extensions = NULL; #ifdef COGL_HAS_XLIB_SUPPORT
const gchar *gl_extensions = NULL; ClutterBackendClass *parent_class;
ClutterFeatureFlags flags; #endif
ClutterFeatureFlags flags = 0;
g_assert (backend_egl->egl_context != NULL);
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
{ parent_class = CLUTTER_BACKEND_CLASS (_clutter_backend_egl_parent_class);
ClutterBackendClass *parent_class;
parent_class = CLUTTER_BACKEND_CLASS (_clutter_backend_egl_parent_class); flags = parent_class->get_features (backend);
flags = parent_class->get_features (backend);
flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
}
#else
flags = CLUTTER_FEATURE_STAGE_STATIC;
#endif #endif
/* First check for explicit disabling or it set elsewhere (eg NVIDIA) */ if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN))
if (check_vblank_env ("none")) {
backend_egl->vblank_type = CLUTTER_VBLANK_NONE; CLUTTER_NOTE (BACKEND, "Cogl supports multiple onscreen framebuffers");
flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
}
else else
backend_egl->vblank_type = CLUTTER_VBLANK_SWAP_INTERVAL;
egl_extensions = eglQueryString (backend_egl->edpy, EGL_EXTENSIONS);
if (cogl_clutter_check_extension ("EGL_NOK_swap_region", egl_extensions))
{ {
CLUTTER_NOTE (BACKEND, CLUTTER_NOTE (BACKEND, "Cogl only supports one onscreen framebuffer");
"Using EGL_NOK_swap_region for sub_buffer copies"); flags |= CLUTTER_FEATURE_STAGE_STATIC;
backend_egl->swap_buffers_region =
(void *)cogl_get_proc_address ("eglSwapBuffersRegionNOK");
backend_egl->can_blit_sub_buffer = TRUE;
backend_egl->blit_sub_buffer_is_synchronized = TRUE;
} }
gl_extensions = (const gchar *)glGetString (GL_EXTENSIONS); if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_THROTTLE))
#if 0 /* XXX need GL_ARB_draw_buffers */
if (!backend_egl->swap_buffers_region &&
cogl_clutter_check_extension ("GL_EXT_framebuffer_blit", gl_extensions))
{ {
CLUTTER_NOTE (BACKEND, CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers throttling");
"Using glBlitFramebuffer fallback for sub_buffer copies"); flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
backend_egl->blit_framebuffer =
(BlitFramebufferProc) cogl_get_proc_address ("glBlitFramebuffer");
backend_egl->can_blit_sub_buffer = TRUE;
backend_egl->blit_sub_buffer_is_synchronized = FALSE;
} }
#endif else
CLUTTER_NOTE (BACKEND, "Cogl doesn't support swap buffers throttling");
CLUTTER_NOTE (BACKEND, "Checking features\n" if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
"GL_VENDOR: %s\n" {
"GL_RENDERER: %s\n" CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers complete events");
"GL_VERSION: %s\n" flags |= CLUTTER_FEATURE_SWAP_EVENTS;
"EGL_VENDOR: %s\n" }
"EGL_VERSION: %s\n"
"EGL_EXTENSIONS: %s\n", if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION))
glGetString (GL_VENDOR), {
glGetString (GL_RENDERER), CLUTTER_NOTE (BACKEND, "Cogl supports swapping buffer regions");
glGetString (GL_VERSION), backend_egl->can_blit_sub_buffer = TRUE;
eglQueryString (backend_egl->edpy, EGL_VENDOR), }
eglQueryString (backend_egl->edpy, EGL_VERSION),
eglQueryString (backend_egl->edpy, EGL_EXTENSIONS));
return flags; return flags;
} }
#ifdef COGL_HAS_XLIB_SUPPORT
static XVisualInfo *
clutter_backend_egl_get_visual_info (ClutterBackendX11 *backend_x11)
{
return cogl_clutter_winsys_xlib_get_visual_info ();
}
#endif
static gboolean
clutter_backend_egl_create_context (ClutterBackend *backend,
GError **error)
{
#ifdef COGL_HAS_XLIB_SUPPORT
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
#endif
CoglSwapChain *swap_chain = NULL;
CoglOnscreenTemplate *onscreen_template = NULL;
if (backend->cogl_context)
return TRUE;
backend->cogl_renderer = cogl_renderer_new ();
#ifdef COGL_HAS_XLIB_SUPPORT
cogl_renderer_xlib_set_foreign_display (backend->cogl_renderer,
backend_x11->xdpy);
#endif
if (!cogl_renderer_connect (backend->cogl_renderer, error))
goto error;
swap_chain = cogl_swap_chain_new ();
#ifdef COGL_HAS_XLIB_SUPPORT
cogl_swap_chain_set_has_alpha (swap_chain,
clutter_x11_get_use_argb_visual ());
#endif
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_GDL_SUPPORT
cogl_swap_chain_set_length (swap_chain, gdl_n_buffers);
#endif
onscreen_template = cogl_onscreen_template_new (swap_chain);
cogl_object_unref (swap_chain);
/* XXX: I have some doubts that this is a good design.
* Conceptually should we be able to check an onscreen_template
* without more details about the CoglDisplay configuration?
*/
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);
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_GDL_SUPPORT
cogl_display_cex100_set_gdl_plane (backend->cogl_display, gdl_plane);
#endif
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 * static ClutterStageWindow *
clutter_backend_egl_create_stage (ClutterBackend *backend, clutter_backend_egl_create_stage (ClutterBackend *backend,
ClutterStage *wrapper, ClutterStage *wrapper,
@ -768,7 +407,8 @@ clutter_backend_egl_create_stage (ClutterBackend *backend,
{ {
g_set_error (error, CLUTTER_INIT_ERROR, g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND, CLUTTER_INIT_ERROR_BACKEND,
"The EGL native backend does not support multiple stages"); "The Cogl backend does not support multiple "
"onscreen windows");
return backend_egl->stage; return backend_egl->stage;
} }
@ -785,57 +425,15 @@ clutter_backend_egl_create_stage (ClutterBackend *backend,
return stage; return stage;
} }
#ifdef COGL_HAS_XLIB_SUPPORT static void
static XVisualInfo * clutter_backend_egl_ensure_context (ClutterBackend *backend,
clutter_backend_egl_get_visual_info (ClutterBackendX11 *backend_x11) ClutterStage *stage)
{ {
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend_x11); ClutterStageEGL *stage_egl =
XVisualInfo visinfo_template; CLUTTER_STAGE_EGL (_clutter_stage_get_window (stage));
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)) cogl_set_framebuffer (COGL_FRAMEBUFFER (stage_egl->onscreen));
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 static void
_clutter_backend_egl_class_init (ClutterBackendEGLClass *klass) _clutter_backend_egl_class_init (ClutterBackendEGLClass *klass)
@ -869,29 +467,16 @@ _clutter_backend_egl_class_init (ClutterBackendEGLClass *klass)
static void static void
_clutter_backend_egl_init (ClutterBackendEGL *backend_egl) _clutter_backend_egl_init (ClutterBackendEGL *backend_egl)
{ {
#ifndef COGL_HAS_XLIB_SUPPORT
#ifdef HAVE_TSLIB #ifdef HAVE_TSLIB
backend_egl->event_timer = g_timer_new (); 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 #endif
} }
#ifdef CLUTTER_EGL_BACKEND_GENERIC
GType GType
_clutter_backend_impl_get_type (void) _clutter_backend_impl_get_type (void)
{ {
return _clutter_backend_egl_get_type (); return _clutter_backend_egl_get_type ();
} }
#endif
EGLDisplay EGLDisplay
clutter_eglx_display (void) clutter_eglx_display (void)
@ -914,5 +499,25 @@ clutter_egl_get_egl_display (void)
return 0; return 0;
} }
return backend_singleton->edpy; return cogl_context_egl_get_egl_display (backend_singleton->cogl_context);
} }
/* FIXME we should have a CLUTTER_ define for this */
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_GDL_SUPPORT
void
clutter_cex100_set_plane (gdl_plane_id_t plane)
{
g_return_if_fail (plane >= GDL_PLANE_ID_UPP_A && plane <= GDL_PLANE_ID_UPP_E);
gdl_plane = plane;
}
void
clutter_cex100_set_buffering_mode (ClutterCex100BufferingMode mode)
{
g_return_if_fail (mode == CLUTTER_CEX100_DOUBLE_BUFFERING ||
mode == CLUTTER_CEX100_TRIPLE_BUFFERING);
gdl_n_buffers = mode;
}
#endif

View File

@ -57,52 +57,14 @@ G_BEGIN_DECLS
typedef struct _ClutterBackendEGL ClutterBackendEGL; typedef struct _ClutterBackendEGL ClutterBackendEGL;
typedef struct _ClutterBackendEGLClass ClutterBackendEGLClass; typedef struct _ClutterBackendEGLClass ClutterBackendEGLClass;
typedef enum ClutterEGLVBlankType {
CLUTTER_VBLANK_NONE = 0,
CLUTTER_VBLANK_SWAP_INTERVAL
} ClutterEGLVBlankType;
typedef void (*BlitFramebufferProc) (GLint srcX0,
GLint srcY0,
GLint srcX1,
GLint srcY1,
GLint dstX0,
GLint dstY0,
GLint dstX1,
GLint dstY1,
GLbitfield mask,
GLenum filter);
typedef EGLBoolean (*SwapBuffersRegionProc) (EGLDisplay dpy,
EGLSurface surface,
EGLint numRects,
const EGLint *rects);
struct _ClutterBackendEGL struct _ClutterBackendEGL
{ {
#ifdef COGL_HAS_XLIB_SUPPORT #ifdef COGL_HAS_XLIB_SUPPORT
ClutterBackendX11 parent_instance; ClutterBackendX11 parent_instance;
/* EGL Specific */
EGLDisplay edpy;
EGLContext egl_context;
EGLConfig egl_config;
Window dummy_xwin;
EGLSurface dummy_surface;
#else /* COGL_HAS_X11_SUPPORT */ #else /* COGL_HAS_X11_SUPPORT */
ClutterBackend parent_instance; 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 */ /* main stage singleton */
ClutterStageWindow *stage; ClutterStageWindow *stage;
@ -115,20 +77,11 @@ struct _ClutterBackendEGL
/* event timer */ /* event timer */
GTimer *event_timer; GTimer *event_timer;
/* FB device */
gint fb_device_id;
#endif /* COGL_HAS_X11_SUPPORT */ #endif /* COGL_HAS_X11_SUPPORT */
gint egl_version_major; CoglContext *cogl_context;
gint egl_version_minor;
ClutterEGLVBlankType vblank_type; gboolean can_blit_sub_buffer;
gboolean can_blit_sub_buffer;
BlitFramebufferProc blit_framebuffer;
SwapBuffersRegionProc swap_buffers_region;
gboolean blit_sub_buffer_is_synchronized;
}; };
struct _ClutterBackendEGLClass struct _ClutterBackendEGLClass
@ -145,10 +98,8 @@ GType _clutter_backend_egl_get_type (void) G_GNUC_CONST;
void _clutter_events_egl_init (ClutterBackendEGL *backend); void _clutter_events_egl_init (ClutterBackendEGL *backend);
void _clutter_events_egl_uninit (ClutterBackendEGL *backend); void _clutter_events_egl_uninit (ClutterBackendEGL *backend);
void G_CONST_RETURN gchar*
_clutter_backend_egl_blit_sub_buffer (ClutterBackendEGL *backend_egl, _clutter_backend_egl_get_vblank (void);
EGLSurface drawable,
int x, int y, int width, int height);
G_END_DECLS G_END_DECLS

View File

@ -32,41 +32,36 @@ G_DEFINE_TYPE_WITH_CODE (ClutterStageEGL,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
clutter_stage_window_iface_init)); clutter_stage_window_iface_init));
#ifdef COGL_HAS_XLIB_SUPPORT
static void static void
clutter_stage_egl_unrealize (ClutterStageWindow *stage_window) 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); ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window);
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
CLUTTER_NOTE (BACKEND, "Unrealizing EGL stage [%p]", stage_egl); CLUTTER_NOTE (BACKEND, "Unrealizing EGL stage [%p]", stage_egl);
clutter_x11_trap_x_errors (); #ifdef COGL_HAS_XLIB_SUPPORT
/* chain up to the StageX11 implementation */
clutter_stage_window_parent_iface->unrealize (stage_window);
#endif
if (stage_egl->egl_surface != EGL_NO_SURFACE) cogl_object_unref (stage_egl->onscreen);
{ stage_egl->onscreen = NULL;
eglDestroySurface (clutter_egl_get_egl_display (), stage_egl->egl_surface);
stage_egl->egl_surface = EGL_NO_SURFACE;
}
_clutter_stage_x11_destroy_window_untrapped (stage_x11);
XSync (backend_x11->xdpy, False);
clutter_x11_untrap_x_errors ();
} }
static gboolean static gboolean
clutter_stage_egl_realize (ClutterStageWindow *stage_window) clutter_stage_egl_realize (ClutterStageWindow *stage_window)
{ {
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window); ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window);
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); #ifdef COGL_HAS_XLIB_SUPPORT
ClutterBackend *backend; ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
#endif
ClutterBackend *backend;
ClutterBackendEGL *backend_egl; ClutterBackendEGL *backend_egl;
EGLDisplay edpy; CoglFramebuffer *framebuffer;
GError *error = NULL;
gfloat width = 800;
gfloat height = 600;
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_egl),
@ -75,40 +70,49 @@ clutter_stage_egl_realize (ClutterStageWindow *stage_window)
backend = clutter_get_default_backend (); backend = clutter_get_default_backend ();
backend_egl = CLUTTER_BACKEND_EGL (backend); backend_egl = CLUTTER_BACKEND_EGL (backend);
edpy = clutter_egl_get_egl_display (); #ifdef COGL_HAS_XLIB_SUPPORT
clutter_actor_get_size (CLUTTER_ACTOR (stage_x11->wrapper), &width, &height);
#endif
if (!_clutter_stage_x11_create_window (stage_x11)) stage_egl->onscreen = cogl_onscreen_new (backend->cogl_context,
return FALSE; width, height);
#ifdef COGL_HAS_XLIB_SUPPORT
if (stage_x11->xwin != None)
cogl_onscreen_x11_set_foreign_window_xid (stage_egl->onscreen,
stage_x11->xwin);
#endif
if (stage_egl->egl_surface == EGL_NO_SURFACE) clutter_vblank = _clutter_backend_egl_get_vblank ();
if (clutter_vblank && strcmp (clutter_vblank, "none") == 0)
cogl_onscreen_set_swap_throttled (stage_egl->onscreen, FALSE);
framebuffer = COGL_FRAMEBUFFER (stage_egl->onscreen);
if (!cogl_framebuffer_allocate (framebuffer, &error))
{ {
stage_egl->egl_surface = g_warning ("Failed to allocate stage: %s", error->message);
eglCreateWindowSurface (edpy, g_error_free (error);
backend_egl->egl_config, cogl_object_unref (stage_egl->onscreen);
(NativeWindowType) stage_x11->xwin, stage_egl->onscreen = NULL;
NULL); return FALSE;
} }
/* FIXME: for fullscreen EGL platforms then the size we gave above
* will be ignored, so we need to make sure the stage size is
* updated to this size. */
if (stage_egl->egl_surface == EGL_NO_SURFACE) #ifdef COGL_HAS_XLIB_SUPPORT
g_warning ("Unable to create an EGL surface"); if (stage_x11->xwin == None)
stage_x11->xwin = cogl_onscreen_x11_get_window_xid (stage_egl->onscreen);
return clutter_stage_egl_parent_iface->realize (stage_window); return clutter_stage_egl_parent_iface->realize (stage_window);
} #else
#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; return TRUE;
#endif
} }
#ifndef COGL_HAS_XLIB_SUPPORT
/* FIXME: Move this warnings up into clutter-stage.c */
static void static void
clutter_stage_egl_set_fullscreen (ClutterStageWindow *stage_window, clutter_stage_egl_set_fullscreen (ClutterStageWindow *stage_window,
gboolean fullscreen) gboolean fullscreen)
@ -161,14 +165,25 @@ clutter_stage_egl_get_geometry (ClutterStageWindow *stage_window,
ClutterGeometry *geometry) ClutterGeometry *geometry)
{ {
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window); ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window);
ClutterBackendEGL *backend_egl = stage_egl->backend;
if (geometry) if (geometry)
{ {
geometry->x = geometry->y = 0; if (stage_egl->onscreen)
{
CoglFramebuffer *framebuffer =
COGL_FRAMEBUFFER (stage_egl->onscreen);
geometry->width = backend_egl->surface_width; geometry->x = geometry->y = 0;
geometry->height = backend_egl->surface_height;
geometry->width = cogl_framebuffer_get_width (framebuffer);
geometry->height = cogl_framebuffer_get_height (framebuffer);
}
else
{
geometry->x = geometry->y = 0;
geometry->width = 800;
geometry->height = 600;
}
} }
} }
@ -268,30 +283,51 @@ clutter_stage_egl_add_redraw_clip (ClutterStageWindow *stage_window,
stage_egl->initialized_redraw_clip = TRUE; stage_egl->initialized_redraw_clip = TRUE;
} }
/* XXX: This is basically identical to clutter_stage_glx_redraw */
static void static void
clutter_stage_egl_redraw (ClutterStageWindow *stage_window) clutter_stage_egl_redraw (ClutterStageWindow *stage_window)
{ {
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window); ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window);
ClutterBackend *backend = clutter_get_default_backend ();
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterActor *wrapper; ClutterActor *wrapper;
EGLSurface egl_surface; ClutterBackend *backend;
ClutterBackendEGL *backend_egl;
gboolean may_use_clipped_redraw; gboolean may_use_clipped_redraw;
gboolean 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 */
"eglSwapBuffers",
"The time spent blocked by eglSwapBuffers",
0 /* no application private data */);
CLUTTER_STATIC_TIMER (blit_sub_buffer_timer,
"Redrawing", /* parent */
"egl_blit_sub_buffer",
"The time spent in _egl_blit_sub_buffer",
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_egl);
wrapper = CLUTTER_ACTOR (stage_x11->wrapper); wrapper = CLUTTER_ACTOR (stage_x11->wrapper);
egl_surface = stage_egl->egl_surface;
#else #else
wrapper = CLUTTER_ACTOR (stage_egl->wrapper); 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 #endif
if (!stage_egl->onscreen)
return;
backend = clutter_get_default_backend ();
backend_egl = CLUTTER_BACKEND_EGL (backend);
CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer);
if (G_LIKELY (backend_egl->can_blit_sub_buffer) && if (G_LIKELY (backend_egl->can_blit_sub_buffer) &&
/* NB: a zero width clip == full stage redraw */ /* NB: a zero width redraw clip == full stage redraw */
stage_egl->bounding_redraw_clip.width != 0 && stage_egl->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... */
@ -303,7 +339,9 @@ clutter_stage_egl_redraw (ClutterStageWindow *stage_window)
&& G_LIKELY (stage_x11->clipped_redraws_cool_off == 0) && G_LIKELY (stage_x11->clipped_redraws_cool_off == 0)
#endif #endif
) )
may_use_clipped_redraw = TRUE; {
may_use_clipped_redraw = TRUE;
}
else else
may_use_clipped_redraw = FALSE; may_use_clipped_redraw = FALSE;
@ -327,11 +365,12 @@ clutter_stage_egl_redraw (ClutterStageWindow *stage_window)
else else
_clutter_stage_do_paint (CLUTTER_STAGE (wrapper), NULL); _clutter_stage_do_paint (CLUTTER_STAGE (wrapper), NULL);
if (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS && if (may_use_clipped_redraw &&
may_use_clipped_redraw) G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS)))
{ {
ClutterGeometry *clip = &stage_egl->bounding_redraw_clip;
static CoglMaterial *outline = NULL; static CoglMaterial *outline = NULL;
ClutterGeometry *clip = &stage_egl->bounding_redraw_clip;
ClutterActor *actor = CLUTTER_ACTOR (wrapper);
CoglHandle vbo; CoglHandle vbo;
float x_1 = clip->x; float x_1 = clip->x;
float x_2 = clip->x + clip->width; float x_2 = clip->x + clip->width;
@ -363,7 +402,7 @@ clutter_stage_egl_redraw (ClutterStageWindow *stage_window)
cogl_push_matrix (); cogl_push_matrix ();
cogl_matrix_init_identity (&modelview); cogl_matrix_init_identity (&modelview);
_clutter_actor_apply_modelview_transform (wrapper, &modelview); _clutter_actor_apply_modelview_transform (actor, &modelview);
cogl_set_modelview_matrix (&modelview); cogl_set_modelview_matrix (&modelview);
cogl_set_source (outline); cogl_set_source (outline);
cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_LINE_LOOP, cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_LINE_LOOP,
@ -372,46 +411,52 @@ clutter_stage_egl_redraw (ClutterStageWindow *stage_window)
cogl_object_unref (vbo); cogl_object_unref (vbo);
} }
cogl_flush (); CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer);
/* 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_egl->bounding_redraw_clip;
ClutterGeometry copy_area; 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 (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, CLUTTER_NOTE (BACKEND,
"_egl_blit_sub_buffer (surface: %p, " "cogl_framebuffer_swap_region (onscreen: %p, "
"x: %d, y: %d, " "x: %d, y: %d, "
"width: %d, height: %d)", "width: %d, height: %d)",
egl_surface, stage_egl->onscreen,
stage_egl->bounding_redraw_clip.x, copy_area[0], copy_area[1], copy_area[2], copy_area[3]);
stage_egl->bounding_redraw_clip.y,
stage_egl->bounding_redraw_clip.width,
stage_egl->bounding_redraw_clip.height);
copy_area.x = clip->x;
copy_area.y = clip->y;
copy_area.width = clip->width;
copy_area.height = clip->height;
CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer); CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer);
_clutter_backend_egl_blit_sub_buffer (backend_egl,
egl_surface, cogl_framebuffer_swap_region (COGL_FRAMEBUFFER (stage_egl->onscreen),
copy_area.x, copy_area, 1);
copy_area.y,
copy_area.width,
copy_area.height);
CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer); CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer);
} }
else else
{ {
CLUTTER_NOTE (BACKEND, "eglwapBuffers (display: %p, surface: %p)", CLUTTER_NOTE (BACKEND, "cogl_framebuffer_swap_buffers (onscreen: %p)",
backend_egl->edpy, stage_egl->onscreen);
egl_surface);
CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer); CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer);
eglSwapBuffers (backend_egl->edpy, egl_surface); cogl_framebuffer_swap_buffers (COGL_FRAMEBUFFER (stage_egl->onscreen));
CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer); CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer);
} }
@ -467,25 +512,14 @@ _clutter_stage_egl_class_init (ClutterStageEGLClass *klass)
gobject_class->dispose = clutter_stage_egl_dispose; gobject_class->dispose = clutter_stage_egl_dispose;
} }
#else
static void
_clutter_stage_egl_init (ClutterStageEGL *stage)
{
stage->egl_surface = EGL_NO_SURFACE;
}
#else /* COGL_HAS_X11_SUPPORT */
static void static void
_clutter_stage_egl_class_init (ClutterStageEGLClass *klass) _clutter_stage_egl_class_init (ClutterStageEGLClass *klass)
{ {
} }
#endif /* COGL_HAS_X11_SUPPORT */
static void static void
_clutter_stage_egl_init (ClutterStageEGL *stage) _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 */

View File

@ -36,8 +36,6 @@ struct _ClutterStageEGL
ClutterStageX11 parent_instance; ClutterStageX11 parent_instance;
EGLSurface egl_surface;
#else #else
GObject parent_instance; GObject parent_instance;
@ -50,6 +48,8 @@ struct _ClutterStageEGL
#endif #endif
CoglOnscreen *onscreen;
/* We only enable clipped redraws after 2 frames, since we've seen /* We only enable clipped redraws after 2 frames, since we've seen
* a lot of drivers can struggle to get going and may output some * a lot of drivers can struggle to get going and may output some
* junk frames to start with. */ * junk frames to start with. */

View File

@ -56,16 +56,9 @@ struct _ClutterBackendGLX
{ {
ClutterBackendX11 parent_instance; ClutterBackendX11 parent_instance;
int error_base; CoglContext *cogl_context;
int event_base;
CoglContext *cogl_context; gboolean can_blit_sub_buffer;
/* Vblank stuff */
ClutterGLXVBlankType vblank_type;
unsigned int last_video_sync_count;
gboolean can_blit_sub_buffer;
/* props */ /* props */
Atom atom_WM_STATE; Atom atom_WM_STATE;

View File

@ -1358,111 +1358,6 @@ clutter_x11_set_stage_foreign (ClutterStage *stage,
return TRUE; return TRUE;
} }
void
_clutter_stage_x11_destroy_window_untrapped (ClutterStageX11 *stage_x11)
{
Window xwin = stage_x11->xwin;
if (clutter_stages_by_xid != NULL)
{
CLUTTER_NOTE (BACKEND, "Removing X11 stage 0x%x [%p]",
(unsigned int) xwin,
stage_x11);
g_hash_table_remove (clutter_stages_by_xid, GINT_TO_POINTER (xwin));
}
if (!stage_x11->is_foreign_xwin && xwin != None)
{
ClutterBackendX11 *backend_x11 = stage_x11->backend;
g_assert (clutter_stages_by_xid != NULL);
XDestroyWindow (backend_x11->xdpy, xwin);
stage_x11->xwin = None;
}
else
stage_x11->xwin = None;
}
void
_clutter_stage_x11_destroy_window (ClutterStageX11 *stage_x11)
{
if (stage_x11->xwin == None)
return;
clutter_x11_trap_x_errors ();
_clutter_stage_x11_destroy_window_untrapped (stage_x11);
clutter_x11_untrap_x_errors ();
}
gboolean
_clutter_stage_x11_create_window (ClutterStageX11 *stage_x11)
{
ClutterBackendX11 *backend_x11 = stage_x11->backend;
XSetWindowAttributes xattr;
XVisualInfo *xvisinfo;
unsigned long mask;
gfloat width, height;
if (stage_x11->xwin != None)
return TRUE;
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.
*
* we also round to the nearest integer because stage sizes
* should always be in pixels
*/
clutter_actor_get_size (CLUTTER_ACTOR (stage_x11->wrapper), &width, &height);
stage_x11->xwin_width = floorf (width + 0.5);
stage_x11->xwin_height = floorf (height + 0.5);
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_x11,
(unsigned int) stage_x11->xwin,
stage_x11->xwin_width,
stage_x11->xwin_height);
XFree (xvisinfo);
return TRUE;
}
void void
_clutter_stage_x11_set_user_time (ClutterStageX11 *stage_x11, _clutter_stage_x11_set_user_time (ClutterStageX11 *stage_x11,
guint32 user_time) guint32 user_time)

View File

@ -81,9 +81,6 @@ struct _ClutterStageX11Class
GType _clutter_stage_x11_get_type (void) G_GNUC_CONST; GType _clutter_stage_x11_get_type (void) G_GNUC_CONST;
/* Private to subclasses */ /* Private to subclasses */
gboolean _clutter_stage_x11_create_window (ClutterStageX11 *stage_x11);
void _clutter_stage_x11_destroy_window_untrapped (ClutterStageX11 *stage_x11);
void _clutter_stage_x11_destroy_window (ClutterStageX11 *stage_x11);
void _clutter_stage_x11_set_user_time (ClutterStageX11 *stage_x11, void _clutter_stage_x11_set_user_time (ClutterStageX11 *stage_x11,
guint32 user_time); guint32 user_time);
gboolean _clutter_stage_x11_get_root_coords (ClutterStageX11 *stage_x11, gboolean _clutter_stage_x11_get_root_coords (ClutterStageX11 *stage_x11,

View File

@ -459,6 +459,8 @@ AS_IF([test "x$SUPPORT_GLX" = "x1"],
AC_DEFINE([HAVE_CLUTTER_GLX], [1], [Have the GLX backend]) AC_DEFINE([HAVE_CLUTTER_GLX], [1], [Have the GLX backend])
AC_DEFINE([COGL_HAS_FULL_WINSYS], [1], [Cogl can create its own OpenGL context])
AC_CHECK_HEADERS([GL/glx.h], AC_CHECK_HEADERS([GL/glx.h],
[], [],
[AC_MSG_ERROR([Unable to locate required GLX headers])]) [AC_MSG_ERROR([Unable to locate required GLX headers])])
@ -489,12 +491,14 @@ AS_IF([test "x$SUPPORT_EGL_PLATFORM_POWERVR_X11" = "x1"],
[ [
AC_DEFINE([COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT], [1], AC_DEFINE([COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT], [1],
[Cogl supports OpenGL[ES] using the EGL API with PowerVR X11 platform typedefs]) [Cogl supports OpenGL[ES] using the EGL API with PowerVR X11 platform typedefs])
AC_DEFINE([COGL_HAS_FULL_WINSYS], [1], [Cogl can create its own OpenGL context])
]) ])
AS_IF([test "x$SUPPORT_EGL_PLATFORM_POWERVR_NULL" = "x1"], AS_IF([test "x$SUPPORT_EGL_PLATFORM_POWERVR_NULL" = "x1"],
[ [
AC_DEFINE([COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT], [1], AC_DEFINE([COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT], [1],
[Cogl supports OpenGL[ES] using the EGL API with PowerVR NULL platform typedefs]) [Cogl supports OpenGL[ES] using the EGL API with PowerVR NULL platform typedefs])
AC_DEFINE([COGL_HAS_FULL_WINSYS], [1], [Cogl can create its own OpenGL context])
]) ])
AS_IF([test "x$SUPPORT_EGL_PLATFORM_POWERVR_GDL" = "x1"], AS_IF([test "x$SUPPORT_EGL_PLATFORM_POWERVR_GDL" = "x1"],