From: Robert Bragg Date: Fri, 25 Feb 2011 00:31:41 +0000 (+0000) Subject: Moves all EGL code down from Clutter to Cogl X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c55cffbb6b5c75d2af073b7c5be857acb97b6acf;p=profile%2Fivi%2Fclutter.git 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. --- diff --git a/clutter/Makefile.am b/clutter/Makefile.am index 480474d..d171178 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 426b59a..335f21d 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 ac76d4f..e1b18f6 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 9394fbf..7cd0785 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 0000000..58c0734 --- /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 bafafc0..b6446dc 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 + +#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 -#include -#include +#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 8d56bea..4f3d494 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 f5d6403..0000000 --- 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 79e03d0..0000000 --- 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 2af37de..ec2d781 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,409 +112,19 @@ 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); -#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 */ + g_atexit (clutter_backend_at_exit); 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 @@ -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); -#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) + if (backend->cogl_context) { - 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; + 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); + if (backend_egl->event_timer != NULL) { g_timer_destroy (backend_egl->event_timer); @@ -651,85 +228,147 @@ 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); + { + CLUTTER_NOTE (BACKEND, "Cogl only supports one onscreen framebuffer"); + flags |= CLUTTER_FEATURE_STAGE_STATIC; + } - if (cogl_clutter_check_extension ("EGL_NOK_swap_region", egl_extensions)) + if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_THROTTLE)) { - 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 supports swap buffers throttling"); + flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK; } + else + CLUTTER_NOTE (BACKEND, "Cogl doesn't support swap buffers throttling"); - gl_extensions = (const gchar *)glGetString (GL_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 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_REGION)) { - CLUTTER_NOTE (BACKEND, - "Using glBlitFramebuffer fallback for sub_buffer copies"); - backend_egl->blit_framebuffer = - (BlitFramebufferProc) cogl_get_proc_address ("glBlitFramebuffer"); + CLUTTER_NOTE (BACKEND, "Cogl supports swapping buffer regions"); backend_egl->can_blit_sub_buffer = TRUE; - backend_egl->blit_sub_buffer_is_synchronized = FALSE; } + + 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 - 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)); +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; - return flags; + 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 * @@ -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; - - 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; - } + ClutterStageEGL *stage_egl = + CLUTTER_STAGE_EGL (_clutter_stage_get_window (stage)); - 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 c946380..e1b082d 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; - - ClutterEGLVBlankType vblank_type; + CoglContext *cogl_context; - 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 276c479..887494e 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 (); - - 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); +#ifdef COGL_HAS_XLIB_SUPPORT + /* chain up to the StageX11 implementation */ + clutter_stage_window_parent_iface->unrealize (stage_window); +#endif - 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,39 +70,48 @@ 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 + + clutter_vblank = _clutter_backend_egl_get_vblank (); + if (clutter_vblank && strcmp (clutter_vblank, "none") == 0) + cogl_onscreen_set_swap_throttled (stage_egl->onscreen, FALSE); - if (stage_egl->egl_surface == EGL_NO_SURFACE) + 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 + return TRUE; +#endif } -#else /* COGL_HAS_XLIB_SUPPORT */ +#ifndef 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; -} +/* FIXME: Move this warnings up into clutter-stage.c */ static void clutter_stage_egl_set_fullscreen (ClutterStageWindow *stage_window, @@ -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->x = geometry->y = 0; - geometry->width = backend_egl->surface_width; - 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; } +/* 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); - - copy_area.x = clip->x; - copy_area.y = clip->y; - copy_area.width = clip->width; - copy_area.height = 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]); + 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 86e075e..e080f3c 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 a1d6eae..0b64aa4 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 36e6916..d0553b0 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -1359,111 +1359,6 @@ clutter_x11_set_stage_foreign (ClutterStage *stage, } 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 f2621f9..71732f5 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 65d044f..4e98302 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"],