window-actor: Fix screencast with fractionally scaled surfaces
Instead of using `clutter_actor_get_resource_scale()`, we now deduce the intended buffer scale from the window by dividing the unscaled size by the final actor size. This is more correct as while the return value of `clutter_actor_get_resource_scale()` depends only on the monitor where the surface resides, the actual scale of the surface is determined solely by the application itself. `get_resource_scale` will differ from the actual buffer scale if the application only supports 100% scaling (Xwayland), or is performing scaling with wp_viewporter (clients using fractional_scale_v1). This also fixes a mismatch between the calculated buffer sizes between `meta_window_actor_get_buffer_bounds` and `meta_window_actor_blit_to_framebuffer` which causes broken screencasting for Chromium 114 and later when using the native Ozone Wayland backend. Additionally, this commit also changes `meta_window_actor_blit_to_framebuffer` from using a simple translation to using an inverted matrix transformation of the transformation matrix between the parent of the window actor and the surface actor to ensure maximum sharpness for fractionally scaled windows. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3053>
This commit is contained in:
parent
742d026479
commit
842f73ac4c
2 changed files with 66 additions and 37 deletions
|
@ -1533,8 +1533,11 @@ get_unscaled_size (MetaShapedTexture *stex)
|
|||
float
|
||||
meta_shaped_texture_get_unscaled_width (MetaShapedTexture *stex)
|
||||
{
|
||||
graphene_size_t unscaled_size;
|
||||
|
||||
g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), 0);
|
||||
graphene_size_t unscaled_size = get_unscaled_size (stex);
|
||||
|
||||
unscaled_size = get_unscaled_size (stex);
|
||||
|
||||
return unscaled_size.width;
|
||||
}
|
||||
|
@ -1548,8 +1551,11 @@ meta_shaped_texture_get_unscaled_width (MetaShapedTexture *stex)
|
|||
float
|
||||
meta_shaped_texture_get_unscaled_height (MetaShapedTexture *stex)
|
||||
{
|
||||
graphene_size_t unscaled_size;
|
||||
|
||||
g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), 0);
|
||||
graphene_size_t unscaled_size = get_unscaled_size (stex);
|
||||
|
||||
unscaled_size = get_unscaled_size (stex);
|
||||
|
||||
return unscaled_size.height;
|
||||
}
|
||||
|
|
|
@ -1118,13 +1118,11 @@ meta_window_actor_get_buffer_bounds (MetaScreenCastWindow *screen_cast_window,
|
|||
MetaWindowActorPrivate *priv =
|
||||
meta_window_actor_get_instance_private (window_actor);
|
||||
MetaShapedTexture *stex;
|
||||
int buffer_scale;
|
||||
|
||||
stex = meta_surface_actor_get_texture (priv->surface);
|
||||
buffer_scale = meta_shaped_texture_get_buffer_scale (stex);
|
||||
*bounds = (MetaRectangle) {
|
||||
.width = meta_shaped_texture_get_width (stex) * buffer_scale,
|
||||
.height = meta_shaped_texture_get_height (stex) * buffer_scale,
|
||||
.width = floorf (meta_shaped_texture_get_unscaled_width (stex)),
|
||||
.height = floorf (meta_shaped_texture_get_unscaled_height (stex)),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1209,7 +1207,13 @@ meta_window_actor_transform_cursor_position (MetaScreenCastWindow *screen_cast_w
|
|||
|
||||
if (out_relative_cursor_position)
|
||||
{
|
||||
float resource_scale;
|
||||
MetaShapedTexture *stex = meta_surface_actor_get_texture (priv->surface);
|
||||
|
||||
float unscaled_width = meta_shaped_texture_get_unscaled_width (stex);
|
||||
float unscaled_height = meta_shaped_texture_get_unscaled_height (stex);
|
||||
|
||||
int width = meta_shaped_texture_get_width (stex);
|
||||
int height = meta_shaped_texture_get_height (stex);
|
||||
|
||||
clutter_actor_transform_stage_point (CLUTTER_ACTOR (priv->surface),
|
||||
cursor_position->x,
|
||||
|
@ -1217,10 +1221,10 @@ meta_window_actor_transform_cursor_position (MetaScreenCastWindow *screen_cast_w
|
|||
&out_relative_cursor_position->x,
|
||||
&out_relative_cursor_position->y);
|
||||
|
||||
resource_scale =
|
||||
clutter_actor_get_resource_scale (CLUTTER_ACTOR (window_actor));
|
||||
out_relative_cursor_position->x *= resource_scale;
|
||||
out_relative_cursor_position->y *= resource_scale;
|
||||
if (width != 0)
|
||||
out_relative_cursor_position->x *= unscaled_width / width;
|
||||
if (height != 0)
|
||||
out_relative_cursor_position->y *= unscaled_height / height;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
@ -1288,54 +1292,73 @@ meta_window_actor_blit_to_framebuffer (MetaScreenCastWindow *screen_cast_window,
|
|||
CoglFramebuffer *framebuffer)
|
||||
{
|
||||
MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window);
|
||||
MetaWindowActorPrivate *priv =
|
||||
meta_window_actor_get_instance_private (window_actor);
|
||||
ClutterActor *actor = CLUTTER_ACTOR (window_actor);
|
||||
ClutterPaintContext *paint_context;
|
||||
MetaRectangle scaled_clip;
|
||||
graphene_rect_t scaled_clip;
|
||||
CoglColor clear_color;
|
||||
float resource_scale;
|
||||
MetaShapedTexture *stex;
|
||||
graphene_matrix_t transform, inverted_transform;
|
||||
float width, height;
|
||||
float x, y;
|
||||
float unscaled_width, unscaled_height;
|
||||
|
||||
if (meta_window_actor_is_destroyed (window_actor))
|
||||
return FALSE;
|
||||
|
||||
clutter_actor_get_size (actor, &width, &height);
|
||||
if (!priv->surface)
|
||||
return FALSE;
|
||||
|
||||
stex = meta_surface_actor_get_texture (priv->surface);
|
||||
|
||||
width = meta_shaped_texture_get_width (stex);
|
||||
height = meta_shaped_texture_get_height (stex);
|
||||
|
||||
if (width == 0 || height == 0)
|
||||
return FALSE;
|
||||
|
||||
resource_scale = clutter_actor_get_resource_scale (actor);
|
||||
clutter_actor_get_relative_transformation_matrix (CLUTTER_ACTOR (priv->surface),
|
||||
clutter_actor_get_stage (actor),
|
||||
&transform);
|
||||
|
||||
if (!graphene_matrix_inverse (&transform, &inverted_transform))
|
||||
return FALSE;
|
||||
|
||||
unscaled_width = meta_shaped_texture_get_unscaled_width (stex);
|
||||
unscaled_height = meta_shaped_texture_get_unscaled_height (stex);
|
||||
|
||||
clutter_actor_inhibit_culling (actor);
|
||||
|
||||
width = ceilf (width * resource_scale);
|
||||
height = ceilf (height * resource_scale);
|
||||
|
||||
clutter_actor_get_position (actor, &x, &y);
|
||||
|
||||
cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0);
|
||||
cogl_framebuffer_clear (framebuffer, COGL_BUFFER_BIT_COLOR, &clear_color);
|
||||
cogl_framebuffer_orthographic (framebuffer, 0, 0, width, height, 0, 1.0);
|
||||
cogl_framebuffer_set_viewport (framebuffer, 0, 0, width, height);
|
||||
cogl_framebuffer_orthographic (framebuffer,
|
||||
0, 0,
|
||||
unscaled_width, unscaled_height,
|
||||
0, 1.0);
|
||||
cogl_framebuffer_set_viewport (framebuffer,
|
||||
0, 0,
|
||||
unscaled_width, unscaled_height);
|
||||
|
||||
meta_rectangle_scale_double (bounds, resource_scale,
|
||||
META_ROUNDING_STRATEGY_GROW,
|
||||
&scaled_clip);
|
||||
meta_rectangle_intersect (&scaled_clip,
|
||||
&(MetaRectangle) {
|
||||
.width = width,
|
||||
.height = height,
|
||||
},
|
||||
&scaled_clip);
|
||||
scaled_clip = meta_rectangle_to_graphene_rect (bounds);
|
||||
graphene_rect_scale (&scaled_clip,
|
||||
unscaled_width / width,
|
||||
unscaled_height / height,
|
||||
&scaled_clip);
|
||||
graphene_rect_intersection (&scaled_clip,
|
||||
&GRAPHENE_RECT_INIT (0, 0, unscaled_width, unscaled_height),
|
||||
&scaled_clip);
|
||||
|
||||
cogl_framebuffer_push_rectangle_clip (framebuffer,
|
||||
scaled_clip.x, scaled_clip.y,
|
||||
scaled_clip.x + scaled_clip.width,
|
||||
scaled_clip.y + scaled_clip.height);
|
||||
scaled_clip.origin.x, scaled_clip.origin.y,
|
||||
scaled_clip.origin.x + scaled_clip.size.width,
|
||||
scaled_clip.origin.y + scaled_clip.size.height);
|
||||
|
||||
cogl_framebuffer_push_matrix (framebuffer);
|
||||
cogl_framebuffer_scale (framebuffer, resource_scale, resource_scale, 1);
|
||||
cogl_framebuffer_translate (framebuffer, -x, -y, 0);
|
||||
cogl_framebuffer_scale (framebuffer,
|
||||
unscaled_width / width,
|
||||
unscaled_height / height,
|
||||
1);
|
||||
cogl_framebuffer_transform (framebuffer, &inverted_transform);
|
||||
|
||||
paint_context =
|
||||
clutter_paint_context_new_for_framebuffer (framebuffer, NULL,
|
||||
|
|
Loading…
Reference in a new issue