From e59a19bd03964aacfa64479fdb51555350992989 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 13 May 2009 21:49:45 +0100 Subject: [PATCH] [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. --- clutter/glx/clutter-backend-glx.c | 67 ++++++++++++++++++++++++++++--- clutter/glx/clutter-stage-glx.c | 44 +++++--------------- clutter/x11/clutter-backend-x11.c | 14 +++++++ clutter/x11/clutter-backend-x11.h | 7 ++++ clutter/x11/clutter-stage-x11.c | 16 +++++++- 5 files changed, 107 insertions(+), 41 deletions(-) diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c index 7ddc1ad6e..c255aeacc 100644 --- a/clutter/glx/clutter-backend-glx.c +++ b/clutter/glx/clutter-backend-glx.c @@ -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 diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c index f8d2d4987..fb47ae9da 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -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; diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c index 28fe3e825..d5537c206 100644 --- a/clutter/x11/clutter-backend-x11.c +++ b/clutter/x11/clutter-backend-x11.c @@ -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; +} diff --git a/clutter/x11/clutter-backend-x11.h b/clutter/x11/clutter-backend-x11.h index 3b51e12fa..4f75359c8 100644 --- a/clutter/x11/clutter-backend-x11.h +++ b/clutter/x11/clutter-backend-x11.h @@ -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); diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index 360417dbd..dc6277e9e 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -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 {