fe01ec6323
Most of clutter_stage_egl_realize was renamed to _clutter_stage_egl_try_realize which now takes a cookie indicating which fallback number should tried next. clutter_stage_egl_realize now keeps trying to realize with successive fallback numbers until it succeeds or runs out of fallbacks. The only fallback supported for now is for hardware with no stencil buffer support.
327 lines
9.7 KiB
C
327 lines
9.7 KiB
C
#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)
|
|
{
|
|
}
|