Exemple #1
0
void
test_fence (void)
{
  GSource *cogl_source;
  int fb_width = cogl_framebuffer_get_width (test_fb);
  int fb_height = cogl_framebuffer_get_height (test_fb);
  CoglFenceClosure *closure;

  cogl_source = cogl_glib_source_new (test_ctx, G_PRIORITY_DEFAULT);
  g_source_attach (cogl_source, NULL);
  loop = g_main_loop_new (NULL, TRUE);

  cogl_framebuffer_orthographic (test_fb, 0, 0, fb_width, fb_height, -1, 100);
  cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR,
                            0.0f, 1.0f, 0.0f, 0.0f);

  closure = cogl_framebuffer_add_fence_callback (test_fb,
                                                 callback,
                                                 MAGIC_CHUNK_O_DATA);
  g_assert (closure != NULL);

  g_timeout_add_seconds (5, timeout, NULL);

  g_main_loop_run (loop);

  if (cogl_test_verbose ())
    g_print ("OK\n");
}
Exemple #2
0
int
main (int argc, char **argv)
{
    Data data;
    CoglOnscreen *onscreen;
    CoglError *error = NULL;
    CoglVertexP2C4 triangle_vertices[] = {
        {0, 0.7, 0xff, 0x00, 0x00, 0x80},
        {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
        {0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
    };
    GSource *cogl_source;
    GMainLoop *loop;

    data.ctx = cogl_context_new (NULL, &error);
    if (!data.ctx) {
        fprintf (stderr, "Failed to create context: %s\n", error->message);
        return 1;
    }

    onscreen = cogl_onscreen_new (data.ctx, 640, 480);
    cogl_onscreen_show (onscreen);
    data.fb = COGL_FRAMEBUFFER (onscreen);

    cogl_onscreen_set_resizable (onscreen, TRUE);

    data.triangle = cogl_primitive_new_p2c4 (data.ctx,
                                             COGL_VERTICES_MODE_TRIANGLES,
                                             3, triangle_vertices);
    data.pipeline = cogl_pipeline_new (data.ctx);

    cogl_source = cogl_glib_source_new (data.ctx, G_PRIORITY_DEFAULT);

    g_source_attach (cogl_source, NULL);

    if (cogl_has_feature (data.ctx, COGL_FEATURE_ID_SWAP_BUFFERS_EVENT))
      cogl_onscreen_add_swap_buffers_callback (COGL_ONSCREEN (data.fb),
                                               swap_complete_cb, &data);

    g_idle_add (paint_cb, &data);

    loop = g_main_loop_new (NULL, TRUE);
    g_main_loop_run (loop);

    return 0;
}
Exemple #3
0
int
main (int argc, char **argv)
{
    Data data;
    CoglOnscreen *onscreen;
    GError *error = NULL;
    GSource *cogl_source;
    GMainLoop *loop;
    CoglRenderer *renderer;
    CoglDisplay *display;

    renderer = cogl_renderer_new ();
    cogl_renderer_add_constraint (renderer,
                                  COGL_RENDERER_CONSTRAINT_SUPPORTS_COGL_GLES2);
    display = cogl_display_new (renderer, NULL);
    data.ctx = cogl_context_new (display, NULL);

    onscreen = cogl_onscreen_new (data.ctx, 300, 300);
    cogl_onscreen_show (onscreen);
    data.fb = COGL_FRAMEBUFFER (onscreen);

    data.gles2_ctx = cogl_gles2_context_new (data.ctx, &error);
    if (!data.gles2_ctx)
        g_error ("Failed to create GLES2 context: %s\n", error->message);

    /* Draw scene with GLES2 */
    if (!cogl_push_gles2_context (data.ctx,
                                  data.gles2_ctx,
                                  data.fb,
                                  data.fb,
                                  &error))
    {
        g_error ("Failed to push gles2 context: %s\n", error->message);
    }

    gears_reshape (cogl_framebuffer_get_width (data.fb),
                   cogl_framebuffer_get_height (data.fb));

    /* Initialize the gears */
    gears_init();

    cogl_pop_gles2_context (data.ctx);

    cogl_source = cogl_glib_source_new (data.ctx, G_PRIORITY_DEFAULT);

    g_source_attach (cogl_source, NULL);

    if (cogl_has_feature (data.ctx, COGL_FEATURE_ID_SWAP_BUFFERS_EVENT))
        cogl_onscreen_add_swap_buffers_callback (COGL_ONSCREEN (data.fb),
                                                 swap_complete_cb, &data);

    g_idle_add (paint_cb, &data);

    data.timer = g_timer_new ();
    data.frames = 0;
    data.last_elapsed = 0;

    loop = g_main_loop_new (NULL, TRUE);
    g_main_loop_run (loop);

    return 0;
}
Exemple #4
0
int
main (int argc, char **argv)
{
  CoglandCompositor compositor;
  GMainLoop *loop;
  CoglError *error = NULL;
  GError *gerror = NULL;
  CoglVertexP2C4 triangle_vertices[] = {
      {0, 0.7, 0xff, 0x00, 0x00, 0xff},
      {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
      {0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
  };
  GSource *cogl_source;

  if (!process_arguments (&argc, &argv, &gerror))
    {
      fprintf (stderr, "%s\n", gerror->message);
      return EXIT_FAILURE;
    }

  memset (&compositor, 0, sizeof (compositor));

  compositor.wayland_display = wl_display_create ();
  if (compositor.wayland_display == NULL)
    g_error ("failed to create wayland display");

  wl_list_init (&compositor.frame_callbacks);

  if (!wl_display_add_global (compositor.wayland_display,
                              &wl_compositor_interface,
                              &compositor,
                              compositor_bind))
    g_error ("Failed to register wayland compositor object");

  wl_display_init_shm (compositor.wayland_display);

  loop = g_main_loop_new (NULL, FALSE);
  compositor.wayland_loop =
    wl_display_get_event_loop (compositor.wayland_display);
  compositor.wayland_event_source =
    wayland_event_source_new (compositor.wayland_display);
  g_source_attach (compositor.wayland_event_source, NULL);

  /* We want Cogl to use an EGL renderer because otherwise it won't
   * set up the wl_drm object and only SHM buffers will work. */
  compositor.cogl_context =
    create_cogl_context (&compositor,
                         TRUE /* use EGL constraint */,
                         &error);
  if (compositor.cogl_context == NULL)
    {
      /* If we couldn't get an EGL context then try any type of
       * context */
      cogl_error_free (error);
      error = NULL;

      compositor.cogl_context =
        create_cogl_context (&compositor,
                             FALSE, /* don't set EGL constraint */
                             &error);

      if (compositor.cogl_context)
        g_warning ("Failed to create context with EGL constraint, "
                   "falling back");
      else
        g_error ("Failed to create a Cogl context: %s\n", error->message);
    }

  compositor.virtual_width = 800;
  compositor.virtual_height = 600;

  if (option_multiple_outputs)
    {
      int hw = compositor.virtual_width / 2;
      int hh = compositor.virtual_height / 2;
      /* Emulate compositing with multiple monitors... */
      cogland_compositor_create_output (&compositor, 0, 0, hw, hh);
      cogland_compositor_create_output (&compositor, hw, 0, hw, hh);
      cogland_compositor_create_output (&compositor, 0, hh, hw, hh);
      cogland_compositor_create_output (&compositor, hw, hh, hw, hh);
    }
  else
    {
      cogland_compositor_create_output (&compositor,
                                        0, 0,
                                        compositor.virtual_width,
                                        compositor.virtual_height);
    }

  if (wl_display_add_global (compositor.wayland_display, &wl_shell_interface,
                             &compositor, bind_shell) == NULL)
    g_error ("Failed to register a global shell object");

  if (wl_display_add_socket (compositor.wayland_display, "wayland-0"))
    g_error ("Failed to create socket");

  compositor.triangle = cogl_primitive_new_p2c4 (compositor.cogl_context,
                                                 COGL_VERTICES_MODE_TRIANGLES,
                                                 3, triangle_vertices);
  compositor.triangle_pipeline = cogl_pipeline_new (compositor.cogl_context);

  cogl_source = cogl_glib_source_new (compositor.cogl_context,
                                      G_PRIORITY_DEFAULT);

  g_source_attach (cogl_source, NULL);

  g_main_loop_run (loop);

  return 0;
}
static gboolean
clutter_backend_real_create_context (ClutterBackend  *backend,
                                     GError         **error)
{
  ClutterBackendClass *klass;
  CoglSwapChain *swap_chain;
  GError *internal_error;

  if (backend->cogl_context != NULL)
    return TRUE;

  klass = CLUTTER_BACKEND_GET_CLASS (backend);

  swap_chain = NULL;
  internal_error = NULL;

  CLUTTER_NOTE (BACKEND, "Creating Cogl renderer");
  if (klass->get_renderer != NULL)
    backend->cogl_renderer = klass->get_renderer (backend, &internal_error);
  else
    backend->cogl_renderer = cogl_renderer_new ();

  if (backend->cogl_renderer == NULL)
    goto error;

#ifdef HAVE_CLUTTER_WAYLAND_COMPOSITOR
  /* If the application is trying to act as a Wayland compositor then
     it needs to have an EGL-based renderer backend */
  if (_wayland_compositor_display)
    cogl_renderer_add_constraint (backend->cogl_renderer,
                                  COGL_RENDERER_CONSTRAINT_USES_EGL);
#endif

  CLUTTER_NOTE (BACKEND, "Connecting the renderer");
  if (!cogl_renderer_connect (backend->cogl_renderer, &internal_error))
    goto error;

  CLUTTER_NOTE (BACKEND, "Creating Cogl swap chain");
  swap_chain = cogl_swap_chain_new ();

  CLUTTER_NOTE (BACKEND, "Creating Cogl display");
  if (klass->get_display != NULL)
    {
      backend->cogl_display = klass->get_display (backend,
                                                  backend->cogl_renderer,
                                                  swap_chain,
                                                  &internal_error);
    }
  else
    {
      CoglOnscreenTemplate *tmpl;
      gboolean res;

      tmpl = cogl_onscreen_template_new (swap_chain);

      /* XXX: I have some doubts that this is a good design.
       *
       * Conceptually should we be able to check an onscreen_template
       * without more details about the CoglDisplay configuration?
       */
      res = cogl_renderer_check_onscreen_template (backend->cogl_renderer,
                                                   tmpl,
                                                   &internal_error);

      if (!res)
        goto error;

      backend->cogl_display = cogl_display_new (backend->cogl_renderer, tmpl);

      /* the display owns the template */
      cogl_object_unref (tmpl);
    }

  if (backend->cogl_display == NULL)
    goto error;

#ifdef HAVE_CLUTTER_WAYLAND_COMPOSITOR
  cogl_wayland_display_set_compositor_display (backend->cogl_display,
                                               _wayland_compositor_display);
#endif

  CLUTTER_NOTE (BACKEND, "Setting up the display");
  if (!cogl_display_setup (backend->cogl_display, &internal_error))
    goto error;

  CLUTTER_NOTE (BACKEND, "Creating the Cogl context");
  backend->cogl_context = cogl_context_new (backend->cogl_display, &internal_error);
  if (backend->cogl_context == NULL)
    goto error;

  backend->cogl_source = cogl_glib_source_new (backend->cogl_context,
                                               G_PRIORITY_DEFAULT);
  g_source_attach (backend->cogl_source, NULL);

  /* the display owns the renderer and the swap chain */
  cogl_object_unref (backend->cogl_renderer);
  cogl_object_unref (swap_chain);

  return TRUE;

error:
  if (backend->cogl_display != NULL)
    {
      cogl_object_unref (backend->cogl_display);
      backend->cogl_display = NULL;
    }

  if (backend->cogl_renderer != NULL)
    {
      cogl_object_unref (backend->cogl_renderer);
      backend->cogl_renderer = NULL;
    }

  if (swap_chain != NULL)
    cogl_object_unref (swap_chain);

  if (internal_error != NULL)
    g_propagate_error (error, internal_error);
  else
    g_set_error_literal (error, CLUTTER_INIT_ERROR,
                         CLUTTER_INIT_ERROR_BACKEND,
                         _("Unable to initialize the Clutter backend"));

  return FALSE;
}
Exemple #6
0
int
main (int argc, char *argv[])
{
  CoglTexture *tex;
  CoglOnscreen *onscreen;
  GSource *cogl_source;
  GMainLoop *loop;
  Data data;
  int i;

  data.context = cogl_context_new (NULL, NULL);

  create_primitive (&data);

  data.pipeline = cogl_pipeline_new (data.context);
  data.last_spark_time = g_timer_new ();
  data.next_spark_num = 0;
  cogl_pipeline_set_point_size (data.pipeline, TEXTURE_SIZE);

  tex = generate_round_texture (data.context);
  cogl_pipeline_set_layer_texture (data.pipeline, 0, tex);
  cogl_object_unref (tex);

  cogl_pipeline_set_layer_point_sprite_coords_enabled (data.pipeline,
                                                       0, /* layer */
                                                       TRUE,
                                                       NULL /* error */);

  for (i = 0; i < N_FIREWORKS; i++)
    {
      data.fireworks[i].x = -FLT_MAX;
      data.fireworks[i].y = FLT_MAX;
      data.fireworks[i].size = 0.0f;
      data.fireworks[i].timer = g_timer_new ();
    }

  for (i = 0; i < N_SPARKS; i++)
    {
      data.sparks[i].x = 2.0f;
      data.sparks[i].y = 2.0f;
    }

  onscreen = cogl_onscreen_new (data.context, 800, 600);
  cogl_onscreen_show (onscreen);
  data.fb = onscreen;

  cogl_source = cogl_glib_source_new (data.context, G_PRIORITY_DEFAULT);

  g_source_attach (cogl_source, NULL);

  cogl_onscreen_add_frame_callback (onscreen,
                                    frame_event_cb,
                                    &data,
                                    NULL /* destroy notify */);

  loop = g_main_loop_new (NULL, TRUE);

  paint (&data);

  g_main_loop_run (loop);

  g_main_loop_unref (loop);

  g_source_destroy (cogl_source);

  cogl_object_unref (data.pipeline);
  cogl_object_unref (data.attribute_buffer);
  cogl_object_unref (data.primitive);
  cogl_object_unref (onscreen);
  cogl_object_unref (data.context);

  g_timer_destroy (data.last_spark_time);

  for (i = 0; i < N_FIREWORKS; i++)
    g_timer_destroy (data.fireworks[i].timer);

  return 0;
}
Exemple #7
0
int
main (int argc, char **argv)
{
    Data data;
    CoglOnscreen *onscreen;
    CoglError *error = NULL;
    CoglVertexP2C4 triangle_vertices[] = {
        {0, 0.7, 0xff, 0x00, 0x00, 0xff},
        {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
        {0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
    };
    GSource *cogl_source;
    GMainLoop *loop;
    CoglRenderer *renderer;
    CoglDisplay *display;

    renderer = cogl_renderer_new ();
    cogl_renderer_add_constraint (renderer,
                                  COGL_RENDERER_CONSTRAINT_SUPPORTS_COGL_GLES2);
    display = cogl_display_new (renderer, NULL);
    data.ctx = cogl_context_new (display, NULL);

    onscreen = cogl_onscreen_new (data.ctx, 640, 480);
    cogl_onscreen_show (onscreen);
    data.fb = COGL_FRAMEBUFFER (onscreen);

    /* Prepare onscreen primitive */
    data.triangle = cogl_primitive_new_p2c4 (data.ctx,
                                             COGL_VERTICES_MODE_TRIANGLES,
                                             3, triangle_vertices);
    data.pipeline = cogl_pipeline_new (data.ctx);

    data.offscreen_texture = COGL_TEXTURE (
      cogl_texture_2d_new_with_size (data.ctx,
                                     OFFSCREEN_WIDTH,
                                     OFFSCREEN_HEIGHT,
                                     COGL_PIXEL_FORMAT_ANY));
    data.offscreen = cogl_offscreen_new_to_texture (data.offscreen_texture);

    data.gles2_ctx = cogl_gles2_context_new (data.ctx, &error);
    if (!data.gles2_ctx) {
        g_error ("Failed to create GLES2 context: %s\n", error->message);
    }

    data.gles2_vtable = cogl_gles2_context_get_vtable (data.gles2_ctx);

    /* Draw scene with GLES2 */
    if (!cogl_push_gles2_context (data.ctx,
                                  data.gles2_ctx,
                                  data.fb,
                                  data.fb,
                                  &error))
    {
        g_error ("Failed to push gles2 context: %s\n", error->message);
    }

    cogl_pop_gles2_context (data.ctx);

    cogl_source = cogl_glib_source_new (data.ctx, G_PRIORITY_DEFAULT);

    g_source_attach (cogl_source, NULL);

    cogl_onscreen_add_frame_callback (COGL_ONSCREEN (data.fb),
                                      frame_event_cb,
                                      &data,
                                      NULL); /* destroy notify */

    g_idle_add (paint_cb, &data);

    loop = g_main_loop_new (NULL, TRUE);
    g_main_loop_run (loop);

    return 0;
}
Exemple #8
0
int
main (int argc,
      char **argv)
{
  Data data;
  CoglContext *ctx;
  CoglOnscreen *onscreen;
  GstElement *pipeline;
  GSource *cogl_source;
  GstBus *bus;
  char *uri;
  GError *error = NULL;

  memset (&data, 0, sizeof (Data));

  /* Set the necessary cogl elements */

  ctx = cogl_context_new (NULL, NULL);

  onscreen = cogl_onscreen_new (ctx, 640, 480);
  cogl_onscreen_set_resizable (onscreen, TRUE);
  cogl_onscreen_add_resize_callback (onscreen, _resize_callback, &data, NULL);
  cogl_onscreen_show (onscreen);

  data.fb = onscreen;
  cogl_framebuffer_orthographic (data.fb, 0, 0, 640, 480, -1, 100);

  data.border_pipeline = cogl_pipeline_new (ctx);
  cogl_pipeline_set_color4f (data.border_pipeline, 0, 0, 0, 1);
  /* disable blending */
  cogl_pipeline_set_blend (data.border_pipeline,
                           "RGBA = ADD (SRC_COLOR, 0)", NULL);

  /* Intialize GStreamer */

  gst_init (&argc, &argv);

  /*
     Create the cogl-gst video sink by calling the cogl_gst_video_sink_new
     function and passing it a CoglContext (this is used to create the
     CoglPipeline and the texures for each frame). Alternatively you can use
     gst_element_factory_make ("coglsink", "some_name") and then set the
     context with cogl_gst_video_sink_set_context.
  */

  if (argc < 2)
    uri = "http://docs.gstreamer.com/media/sintel_trailer-480p.webm";
  else
    uri = argv[1];

  if (!make_pipeline_for_uri (ctx, uri, &pipeline, &data.sink, &error))
    {
      g_print ("Error creating pipeline: %s\n", error->message);
      g_clear_error (&error);
      return EXIT_FAILURE;
    }

  gst_element_set_state (pipeline, GST_STATE_PLAYING);
  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  gst_bus_add_watch (bus, _bus_watch, &data);

  data.main_loop = g_main_loop_new (NULL, FALSE);

  cogl_source = cogl_glib_source_new (ctx, G_PRIORITY_DEFAULT);
  g_source_attach (cogl_source, NULL);

  /*
    The cogl-pipeline-ready signal tells you when the cogl pipeline is
    initialized i.e. when cogl-gst has figured out the video format and
    is prepared to retrieve and attach the first frame of the video.
  */

  g_signal_connect (data.sink, "pipeline-ready",
                    G_CALLBACK (_set_up_pipeline), &data);

  data.draw_ready = TRUE;
  data.frame_ready = FALSE;

  g_main_loop_run (data.main_loop);

  g_source_destroy (cogl_source);
  g_source_unref (cogl_source);

  g_main_loop_unref (data.main_loop);

  return 0;
}
Exemple #9
0
int
main (int argc, char **argv)
{
  CoglandCompositor compositor;
  GMainLoop *loop;
  CoglError *error = NULL;
  CoglVertexP2C4 triangle_vertices[] = {
      {0, 0.7, 0xff, 0x00, 0x00, 0x80},
      {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
      {0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
  };
  GSource *cogl_source;

  memset (&compositor, 0, sizeof (compositor));

  compositor.wayland_display = wl_display_create ();
  if (compositor.wayland_display == NULL)
    g_error ("failed to create wayland display");

  g_queue_init (&compositor.frame_callbacks);

  if (!wl_display_add_global (compositor.wayland_display,
                              &wl_compositor_interface,
                              &compositor,
                              compositor_bind))
    g_error ("Failed to register wayland compositor object");

  compositor.wayland_shm = wl_shm_init (compositor.wayland_display,
                                        &shm_callbacks);
  if (!compositor.wayland_shm)
    g_error ("Failed to allocate setup wayland shm callbacks");

  loop = g_main_loop_new (NULL, FALSE);
  compositor.wayland_loop =
    wl_display_get_event_loop (compositor.wayland_display);
  compositor.wayland_event_source =
    wayland_event_source_new (compositor.wayland_loop);
  g_source_attach (compositor.wayland_event_source, NULL);

  compositor.cogl_display = cogl_display_new (NULL, NULL);
  cogl_wayland_display_set_compositor_display (compositor.cogl_display,
                                               compositor.wayland_display);

  compositor.cogl_context = cogl_context_new (compositor.cogl_display, &error);
  if (!compositor.cogl_context)
    g_error ("Failed to create a Cogl context: %s\n", error->message);

  compositor.virtual_width = 640;
  compositor.virtual_height = 480;

  /* Emulate compositing with multiple monitors... */
  cogland_compositor_create_output (&compositor, 0, 0, 320, 240);
  cogland_compositor_create_output (&compositor, 320, 0, 320, 240);
  cogland_compositor_create_output (&compositor, 0, 240, 320, 240);
  cogland_compositor_create_output (&compositor, 320, 240, 320, 240);

  if (wl_display_add_global (compositor.wayland_display, &wl_shell_interface,
                             &compositor, bind_shell) == NULL)
    g_error ("Failed to register a global shell object");

  if (wl_display_add_socket (compositor.wayland_display, "wayland-0"))
    g_error ("Failed to create socket");

  compositor.triangle = cogl_primitive_new_p2c4 (compositor.cogl_context,
                                                 COGL_VERTICES_MODE_TRIANGLES,
                                                 3, triangle_vertices);
  compositor.triangle_pipeline = cogl_pipeline_new (compositor.cogl_context);

  g_timeout_add (16, paint_cb, &compositor);

  cogl_source = cogl_glib_source_new (compositor.cogl_context,
                                      G_PRIORITY_DEFAULT);

  g_source_attach (cogl_source, NULL);

  g_main_loop_run (loop);

  return 0;
}
Exemple #10
0
static gboolean
clutter_backend_real_create_context (ClutterBackend  *backend,
                                     GError         **error)
{
  GError *internal_error = NULL;
  const char *drivers_list;
  char **known_drivers;
  gboolean allow_any;
  int i;

  if (allowed_drivers == NULL)
    allowed_drivers = CLUTTER_DRIVERS;

  allow_any = strstr (allowed_drivers, "*") != NULL;

  drivers_list = g_getenv ("CLUTTER_DRIVER");
  if (drivers_list == NULL)
    drivers_list = allowed_drivers;

  known_drivers = g_strsplit (drivers_list, ",", 0);

  for (i = 0; backend->cogl_context == NULL && known_drivers[i] != NULL; i++)
    {
      const char *driver_name = known_drivers[i];
      gboolean is_any = g_str_equal (driver_name, "*");
      int j;

      for (j = 0; j < G_N_ELEMENTS (all_known_drivers); j++)
        {
          if (!allow_any && !is_any && !strstr (driver_name, all_known_drivers[j].driver_name))
            continue;

          if ((allow_any && is_any) ||
              (is_any && strstr (allowed_drivers, all_known_drivers[j].driver_name)) ||
              g_str_equal (all_known_drivers[j].driver_name, driver_name))
            {
              CLUTTER_NOTE (BACKEND, "Checking for the %s driver", all_known_drivers[j].driver_desc);

              if (clutter_backend_do_real_create_context (backend, all_known_drivers[j].driver_id, &internal_error))
                break;

              if (internal_error)
                {
                  CLUTTER_NOTE (BACKEND, "Unable to use the %s driver: %s",
                                all_known_drivers[j].driver_desc,
                                internal_error->message);
                  g_clear_error (&internal_error);
                }
            }
        }
    }

  g_strfreev (known_drivers);

  if (backend->cogl_context == NULL)
    {
      if (internal_error != NULL)
        g_propagate_error (error, internal_error);
      else
        g_set_error_literal (error, CLUTTER_INIT_ERROR,
                             CLUTTER_INIT_ERROR_BACKEND,
                            _("Unable to initialize the Clutter backend: no available drivers found."));

      return FALSE;
    }

  backend->cogl_source = cogl_glib_source_new (backend->cogl_context, G_PRIORITY_DEFAULT);
  g_source_attach (backend->cogl_source, NULL);

  return TRUE;
}