mirror of
https://github.com/brl/mutter.git
synced 2024-12-24 20:12:06 +00:00
shaped-texture: Add support for viewports
This implements the viewporter protocol which offers a cropping and scaling capabilities to wayland clients. There are several use cases for this, for example video players and games, both as a convenience function and as potential performance optimization when paired with hardware overlays etc. https://gitlab.gnome.org/GNOME/mutter/merge_requests/323
This commit is contained in:
parent
07e65a6ef2
commit
edfe5cc3b7
@ -44,5 +44,12 @@ gboolean meta_shaped_texture_is_obscured (MetaShapedTexture *self);
|
|||||||
cairo_region_t * meta_shaped_texture_get_opaque_region (MetaShapedTexture *stex);
|
cairo_region_t * meta_shaped_texture_get_opaque_region (MetaShapedTexture *stex);
|
||||||
void meta_shaped_texture_set_transform (MetaShapedTexture *stex,
|
void meta_shaped_texture_set_transform (MetaShapedTexture *stex,
|
||||||
MetaMonitorTransform transform);
|
MetaMonitorTransform transform);
|
||||||
|
void meta_shaped_texture_set_viewport_src_rect (MetaShapedTexture *stex,
|
||||||
|
ClutterRect *src_rect);
|
||||||
|
void meta_shaped_texture_reset_viewport_src_rect (MetaShapedTexture *stex);
|
||||||
|
void meta_shaped_texture_set_viewport_dst_size (MetaShapedTexture *stex,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height);
|
||||||
|
void meta_shaped_texture_reset_viewport_dst_size (MetaShapedTexture *stex);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "core/boxes-private.h"
|
#include "core/boxes-private.h"
|
||||||
|
|
||||||
#include <gdk/gdk.h>
|
#include <gdk/gdk.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "cogl/cogl.h"
|
#include "cogl/cogl.h"
|
||||||
#include "compositor/clutter-utils.h"
|
#include "compositor/clutter-utils.h"
|
||||||
@ -106,6 +107,11 @@ struct _MetaShapedTexture
|
|||||||
|
|
||||||
gboolean size_invalid;
|
gboolean size_invalid;
|
||||||
MetaMonitorTransform transform;
|
MetaMonitorTransform transform;
|
||||||
|
gboolean has_viewport_src_rect;
|
||||||
|
ClutterRect viewport_src_rect;
|
||||||
|
gboolean has_viewport_dst_size;
|
||||||
|
int viewport_dst_width;
|
||||||
|
int viewport_dst_height;
|
||||||
|
|
||||||
int tex_width, tex_height;
|
int tex_width, tex_height;
|
||||||
int fallback_width, fallback_height;
|
int fallback_width, fallback_height;
|
||||||
@ -169,33 +175,53 @@ meta_shaped_texture_init (MetaShapedTexture *stex)
|
|||||||
static void
|
static void
|
||||||
update_size (MetaShapedTexture *stex)
|
update_size (MetaShapedTexture *stex)
|
||||||
{
|
{
|
||||||
|
ClutterActor *actor = CLUTTER_ACTOR (stex);
|
||||||
int dst_width;
|
int dst_width;
|
||||||
int dst_height;
|
int dst_height;
|
||||||
|
|
||||||
if (meta_monitor_transform_is_rotated (stex->transform))
|
if (stex->has_viewport_dst_size)
|
||||||
{
|
{
|
||||||
if (stex->texture)
|
double tex_scale;
|
||||||
{
|
|
||||||
dst_width = stex->tex_height;
|
clutter_actor_get_scale (actor, &tex_scale, NULL);
|
||||||
dst_height = stex->tex_width;
|
dst_width = ceil (stex->viewport_dst_width / tex_scale);
|
||||||
}
|
dst_height = ceil (stex->viewport_dst_height / tex_scale);
|
||||||
else
|
}
|
||||||
{
|
else if (stex->has_viewport_src_rect)
|
||||||
dst_width = stex->fallback_height;
|
{
|
||||||
dst_height = stex->fallback_width;
|
double tex_scale;
|
||||||
}
|
|
||||||
|
clutter_actor_get_scale (actor, &tex_scale, NULL);
|
||||||
|
dst_width = ceil (stex->viewport_src_rect.size.width / tex_scale);
|
||||||
|
dst_height = ceil (stex->viewport_src_rect.size.height / tex_scale);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (stex->texture)
|
if (meta_monitor_transform_is_rotated (stex->transform))
|
||||||
{
|
{
|
||||||
dst_width = stex->tex_width;
|
if (stex->texture)
|
||||||
dst_height = stex->tex_height;
|
{
|
||||||
|
dst_width = stex->tex_height;
|
||||||
|
dst_height = stex->tex_width;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dst_width = stex->fallback_height;
|
||||||
|
dst_height = stex->fallback_width;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dst_width = stex->fallback_width;
|
if (stex->texture)
|
||||||
dst_height = stex->fallback_height;
|
{
|
||||||
|
dst_width = stex->tex_width;
|
||||||
|
dst_height = stex->tex_height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dst_width = stex->fallback_width;
|
||||||
|
dst_height = stex->fallback_height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,23 +434,66 @@ get_unblended_pipeline (MetaShapedTexture *stex,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
paint_clipped_rectangle (CoglFramebuffer *fb,
|
paint_clipped_rectangle (MetaShapedTexture *stex,
|
||||||
|
CoglFramebuffer *fb,
|
||||||
CoglPipeline *pipeline,
|
CoglPipeline *pipeline,
|
||||||
cairo_rectangle_int_t *rect,
|
cairo_rectangle_int_t *rect,
|
||||||
ClutterActorBox *alloc)
|
ClutterActorBox *alloc)
|
||||||
{
|
{
|
||||||
float coords[8];
|
float coords[8];
|
||||||
float x1, y1, x2, y2;
|
float x1, y1, x2, y2;
|
||||||
|
float alloc_width;
|
||||||
|
float alloc_height;
|
||||||
|
|
||||||
x1 = rect->x;
|
x1 = rect->x;
|
||||||
y1 = rect->y;
|
y1 = rect->y;
|
||||||
x2 = rect->x + rect->width;
|
x2 = rect->x + rect->width;
|
||||||
y2 = rect->y + rect->height;
|
y2 = rect->y + rect->height;
|
||||||
|
alloc_width = alloc->x2 - alloc->x1;
|
||||||
|
alloc_height = alloc->y2 - alloc->y1;
|
||||||
|
|
||||||
coords[0] = rect->x / (alloc->x2 - alloc->x1);
|
if (stex->has_viewport_src_rect)
|
||||||
coords[1] = rect->y / (alloc->y2 - alloc->y1);
|
{
|
||||||
coords[2] = (rect->x + rect->width) / (alloc->x2 - alloc->x1);
|
double tex_scale;
|
||||||
coords[3] = (rect->y + rect->height) / (alloc->y2 - alloc->y1);
|
float src_x;
|
||||||
|
float src_y;
|
||||||
|
float src_width;
|
||||||
|
float src_height;
|
||||||
|
|
||||||
|
clutter_actor_get_scale (CLUTTER_ACTOR (stex), &tex_scale, NULL);
|
||||||
|
|
||||||
|
src_x = stex->viewport_src_rect.origin.x / tex_scale;
|
||||||
|
src_y = stex->viewport_src_rect.origin.y / tex_scale;
|
||||||
|
src_width = stex->viewport_src_rect.size.width / tex_scale;
|
||||||
|
src_height = stex->viewport_src_rect.size.height / tex_scale;
|
||||||
|
|
||||||
|
coords[0] = rect->x * src_width / alloc_width + src_x;
|
||||||
|
coords[1] = rect->y * src_height / alloc_height + src_y;
|
||||||
|
coords[2] = rect->width * src_width / alloc_width + coords[0];
|
||||||
|
coords[3] = rect->height * src_height / alloc_height + coords[1];
|
||||||
|
|
||||||
|
if (meta_monitor_transform_is_rotated (stex->transform))
|
||||||
|
{
|
||||||
|
coords[0] /= stex->tex_height;
|
||||||
|
coords[1] /= stex->tex_width;
|
||||||
|
coords[2] /= stex->tex_height;
|
||||||
|
coords[3] /= stex->tex_width;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
coords[0] /= stex->tex_width;
|
||||||
|
coords[1] /= stex->tex_height;
|
||||||
|
coords[2] /= stex->tex_width;
|
||||||
|
coords[3] /= stex->tex_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
coords[0] = rect->x / alloc_width;
|
||||||
|
coords[1] = rect->y / alloc_height;
|
||||||
|
coords[2] = (rect->x + rect->width) / alloc_width;
|
||||||
|
coords[3] = (rect->y + rect->height) / alloc_height;
|
||||||
|
}
|
||||||
|
|
||||||
coords[4] = coords[0];
|
coords[4] = coords[0];
|
||||||
coords[5] = coords[1];
|
coords[5] = coords[1];
|
||||||
@ -624,7 +693,11 @@ do_paint (MetaShapedTexture *stex,
|
|||||||
{
|
{
|
||||||
cairo_rectangle_int_t rect;
|
cairo_rectangle_int_t rect;
|
||||||
cairo_region_get_rectangle (region, i, &rect);
|
cairo_region_get_rectangle (region, i, &rect);
|
||||||
paint_clipped_rectangle (fb, opaque_pipeline, &rect, &alloc);
|
paint_clipped_rectangle (stex,
|
||||||
|
fb,
|
||||||
|
opaque_pipeline,
|
||||||
|
&rect,
|
||||||
|
&alloc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,16 +750,21 @@ do_paint (MetaShapedTexture *stex,
|
|||||||
if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
|
if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
paint_clipped_rectangle (fb, blended_pipeline, &rect, &alloc);
|
paint_clipped_rectangle (stex,
|
||||||
|
fb,
|
||||||
|
blended_pipeline,
|
||||||
|
&rect,
|
||||||
|
&alloc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* 3) blended_tex_region is NULL. Do a full paint. */
|
/* 3) blended_tex_region is NULL. Do a full paint. */
|
||||||
cogl_framebuffer_draw_rectangle (fb, blended_pipeline,
|
paint_clipped_rectangle (stex,
|
||||||
0, 0,
|
fb,
|
||||||
alloc.x2 - alloc.x1,
|
blended_pipeline,
|
||||||
alloc.y2 - alloc.y1);
|
&tex_rect,
|
||||||
|
&alloc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -909,6 +987,59 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
|
|||||||
stex->dst_height,
|
stex->dst_height,
|
||||||
&clip);
|
&clip);
|
||||||
|
|
||||||
|
if (stex->has_viewport_src_rect || stex->has_viewport_dst_size)
|
||||||
|
{
|
||||||
|
ClutterRect viewport;
|
||||||
|
ClutterRect inverted_viewport;
|
||||||
|
double tex_scale;
|
||||||
|
float dst_width;
|
||||||
|
float dst_height;
|
||||||
|
int inverted_dst_width;
|
||||||
|
int inverted_dst_height;
|
||||||
|
|
||||||
|
clutter_actor_get_scale (CLUTTER_ACTOR (stex), &tex_scale, NULL);
|
||||||
|
|
||||||
|
if (stex->has_viewport_src_rect)
|
||||||
|
{
|
||||||
|
viewport = stex->viewport_src_rect;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
viewport = (ClutterRect) {
|
||||||
|
.origin.x = 0,
|
||||||
|
.origin.y = 0,
|
||||||
|
.size.width = stex->tex_width * tex_scale,
|
||||||
|
.size.height = stex->tex_height * tex_scale
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stex->has_viewport_dst_size)
|
||||||
|
{
|
||||||
|
dst_width = (float) stex->viewport_dst_width;
|
||||||
|
dst_height = (float) stex->viewport_dst_height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dst_width = (float) stex->tex_width * tex_scale;
|
||||||
|
dst_height = (float) stex->tex_height * tex_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
inverted_viewport = (ClutterRect) {
|
||||||
|
.origin.x = -((viewport.origin.x * (dst_width / viewport.size.width)) / tex_scale),
|
||||||
|
.origin.y = -((viewport.origin.y * (dst_height / viewport.size.height)) / tex_scale),
|
||||||
|
.size.width = dst_width,
|
||||||
|
.size.height = dst_height
|
||||||
|
};
|
||||||
|
inverted_dst_width = ceilf (viewport.size.width);
|
||||||
|
inverted_dst_height = ceilf (viewport.size.height);
|
||||||
|
|
||||||
|
meta_rectangle_crop_and_scale (&clip,
|
||||||
|
&inverted_viewport,
|
||||||
|
inverted_dst_width,
|
||||||
|
inverted_dst_height,
|
||||||
|
&clip);
|
||||||
|
}
|
||||||
|
|
||||||
meta_texture_tower_update_area (stex->paint_tower,
|
meta_texture_tower_update_area (stex->paint_tower,
|
||||||
clip.x,
|
clip.x,
|
||||||
clip.y,
|
clip.y,
|
||||||
@ -1063,12 +1194,61 @@ meta_shaped_texture_set_transform (MetaShapedTexture *stex,
|
|||||||
invalidate_size (stex);
|
invalidate_size (stex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_shaped_texture_set_viewport_src_rect (MetaShapedTexture *stex,
|
||||||
|
ClutterRect *src_rect)
|
||||||
|
{
|
||||||
|
if (!stex->has_viewport_src_rect ||
|
||||||
|
stex->viewport_src_rect.origin.x != src_rect->origin.x ||
|
||||||
|
stex->viewport_src_rect.origin.y != src_rect->origin.y ||
|
||||||
|
stex->viewport_src_rect.size.width != src_rect->size.width ||
|
||||||
|
stex->viewport_src_rect.size.height != src_rect->size.height)
|
||||||
|
{
|
||||||
|
stex->has_viewport_src_rect = TRUE;
|
||||||
|
stex->viewport_src_rect = *src_rect;
|
||||||
|
invalidate_size (stex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_shaped_texture_reset_viewport_src_rect (MetaShapedTexture *stex)
|
||||||
|
{
|
||||||
|
stex->has_viewport_src_rect = FALSE;
|
||||||
|
invalidate_size (stex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_shaped_texture_set_viewport_dst_size (MetaShapedTexture *stex,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height)
|
||||||
|
{
|
||||||
|
if (!stex->has_viewport_dst_size ||
|
||||||
|
stex->viewport_dst_width != dst_width ||
|
||||||
|
stex->viewport_dst_height != dst_height)
|
||||||
|
{
|
||||||
|
stex->has_viewport_dst_size = TRUE;
|
||||||
|
stex->viewport_dst_width = dst_width;
|
||||||
|
stex->viewport_dst_height = dst_height;
|
||||||
|
invalidate_size (stex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_shaped_texture_reset_viewport_dst_size (MetaShapedTexture *stex)
|
||||||
|
{
|
||||||
|
stex->has_viewport_dst_size = FALSE;
|
||||||
|
invalidate_size (stex);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
should_get_via_offscreen (MetaShapedTexture *stex)
|
should_get_via_offscreen (MetaShapedTexture *stex)
|
||||||
{
|
{
|
||||||
if (!cogl_texture_is_get_data_supported (stex->texture))
|
if (!cogl_texture_is_get_data_supported (stex->texture))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
if (stex->has_viewport_src_rect || stex->has_viewport_dst_size)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
switch (stex->transform)
|
switch (stex->transform)
|
||||||
{
|
{
|
||||||
case META_MONITOR_TRANSFORM_90:
|
case META_MONITOR_TRANSFORM_90:
|
||||||
|
@ -419,3 +419,44 @@ meta_surface_actor_set_transform (MetaSurfaceActor *self,
|
|||||||
|
|
||||||
meta_shaped_texture_set_transform (priv->texture, transform);
|
meta_shaped_texture_set_transform (priv->texture, transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_surface_actor_set_viewport_src_rect (MetaSurfaceActor *self,
|
||||||
|
ClutterRect *src_rect)
|
||||||
|
{
|
||||||
|
MetaSurfaceActorPrivate *priv =
|
||||||
|
meta_surface_actor_get_instance_private (self);
|
||||||
|
|
||||||
|
meta_shaped_texture_set_viewport_src_rect (priv->texture, src_rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_surface_actor_reset_viewport_src_rect (MetaSurfaceActor *self)
|
||||||
|
{
|
||||||
|
MetaSurfaceActorPrivate *priv =
|
||||||
|
meta_surface_actor_get_instance_private (self);
|
||||||
|
|
||||||
|
meta_shaped_texture_reset_viewport_src_rect (priv->texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_surface_actor_set_viewport_dst_size (MetaSurfaceActor *self,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height)
|
||||||
|
{
|
||||||
|
MetaSurfaceActorPrivate *priv =
|
||||||
|
meta_surface_actor_get_instance_private (self);
|
||||||
|
|
||||||
|
meta_shaped_texture_set_viewport_dst_size (priv->texture,
|
||||||
|
dst_width,
|
||||||
|
dst_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_surface_actor_reset_viewport_dst_size (MetaSurfaceActor *self)
|
||||||
|
{
|
||||||
|
MetaSurfaceActorPrivate *priv =
|
||||||
|
meta_surface_actor_get_instance_private (self);
|
||||||
|
|
||||||
|
meta_shaped_texture_reset_viewport_dst_size (priv->texture);
|
||||||
|
}
|
||||||
|
@ -65,6 +65,13 @@ gboolean meta_surface_actor_is_unredirected (MetaSurfaceActor *actor);
|
|||||||
|
|
||||||
void meta_surface_actor_set_transform (MetaSurfaceActor *self,
|
void meta_surface_actor_set_transform (MetaSurfaceActor *self,
|
||||||
MetaMonitorTransform transform);
|
MetaMonitorTransform transform);
|
||||||
|
void meta_surface_actor_set_viewport_src_rect (MetaSurfaceActor *self,
|
||||||
|
ClutterRect *src_rect);
|
||||||
|
void meta_surface_actor_reset_viewport_src_rect (MetaSurfaceActor *self);
|
||||||
|
void meta_surface_actor_set_viewport_dst_size (MetaSurfaceActor *self,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height);
|
||||||
|
void meta_surface_actor_reset_viewport_dst_size (MetaSurfaceActor *self);
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* META_SURFACE_ACTOR_PRIVATE_H */
|
#endif /* META_SURFACE_ACTOR_PRIVATE_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user