From 01a47c7d6d237da913468df97bd5753f9142c6b5 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Sun, 24 Aug 2014 12:02:53 -0400 Subject: [PATCH] shaped-texture: If we have too many rectangles, don't paint the opaque region first If we're going to render the entire texture blended, then don't bother painting the unblended stuff, since we're just going to draw on top anyway. --- src/compositor/meta-shaped-texture.c | 188 ++++++++++++++------------- 1 file changed, 99 insertions(+), 89 deletions(-) diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index 7ae1913b5..afa08de1f 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c @@ -298,10 +298,8 @@ meta_shaped_texture_paint (ClutterActor *actor) guchar opacity; CoglContext *ctx; CoglFramebuffer *fb; - CoglPipeline *pipeline = NULL; CoglTexture *paint_tex; ClutterActorBox alloc; - cairo_region_t *blended_region = NULL; CoglPipelineFilter filter; if (priv->clip_region && cairo_region_is_empty (priv->clip_region)) @@ -339,6 +337,8 @@ meta_shaped_texture_paint (ClutterActor *actor) if (tex_width == 0 || tex_height == 0) /* no contents yet */ return; + cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height }; + /* Use nearest-pixel interpolation if the texture is unscaled. This * improves performance, especially with software rendering. */ @@ -354,7 +354,45 @@ meta_shaped_texture_paint (ClutterActor *actor) opacity = clutter_actor_get_paint_opacity (actor); clutter_actor_get_allocation_box (actor, &alloc); - if (priv->opaque_region != NULL && opacity == 255) + cairo_region_t *blended_region; + gboolean use_opaque_region = (priv->opaque_region != NULL && opacity == 255); + + if (use_opaque_region) + { + if (priv->clip_region != NULL) + blended_region = cairo_region_copy (priv->clip_region); + else + blended_region = cairo_region_create_rectangle (&tex_rect); + + cairo_region_subtract (blended_region, priv->opaque_region); + } + else + { + if (priv->clip_region != NULL) + blended_region = cairo_region_reference (priv->clip_region); + else + blended_region = NULL; + } + + /* Limit to how many separate rectangles we'll draw; beyond this just + * fall back and draw the whole thing */ +#define MAX_RECTS 16 + + if (blended_region != NULL) + { + int n_rects = cairo_region_num_rectangles (blended_region); + if (n_rects > MAX_RECTS) + { + /* Fall back to taking the fully blended path. */ + use_opaque_region = FALSE; + + cairo_region_destroy (blended_region); + blended_region = NULL; + } + } + + /* First, paint the unblended parts, which are part of the opaque region. */ + if (use_opaque_region) { CoglPipeline *opaque_pipeline; cairo_region_t *region; @@ -371,103 +409,75 @@ meta_shaped_texture_paint (ClutterActor *actor) region = cairo_region_reference (priv->opaque_region); } - if (cairo_region_is_empty (region)) - goto paint_blended; - - opaque_pipeline = get_unblended_pipeline (ctx); - cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex); - cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter); - - n_rects = cairo_region_num_rectangles (region); - for (i = 0; i < n_rects; i++) + if (!cairo_region_is_empty (region)) { - cairo_rectangle_int_t rect; - cairo_region_get_rectangle (region, i, &rect); - paint_clipped_rectangle (fb, opaque_pipeline, &rect, &alloc); + opaque_pipeline = get_unblended_pipeline (ctx); + cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex); + cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter); + + n_rects = cairo_region_num_rectangles (region); + for (i = 0; i < n_rects; i++) + { + cairo_rectangle_int_t rect; + cairo_region_get_rectangle (region, i, &rect); + paint_clipped_rectangle (fb, opaque_pipeline, &rect, &alloc); + } + + cogl_object_unref (opaque_pipeline); } - cogl_object_unref (opaque_pipeline); - - if (priv->clip_region != NULL) - { - blended_region = cairo_region_copy (priv->clip_region); - } - else - { - cairo_rectangle_int_t rect = { 0, 0, tex_width, tex_height }; - blended_region = cairo_region_create_rectangle (&rect); - } - - cairo_region_subtract (blended_region, priv->opaque_region); - - paint_blended: cairo_region_destroy (region); } - if (blended_region == NULL && priv->clip_region != NULL) - blended_region = cairo_region_reference (priv->clip_region); - - if (blended_region != NULL && cairo_region_is_empty (blended_region)) - goto out; - - if (priv->mask_texture == NULL) - { - pipeline = get_unmasked_pipeline (ctx); - } - else - { - pipeline = get_masked_pipeline (ctx); - cogl_pipeline_set_layer_texture (pipeline, 1, priv->mask_texture); - cogl_pipeline_set_layer_filters (pipeline, 1, filter, filter); - } - - cogl_pipeline_set_layer_texture (pipeline, 0, paint_tex); - cogl_pipeline_set_layer_filters (pipeline, 0, filter, filter); - + /* Now, go ahead and paint the blended parts. */ { + CoglPipeline *blended_pipeline; + + if (priv->mask_texture == NULL) + { + blended_pipeline = get_unmasked_pipeline (ctx); + } + else + { + blended_pipeline = get_masked_pipeline (ctx); + cogl_pipeline_set_layer_texture (blended_pipeline, 1, priv->mask_texture); + cogl_pipeline_set_layer_filters (blended_pipeline, 1, filter, filter); + } + + cogl_pipeline_set_layer_texture (blended_pipeline, 0, paint_tex); + cogl_pipeline_set_layer_filters (blended_pipeline, 0, filter, filter); + CoglColor color; cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity); - cogl_pipeline_set_color (pipeline, &color); + cogl_pipeline_set_color (blended_pipeline, &color); + + if (blended_region != NULL && !cairo_region_is_empty (blended_region)) + { + int i; + int n_rects = cairo_region_num_rectangles (blended_region); + + for (i = 0; i < n_rects; i++) + { + cairo_rectangle_int_t rect; + cairo_region_get_rectangle (blended_region, i, &rect); + + if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect)) + continue; + + paint_clipped_rectangle (fb, blended_pipeline, &rect, &alloc); + } + } + else + { + cogl_framebuffer_draw_rectangle (fb, blended_pipeline, + 0, 0, + alloc.x2 - alloc.x1, + alloc.y2 - alloc.y1); + } + + cogl_object_unref (blended_pipeline); } - if (blended_region != NULL) - { - int n_rects; - - /* Limit to how many separate rectangles we'll draw; beyond this just - * fall back and draw the whole thing */ -# define MAX_RECTS 16 - - n_rects = cairo_region_num_rectangles (blended_region); - if (n_rects <= MAX_RECTS) - { - int i; - cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height }; - - for (i = 0; i < n_rects; i++) - { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (blended_region, i, &rect); - - if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect)) - continue; - - paint_clipped_rectangle (fb, pipeline, &rect, &alloc); - } - - goto out; - } - } - - cogl_framebuffer_draw_rectangle (fb, pipeline, - 0, 0, - alloc.x2 - alloc.x1, - alloc.y2 - alloc.y1); - - out: - if (pipeline != NULL) - cogl_object_unref (pipeline); if (blended_region != NULL) cairo_region_destroy (blended_region); }