x11: Add frame synchronization to window frames

There's two meanings of "frame" there! Since SSD frames are now
rendered by an external client, and there are no actual mechanism
that ensures the frame did already get painted when the client did
respond to its NET_WM_FRAME_SYNC_REQUEST request, there may be
artifacts when resizing windows.

In order to get always the best visual result, we should actually
synchronize rendering with both the client window and the window
frame window.

This commit adds these mechanisms, so a sync alarm update is
expected on both windows until further resizes are allowed, this
ensures window and frame stay in sync, even after moving rendering
elsewhere.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
This commit is contained in:
Carlos Garnacho 2022-09-09 15:54:28 +02:00 committed by Marge Bot
parent 782d200d6c
commit f2237fa0c8
6 changed files with 109 additions and 16 deletions

View File

@ -132,6 +132,13 @@ send_frame_messages_timeout (gpointer data)
sync_counter = meta_window_x11_get_sync_counter (window);
meta_sync_counter_finish_incomplete (sync_counter);
if (window->frame)
{
sync_counter = meta_frame_get_sync_counter (window->frame);
meta_sync_counter_finish_incomplete (sync_counter);
}
actor_x11->send_frame_messages_timer = 0;
return G_SOURCE_REMOVE;
@ -208,6 +215,13 @@ assign_frame_counter_to_frames (MetaWindowActorX11 *actor_x11)
sync_counter = meta_window_x11_get_sync_counter (window);
meta_sync_counter_assign_counter_to_frames (sync_counter,
clutter_stage_get_frame_counter (stage));
if (window->frame)
{
sync_counter = meta_frame_get_sync_counter (window->frame);
meta_sync_counter_assign_counter_to_frames (sync_counter,
clutter_stage_get_frame_counter (stage));
}
}
static void
@ -225,6 +239,14 @@ meta_window_actor_x11_frame_complete (MetaWindowActor *actor,
meta_sync_counter_complete_frame (sync_counter,
frame_info,
presentation_time);
if (window->frame)
{
sync_counter = meta_frame_get_sync_counter (window->frame);
meta_sync_counter_complete_frame (sync_counter,
frame_info,
presentation_time);
}
}
static MetaSurfaceActor *
@ -1207,6 +1229,12 @@ meta_window_actor_x11_after_paint (MetaWindowActor *actor,
{
sync_counter = meta_window_x11_get_sync_counter (window);
meta_sync_counter_send_frame_drawn (sync_counter);
if (window->frame)
{
sync_counter = meta_frame_get_sync_counter (window->frame);
meta_sync_counter_send_frame_drawn (sync_counter);
}
}
/* This is for Xwayland, and a no-op on plain Xorg */

View File

@ -30,6 +30,7 @@
#include "core/keybindings-private.h"
#include "meta/meta-x11-errors.h"
#include "x11/meta-x11-display-private.h"
#include "x11/window-props.h"
#include <X11/Xatom.h>
@ -69,7 +70,7 @@ meta_window_set_frame_xwindow (MetaWindow *window,
frame = g_new0 (MetaFrame, 1);
frame->window = window;
frame->xwindow = None;
frame->xwindow = xframe;
frame->rect = window->rect;
frame->child_x = 0;
@ -79,6 +80,8 @@ meta_window_set_frame_xwindow (MetaWindow *window,
frame->borders_cached = FALSE;
meta_sync_counter_init (&frame->sync_counter, window, frame->xwindow);
window->frame = frame;
meta_verbose ("Frame geometry %d,%d %dx%d",
@ -91,8 +94,6 @@ meta_window_set_frame_xwindow (MetaWindow *window,
frame->rect.x, frame->rect.y,
frame->rect.width, frame->rect.height);
frame->xwindow = xframe;
meta_stack_tracker_record_add (window->display->stack_tracker,
frame->xwindow,
create_serial);
@ -136,6 +137,10 @@ meta_window_set_frame_xwindow (MetaWindow *window,
/* stick frame to the window */
window->frame = frame;
meta_window_reload_property_from_xwindow (window, frame->xwindow,
x11_display->atom__NET_WM_SYNC_REQUEST_COUNTER,
TRUE);
XMapWindow (x11_display->xdisplay, frame->xwindow);
/* Move keybindings to frame instead of window */
@ -222,6 +227,8 @@ meta_window_destroy_frame (MetaWindow *window)
/* Move keybindings to window instead of frame */
meta_window_grab_keys (window);
meta_sync_counter_clear (&frame->sync_counter);
g_free (frame);
/* Put our state back where it should be */
@ -496,6 +503,14 @@ meta_frame_handle_xevent (MetaFrame *frame,
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
return TRUE;
}
else if (xevent->xany.type == PropertyNotify &&
xevent->xproperty.state == PropertyNewValue &&
xevent->xproperty.atom == x11_display->atom__NET_WM_SYNC_REQUEST_COUNTER)
{
meta_window_reload_property_from_xwindow (window, frame->xwindow,
xevent->xproperty.atom, FALSE);
return TRUE;
}
return FALSE;
}
@ -572,3 +587,9 @@ meta_frame_type_to_string (MetaFrameType type)
return "<unknown>";
}
MetaSyncCounter *
meta_frame_get_sync_counter (MetaFrame *frame)
{
return &frame->sync_counter;
}

View File

@ -24,6 +24,8 @@
#include "core/window-private.h"
#include "x11/meta-sync-counter.h"
struct _MetaFrame
{
/* window we frame */
@ -39,6 +41,8 @@ struct _MetaFrame
MetaFrameBorders cached_borders; /* valid if borders_cached is set */
MetaSyncCounter sync_counter;
/* position of client, size of frame */
int child_x;
int child_y;
@ -75,4 +79,6 @@ gboolean meta_frame_handle_xevent (MetaFrame *frame,
GSubprocess * meta_frame_launch_client (MetaX11Display *x11_display,
const char *display_name);
MetaSyncCounter * meta_frame_get_sync_counter (MetaFrame *frame);
#endif

View File

@ -250,7 +250,7 @@ meta_frame_new (Window window)
gtk_widget_realize (GTK_WIDGET (frame));
surface = gtk_native_get_surface (GTK_NATIVE (frame));
gdk_x11_surface_set_frame_sync_enabled (surface, FALSE);
gdk_x11_surface_set_frame_sync_enabled (surface, TRUE);
gtk_widget_measure (header,
GTK_ORIENTATION_VERTICAL, 1,

View File

@ -1054,7 +1054,12 @@ reload_update_counter (MetaWindow *window,
{
MetaSyncCounter *sync_counter;
sync_counter = meta_window_x11_get_sync_counter (window);
if (value->source_xwindow == window->xwindow)
sync_counter = meta_window_x11_get_sync_counter (window);
else if (window->frame && value->source_xwindow == window->frame->xwindow)
sync_counter = meta_frame_get_sync_counter (window->frame);
else
g_assert_not_reached ();
if (value->v.xcounter_list.n_counters == 0)
{

View File

@ -1479,9 +1479,6 @@ meta_window_x11_move_resize_internal (MetaWindow *window,
else
configure_frame_first = size_dx + size_dy >= 0;
if (configure_frame_first && window->frame)
frame_shape_changed = meta_frame_sync_to_window (window->frame, need_resize_frame);
values.border_width = 0;
values.x = client_rect.x;
values.y = client_rect.y;
@ -1496,25 +1493,33 @@ meta_window_x11_move_resize_internal (MetaWindow *window,
if (need_resize_client)
mask |= (CWWidth | CWHeight);
meta_x11_error_trap_push (window->display->x11_display);
if (mask != 0 &&
window == window->display->grab_window &&
meta_grab_op_is_resizing (window->display->grab_op))
{
meta_sync_counter_send_request (&priv->sync_counter);
if (window->frame)
meta_sync_counter_send_request (meta_frame_get_sync_counter (window->frame));
}
if (configure_frame_first && window->frame)
frame_shape_changed = meta_frame_sync_to_window (window->frame, need_resize_frame);
if (mask != 0)
{
meta_x11_error_trap_push (window->display->x11_display);
if (window == window->display->grab_window &&
meta_grab_op_is_resizing (window->display->grab_op))
meta_sync_counter_send_request (&priv->sync_counter);
XConfigureWindow (window->display->x11_display->xdisplay,
window->xwindow,
mask,
&values);
meta_x11_error_trap_pop (window->display->x11_display);
}
if (!configure_frame_first && window->frame)
frame_shape_changed = meta_frame_sync_to_window (window->frame, need_resize_frame);
meta_x11_error_trap_pop (window->display->x11_display);
if (window->frame)
window->buffer_rect = window->frame->rect;
else
@ -1900,6 +1905,10 @@ meta_window_x11_are_updates_frozen (MetaWindow *window)
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
if (window->frame &&
meta_sync_counter_is_waiting (meta_frame_get_sync_counter (window->frame)))
return TRUE;
return meta_sync_counter_is_waiting (&priv->sync_counter);
}
@ -4111,6 +4120,9 @@ meta_window_x11_create_sync_request_alarm (MetaWindow *window)
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
if (window->frame)
meta_sync_counter_create_sync_alarm (meta_frame_get_sync_counter (window->frame));
meta_sync_counter_create_sync_alarm (&priv->sync_counter);
}
@ -4120,6 +4132,9 @@ meta_window_x11_destroy_sync_request_alarm (MetaWindow *window)
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
if (window->frame)
meta_sync_counter_destroy_sync_alarm (meta_frame_get_sync_counter (window->frame));
meta_sync_counter_destroy_sync_alarm (&priv->sync_counter);
}
@ -4276,6 +4291,10 @@ meta_window_x11_has_active_sync_alarms (MetaWindow *window)
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
if (window->frame &&
meta_sync_counter_has_sync_alarm (meta_frame_get_sync_counter (window->frame)))
return TRUE;
return meta_sync_counter_has_sync_alarm (&priv->sync_counter);
}
@ -4285,12 +4304,26 @@ meta_window_x11_is_awaiting_sync_response (MetaWindow *window)
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
if (window->frame &&
meta_sync_counter_is_waiting_response (meta_frame_get_sync_counter (window->frame)))
return TRUE;
return meta_sync_counter_is_waiting_response (&priv->sync_counter);
}
void
meta_window_x11_check_update_resize (MetaWindow *window)
{
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
if (window->frame &&
meta_sync_counter_is_waiting (meta_frame_get_sync_counter (window->frame)))
return;
if (meta_sync_counter_is_waiting (&priv->sync_counter))
return;
meta_window_update_resize (window,
window->display->grab_last_edge_resistance_flags,
window->display->grab_latest_motion_x,