static ClutterFeatureFlags
clutter_backend_egl_get_features (ClutterBackend *backend)
{
  ClutterBackendEGL  *backend_egl = CLUTTER_BACKEND_EGL (backend);
  ClutterFeatureFlags flags;

  flags = clutter_backend_x11_get_features (backend);
  flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;

  CLUTTER_NOTE (BACKEND, "Checking features\n"
                "GL_VENDOR: %s\n"
                "GL_RENDERER: %s\n"
                "GL_VERSION: %s\n"
                "EGL_VENDOR: %s\n"
                "EGL_VERSION: %s\n"
                "EGL_EXTENSIONS: %s\n",
                glGetString (GL_VENDOR),
                glGetString (GL_RENDERER),
                glGetString (GL_VERSION),
                eglQueryString (backend_egl->edpy, EGL_VENDOR),
                eglQueryString (backend_egl->edpy, EGL_VERSION),
                eglQueryString (backend_egl->edpy, EGL_EXTENSIONS));

  return flags;
}
static ClutterFeatureFlags
clutter_backend_glx_get_features (ClutterBackend *backend)
{
  ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
  const gchar *glx_extensions = NULL;
  const gchar *gl_extensions = NULL;
  ClutterFeatureFlags flags;
  gboolean use_dri = FALSE;

  flags = clutter_backend_x11_get_features (backend);
  flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;

  /* this will make sure that the GL context exists */
  g_assert (backend_glx->gl_context != None);
  g_assert (glXGetCurrentDrawable () != None);

  CLUTTER_NOTE (BACKEND,
                "Checking features\n"
                "  GL_VENDOR: %s\n"
                "  GL_RENDERER: %s\n"
                "  GL_VERSION: %s\n"
                "  GL_EXTENSIONS: %s",
                glGetString (GL_VENDOR),
                glGetString (GL_RENDERER),
                glGetString (GL_VERSION),
                glGetString (GL_EXTENSIONS));

  glx_extensions =
    glXQueryExtensionsString (clutter_x11_get_default_display (),
                              clutter_x11_get_default_screen ());

  CLUTTER_NOTE (BACKEND, "  GLX Extensions: %s", glx_extensions);

  gl_extensions = (const gchar *)glGetString (GL_EXTENSIONS);

  /* When using glBlitFramebuffer or glXCopySubBufferMESA for sub stage
   * redraws, we cannot rely on glXSwapIntervalSGI to throttle the blits
   * so we need to resort to manually synchronizing with the vblank so we
   * always check for the video_sync extension...
   */
  if (_cogl_check_extension ("GLX_SGI_video_sync", glx_extensions) &&
      /* Note: the GLX_SGI_video_sync spec explicitly states this extension
       * only works for direct contexts. */
      glXIsDirect (clutter_x11_get_default_display (),
                   backend_glx->gl_context))
    {
      backend_glx->get_video_sync =
        (GetVideoSyncProc) cogl_get_proc_address ("glXGetVideoSyncSGI");

      backend_glx->wait_video_sync =
        (WaitVideoSyncProc) cogl_get_proc_address ("glXWaitVideoSyncSGI");
    }

  use_dri = check_vblank_env ("dri");

  /* First check for explicit disabling or it set elsewhere (eg NVIDIA) */
  if (check_vblank_env ("none"))
    {
      CLUTTER_NOTE (BACKEND, "vblank sync: disabled at user request");
      goto vblank_setup_done;
    }

  if (g_getenv ("__GL_SYNC_TO_VBLANK") != NULL)
    {
      backend_glx->vblank_type = CLUTTER_VBLANK_GLX_SWAP;
      flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;

      CLUTTER_NOTE (BACKEND, "Using __GL_SYNC_TO_VBLANK hint");
      goto vblank_setup_done;
    }

  /* We try two GL vblank syncing mechanisms.
   * glXSwapIntervalSGI is tried first, then glXGetVideoSyncSGI.
   *
   * glXSwapIntervalSGI is known to work with Mesa and in particular
   * the Intel drivers. glXGetVideoSyncSGI has serious problems with
   * Intel drivers causing terrible frame rate so it only tried as a
   * fallback.
   *
   * How well glXGetVideoSyncSGI works with other driver (ATI etc) needs
   * to be investigated. glXGetVideoSyncSGI on ATI at least seems to have
   * no effect.
   */
  if (!use_dri &&
      _cogl_check_extension ("GLX_SGI_swap_control", glx_extensions))
    {
      backend_glx->swap_interval =
        (SwapIntervalProc) cogl_get_proc_address ("glXSwapIntervalSGI");

      CLUTTER_NOTE (BACKEND, "attempting glXSwapIntervalSGI vblank setup");

      if (backend_glx->swap_interval != NULL &&
          backend_glx->swap_interval (1) == 0)
        {
          backend_glx->vblank_type = CLUTTER_VBLANK_GLX_SWAP;
          flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;

          CLUTTER_NOTE (BACKEND, "glXSwapIntervalSGI setup success");

#ifdef GLX_INTEL_swap_event
          /* GLX_INTEL_swap_event allows us to avoid blocking the CPU
           * while we wait for glXSwapBuffers to complete, and instead
           * we get an X event notifying us of completion...
           */
          if (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_SWAP_EVENTS) &&
              _cogl_check_extension ("GLX_INTEL_swap_event", glx_extensions))
            {
              flags |= CLUTTER_FEATURE_SWAP_EVENTS;
            }
#endif /* GLX_INTEL_swap_event */

          goto vblank_setup_done;
        }

      CLUTTER_NOTE (BACKEND, "glXSwapIntervalSGI vblank setup failed");
    }

  if (!use_dri &&
      !(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK) &&
      _cogl_check_extension ("GLX_SGI_video_sync", glx_extensions))
    {
      CLUTTER_NOTE (BACKEND, "attempting glXGetVideoSyncSGI vblank setup");

      if ((backend_glx->get_video_sync != NULL) &&
          (backend_glx->wait_video_sync != NULL))
        {
          CLUTTER_NOTE (BACKEND, "glXGetVideoSyncSGI vblank setup success");

          backend_glx->vblank_type = CLUTTER_VBLANK_GLX;
          flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;

          goto vblank_setup_done;
        }

      CLUTTER_NOTE (BACKEND, "glXGetVideoSyncSGI vblank setup failed");
    }

