[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