[x11] Abstract XVisualInfo creation

The XVisualInfo for GL is created when a stage is being realized.
When embedding Clutter inside another toolkit we might not want to
realize a stage to extract the XVisualInfo, then set the stage
window using a foreign X Window -- which will cause a re-realization.

Instead, we should abstract as much as possible into the X11 backend.

Unfortunately, the XVisualInfo for GL is requested using GLX API; for
this reason we have to create a ClutterBackendX11 method that we
override inside the ClutterBackendGLX implementation.

This also allows us to move a little bit of complexity from out of
the stage realization, which is currently a very delicate and hard
to debug section.
This commit is contained in:
Emmanuele Bassi 2009-05-13 21:49:45 +01:00
parent dd95939d26
commit e59a19bd03
5 changed files with 107 additions and 41 deletions

View File

@ -434,8 +434,11 @@ clutter_backend_glx_redraw (ClutterBackend *backend,
ClutterStageWindow *impl;
impl = _clutter_stage_get_window (stage);
if (!impl)
return;
if (G_UNLIKELY (impl == NULL))
{
CLUTTER_NOTE (BACKEND, "Stage [%p] has no implementation", stage);
return;
}
g_assert (CLUTTER_IS_STAGE_GLX (impl));
@ -445,18 +448,23 @@ clutter_backend_glx_redraw (ClutterBackend *backend,
/* this will cause the stage implementation to be painted */
clutter_actor_paint (CLUTTER_ACTOR (stage));
/* Why this paint is done in backend as likely GL windowing system
* specific calls, like swapping buffers.
*/
if (stage_x11->xwin)
if (stage_x11->xwin != None)
{
/* wait for the next vblank */
CLUTTER_NOTE (BACKEND, "Waiting for vblank");
clutter_backend_glx_wait_for_vblank (CLUTTER_BACKEND_GLX (backend));
/* push on the screen */
CLUTTER_NOTE (BACKEND, "glXSwapBuffers (display: %p, window: 0x%lx)",
stage_x11->xdpy,
(unsigned long) stage_x11->xwin);
glXSwapBuffers (stage_x11->xdpy, stage_x11->xwin);
}
else
{
/* offscreen */
glXWaitGL ();
CLUTTER_GLERR ();
}
}
@ -494,11 +502,56 @@ clutter_backend_glx_create_stage (ClutterBackend *backend,
return stage;
}
static XVisualInfo *
clutter_backend_glx_get_visual_info (ClutterBackendX11 *backend_x11,
gboolean for_offscreen)
{
XVisualInfo *xvisinfo;
int onscreen_gl_attributes[] = {
GLX_RGBA,
GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_STENCIL_SIZE, 1,
0
};
int offscreen_gl_attributes[] = {
GLX_RGBA,
GLX_USE_GL,
GLX_DEPTH_SIZE, 0,
GLX_ALPHA_SIZE, 0,
GLX_STENCIL_SIZE, 1,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
0
};
if (backend_x11->xdpy == None || backend_x11->xscreen == None)
return NULL;
CLUTTER_NOTE (BACKEND,
"Retrieving GL visual (for %s use), dpy: %p, xscreen; %p (%d)",
for_offscreen ? "offscreen" : "onscreen",
backend_x11->xdpy,
backend_x11->xscreen,
backend_x11->xscreen_num);
xvisinfo = glXChooseVisual (backend_x11->xdpy,
backend_x11->xscreen_num,
for_offscreen ? offscreen_gl_attributes
: onscreen_gl_attributes);
return xvisinfo;
}
static void
clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
ClutterBackendX11Class *backendx11_class = CLUTTER_BACKEND_X11_CLASS (klass);
gobject_class->constructor = clutter_backend_glx_constructor;
gobject_class->dispose = clutter_backend_glx_dispose;
@ -511,6 +564,8 @@ clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
backend_class->get_features = clutter_backend_glx_get_features;
backend_class->redraw = clutter_backend_glx_redraw;
backend_class->ensure_context = clutter_backend_glx_ensure_context;
backendx11_class->get_visual_info = clutter_backend_glx_get_visual_info;
}
static void

