clutter/stage-cogl: Check for buffer age early

Fix a regression that got introduced with
c483b52d24 where we started passing the
redraw_clip to paint_stage() instead of creating a temporary view_region
for unclipped redraws: In case we detect an invalid buffer age, we fall
back to doing an unclipped redraw after we passed the first check
setting up may_use_clipped_redraw. That means we didn't reset the
redraw_clip to the view_rect, and we're now going to redraw the stage
using the original redraw clip even though we're swapping the full
framebuffer without damage.

To fix that, check for the buffer age before setting up the
fb_clip_region and the redraw_clip and set may_use_clipped_redraw to
FALSE if the buffer age is invalid, too. This ensures the redraw_clip is
always going to be correctly set to the view rect when we want to force
a full redraw.

Fixes https://gitlab.gnome.org/GNOME/mutter/issues/1128
This commit is contained in:
Jonas Dreßler 2020-03-19 22:30:06 +01:00 committed by Jonas Ådahl
parent da600b8400
commit 92710d8f89

View File

@ -628,6 +628,7 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
float fb_scale; float fb_scale;
int subpixel_compensation = 0; int subpixel_compensation = 0;
int fb_width, fb_height; int fb_width, fb_height;
int buffer_age;
wrapper = CLUTTER_ACTOR (stage_cogl->wrapper); wrapper = CLUTTER_ACTOR (stage_cogl->wrapper);
@ -650,16 +651,26 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
else else
is_full_redraw = FALSE; is_full_redraw = FALSE;
may_use_clipped_redraw = FALSE; may_use_clipped_redraw =
if (_clutter_stage_window_can_clip_redraws (stage_window) && _clutter_stage_window_can_clip_redraws (stage_window) &&
(can_blit_sub_buffer || has_buffer_age) && (can_blit_sub_buffer || has_buffer_age) &&
!is_full_redraw && !is_full_redraw &&
/* some drivers struggle to get going and produce some junk /* some drivers struggle to get going and produce some junk
* frames when starting up... */ * frames when starting up... */
cogl_onscreen_get_frame_counter (COGL_ONSCREEN (fb)) > 3) cogl_onscreen_get_frame_counter (COGL_ONSCREEN (fb)) > 3;
{
may_use_clipped_redraw = TRUE;
if (has_buffer_age)
{
buffer_age = cogl_onscreen_get_buffer_age (COGL_ONSCREEN (fb));
if (!valid_buffer_age (view_cogl, buffer_age))
{
CLUTTER_NOTE (CLIPPING, "Invalid back buffer(age=%d): forcing full redraw\n", buffer_age);
may_use_clipped_redraw = FALSE;
}
}
if (may_use_clipped_redraw)
{
fb_clip_region = offset_scale_and_clamp_region (redraw_clip, fb_clip_region = offset_scale_and_clamp_region (redraw_clip,
-view_rect.x, -view_rect.x,
-view_rect.y, -view_rect.y,
@ -715,64 +726,43 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
{ {
if (use_clipped_redraw && !clip_region_empty) if (use_clipped_redraw && !clip_region_empty)
{ {
int age; cairo_region_t *fb_damage;
cairo_region_t *view_damage;
int i;
age = cogl_onscreen_get_buffer_age (COGL_ONSCREEN (fb)); fill_current_damage_history (view, fb_clip_region);
if (valid_buffer_age (view_cogl, age)) fb_damage = cairo_region_create ();
for (i = 1; i <= buffer_age; i++)
{ {
cairo_region_t *fb_damage; int damage_index;
cairo_region_t *view_damage;
int i;
fill_current_damage_history (view, fb_clip_region); damage_index = DAMAGE_HISTORY (view_priv->damage_index - i - 1);
cairo_region_union (fb_damage,
fb_damage = cairo_region_create (); view_priv->damage_history[damage_index]);
for (i = 1; i <= age; i++)
{
int damage_index;
damage_index = DAMAGE_HISTORY (view_priv->damage_index - i - 1);
cairo_region_union (fb_damage,
view_priv->damage_history[damage_index]);
}
/* Update the fb clip region with the extra damage. */
cairo_region_union (fb_clip_region, fb_damage);
view_damage = offset_scale_and_clamp_region (fb_damage,
0, 0,
1.0f / fb_scale);
cairo_region_translate (view_damage, view_rect.x, view_rect.y);
cairo_region_intersect_rectangle (view_damage, &view_rect);
/* Update the redraw clip region with the extra damage. */
cairo_region_union (redraw_clip, view_damage);
cairo_region_destroy (view_damage);
cairo_region_destroy (fb_damage);
CLUTTER_NOTE (CLIPPING, "Reusing back buffer(age=%d) - repairing region: num rects: %d\n",
age,
cairo_region_num_rectangles (fb_clip_region));
swap_with_damage = TRUE;
} }
else
{
cairo_rectangle_int_t fb_damage;
CLUTTER_NOTE (CLIPPING, "Invalid back buffer(age=%d): forcing full redraw\n", age); /* Update the fb clip region with the extra damage. */
use_clipped_redraw = FALSE; cairo_region_union (fb_clip_region, fb_damage);
fb_damage = (cairo_rectangle_int_t) {
.x = 0, view_damage = offset_scale_and_clamp_region (fb_damage,
.y = 0, 0, 0,
.width = ceilf (view_rect.width * fb_scale), 1.0f / fb_scale);
.height = ceilf (view_rect.height * fb_scale) cairo_region_translate (view_damage, view_rect.x, view_rect.y);
}; cairo_region_intersect_rectangle (view_damage, &view_rect);
fill_current_damage_history_rectangle (view, &fb_damage);
} /* Update the redraw clip region with the extra damage. */
cairo_region_union (redraw_clip, view_damage);
cairo_region_destroy (view_damage);
cairo_region_destroy (fb_damage);
CLUTTER_NOTE (CLIPPING, "Reusing back buffer(age=%d) - repairing region: num rects: %d\n",
buffer_age,
cairo_region_num_rectangles (fb_clip_region));
swap_with_damage = TRUE;
} }
else if (!use_clipped_redraw) else if (!use_clipped_redraw)
{ {