mirror of
https://github.com/brl/mutter.git
synced 2024-11-22 16:10:41 -05:00
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:
parent
7eb99ddef7
commit
4919a53f84
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user