From 4919a53f8409da7d6baf22287d788ab9ae10d235 Mon Sep 17 00:00:00 2001 From: Dor Askayo Date: Tue, 17 Mar 2020 01:44:25 +0200 Subject: [PATCH] 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: --- src/compositor/meta-compositor-native.c | 3 + src/compositor/meta-compositor-view-native.c | 252 ++++++++++++++++++- src/compositor/meta-compositor-view-native.h | 3 + 3 files changed, 257 insertions(+), 1 deletion(-) diff --git a/src/compositor/meta-compositor-native.c b/src/compositor/meta-compositor-native.c index d313793ba..b7525513f 100644 --- a/src/compositor/meta-compositor-native.c +++ b/src/compositor/meta-compositor-native.c @@ -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); } diff --git a/src/compositor/meta-compositor-view-native.c b/src/compositor/meta-compositor-view-native.c index 0d5a23cf9..223536a65 100644 --- a/src/compositor/meta-compositor-view-native.c +++ b/src/compositor/meta-compositor-view-native.c @@ -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; } diff --git a/src/compositor/meta-compositor-view-native.h b/src/compositor/meta-compositor-view-native.h index d93116267..52a2bef27 100644 --- a/src/compositor/meta-compositor-view-native.h +++ b/src/compositor/meta-compositor-view-native.h @@ -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);