From d5d11f18786b5e567f394359966a556cac7697a8 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Fri, 25 Feb 2011 00:31:41 +0000 Subject: [PATCH] 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. --- cogl/Makefile.am | 9 +- cogl/cogl-context.c | 9 + cogl/cogl-context.h | 17 + .../cogl-winsys-egl-feature-functions.h | 57 + cogl/winsys/cogl-winsys-egl.c | 1050 ++++++++++++++++- cogl/winsys/cogl-winsys-private.h | 5 + 6 files changed, 1134 insertions(+), 13 deletions(-) create mode 100644 cogl/winsys/cogl-winsys-egl-feature-functions.h diff --git a/cogl/Makefile.am b/cogl/Makefile.am index 426b59ae0..335f21d7a 100644 --- a/cogl/Makefile.am +++ b/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/cogl/cogl-context.c b/cogl/cogl-context.c index ac76d4fae..e1b18f6e5 100644 --- a/cogl/cogl-context.c +++ b/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/cogl/cogl-context.h b/cogl/cogl-context.h index 9394fbfa2..7cd0785d6 100644 --- a/cogl/cogl-context.h +++ b/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/cogl/winsys/cogl-winsys-egl-feature-functions.h b/cogl/winsys/cogl-winsys-egl-feature-functions.h new file mode 100644 index 000000000..58c07348d --- /dev/null +++ b/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/cogl/winsys/cogl-winsys-egl.c b/cogl/winsys/cogl-winsys-egl.c index bafafc0ac..b6446dc1b 100644 --- a/cogl/winsys/cogl-winsys-egl.c +++ b/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/cogl/winsys/cogl-winsys-private.h b/cogl/winsys/cogl-winsys-private.h index 8d56bea40..4f3d494b3 100644 --- a/cogl/winsys/cogl-winsys-private.h +++ b/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);