View File

@ -124,26 +124,14 @@ clutter_stage_glx_realize (ClutterActor *actor)
if (G_LIKELY (!is_offscreen))
{
int gl_attributes[] =
{
GLX_RGBA,
GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_STENCIL_SIZE, 1,
0
};
if (stage_x11->xvisinfo != None)
{
XFree (stage_x11->xvisinfo);
stage_x11->xvisinfo = None;
}
stage_x11->xvisinfo = glXChooseVisual (stage_x11->xdpy,
stage_x11->xscreen,
gl_attributes);
stage_x11->xvisinfo =
clutter_backend_x11_get_visual_info (backend_x11, FALSE);
if (stage_x11->xvisinfo == None)
{
g_critical ("Unable to find suitable GL visual.");
@ -232,27 +220,15 @@ clutter_stage_glx_realize (ClutterActor *actor)
}
else
{
int gl_attributes[] = {
GLX_DEPTH_SIZE, 0,
GLX_ALPHA_SIZE, 0,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_USE_GL,
GLX_RGBA,
0
};
if (stage_x11->xvisinfo != None)
{
XFree (stage_x11->xvisinfo);
stage_x11->xvisinfo = None;
}
if (stage_x11->xvisinfo)
XFree (stage_x11->xvisinfo);
stage_x11->xvisinfo = NULL;
CLUTTER_NOTE (GL, "glXChooseVisual");
stage_x11->xvisinfo = glXChooseVisual (stage_x11->xdpy,
stage_x11->xscreen,
gl_attributes);
if (!stage_x11->xvisinfo)
stage_x11->xvisinfo =
clutter_backend_x11_get_visual_info (backend_x11, TRUE);
if (stage_x11->xvisinfo == None)
{
g_critical ("Unable to find suitable GL visual.");
goto fail;

View File

@ -969,3 +969,17 @@ clutter_x11_has_composite_extension (void)
return have_composite;
}
XVisualInfo *
clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11,
gboolean for_offscreen)
{
ClutterBackendX11Class *klass;
g_return_val_if_fail (CLUTTER_IS_BACKEND_X11 (backend_x11), NULL);
klass = CLUTTER_BACKEND_X11_GET_CLASS (backend_x11);
if (klass->get_visual_info)
return klass->get_visual_info (backend_x11, for_offscreen);
return NULL;
}

View File

@ -90,6 +90,9 @@ struct _ClutterBackendX11
struct _ClutterBackendX11Class
{
ClutterBackendClass parent_class;
XVisualInfo *(* get_visual_info) (ClutterBackendX11 *backend,
gboolean for_offscreen);
};
void _clutter_backend_x11_events_init (ClutterBackend *backend);
@ -120,6 +123,10 @@ clutter_backend_x11_add_options (ClutterBackend *backend,
ClutterFeatureFlags
clutter_backend_x11_get_features (ClutterBackend *backend);
XVisualInfo *
clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11,
gboolean for_offscreen);
#ifdef USE_XINPUT
void
_clutter_x11_register_xinput (void);

View File

@ -656,13 +656,27 @@ XVisualInfo *
clutter_x11_get_stage_visual (ClutterStage *stage)
{
ClutterStageWindow *impl;
ClutterStageX11 *stage_x11;
gboolean is_offscreen = FALSE;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
g_object_get (G_OBJECT (stage), "offscreen", &is_offscreen, NULL);
impl = _clutter_stage_get_window (stage);
g_assert (CLUTTER_IS_STAGE_X11 (impl));
return CLUTTER_STAGE_X11 (impl)->xvisinfo;
stage_x11 = CLUTTER_STAGE_X11 (impl);
if (stage_x11->xvisinfo == NULL)
{
ClutterBackendX11 *backend_x11 = stage_x11->backend;
stage_x11->xvisinfo =
clutter_backend_x11_get_visual_info (backend_x11, is_offscreen);
}
return stage_x11->xvisinfo;
}
typedef struct {