diff --git a/clutter/Makefile.am b/clutter/Makefile.am index 480474dcc..d17117896 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -471,8 +471,6 @@ evdev_h_priv = \ $(srcdir)/evdev/clutter-input-device-evdev.h \ $(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 if SUPPORT_EGL @@ -487,8 +485,6 @@ egl_source_h_priv += $(evdev_h_priv) endif # SUPPORT_EVDEV 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) endif # SUPPORT_CEX100 diff --git a/clutter/cogl/cogl/Makefile.am b/clutter/cogl/cogl/Makefile.am index 426b59ae0..335f21d7a 100644 --- a/clutter/cogl/cogl/Makefile.am +++ b/clutter/cogl/cogl/Makefile.am @@ -332,18 +332,15 @@ cogl_sources_c += \ endif if SUPPORT_EGL_PLATFORM_POWERVR_X11 cogl_sources_c += \ - $(srcdir)/winsys/cogl-winsys-egl.c \ - $(srcdir)/winsys/cogl-winsys-stub.c + $(srcdir)/winsys/cogl-winsys-egl.c endif if SUPPORT_EGL_PLATFORM_POWERVR_NULL cogl_sources_c += \ - $(srcdir)/winsys/cogl-winsys-egl.c \ - $(srcdir)/winsys/cogl-winsys-stub.c + $(srcdir)/winsys/cogl-winsys-egl.c endif if SUPPORT_EGL_PLATFORM_POWERVR_GDL cogl_sources_c += \ - $(srcdir)/winsys/cogl-winsys-egl.c \ - $(srcdir)/winsys/cogl-winsys-stub.c + $(srcdir)/winsys/cogl-winsys-egl.c endif if SUPPORT_WIN32 cogl_sources_c += \ diff --git a/clutter/cogl/cogl/cogl-context.c b/clutter/cogl/cogl/cogl-context.c index ac76d4fae..e1b18f6e5 100644 --- a/clutter/cogl/cogl/cogl-context.c +++ b/clutter/cogl/cogl/cogl-context.c @@ -475,3 +475,12 @@ cogl_set_default_context (CoglContext *context) cogl_object_unref (_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 + diff --git a/clutter/cogl/cogl/cogl-context.h b/clutter/cogl/cogl/cogl-context.h index 9394fbfa2..7cd0785d6 100644 --- a/clutter/cogl/cogl/cogl-context.h +++ b/clutter/cogl/cogl/cogl-context.h @@ -33,6 +33,17 @@ #include +#ifdef COGL_HAS_EGL_SUPPORT +#ifdef COGL_HAS_GLES1 +#include +#include +#else +#include +#define NativeDisplayType EGLNativeDisplayType +#define NativeWindowType EGLNativeWindowType +#endif +#endif + G_BEGIN_DECLS /** @@ -61,6 +72,12 @@ cogl_context_new (CoglDisplay *display, void 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 #endif /* __COGL_CONTEXT_H__ */ diff --git a/clutter/cogl/cogl/winsys/cogl-winsys-egl-feature-functions.h b/clutter/cogl/cogl/winsys/cogl-winsys-egl-feature-functions.h new file mode 100644 index 000000000..58c07348d --- /dev/null +++ b/clutter/cogl/cogl/winsys/cogl-winsys-egl-feature-functions.h @@ -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 + * . + * + * + */ + +/* 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 () diff --git a/clutter/cogl/cogl/winsys/cogl-winsys-egl.c b/clutter/cogl/cogl/winsys/cogl-winsys-egl.c index bafafc0ac..b6446dc1b 100644 --- a/clutter/cogl/cogl/winsys/cogl-winsys-egl.c +++ b/clutter/cogl/cogl/winsys/cogl-winsys-egl.c @@ -3,7 +3,7 @@ * * An object oriented GL/GLES Abstraction/Utility Layer * - * Copyright (C) 2007,2008,2009 Intel Corporation. + * Copyright (C) 2007,2008,2009,2010,2011 Intel Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,9 +16,12 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . + * License along with this library. If not, see + * . * * + * Authors: + * Robert Bragg */ #ifdef HAVE_CONFIG_H @@ -27,19 +30,1052 @@ #include "cogl.h" -#ifdef HAVE_STANDALONE_EGL +#include "cogl-winsys-private.h" +#include "cogl-feature-private.h" +#include "cogl-context-private.h" +#include "cogl-framebuffer.h" +#include "cogl-swap-chain-private.h" +#include "cogl-renderer-private.h" +#include "cogl-onscreen-template-private.h" +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT +#include "cogl-renderer-xlib-private.h" +#include "cogl-display-xlib-private.h" +#endif +#include "cogl-private.h" + +#include +#include +#include +#include + +#include + +#ifdef COGL_HAS_GLES1 + +#include +#include + +#else + #include -#include #define NativeDisplayType EGLNativeDisplayType #define NativeWindowType EGLNativeWindowType -#else -#include -#include + #endif + +#include + +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT +#include +#endif + +typedef struct _CoglRendererEGL +{ +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + CoglRendererXlib _parent; +#endif + + EGLDisplay edpy; + + EGLint egl_version_major; + EGLint egl_version_minor; + + /* Function pointers for GLX specific extensions */ +#define COGL_WINSYS_FEATURE_BEGIN(a, b, c, d, e, f) + +#define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) \ + ret (APIENTRY * pf_ ## name) args; + +#define COGL_WINSYS_FEATURE_END() + +#include "cogl-winsys-egl-feature-functions.h" + +#undef COGL_WINSYS_FEATURE_BEGIN +#undef COGL_WINSYS_FEATURE_FUNCTION +#undef COGL_WINSYS_FEATURE_END +} CoglRendererEGL; + +typedef struct _CoglDisplayEGL +{ +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + CoglDisplayXlib _parent; +#endif + + EGLContext egl_context; +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + EGLSurface dummy_surface; +#elif defined (COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT) + EGLSurface egl_surface; + int egl_surface_width; + int egl_surface_height; + gboolean have_onscreen; +#else +#error "Unknown EGL platform" +#endif + + EGLConfig egl_config; + gboolean found_egl_config; +} CoglDisplayEGL; + +typedef struct _CoglContextEGL +{ + EGLSurface current_surface; +} CoglContextEGL; + +typedef struct _CoglOnscreenXlib +{ + Window xwin; + gboolean is_foreign_xwin; +} CoglOnscreenXlib; + +typedef struct _CoglOnscreenEGL +{ + CoglOnscreenXlib _parent; + EGLSurface egl_surface; +} CoglOnscreenEGL; + +/* Define a set of arrays containing the functions required from GL + for each winsys feature */ +#define COGL_WINSYS_FEATURE_BEGIN(name, namespaces, extension_names, \ + feature_flags, feature_flags_private, \ + winsys_feature) \ + static const CoglFeatureFunction \ + cogl_egl_feature_ ## name ## _funcs[] = { +#define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) \ + { G_STRINGIFY (name), G_STRUCT_OFFSET (CoglRendererEGL, pf_ ## name) }, +#define COGL_WINSYS_FEATURE_END() \ + { NULL, 0 }, \ + }; +#include "cogl-winsys-egl-feature-functions.h" + +/* Define an array of features */ +#undef COGL_WINSYS_FEATURE_BEGIN +#define COGL_WINSYS_FEATURE_BEGIN(name, namespaces, extension_names, \ + feature_flags, feature_flags_private, \ + winsys_feature) \ + { 255, 255, namespaces, extension_names, \ + feature_flags, feature_flags_private, \ + winsys_feature, \ + cogl_egl_feature_ ## name ## _funcs }, +#undef COGL_WINSYS_FEATURE_FUNCTION +#define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) +#undef COGL_WINSYS_FEATURE_END +#define COGL_WINSYS_FEATURE_END() + +static const CoglFeatureData winsys_feature_data[] = + { +#include "cogl-winsys-egl-feature-functions.h" + }; + CoglFuncPtr _cogl_winsys_get_proc_address (const char *name) { return (CoglFuncPtr) eglGetProcAddress (name); } +#undef COGL_WINSYS_FEATURE_BEGIN +#define COGL_WINSYS_FEATURE_BEGIN(a, b, c, d, e, f) +#undef COGL_WINSYS_FEATURE_FUNCTION +#define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) \ + egl_renderer->pf_ ## name = NULL; +#undef COGL_WINSYS_FEATURE_END +#define COGL_WINSYS_FEATURE_END() + +static void +initialize_function_table (CoglRenderer *renderer) +{ + CoglRendererEGL *egl_renderer = renderer->winsys; + +#include "cogl-winsys-egl-feature-functions.h" +} + +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT +static CoglOnscreen * +find_onscreen_for_xid (CoglContext *context, guint32 xid) +{ + GList *l; + + for (l = context->framebuffers; l; l = l->next) + { + CoglFramebuffer *framebuffer = l->data; + CoglOnscreenXlib *xlib_onscreen; + + if (!framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) + continue; + + xlib_onscreen = COGL_ONSCREEN (framebuffer)->winsys; + if (xlib_onscreen->xwin == (Window)xid) + return COGL_ONSCREEN (framebuffer); + } + + return NULL; +} + +static CoglFilterReturn +event_filter_cb (void *event, void *data) +{ + XEvent *xevent = event; + CoglContext *context = data; + + if (xevent->type == ConfigureNotify) + { + CoglOnscreen *onscreen = + find_onscreen_for_xid (context, xevent->xconfigure.window); + + if (onscreen) + { + CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); + + /* XXX: consider adding an abstraction for this... */ + framebuffer->width = xevent->xconfigure.width; + framebuffer->height = xevent->xconfigure.height; + } + } + + return COGL_FILTER_CONTINUE; +} +#endif /* COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT */ + +gboolean +_cogl_winsys_renderer_connect (CoglRenderer *renderer, + GError **error) +{ + CoglRendererEGL *egl_renderer; +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + CoglRendererXlib *xlib_renderer; +#endif + EGLBoolean status; + + renderer->winsys = g_slice_new0 (CoglRendererEGL); + + egl_renderer = renderer->winsys; +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + xlib_renderer = renderer->winsys; + + if (!_cogl_renderer_xlib_connect (renderer, error)) + goto error; + + egl_renderer->edpy = + eglGetDisplay ((NativeDisplayType) xlib_renderer->xdpy); + + status = eglInitialize (egl_renderer->edpy, + &egl_renderer->egl_version_major, + &egl_renderer->egl_version_minor); +#else + egl_renderer->edpy = eglGetDisplay (EGL_DEFAULT_DISPLAY); + + status = eglInitialize (egl_renderer->edpy, + &egl_renderer->egl_version_major, + &egl_renderer->egl_version_minor); + + if (status != EGL_TRUE) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_INIT, + "Failed to initialize EGL"); + goto error; + } +#endif + + return TRUE; + +error: + _cogl_winsys_renderer_disconnect (renderer); + return FALSE; +} + +void +_cogl_winsys_renderer_disconnect (CoglRenderer *renderer) +{ + CoglRendererEGL *egl_renderer = renderer->winsys; + +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + _cogl_renderer_xlib_disconnect (renderer); +#endif + + eglTerminate (egl_renderer->edpy); + + g_slice_free (CoglRendererEGL, egl_renderer); +} + +void +update_winsys_features (CoglContext *context) +{ + CoglDisplayEGL *egl_display = context->display->winsys; + CoglRendererEGL *egl_renderer = context->display->renderer->winsys; + const char *egl_extensions; + int i; + + g_return_if_fail (egl_display->egl_context); + + _cogl_gl_update_features (context); + + memset (context->winsys_features, 0, sizeof (context->winsys_features)); + + egl_extensions = eglQueryString (egl_renderer->edpy, EGL_EXTENSIONS); + + COGL_NOTE (WINSYS, " EGL Extensions: %s", egl_extensions); + +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + context->feature_flags |= COGL_FEATURE_ONSCREEN_MULTIPLE; + COGL_FLAGS_SET (context->winsys_features, + COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN, + TRUE); +#endif + + initialize_function_table (context->display->renderer); + + for (i = 0; i < G_N_ELEMENTS (winsys_feature_data); i++) + if (_cogl_feature_check ("EGL", winsys_feature_data + i, 0, 0, + egl_extensions, + egl_renderer)) + { + context->feature_flags |= winsys_feature_data[i].feature_flags; + if (winsys_feature_data[i].winsys_feature) + COGL_FLAGS_SET (context->winsys_features, + winsys_feature_data[i].winsys_feature, + TRUE); + } + + /* FIXME: the winsys_feature_data can currently only have one + * winsys feature per extension... */ + if (egl_renderer->pf_eglSwapBuffersRegion) + { + COGL_FLAGS_SET (context->winsys_features, + COGL_WINSYS_FEATURE_SWAP_REGION, TRUE); + COGL_FLAGS_SET (context->winsys_features, + COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, TRUE); + } +} + +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT +static XVisualInfo * +get_visual_info (CoglDisplay *display, EGLConfig egl_config) +{ + CoglRendererXlib *xlib_renderer = display->renderer->winsys; + CoglRendererEGL *egl_renderer = display->renderer->winsys; + XVisualInfo visinfo_template; + int template_mask = 0; + XVisualInfo *visinfo = NULL; + int visinfos_count; + EGLint visualid, red_size, green_size, blue_size, alpha_size; + + eglGetConfigAttrib (egl_renderer->edpy, 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 (egl_renderer->edpy, egl_config, + EGL_RED_SIZE, &red_size); + eglGetConfigAttrib (egl_renderer->edpy, egl_config, + EGL_GREEN_SIZE, &green_size); + eglGetConfigAttrib (egl_renderer->edpy, egl_config, + EGL_BLUE_SIZE, &blue_size); + eglGetConfigAttrib (egl_renderer->edpy, egl_config, + EGL_ALPHA_SIZE, &alpha_size); + + visinfo_template.depth = red_size + green_size + blue_size + alpha_size; + template_mask |= VisualDepthMask; + + visinfo_template.screen = DefaultScreen (xlib_renderer->xdpy); + template_mask |= VisualScreenMask; + } + + visinfo = XGetVisualInfo (xlib_renderer->xdpy, + template_mask, + &visinfo_template, + &visinfos_count); + + return visinfo; +} +#endif + +static gboolean +try_create_context (CoglDisplay *display, + int retry_cookie, + gboolean *try_fallback, + GError **error) +{ + CoglDisplayEGL *egl_display = display->winsys; +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + CoglDisplayXlib *xlib_display = display->winsys; + CoglRendererXlib *xlib_renderer = display->renderer->winsys; +#endif + CoglRendererEGL *egl_renderer = display->renderer->winsys; + EGLDisplay edpy; + 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 + }; +#if defined (HAVE_COGL_GLES2) + EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; +#else + EGLint *attribs = NULL; +#endif + +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + XVisualInfo *xvisinfo; + XSetWindowAttributes attrs; +#endif + const char *error_message; + + edpy = egl_renderer->edpy; + +#ifdef HAVE_COGL_GL + eglBindAPI (EGL_OPENGL_API); +#endif + + /* 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 find a usable EGL configuration"; + goto fail; + } + + egl_display->egl_config = config; + + egl_display->egl_context = eglCreateContext (edpy, + config, + EGL_NO_CONTEXT, + attribs); + if (egl_display->egl_context == EGL_NO_CONTEXT) + { + error_message = "Unable to create a suitable EGL context"; + goto fail; + } + +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + + xvisinfo = get_visual_info (display, config); + if (xvisinfo == NULL) + { + error_message = "Unable to find suitable X visual"; + goto fail; + } + + attrs.override_redirect = True; + attrs.colormap = XCreateColormap (xlib_renderer->xdpy, + DefaultRootWindow (xlib_renderer->xdpy), + xvisinfo->visual, + AllocNone); + attrs.border_pixel = 0; + + xlib_display->dummy_xwin = + XCreateWindow (xlib_renderer->xdpy, + DefaultRootWindow (xlib_renderer->xdpy), + -100, -100, 1, 1, + 0, + xvisinfo->depth, + CopyFromParent, + xvisinfo->visual, + CWOverrideRedirect | + CWColormap | + CWBorderPixel, + &attrs); + + XFree (xvisinfo); + + egl_display->dummy_surface = + eglCreateWindowSurface (edpy, + egl_display->egl_config, + (NativeWindowType) xlib_display->dummy_xwin, + NULL); + + if (egl_display->dummy_surface == EGL_NO_SURFACE) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Unable to create an EGL surface"); + goto fail; + } + + if (!eglMakeCurrent (edpy, + egl_display->dummy_surface, + egl_display->dummy_surface, + egl_display->egl_context)) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Unable to eglMakeCurrent with dummy surface"); + goto fail; + } + +#elif defined (COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT) + + egl_display->egl_surface = + eglCreateWindowSurface (edpy, + config, + (NativeWindowType) NULL, + NULL); + if (egl_display->egl_surface == EGL_NO_SURFACE) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Unable to create EGL window surface"); + goto fail; + } + + if (!eglMakeCurrent (egl_renderer->edpy, + egl_display->egl_surface, + egl_display->egl_surface, + egl_display->egl_context)) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Unable to eglMakeCurrent with egl surface"); + goto fail; + } + + eglQuerySurface (egl_renderer->edpy, + egl_display->egl_surface, + EGL_WIDTH, + &egl_display->egl_surface_width); + + eglQuerySurface (egl_renderer->edpy, + egl_display->egl_surface, + EGL_HEIGHT, + &egl_display->egl_surface_height); + +#else +#error "Unknown EGL platform" +#endif + + return TRUE; + +fail: + + /* Currently we only have one fallback path... */ + if (retry_cookie == 0) + { + *try_fallback = TRUE; + return FALSE; + } + else + { + *try_fallback = FALSE; + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "%s", error_message); + return FALSE; + } +} + +static void +cleanup_context (CoglDisplay *display) +{ + CoglDisplayEGL *egl_display = display->winsys; + CoglRendererEGL *egl_renderer = display->renderer->winsys; +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + CoglDisplayXlib *xlib_display = display->winsys; + CoglRendererXlib *xlib_renderer = display->renderer->winsys; +#endif + + if (egl_display->egl_context != EGL_NO_CONTEXT) + { + eglMakeCurrent (egl_renderer->edpy, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + eglDestroyContext (egl_renderer->edpy, egl_display->egl_context); + egl_display->egl_context = EGL_NO_CONTEXT; + } + +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + if (egl_display->dummy_surface != EGL_NO_SURFACE) + { + eglDestroySurface (egl_renderer->edpy, egl_display->dummy_surface); + egl_display->dummy_surface = EGL_NO_SURFACE; + } + + if (xlib_display->dummy_xwin) + { + XDestroyWindow (xlib_renderer->xdpy, xlib_display->dummy_xwin); + xlib_display->dummy_xwin = None; + } +#endif +} + +static gboolean +create_context (CoglDisplay *display, GError **error) +{ + CoglDisplayEGL *egl_display = display->winsys; + gboolean support_transparent_windows; + int retry_cookie = 0; + gboolean status; + gboolean try_fallback; + GError *try_error = NULL; + + g_return_val_if_fail (egl_display->egl_context == NULL, TRUE); + + if (display->onscreen_template && + display->onscreen_template->swap_chain && + display->onscreen_template->swap_chain->has_alpha) + support_transparent_windows = TRUE; + else + support_transparent_windows = FALSE; + + retry_cookie = 0; + while (!(status = try_create_context (display, + retry_cookie, + &try_fallback, + &try_error)) && + try_fallback) + { + g_error_free (try_error); + cleanup_context (display); + try_error = NULL; + retry_cookie++; + } + if (!status) + g_propagate_error (error, try_error); + + return status; +} + +gboolean +_cogl_winsys_display_setup (CoglDisplay *display, + GError **error) +{ + CoglDisplayEGL *egl_display; + + g_return_val_if_fail (display->winsys == NULL, FALSE); + + egl_display = g_slice_new0 (CoglDisplayEGL); + display->winsys = egl_display; + + if (!create_context (display, error)) + goto error; + + egl_display->found_egl_config = TRUE; + + return TRUE; + +error: + _cogl_winsys_display_destroy (display); + return FALSE; +} + +void +_cogl_winsys_display_destroy (CoglDisplay *display) +{ + CoglDisplayEGL *egl_display = display->winsys; + + g_return_if_fail (egl_display != NULL); + + cleanup_context (display); + + g_slice_free (CoglDisplayEGL, display->winsys); + display->winsys = NULL; +} + +gboolean +_cogl_winsys_context_init (CoglContext *context, GError **error) +{ + context->winsys = g_new0 (CoglContextEGL, 1); + +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + cogl_renderer_add_native_filter (context->display->renderer, + event_filter_cb, + context); +#endif + update_winsys_features (context); + + return TRUE; +} + +void +_cogl_winsys_context_deinit (CoglContext *context) +{ +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + cogl_renderer_remove_native_filter (context->display->renderer, + event_filter_cb, + context); +#endif + g_free (context->winsys); +} + +gboolean +_cogl_winsys_onscreen_init (CoglOnscreen *onscreen, + GError **error) +{ + CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); + CoglContext *context = framebuffer->context; + CoglDisplay *display = context->display; + CoglDisplayEGL *egl_display = display->winsys; +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + CoglRendererEGL *egl_renderer = display->renderer->winsys; + CoglRendererXlib *xlib_renderer = display->renderer->winsys; + CoglOnscreenXlib *xlib_onscreen; + Window xwin; +#endif + CoglOnscreenEGL *egl_onscreen; + + g_return_val_if_fail (egl_display->egl_context, FALSE); + +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + + /* FIXME: We need to explicitly Select for ConfigureNotify events. + * For foreign windows we need to be careful not to mess up any + * existing event mask. + * We need to document that for windows we create then toolkits + * must be careful not to clear event mask bits that we select. + */ + + /* XXX: Note we ignore the user's original width/height when + * given a foreign X window. */ + if (onscreen->foreign_xid) + { + Status status; + CoglXlibTrapState state; + XWindowAttributes attr; + int xerror; + + xwin = onscreen->foreign_xid; + + _cogl_renderer_xlib_trap_errors (display->renderer, &state); + + status = XGetWindowAttributes (xlib_renderer->xdpy, xwin, &attr); + xerror = _cogl_renderer_xlib_untrap_errors (display->renderer, &state); + if (status == 0 || xerror) + { + char message[1000]; + XGetErrorText (xlib_renderer->xdpy, xerror, + message, sizeof (message)); + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_ONSCREEN, + "Unable to query geometry of foreign xid 0x%08lX: %s", + xwin, message); + return FALSE; + } + + _cogl_framebuffer_winsys_update_size (framebuffer, + attr.width, attr.height); + } + else + { + int width; + int height; + CoglXlibTrapState state; + XVisualInfo *xvisinfo; + XSetWindowAttributes xattr; + unsigned long mask; + int xerror; + + width = cogl_framebuffer_get_width (framebuffer); + height = cogl_framebuffer_get_height (framebuffer); + + _cogl_renderer_xlib_trap_errors (display->renderer, &state); + + xvisinfo = get_visual_info (display, egl_display->egl_config); + if (xvisinfo == NULL) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_ONSCREEN, + "Unable to retrieve the X11 visual of context's " + "fbconfig"); + return FALSE; + } + + /* window attributes */ + xattr.background_pixel = WhitePixel (xlib_renderer->xdpy, + DefaultScreen (xlib_renderer->xdpy)); + xattr.border_pixel = 0; + /* XXX: is this an X resource that we are leaking‽... */ + xattr.colormap = XCreateColormap (xlib_renderer->xdpy, + DefaultRootWindow (xlib_renderer->xdpy), + xvisinfo->visual, + AllocNone); + mask = CWBorderPixel | CWColormap; + + xwin = XCreateWindow (xlib_renderer->xdpy, + DefaultRootWindow (xlib_renderer->xdpy), + 0, 0, + width, height, + 0, + xvisinfo->depth, + InputOutput, + xvisinfo->visual, + mask, &xattr); + + XFree (xvisinfo); + + XMapWindow (xlib_renderer->xdpy, xwin); + + XSync (xlib_renderer->xdpy, False); + xerror = _cogl_renderer_xlib_untrap_errors (display->renderer, &state); + if (xerror) + { + char message[1000]; + XGetErrorText (xlib_renderer->xdpy, xerror, + message, sizeof (message)); + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_ONSCREEN, + "X error while creating Window for CoglOnscreen: %s", + message); + return FALSE; + } + } +#endif + + onscreen->winsys = g_slice_new0 (CoglOnscreenEGL); + egl_onscreen = onscreen->winsys; + +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + xlib_onscreen = onscreen->winsys; + + xlib_onscreen->xwin = xwin; + xlib_onscreen->is_foreign_xwin = onscreen->foreign_xid ? TRUE : FALSE; + + egl_onscreen->egl_surface = + eglCreateWindowSurface (egl_renderer->edpy, + egl_display->egl_config, + (NativeWindowType) xlib_onscreen->xwin, + NULL); +#elif defined (COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT) + if (egl_display->have_onscreen) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_ONSCREEN, + "EGL platform only supports a single onscreen window"); + return FALSE; + } + + egl_onscreen->egl_surface = egl_display->egl_surface; + + _cogl_framebuffer_winsys_update_size (framebuffer, + egl_display->egl_surface_width, + egl_display->egl_surface_height); + egl_display->have_onscreen = TRUE; +#else +#error "Unknown EGL platform" +#endif + + return TRUE; +} + +void +_cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen) +{ + CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); + CoglContext *context = framebuffer->context; +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + CoglRendererXlib *xlib_renderer = context->display->renderer->winsys; + CoglXlibTrapState old_state; + CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; +#elif defined (COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT) + CoglDisplayEGL *egl_display = context->display->winsys; +#endif + CoglRendererEGL *egl_renderer = context->display->renderer->winsys; + CoglOnscreenEGL *egl_onscreen = onscreen->winsys; + + if (egl_onscreen->egl_surface != EGL_NO_SURFACE) + { + if (eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface) + == EGL_FALSE) + g_warning ("Failed to destroy EGL surface"); + egl_onscreen->egl_surface = EGL_NO_SURFACE; + } + +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT + egl_display->have_onscreen = FALSE; +#endif + +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + _cogl_xlib_trap_errors (&old_state); + + if (!xlib_onscreen->is_foreign_xwin && xlib_onscreen->xwin != None) + { + XDestroyWindow (xlib_renderer->xdpy, xlib_onscreen->xwin); + xlib_onscreen->xwin = None; + } + else + xlib_onscreen->xwin = None; + + XSync (xlib_renderer->xdpy, False); + + if (_cogl_xlib_untrap_errors (&old_state) != Success) + g_warning ("X Error while destroying X window"); +#endif +} + +void +_cogl_winsys_onscreen_bind (CoglOnscreen *onscreen) +{ + CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; + CoglContextEGL *egl_context = context->winsys; + CoglDisplayEGL *egl_display = context->display->winsys; + CoglRendererEGL *egl_renderer = context->display->renderer->winsys; + CoglOnscreenEGL *egl_onscreen = onscreen->winsys; + + if (egl_context->current_surface == egl_onscreen->egl_surface) + return; + + if (G_UNLIKELY (!onscreen)) + { +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT + eglMakeCurrent (egl_renderer->edpy, + egl_display->dummy_surface, + egl_display->dummy_surface, + egl_display->egl_context); + egl_context->current_surface = egl_display->dummy_surface; +#elif defined (COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT) + return; +#else +#error "Unknown EGL platform" +#endif + } + else + { + eglMakeCurrent (egl_renderer->edpy, + egl_onscreen->egl_surface, + egl_onscreen->egl_surface, + egl_display->egl_context); + egl_context->current_surface = egl_onscreen->egl_surface; + } + + if (onscreen->swap_throttled) + eglSwapInterval (egl_renderer->edpy, 1); + else + eglSwapInterval (egl_renderer->edpy, 0); +} + +void +_cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen, + int *rectangles, + int n_rectangles) +{ + CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; + CoglRendererEGL *egl_renderer = context->display->renderer->winsys; + CoglOnscreenEGL *egl_onscreen = onscreen->winsys; + + if (egl_renderer->pf_eglSwapBuffersRegion (egl_renderer->edpy, + egl_onscreen->egl_surface, + n_rectangles, + rectangles) == EGL_FALSE) + g_warning ("Error reported by eglSwapBuffersRegion"); +} + +guint32 +_cogl_winsys_get_vsync_counter (void) +{ + /* Unsupported feature */ + return 0; +} + +void +_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen) +{ + CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; + CoglRendererEGL *egl_renderer = context->display->renderer->winsys; + CoglOnscreenEGL *egl_onscreen = onscreen->winsys; + + eglSwapBuffers (egl_renderer->edpy, egl_onscreen->egl_surface); +} + +guint32 +_cogl_winsys_onscreen_x11_get_window_xid (CoglOnscreen *onscreen) +{ + CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; + return xlib_onscreen->xwin; +} + +unsigned int +_cogl_winsys_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen, + CoglSwapBuffersNotify callback, + void *user_data) +{ + /* Unsupported feature */ + return 0; +} + +void +_cogl_winsys_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen, + unsigned int id) +{ + /* Unsupported feature */ +} + +void +_cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen) +{ + CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; + CoglContextEGL *egl_context = context->winsys; + CoglOnscreenEGL *egl_onscreen = onscreen->winsys; + + if (egl_context->current_surface != egl_onscreen->egl_surface) + return; + + egl_context->current_surface = EGL_NO_SURFACE; + _cogl_winsys_onscreen_bind (onscreen); +} + +#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT +/* XXX: This is a particularly hacky _cogl_winsys interface... */ +XVisualInfo * +_cogl_winsys_xlib_get_visual_info (void) +{ + CoglDisplayEGL *egl_display; + + _COGL_GET_CONTEXT (ctx, NULL); + + g_return_val_if_fail (ctx->display->winsys, FALSE); + + egl_display = ctx->display->winsys; + + if (!egl_display->found_egl_config) + return NULL; + + return get_visual_info (ctx->display, egl_display->egl_config); +} +#endif + +EGLDisplay +_cogl_winsys_context_egl_get_egl_display (CoglContext *context) +{ + CoglRendererEGL *egl_renderer = context->display->renderer->winsys; + + return egl_renderer->edpy; +} diff --git a/clutter/cogl/cogl/winsys/cogl-winsys-private.h b/clutter/cogl/cogl/winsys/cogl-winsys-private.h index 8d56bea40..4f3d494b3 100644 --- a/clutter/cogl/cogl/winsys/cogl-winsys-private.h +++ b/clutter/cogl/cogl/winsys/cogl-winsys-private.h @@ -71,6 +71,11 @@ _cogl_winsys_context_init (CoglContext *context, GError **error); void _cogl_winsys_context_deinit (CoglContext *context); +#ifdef COGL_HAS_EGL_SUPPORT +EGLDisplay +_cogl_winsys_context_egl_get_egl_display (CoglContext *context); +#endif + gboolean _cogl_winsys_has_feature (CoglWinsysFeature feature); diff --git a/clutter/egl/clutter-backend-cex100.c b/clutter/egl/clutter-backend-cex100.c deleted file mode 100644 index f5d64034c..000000000 --- a/clutter/egl/clutter-backend-cex100.c +++ /dev/null @@ -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 . - * - * Authors: - * Tao Zhao - * Damien Lespiau - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#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; -} diff --git a/clutter/egl/clutter-backend-cex100.h b/clutter/egl/clutter-backend-cex100.h deleted file mode 100644 index 79e03d0e5..000000000 --- a/clutter/egl/clutter-backend-cex100.h +++ /dev/null @@ -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 . - * - * Author: - * Damien Lespiau - */ - -#ifndef __CLUTTER_BACKEND_CEX100_H__ -#define __CLUTTER_BACKEND_CEX100_H__ - -#include - -#include - -#include - -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__ */ diff --git a/clutter/egl/clutter-backend-egl.c b/clutter/egl/clutter-backend-egl.c index 2af37de6c..ec2d781bc 100644 --- a/clutter/egl/clutter-backend-egl.c +++ b/clutter/egl/clutter-backend-egl.c @@ -48,12 +48,20 @@ #include "clutter-private.h" #include "clutter-main.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 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 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_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 clutter_backend_egl_pre_parse (ClutterBackend *backend, GError **error) { const gchar *env_string; #ifdef COGL_HAS_X11_SUPPORT - ClutterBackendClass *backend_x11_class = + ClutterBackendClass *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; #endif env_string = g_getenv ("CLUTTER_VBLANK"); if (env_string) { - clutter_vblank_name = g_strdup (env_string); + clutter_vblank = g_strdup (env_string); env_string = NULL; } - env_string = g_getenv ("CLUTTER_FB_DEVICE"); - if (env_string != NULL && env_string[0] != '\0') - clutter_fb_device = g_strdup (env_string); - return TRUE; } @@ -99,411 +112,21 @@ 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 = + ClutterBackendClass *parent_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)) + if (!parent_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); + return TRUE; #endif 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; } -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 static ClutterDeviceManager * clutter_backend_egl_get_device_manager (ClutterBackend *backend) @@ -553,72 +176,26 @@ clutter_backend_egl_finalize (GObject *gobject) static void clutter_backend_egl_dispose (GObject *gobject) { + ClutterBackend *backend = CLUTTER_BACKEND (gobject); +#ifdef HAVE_TSLIB 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 - destroy the egl context. Otherwise the actors may try to make GL - calls during destruction which causes a crash */ + /* We chain up before disposing our CoglContext so that we will + * destroy all of the stages first. Otherwise the actors may try to + * make Cogl calls during destruction which would cause a crash */ G_OBJECT_CLASS (_clutter_backend_egl_parent_class)->dispose (gobject); + if (backend->cogl_context) + { + cogl_object_unref (backend->cogl_context); + backend->cogl_context = NULL; + } + #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); - 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) { g_timer_destroy (backend_egl->event_timer); @@ -651,87 +228,149 @@ clutter_backend_egl_constructor (GType gtype, return g_object_ref (backend_singleton); } -static gboolean -check_vblank_env (const char *name) -{ - if (clutter_vblank_name && !g_ascii_strcasecmp (clutter_vblank_name, name)) - return TRUE; - - return FALSE; -} - static ClutterFeatureFlags clutter_backend_egl_get_features (ClutterBackend *backend) { ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend); - const gchar *egl_extensions = NULL; - const gchar *gl_extensions = NULL; - ClutterFeatureFlags flags; - - g_assert (backend_egl->egl_context != NULL); +#ifdef COGL_HAS_XLIB_SUPPORT + ClutterBackendClass *parent_class; +#endif + ClutterFeatureFlags flags = 0; #ifdef COGL_HAS_XLIB_SUPPORT - { - ClutterBackendClass *parent_class; + parent_class = CLUTTER_BACKEND_CLASS (_clutter_backend_egl_parent_class); - parent_class = CLUTTER_BACKEND_CLASS (_clutter_backend_egl_parent_class); - flags = parent_class->get_features (backend); - flags |= CLUTTER_FEATURE_STAGE_MULTIPLE; - } -#else - flags = CLUTTER_FEATURE_STAGE_STATIC; + flags = parent_class->get_features (backend); #endif - /* First check for explicit disabling or it set elsewhere (eg NVIDIA) */ - if (check_vblank_env ("none")) - backend_egl->vblank_type = CLUTTER_VBLANK_NONE; + if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN)) + { + CLUTTER_NOTE (BACKEND, "Cogl supports multiple onscreen framebuffers"); + flags |= CLUTTER_FEATURE_STAGE_MULTIPLE; + } else - 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, - "Using EGL_NOK_swap_region for sub_buffer copies"); - 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; + CLUTTER_NOTE (BACKEND, "Cogl only supports one onscreen framebuffer"); + flags |= CLUTTER_FEATURE_STAGE_STATIC; } - gl_extensions = (const gchar *)glGetString (GL_EXTENSIONS); - -#if 0 /* XXX need GL_ARB_draw_buffers */ - if (!backend_egl->swap_buffers_region && - cogl_clutter_check_extension ("GL_EXT_framebuffer_blit", gl_extensions)) + if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_THROTTLE)) { - CLUTTER_NOTE (BACKEND, - "Using glBlitFramebuffer fallback for sub_buffer copies"); - 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; + CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers throttling"); + flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK; } -#endif + else + CLUTTER_NOTE (BACKEND, "Cogl doesn't support swap buffers throttling"); - CLUTTER_NOTE (BACKEND, "Checking features\n" - "GL_VENDOR: %s\n" - "GL_RENDERER: %s\n" - "GL_VERSION: %s\n" - "EGL_VENDOR: %s\n" - "EGL_VERSION: %s\n" - "EGL_EXTENSIONS: %s\n", - glGetString (GL_VENDOR), - glGetString (GL_RENDERER), - glGetString (GL_VERSION), - eglQueryString (backend_egl->edpy, EGL_VENDOR), - eglQueryString (backend_egl->edpy, EGL_VERSION), - eglQueryString (backend_egl->edpy, EGL_EXTENSIONS)); + if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT)) + { + CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers complete events"); + flags |= CLUTTER_FEATURE_SWAP_EVENTS; + } + + if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION)) + { + CLUTTER_NOTE (BACKEND, "Cogl supports swapping buffer regions"); + backend_egl->can_blit_sub_buffer = TRUE; + } 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 * clutter_backend_egl_create_stage (ClutterBackend *backend, ClutterStage *wrapper, @@ -768,7 +407,8 @@ clutter_backend_egl_create_stage (ClutterBackend *backend, { g_set_error (error, CLUTTER_INIT_ERROR, 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; } @@ -785,57 +425,15 @@ clutter_backend_egl_create_stage (ClutterBackend *backend, return stage; } -#ifdef COGL_HAS_XLIB_SUPPORT -static XVisualInfo * -clutter_backend_egl_get_visual_info (ClutterBackendX11 *backend_x11) +static void +clutter_backend_egl_ensure_context (ClutterBackend *backend, + ClutterStage *stage) { - 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; + ClutterStageEGL *stage_egl = + CLUTTER_STAGE_EGL (_clutter_stage_get_window (stage)); - 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; + cogl_set_framebuffer (COGL_FRAMEBUFFER (stage_egl->onscreen)); } -#endif static void _clutter_backend_egl_class_init (ClutterBackendEGLClass *klass) @@ -869,29 +467,16 @@ _clutter_backend_egl_class_init (ClutterBackendEGLClass *klass) static void _clutter_backend_egl_init (ClutterBackendEGL *backend_egl) { -#ifndef COGL_HAS_XLIB_SUPPORT - #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 } -#ifdef CLUTTER_EGL_BACKEND_GENERIC GType _clutter_backend_impl_get_type (void) { return _clutter_backend_egl_get_type (); } -#endif EGLDisplay clutter_eglx_display (void) @@ -914,5 +499,25 @@ clutter_egl_get_egl_display (void) 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 diff --git a/clutter/egl/clutter-backend-egl.h b/clutter/egl/clutter-backend-egl.h index c946380b6..e1b082d84 100644 --- a/clutter/egl/clutter-backend-egl.h +++ b/clutter/egl/clutter-backend-egl.h @@ -57,52 +57,14 @@ G_BEGIN_DECLS typedef struct _ClutterBackendEGL ClutterBackendEGL; 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 { #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; @@ -115,20 +77,11 @@ struct _ClutterBackendEGL /* event timer */ GTimer *event_timer; - /* FB device */ - gint fb_device_id; - #endif /* COGL_HAS_X11_SUPPORT */ - gint egl_version_major; - gint egl_version_minor; + CoglContext *cogl_context; - ClutterEGLVBlankType vblank_type; - - gboolean can_blit_sub_buffer; - BlitFramebufferProc blit_framebuffer; - SwapBuffersRegionProc swap_buffers_region; - gboolean blit_sub_buffer_is_synchronized; + gboolean can_blit_sub_buffer; }; 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_uninit (ClutterBackendEGL *backend); -void -_clutter_backend_egl_blit_sub_buffer (ClutterBackendEGL *backend_egl, - EGLSurface drawable, - int x, int y, int width, int height); +G_CONST_RETURN gchar* +_clutter_backend_egl_get_vblank (void); G_END_DECLS diff --git a/clutter/egl/clutter-stage-egl.c b/clutter/egl/clutter-stage-egl.c index 276c47956..887494ed0 100644 --- a/clutter/egl/clutter-stage-egl.c +++ b/clutter/egl/clutter-stage-egl.c @@ -32,41 +32,36 @@ G_DEFINE_TYPE_WITH_CODE (ClutterStageEGL, 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) { - 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 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) - { - 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 (); + cogl_object_unref (stage_egl->onscreen); + stage_egl->onscreen = NULL; } 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; + ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window); +#ifdef COGL_HAS_XLIB_SUPPORT + ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); +#endif + ClutterBackend *backend; 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]", G_OBJECT_TYPE_NAME (stage_egl), @@ -75,40 +70,49 @@ clutter_stage_egl_realize (ClutterStageWindow *stage_window) backend = clutter_get_default_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)) - return FALSE; + stage_egl->onscreen = cogl_onscreen_new (backend->cogl_context, + 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 = - eglCreateWindowSurface (edpy, - backend_egl->egl_config, - (NativeWindowType) stage_x11->xwin, - NULL); + g_warning ("Failed to allocate stage: %s", error->message); + g_error_free (error); + cogl_object_unref (stage_egl->onscreen); + stage_egl->onscreen = 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) - g_warning ("Unable to create an EGL surface"); +#ifdef COGL_HAS_XLIB_SUPPORT + 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); -} - -#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 */ +#else return TRUE; +#endif } +#ifndef COGL_HAS_XLIB_SUPPORT + +/* FIXME: Move this warnings up into clutter-stage.c */ + static void clutter_stage_egl_set_fullscreen (ClutterStageWindow *stage_window, gboolean fullscreen) @@ -161,14 +165,25 @@ 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; + if (stage_egl->onscreen) + { + CoglFramebuffer *framebuffer = + COGL_FRAMEBUFFER (stage_egl->onscreen); - geometry->width = backend_egl->surface_width; - geometry->height = backend_egl->surface_height; + geometry->x = geometry->y = 0; + + 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; } +/* XXX: This is basically identical to clutter_stage_glx_redraw */ static void clutter_stage_egl_redraw (ClutterStageWindow *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; - EGLSurface egl_surface; + ClutterBackend *backend; + ClutterBackendEGL *backend_egl; gboolean may_use_clipped_redraw; gboolean use_clipped_redraw; + + CLUTTER_STATIC_TIMER (painting_timer, + "Redrawing", /* parent */ + "Painting actors", + "The time spent painting actors", + 0 /* no application private data */); + CLUTTER_STATIC_TIMER (swapbuffers_timer, + "Redrawing", /* parent */ + "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 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 + 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) && - /* NB: a zero width clip == full stage redraw */ + /* NB: a zero width redraw clip == full stage redraw */ stage_egl->bounding_redraw_clip.width != 0 && /* some drivers struggle to get going and produce some junk * frames when starting up... */ @@ -303,7 +339,9 @@ clutter_stage_egl_redraw (ClutterStageWindow *stage_window) && G_LIKELY (stage_x11->clipped_redraws_cool_off == 0) #endif ) - may_use_clipped_redraw = TRUE; + { + may_use_clipped_redraw = TRUE; + } else may_use_clipped_redraw = FALSE; @@ -327,11 +365,12 @@ clutter_stage_egl_redraw (ClutterStageWindow *stage_window) else _clutter_stage_do_paint (CLUTTER_STAGE (wrapper), NULL); - if (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS && - may_use_clipped_redraw) + if (may_use_clipped_redraw && + G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))) { - ClutterGeometry *clip = &stage_egl->bounding_redraw_clip; static CoglMaterial *outline = NULL; + ClutterGeometry *clip = &stage_egl->bounding_redraw_clip; + ClutterActor *actor = CLUTTER_ACTOR (wrapper); CoglHandle vbo; float x_1 = clip->x; float x_2 = clip->x + clip->width; @@ -363,7 +402,7 @@ clutter_stage_egl_redraw (ClutterStageWindow *stage_window) cogl_push_matrix (); 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_source (outline); 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_flush (); + CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer); /* push on the screen */ if (use_clipped_redraw) { 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, - "_egl_blit_sub_buffer (surface: %p, " - "x: %d, y: %d, " - "width: %d, height: %d)", - egl_surface, - stage_egl->bounding_redraw_clip.x, - stage_egl->bounding_redraw_clip.y, - stage_egl->bounding_redraw_clip.width, - stage_egl->bounding_redraw_clip.height); + "cogl_framebuffer_swap_region (onscreen: %p, " + "x: %d, y: %d, " + "width: %d, height: %d)", + stage_egl->onscreen, + copy_area[0], copy_area[1], copy_area[2], copy_area[3]); - 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_backend_egl_blit_sub_buffer (backend_egl, - egl_surface, - copy_area.x, - copy_area.y, - copy_area.width, - copy_area.height); + + cogl_framebuffer_swap_region (COGL_FRAMEBUFFER (stage_egl->onscreen), + copy_area, 1); + CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer); } else { - CLUTTER_NOTE (BACKEND, "eglwapBuffers (display: %p, surface: %p)", - backend_egl->edpy, - egl_surface); + CLUTTER_NOTE (BACKEND, "cogl_framebuffer_swap_buffers (onscreen: %p)", + stage_egl->onscreen); 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); } @@ -467,25 +512,14 @@ _clutter_stage_egl_class_init (ClutterStageEGLClass *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 */ - +#else static void _clutter_stage_egl_class_init (ClutterStageEGLClass *klass) { } +#endif /* COGL_HAS_X11_SUPPORT */ 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 */ diff --git a/clutter/egl/clutter-stage-egl.h b/clutter/egl/clutter-stage-egl.h index 86e075e1d..e080f3cf7 100644 --- a/clutter/egl/clutter-stage-egl.h +++ b/clutter/egl/clutter-stage-egl.h @@ -36,8 +36,6 @@ struct _ClutterStageEGL ClutterStageX11 parent_instance; - EGLSurface egl_surface; - #else GObject parent_instance; @@ -50,6 +48,8 @@ struct _ClutterStageEGL #endif + CoglOnscreen *onscreen; + /* We only enable clipped redraws after 2 frames, since we've seen * a lot of drivers can struggle to get going and may output some * junk frames to start with. */ diff --git a/clutter/glx/clutter-backend-glx.h b/clutter/glx/clutter-backend-glx.h index a1d6eaec4..0b64aa4d6 100644 --- a/clutter/glx/clutter-backend-glx.h +++ b/clutter/glx/clutter-backend-glx.h @@ -56,16 +56,9 @@ struct _ClutterBackendGLX { ClutterBackendX11 parent_instance; - int error_base; - int event_base; + CoglContext *cogl_context; - CoglContext *cogl_context; - - /* Vblank stuff */ - ClutterGLXVBlankType vblank_type; - unsigned int last_video_sync_count; - - gboolean can_blit_sub_buffer; + gboolean can_blit_sub_buffer; /* props */ Atom atom_WM_STATE; diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index 36e69166f..d0553b0be 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -1358,111 +1358,6 @@ clutter_x11_set_stage_foreign (ClutterStage *stage, 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 _clutter_stage_x11_set_user_time (ClutterStageX11 *stage_x11, guint32 user_time) diff --git a/clutter/x11/clutter-stage-x11.h b/clutter/x11/clutter-stage-x11.h index f2621f9a2..71732f5b7 100644 --- a/clutter/x11/clutter-stage-x11.h +++ b/clutter/x11/clutter-stage-x11.h @@ -81,9 +81,6 @@ struct _ClutterStageX11Class GType _clutter_stage_x11_get_type (void) G_GNUC_CONST; /* 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, guint32 user_time); gboolean _clutter_stage_x11_get_root_coords (ClutterStageX11 *stage_x11, diff --git a/configure.ac b/configure.ac index 65d044f99..4e98302a9 100644 --- a/configure.ac +++ b/configure.ac @@ -459,6 +459,8 @@ AS_IF([test "x$SUPPORT_GLX" = "x1"], 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_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], [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"], [ AC_DEFINE([COGL_HAS_EGL_PLATFORM_POWERVR_NULL_SUPPORT], [1], [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"],