[PATCH 2/2] compositor-drm: use a DRM specific repaint function
Jesse Barnes
jbarnes at virtuousgeek.org
Fri Jan 6 11:36:15 PST 2012
The DRM repaint function can allocate available DRM display planes for
use in drawing surfaces. In some cases a repaint can even be avoided if
only a surface currently using a sprite has been updated.
---
src/compositor-drm.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 108 insertions(+), 1 deletions(-)
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 433c644..db1be29 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -78,6 +78,113 @@ struct drm_output {
uint32_t pending_fs_surf_fb_id;
};
+/*
+ * An output has a primary display plane plus zero or more sprites for
+ * blending display contents.
+ */
+struct drm_output_sprite {
+ uint32_t fb_id;
+
+ int32_t src_x, src_y;
+ uint32_t src_w, src_h;
+ uint32_t dest_x, dest_y;
+ uint32_t dest_w, dest_h;
+};
+
+static void
+weston_find_sprite_surfaces(struct weston_output *output)
+{
+ struct weston_compositor *ec = output->compositor;
+ struct weston_surface *es;
+
+ /*
+ * Find a surface for each sprite in the output using some heuristics:
+ * 1) size
+ * 2) frequency of update
+ * 3) opacity (though some hw might support alpha blending)
+ * 4) clipping (this can be fixed with color keys)
+ *
+ * The idea is to save on blitting since this should save power.
+ * If we can get a large video surface on the sprite for example,
+ * the main display surface may not need to update at all, and
+ * the client buffer can be used directly for the sprite surface
+ * as we do for flipping full screen surfaces.
+ */
+}
+
+static void
+drm_output_repaint(struct weston_output *output)
+{
+ struct weston_compositor *ec = output->compositor;
+ struct weston_surface *es;
+ pixman_region32_t opaque, new_damage, total_damage, repaint;
+
+ output->prepare_render(output);
+
+ glViewport(0, 0, output->current->width, output->current->height);
+
+ glUseProgram(ec->texture_shader.program);
+ glUniformMatrix4fv(ec->texture_shader.proj_uniform,
+ 1, GL_FALSE, output->matrix.d);
+ glUniform1i(ec->texture_shader.tex_uniform, 0);
+
+ weston_output_set_cursor(output, ec->input_device,
+ ec->fade.spring.current >= 0.001);
+
+ pixman_region32_init(&new_damage);
+ pixman_region32_init(&opaque);
+
+ wl_list_for_each(es, &ec->surface_list, link) {
+ pixman_region32_subtract(&es->damage, &es->damage, &opaque);
+ pixman_region32_union(&new_damage, &new_damage, &es->damage);
+ pixman_region32_union(&opaque, &opaque, &es->opaque);
+ }
+
+ pixman_region32_init(&total_damage);
+ pixman_region32_union(&total_damage, &new_damage,
+ &output->previous_damage);
+ pixman_region32_intersect(&output->previous_damage,
+ &new_damage, &output->region);
+
+ pixman_region32_fini(&opaque);
+ pixman_region32_fini(&new_damage);
+
+ es = container_of(ec->surface_list.next, struct weston_surface, link);
+
+ if (setup_scanout_surface(output, es) == 0)
+ /* We're drawing nothing, just let the damage accumulate */
+ return;
+
+ if (es->fullscreen_output == output) {
+ if (es->width < output->current->width ||
+ es->height < output->current->height)
+ glClear(GL_COLOR_BUFFER_BIT);
+ weston_surface_draw(es, output, &total_damage);
+ } else {
+ weston_find_sprite_surfaces(output);
+
+ wl_list_for_each(es, &ec->surface_list, link) {
+ pixman_region32_copy(&es->damage, &total_damage);
+ pixman_region32_subtract(&total_damage, &total_damage, &es->opaque);
+ }
+
+ wl_list_for_each_reverse(es, &ec->surface_list, link) {
+ pixman_region32_init(&repaint);
+ pixman_region32_intersect(&repaint, &output->region,
+ &es->damage);
+ weston_surface_draw(es, output, &repaint);
+ pixman_region32_subtract(&es->damage,
+ &es->damage, &output->region);
+ pixman_region32_fini(&repaint);
+ }
+ }
+
+ if (ec->fade.spring.current > 0.001)
+ fade_output(output, ec->fade.spring.current, &total_damage);
+
+ pixman_region32_fini(&total_damage);
+}
+
static int
drm_output_prepare_render(struct weston_output *output_base)
{
@@ -548,7 +655,7 @@ create_output_for_connector(struct drm_compositor *ec,
wl_list_insert(ec->base.output_list.prev, &output->base.link);
output->pending_fs_surf_fb_id = 0;
- output->base.repaint = weston_output_repaint;
+ output->base.repaint = drm_output_repaint;
output->base.prepare_render = drm_output_prepare_render;
output->base.present = drm_output_present;
output->base.prepare_scanout_surface =
--
1.7.4.1
More information about the wayland-devel
mailing list