[gtk/wip/carlosg/stuck-frames: 31/31] surface: Always set PHASE_PAINT as pending when updates are scheduled




commit 07167fdf2223172cae57b5cf10eba9d29869af3b
Author: Carlos Garnacho <carlosg gnome org>
Date:   Wed Apr 7 21:04:28 2021 +0200

    surface: Always set PHASE_PAINT as pending when updates are scheduled
    
    At times (most often when closing subsurfaces that are scheduling
    relayouts) the PHASE_PAINT handling gets broken with the following
    sequence:
    
    1. Surface receives wl_callback.done for the previous frame.
       Surface is thawed.
    2. A new update on the surface is scheduled. PHASE_PAINT is
       requested directly on the frame clock. priv->pending_phase is
       left unset in the surface.
    3. Surface gets frozen
    4. Frame clock processes the update scheduled at 2. The surface
       is frozen, so paint is prevented. PHASE_PAINT is considered
       handled.
    5. Compositor emits wl_callback.done again. Surface is thawed.
    6. At this point the machinery is off
       - The surface didn't paint but has pending update regions
       - priv->draw_needed is set in the toplevel and other portions
         of the widget tree
       - So queueing redraws is ineffective at eventually calling
         gdk_surface_schedule_update() again on the toplevel surface.
       - We don't paint anymore, so this broken state is not flushed
         until other subsurface changes manage to schedule the missing
         update.
    
    To fix this, always set PHASE_PAINT in priv->pending_phase when
    doing gdk_surface_schedule_update(). If the frame clock turns
    around before the surface is thawed, it will still be waiting to
    be processed the next iteration.
    
    Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/3750

 gdk/gdksurface.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)
---
diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c
index c55a9a8042..ef6464c43a 100644
--- a/gdk/gdksurface.c
+++ b/gdk/gdksurface.c
@@ -1299,12 +1299,11 @@ gdk_surface_schedule_update (GdkSurface *surface)
 
   g_return_if_fail (surface);
 
+  surface->pending_phases |= GDK_FRAME_CLOCK_PHASE_PAINT;
+
   if (surface->update_freeze_count ||
       gdk_surface_is_toplevel_frozen (surface))
-    {
-      surface->pending_phases |= GDK_FRAME_CLOCK_PHASE_PAINT;
-      return;
-    }
+    return;
 
   /* If there's no frame clock (a foreign surface), then the invalid
    * region will just stick around unless gdk_surface_process_updates()


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]