compositor/native: Enable frame synchronization for surface actors

Find a surface actor that meets the criteria to drive the refresh
rate for the view. If a new surface actor is found, add a
reference to it and request frame synchronization to be enabled
for the relevant MetaRendererViewNative.

Whenever the surface actor schedules a repaint or an update, and
in case frame synchronization is enabled for the
MetaRendererViewNative, schedule the update to occur "now". This
effectively makes the surface actor's frame rate drive the refresh
rate of the monitor.

If the actor is frozen or destroyed, it is no longer expected to
schedule repaints or updates and should stop driving the refresh
rate.

When there is no surface actor to drive the refresh rate, request
frame synchronization to be disabled for the MetaRendererViewNative.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1154>
This commit is contained in:
Dor Askayo 2020-03-17 01:44:25 +02:00 committed by Marge Bot
parent 7eb99ddef7
commit 4919a53f84
3 changed files with 257 additions and 1 deletions

View File

@ -43,6 +43,9 @@ meta_compositor_native_before_paint (MetaCompositor *compositor,
compositor);
#endif
meta_compositor_view_native_maybe_update_frame_sync_surface (compositor_view_native,
compositor);
parent_class = META_COMPOSITOR_CLASS (meta_compositor_native_parent_class);
parent_class->before_paint (compositor, compositor_view);
}

View File

