mirror of
https://github.com/brl/mutter.git
synced 2024-12-01 12:20:47 -05:00
shaped-texture: Turn blending off when drawing entirely opaque regions
When drawing entirely opaque regions, we traditionally kept blending on simply because it made the code more convenient and obvious to handle. However, this can cause lots of performance issues on GPUs that aren't too powerful, as they have to readback the buffer underneath. Keep track of the opaque region set by windows (through _NET_WM_OPAQUE_REGION, Wayland opaque_region hints, standard RGB32 frame masks or similar), and draw those rectangles separately through a different path with blending turned off. https://bugzilla.gnome.org/show_bug.cgi?id=707019
This commit is contained in:
parent
452be05ea0
commit
0089b5769c
@ -94,6 +94,7 @@ struct _MetaShapedTexturePrivate
|
|||||||
|
|
||||||
cairo_region_t *clip_region;
|
cairo_region_t *clip_region;
|
||||||
cairo_region_t *input_shape_region;
|
cairo_region_t *input_shape_region;
|
||||||
|
cairo_region_t *opaque_region;
|
||||||
|
|
||||||
guint tex_width, tex_height;
|
guint tex_width, tex_height;
|
||||||
|
|
||||||
@ -172,6 +173,55 @@ get_masked_pipeline (CoglContext *ctx)
|
|||||||
return cogl_pipeline_copy (template);
|
return cogl_pipeline_copy (template);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CoglPipeline *
|
||||||
|
get_unblended_pipeline (CoglContext *ctx)
|
||||||
|
{
|
||||||
|
static CoglPipeline *template = NULL;
|
||||||
|
if (G_UNLIKELY (template == NULL))
|
||||||
|
{
|
||||||
|
CoglColor color;
|
||||||
|
template = cogl_pipeline_new (ctx);
|
||||||
|
cogl_color_init_from_4ub (&color, 255, 255, 255, 255);
|
||||||
|
cogl_pipeline_set_blend (template,
|
||||||
|
"RGBA = ADD (SRC_COLOR, 0)",
|
||||||
|
NULL);
|
||||||
|
cogl_pipeline_set_color (template, &color);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cogl_pipeline_copy (template);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
paint_clipped_rectangle (CoglFramebuffer *fb,
|
||||||
|
CoglPipeline *pipeline,
|
||||||
|
cairo_rectangle_int_t *rect,
|
||||||
|
ClutterActorBox *alloc)
|
||||||
|
{
|
||||||
|
float coords[8];
|
||||||
|
float x1, y1, x2, y2;
|
||||||
|
|
||||||
|
x1 = rect->x;
|
||||||
|
y1 = rect->y;
|
||||||
|
x2 = rect->x + rect->width;
|
||||||
|
y2 = rect->y + rect->height;
|
||||||
|
|
||||||
|
coords[0] = rect->x / (alloc->x2 - alloc->x1);
|
||||||
|
coords[1] = rect->y / (alloc->y2 - alloc->y1);
|
||||||
|
coords[2] = (rect->x + rect->width) / (alloc->x2 - alloc->x1);
|
||||||
|
coords[3] = (rect->y + rect->height) / (alloc->y2 - alloc->y1);
|
||||||
|
|
||||||
|
coords[4] = coords[0];
|
||||||
|
coords[5] = coords[1];
|
||||||
|
coords[6] = coords[2];
|
||||||
|
coords[7] = coords[3];
|
||||||
|
|
||||||
|
cogl_framebuffer_draw_multitextured_rectangle (fb, pipeline,
|
||||||
|
x1, y1, x2, y2,
|
||||||
|
&coords[0], 8);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_cogl_texture (MetaShapedTexture *stex,
|
set_cogl_texture (MetaShapedTexture *stex,
|
||||||
CoglTexture *cogl_tex)
|
CoglTexture *cogl_tex)
|
||||||
@ -222,11 +272,13 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
|||||||
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
|
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
|
||||||
MetaShapedTexturePrivate *priv = stex->priv;
|
MetaShapedTexturePrivate *priv = stex->priv;
|
||||||
guint tex_width, tex_height;
|
guint tex_width, tex_height;
|
||||||
|
guchar opacity;
|
||||||
CoglContext *ctx;
|
CoglContext *ctx;
|
||||||
CoglFramebuffer *fb;
|
CoglFramebuffer *fb;
|
||||||
CoglPipeline *pipeline = NULL;
|
CoglPipeline *pipeline = NULL;
|
||||||
CoglTexture *paint_tex;
|
CoglTexture *paint_tex;
|
||||||
ClutterActorBox alloc;
|
ClutterActorBox alloc;
|
||||||
|
cairo_region_t *blended_region = NULL;
|
||||||
|
|
||||||
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
|
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
|
||||||
return;
|
return;
|
||||||
@ -266,6 +318,64 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
|||||||
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||||
fb = cogl_get_draw_framebuffer ();
|
fb = cogl_get_draw_framebuffer ();
|
||||||
|
|
||||||
|
opacity = clutter_actor_get_paint_opacity (actor);
|
||||||
|
clutter_actor_get_allocation_box (actor, &alloc);
|
||||||
|
|
||||||
|
if (priv->opaque_region != NULL && opacity == 255)
|
||||||
|
{
|
||||||
|
CoglPipeline *opaque_pipeline;
|
||||||
|
cairo_region_t *region;
|
||||||
|
int n_rects;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (priv->clip_region != NULL)
|
||||||
|
{
|
||||||
|
region = cairo_region_copy (priv->clip_region);
|
||||||
|
cairo_region_intersect (region, priv->opaque_region);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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)
|
if (priv->mask_texture == NULL)
|
||||||
{
|
{
|
||||||
pipeline = get_unmasked_pipeline (ctx);
|
pipeline = get_unmasked_pipeline (ctx);
|
||||||
@ -280,18 +390,13 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
|||||||
|
|
||||||
{
|
{
|
||||||
CoglColor color;
|
CoglColor color;
|
||||||
guchar opacity = clutter_actor_get_paint_opacity (actor);
|
|
||||||
cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
|
cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
|
||||||
cogl_pipeline_set_color (pipeline, &color);
|
cogl_pipeline_set_color (pipeline, &color);
|
||||||
}
|
}
|
||||||
|
|
||||||
clutter_actor_get_allocation_box (actor, &alloc);
|
if (blended_region != NULL)
|
||||||
|
|
||||||
if (priv->clip_region)
|
|
||||||
{
|
{
|
||||||
int n_rects;
|
int n_rects;
|
||||||
int i;
|
|
||||||
cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
|
|
||||||
|
|
||||||
/* Limit to how many separate rectangles we'll draw; beyond this just
|
/* Limit to how many separate rectangles we'll draw; beyond this just
|
||||||
* fall back and draw the whole thing */
|
* fall back and draw the whole thing */
|
||||||
@ -300,8 +405,8 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
|||||||
n_rects = cairo_region_num_rectangles (priv->clip_region);
|
n_rects = cairo_region_num_rectangles (priv->clip_region);
|
||||||
if (n_rects <= MAX_RECTS)
|
if (n_rects <= MAX_RECTS)
|
||||||
{
|
{
|
||||||
float coords[8];
|
int i;
|
||||||
float x1, y1, x2, y2;
|
cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
|
||||||
|
|
||||||
for (i = 0; i < n_rects; i++)
|
for (i = 0; i < n_rects; i++)
|
||||||
{
|
{
|
||||||
@ -312,24 +417,7 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
|||||||
if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
|
if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
x1 = rect.x;
|
paint_clipped_rectangle (fb, pipeline, &rect, &alloc);
|
||||||
y1 = rect.y;
|
|
||||||
x2 = rect.x + rect.width;
|
|
||||||
y2 = rect.y + rect.height;
|
|
||||||
|
|
||||||
coords[0] = rect.x / (alloc.x2 - alloc.x1);
|
|
||||||
coords[1] = rect.y / (alloc.y2 - alloc.y1);
|
|
||||||
coords[2] = (rect.x + rect.width) / (alloc.x2 - alloc.x1);
|
|
||||||
coords[3] = (rect.y + rect.height) / (alloc.y2 - alloc.y1);
|
|
||||||
|
|
||||||
coords[4] = coords[0];
|
|
||||||
coords[5] = coords[1];
|
|
||||||
coords[6] = coords[2];
|
|
||||||
coords[7] = coords[3];
|
|
||||||
|
|
||||||
cogl_framebuffer_draw_multitextured_rectangle (fb, pipeline,
|
|
||||||
x1, y1, x2, y2,
|
|
||||||
&coords[0], 8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
@ -344,6 +432,8 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
|||||||
out:
|
out:
|
||||||
if (pipeline != NULL)
|
if (pipeline != NULL)
|
||||||
cogl_object_unref (pipeline);
|
cogl_object_unref (pipeline);
|
||||||
|
if (blended_region != NULL)
|
||||||
|
cairo_region_destroy (blended_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -844,6 +934,36 @@ meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
|
|||||||
priv->clip_region = NULL;
|
priv->clip_region = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* meta_shaped_texture_set_opaque_region:
|
||||||
|
* @stex: a #MetaShapedTexture
|
||||||
|
* @opaque_region: (transfer full): the region of the texture that
|
||||||
|
* can have blending turned off.
|
||||||
|
*
|
||||||
|
* As most windows have a large portion that does not require blending,
|
||||||
|
* we can easily turn off blending if we know the areas that do not
|
||||||
|
* require blending. This sets the region where we will not blend for
|
||||||
|
* optimization purposes.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
|
||||||
|
cairo_region_t *opaque_region)
|
||||||
|
{
|
||||||
|
MetaShapedTexturePrivate *priv;
|
||||||
|
|
||||||
|
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
||||||
|
|
||||||
|
priv = stex->priv;
|
||||||
|
|
||||||
|
if (priv->opaque_region)
|
||||||
|
cairo_region_destroy (priv->opaque_region);
|
||||||
|
|
||||||
|
if (opaque_region)
|
||||||
|
priv->opaque_region = cairo_region_reference (opaque_region);
|
||||||
|
else
|
||||||
|
priv->opaque_region = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* meta_shaped_texture_get_image:
|
* meta_shaped_texture_get_image:
|
||||||
* @stex: A #MetaShapedTexture
|
* @stex: A #MetaShapedTexture
|
||||||
|
@ -2286,6 +2286,9 @@ meta_window_actor_update_opaque_region (MetaWindowActor *self)
|
|||||||
priv->opaque_region = NULL;
|
priv->opaque_region = NULL;
|
||||||
else
|
else
|
||||||
priv->opaque_region = cairo_region_reference (priv->shape_region);
|
priv->opaque_region = cairo_region_reference (priv->shape_region);
|
||||||
|
|
||||||
|
meta_shaped_texture_set_opaque_region (META_SHAPED_TEXTURE (priv->actor),
|
||||||
|
priv->opaque_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -84,6 +84,9 @@ void meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex,
|
|||||||
void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
|
void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
|
||||||
cairo_region_t *clip_region);
|
cairo_region_t *clip_region);
|
||||||
|
|
||||||
|
void meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
|
||||||
|
cairo_region_t *opaque_region);
|
||||||
|
|
||||||
cairo_surface_t * meta_shaped_texture_get_image (MetaShapedTexture *stex,
|
cairo_surface_t * meta_shaped_texture_get_image (MetaShapedTexture *stex,
|
||||||
cairo_rectangle_int_t *clip);
|
cairo_rectangle_int_t *clip);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user