#ifdef __linux__
  /*
   * DRI is really an extreme fallback -rumoured to work with Via chipsets
   */
  if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
    {
      CLUTTER_NOTE (BACKEND, "attempting DRI vblank setup");

      backend_glx->dri_fd = open("/dev/dri/card0", O_RDWR);
      if (backend_glx->dri_fd >= 0)
        {
          CLUTTER_NOTE (BACKEND, "DRI vblank setup success");

          backend_glx->vblank_type = CLUTTER_VBLANK_DRI;
          flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;

          goto vblank_setup_done;
        }

      CLUTTER_NOTE (BACKEND, "DRI vblank setup failed");
    }
#endif /* __linux__ */

  CLUTTER_NOTE (BACKEND, "no use-able vblank mechanism found");

vblank_setup_done:

  if (_cogl_check_extension ("GLX_MESA_copy_sub_buffer", glx_extensions))
    {
      backend_glx->copy_sub_buffer =
        (CopySubBufferProc) cogl_get_proc_address ("glXCopySubBufferMESA");
      backend_glx->can_blit_sub_buffer = TRUE;
      backend_glx->blit_sub_buffer_is_synchronized = TRUE;
    }
  else if (_cogl_check_extension ("GL_EXT_framebuffer_blit", gl_extensions))
    {
      CLUTTER_NOTE (BACKEND,
                    "Using glBlitFramebuffer fallback for sub_buffer copies");
      backend_glx->blit_framebuffer =
        (BlitFramebufferProc) cogl_get_proc_address ("glBlitFramebuffer");
      backend_glx->can_blit_sub_buffer = TRUE;
      backend_glx->blit_sub_buffer_is_synchronized = FALSE;
    }

  CLUTTER_NOTE (BACKEND, "backend features checked");

  return flags;
}
static ClutterFeatureFlags
clutter_backend_glx_get_features (ClutterBackend *backend)
{
  ClutterBackendGLX  *backend_glx = CLUTTER_BACKEND_GLX (backend);
  const gchar        *glx_extensions = NULL;
  ClutterFeatureFlags flags;
  
  flags = clutter_backend_x11_get_features (backend);
  flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;

  /* this will make sure that the GL context exists and
   * it's bound to a drawable
   */
  g_assert (backend_glx->gl_context != None);
  g_assert (glXGetCurrentDrawable () != None);

  CLUTTER_NOTE (BACKEND, "Checking features\n"
                "GL_VENDOR: %s\n"
                "GL_RENDERER: %s\n"
                "GL_VERSION: %s\n"
                "GL_EXTENSIONS: %s\n",
                glGetString (GL_VENDOR),
                glGetString (GL_RENDERER),
                glGetString (GL_VERSION),
                glGetString (GL_EXTENSIONS));

  glx_extensions = 
    glXQueryExtensionsString (clutter_x11_get_default_display (),
			      clutter_x11_get_default_screen ());

  CLUTTER_NOTE (BACKEND, "GLX Extensions: %s", glx_extensions);

  /* First check for explicit disabling or it set elsewhere (eg NVIDIA) */
  if (getenv("__GL_SYNC_TO_VBLANK") || check_vblank_env ("none"))
    {
      CLUTTER_NOTE (BACKEND, "vblank sync: disabled at user request");
    }
  else
    {
      /* We try two GL vblank syncing mechanisms.  
       * glXSwapIntervalSGI is tried first, then glXGetVideoSyncSGI.
       *
       * glXSwapIntervalSGI is known to work with Mesa and in particular
       * the Intel drivers. glXGetVideoSyncSGI has serious problems with
       * Intel drivers causing terrible frame rate so it only tried as a
       * fallback.
       *
       * How well glXGetVideoSyncSGI works with other driver (ATI etc) needs
       * to be investigated. glXGetVideoSyncSGI on ATI at least seems to have
       * no effect.
      */
      if (!check_vblank_env ("dri") && 
          cogl_check_extension ("GLX_SGI_swap_control", glx_extensions))
        {
          backend_glx->swap_interval = 
            (SwapIntervalProc) cogl_get_proc_address ("glXSwapIntervalSGI");

          CLUTTER_NOTE (BACKEND, "attempting glXSwapIntervalSGI vblank setup");

          if (backend_glx->swap_interval != NULL)
            {
              if (backend_glx->swap_interval (1) == 0)
                {
                  backend_glx->vblank_type = CLUTTER_VBLANK_GLX_SWAP;
                  flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
                  CLUTTER_NOTE (BACKEND, "glXSwapIntervalSGI setup success");
                }
            }

          if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
            CLUTTER_NOTE (BACKEND, "glXSwapIntervalSGI vblank setup failed");
        }

      if (!check_vblank_env ("dri") && 
          !(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK) &&
          cogl_check_extension ("GLX_SGI_video_sync", glx_extensions))
        {
          CLUTTER_NOTE (BACKEND, "attempting glXGetVideoSyncSGI vblank setup");

          backend_glx->get_video_sync = 
            (GetVideoSyncProc) cogl_get_proc_address ("glXGetVideoSyncSGI");

          backend_glx->wait_video_sync = 
            (WaitVideoSyncProc) cogl_get_proc_address ("glXWaitVideoSyncSGI");

          if ((backend_glx->get_video_sync != NULL) &&
              (backend_glx->wait_video_sync != NULL))
            {
              CLUTTER_NOTE (BACKEND, 
                            "glXGetVideoSyncSGI vblank setup success");

              backend_glx->vblank_type = CLUTTER_VBLANK_GLX;
              flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
            }

          if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
            CLUTTER_NOTE (BACKEND, "glXGetVideoSyncSGI vblank setup failed");
        }
#ifdef __linux__
      /* 
       * DRI is really an extreme fallback -rumoured to work with Via chipsets
      */
      if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
        {
          CLUTTER_NOTE (BACKEND, "attempting DRI vblank setup");
          backend_glx->dri_fd = open("/dev/dri/card0", O_RDWR);
          if (backend_glx->dri_fd >= 0)
            {
              CLUTTER_NOTE (BACKEND, "DRI vblank setup success");
              backend_glx->vblank_type = CLUTTER_VBLANK_DRI;
              flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
            }

          if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
            CLUTTER_NOTE (BACKEND, "DRI vblank setup failed");
        }
#endif
      if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
        {
          CLUTTER_NOTE (BACKEND,
                        "no use-able vblank mechanism found");
        }
    }

  CLUTTER_NOTE (MISC, "backend features checked");

  return flags;
}