@ -1,7 +1,8 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2022 Dor Askayo
* Copyright (C) 2022-2023 Dor Askayo
* Copyright (C) 2024 GNOME Foundation Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@ -26,14 +27,20 @@
#include "backends/meta-crtc.h"
#include "backends/native/meta-crtc-kms.h"
#include "backends/native/meta-onscreen-native.h"
#include "clutter/clutter.h"
#include "compositor/compositor-private.h"
#include "compositor/meta-window-actor-private.h"
#include "core/window-private.h"
#ifdef HAVE_WAYLAND
#include "compositor/meta-surface-actor-wayland.h"
#include "wayland/meta-wayland-surface-private.h"
#endif /* HAVE_WAYLAND */
static void update_frame_sync_surface (MetaCompositorViewNative *view_native,
MetaSurfaceActor *surface_actor);
struct _MetaCompositorViewNative
{
MetaCompositorView parent;
@ -41,11 +48,73 @@ struct _MetaCompositorViewNative
#ifdef HAVE_WAYLAND
MetaWaylandSurface *scanout_candidate;
#endif /* HAVE_WAYLAND */
MetaSurfaceActor *frame_sync_surface;
gulong frame_sync_surface_repaint_scheduled_id;
gulong frame_sync_surface_update_scheduled_id;
gulong frame_sync_surface_is_frozen_changed_id;
gulong frame_sync_surface_destroy_id;
};
G_DEFINE_TYPE (MetaCompositorViewNative, meta_compositor_view_native,
META_TYPE_COMPOSITOR_VIEW)
static void
maybe_schedule_update_now (MetaCompositorViewNative *view_native)
{
MetaCompositorView *compositor_view = META_COMPOSITOR_VIEW (view_native);
ClutterStageView *stage_view;
CoglFramebuffer *framebuffer;
stage_view = meta_compositor_view_get_stage_view (compositor_view);
framebuffer = clutter_stage_view_get_onscreen (stage_view);
if (!META_IS_ONSCREEN_NATIVE (framebuffer))
return;
if (meta_onscreen_native_is_frame_sync_enabled (META_ONSCREEN_NATIVE (framebuffer)))
{
ClutterFrameClock *frame_clock;
frame_clock = clutter_stage_view_get_frame_clock (stage_view);
if (!frame_clock)
return;
clutter_frame_clock_schedule_update_now (frame_clock);
}
}
static void
on_frame_sync_surface_repaint_scheduled (MetaSurfaceActor *surface_actor,
MetaCompositorViewNative *view_native)
{
maybe_schedule_update_now (view_native);
}
static void
on_frame_sync_surface_update_scheduled (MetaSurfaceActor *surface_actor,
MetaCompositorViewNative *view_native)
{
maybe_schedule_update_now (view_native);
}
static void
on_frame_sync_surface_is_frozen_changed (MetaSurfaceActor *surface_actor,
GParamSpec *pspec,
MetaCompositorViewNative *view_native)
{
if (meta_surface_actor_is_frozen (surface_actor))
update_frame_sync_surface (view_native, NULL);
}
static void
on_frame_sync_surface_destroyed (MetaSurfaceActor *surface_actor,
MetaCompositorViewNative *view_native)
{
update_frame_sync_surface (view_native, NULL);
}
#ifdef HAVE_WAYLAND
static void
update_scanout_candidate (MetaCompositorViewNative *view_native,
@ -287,6 +356,168 @@ meta_compositor_view_native_maybe_assign_scanout (MetaCompositorViewNative *view
}
#endif /* HAVE_WAYLAND */
static MetaSurfaceActor *
find_frame_sync_candidate (MetaCompositorView *compositor_view,
MetaCompositor *compositor)
{
MetaWindowActor *window_actor;
MetaWindow *window;
ClutterStageView *stage_view;
MtkRectangle view_layout;
MetaSurfaceActor *surface_actor;
if (meta_compositor_is_unredirect_inhibited (compositor))
{
meta_topic (META_DEBUG_RENDER,
"No frame sync candidate: unredirect inhibited");
return NULL;
}
window_actor =
meta_compositor_view_get_top_window_actor (compositor_view);
if (!window_actor)
{
meta_topic (META_DEBUG_RENDER,
"No frame sync candidate: no top window actor");
return NULL;
}
if (meta_window_actor_is_frozen (window_actor))
{
meta_topic (META_DEBUG_RENDER,
"No frame sync candidate: window-actor is frozen");
return NULL;
}
if (meta_window_actor_effect_in_progress (window_actor))
{
meta_topic (META_DEBUG_RENDER,
"No frame sync candidate: window-actor effects in progress");
return NULL;
}
if (clutter_actor_has_transitions (CLUTTER_ACTOR (window_actor)))
{
meta_topic (META_DEBUG_RENDER,
"No frame sync candidate: window-actor has transition");
return NULL;
}
window = meta_window_actor_get_meta_window (window_actor);
if (!window)
{
meta_topic (META_DEBUG_RENDER,
"No frame sync candidate: no meta-window");
return NULL;
}
stage_view = meta_compositor_view_get_stage_view (compositor_view);
clutter_stage_view_get_layout (stage_view, &view_layout);
if (!meta_window_geometry_contains_rect (window, &view_layout))
{
meta_topic (META_DEBUG_RENDER,
"No frame sync candidate: stage-view layout not covered "
"by meta-window frame");
return NULL;
}
surface_actor = meta_window_actor_get_scanout_candidate (window_actor);
if (!surface_actor)
{
meta_topic (META_DEBUG_RENDER,
"No frame sync candidate: window-actor has no scanout candidate");
return NULL;
}
if (meta_surface_actor_is_frozen (surface_actor))
{
meta_topic (META_DEBUG_RENDER,
"No frame sync candidate: surface-actor is frozen");
return NULL;
}
if (!meta_surface_actor_contains_rect (surface_actor,
&view_layout))
{
meta_topic (META_DEBUG_RENDER,
"No frame sync candidate: stage-view layout not covered "
"by surface-actor");
return NULL;
}
return surface_actor;
}
static void
update_frame_sync_surface (MetaCompositorViewNative *view_native,
MetaSurfaceActor *surface_actor)
{
MetaCompositorView *compositor_view =
META_COMPOSITOR_VIEW (view_native);
ClutterStageView *stage_view;
CoglFramebuffer *framebuffer;
g_clear_signal_handler (&view_native->frame_sync_surface_repaint_scheduled_id,
view_native->frame_sync_surface);
g_clear_signal_handler (&view_native->frame_sync_surface_update_scheduled_id,
view_native->frame_sync_surface);
g_clear_signal_handler (&view_native->frame_sync_surface_is_frozen_changed_id,
view_native->frame_sync_surface);
g_clear_signal_handler (&view_native->frame_sync_surface_destroy_id,
view_native->frame_sync_surface);
if (surface_actor)
{
view_native->frame_sync_surface_repaint_scheduled_id =
g_signal_connect (surface_actor, "repaint-scheduled",
G_CALLBACK (on_frame_sync_surface_repaint_scheduled),
view_native);
view_native->frame_sync_surface_update_scheduled_id =
g_signal_connect (surface_actor, "update-scheduled",
G_CALLBACK (on_frame_sync_surface_update_scheduled),
view_native);
view_native->frame_sync_surface_is_frozen_changed_id =
g_signal_connect (surface_actor,
"notify::is-frozen",
G_CALLBACK (on_frame_sync_surface_is_frozen_changed),
view_native);
view_native->frame_sync_surface_destroy_id =
g_signal_connect (surface_actor, "destroy",
G_CALLBACK (on_frame_sync_surface_destroyed),
view_native);
}
view_native->frame_sync_surface = surface_actor;
stage_view = meta_compositor_view_get_stage_view (compositor_view);
framebuffer = clutter_stage_view_get_onscreen (stage_view);
if (!META_IS_ONSCREEN_NATIVE (framebuffer))
return;
meta_onscreen_native_request_frame_sync (META_ONSCREEN_NATIVE (framebuffer),
surface_actor != NULL);
}
void
meta_compositor_view_native_maybe_update_frame_sync_surface (MetaCompositorViewNative *view_native,
MetaCompositor *compositor)
{
MetaCompositorView *compositor_view = META_COMPOSITOR_VIEW (view_native);
MetaSurfaceActor *surface_actor;
surface_actor = find_frame_sync_candidate (compositor_view,
compositor);
if (G_LIKELY (surface_actor == view_native->frame_sync_surface))
return;
update_frame_sync_surface (view_native,
surface_actor);
}
MetaCompositorViewNative *
meta_compositor_view_native_new (ClutterStageView *stage_view)
{
@ -297,6 +528,24 @@ meta_compositor_view_native_new (ClutterStageView *stage_view)
NULL);
}
static void
meta_compositor_view_native_dispose (GObject *object)
{
MetaCompositorViewNative *view_native = META_COMPOSITOR_VIEW_NATIVE (object);
g_clear_signal_handler (&view_native->frame_sync_surface_repaint_scheduled_id,
view_native->frame_sync_surface);
g_clear_signal_handler (&view_native->frame_sync_surface_update_scheduled_id,
view_native->frame_sync_surface);
g_clear_signal_handler (&view_native->frame_sync_surface_destroy_id,
view_native->frame_sync_surface);
g_clear_signal_handler (&view_native->frame_sync_surface_is_frozen_changed_id,
view_native->frame_sync_surface);
view_native->frame_sync_surface = NULL;
G_OBJECT_CLASS (meta_compositor_view_native_parent_class)->dispose (object);
}
static void
meta_compositor_view_native_finalize (GObject *object)
{
@ -314,6 +563,7 @@ meta_compositor_view_native_class_init (MetaCompositorViewNativeClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = meta_compositor_view_native_dispose;
object_class->finalize = meta_compositor_view_native_finalize;
}

View File

@ -36,3 +36,6 @@ MetaCompositorViewNative *meta_compositor_view_native_new (ClutterStageView *sta
void meta_compositor_view_native_maybe_assign_scanout (MetaCompositorViewNative *view_native,
MetaCompositor *compositor);
#endif /* HAVE_WAYLAND */
void meta_compositor_view_native_maybe_update_frame_sync_surface (MetaCompositorViewNative *view_native,
MetaCompositor *compositor);