2019-08-14 21:25:54 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2019 Red Hat Inc.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2023-08-07 09:50:23 +00:00
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
2019-08-14 21:25:54 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include "compositor/meta-compositor-x11.h"
|
|
|
|
|
|
|
|
#include <X11/extensions/shape.h>
|
|
|
|
#include <X11/extensions/Xcomposite.h>
|
|
|
|
|
|
|
|
#include "backends/x11/meta-backend-x11.h"
|
2021-05-10 21:40:49 +00:00
|
|
|
#include "backends/x11/meta-clutter-backend-x11.h"
|
2019-03-22 12:53:00 +00:00
|
|
|
#include "backends/x11/meta-event-x11.h"
|
2022-07-15 09:06:12 +00:00
|
|
|
#include "compositor/meta-compositor-view.h"
|
2019-08-14 21:25:54 +00:00
|
|
|
#include "compositor/meta-sync-ring.h"
|
2019-08-17 08:00:46 +00:00
|
|
|
#include "compositor/meta-window-actor-x11.h"
|
2019-08-14 21:25:54 +00:00
|
|
|
#include "core/display-private.h"
|
|
|
|
#include "x11/meta-x11-display-private.h"
|
|
|
|
|
|
|
|
struct _MetaCompositorX11
|
|
|
|
{
|
|
|
|
MetaCompositor parent;
|
|
|
|
|
|
|
|
Window output;
|
|
|
|
|
2020-05-29 21:47:29 +00:00
|
|
|
gulong before_update_handler_id;
|
2021-03-04 18:11:12 +00:00
|
|
|
gulong after_update_handler_id;
|
2020-05-29 21:47:29 +00:00
|
|
|
|
2019-08-14 21:25:54 +00:00
|
|
|
gboolean frame_has_updated_xsurfaces;
|
|
|
|
gboolean have_x11_sync_object;
|
|
|
|
|
|
|
|
MetaWindow *unredirected_window;
|
compositor: Make sure _NET_WM_FRAME_DRAWN timestamp has the right scope
The timestamp sent with _NET_WM_FRAME_DRAWN should be in "high
resolution X server timestamps", meaning they should have the same scope
as the built in X11 32 bit unsigned integer timestamps, i.e. overflow at
the same time.
This was not done correctly when mutter had determined the X server used
the monotonic clock, where it'd just forward the monotonic clock,
confusing any client using _NET_WM_FRAME_DRAWN and friends.
Fix this by 1) splitting the timestamp conversiot into an X11 case and a
display server case, where the display server case simply clamps the
monotonic clock, as it is assumed Xwayland is always usign the monotonic
clock, and 2) if we're a X11 compositing manager, if the X server is
using the monotonic clock, apply the same semantics as the display
server case and always just clamp, or if not, calculate the offset every
10 seconds, and offset the monotonic clock timestamp with the calculated
X server timestamp offset.
This fixes an issue that would occur if mutter (or rather GNOME Shell)
would have been started before a X11 timestamp overflow, after the
overflow happened. In this case, GTK3 clients would get unclamped
timestamps, and get very confused, resulting in frames queued several
weeks into the future.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1494
2020-07-08 14:53:14 +00:00
|
|
|
|
|
|
|
gboolean xserver_uses_monotonic_clock;
|
|
|
|
int64_t xserver_time_query_time_us;
|
|
|
|
int64_t xserver_time_offset_us;
|
2019-08-14 21:25:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (MetaCompositorX11, meta_compositor_x11, META_TYPE_COMPOSITOR)
|
|
|
|
|
|
|
|
static void
|
|
|
|
process_damage (MetaCompositorX11 *compositor_x11,
|
|
|
|
XDamageNotifyEvent *damage_xevent,
|
|
|
|
MetaWindow *window)
|
|
|
|
{
|
|
|
|
MetaWindowActor *window_actor = meta_window_actor_from_window (window);
|
2019-08-17 08:00:46 +00:00
|
|
|
MetaWindowActorX11 *window_actor_x11 = META_WINDOW_ACTOR_X11 (window_actor);
|
2019-08-14 21:25:54 +00:00
|
|
|
|
2019-08-17 08:00:46 +00:00
|
|
|
meta_window_actor_x11_process_damage (window_actor_x11, damage_xevent);
|
2019-08-14 21:25:54 +00:00
|
|
|
|
|
|
|
compositor_x11->frame_has_updated_xsurfaces = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_compositor_x11_process_xevent (MetaCompositorX11 *compositor_x11,
|
|
|
|
XEvent *xevent,
|
|
|
|
MetaWindow *window)
|
|
|
|
{
|
|
|
|
MetaCompositor *compositor = META_COMPOSITOR (compositor_x11);
|
|
|
|
MetaDisplay *display = meta_compositor_get_display (compositor);
|
|
|
|
MetaX11Display *x11_display = display->x11_display;
|
|
|
|
int damage_event_base;
|
|
|
|
|
|
|
|
damage_event_base = meta_x11_display_get_damage_event_base (x11_display);
|
|
|
|
if (xevent->type == damage_event_base + XDamageNotify)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Core code doesn't handle damage events, so we need to extract the
|
|
|
|
* MetaWindow ourselves.
|
|
|
|
*/
|
|
|
|
if (!window)
|
|
|
|
{
|
|
|
|
Window xwindow;
|
|
|
|
|
|
|
|
xwindow = ((XDamageNotifyEvent *) xevent)->drawable;
|
|
|
|
window = meta_x11_display_lookup_x_window (x11_display, xwindow);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window)
|
|
|
|
process_damage (compositor_x11, (XDamageNotifyEvent *) xevent, window);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (compositor_x11->have_x11_sync_object)
|
|
|
|
meta_sync_ring_handle_event (xevent);
|
|
|
|
}
|
|
|
|
|
compositor: Make sure _NET_WM_FRAME_DRAWN timestamp has the right scope
The timestamp sent with _NET_WM_FRAME_DRAWN should be in "high
resolution X server timestamps", meaning they should have the same scope
as the built in X11 32 bit unsigned integer timestamps, i.e. overflow at
the same time.
This was not done correctly when mutter had determined the X server used
the monotonic clock, where it'd just forward the monotonic clock,
confusing any client using _NET_WM_FRAME_DRAWN and friends.
Fix this by 1) splitting the timestamp conversiot into an X11 case and a
display server case, where the display server case simply clamps the
monotonic clock, as it is assumed Xwayland is always usign the monotonic
clock, and 2) if we're a X11 compositing manager, if the X server is
using the monotonic clock, apply the same semantics as the display
server case and always just clamp, or if not, calculate the offset every
10 seconds, and offset the monotonic clock timestamp with the calculated
X server timestamp offset.
This fixes an issue that would occur if mutter (or rather GNOME Shell)
would have been started before a X11 timestamp overflow, after the
overflow happened. In this case, GTK3 clients would get unclamped
timestamps, and get very confused, resulting in frames queued several
weeks into the future.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1494
2020-07-08 14:53:14 +00:00
|
|
|
static void
|
|
|
|
determine_server_clock_source (MetaCompositorX11 *compositor_x11)
|
|
|
|
{
|
|
|
|
MetaCompositor *compositor = META_COMPOSITOR (compositor_x11);
|
|
|
|
MetaDisplay *display = meta_compositor_get_display (compositor);
|
|
|
|
MetaX11Display *x11_display = display->x11_display;
|
|
|
|
uint32_t server_time_ms;
|
|
|
|
int64_t server_time_us;
|
|
|
|
int64_t translated_monotonic_now_us;
|
|
|
|
|
|
|
|
server_time_ms = meta_x11_display_get_current_time_roundtrip (x11_display);
|
|
|
|
server_time_us = ms2us (server_time_ms);
|
|
|
|
translated_monotonic_now_us =
|
|
|
|
meta_translate_to_high_res_xserver_time (g_get_monotonic_time ());
|
|
|
|
|
|
|
|
/* If the server time offset is within a second of the monotonic time, we
|
|
|
|
* assume that they are identical. This seems like a big margin, but we want
|
|
|
|
* to be as robust as possible even if the system is under load and our
|
|
|
|
* processing of the server response is delayed.
|
|
|
|
*/
|
|
|
|
if (ABS (server_time_us - translated_monotonic_now_us) < s2us (1))
|
|
|
|
compositor_x11->xserver_uses_monotonic_clock = TRUE;
|
|
|
|
else
|
|
|
|
compositor_x11->xserver_uses_monotonic_clock = FALSE;
|
|
|
|
}
|
|
|
|
|
2020-03-03 08:27:33 +00:00
|
|
|
static gboolean
|
|
|
|
meta_compositor_x11_manage (MetaCompositor *compositor,
|
|
|
|
GError **error)
|
2019-08-14 21:25:54 +00:00
|
|
|
{
|
|
|
|
MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor);
|
|
|
|
MetaDisplay *display = meta_compositor_get_display (compositor);
|
2022-05-27 20:17:13 +00:00
|
|
|
MetaContext *context = meta_display_get_context (display);
|
|
|
|
MetaBackend *backend = meta_context_get_backend (context);
|
2020-03-03 08:27:33 +00:00
|
|
|
MetaX11Display *x11_display = display->x11_display;
|
|
|
|
Display *xdisplay = meta_x11_display_get_xdisplay (x11_display);
|
|
|
|
int composite_version;
|
2019-08-14 21:25:54 +00:00
|
|
|
Window xwindow;
|
|
|
|
|
2020-03-03 08:27:33 +00:00
|
|
|
if (!META_X11_DISPLAY_HAS_COMPOSITE (x11_display) ||
|
|
|
|
!META_X11_DISPLAY_HAS_DAMAGE (x11_display))
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Missing required extension %s",
|
|
|
|
!META_X11_DISPLAY_HAS_COMPOSITE (x11_display) ?
|
|
|
|
"composite" : "damage");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
composite_version = ((x11_display->composite_major_version * 10) +
|
|
|
|
x11_display->composite_minor_version);
|
|
|
|
if (composite_version < 3)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"COMPOSITE extension 3.0 required (found %d.%d)",
|
|
|
|
x11_display->composite_major_version,
|
|
|
|
x11_display->composite_minor_version);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
compositor: Make sure _NET_WM_FRAME_DRAWN timestamp has the right scope
The timestamp sent with _NET_WM_FRAME_DRAWN should be in "high
resolution X server timestamps", meaning they should have the same scope
as the built in X11 32 bit unsigned integer timestamps, i.e. overflow at
the same time.
This was not done correctly when mutter had determined the X server used
the monotonic clock, where it'd just forward the monotonic clock,
confusing any client using _NET_WM_FRAME_DRAWN and friends.
Fix this by 1) splitting the timestamp conversiot into an X11 case and a
display server case, where the display server case simply clamps the
monotonic clock, as it is assumed Xwayland is always usign the monotonic
clock, and 2) if we're a X11 compositing manager, if the X server is
using the monotonic clock, apply the same semantics as the display
server case and always just clamp, or if not, calculate the offset every
10 seconds, and offset the monotonic clock timestamp with the calculated
X server timestamp offset.
This fixes an issue that would occur if mutter (or rather GNOME Shell)
would have been started before a X11 timestamp overflow, after the
overflow happened. In this case, GTK3 clients would get unclamped
timestamps, and get very confused, resulting in frames queued several
weeks into the future.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1494
2020-07-08 14:53:14 +00:00
|
|
|
determine_server_clock_source (compositor_x11);
|
|
|
|
|
2019-08-14 21:25:54 +00:00
|
|
|
compositor_x11->output = display->x11_display->composite_overlay_window;
|
|
|
|
|
|
|
|
xwindow = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend));
|
|
|
|
|
|
|
|
XReparentWindow (xdisplay, xwindow, compositor_x11->output, 0, 0);
|
|
|
|
|
2019-08-16 14:23:08 +00:00
|
|
|
meta_x11_display_clear_stage_input_region (display->x11_display);
|
2019-08-14 21:25:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure there isn't any left-over output shape on the overlay window by
|
|
|
|
* setting the whole screen to be an output region.
|
|
|
|
*
|
|
|
|
* Note: there doesn't seem to be any real chance of that because the X
|
|
|
|
* server will destroy the overlay window when the last client using it
|
|
|
|
* exits.
|
|
|
|
*/
|
|
|
|
XFixesSetWindowShapeRegion (xdisplay, compositor_x11->output,
|
|
|
|
ShapeBounding, 0, 0, None);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Map overlay window before redirecting windows offscreen so we catch their
|
|
|
|
* contents until we show the stage.
|
|
|
|
*/
|
|
|
|
XMapWindow (xdisplay, compositor_x11->output);
|
|
|
|
|
|
|
|
compositor_x11->have_x11_sync_object = meta_sync_ring_init (xdisplay);
|
2020-02-28 17:59:39 +00:00
|
|
|
|
2020-03-03 08:27:33 +00:00
|
|
|
return TRUE;
|
2019-08-14 21:25:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_compositor_x11_unmanage (MetaCompositor *compositor)
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_compositor_get_display (compositor);
|
2023-05-29 12:12:19 +00:00
|
|
|
MetaContext *context = meta_display_get_context (display);
|
|
|
|
MetaBackend *backend = meta_context_get_backend (context);
|
2019-08-14 21:25:54 +00:00
|
|
|
MetaX11Display *x11_display = display->x11_display;
|
|
|
|
Display *xdisplay = x11_display->xdisplay;
|
|
|
|
Window xroot = x11_display->xroot;
|
2023-05-29 12:12:19 +00:00
|
|
|
Window backend_xwindow;
|
2022-01-28 23:15:28 +00:00
|
|
|
MetaCompositorClass *parent_class;
|
2019-08-14 21:25:54 +00:00
|
|
|
|
2023-05-29 12:12:19 +00:00
|
|
|
backend_xwindow = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend));
|
|
|
|
XReparentWindow (xdisplay, backend_xwindow, xroot, 0, 0);
|
|
|
|
|
2019-08-14 21:25:54 +00:00
|
|
|
/*
|
|
|
|
* This is the most important part of cleanup - we have to do this before
|
|
|
|
* giving up the window manager selection or the next window manager won't be
|
|
|
|
* able to redirect subwindows
|
|
|
|
*/
|
|
|
|
XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
|
2022-01-28 23:15:28 +00:00
|
|
|
|
|
|
|
parent_class = META_COMPOSITOR_CLASS (meta_compositor_x11_parent_class);
|
|
|
|
parent_class->unmanage (compositor);
|
2019-08-14 21:25:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sets an bounding shape on the COW so that the given window
|
|
|
|
* is exposed. If window is %NULL it clears the shape again.
|
|
|
|
*
|
|
|
|
* Used so we can unredirect windows, by shaping away the part
|
|
|
|
* of the COW, letting the raw window be seen through below.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
shape_cow_for_window (MetaCompositorX11 *compositor_x11,
|
|
|
|
MetaWindow *window)
|
|
|
|
{
|
|
|
|
MetaCompositor *compositor = META_COMPOSITOR (compositor_x11);
|
|
|
|
MetaDisplay *display = meta_compositor_get_display (compositor);
|
|
|
|
Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
|
|
|
|
|
|
|
|
if (!window)
|
|
|
|
{
|
|
|
|
XFixesSetWindowShapeRegion (xdisplay, compositor_x11->output,
|
|
|
|
ShapeBounding, 0, 0, None);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
XserverRegion output_region;
|
|
|
|
XRectangle screen_rect, window_bounds;
|
|
|
|
int width, height;
|
2023-07-19 23:46:15 +00:00
|
|
|
MtkRectangle rect;
|
2019-08-14 21:25:54 +00:00
|
|
|
|
|
|
|
meta_window_get_frame_rect (window, &rect);
|
|
|
|
|
|
|
|
window_bounds.x = rect.x;
|
|
|
|
window_bounds.y = rect.y;
|
|
|
|
window_bounds.width = rect.width;
|
|
|
|
window_bounds.height = rect.height;
|
|
|
|
|
|
|
|
meta_display_get_size (display, &width, &height);
|
|
|
|
screen_rect.x = 0;
|
|
|
|
screen_rect.y = 0;
|
|
|
|
screen_rect.width = width;
|
|
|
|
screen_rect.height = height;
|
|
|
|
|
|
|
|
output_region = XFixesCreateRegion (xdisplay, &window_bounds, 1);
|
|
|
|
|
|
|
|
XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region);
|
|
|
|
XFixesSetWindowShapeRegion (xdisplay, compositor_x11->output,
|
|
|
|
ShapeBounding, 0, 0, output_region);
|
|
|
|
XFixesDestroyRegion (xdisplay, output_region);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
set_unredirected_window (MetaCompositorX11 *compositor_x11,
|
|
|
|
MetaWindow *window)
|
|
|
|
{
|
|
|
|
MetaWindow *prev_unredirected_window = compositor_x11->unredirected_window;
|
|
|
|
|
|
|
|
if (prev_unredirected_window == window)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (prev_unredirected_window)
|
|
|
|
{
|
|
|
|
MetaWindowActor *window_actor;
|
2019-08-17 08:00:46 +00:00
|
|
|
MetaWindowActorX11 *window_actor_x11;
|
2019-08-14 21:25:54 +00:00
|
|
|
|
|
|
|
window_actor = meta_window_actor_from_window (prev_unredirected_window);
|
2019-08-17 08:00:46 +00:00
|
|
|
window_actor_x11 = META_WINDOW_ACTOR_X11 (window_actor);
|
|
|
|
meta_window_actor_x11_set_unredirected (window_actor_x11, FALSE);
|
2019-08-14 21:25:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
shape_cow_for_window (compositor_x11, window);
|
|
|
|
compositor_x11->unredirected_window = window;
|
|
|
|
|
|
|
|
if (window)
|
|
|
|
{
|
|
|
|
MetaWindowActor *window_actor;
|
2019-08-17 08:00:46 +00:00
|
|
|
MetaWindowActorX11 *window_actor_x11;
|
2019-08-14 21:25:54 +00:00
|
|
|
|
|
|
|
window_actor = meta_window_actor_from_window (window);
|
2019-08-17 08:00:46 +00:00
|
|
|
window_actor_x11 = META_WINDOW_ACTOR_X11 (window_actor);
|
|
|
|
meta_window_actor_x11_set_unredirected (window_actor_x11, TRUE);
|
2019-08-14 21:25:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-17 07:46:55 +00:00
|
|
|
static void
|
|
|
|
maybe_unredirect_top_window (MetaCompositorX11 *compositor_x11)
|
|
|
|
{
|
|
|
|
MetaCompositor *compositor = META_COMPOSITOR (compositor_x11);
|
|
|
|
MetaWindow *window_to_unredirect = NULL;
|
|
|
|
MetaWindowActor *window_actor;
|
2019-08-17 08:00:46 +00:00
|
|
|
MetaWindowActorX11 *window_actor_x11;
|
2019-08-17 07:46:55 +00:00
|
|
|
|
|
|
|
if (meta_compositor_is_unredirect_inhibited (compositor))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
window_actor = meta_compositor_get_top_window_actor (compositor);
|
|
|
|
if (!window_actor)
|
|
|
|
goto out;
|
|
|
|
|
2019-08-17 08:00:46 +00:00
|
|
|
window_actor_x11 = META_WINDOW_ACTOR_X11 (window_actor);
|
|
|
|
if (!meta_window_actor_x11_should_unredirect (window_actor_x11))
|
2019-08-17 07:46:55 +00:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
window_to_unredirect = meta_window_actor_get_meta_window (window_actor);
|
|
|
|
|
|
|
|
out:
|
|
|
|
set_unredirected_window (compositor_x11, window_to_unredirect);
|
|
|
|
}
|
|
|
|
|
2019-08-14 21:25:54 +00:00
|
|
|
static void
|
clutter: Paint views with individual frame clocks
Replace the default master clock with multiple frame clocks, each
driving its own stage view. As each stage view represents one CRTC, this
means we draw each CRTC with its own designated frame clock,
disconnected from all the others.
For example this means we when using the native backend will never need
to wait for one monitor to vsync before painting another, so e.g. having
a 144 Hz monitor next to a 60 Hz monitor, things including both Wayland
and X11 applications and shell UI will be able to render at the
corresponding monitor refresh rate.
This also changes a warning about missed frames when sending
_NETWM_FRAME_TIMINGS messages to a debug log entry, as it's expected
that we'll start missing frames e.g. when a X11 window (via Xwayland) is
exclusively within a stage view that was not painted, while another one
was, still increasing the global frame clock.
Addititonally, this also requires the X11 window actor to schedule
timeouts for _NET_WM_FRAME_DRAWN/_NET_WM_FRAME_TIMINGS event emitting,
if the actor wasn't on any stage views, as now we'll only get the frame
callbacks on actors when they actually were painted, while in the past,
we'd invoke that vfunc when anything was painted.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/903
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1285
2020-05-29 22:27:56 +00:00
|
|
|
on_before_update (ClutterStage *stage,
|
|
|
|
ClutterStageView *stage_view,
|
2022-10-13 15:50:34 +00:00
|
|
|
ClutterFrame *frame,
|
clutter: Paint views with individual frame clocks
Replace the default master clock with multiple frame clocks, each
driving its own stage view. As each stage view represents one CRTC, this
means we draw each CRTC with its own designated frame clock,
disconnected from all the others.
For example this means we when using the native backend will never need
to wait for one monitor to vsync before painting another, so e.g. having
a 144 Hz monitor next to a 60 Hz monitor, things including both Wayland
and X11 applications and shell UI will be able to render at the
corresponding monitor refresh rate.
This also changes a warning about missed frames when sending
_NETWM_FRAME_TIMINGS messages to a debug log entry, as it's expected
that we'll start missing frames e.g. when a X11 window (via Xwayland) is
exclusively within a stage view that was not painted, while another one
was, still increasing the global frame clock.
Addititonally, this also requires the X11 window actor to schedule
timeouts for _NET_WM_FRAME_DRAWN/_NET_WM_FRAME_TIMINGS event emitting,
if the actor wasn't on any stage views, as now we'll only get the frame
callbacks on actors when they actually were painted, while in the past,
we'd invoke that vfunc when anything was painted.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/903
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1285
2020-05-29 22:27:56 +00:00
|
|
|
MetaCompositor *compositor)
|
2019-08-14 21:25:54 +00:00
|
|
|
{
|
|
|
|
MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor);
|
|
|
|
|
|
|
|
if (compositor_x11->frame_has_updated_xsurfaces)
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_compositor_get_display (compositor);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We need to make sure that any X drawing that happens before the
|
|
|
|
* XDamageSubtract() for each window above is visible to subsequent GL
|
|
|
|
* rendering; the standardized way to do this is GL_EXT_X11_sync_object.
|
|
|
|
* Since this isn't implemented yet in mesa, we also have a path that
|
|
|
|
* relies on the implementation of the open source drivers.
|
|
|
|
*
|
|
|
|
* Anything else, we just hope for the best.
|
|
|
|
*
|
|
|
|
* Xorg and open source driver specifics:
|
|
|
|
*
|
|
|
|
* The X server makes sure to flush drawing to the kernel before sending
|
|
|
|
* out damage events, but since we use DamageReportBoundingBox there may
|
|
|
|
* be drawing between the last damage event and the XDamageSubtract()
|
|
|
|
* that needs to be flushed as well.
|
|
|
|
*
|
|
|
|
* Xorg always makes sure that drawing is flushed to the kernel before
|
|
|
|
* writing events or responses to the client, so any round trip request
|
|
|
|
* at this point is sufficient to flush the GLX buffers.
|
|
|
|
*/
|
|
|
|
if (compositor_x11->have_x11_sync_object)
|
|
|
|
compositor_x11->have_x11_sync_object = meta_sync_ring_insert_wait ();
|
|
|
|
else
|
|
|
|
XSync (display->x11_display->xdisplay, False);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-29 21:47:29 +00:00
|
|
|
static void
|
2021-03-04 18:11:12 +00:00
|
|
|
on_after_update (ClutterStage *stage,
|
|
|
|
ClutterStageView *stage_view,
|
2022-10-13 15:50:34 +00:00
|
|
|
ClutterFrame *frame,
|
2021-03-04 18:11:12 +00:00
|
|
|
MetaCompositor *compositor)
|
2020-05-29 21:47:29 +00:00
|
|
|
{
|
|
|
|
MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor);
|
|
|
|
|
2021-03-04 18:11:12 +00:00
|
|
|
if (compositor_x11->frame_has_updated_xsurfaces)
|
|
|
|
{
|
|
|
|
if (compositor_x11->have_x11_sync_object)
|
|
|
|
compositor_x11->have_x11_sync_object = meta_sync_ring_after_frame ();
|
2020-05-29 21:47:29 +00:00
|
|
|
|
2021-03-04 18:11:12 +00:00
|
|
|
compositor_x11->frame_has_updated_xsurfaces = FALSE;
|
|
|
|
}
|
2020-05-29 21:47:29 +00:00
|
|
|
}
|
|
|
|
|
2019-08-14 21:25:54 +00:00
|
|
|
static void
|
compositor: Expose the MetaCompositorView in before_paint () vfunc
The idea is that the state of the MetaCompositorView shall be
up-to-date only in specific scenarios, thus allowing operations
performed on it to be queued and aggregated to be handled in the
right time, and only if they are still necessary.
For example, in a following commit, the top window actor in each
view will be planned (if needed) only once before painting a frame,
rendering the top window actor in the MetaCompositorView potentially
stale in all other times.
Similarly, if a MetaCompositorView is destroyed before the beginning
of the frame, a queued operation to update its top window actor can be
discarded.
As an interface segragation measure, and as part of an attempt to
avoid the use of g_return_if_fail () to check the validity of the
MetaCompositorView's state in multiple places (which is still prone to
human error), the interfaces through which a MetaCompositorView is
made available would only ones where it's state is gurenteed to be
up-to-date.
Specifically, this commit gurentees that the state of the
MetaCompositorView would be up-to-date during the before_paint () and
after_paint () vfuncs exposed to child classes of the MetaCompositor.
The frame_in_progress variable will be used in a following commit to
guarantee that the MetaCompositorView's state is not invalidated during
this time.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2526>
2022-07-11 09:23:24 +00:00
|
|
|
meta_compositor_x11_before_paint (MetaCompositor *compositor,
|
|
|
|
MetaCompositorView *compositor_view)
|
2019-08-14 21:25:54 +00:00
|
|
|
{
|
|
|
|
MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor);
|
|
|
|
MetaCompositorClass *parent_class;
|
|
|
|
|
2021-03-04 18:11:12 +00:00
|
|
|
maybe_unredirect_top_window (compositor_x11);
|
2019-08-14 21:25:54 +00:00
|
|
|
|
|
|
|
parent_class = META_COMPOSITOR_CLASS (meta_compositor_x11_parent_class);
|
compositor: Expose the MetaCompositorView in before_paint () vfunc
The idea is that the state of the MetaCompositorView shall be
up-to-date only in specific scenarios, thus allowing operations
performed on it to be queued and aggregated to be handled in the
right time, and only if they are still necessary.
For example, in a following commit, the top window actor in each
view will be planned (if needed) only once before painting a frame,
rendering the top window actor in the MetaCompositorView potentially
stale in all other times.
Similarly, if a MetaCompositorView is destroyed before the beginning
of the frame, a queued operation to update its top window actor can be
discarded.
As an interface segragation measure, and as part of an attempt to
avoid the use of g_return_if_fail () to check the validity of the
MetaCompositorView's state in multiple places (which is still prone to
human error), the interfaces through which a MetaCompositorView is
made available would only ones where it's state is gurenteed to be
up-to-date.
Specifically, this commit gurentees that the state of the
MetaCompositorView would be up-to-date during the before_paint () and
after_paint () vfuncs exposed to child classes of the MetaCompositor.
The frame_in_progress variable will be used in a following commit to
guarantee that the MetaCompositorView's state is not invalidated during
this time.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2526>
2022-07-11 09:23:24 +00:00
|
|
|
parent_class->before_paint (compositor, compositor_view);
|
2019-08-14 21:25:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_compositor_x11_remove_window (MetaCompositor *compositor,
|
|
|
|
MetaWindow *window)
|
|
|
|
{
|
|
|
|
MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor);
|
|
|
|
MetaCompositorClass *parent_class;
|
|
|
|
|
|
|
|
if (compositor_x11->unredirected_window == window)
|
|
|
|
set_unredirected_window (compositor_x11, NULL);
|
|
|
|
|
|
|
|
parent_class = META_COMPOSITOR_CLASS (meta_compositor_x11_parent_class);
|
|
|
|
parent_class->remove_window (compositor, window);
|
|
|
|
}
|
|
|
|
|
compositor: Make sure _NET_WM_FRAME_DRAWN timestamp has the right scope
The timestamp sent with _NET_WM_FRAME_DRAWN should be in "high
resolution X server timestamps", meaning they should have the same scope
as the built in X11 32 bit unsigned integer timestamps, i.e. overflow at
the same time.
This was not done correctly when mutter had determined the X server used
the monotonic clock, where it'd just forward the monotonic clock,
confusing any client using _NET_WM_FRAME_DRAWN and friends.
Fix this by 1) splitting the timestamp conversiot into an X11 case and a
display server case, where the display server case simply clamps the
monotonic clock, as it is assumed Xwayland is always usign the monotonic
clock, and 2) if we're a X11 compositing manager, if the X server is
using the monotonic clock, apply the same semantics as the display
server case and always just clamp, or if not, calculate the offset every
10 seconds, and offset the monotonic clock timestamp with the calculated
X server timestamp offset.
This fixes an issue that would occur if mutter (or rather GNOME Shell)
would have been started before a X11 timestamp overflow, after the
overflow happened. In this case, GTK3 clients would get unclamped
timestamps, and get very confused, resulting in frames queued several
weeks into the future.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1494
2020-07-08 14:53:14 +00:00
|
|
|
static int64_t
|
|
|
|
meta_compositor_x11_monotonic_to_high_res_xserver_time (MetaCompositor *compositor,
|
|
|
|
int64_t monotonic_time_us)
|
|
|
|
{
|
|
|
|
MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor);
|
|
|
|
int64_t now_us;
|
|
|
|
|
|
|
|
if (compositor_x11->xserver_uses_monotonic_clock)
|
|
|
|
return meta_translate_to_high_res_xserver_time (monotonic_time_us);
|
|
|
|
|
|
|
|
now_us = g_get_monotonic_time ();
|
|
|
|
|
|
|
|
if (compositor_x11->xserver_time_query_time_us == 0 ||
|
|
|
|
now_us > (compositor_x11->xserver_time_query_time_us + s2us (10)))
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_compositor_get_display (compositor);
|
|
|
|
MetaX11Display *x11_display = display->x11_display;
|
|
|
|
uint32_t xserver_time_ms;
|
|
|
|
int64_t xserver_time_us;
|
|
|
|
|
|
|
|
compositor_x11->xserver_time_query_time_us = now_us;
|
|
|
|
|
|
|
|
xserver_time_ms =
|
|
|
|
meta_x11_display_get_current_time_roundtrip (x11_display);
|
|
|
|
xserver_time_us = ms2us (xserver_time_ms);
|
|
|
|
compositor_x11->xserver_time_offset_us = xserver_time_us - now_us;
|
|
|
|
}
|
|
|
|
|
|
|
|
return monotonic_time_us + compositor_x11->xserver_time_offset_us;
|
|
|
|
}
|
|
|
|
|
2021-02-13 11:48:31 +00:00
|
|
|
static void
|
|
|
|
meta_compositor_x11_grab_begin (MetaCompositor *compositor)
|
|
|
|
{
|
2022-05-27 20:17:13 +00:00
|
|
|
MetaDisplay *display = meta_compositor_get_display (compositor);
|
|
|
|
MetaContext *context = meta_display_get_context (display);
|
|
|
|
MetaBackend *backend = meta_context_get_backend (context);
|
|
|
|
MetaBackendX11 *backend_x11 = META_BACKEND_X11 (backend);
|
2020-12-18 13:59:17 +00:00
|
|
|
|
|
|
|
meta_backend_x11_sync_pointer (backend_x11);
|
2021-02-13 11:48:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_compositor_x11_grab_end (MetaCompositor *compositor)
|
|
|
|
{
|
2022-05-27 20:17:13 +00:00
|
|
|
MetaDisplay *display = meta_compositor_get_display (compositor);
|
|
|
|
MetaContext *context = meta_display_get_context (display);
|
|
|
|
MetaBackend *backend = meta_context_get_backend (context);
|
|
|
|
MetaBackendX11 *backend_x11 = META_BACKEND_X11 (backend);
|
2020-12-18 13:59:17 +00:00
|
|
|
|
|
|
|
meta_backend_x11_sync_pointer (backend_x11);
|
2021-02-13 11:48:31 +00:00
|
|
|
}
|
|
|
|
|
2022-07-15 09:06:12 +00:00
|
|
|
static MetaCompositorView *
|
|
|
|
meta_compositor_x11_create_view (MetaCompositor *compositor,
|
|
|
|
ClutterStageView *stage_view)
|
|
|
|
{
|
|
|
|
return meta_compositor_view_new (stage_view);
|
|
|
|
}
|
|
|
|
|
2019-08-14 21:25:54 +00:00
|
|
|
Window
|
|
|
|
meta_compositor_x11_get_output_xwindow (MetaCompositorX11 *compositor_x11)
|
|
|
|
{
|
|
|
|
return compositor_x11->output;
|
|
|
|
}
|
|
|
|
|
2019-08-19 08:24:17 +00:00
|
|
|
MetaCompositorX11 *
|
2020-04-16 17:14:21 +00:00
|
|
|
meta_compositor_x11_new (MetaDisplay *display,
|
|
|
|
MetaBackend *backend)
|
2019-08-19 08:24:17 +00:00
|
|
|
{
|
|
|
|
return g_object_new (META_TYPE_COMPOSITOR_X11,
|
|
|
|
"display", display,
|
2020-04-16 17:14:21 +00:00
|
|
|
"backend", backend,
|
2019-08-19 08:24:17 +00:00
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2020-05-29 21:47:29 +00:00
|
|
|
static void
|
|
|
|
meta_compositor_x11_constructed (GObject *object)
|
|
|
|
{
|
|
|
|
MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (object);
|
|
|
|
MetaCompositor *compositor = META_COMPOSITOR (compositor_x11);
|
|
|
|
ClutterStage *stage = meta_compositor_get_stage (compositor);
|
|
|
|
|
|
|
|
compositor_x11->before_update_handler_id =
|
|
|
|
g_signal_connect (stage, "before-update",
|
|
|
|
G_CALLBACK (on_before_update), compositor);
|
2021-03-04 18:11:12 +00:00
|
|
|
compositor_x11->after_update_handler_id =
|
|
|
|
g_signal_connect (stage, "after-update",
|
|
|
|
G_CALLBACK (on_after_update), compositor);
|
2020-05-29 21:47:29 +00:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (meta_compositor_x11_parent_class)->constructed (object);
|
|
|
|
}
|
|
|
|
|
2019-08-14 21:25:54 +00:00
|
|
|
static void
|
|
|
|
meta_compositor_x11_dispose (GObject *object)
|
|
|
|
{
|
|
|
|
MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (object);
|
2020-05-29 21:47:29 +00:00
|
|
|
MetaCompositor *compositor = META_COMPOSITOR (compositor_x11);
|
|
|
|
ClutterStage *stage = meta_compositor_get_stage (compositor);
|
2019-08-14 21:25:54 +00:00
|
|
|
|
|
|
|
if (compositor_x11->have_x11_sync_object)
|
|
|
|
{
|
|
|
|
meta_sync_ring_destroy ();
|
|
|
|
compositor_x11->have_x11_sync_object = FALSE;
|
|
|
|
}
|
|
|
|
|
2020-05-29 21:47:29 +00:00
|
|
|
g_clear_signal_handler (&compositor_x11->before_update_handler_id, stage);
|
2021-03-04 18:11:12 +00:00
|
|
|
g_clear_signal_handler (&compositor_x11->after_update_handler_id, stage);
|
2020-05-29 21:47:29 +00:00
|
|
|
|
2019-08-14 21:25:54 +00:00
|
|
|
G_OBJECT_CLASS (meta_compositor_x11_parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_compositor_x11_init (MetaCompositorX11 *compositor_x11)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_compositor_x11_class_init (MetaCompositorX11Class *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
MetaCompositorClass *compositor_class = META_COMPOSITOR_CLASS (klass);
|
|
|
|
|
2020-05-29 21:47:29 +00:00
|
|
|
object_class->constructed = meta_compositor_x11_constructed;
|
2019-08-14 21:25:54 +00:00
|
|
|
object_class->dispose = meta_compositor_x11_dispose;
|
|
|
|
|
|
|
|
compositor_class->manage = meta_compositor_x11_manage;
|
|
|
|
compositor_class->unmanage = meta_compositor_x11_unmanage;
|
2020-05-29 22:02:42 +00:00
|
|
|
compositor_class->before_paint = meta_compositor_x11_before_paint;
|
2019-08-14 21:25:54 +00:00
|
|
|
compositor_class->remove_window = meta_compositor_x11_remove_window;
|
compositor: Make sure _NET_WM_FRAME_DRAWN timestamp has the right scope
The timestamp sent with _NET_WM_FRAME_DRAWN should be in "high
resolution X server timestamps", meaning they should have the same scope
as the built in X11 32 bit unsigned integer timestamps, i.e. overflow at
the same time.
This was not done correctly when mutter had determined the X server used
the monotonic clock, where it'd just forward the monotonic clock,
confusing any client using _NET_WM_FRAME_DRAWN and friends.
Fix this by 1) splitting the timestamp conversiot into an X11 case and a
display server case, where the display server case simply clamps the
monotonic clock, as it is assumed Xwayland is always usign the monotonic
clock, and 2) if we're a X11 compositing manager, if the X server is
using the monotonic clock, apply the same semantics as the display
server case and always just clamp, or if not, calculate the offset every
10 seconds, and offset the monotonic clock timestamp with the calculated
X server timestamp offset.
This fixes an issue that would occur if mutter (or rather GNOME Shell)
would have been started before a X11 timestamp overflow, after the
overflow happened. In this case, GTK3 clients would get unclamped
timestamps, and get very confused, resulting in frames queued several
weeks into the future.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1494
2020-07-08 14:53:14 +00:00
|
|
|
compositor_class->monotonic_to_high_res_xserver_time =
|
|
|
|
meta_compositor_x11_monotonic_to_high_res_xserver_time;
|
2021-02-13 11:48:31 +00:00
|
|
|
compositor_class->grab_begin = meta_compositor_x11_grab_begin;
|
|
|
|
compositor_class->grab_end = meta_compositor_x11_grab_end;
|
2022-07-15 09:06:12 +00:00
|
|
|
compositor_class->create_view = meta_compositor_x11_create_view;
|
2019-08-14 21:25:54 +00:00
|
|
|
}
|