cogland: Don't redraw constantly

Instead of always drawing at 60FPS without ever going idle, Cogland
now only redraws when a client commits a frame or a surface is
destroyed. This is acheived using an idle handler on the glib main
loop.

Reviewed-by: Robert Bragg <robert@linux.intel.com>

(cherry picked from commit 906e1b5eb535a86a849bed7a363f800ad71ab9bc)

Conflicts:
	examples/cogland.c
This commit is contained in:
Neil Roberts 2013-03-22 13:57:58 +00:00
parent 666d0e100c
commit 53a684bf9e

View File

@ -108,6 +108,8 @@ struct _CoglandCompositor
GSource *wayland_event_source; GSource *wayland_event_source;
GList *surfaces; GList *surfaces;
unsigned int redraw_idle;
}; };
static CoglBool option_multiple_outputs = FALSE; static CoglBool option_multiple_outputs = FALSE;
@ -264,6 +266,73 @@ wayland_event_source_new (struct wl_display *display)
return &source->source; return &source->source;
} }
typedef struct _CoglandFrameCallback
{
struct wl_list link;
/* Pointer back to the compositor */
CoglandCompositor *compositor;
struct wl_resource resource;
} CoglandFrameCallback;
static CoglBool
paint_cb (void *user_data)
{
CoglandCompositor *compositor = user_data;
GList *l;
for (l = compositor->outputs; l; l = l->next)
{
CoglandOutput *output = l->data;
CoglFramebuffer *fb = COGL_FRAMEBUFFER (output->onscreen);
GList *l2;
cogl_push_framebuffer (fb);
cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
cogl_framebuffer_draw_primitive (fb, compositor->triangle_pipeline,
compositor->triangle);
for (l2 = compositor->surfaces; l2; l2 = l2->next)
{
CoglandSurface *surface = l2->data;
if (surface->texture)
{
CoglTexture2D *texture = surface->texture;
cogl_set_source_texture (COGL_TEXTURE (texture));
cogl_rectangle (-1, 1, 1, -1);
}
}
cogl_onscreen_swap_buffers (COGL_ONSCREEN (fb));
cogl_pop_framebuffer ();
}
while (!wl_list_empty (&compositor->frame_callbacks))
{
CoglandFrameCallback *callback =
wl_container_of (compositor->frame_callbacks.next, callback, link);
wl_resource_post_event (&callback->resource,
WL_CALLBACK_DONE, get_time ());
wl_resource_destroy (&callback->resource);
}
compositor->redraw_idle = 0;
return G_SOURCE_REMOVE;
}
static void
cogland_queue_redraw (CoglandCompositor *compositor)
{
if (compositor->redraw_idle == 0)
compositor->redraw_idle = g_idle_add (paint_cb, compositor);
}
static void static void
shm_buffer_damaged (CoglandSurface *surface, shm_buffer_damaged (CoglandSurface *surface,
int32_t x, int32_t x,
@ -335,6 +404,8 @@ cogland_surface_detach_buffer (CoglandSurface *surface)
cogl_object_unref (surface->texture); cogl_object_unref (surface->texture);
surface->texture = NULL; surface->texture = NULL;
} }
cogland_queue_redraw (surface->compositor);
} }
} }
@ -399,16 +470,6 @@ cogland_surface_damage (struct wl_client *client,
region_add (&surface->pending.damage, x, y, width, height); region_add (&surface->pending.damage, x, y, width, height);
} }
typedef struct _CoglandFrameCallback
{
struct wl_list link;
/* Pointer back to the compositor */
CoglandCompositor *compositor;
struct wl_resource resource;
} CoglandFrameCallback;
static void static void
destroy_frame_callback (struct wl_resource *callback_resource) destroy_frame_callback (struct wl_resource *callback_resource)
{ {
@ -520,6 +581,8 @@ cogland_surface_commit (struct wl_client *client,
wl_list_insert_list (&compositor->frame_callbacks, wl_list_insert_list (&compositor->frame_callbacks,
&surface->pending.frame_callback_list); &surface->pending.frame_callback_list);
wl_list_init (&surface->pending.frame_callback_list); wl_list_init (&surface->pending.frame_callback_list);
cogland_queue_redraw (compositor);
} }
static void static void
@ -757,54 +820,6 @@ cogland_compositor_create_output (CoglandCompositor *compositor,
compositor->outputs = g_list_prepend (compositor->outputs, output); compositor->outputs = g_list_prepend (compositor->outputs, output);
} }
static CoglBool
paint_cb (void *user_data)
{
CoglandCompositor *compositor = user_data;
GList *l;
for (l = compositor->outputs; l; l = l->next)
{
CoglandOutput *output = l->data;
CoglFramebuffer *fb = COGL_FRAMEBUFFER (output->onscreen);
GList *l2;
cogl_push_framebuffer (fb);
cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
cogl_framebuffer_draw_primitive (fb, compositor->triangle_pipeline,
compositor->triangle);
for (l2 = compositor->surfaces; l2; l2 = l2->next)
{
CoglandSurface *surface = l2->data;
if (surface->texture)
{
CoglTexture2D *texture = surface->texture;
cogl_set_source_texture (COGL_TEXTURE (texture));
cogl_rectangle (-1, 1, 1, -1);
}
}
cogl_onscreen_swap_buffers (COGL_ONSCREEN (fb));
cogl_pop_framebuffer ();
}
while (!wl_list_empty (&compositor->frame_callbacks))
{
CoglandFrameCallback *callback =
wl_container_of (compositor->frame_callbacks.next, callback, link);
wl_resource_post_event (&callback->resource,
WL_CALLBACK_DONE, get_time ());
wl_resource_destroy (&callback->resource);
}
return TRUE;
}
const static struct wl_compositor_interface cogland_compositor_interface = const static struct wl_compositor_interface cogland_compositor_interface =
{ {
cogland_compositor_create_surface, cogland_compositor_create_surface,
@ -1079,13 +1094,13 @@ main (int argc, char **argv)
3, triangle_vertices); 3, triangle_vertices);
compositor.triangle_pipeline = cogl_pipeline_new (compositor.cogl_context); 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, cogl_source = cogl_glib_source_new (compositor.cogl_context,
G_PRIORITY_DEFAULT); G_PRIORITY_DEFAULT);
g_source_attach (cogl_source, NULL); g_source_attach (cogl_source, NULL);
cogland_queue_redraw (&compositor);
g_main_loop_run (loop); g_main_loop_run (loop);
return 0; return 0;