clutter/offscreen-effect: Set the viewport correctly

Previously we were setting the FBO's viewport to be the same dimensions as
the stage itself for compatibility. This works for most cases, but not if
the actor is larger than the stage. In that case it could cause excessive
clipping if the actor's transformed screen position was negative, which
is seen in https://gitlab.gnome.org/GNOME/gnome-shell/issues/2087

Also if a small actor paints to its negative dimensions (like a box-shadow)
then we might be missing those pixels on the left or top, even though
they're inside the paint volume.

Now we set the viewport dimensions to match the area we're actually
rendering so the FBO contents are never over or under clipped.

Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3068

Although if you try using shadows larger than that (like in
gnome-shell#1090) then you will also need gnome-shell!1417.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1053>
This commit is contained in:
Daniel van Vugt 2020-02-13 16:27:32 +08:00 committed by Marge Bot
parent f887b02714
commit 41bf0181b9

View File

@ -300,7 +300,7 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
CoglFramebuffer *offscreen; CoglFramebuffer *offscreen;
ClutterActorBox raw_box, box; ClutterActorBox raw_box, box;
ClutterActor *stage; ClutterActor *stage;
graphene_matrix_t projection, modelview; graphene_matrix_t projection, modelview, transform;
const ClutterPaintVolume *volume; const ClutterPaintVolume *volume;
gfloat stage_width, stage_height; gfloat stage_width, stage_height;
gfloat target_width = -1, target_height = -1; gfloat target_width = -1, target_height = -1;
@ -368,16 +368,25 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
* contents on screen... * contents on screen...
*/ */
clutter_actor_get_transform (priv->stage, &modelview); clutter_actor_get_transform (priv->stage, &modelview);
graphene_matrix_init_translate (&transform,
&GRAPHENE_POINT3D_INIT (-priv->fbo_offset_x,
-priv->fbo_offset_y,
0.0));
graphene_matrix_scale (&transform,
stage_width / target_width,
stage_height / target_height,
1.0);
graphene_matrix_multiply (&transform, &modelview, &modelview);
cogl_framebuffer_set_modelview_matrix (offscreen, &modelview); cogl_framebuffer_set_modelview_matrix (offscreen, &modelview);
/* Set up the viewport so that it has the same size as the stage (avoid /* Set up the viewport so that it has the minimal size required to render any
* distortion), but translated to account for the FBO offset... * pixel in the FBO without clipping.
*/ */
cogl_framebuffer_set_viewport (offscreen, cogl_framebuffer_set_viewport (offscreen,
-priv->fbo_offset_x, 0,
-priv->fbo_offset_y, 0,
stage_width, target_width,
stage_height); target_height);
/* Copy the stage's projection matrix across to the offscreen */ /* Copy the stage's projection matrix across to the offscreen */
_clutter_stage_get_projection_matrix (CLUTTER_STAGE (priv->stage), _clutter_stage_get_projection_matrix (CLUTTER_STAGE (priv->stage),