#ifdef HAVE_CONFIG_H #include "config.h" #endif #include "clutter-backend-egl.h" #include "clutter-stage-egl.h" #include "clutter-eglx.h" #include "../clutter-main.h" #include "../clutter-feature.h" #include "../clutter-color.h" #include "../clutter-util.h" #include "../clutter-event.h" #include "../clutter-enum-types.h" #include "../clutter-private.h" #include "../clutter-debug.h" #include "../clutter-units.h" #include "../clutter-container.h" #include "../clutter-stage.h" #include "../clutter-stage-window.h" static ClutterStageWindowIface *clutter_stage_egl_parent_iface = NULL; static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface); G_DEFINE_TYPE_WITH_CODE (ClutterStageEGL, clutter_stage_egl, CLUTTER_TYPE_STAGE_X11, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW, clutter_stage_window_iface_init)); 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 stage"); clutter_x11_trap_x_errors (); if (!stage_x11->is_foreign_xwin && stage_x11->xwin != None) { XDestroyWindow (backend_x11->xdpy, stage_x11->xwin); stage_x11->xwin = None; } else stage_x11->xwin = None; if (stage_egl->egl_surface) { eglDestroySurface (clutter_eglx_display (), stage_egl->egl_surface); stage_egl->egl_surface = EGL_NO_SURFACE; } XSync (backend_x11->xdpy, False); clutter_x11_untrap_x_errors (); } static gboolean _clutter_stage_egl_try_realize (ClutterStageWindow *stage_window, int *retry_cookie) { ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window); ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); ClutterBackend *backend; ClutterBackendEGL *backend_egl; ClutterBackendX11 *backend_x11; EGLConfig config; EGLint config_count; EGLBoolean status; int i; int num_configs; EGLConfig *all_configs; EGLint cfg_attribs[] = { /* NB: This must be the first attribute, since we may * try and fallback to no stencil buffer */ EGL_STENCIL_SIZE, 8, EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6, EGL_BLUE_SIZE, 5, EGL_BUFFER_SIZE, EGL_DONT_CARE, #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 }; EGLDisplay edpy; /* 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 */ backend = clutter_get_default_backend (); backend_egl = CLUTTER_BACKEND_EGL (backend); backend_x11 = CLUTTER_BACKEND_X11 (backend); edpy = clutter_eglx_display (); eglGetConfigs (edpy, NULL, 0, &num_configs); all_configs = g_malloc (num_configs * sizeof (EGLConfig)); eglGetConfigs (clutter_eglx_display (), all_configs, num_configs, &num_configs); for (i = 0; i < num_configs; ++i) { EGLint red = -1, green = -1, blue = -1, alpha = -1, stencil = -1; eglGetConfigAttrib (edpy, all_configs[i], EGL_RED_SIZE, &red); eglGetConfigAttrib (edpy, all_configs[i], EGL_GREEN_SIZE, &green); eglGetConfigAttrib (edpy, all_configs[i], EGL_BLUE_SIZE, &blue); eglGetConfigAttrib (edpy, all_configs[i], EGL_ALPHA_SIZE, &alpha); eglGetConfigAttrib (edpy, all_configs[i], EGL_STENCIL_SIZE, &stencil); CLUTTER_NOTE (BACKEND, "EGLConfig == R:%d G:%d B:%d A:%d S:%d \n", red, green, blue, alpha, stencil); } g_free (all_configs); status = eglChooseConfig (edpy, cfg_attribs, &config, 1, &config_count); if (status != EGL_TRUE) { g_warning ("eglChooseConfig failed"); goto fail; } if (stage_x11->xwin == None) stage_x11->xwin = XCreateSimpleWindow (backend_x11->xdpy, backend_x11->xwin_root, 0, 0, stage_x11->xwin_width, stage_x11->xwin_height, 0, 0, WhitePixel (backend_x11->xdpy, backend_x11->xscreen_num)); if (clutter_x11_has_event_retrieval ()) { if (clutter_x11_has_xinput ()) { XSelectInput (backend_x11->xdpy, stage_x11->xwin, StructureNotifyMask | FocusChangeMask | ExposureMask | EnterWindowMask | LeaveWindowMask | PropertyChangeMask); #ifdef USE_XINPUT _clutter_x11_select_events (stage_x11->xwin); #endif } else XSelectInput (backend_x11->xdpy, stage_x11->xwin, StructureNotifyMask | FocusChangeMask | ExposureMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PropertyChangeMask); } clutter_stage_x11_fix_window_size (stage_x11, -1, -1); clutter_stage_x11_set_wm_protocols (stage_x11); if (stage_egl->egl_surface != EGL_NO_SURFACE) { eglDestroySurface (edpy, stage_egl->egl_surface); stage_egl->egl_surface = EGL_NO_SURFACE; } stage_egl->egl_surface = eglCreateWindowSurface (edpy, config, (NativeWindowType) stage_x11->xwin, NULL); if (stage_egl->egl_surface == EGL_NO_SURFACE) { g_warning ("Unable to create an EGL surface"); goto fail; } if (G_UNLIKELY (backend_egl->egl_context == None)) { #ifdef HAVE_COGL_GLES2 static const EGLint attribs[3] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; backend_egl->egl_context = eglCreateContext (edpy, config, EGL_NO_CONTEXT, attribs); #else /* Seems some GLES implementations 1.x do not like attribs... */ backend_egl->egl_context = eglCreateContext (edpy, config, EGL_NO_CONTEXT, NULL); #endif if (backend_egl->egl_context == EGL_NO_CONTEXT) { g_warning ("Unable to create a suitable EGL context"); goto fail; } backend_egl->egl_config = config; CLUTTER_NOTE (GL, "Created EGL Context"); } *retry_cookie = 0; return TRUE; fail: if (stage_egl->egl_surface != EGL_NO_SURFACE) { eglDestroySurface (backend_egl->edpy, stage_egl->egl_surface); stage_egl->egl_surface = EGL_NO_SURFACE; } if (stage_x11->xwin != None) { XDestroyWindow (backend_x11->xdpy, stage_x11->xwin); stage_x11->xwin = None; } /* NB: We currently only support a single fallback option */ if (*retry_cookie == 0) *retry_cookie = 1; /* tell the caller to try again */ else *retry_cookie = 0; /* tell caller not to try again! */ return FALSE; } static gboolean clutter_stage_egl_realize (ClutterStageWindow *stage_window) { int retry_cookie = 0; CLUTTER_NOTE (BACKEND, "Realizing main stage"); while (1) { /* _clutter_stage_egl_try_realize supports fallbacks, and the number of * fallbacks already tried is tracked in the retry_cookie, so what we are * doing here is re-trying until we get told there are no more fallback * options... */ if (_clutter_stage_egl_try_realize (stage_window, &retry_cookie)) { gboolean ret = clutter_stage_egl_parent_iface->realize (stage_window); if (G_LIKELY (ret)) CLUTTER_NOTE (BACKEND, "Successfully realized stage"); return ret; } if (retry_cookie == 0) return FALSE; /* we've been told not to try again! */ g_warning ("%s: Trying fallback", G_STRFUNC); } g_return_val_if_reached (FALSE); } static void clutter_stage_egl_dispose (GObject *gobject) { G_OBJECT_CLASS (clutter_stage_egl_parent_class)->dispose (gobject); } static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface) { clutter_stage_egl_parent_iface = g_type_interface_peek_parent (iface); iface->realize = clutter_stage_egl_realize; iface->unrealize = clutter_stage_egl_unrealize; /* the rest is inherited from ClutterStageX11 */ } static void clutter_stage_egl_class_init (ClutterStageEGLClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->dispose = clutter_stage_egl_dispose; } static void clutter_stage_egl_init (ClutterStageEGL *stage) { }