diff --git a/clutter/clutter/clutter-main.c b/clutter/clutter/clutter-main.c index d052b1474..e78a33e2d 100644 --- a/clutter/clutter/clutter-main.c +++ b/clutter/clutter/clutter-main.c @@ -61,7 +61,6 @@ #include "clutter-input-pointer-a11y-private.h" #include "clutter-graphene.h" #include "clutter-main.h" -#include "clutter-master-clock.h" #include "clutter-mutter.h" #include "clutter-paint-node-private.h" #include "clutter-private.h" diff --git a/clutter/clutter/clutter-master-clock-default.c b/clutter/clutter/clutter-master-clock-default.c deleted file mode 100644 index 031838966..000000000 --- a/clutter/clutter/clutter-master-clock-default.c +++ /dev/null @@ -1,609 +0,0 @@ -/* - * Clutter. - * - * An OpenGL based 'interactive canvas' library. - * - * Authored By: Emmanuele Bassi - * - * Copyright (C) 2009 Intel Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - */ - -/* - * SECTION:clutter-master-clock-default - * @short_description: The default master clock for all animations - * - * The #ClutterMasterClockDefault class is the default implementation - * of #ClutterMasterClock. - */ - -#include "clutter-build-config.h" - -#include - -#include "clutter-master-clock.h" -#include "clutter-master-clock-default.h" -#include "clutter-debug.h" -#include "clutter-private.h" -#include "clutter-stage-manager-private.h" -#include "clutter-stage-private.h" -#include "clutter-timeline-private.h" - -#ifdef CLUTTER_ENABLE_DEBUG -#define clutter_warn_if_over_budget(master_clock,start_time,section) G_STMT_START { \ - gint64 __delta = g_get_monotonic_time () - start_time; \ - gint64 __budget = master_clock->remaining_budget; \ - if (__budget > 0 && __delta >= __budget) { \ - _clutter_diagnostic_message ("%s took %" G_GINT64_FORMAT " microseconds " \ - "more than the remaining budget of %" G_GINT64_FORMAT \ - " microseconds", \ - section, __delta - __budget, __budget); \ - } } G_STMT_END -#else -#define clutter_warn_if_over_budget(master_clock,start_time,section) -#endif - -typedef struct _ClutterClockSource ClutterClockSource; - -struct _ClutterMasterClockDefault -{ - GObject parent_instance; - - /* the list of timelines handled by the clock */ - GSList *timelines; - - /* the current state of the clock, in usecs */ - gint64 cur_tick; - -#ifdef CLUTTER_ENABLE_DEBUG - gint64 frame_budget; - gint64 remaining_budget; -#endif - - /* an idle source, used by the Master Clock to queue - * a redraw on the stage and drive the animations - */ - GSource *source; - - guint ensure_next_iteration : 1; - - guint paused : 1; -}; - -struct _ClutterClockSource -{ - GSource source; - - ClutterMasterClockDefault *master_clock; -}; - -static gboolean clutter_clock_prepare (GSource *source, - gint *timeout); -static gboolean clutter_clock_check (GSource *source); -static gboolean clutter_clock_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data); - -static GSourceFuncs clock_funcs = { - clutter_clock_prepare, - clutter_clock_check, - clutter_clock_dispatch, - NULL -}; - -static void -clutter_master_clock_iface_init (ClutterMasterClockInterface *iface); - -#define clutter_master_clock_default_get_type _clutter_master_clock_default_get_type - -G_DEFINE_TYPE_WITH_CODE (ClutterMasterClockDefault, - clutter_master_clock_default, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_MASTER_CLOCK, - clutter_master_clock_iface_init)); - -/* - * master_clock_is_running: - * @master_clock: a #ClutterMasterClock - * - * Checks if we should currently be advancing timelines or redrawing - * stages. - * - * Return value: %TRUE if the #ClutterMasterClock has at least - * one running timeline - */ -static gboolean -master_clock_is_running (ClutterMasterClockDefault *master_clock) -{ - ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); - const GSList *stages, *l; - - stages = clutter_stage_manager_peek_stages (stage_manager); - - if (master_clock->paused) - return FALSE; - - if (master_clock->timelines) - return TRUE; - - for (l = stages; l; l = l->next) - { - if (clutter_actor_is_mapped (l->data) && - (_clutter_stage_has_queued_events (l->data) || - _clutter_stage_needs_update (l->data))) - return TRUE; - } - - if (master_clock->ensure_next_iteration) - { - master_clock->ensure_next_iteration = FALSE; - return TRUE; - } - - return FALSE; -} - -static gint -master_clock_get_swap_wait_time (ClutterMasterClockDefault *master_clock) -{ - ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); - const GSList *stages, *l; - gint64 min_update_time = -1; - - stages = clutter_stage_manager_peek_stages (stage_manager); - - for (l = stages; l != NULL; l = l->next) - { - gint64 update_time = _clutter_stage_get_update_time (l->data); - if (min_update_time == -1 || - (update_time != -1 && update_time < min_update_time)) - min_update_time = update_time; - } - - if (min_update_time == -1) - { - return -1; - } - else - { - gint64 now = g_source_get_time (master_clock->source); - if (min_update_time < now) - { - return 0; - } - else - { - gint64 delay_us = min_update_time - now; - return (delay_us + 999) / 1000; - } - } -} - -static void -master_clock_schedule_stage_updates (ClutterMasterClockDefault *master_clock) -{ - ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); - const GSList *stages, *l; - - stages = clutter_stage_manager_peek_stages (stage_manager); - - for (l = stages; l != NULL; l = l->next) - clutter_stage_schedule_update (l->data); -} - -static GSList * -master_clock_list_ready_stages (ClutterMasterClockDefault *master_clock) -{ - ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); - const GSList *stages, *l; - GSList *result; - - stages = clutter_stage_manager_peek_stages (stage_manager); - - result = NULL; - for (l = stages; l != NULL; l = l->next) - { - gint64 update_time = _clutter_stage_get_update_time (l->data); - /* We carefully avoid to update stages that aren't mapped, because - * they have nothing to render and this could cause a deadlock with - * some of the SwapBuffers implementations (in particular - * GLX_INTEL_swap_event is not emitted if nothing was rendered). - * - * Also, if a stage has a swap-buffers pending we don't want to draw - * to it in case the driver may block the CPU while it waits for the - * next backbuffer to become available. - * - * TODO: We should be able to identify if we are running triple or N - * buffered and in these cases we can still draw if there is 1 swap - * pending so we can hopefully always be ready to swap for the next - * vblank and really match the vsync frequency. - */ - if (clutter_actor_is_mapped (l->data) && - update_time != -1 && update_time <= master_clock->cur_tick) - result = g_slist_prepend (result, g_object_ref (l->data)); - } - - return g_slist_reverse (result); -} - -static void -master_clock_reschedule_stage_updates (ClutterMasterClockDefault *master_clock, - GSList *stages) -{ - const GSList *l; - - for (l = stages; l != NULL; l = l->next) - { - /* Clear the old update time */ - _clutter_stage_clear_update_time (l->data); - - /* And if there is still work to be done, schedule a new one */ - if (master_clock->timelines || - _clutter_stage_has_queued_events (l->data) || - _clutter_stage_needs_update (l->data)) - clutter_stage_schedule_update (l->data); - } -} - -/* - * master_clock_next_frame_delay: - * @master_clock: a #ClutterMasterClock - * - * Computes the number of delay before we need to draw the next frame. - * - * Return value: -1 if there is no next frame pending, otherwise the - * number of millseconds before the we need to draw the next frame - */ -static gint -master_clock_next_frame_delay (ClutterMasterClockDefault *master_clock) -{ - if (!master_clock_is_running (master_clock)) - return -1; - - /* If all of the stages are busy waiting for a swap-buffers to complete - * then we wait for one to be ready.. */ - return master_clock_get_swap_wait_time (master_clock); -} - -static void -master_clock_process_events (ClutterMasterClockDefault *master_clock, - GSList *stages) -{ - GSList *l; -#ifdef CLUTTER_ENABLE_DEBUG - gint64 start = g_get_monotonic_time (); -#endif - - /* Process queued events */ - for (l = stages; l != NULL; l = l->next) - _clutter_stage_process_queued_events (l->data); - -#ifdef CLUTTER_ENABLE_DEBUG - if (_clutter_diagnostic_enabled ()) - clutter_warn_if_over_budget (master_clock, start, "Event processing"); - - master_clock->remaining_budget -= (g_get_monotonic_time () - start); -#endif -} - -/* - * master_clock_advance_timelines: - * @master_clock: a #ClutterMasterClock - * - * Advances all the timelines held by the master clock. This function - * should be called before calling _clutter_stage_do_update() to - * make sure that all the timelines are advanced and the scene is updated. - */ -static void -master_clock_advance_timelines (ClutterMasterClockDefault *master_clock) -{ - GSList *timelines, *l; -#ifdef CLUTTER_ENABLE_DEBUG - gint64 start = g_get_monotonic_time (); -#endif - - /* we protect ourselves from timelines being removed during - * the advancement by other timelines by copying the list of - * timelines, taking a reference on them, iterating over the - * copied list and then releasing the reference. - * - * we cannot simply take a reference on the timelines and still - * use the list held by the master clock because the do_tick() - * might result in the creation of a new timeline, which gets - * added at the end of the list with no reference increase and - * thus gets disposed at the end of the iteration. - * - * this implies that a newly added timeline will not be advanced - * by this clock iteration, which is perfectly fine since we're - * in its first cycle. - * - * we also cannot steal the master clock timelines list because - * a timeline might be removed as the direct result of do_tick() - * and remove_timeline() would not find the timeline, failing - * and leaving a dangling pointer behind. - */ - timelines = g_slist_copy (master_clock->timelines); - g_slist_foreach (timelines, (GFunc) g_object_ref, NULL); - - for (l = timelines; l != NULL; l = l->next) - _clutter_timeline_do_tick (l->data, master_clock->cur_tick / 1000); - - g_slist_free_full (timelines, g_object_unref); - -#ifdef CLUTTER_ENABLE_DEBUG - if (_clutter_diagnostic_enabled ()) - clutter_warn_if_over_budget (master_clock, start, "Animations"); - - master_clock->remaining_budget -= (g_get_monotonic_time () - start); -#endif -} - -static gboolean -master_clock_update_stages (ClutterMasterClockDefault *master_clock, - GSList *stages) -{ - gboolean stages_updated = FALSE; - GSList *l; -#ifdef CLUTTER_ENABLE_DEBUG - gint64 start = g_get_monotonic_time (); -#endif - - _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_PRE_PAINT); - - /* Update any stage that needs redraw/relayout after the clock - * is advanced. - */ - for (l = stages; l != NULL; l = l->next) - stages_updated |= _clutter_stage_do_update (l->data); - - _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_POST_PAINT); - -#ifdef CLUTTER_ENABLE_DEBUG - if (_clutter_diagnostic_enabled ()) - clutter_warn_if_over_budget (master_clock, start, "Updating the stage"); - - master_clock->remaining_budget -= (g_get_monotonic_time () - start); -#endif - - return stages_updated; -} - -/* - * clutter_clock_source_new: - * @master_clock: a #ClutterMasterClock for the source - * - * The #ClutterClockSource is an idle GSource that will queue a redraw - * if @master_clock has at least a running #ClutterTimeline. The redraw - * will cause @master_clock to advance all timelines, thus advancing all - * animations as well. - * - * Return value: the newly created #GSource - */ -static GSource * -clutter_clock_source_new (ClutterMasterClockDefault *master_clock) -{ - GSource *source = g_source_new (&clock_funcs, sizeof (ClutterClockSource)); - ClutterClockSource *clock_source = (ClutterClockSource *) source; - - g_source_set_name (source, "Clutter master clock"); - g_source_set_priority (source, CLUTTER_PRIORITY_REDRAW); - g_source_set_can_recurse (source, FALSE); - clock_source->master_clock = master_clock; - - return source; -} - -static gboolean -clutter_clock_prepare (GSource *source, - gint *timeout) -{ - ClutterClockSource *clock_source = (ClutterClockSource *) source; - ClutterMasterClockDefault *master_clock = clock_source->master_clock; - int delay; - - if (G_UNLIKELY (clutter_paint_debug_flags & - CLUTTER_DEBUG_CONTINUOUS_REDRAW)) - { - ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); - const GSList *stages, *l; - - stages = clutter_stage_manager_peek_stages (stage_manager); - - /* Queue a full redraw on all of the stages */ - for (l = stages; l != NULL; l = l->next) - clutter_actor_queue_redraw (l->data); - } - - delay = master_clock_next_frame_delay (master_clock); - - *timeout = delay; - - return delay == 0; -} - -static gboolean -clutter_clock_check (GSource *source) -{ - ClutterClockSource *clock_source = (ClutterClockSource *) source; - ClutterMasterClockDefault *master_clock = clock_source->master_clock; - int delay; - - delay = master_clock_next_frame_delay (master_clock); - - return delay == 0; -} - -static gboolean -clutter_clock_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data) -{ - ClutterClockSource *clock_source = (ClutterClockSource *) source; - ClutterMasterClockDefault *master_clock = clock_source->master_clock; - GSList *stages; - - CLUTTER_NOTE (SCHEDULER, "Master clock [tick]"); - - COGL_TRACE_BEGIN (ClutterMasterClockTick, "Master Clock (tick)"); - - /* Get the time to use for this frame */ - master_clock->cur_tick = g_source_get_time (source); - -#ifdef CLUTTER_ENABLE_DEBUG - master_clock->remaining_budget = master_clock->frame_budget; -#endif - - /* We need to protect ourselves against stages being destroyed during - * event handling - master_clock_list_ready_stages() returns a - * list of referenced that we'll unref afterwards. - */ - stages = master_clock_list_ready_stages (master_clock); - - /* Each frame is split into three separate phases: */ - - /* 1. process all the events; each stage goes through its events queue - * and processes each event according to its type, then emits the - * various signals that are associated with the event - */ - master_clock_process_events (master_clock, stages); - - /* 2. advance the timelines */ - master_clock_advance_timelines (master_clock); - - /* 3. relayout and redraw the stages */ - master_clock_update_stages (master_clock, stages); - - master_clock_reschedule_stage_updates (master_clock, stages); - - g_slist_free_full (stages, g_object_unref); - - COGL_TRACE_END (ClutterMasterClockTick); - - return TRUE; -} - -static void -clutter_master_clock_default_finalize (GObject *gobject) -{ - ClutterMasterClockDefault *master_clock = CLUTTER_MASTER_CLOCK_DEFAULT (gobject); - - g_slist_free (master_clock->timelines); - - G_OBJECT_CLASS (clutter_master_clock_default_parent_class)->finalize (gobject); -} - -static void -clutter_master_clock_default_class_init (ClutterMasterClockDefaultClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->finalize = clutter_master_clock_default_finalize; -} - -static void -clutter_master_clock_default_init (ClutterMasterClockDefault *self) -{ - GSource *source; - - source = clutter_clock_source_new (self); - self->source = source; - - self->ensure_next_iteration = FALSE; - self->paused = FALSE; - -#ifdef CLUTTER_ENABLE_DEBUG - self->frame_budget = G_USEC_PER_SEC / 60; -#endif - - g_source_attach (source, NULL); -} - -static void -clutter_master_clock_default_add_timeline (ClutterMasterClock *clock, - ClutterTimeline *timeline) -{ - ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock; - gboolean is_first; - - if (g_slist_find (master_clock->timelines, timeline)) - return; - - is_first = master_clock->timelines == NULL; - - master_clock->timelines = g_slist_prepend (master_clock->timelines, - timeline); - - if (is_first) - { - master_clock_schedule_stage_updates (master_clock); - _clutter_master_clock_start_running (clock); - } -} - -static void -clutter_master_clock_default_remove_timeline (ClutterMasterClock *clock, - ClutterTimeline *timeline) -{ - ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock; - - master_clock->timelines = g_slist_remove (master_clock->timelines, - timeline); -} - -static void -clutter_master_clock_default_start_running (ClutterMasterClock *master_clock) -{ - /* If called from a different thread, we need to wake up the - * main loop to start running the timelines - */ - g_main_context_wakeup (NULL); -} - -static void -clutter_master_clock_default_ensure_next_iteration (ClutterMasterClock *clock) -{ - ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock; - - master_clock->ensure_next_iteration = TRUE; -} - -static void -clutter_master_clock_default_set_paused (ClutterMasterClock *clock, - gboolean paused) -{ - ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock; - - if (paused && !master_clock->paused) - { - g_clear_pointer (&master_clock->source, g_source_destroy); - } - else if (!paused && master_clock->paused) - { - master_clock->source = clutter_clock_source_new (master_clock); - g_source_attach (master_clock->source, NULL); - } - - master_clock->paused = !!paused; -} - -static void -clutter_master_clock_iface_init (ClutterMasterClockInterface *iface) -{ - iface->add_timeline = clutter_master_clock_default_add_timeline; - iface->remove_timeline = clutter_master_clock_default_remove_timeline; - iface->start_running = clutter_master_clock_default_start_running; - iface->ensure_next_iteration = clutter_master_clock_default_ensure_next_iteration; - iface->set_paused = clutter_master_clock_default_set_paused; -} diff --git a/clutter/clutter/clutter-master-clock-default.h b/clutter/clutter/clutter-master-clock-default.h deleted file mode 100644 index 87dcf6c68..000000000 --- a/clutter/clutter/clutter-master-clock-default.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Clutter. - * - * An OpenGL based 'interactive canvas' library. - * - * Authored By: Lionel Landwerlin - * - * Copyright (C) 2015 Intel Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - */ - -#ifndef __CLUTTER_MASTER_CLOCK_DEFAULT_H__ -#define __CLUTTER_MASTER_CLOCK_DEFAULT_H__ - -#include - -G_BEGIN_DECLS - -#define CLUTTER_TYPE_MASTER_CLOCK_DEFAULT (_clutter_master_clock_default_get_type ()) -#define CLUTTER_MASTER_CLOCK_DEFAULT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_MASTER_CLOCK_DEFAULT, ClutterMasterClockDefault)) -#define CLUTTER_IS_MASTER_CLOCK_DEFAULT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_MASTER_CLOCK_DEFAULT)) -#define CLUTTER_MASTER_CLOCK_DEFAULT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_MASTER_CLOCK_DEFAULT, ClutterMasterClockDefaultClass)) - -typedef struct _ClutterMasterClockDefault ClutterMasterClockDefault; -typedef struct _ClutterMasterClockDefaultClass ClutterMasterClockDefaultClass; - -struct _ClutterMasterClockDefaultClass -{ - GObjectClass parent_class; -}; - -GType _clutter_master_clock_default_get_type (void) G_GNUC_CONST; - -G_END_DECLS - -#endif /* __CLUTTER_MASTER_CLOCK_DEFAULT_H__ */ diff --git a/clutter/clutter/clutter-master-clock.c b/clutter/clutter/clutter-master-clock.c deleted file mode 100644 index c4dff9676..000000000 --- a/clutter/clutter/clutter-master-clock.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Clutter. - * - * An OpenGL based 'interactive canvas' library. - * - * Authored By: Emmanuele Bassi - * - * Copyright (C) 2009 Intel Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - */ - -/* - * SECTION:clutter-master-clock - * @short_description: The master clock for all animations - * - * The #ClutterMasterClock class is responsible for advancing all - * #ClutterTimelines when a stage is being redrawn. The master clock - * makes sure that the scenegraph is always integrally updated before - * painting it. - */ - -#include "clutter-build-config.h" - -#include "clutter-master-clock.h" -#include "clutter-master-clock-default.h" -#include "clutter-private.h" - -G_DEFINE_INTERFACE (ClutterMasterClock, clutter_master_clock, G_TYPE_OBJECT) - -static void -clutter_master_clock_default_init (ClutterMasterClockInterface *iface) -{ -} - -ClutterMasterClock * -_clutter_master_clock_get_default (void) -{ - ClutterMainContext *context = _clutter_context_get_default (); - - if (G_UNLIKELY (context->master_clock == NULL)) - context->master_clock = g_object_new (CLUTTER_TYPE_MASTER_CLOCK_DEFAULT, NULL); - - return context->master_clock; - -} - -/* - * _clutter_master_clock_add_timeline: - * @master_clock: a #ClutterMasterClock - * @timeline: a #ClutterTimeline - * - * Adds @timeline to the list of playing timelines held by the master - * clock. - */ -void -_clutter_master_clock_add_timeline (ClutterMasterClock *master_clock, - ClutterTimeline *timeline) -{ - g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock)); - - CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->add_timeline (master_clock, - timeline); -} - -/* - * _clutter_master_clock_remove_timeline: - * @master_clock: a #ClutterMasterClock - * @timeline: a #ClutterTimeline - * - * Removes @timeline from the list of playing timelines held by the - * master clock. - */ -void -_clutter_master_clock_remove_timeline (ClutterMasterClock *master_clock, - ClutterTimeline *timeline) -{ - g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock)); - - CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->remove_timeline (master_clock, - timeline); -} - -/* - * _clutter_master_clock_start_running: - * @master_clock: a #ClutterMasterClock - * - * Called when we have events or redraws to process; if the clock - * is stopped, does the processing necessary to wake it up again. - */ -void -_clutter_master_clock_start_running (ClutterMasterClock *master_clock) -{ - g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock)); - - CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->start_running (master_clock); -} - -/** - * _clutter_master_clock_ensure_next_iteration: - * @master_clock: a #ClutterMasterClock - * - * Ensures that the master clock will run at least one iteration - */ -void -_clutter_master_clock_ensure_next_iteration (ClutterMasterClock *master_clock) -{ - g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock)); - - CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->ensure_next_iteration (master_clock); -} - -void -_clutter_master_clock_set_paused (ClutterMasterClock *master_clock, - gboolean paused) -{ - g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock)); - - CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->set_paused (master_clock, - !!paused); -} diff --git a/clutter/clutter/clutter-master-clock.h b/clutter/clutter/clutter-master-clock.h deleted file mode 100644 index 88ee6afea..000000000 --- a/clutter/clutter/clutter-master-clock.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Clutter. - * - * An OpenGL based 'interactive canvas' library. - * - * Authored By: Emmanuele Bassi - * - * Copyright (C) 2009 Intel Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - */ - -#ifndef __CLUTTER_MASTER_CLOCK_H__ -#define __CLUTTER_MASTER_CLOCK_H__ - -#include - -G_BEGIN_DECLS - -#define CLUTTER_TYPE_MASTER_CLOCK (clutter_master_clock_get_type ()) -G_DECLARE_INTERFACE (ClutterMasterClock, clutter_master_clock, - CLUTTER, MASTER_CLOCK, - GObject) - -struct _ClutterMasterClockInterface -{ - /*< private >*/ - GTypeInterface parent_iface; - - void (* add_timeline) (ClutterMasterClock *master_clock, - ClutterTimeline *timeline); - void (* remove_timeline) (ClutterMasterClock *master_clock, - ClutterTimeline *timeline); - void (* start_running) (ClutterMasterClock *master_clock); - void (* ensure_next_iteration) (ClutterMasterClock *master_clock); - void (* set_paused) (ClutterMasterClock *master_clock, - gboolean paused); -}; - -ClutterMasterClock * _clutter_master_clock_get_default (void); -void _clutter_master_clock_add_timeline (ClutterMasterClock *master_clock, - ClutterTimeline *timeline); -void _clutter_master_clock_remove_timeline (ClutterMasterClock *master_clock, - ClutterTimeline *timeline); -void _clutter_master_clock_start_running (ClutterMasterClock *master_clock); -void _clutter_master_clock_ensure_next_iteration (ClutterMasterClock *master_clock); -void _clutter_master_clock_set_paused (ClutterMasterClock *master_clock, - gboolean paused); - -G_END_DECLS - -#endif /* __CLUTTER_MASTER_CLOCK_H__ */ diff --git a/clutter/clutter/clutter-mutter.h b/clutter/clutter/clutter-mutter.h index cc1ba9a97..5aa9a7e14 100644 --- a/clutter/clutter/clutter-mutter.h +++ b/clutter/clutter/clutter-mutter.h @@ -68,12 +68,6 @@ gboolean clutter_stage_paint_to_buffer (ClutterStage *stage, ClutterPaintFlag paint_flags, GError **error); -CLUTTER_EXPORT -void clutter_stage_freeze_updates (ClutterStage *stage); - -CLUTTER_EXPORT -void clutter_stage_thaw_updates (ClutterStage *stage); - CLUTTER_EXPORT void clutter_stage_clear_stage_views (ClutterStage *stage); diff --git a/clutter/clutter/clutter-pan-action.c b/clutter/clutter/clutter-pan-action.c index b48146783..6a42627e4 100644 --- a/clutter/clutter/clutter-pan-action.c +++ b/clutter/clutter/clutter-pan-action.c @@ -62,6 +62,7 @@ #include "clutter-gesture-action-private.h" #include "clutter-marshal.h" #include "clutter-private.h" +#include "clutter-timeline.h" #include #define FLOAT_EPSILON (1e-15) diff --git a/clutter/clutter/clutter-private.h b/clutter/clutter/clutter-private.h index a71eac252..e3f89ed09 100644 --- a/clutter/clutter/clutter-private.h +++ b/clutter/clutter/clutter-private.h @@ -37,7 +37,6 @@ #include "clutter-feature.h" #include "clutter-id-pool.h" #include "clutter-layout-manager.h" -#include "clutter-master-clock.h" #include "clutter-settings.h" #include "clutter-stage-manager.h" #include "clutter-stage.h" @@ -122,9 +121,6 @@ struct _ClutterMainContext /* the object holding all the stage instances */ ClutterStageManager *stage_manager; - /* the clock driving all the frame operations */ - ClutterMasterClock *master_clock; - /* the main event queue */ GQueue *events_queue; diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h index 0c4c7066b..7297d56a6 100644 --- a/clutter/clutter/clutter-stage-private.h +++ b/clutter/clutter/clutter-stage-private.h @@ -40,10 +40,14 @@ void clutter_stage_paint_view (ClutterStage ClutterStageView *view, const cairo_region_t *redraw_clip); -void clutter_stage_emit_before_update (ClutterStage *stage); -void clutter_stage_emit_before_paint (ClutterStage *stage); -void clutter_stage_emit_after_paint (ClutterStage *stage); -void clutter_stage_emit_after_update (ClutterStage *stage); +void clutter_stage_emit_before_update (ClutterStage *stage, + ClutterStageView *view); +void clutter_stage_emit_before_paint (ClutterStage *stage, + ClutterStageView *view); +void clutter_stage_emit_after_paint (ClutterStage *stage, + ClutterStageView *view); +void clutter_stage_emit_after_update (ClutterStage *stage, + ClutterStageView *view); CLUTTER_EXPORT void _clutter_stage_set_window (ClutterStage *stage, @@ -67,8 +71,6 @@ GSList * clutter_stage_find_updated_devices (ClutterStage void clutter_stage_update_devices (ClutterStage *stage, GSList *devices); void clutter_stage_update_actor_stage_views (ClutterStage *stage); -gboolean _clutter_stage_needs_update (ClutterStage *stage); -gboolean _clutter_stage_do_update (ClutterStage *stage); CLUTTER_EXPORT void _clutter_stage_queue_event (ClutterStage *stage, @@ -77,8 +79,6 @@ void _clutter_stage_queue_event (ClutterStage *stage, gboolean _clutter_stage_has_queued_events (ClutterStage *stage); void _clutter_stage_process_queued_events (ClutterStage *stage); void _clutter_stage_update_input_devices (ClutterStage *stage); -gint64 _clutter_stage_get_update_time (ClutterStage *stage); -void _clutter_stage_clear_update_time (ClutterStage *stage); gboolean _clutter_stage_has_full_redraw_queued (ClutterStage *stage); void clutter_stage_log_pick (ClutterStage *stage, @@ -135,6 +135,7 @@ void _clutter_stage_set_scale_factor (ClutterStage *stag int factor); void clutter_stage_presented (ClutterStage *stage, + ClutterStageView *view, ClutterFrameInfo *frame_info); void clutter_stage_queue_actor_relayout (ClutterStage *stage, diff --git a/clutter/clutter/clutter-stage-view-private.h b/clutter/clutter/clutter-stage-view-private.h index 02eb22b68..71392f355 100644 --- a/clutter/clutter/clutter-stage-view-private.h +++ b/clutter/clutter/clutter-stage-view-private.h @@ -63,6 +63,11 @@ void clutter_stage_view_transform_rect_to_onscreen (ClutterStageView int dst_height, cairo_rectangle_int_t *dst_rect); +void clutter_stage_view_schedule_update (ClutterStageView *view); + float clutter_stage_view_get_refresh_rate (ClutterStageView *view); +void clutter_stage_view_notify_presented (ClutterStageView *view, + ClutterFrameInfo *frame_info); + #endif /* __CLUTTER_STAGE_VIEW_PRIVATE_H__ */ diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c index b5b04c518..5dd8fc0d9 100644 --- a/clutter/clutter/clutter-stage-view.c +++ b/clutter/clutter/clutter-stage-view.c @@ -27,6 +27,7 @@ #include "clutter/clutter-frame-clock.h" #include "clutter/clutter-private.h" #include "clutter/clutter-mutter.h" +#include "clutter/clutter-stage-private.h" #include "cogl/cogl.h" enum @@ -1001,6 +1002,15 @@ clutter_stage_view_take_scanout (ClutterStageView *view) return g_steal_pointer (&priv->next_scanout); } +void +clutter_stage_view_schedule_update (ClutterStageView *view) +{ + ClutterStageViewPrivate *priv = + clutter_stage_view_get_instance_private (view); + + clutter_frame_clock_schedule_update (priv->frame_clock); +} + float clutter_stage_view_get_refresh_rate (ClutterStageView *view) { @@ -1040,7 +1050,57 @@ handle_frame_clock_frame (ClutterFrameClock *frame_clock, int64_t time_us, gpointer user_data) { - return CLUTTER_FRAME_RESULT_IDLE; + ClutterStageView *view = user_data; + ClutterStageViewPrivate *priv = + clutter_stage_view_get_instance_private (view); + ClutterStage *stage = priv->stage; + g_autoptr (GSList) devices = NULL; + ClutterFrameResult result; + + if (CLUTTER_ACTOR_IN_DESTRUCTION (stage)) + return CLUTTER_FRAME_RESULT_IDLE; + + if (!clutter_actor_is_realized (CLUTTER_ACTOR (stage))) + return CLUTTER_FRAME_RESULT_IDLE; + + if (!clutter_actor_is_mapped (CLUTTER_ACTOR (stage))) + return CLUTTER_FRAME_RESULT_IDLE; + + _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_PRE_PAINT); + clutter_stage_emit_before_update (stage, view); + + clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage)); + clutter_stage_update_actor_stage_views (stage); + clutter_stage_maybe_finish_queue_redraws (stage); + + devices = clutter_stage_find_updated_devices (stage); + + if (clutter_stage_view_has_redraw_clip (view)) + { + ClutterStageWindow *stage_window; + + clutter_stage_emit_before_paint (stage, view); + + stage_window = _clutter_stage_get_window (stage); + _clutter_stage_window_redraw_view (stage_window, view); + + clutter_stage_emit_after_paint (stage, view); + + _clutter_stage_window_finish_frame (stage_window); + + result = CLUTTER_FRAME_RESULT_PENDING_PRESENTED; + } + else + { + result = CLUTTER_FRAME_RESULT_IDLE; + } + + clutter_stage_update_devices (stage, devices); + + _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_POST_PAINT); + clutter_stage_emit_after_update (stage, view); + + return result; } static const ClutterFrameListenerIface frame_clock_listener_iface = { @@ -1048,6 +1108,17 @@ static const ClutterFrameListenerIface frame_clock_listener_iface = { .frame = handle_frame_clock_frame, }; +void +clutter_stage_view_notify_presented (ClutterStageView *view, + ClutterFrameInfo *frame_info) +{ + ClutterStageViewPrivate *priv = + clutter_stage_view_get_instance_private (view); + + clutter_stage_presented (priv->stage, view, frame_info); + clutter_frame_clock_notify_presented (priv->frame_clock, frame_info); +} + static void sanity_check_framebuffer (ClutterStageView *view) { @@ -1071,10 +1142,12 @@ clutter_stage_view_set_framebuffer (ClutterStageView *view, ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); - priv->framebuffer = cogl_object_ref (framebuffer); - - if (priv->framebuffer) - sanity_check_framebuffer (view); + g_warn_if_fail (!priv->framebuffer); + if (framebuffer) + { + priv->framebuffer = cogl_object_ref (framebuffer); + sanity_check_framebuffer (view); + } } static void diff --git a/clutter/clutter/clutter-stage-window.c b/clutter/clutter/clutter-stage-window.c index fe09aa1db..e4e358e6f 100644 --- a/clutter/clutter/clutter-stage-window.c +++ b/clutter/clutter/clutter-stage-window.c @@ -103,81 +103,12 @@ _clutter_stage_window_get_geometry (ClutterStageWindow *window, } void -_clutter_stage_window_schedule_update (ClutterStageWindow *window, - int sync_delay) +_clutter_stage_window_redraw_view (ClutterStageWindow *window, + ClutterStageView *view) { - ClutterStageWindowInterface *iface; - g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window)); - iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); - if (iface->schedule_update == NULL) - { - g_assert (!clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS)); - return; - } - - iface->schedule_update (window, sync_delay); -} - -/** - * _clutter_stage_window_get_update_time: - * @window: a #ClutterStageWindow object - * - * See _clutter_stage_get_update_time() for more info. - * - * Returns: The timestamp of the update time - */ -gint64 -_clutter_stage_window_get_update_time (ClutterStageWindow *window) -{ - ClutterStageWindowInterface *iface; - - g_return_val_if_fail (CLUTTER_IS_STAGE_WINDOW (window), 0); - - iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); - if (iface->get_update_time == NULL) - { - g_assert (!clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS)); - return 0; - } - - return iface->get_update_time (window); -} - -/** - * _clutter_stage_window_clear_update_time: - * @window: a #ClutterStageWindow object - * - * Clears the update time. See _clutter_stage_clear_update_time() for more info. - */ -void -_clutter_stage_window_clear_update_time (ClutterStageWindow *window) -{ - ClutterStageWindowInterface *iface; - - g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window)); - - iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); - if (iface->clear_update_time == NULL) - { - g_assert (!clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS)); - return; - } - - iface->clear_update_time (window); -} - -void -_clutter_stage_window_redraw (ClutterStageWindow *window) -{ - ClutterStageWindowInterface *iface; - - g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window)); - - iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); - if (iface->redraw) - iface->redraw (window); + CLUTTER_STAGE_WINDOW_GET_IFACE (window)->redraw_view (window, view); } gboolean diff --git a/clutter/clutter/clutter-stage-window.h b/clutter/clutter/clutter-stage-window.h index 9f78ed25c..b4bb1a1bd 100644 --- a/clutter/clutter/clutter-stage-window.h +++ b/clutter/clutter/clutter-stage-window.h @@ -44,12 +44,8 @@ struct _ClutterStageWindowInterface void (* get_geometry) (ClutterStageWindow *stage_window, cairo_rectangle_int_t *geometry); - void (* schedule_update) (ClutterStageWindow *stage_window, - int sync_delay); - gint64 (* get_update_time) (ClutterStageWindow *stage_window); - void (* clear_update_time) (ClutterStageWindow *stage_window); - - void (* redraw) (ClutterStageWindow *stage_window); + void (* redraw_view) (ClutterStageWindow *stage_window, + ClutterStageView *view); gboolean (* can_clip_redraws) (ClutterStageWindow *stage_window); @@ -78,15 +74,12 @@ void _clutter_stage_window_resize (ClutterStageWin CLUTTER_EXPORT void _clutter_stage_window_get_geometry (ClutterStageWindow *window, cairo_rectangle_int_t *geometry); -void _clutter_stage_window_schedule_update (ClutterStageWindow *window, - int sync_delay); -gint64 _clutter_stage_window_get_update_time (ClutterStageWindow *window); -void _clutter_stage_window_clear_update_time (ClutterStageWindow *window); void _clutter_stage_window_set_accept_focus (ClutterStageWindow *window, gboolean accept_focus); -void _clutter_stage_window_redraw (ClutterStageWindow *window); +void _clutter_stage_window_redraw_view (ClutterStageWindow *window, + ClutterStageView *view); gboolean _clutter_stage_window_can_clip_redraws (ClutterStageWindow *window); diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index 1f5f03987..e9368fe44 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -60,11 +60,11 @@ #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-event-private.h" +#include "clutter-frame-clock.h" #include "clutter-id-pool.h" #include "clutter-input-device-private.h" #include "clutter-main.h" #include "clutter-marshal.h" -#include "clutter-master-clock.h" #include "clutter-mutter.h" #include "clutter-paint-context-private.h" #include "clutter-paint-volume-private.h" @@ -139,7 +139,6 @@ struct _ClutterStagePrivate int update_freeze_count; - gboolean needs_update; gboolean needs_update_devices; gboolean pending_finish_queue_redraws; @@ -893,27 +892,31 @@ clutter_stage_paint_view (ClutterStage *stage, } void -clutter_stage_emit_before_update (ClutterStage *stage) +clutter_stage_emit_before_update (ClutterStage *stage, + ClutterStageView *view) { - g_signal_emit (stage, stage_signals[BEFORE_UPDATE], 0); + g_signal_emit (stage, stage_signals[BEFORE_UPDATE], 0, view); } void -clutter_stage_emit_before_paint (ClutterStage *stage) +clutter_stage_emit_before_paint (ClutterStage *stage, + ClutterStageView *view) { - g_signal_emit (stage, stage_signals[BEFORE_PAINT], 0); + g_signal_emit (stage, stage_signals[BEFORE_PAINT], 0, view); } void -clutter_stage_emit_after_paint (ClutterStage *stage) +clutter_stage_emit_after_paint (ClutterStage *stage, + ClutterStageView *view) { - g_signal_emit (stage, stage_signals[AFTER_PAINT], 0); + g_signal_emit (stage, stage_signals[AFTER_PAINT], 0, view); } void -clutter_stage_emit_after_update (ClutterStage *stage) +clutter_stage_emit_after_update (ClutterStage *stage, + ClutterStageView *view) { - g_signal_emit (stage, stage_signals[AFTER_UPDATE], 0); + g_signal_emit (stage, stage_signals[AFTER_UPDATE], 0, view); } static gboolean @@ -1072,11 +1075,7 @@ _clutter_stage_queue_event (ClutterStage *stage, g_queue_push_tail (priv->event_queue, event); if (first_event) - { - ClutterMasterClock *master_clock = _clutter_master_clock_get_default (); - _clutter_master_clock_start_running (master_clock); - clutter_stage_schedule_update (stage); - } + clutter_stage_schedule_update (stage); } gboolean @@ -1190,28 +1189,6 @@ _clutter_stage_process_queued_events (ClutterStage *stage) g_object_unref (stage); } -/** - * _clutter_stage_needs_update: - * @stage: A #ClutterStage - * - * Determines if _clutter_stage_do_update() needs to be called. - * - * Return value: %TRUE if the stage need layout or painting - */ -gboolean -_clutter_stage_needs_update (ClutterStage *stage) -{ - ClutterStagePrivate *priv; - - g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); - - priv = stage->priv; - - return (priv->redraw_pending || - priv->needs_update || - priv->pending_relayouts != NULL); -} - void clutter_stage_queue_actor_relayout (ClutterStage *stage, ClutterActor *actor) @@ -1276,52 +1253,6 @@ clutter_stage_maybe_relayout (ClutterActor *actor) priv->needs_update_devices = TRUE; } -static void -clutter_stage_do_redraw (ClutterStage *stage) -{ - ClutterActor *actor = CLUTTER_ACTOR (stage); - ClutterStagePrivate *priv = stage->priv; - - if (CLUTTER_ACTOR_IN_DESTRUCTION (stage)) - return; - - if (priv->impl == NULL) - return; - - COGL_TRACE_BEGIN_SCOPED (ClutterStagePaint, "Paint"); - - CLUTTER_NOTE (PAINT, "Redraw started for stage '%s'[%p]", - _clutter_actor_get_debug_name (actor), - stage); - - if (_clutter_context_get_show_fps ()) - { - if (priv->fps_timer == NULL) - priv->fps_timer = g_timer_new (); - } - - _clutter_stage_window_redraw (priv->impl); - - if (_clutter_context_get_show_fps ()) - { - priv->timer_n_frames += 1; - - if (g_timer_elapsed (priv->fps_timer, NULL) >= 1.0) - { - g_print ("*** FPS for %s: %i ***\n", - _clutter_actor_get_debug_name (actor), - priv->timer_n_frames); - - priv->timer_n_frames = 0; - g_timer_start (priv->fps_timer); - } - } - - CLUTTER_NOTE (PAINT, "Redraw finished for stage '%s'[%p]", - _clutter_actor_get_debug_name (actor), - stage); -} - GSList * clutter_stage_find_updated_devices (ClutterStage *stage) { @@ -1431,75 +1362,6 @@ clutter_stage_update_devices (ClutterStage *stage, } } -/** - * _clutter_stage_do_update: - * @stage: A #ClutterStage - * - * Handles per-frame layout and repaint for the stage. - * - * Return value: %TRUE if the stage was updated - */ -gboolean -_clutter_stage_do_update (ClutterStage *stage) -{ - ClutterStagePrivate *priv = stage->priv; - g_autoptr (GSList) devices = NULL; - - priv->needs_update = FALSE; - - /* if the stage is being destroyed, or if the destruction already - * happened and we don't have an StageWindow any more, then we - * should bail out - */ - if (CLUTTER_ACTOR_IN_DESTRUCTION (stage) || priv->impl == NULL) - return FALSE; - - if (!CLUTTER_ACTOR_IS_REALIZED (stage)) - return FALSE; - - COGL_TRACE_BEGIN_SCOPED (ClutterStageDoUpdate, "Update"); - - clutter_stage_emit_before_update (stage); - - /* NB: We need to ensure we have an up to date layout *before* we - * check or clear the pending redraws flag since a relayout may - * queue a redraw. - */ - clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage)); - - if (!priv->redraw_pending) - { - clutter_stage_emit_after_update (stage); - return FALSE; - } - - clutter_stage_update_actor_stage_views (stage); - clutter_stage_maybe_finish_queue_redraws (stage); - - devices = clutter_stage_find_updated_devices (stage); - - clutter_stage_do_redraw (stage); - - /* reset the guard, so that new redraws are possible */ - priv->redraw_pending = FALSE; - -#ifdef CLUTTER_ENABLE_DEBUG - if (priv->redraw_count > 0) - { - CLUTTER_NOTE (SCHEDULER, "Queued %lu redraws during the last cycle", - priv->redraw_count); - - priv->redraw_count = 0; - } -#endif /* CLUTTER_ENABLE_DEBUG */ - - clutter_stage_update_devices (stage, devices); - - clutter_stage_emit_after_update (stage); - - return TRUE; -} - static void clutter_stage_real_queue_relayout (ClutterActor *self) { @@ -2028,6 +1890,7 @@ clutter_stage_class_init (ClutterStageClass *klass) /** * ClutterStage::before-update: * @stage: the #ClutterStage + * @view: a #ClutterStageView */ stage_signals[BEFORE_UPDATE] = g_signal_new (I_("before-update"), @@ -2035,11 +1898,13 @@ clutter_stage_class_init (ClutterStageClass *klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 0); + G_TYPE_NONE, 1, + CLUTTER_TYPE_STAGE_VIEW); /** * ClutterStage::before-paint: * @stage: the stage that received the event + * @view: a #ClutterStageView * * The ::before-paint signal is emitted before the stage is painted. */ @@ -2049,11 +1914,12 @@ clutter_stage_class_init (ClutterStageClass *klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 0); + G_TYPE_NONE, 1, + CLUTTER_TYPE_STAGE_VIEW); /** * ClutterStage::after-paint: * @stage: the stage that received the event - * @paint_Context: the paint context + * @view: a #ClutterStageView * * The ::after-paint signal is emitted after the stage is painted, * but before the results are displayed on the screen. @@ -2066,11 +1932,13 @@ clutter_stage_class_init (ClutterStageClass *klass) G_SIGNAL_RUN_LAST, 0, /* no corresponding vfunc */ NULL, NULL, NULL, - G_TYPE_NONE, 0); + G_TYPE_NONE, 1, + CLUTTER_TYPE_STAGE_VIEW); /** * ClutterStage::after-update: * @stage: the #ClutterStage + * @view: a #ClutterStageView */ stage_signals[AFTER_UPDATE] = g_signal_new (I_("after-update"), @@ -2078,7 +1946,8 @@ clutter_stage_class_init (ClutterStageClass *klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 0); + G_TYPE_NONE, 1, + CLUTTER_TYPE_STAGE_VIEW); /** * ClutterStage::paint-view: @@ -2106,6 +1975,7 @@ clutter_stage_class_init (ClutterStageClass *klass) /** * ClutterStage::presented: (skip) * @stage: the stage that received the event + * @view: the #ClutterStageView presented * @frame_info: a #ClutterFrameInfo * * Signals that the #ClutterStage was presented on the screen to the user. @@ -2116,7 +1986,8 @@ clutter_stage_class_init (ClutterStageClass *klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 1, + G_TYPE_NONE, 2, + CLUTTER_TYPE_STAGE_VIEW, G_TYPE_POINTER); klass->activate = clutter_stage_real_activate; @@ -3204,6 +3075,7 @@ void clutter_stage_schedule_update (ClutterStage *stage) { ClutterStageWindow *stage_window; + GList *l; if (CLUTTER_ACTOR_IN_DESTRUCTION (stage)) return; @@ -3212,54 +3084,12 @@ clutter_stage_schedule_update (ClutterStage *stage) if (stage_window == NULL) return; - stage->priv->needs_update = TRUE; + for (l = clutter_stage_peek_stage_views (stage); l; l = l->next) + { + ClutterStageView *view = l->data; - return _clutter_stage_window_schedule_update (stage_window, - stage->priv->sync_delay); -} - -/** - * _clutter_stage_get_update_time: - * @stage: a #ClutterStage actor - * - * Returns the earliest time in which the stage is ready to update. The update - * time is set when clutter_stage_schedule_update() is called. This can then - * be used by e.g. the #ClutterMasterClock to know when the stage needs to be - * redrawn. - * - * Returns: -1 if no redraw is needed; 0 if the backend doesn't know, or the - * timestamp (in microseconds) otherwise. - */ -gint64 -_clutter_stage_get_update_time (ClutterStage *stage) -{ - ClutterStageWindow *stage_window; - - if (CLUTTER_ACTOR_IN_DESTRUCTION (stage)) - return 0; - - stage_window = _clutter_stage_get_window (stage); - if (stage_window == NULL) - return 0; - - return _clutter_stage_window_get_update_time (stage_window); -} - -/** - * _clutter_stage_clear_update_time: - * @stage: a #ClutterStage actor - * - * Resets the update time. Call this after a redraw, so that the update time - * can again be updated. - */ -void -_clutter_stage_clear_update_time (ClutterStage *stage) -{ - ClutterStageWindow *stage_window; - - stage_window = _clutter_stage_get_window (stage); - if (stage_window) - _clutter_stage_window_clear_update_time (stage_window); + clutter_stage_view_schedule_update (view); + } } ClutterPaintVolume * @@ -3327,19 +3157,26 @@ _clutter_stage_queue_actor_redraw (ClutterStage *stage, */ priv->cached_pick_mode = CLUTTER_PICK_NONE; - priv->pending_finish_queue_redraws = TRUE; + if (!priv->pending_finish_queue_redraws) + { + GList *l; + + for (l = clutter_stage_peek_stage_views (stage); l; l = l->next) + { + ClutterStageView *view = l->data; + + clutter_stage_view_schedule_update (view); + } + + priv->pending_finish_queue_redraws = TRUE; + } if (!priv->redraw_pending) { - ClutterMasterClock *master_clock; - CLUTTER_NOTE (PAINT, "First redraw request"); clutter_stage_schedule_update (stage); priv->redraw_pending = TRUE; - - master_clock = _clutter_master_clock_get_default (); - _clutter_master_clock_start_running (master_clock); } #ifdef CLUTTER_ENABLE_DEBUG else @@ -3749,27 +3586,6 @@ clutter_stage_set_sync_delay (ClutterStage *stage, stage->priv->sync_delay = sync_delay; } -/** - * clutter_stage_skip_sync_delay: - * @stage: a #ClutterStage - * - * Causes the next frame for the stage to be drawn as quickly as - * possible, ignoring any delay that clutter_stage_set_sync_delay() - * would normally cause. - * - * Since: 1.14 - * Stability: unstable - */ -void -clutter_stage_skip_sync_delay (ClutterStage *stage) -{ - ClutterStageWindow *stage_window; - - stage_window = _clutter_stage_get_window (stage); - if (stage_window) - _clutter_stage_window_schedule_update (stage_window, -1); -} - int64_t clutter_stage_get_frame_counter (ClutterStage *stage) { @@ -3781,9 +3597,10 @@ clutter_stage_get_frame_counter (ClutterStage *stage) void clutter_stage_presented (ClutterStage *stage, + ClutterStageView *view, ClutterFrameInfo *frame_info) { - g_signal_emit (stage, stage_signals[PRESENTED], 0, frame_info); + g_signal_emit (stage, stage_signals[PRESENTED], 0, view, frame_info); } static void @@ -4123,61 +3940,6 @@ clutter_stage_capture_into (ClutterStage *stage, } } -/** - * clutter_stage_freeze_updates: - * - * Freezing updates makes Clutter stop processing events, - * redrawing, and advancing timelines, by pausing the master clock. This is - * necessary when implementing a display server, to ensure that Clutter doesn't - * keep trying to page flip when DRM master has been dropped, e.g. when VT - * switched away. - * - * The master clock starts out running, so if you are VT switched away on - * startup, you need to call this immediately. - * - * To thaw updates, use clutter_stage_thaw_updates(). - */ -void -clutter_stage_freeze_updates (ClutterStage *stage) -{ - ClutterStagePrivate *priv = stage->priv; - - priv->update_freeze_count++; - if (priv->update_freeze_count == 1) - { - ClutterMasterClock *master_clock; - - master_clock = _clutter_master_clock_get_default (); - _clutter_master_clock_set_paused (master_clock, TRUE); - } -} - -/** - * clutter_stage_thaw_updates: - * - * Resumes a master clock that has previously been frozen with - * clutter_stage_freeze_updates(), and start pumping the master clock - * again at the next iteration. Note that if you're switching back to your - * own VT, you should probably also queue a stage redraw with - * clutter_stage_ensure_redraw(). - */ -void -clutter_stage_thaw_updates (ClutterStage *stage) -{ - ClutterStagePrivate *priv = stage->priv; - - g_assert (priv->update_freeze_count > 0); - - priv->update_freeze_count--; - if (priv->update_freeze_count == 0) - { - ClutterMasterClock *master_clock; - - master_clock = _clutter_master_clock_get_default (); - _clutter_master_clock_set_paused (master_clock, FALSE); - } -} - /** * clutter_stage_peek_stage_views: (skip) */ diff --git a/clutter/clutter/clutter-timeline.c b/clutter/clutter/clutter-timeline.c index 353a24ca9..2cf460d5f 100644 --- a/clutter/clutter/clutter-timeline.c +++ b/clutter/clutter/clutter-timeline.c @@ -103,7 +103,6 @@ #include "clutter-frame-clock.h" #include "clutter-main.h" #include "clutter-marshal.h" -#include "clutter-master-clock.h" #include "clutter-private.h" #include "clutter-scriptable.h" #include "clutter-timeline-private.h" @@ -112,10 +111,12 @@ struct _ClutterTimelinePrivate { ClutterTimelineDirection direction; + ClutterFrameClock *custom_frame_clock; ClutterFrameClock *frame_clock; ClutterActor *actor; gulong actor_destroy_handler_id; + gulong actor_stage_views_handler_id; guint delay_id; @@ -322,6 +323,70 @@ clutter_timeline_get_actor (ClutterTimeline *timeline) return priv->actor; } +static void +maybe_add_timeline (ClutterTimeline *timeline) +{ + ClutterTimelinePrivate *priv = timeline->priv; + + if (!priv->frame_clock) + return; + + clutter_frame_clock_add_timeline (priv->frame_clock, timeline); +} + +static void +maybe_remove_timeline (ClutterTimeline *timeline) +{ + ClutterTimelinePrivate *priv = timeline->priv; + + if (!priv->frame_clock) + return; + + clutter_frame_clock_remove_timeline (priv->frame_clock, timeline); +} + +static void +set_frame_clock_internal (ClutterTimeline *timeline, + ClutterFrameClock *frame_clock) +{ + ClutterTimelinePrivate *priv = timeline->priv; + + if (priv->frame_clock == frame_clock) + return; + + if (priv->frame_clock && priv->is_playing) + maybe_remove_timeline (timeline); + + g_set_object (&priv->frame_clock, frame_clock); + + g_object_notify_by_pspec (G_OBJECT (timeline), + obj_props[PROP_FRAME_CLOCK]); + + if (priv->is_playing) + maybe_add_timeline (timeline); +} + +static void +update_frame_clock (ClutterTimeline *timeline) +{ + ClutterTimelinePrivate *priv = timeline->priv; + ClutterFrameClock *frame_clock; + + if (priv->actor) + frame_clock = clutter_actor_pick_frame_clock (priv->actor); + else + frame_clock = NULL; + + set_frame_clock_internal (timeline, frame_clock); +} + +static void +on_actor_stage_views_changed (ClutterActor *actor, + ClutterTimeline *timeline) +{ + update_frame_clock (timeline); +} + /** * clutter_timeline_set_actor: * @timeline: a #ClutterTimeline @@ -335,9 +400,18 @@ clutter_timeline_set_actor (ClutterTimeline *timeline, { ClutterTimelinePrivate *priv = timeline->priv; + g_return_if_fail (!actor || (actor && !priv->custom_frame_clock)); + if (priv->actor) { g_clear_signal_handler (&priv->actor_destroy_handler_id, priv->actor); + g_clear_signal_handler (&priv->actor_stage_views_handler_id, priv->actor); + priv->actor = NULL; + + if (priv->is_playing) + maybe_remove_timeline (timeline); + + priv->frame_clock = NULL; } priv->actor = actor; @@ -348,7 +422,13 @@ clutter_timeline_set_actor (ClutterTimeline *timeline, g_signal_connect (priv->actor, "destroy", G_CALLBACK (on_actor_destroyed), timeline); + priv->actor_stage_views_handler_id = + g_signal_connect (priv->actor, "stage-views-changed", + G_CALLBACK (on_actor_stage_views_changed), + timeline); } + + update_frame_clock (timeline); } /* Scriptable */ @@ -579,42 +659,6 @@ clutter_timeline_get_property (GObject *object, } } -static void -add_timeline (ClutterTimeline *timeline) -{ - ClutterTimelinePrivate *priv = timeline->priv; - - if (priv->frame_clock) - { - clutter_frame_clock_add_timeline (priv->frame_clock, timeline); - } - else - { - ClutterMasterClock *master_clock; - - master_clock = _clutter_master_clock_get_default (); - _clutter_master_clock_add_timeline (master_clock, timeline); - } -} - -static void -remove_timeline (ClutterTimeline *timeline) -{ - ClutterTimelinePrivate *priv = timeline->priv; - - if (priv->frame_clock) - { - clutter_frame_clock_remove_timeline (priv->frame_clock, timeline); - } - else - { - ClutterMasterClock *master_clock; - - master_clock = _clutter_master_clock_get_default (); - _clutter_master_clock_remove_timeline (master_clock, timeline); - } -} - static void clutter_timeline_constructed (GObject *object) { @@ -636,7 +680,7 @@ clutter_timeline_finalize (GObject *object) g_hash_table_destroy (priv->markers_by_name); if (priv->is_playing) - remove_timeline (self); + maybe_remove_timeline (self); g_clear_object (&priv->frame_clock); @@ -656,6 +700,7 @@ clutter_timeline_dispose (GObject *object) if (priv->actor) { g_clear_signal_handler (&priv->actor_destroy_handler_id, priv->actor); + g_clear_signal_handler (&priv->actor_stage_views_handler_id, priv->actor); priv->actor = NULL; } @@ -1093,11 +1138,11 @@ set_is_playing (ClutterTimeline *timeline, priv->waiting_first_tick = TRUE; priv->current_repeat = 0; - add_timeline (timeline); + maybe_add_timeline (timeline); } else { - remove_timeline (timeline); + maybe_remove_timeline (timeline); } } @@ -1797,7 +1842,7 @@ _clutter_timeline_do_tick (ClutterTimeline *timeline, /* Check the is_playing variable before performing the timeline tick. * This is necessary, as if a timeline is stopped in response to a - * master-clock generated signal of a different timeline, this code can + * frame clock generated signal of a different timeline, this code can * still be reached. */ if (!priv->is_playing) @@ -2637,17 +2682,10 @@ clutter_timeline_set_frame_clock (ClutterTimeline *timeline, priv = timeline->priv; - if (priv->frame_clock == frame_clock) - return; + g_assert (!frame_clock || (frame_clock && !priv->actor)); + g_return_if_fail (!frame_clock || (frame_clock && !priv->actor)); - if (priv->frame_clock && priv->is_playing) - remove_timeline (timeline); - - g_set_object (&priv->frame_clock, frame_clock); - - g_object_notify_by_pspec (G_OBJECT (timeline), - obj_props[PROP_FRAME_CLOCK]); - - if (priv->is_playing) - add_timeline (timeline); + priv->custom_frame_clock = frame_clock; + if (!priv->actor) + set_frame_clock_internal (timeline, frame_clock); } diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c index 6aa912e71..695c594bb 100644 --- a/clutter/clutter/cogl/clutter-stage-cogl.c +++ b/clutter/clutter/cogl/clutter-stage-cogl.c @@ -47,6 +47,7 @@ #include "clutter-private.h" #include "clutter-stage-private.h" #include "clutter-stage-view-private.h" +#include "cogl.h" #define MAX_STACK_RECTS 256 @@ -55,6 +56,8 @@ typedef struct _ClutterStageViewCoglPrivate /* Damage history, in stage view render target framebuffer coordinate space. */ ClutterDamageHistory *damage_history; + + guint notify_presented_handle_id; } ClutterStageViewCoglPrivate; G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageViewCogl, clutter_stage_view_cogl, @@ -83,67 +86,12 @@ enum PROP_LAST }; -static void -clutter_stage_cogl_schedule_update (ClutterStageWindow *stage_window, - gint sync_delay); - static void clutter_stage_cogl_unrealize (ClutterStageWindow *stage_window) { CLUTTER_NOTE (BACKEND, "Unrealizing Cogl stage [%p]", stage_window); } -void -_clutter_stage_cogl_presented (ClutterStageCogl *stage_cogl, - CoglFrameEvent frame_event, - ClutterFrameInfo *frame_info) -{ - - if (frame_event == COGL_FRAME_EVENT_SYNC) - { - /* Early versions of the swap_event implementation in Mesa - * deliver BufferSwapComplete event when not selected for, - * so if we get a swap event we aren't expecting, just ignore it. - * - * https://bugs.freedesktop.org/show_bug.cgi?id=27962 - * - * FIXME: This issue can be hidden inside Cogl so we shouldn't - * need to care about this bug here. - */ - if (stage_cogl->pending_swaps > 0) - stage_cogl->pending_swaps--; - } - else if (frame_event == COGL_FRAME_EVENT_COMPLETE) - { - gint64 presentation_time_cogl = frame_info->presentation_time; - - if (presentation_time_cogl != 0) - { - ClutterBackend *backend = stage_cogl->backend; - CoglContext *context = clutter_backend_get_cogl_context (backend); - gint64 current_time_cogl = cogl_get_clock_time (context); - gint64 now = g_get_monotonic_time (); - - stage_cogl->last_presentation_time = - now + (presentation_time_cogl - current_time_cogl) / 1000; - } - - stage_cogl->refresh_rate = frame_info->refresh_rate; - } - - clutter_stage_presented (stage_cogl->wrapper, frame_info); - - if (frame_event == COGL_FRAME_EVENT_COMPLETE && - stage_cogl->update_time != -1) - { - ClutterStageWindow *stage_window = CLUTTER_STAGE_WINDOW (stage_cogl); - - stage_cogl->update_time = -1; - clutter_stage_cogl_schedule_update (stage_window, - stage_cogl->last_sync_delay); - } -} - static gboolean clutter_stage_cogl_realize (ClutterStageWindow *stage_window) { @@ -174,103 +122,6 @@ clutter_stage_cogl_get_frame_counter (ClutterStageWindow *stage_window) return priv->global_frame_counter; } -static void -clutter_stage_cogl_schedule_update (ClutterStageWindow *stage_window, - gint sync_delay) -{ - ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); - gint64 now; - float refresh_rate; - gint64 refresh_interval; - int64_t min_render_time_allowed; - int64_t max_render_time_allowed; - int64_t next_presentation_time; - - if (stage_cogl->update_time != -1) - return; - - stage_cogl->last_sync_delay = sync_delay; - - now = g_get_monotonic_time (); - - if (sync_delay < 0) - { - stage_cogl->update_time = now; - return; - } - - refresh_rate = stage_cogl->refresh_rate; - if (refresh_rate <= 0.0) - refresh_rate = clutter_get_default_frame_rate (); - - refresh_interval = (gint64) (0.5 + G_USEC_PER_SEC / refresh_rate); - if (refresh_interval == 0) - { - stage_cogl->update_time = now; - return; - } - - min_render_time_allowed = refresh_interval / 2; - max_render_time_allowed = refresh_interval - 1000 * sync_delay; - - /* Be robust in the case of incredibly bogus refresh rate */ - if (max_render_time_allowed <= 0) - { - g_warning ("Unsupported monitor refresh rate detected. " - "(Refresh rate: %.3f, refresh interval: %" G_GINT64_FORMAT ")", - refresh_rate, - refresh_interval); - stage_cogl->update_time = now; - return; - } - - if (min_render_time_allowed > max_render_time_allowed) - min_render_time_allowed = max_render_time_allowed; - - next_presentation_time = stage_cogl->last_presentation_time + refresh_interval; - - /* Get next_presentation_time closer to its final value, to reduce - * the number of while iterations below. - */ - if (next_presentation_time < now) - { - int64_t last_virtual_presentation_time = now - now % refresh_interval; - int64_t hardware_clock_phase = - stage_cogl->last_presentation_time % refresh_interval; - - next_presentation_time = - last_virtual_presentation_time + hardware_clock_phase; - } - - while (next_presentation_time < now + min_render_time_allowed) - next_presentation_time += refresh_interval; - - stage_cogl->update_time = next_presentation_time - max_render_time_allowed; - - if (stage_cogl->update_time == stage_cogl->last_update_time) - stage_cogl->update_time = stage_cogl->last_update_time + refresh_interval; -} - -static gint64 -clutter_stage_cogl_get_update_time (ClutterStageWindow *stage_window) -{ - ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); - - if (stage_cogl->pending_swaps) - return -1; /* in the future, indefinite */ - - return stage_cogl->update_time; -} - -static void -clutter_stage_cogl_clear_update_time (ClutterStageWindow *stage_window) -{ - ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); - - stage_cogl->last_update_time = stage_cogl->update_time; - stage_cogl->update_time = -1; -} - static ClutterActor * clutter_stage_cogl_get_wrapper (ClutterStageWindow *stage_window) { @@ -371,7 +222,27 @@ paint_damage_region (ClutterStageWindow *stage_window, cogl_framebuffer_pop_matrix (framebuffer); } +typedef struct _NotifyPresentedClosure +{ + ClutterStageView *view; + ClutterFrameInfo frame_info; +} NotifyPresentedClosure; + static gboolean +notify_presented_idle (gpointer user_data) +{ + NotifyPresentedClosure *closure = user_data; + ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (closure->view); + ClutterStageViewCoglPrivate *view_priv = + clutter_stage_view_cogl_get_instance_private (view_cogl); + + view_priv->notify_presented_handle_id = 0; + clutter_stage_view_notify_presented (closure->view, &closure->frame_info); + + return G_SOURCE_REMOVE; +} + +static void swap_framebuffer (ClutterStageWindow *stage_window, ClutterStageView *view, cairo_region_t *swap_region, @@ -416,8 +287,6 @@ swap_framebuffer (ClutterStageWindow *stage_window, cogl_onscreen_swap_region (onscreen, damage, n_rects, frame_info); - - return FALSE; } else { @@ -427,17 +296,33 @@ swap_framebuffer (ClutterStageWindow *stage_window, cogl_onscreen_swap_buffers_with_damage (onscreen, damage, n_rects, frame_info); - - return TRUE; } } else { + ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view); + ClutterStageViewCoglPrivate *view_priv = + clutter_stage_view_cogl_get_instance_private (view_cogl); + NotifyPresentedClosure *closure; + CLUTTER_NOTE (BACKEND, "cogl_framebuffer_finish (framebuffer: %p)", framebuffer); cogl_framebuffer_finish (framebuffer); - return FALSE; + closure = g_new0 (NotifyPresentedClosure, 1); + closure->view = view; + closure->frame_info = (ClutterFrameInfo) { + .frame_counter = priv->global_frame_counter, + .refresh_rate = clutter_stage_view_get_refresh_rate (view), + .presentation_time = g_get_monotonic_time (), + }; + priv->global_frame_counter++; + + g_warn_if_fail (view_priv->notify_presented_handle_id == 0); + view_priv->notify_presented_handle_id = + g_idle_add_full (G_PRIORITY_DEFAULT, + notify_presented_idle, + closure, g_free); } } @@ -564,11 +449,11 @@ is_buffer_age_enabled (void) cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE); } -static gboolean -clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window, - ClutterStageView *view) +static void +clutter_stage_cogl_redraw_view_primary (ClutterStageCogl *stage_cogl, + ClutterStageView *view) { - ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); + ClutterStageWindow *stage_window = CLUTTER_STAGE_WINDOW (stage_cogl); ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view); ClutterStageViewCoglPrivate *view_priv = clutter_stage_view_cogl_get_instance_private (view_cogl); @@ -587,7 +472,6 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window, float fb_scale; int fb_width, fb_height; int buffer_age = 0; - gboolean res; clutter_stage_view_get_layout (view, &view_rect); fb_scale = clutter_stage_view_get_scale (view); @@ -654,7 +538,7 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window, redraw_clip = cairo_region_create_rectangle (&view_rect); } - g_return_val_if_fail (!cairo_region_is_empty (fb_clip_region), FALSE); + g_return_if_fail (!cairo_region_is_empty (fb_clip_region)); swap_with_damage = FALSE; if (has_buffer_age) @@ -755,14 +639,12 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window, cairo_region_destroy (queued_redraw_clip); } - res = swap_framebuffer (stage_window, - view, - swap_region, - swap_with_damage); + swap_framebuffer (stage_window, + view, + swap_region, + swap_with_damage); cairo_region_destroy (swap_region); - - return res; } static void @@ -787,68 +669,17 @@ clutter_stage_cogl_scanout_view (ClutterStageCogl *stage_cogl, } static void -clutter_stage_cogl_redraw (ClutterStageWindow *stage_window) +clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window, + ClutterStageView *view) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); - gboolean has_redraw_clip = FALSE; - gboolean swap_event = FALSE; - GList *l; + g_autoptr (CoglScanout) scanout = NULL; - COGL_TRACE_BEGIN (ClutterStageCoglRedraw, "Paint (Cogl Redraw)"); - - for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next) - { - ClutterStageView *view = l->data; - - if (!clutter_stage_view_has_redraw_clip (view)) - continue; - - has_redraw_clip = TRUE; - break; - } - - if (has_redraw_clip) - clutter_stage_emit_before_paint (stage_cogl->wrapper); - - for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next) - { - ClutterStageView *view = l->data; - g_autoptr (CoglScanout) scanout = NULL; - - if (!clutter_stage_view_has_redraw_clip (view)) - continue; - - scanout = clutter_stage_view_take_scanout (view); - if (scanout) - { - clutter_stage_cogl_scanout_view (stage_cogl, - view, - scanout); - swap_event = TRUE; - } - else - { - swap_event |= clutter_stage_cogl_redraw_view (stage_window, view); - } - } - - if (has_redraw_clip) - clutter_stage_emit_after_paint (stage_cogl->wrapper); - - _clutter_stage_window_finish_frame (stage_window); - - if (swap_event) - { - /* If we have swap buffer events then cogl_onscreen_swap_buffers - * will return immediately and we need to track that there is a - * swap in progress... */ - if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS)) - stage_cogl->pending_swaps++; - } - - stage_cogl->frame_count++; - - COGL_TRACE_END (ClutterStageCoglRedraw); + scanout = clutter_stage_view_take_scanout (view); + if (scanout) + clutter_stage_cogl_scanout_view (stage_cogl, view, scanout); + else + clutter_stage_cogl_redraw_view_primary (stage_cogl, view); } static void @@ -861,10 +692,7 @@ clutter_stage_window_iface_init (ClutterStageWindowInterface *iface) iface->show = clutter_stage_cogl_show; iface->hide = clutter_stage_cogl_hide; iface->get_frame_counter = clutter_stage_cogl_get_frame_counter; - iface->schedule_update = clutter_stage_cogl_schedule_update; - iface->get_update_time = clutter_stage_cogl_get_update_time; - iface->clear_update_time = clutter_stage_cogl_clear_update_time; - iface->redraw = clutter_stage_cogl_redraw; + iface->redraw_view = clutter_stage_cogl_redraw_view; } static void @@ -905,10 +733,43 @@ _clutter_stage_cogl_class_init (ClutterStageCoglClass *klass) static void _clutter_stage_cogl_init (ClutterStageCogl *stage) { - stage->last_presentation_time = 0; - stage->refresh_rate = 0.0; +} - stage->update_time = -1; +static void +frame_cb (CoglOnscreen *onscreen, + CoglFrameEvent frame_event, + CoglFrameInfo *frame_info, + void *user_data) +{ + ClutterStageView *view = user_data; + ClutterFrameInfo clutter_frame_info; + + if (frame_event == COGL_FRAME_EVENT_SYNC) + return; + + clutter_frame_info = (ClutterFrameInfo) { + .frame_counter = cogl_frame_info_get_global_frame_counter (frame_info), + .refresh_rate = cogl_frame_info_get_refresh_rate (frame_info), + .presentation_time = ns2us (cogl_frame_info_get_presentation_time (frame_info)), + }; + + clutter_stage_view_notify_presented (view, &clutter_frame_info); +} + +static void +on_framebuffer_set (ClutterStageView *view) +{ + CoglFramebuffer *framebuffer; + + framebuffer = clutter_stage_view_get_onscreen (view); + + if (framebuffer && cogl_is_onscreen (framebuffer)) + { + cogl_onscreen_add_frame_callback (COGL_ONSCREEN (framebuffer), + frame_cb, + view, + NULL); + } } static void @@ -918,6 +779,7 @@ clutter_stage_view_cogl_finalize (GObject *object) ClutterStageViewCoglPrivate *view_priv = clutter_stage_view_cogl_get_instance_private (view_cogl); + g_clear_handle_id (&view_priv->notify_presented_handle_id, g_source_remove); clutter_damage_history_free (view_priv->damage_history); G_OBJECT_CLASS (clutter_stage_view_cogl_parent_class)->finalize (object); @@ -930,6 +792,9 @@ clutter_stage_view_cogl_init (ClutterStageViewCogl *view_cogl) clutter_stage_view_cogl_get_instance_private (view_cogl); view_priv->damage_history = clutter_damage_history_new (); + + g_signal_connect (view_cogl, "notify::framebuffer", + G_CALLBACK (on_framebuffer_set), NULL); } static void diff --git a/clutter/clutter/cogl/clutter-stage-cogl.h b/clutter/clutter/cogl/clutter-stage-cogl.h index 1eaa02e8f..a67ba9615 100644 --- a/clutter/clutter/cogl/clutter-stage-cogl.h +++ b/clutter/clutter/cogl/clutter-stage-cogl.h @@ -41,20 +41,6 @@ struct _ClutterStageCogl /* back pointer to the backend */ ClutterBackend *backend; - - float refresh_rate; - int pending_swaps; - - gint64 last_presentation_time; - gint64 update_time; - int64_t last_update_time; - - /* We only enable clipped redraws after 2 frames, since we've seen - * a lot of drivers can struggle to get going and may output some - * junk frames to start with. */ - unsigned int frame_count; - - gint last_sync_delay; }; struct _ClutterStageCoglClass diff --git a/clutter/clutter/meson.build b/clutter/clutter/meson.build index 42dbaa5c4..fa556905e 100644 --- a/clutter/clutter/meson.build +++ b/clutter/clutter/meson.build @@ -141,8 +141,6 @@ clutter_sources = [ 'clutter-layout-manager.c', 'clutter-layout-meta.c', 'clutter-main.c', - 'clutter-master-clock.c', - 'clutter-master-clock-default.c', 'clutter-offscreen-effect.c', 'clutter-page-turn-effect.c', 'clutter-paint-context.c', @@ -200,8 +198,6 @@ clutter_private_headers = [ 'clutter-input-focus-private.h', 'clutter-input-method-private.h', 'clutter-input-pointer-a11y-private.h', - 'clutter-master-clock.h', - 'clutter-master-clock-default.h', 'clutter-offscreen-effect-private.h', 'clutter-paint-context-private.h', 'clutter-paint-node-private.h', diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c index 39f275489..7694d90a7 100644 --- a/src/backends/meta-backend.c +++ b/src/backends/meta-backend.c @@ -170,8 +170,6 @@ struct _MetaBackendPrivate guint sleep_signal_id; GCancellable *cancellable; GDBusConnection *system_bus; - - gboolean was_headless; }; typedef struct _MetaBackendPrivate MetaBackendPrivate; @@ -292,19 +290,6 @@ meta_backend_monitors_changed (MetaBackend *backend) } meta_cursor_renderer_force_update (priv->cursor_renderer); - - if (meta_monitor_manager_is_headless (priv->monitor_manager) && - !priv->was_headless) - { - clutter_stage_freeze_updates (CLUTTER_STAGE (priv->stage)); - priv->was_headless = TRUE; - } - else if (!meta_monitor_manager_is_headless (priv->monitor_manager) && - priv->was_headless) - { - clutter_stage_thaw_updates (CLUTTER_STAGE (priv->stage)); - priv->was_headless = FALSE; - } } void diff --git a/src/backends/meta-cursor-renderer.c b/src/backends/meta-cursor-renderer.c index 73f651c70..5580136fc 100644 --- a/src/backends/meta-cursor-renderer.c +++ b/src/backends/meta-cursor-renderer.c @@ -32,6 +32,7 @@ #include "clutter/clutter.h" #include "clutter/clutter-mutter.h" #include "cogl/cogl.h" +#include "core/boxes-private.h" #include "meta/meta-backend.h" #include "meta/util.h" @@ -155,13 +156,25 @@ queue_redraw (MetaCursorRenderer *renderer, static void meta_cursor_renderer_after_paint (ClutterStage *stage, + ClutterStageView *stage_view, MetaCursorRenderer *renderer) { MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer); if (priv->displayed_cursor && !priv->handled_by_backend) - meta_cursor_renderer_emit_painted (renderer, priv->displayed_cursor); + { + graphene_rect_t rect; + MetaRectangle view_layout; + graphene_rect_t view_rect; + + rect = meta_cursor_renderer_calculate_rect (renderer, + priv->displayed_cursor); + clutter_stage_view_get_layout (stage_view, &view_layout); + view_rect = meta_rectangle_to_graphene_rect (&view_layout); + if (graphene_rect_intersection (&rect, &view_rect, NULL)) + meta_cursor_renderer_emit_painted (renderer, priv->displayed_cursor); + } } static gboolean diff --git a/src/backends/meta-renderer.c b/src/backends/meta-renderer.c index 8260ef623..c0bbb6133 100644 --- a/src/backends/meta-renderer.c +++ b/src/backends/meta-renderer.c @@ -64,6 +64,7 @@ typedef struct _MetaRendererPrivate { MetaBackend *backend; GList *views; + gboolean is_paused; } MetaRendererPrivate; G_DEFINE_TYPE_WITH_PRIVATE (MetaRenderer, meta_renderer, G_TYPE_OBJECT) @@ -247,6 +248,14 @@ meta_renderer_add_view (MetaRenderer *renderer, MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer); priv->views = g_list_append (priv->views, view); + + if (priv->is_paused) + { + ClutterFrameClock *frame_clock = + clutter_stage_view_get_frame_clock (CLUTTER_STAGE_VIEW (view)); + + clutter_frame_clock_inhibit (frame_clock); + } } /** @@ -267,6 +276,44 @@ meta_renderer_get_views (MetaRenderer *renderer) return priv->views; } +void +meta_renderer_pause (MetaRenderer *renderer) +{ + MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer); + GList *l; + + g_return_if_fail (!priv->is_paused); + priv->is_paused = TRUE; + + for (l = priv->views; l; l = l->next) + { + ClutterStageView *stage_view = l->data; + ClutterFrameClock *frame_clock = + clutter_stage_view_get_frame_clock (stage_view); + + clutter_frame_clock_inhibit (frame_clock); + } +} + +void +meta_renderer_resume (MetaRenderer *renderer) +{ + MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer); + GList *l; + + g_return_if_fail (priv->is_paused); + priv->is_paused = FALSE; + + for (l = priv->views; l; l = l->next) + { + ClutterStageView *stage_view = l->data; + ClutterFrameClock *frame_clock = + clutter_stage_view_get_frame_clock (stage_view); + + clutter_frame_clock_uninhibit (frame_clock); + } +} + gboolean meta_renderer_is_hardware_accelerated (MetaRenderer *renderer) { diff --git a/src/backends/meta-renderer.h b/src/backends/meta-renderer.h index 278e64582..134d23abf 100644 --- a/src/backends/meta-renderer.h +++ b/src/backends/meta-renderer.h @@ -67,4 +67,8 @@ GList * meta_renderer_get_views (MetaRenderer *renderer); gboolean meta_renderer_is_hardware_accelerated (MetaRenderer *renderer); +void meta_renderer_pause (MetaRenderer *renderer); + +void meta_renderer_resume (MetaRenderer *renderer); + #endif /* META_RENDERER_H */ diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c index 12f2812b2..17f47b80d 100644 --- a/src/backends/native/meta-backend-native.c +++ b/src/backends/native/meta-backend-native.c @@ -781,7 +781,6 @@ void meta_backend_native_pause (MetaBackendNative *native) { MetaBackend *backend = META_BACKEND (native); - ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend); MetaMonitorManagerKms *monitor_manager_kms = @@ -789,12 +788,13 @@ meta_backend_native_pause (MetaBackendNative *native) ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); MetaSeatNative *seat = META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend)); + MetaRenderer *renderer = meta_backend_get_renderer (backend); COGL_TRACE_BEGIN_SCOPED (MetaBackendNativePause, "Backend (pause)"); meta_seat_native_release_devices (seat); - clutter_stage_freeze_updates (stage); + meta_renderer_pause (renderer); disconnect_udev_device_added_handler (native); @@ -814,6 +814,7 @@ void meta_backend_native_resume (MetaBackendNative *native) ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); MetaSeatNative *seat = META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend)); + MetaRenderer *renderer = meta_backend_get_renderer (backend); COGL_TRACE_BEGIN_SCOPED (MetaBackendNativeResume, "Backend (resume)"); @@ -823,7 +824,7 @@ void meta_backend_native_resume (MetaBackendNative *native) connect_udev_device_added_handler (native); meta_seat_native_reclaim_devices (seat); - clutter_stage_thaw_updates (stage); + meta_renderer_resume (renderer); clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index 255a4ce72..f3a6bd7e4 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -169,8 +169,6 @@ typedef struct _MetaOnscreenNativeSecondaryGpuState MetaDumbBuffer dumb_fbs[2]; } cpu; - int pending_flips; - gboolean noted_primary_gpu_copy_ok; gboolean noted_primary_gpu_copy_failed; MetaSharedFramebufferImportStatus import_status; @@ -199,15 +197,9 @@ typedef struct _MetaOnscreenNative } egl; #endif - gboolean pending_swap_notify; - gboolean pending_set_crtc; - int64_t pending_queue_swap_notify_frame_count; - int64_t pending_swap_notify_frame_count; - MetaRendererView *view; - int total_pending_flips; } MetaOnscreenNative; struct _MetaRendererNative @@ -720,60 +712,6 @@ meta_renderer_native_disconnect (CoglRenderer *cogl_renderer) g_slice_free (CoglRendererEGL, cogl_renderer_egl); } -static void -flush_pending_swap_notify (CoglFramebuffer *framebuffer) -{ - if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) - { - CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); - CoglOnscreenEGL *onscreen_egl = onscreen->winsys; - MetaOnscreenNative *onscreen_native = onscreen_egl->platform; - - if (onscreen_native->pending_swap_notify) - { - CoglFrameInfo *info; - - while ((info = g_queue_peek_head (&onscreen->pending_frame_infos)) && - info->global_frame_counter <= onscreen_native->pending_swap_notify_frame_count) - { - _cogl_onscreen_notify_frame_sync (onscreen, info); - _cogl_onscreen_notify_complete (onscreen, info); - cogl_object_unref (info); - g_queue_pop_head (&onscreen->pending_frame_infos); - } - - onscreen_native->pending_swap_notify = FALSE; - cogl_object_unref (onscreen); - } - } -} - -static void -flush_pending_swap_notify_idle (void *user_data) -{ - CoglContext *cogl_context = user_data; - CoglRendererEGL *cogl_renderer_egl = cogl_context->display->renderer->winsys; - MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform; - MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; - GList *l; - - /* This needs to be disconnected before invoking the callbacks in - * case the callbacks cause it to be queued again */ - _cogl_closure_disconnect (renderer_native->swap_notify_idle); - renderer_native->swap_notify_idle = NULL; - - l = cogl_context->framebuffers; - while (l) - { - GList *next = l->next; - CoglFramebuffer *framebuffer = l->data; - - flush_pending_swap_notify (framebuffer); - - l = next; - } -} - static void free_current_secondary_bo (CoglOnscreen *onscreen) { @@ -801,40 +739,14 @@ free_current_bo (CoglOnscreen *onscreen) static void meta_onscreen_native_queue_swap_notify (CoglOnscreen *onscreen) { - CoglOnscreenEGL *onscreen_egl = onscreen->winsys; - MetaOnscreenNative *onscreen_native = onscreen_egl->platform; - MetaRendererNative *renderer_native = onscreen_native->renderer_native; + CoglFrameInfo *info; - onscreen_native->pending_swap_notify_frame_count = - onscreen_native->pending_queue_swap_notify_frame_count; + g_assert (onscreen->pending_frame_infos.length == 1); - if (onscreen_native->pending_swap_notify) - return; - - /* We only want to notify that the swap is complete when the - * application calls cogl_context_dispatch so instead of - * immediately notifying we queue an idle callback */ - if (!renderer_native->swap_notify_idle) - { - CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); - CoglContext *cogl_context = framebuffer->context; - CoglRenderer *cogl_renderer = cogl_context->display->renderer; - - renderer_native->swap_notify_idle = - _cogl_poll_renderer_add_idle (cogl_renderer, - flush_pending_swap_notify_idle, - cogl_context, - NULL); - } - - /* - * The framebuffer will have its own referenc while the swap notify is - * pending. Otherwise when destroying the view would drop the pending - * notification with if the destruction happens before the idle callback - * is invoked. - */ - cogl_object_ref (onscreen); - onscreen_native->pending_swap_notify = TRUE; + info = g_queue_pop_head (&onscreen->pending_frame_infos); + _cogl_onscreen_notify_frame_sync (onscreen, info); + _cogl_onscreen_notify_complete (onscreen, info); + cogl_object_unref (info); } static gboolean @@ -1147,10 +1059,9 @@ notify_view_crtc_presented (MetaRendererView *view, CoglOnscreenEGL *onscreen_egl = onscreen->winsys; MetaOnscreenNative *onscreen_native = onscreen_egl->platform; MetaRendererNative *renderer_native = onscreen_native->renderer_native; - MetaGpuKms *render_gpu = onscreen_native->render_gpu; CoglFrameInfo *frame_info; MetaCrtc *crtc; - MetaGpuKms *gpu_kms; + MetaRendererNativeGpuData *renderer_gpu_data; /* Only keep the frame info for the fastest CRTC in use, which may not be * the first one to complete a flip. By only telling the compositor about the @@ -1162,35 +1073,21 @@ notify_view_crtc_presented (MetaRendererView *view, crtc = META_CRTC (meta_crtc_kms_from_kms_crtc (kms_crtc)); maybe_update_frame_info (crtc, frame_info, time_ns); - gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); - if (gpu_kms != render_gpu) + + meta_onscreen_native_queue_swap_notify (onscreen); + + renderer_gpu_data = + meta_renderer_native_get_gpu_data (renderer_native, + onscreen_native->render_gpu); + switch (renderer_gpu_data->mode) { - MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state = - onscreen_native->secondary_gpu_state; - - secondary_gpu_state->pending_flips--; - } - - onscreen_native->total_pending_flips--; - if (onscreen_native->total_pending_flips == 0) - { - MetaRendererNativeGpuData *renderer_gpu_data; - - meta_onscreen_native_queue_swap_notify (onscreen); - - renderer_gpu_data = - meta_renderer_native_get_gpu_data (renderer_native, - onscreen_native->render_gpu); - switch (renderer_gpu_data->mode) - { - case META_RENDERER_NATIVE_MODE_GBM: - meta_onscreen_native_swap_drm_fb (onscreen); - break; + case META_RENDERER_NATIVE_MODE_GBM: + meta_onscreen_native_swap_drm_fb (onscreen); + break; #ifdef HAVE_EGL_DEVICE - case META_RENDERER_NATIVE_MODE_EGL_DEVICE: - break; + case META_RENDERER_NATIVE_MODE_EGL_DEVICE: + break; #endif - } } } @@ -1404,10 +1301,6 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, g_object_ref (view), kms_update); - onscreen_native->total_pending_flips++; - if (secondary_gpu_state) - secondary_gpu_state->pending_flips++; - break; #ifdef HAVE_EGL_DEVICE case META_RENDERER_NATIVE_MODE_EGL_DEVICE: @@ -1417,7 +1310,6 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, g_object_ref (view), custom_egl_stream_page_flip, onscreen_native); - onscreen_native->total_pending_flips++; break; #endif } @@ -1485,40 +1377,6 @@ meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen, } } -static void -wait_for_pending_flips (CoglOnscreen *onscreen) -{ - CoglOnscreenEGL *onscreen_egl = onscreen->winsys; - MetaOnscreenNative *onscreen_native = onscreen_egl->platform; - MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; - GError *error = NULL; - - secondary_gpu_state = onscreen_native->secondary_gpu_state; - if (secondary_gpu_state) - { - while (secondary_gpu_state->pending_flips) - { - if (!meta_gpu_kms_wait_for_flip (secondary_gpu_state->gpu_kms, &error)) - { - g_warning ("Failed to wait for flip on secondary GPU: %s", - error->message); - g_clear_error (&error); - break; - } - } - } - - while (onscreen_native->total_pending_flips) - { - if (!meta_gpu_kms_wait_for_flip (onscreen_native->render_gpu, &error)) - { - g_warning ("Failed to wait for flip: %s", error->message); - g_clear_error (&error); - break; - } - } -} - static gboolean import_shared_framebuffer (CoglOnscreen *onscreen, MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state) @@ -2095,15 +1953,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, kms_update = meta_kms_ensure_pending_update (kms); - /* - * Wait for the flip callback before continuing, as we might have started the - * animation earlier due to the animation being driven by some other monitor. - */ - COGL_TRACE_BEGIN (MetaRendererNativeSwapBuffersWait, - "Onscreen (waiting for page flips)"); - wait_for_pending_flips (onscreen); - COGL_TRACE_END (MetaRendererNativeSwapBuffersWait); - update_secondary_gpu_state_pre_swap_buffers (onscreen); parent_vtable->onscreen_swap_buffers_with_damage (onscreen, @@ -2143,9 +1992,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, update_secondary_gpu_state_post_swap_buffers (onscreen, &egl_context_changed); ensure_crtc_modes (onscreen, kms_update); - - onscreen_native->pending_queue_swap_notify_frame_count = - cogl_frame_info_get_global_frame_counter (frame_info); meta_onscreen_native_flip_crtcs (onscreen, kms_update); /* @@ -2315,8 +2161,6 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen, kms_update = meta_kms_ensure_pending_update (kms); - wait_for_pending_flips (onscreen); - renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, render_gpu); @@ -2326,9 +2170,6 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen, g_set_object (&onscreen_native->gbm.next_fb, META_DRM_BUFFER (scanout)); ensure_crtc_modes (onscreen, kms_update); - - onscreen_native->pending_queue_swap_notify_frame_count = - cogl_frame_info_get_global_frame_counter (frame_info); meta_onscreen_native_flip_crtcs (onscreen, kms_update); meta_kms_post_pending_update_sync (kms); diff --git a/src/backends/native/meta-stage-native.c b/src/backends/native/meta-stage-native.c index 4b0551d91..ab519886d 100644 --- a/src/backends/native/meta-stage-native.c +++ b/src/backends/native/meta-stage-native.c @@ -52,86 +52,6 @@ G_DEFINE_TYPE_WITH_CODE (MetaStageNative, meta_stage_native, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW, clutter_stage_window_iface_init)) -static void -frame_cb (CoglOnscreen *onscreen, - CoglFrameEvent frame_event, - CoglFrameInfo *frame_info, - void *user_data) - -{ - MetaStageNative *stage_native = user_data; - ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_native); - int64_t global_frame_counter; - int64_t presented_frame_counter; - ClutterFrameInfo clutter_frame_info; - - global_frame_counter = cogl_frame_info_get_global_frame_counter (frame_info); - - switch (frame_event) - { - case COGL_FRAME_EVENT_SYNC: - presented_frame_counter = stage_native->presented_frame_counter_sync; - stage_native->presented_frame_counter_sync = global_frame_counter; - break; - case COGL_FRAME_EVENT_COMPLETE: - presented_frame_counter = stage_native->presented_frame_counter_complete; - stage_native->presented_frame_counter_complete = global_frame_counter; - break; - default: - g_assert_not_reached (); - } - - if (global_frame_counter <= presented_frame_counter) - return; - - clutter_frame_info = (ClutterFrameInfo) { - .frame_counter = global_frame_counter, - .refresh_rate = cogl_frame_info_get_refresh_rate (frame_info), - .presentation_time = cogl_frame_info_get_presentation_time (frame_info) - }; - - _clutter_stage_cogl_presented (stage_cogl, frame_event, &clutter_frame_info); -} - -static void -ensure_frame_callback (MetaStageNative *stage_native, - ClutterStageView *stage_view) -{ - CoglFramebuffer *framebuffer; - CoglOnscreen *onscreen; - CoglClosure *closure; - - closure = g_object_get_qdata (G_OBJECT (stage_view), - quark_view_frame_closure); - if (closure) - return; - - framebuffer = clutter_stage_view_get_onscreen (stage_view); - onscreen = COGL_ONSCREEN (framebuffer); - closure = cogl_onscreen_add_frame_callback (onscreen, - frame_cb, - stage_native, - NULL); - g_object_set_qdata (G_OBJECT (stage_view), - quark_view_frame_closure, - closure); -} - -static void -ensure_frame_callbacks (MetaStageNative *stage_native) -{ - MetaBackend *backend = meta_get_backend (); - MetaRenderer *renderer = meta_backend_get_renderer (backend); - GList *l; - - for (l = meta_renderer_get_views (renderer); l; l = l->next) - { - ClutterStageView *stage_view = l->data; - - ensure_frame_callback (stage_native, stage_view); - } -} - void meta_stage_native_rebuild_views (MetaStageNative *stage_native) { @@ -141,7 +61,6 @@ meta_stage_native_rebuild_views (MetaStageNative *stage_native) meta_renderer_rebuild_views (renderer); clutter_stage_clear_stage_views (CLUTTER_STAGE (stage)); - ensure_frame_callbacks (stage_native); } static gboolean diff --git a/src/backends/x11/meta-stage-x11.c b/src/backends/x11/meta-stage-x11.c index 13db11fe4..674cd3e47 100644 --- a/src/backends/x11/meta-stage-x11.c +++ b/src/backends/x11/meta-stage-x11.c @@ -247,35 +247,11 @@ meta_stage_x11_unrealize (ClutterStageWindow *stage_window) GINT_TO_POINTER (stage_x11->xwin)); } - if (stage_x11->frame_closure) - { - cogl_onscreen_remove_frame_callback (stage_x11->onscreen, - stage_x11->frame_closure); - stage_x11->frame_closure = NULL; - } - clutter_stage_window_parent_iface->unrealize (stage_window); g_clear_pointer (&stage_x11->onscreen, cogl_object_unref); } -static void -frame_cb (CoglOnscreen *onscreen, - CoglFrameEvent frame_event, - CoglFrameInfo *frame_info, - void *user_data) - -{ - ClutterStageCogl *stage_cogl = user_data; - ClutterFrameInfo clutter_frame_info = { - .frame_counter = cogl_frame_info_get_frame_counter (frame_info), - .presentation_time = cogl_frame_info_get_presentation_time (frame_info), - .refresh_rate = cogl_frame_info_get_refresh_rate (frame_info) - }; - - _clutter_stage_cogl_presented (stage_cogl, frame_event, &clutter_frame_info); -} - static gboolean meta_stage_x11_realize (ClutterStageWindow *stage_window) { @@ -291,12 +267,6 @@ meta_stage_x11_realize (ClutterStageWindow *stage_window) stage_x11->onscreen = cogl_onscreen_new (backend->cogl_context, width, height); - stage_x11->frame_closure = - cogl_onscreen_add_frame_callback (stage_x11->onscreen, - frame_cb, - stage_cogl, - NULL); - if (META_IS_BACKEND_X11_CM (stage_x11->backend)) { MetaRenderer *renderer = meta_backend_get_renderer (stage_x11->backend); diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h index f993ac300..feb60b7e6 100644 --- a/src/compositor/compositor-private.h +++ b/src/compositor/compositor-private.h @@ -23,8 +23,10 @@ struct _MetaCompositorClass gboolean (* manage) (MetaCompositor *compositor, GError **error); void (* unmanage) (MetaCompositor *compositor); - void (* before_paint) (MetaCompositor *compositor); - void (* after_paint) (MetaCompositor *compositor); + void (* before_paint) (MetaCompositor *compositor, + ClutterStageView *stage_view); + void (* after_paint) (MetaCompositor *compositor, + ClutterStageView *stage_view); void (* remove_window) (MetaCompositor *compositor, MetaWindow *window); }; diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index ca4cdfc0c..79c93cf0a 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -139,6 +139,7 @@ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaCompositor, meta_compositor, static void on_presented (ClutterStage *stage, + ClutterStageView *stage_view, ClutterFrameInfo *frame_info, MetaCompositor *compositor); @@ -1034,6 +1035,7 @@ meta_compositor_sync_window_geometry (MetaCompositor *compositor, static void on_presented (ClutterStage *stage, + ClutterStageView *stage_view, ClutterFrameInfo *frame_info, MetaCompositor *compositor) { @@ -1072,34 +1074,42 @@ on_presented (ClutterStage *stage, for (l = priv->windows; l; l = l->next) { ClutterActor *actor = l->data; + GList *actor_stage_views; - meta_window_actor_frame_complete (META_WINDOW_ACTOR (actor), - frame_info, - presentation_time); + actor_stage_views = clutter_actor_peek_stage_views (actor); + if (g_list_find (actor_stage_views, stage_view)) + { + meta_window_actor_frame_complete (META_WINDOW_ACTOR (actor), + frame_info, + presentation_time); + } } } static void -meta_compositor_real_before_paint (MetaCompositor *compositor) +meta_compositor_real_before_paint (MetaCompositor *compositor, + ClutterStageView *stage_view) { MetaCompositorPrivate *priv = meta_compositor_get_instance_private (compositor); GList *l; for (l = priv->windows; l; l = l->next) - meta_window_actor_before_paint (l->data); + meta_window_actor_before_paint (l->data, stage_view); } static void -meta_compositor_before_paint (MetaCompositor *compositor) +meta_compositor_before_paint (MetaCompositor *compositor, + ClutterStageView *stage_view) { COGL_TRACE_BEGIN_SCOPED (MetaCompositorPrePaint, "Compositor (before-paint)"); - META_COMPOSITOR_GET_CLASS (compositor)->before_paint (compositor); + META_COMPOSITOR_GET_CLASS (compositor)->before_paint (compositor, stage_view); } static void -meta_compositor_real_after_paint (MetaCompositor *compositor) +meta_compositor_real_after_paint (MetaCompositor *compositor, + ClutterStageView *stage_view) { MetaCompositorPrivate *priv = meta_compositor_get_instance_private (compositor); @@ -1132,31 +1142,37 @@ meta_compositor_real_after_paint (MetaCompositor *compositor) for (l = priv->windows; l; l = l->next) { ClutterActor *actor = l->data; + GList *actor_stage_views; - meta_window_actor_after_paint (META_WINDOW_ACTOR (actor)); + actor_stage_views = clutter_actor_peek_stage_views (actor); + if (g_list_find (actor_stage_views, stage_view)) + meta_window_actor_after_paint (META_WINDOW_ACTOR (actor), stage_view); } } static void -meta_compositor_after_paint (MetaCompositor *compositor) +meta_compositor_after_paint (MetaCompositor *compositor, + ClutterStageView *stage_view) { COGL_TRACE_BEGIN_SCOPED (MetaCompositorPostPaint, "Compositor (after-paint)"); - META_COMPOSITOR_GET_CLASS (compositor)->after_paint (compositor); + META_COMPOSITOR_GET_CLASS (compositor)->after_paint (compositor, stage_view); } static void -on_before_paint (ClutterStage *stage, - MetaCompositor *compositor) +on_before_paint (ClutterStage *stage, + ClutterStageView *stage_view, + MetaCompositor *compositor) { - meta_compositor_before_paint (compositor); + meta_compositor_before_paint (compositor, stage_view); } static void -on_after_paint (ClutterStage *stage, - MetaCompositor *compositor) +on_after_paint (ClutterStage *stage, + ClutterStageView *stage_view, + MetaCompositor *compositor) { - meta_compositor_after_paint (compositor); + meta_compositor_after_paint (compositor, stage_view); } static void diff --git a/src/compositor/meta-compositor-native.c b/src/compositor/meta-compositor-native.c index 71e3c01b4..92b0aedf9 100644 --- a/src/compositor/meta-compositor-native.c +++ b/src/compositor/meta-compositor-native.c @@ -116,14 +116,15 @@ maybe_assign_primary_plane (MetaCompositor *compositor) } static void -meta_compositor_native_before_paint (MetaCompositor *compositor) +meta_compositor_native_before_paint (MetaCompositor *compositor, + ClutterStageView *stage_view) { MetaCompositorClass *parent_class; maybe_assign_primary_plane (compositor); parent_class = META_COMPOSITOR_CLASS (meta_compositor_native_parent_class); - parent_class->before_paint (compositor); + parent_class->before_paint (compositor, stage_view); } MetaCompositorNative * diff --git a/src/compositor/meta-compositor-x11.c b/src/compositor/meta-compositor-x11.c index 251dee850..fcd292a1f 100644 --- a/src/compositor/meta-compositor-x11.c +++ b/src/compositor/meta-compositor-x11.c @@ -293,8 +293,9 @@ out: } static void -on_before_update (ClutterStage *stage, - MetaCompositor *compositor) +on_before_update (ClutterStage *stage, + ClutterStageView *stage_view, + MetaCompositor *compositor) { MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); @@ -330,7 +331,8 @@ on_before_update (ClutterStage *stage, } static void -meta_compositor_x11_before_paint (MetaCompositor *compositor) +meta_compositor_x11_before_paint (MetaCompositor *compositor, + ClutterStageView *stage_view) { MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); MetaCompositorClass *parent_class; @@ -338,11 +340,12 @@ meta_compositor_x11_before_paint (MetaCompositor *compositor) maybe_unredirect_top_window (compositor_x11); parent_class = META_COMPOSITOR_CLASS (meta_compositor_x11_parent_class); - parent_class->before_paint (compositor); + parent_class->before_paint (compositor, stage_view); } static void -meta_compositor_x11_after_paint (MetaCompositor *compositor) +meta_compositor_x11_after_paint (MetaCompositor *compositor, + ClutterStageView *stage_view) { MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); MetaCompositorClass *parent_class; @@ -356,7 +359,7 @@ meta_compositor_x11_after_paint (MetaCompositor *compositor) } parent_class = META_COMPOSITOR_CLASS (meta_compositor_x11_parent_class); - parent_class->after_paint (compositor); + parent_class->after_paint (compositor, stage_view); } static void diff --git a/src/compositor/meta-later.c b/src/compositor/meta-later.c index 9265f2e44..dff091d75 100644 --- a/src/compositor/meta-later.c +++ b/src/compositor/meta-later.c @@ -165,8 +165,9 @@ run_repaint_laters (GSList **laters_list) } static void -on_before_update (ClutterStage *stage, - MetaLaters *laters) +on_before_update (ClutterStage *stage, + ClutterStageView *stage_view, + MetaLaters *laters) { unsigned int i; GSList *l; diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h index 4d0091f27..57dbd0ad0 100644 --- a/src/compositor/meta-window-actor-private.h +++ b/src/compositor/meta-window-actor-private.h @@ -23,8 +23,10 @@ struct _MetaWindowActorClass void (*queue_frame_drawn) (MetaWindowActor *actor, gboolean skip_sync_delay); - void (*before_paint) (MetaWindowActor *actor); - void (*after_paint) (MetaWindowActor *actor); + void (*before_paint) (MetaWindowActor *actor, + ClutterStageView *stage_view); + void (*after_paint) (MetaWindowActor *actor, + ClutterStageView *stage_view); void (*queue_destroy) (MetaWindowActor *actor); void (*set_frozen) (MetaWindowActor *actor, @@ -50,8 +52,10 @@ void meta_window_actor_size_change (MetaWindowActor *self, MetaRectangle *old_frame_rect, MetaRectangle *old_buffer_rect); -void meta_window_actor_before_paint (MetaWindowActor *self); -void meta_window_actor_after_paint (MetaWindowActor *self); +void meta_window_actor_before_paint (MetaWindowActor *self, + ClutterStageView *stage_view); +void meta_window_actor_after_paint (MetaWindowActor *self, + ClutterStageView *stage_view); void meta_window_actor_frame_complete (MetaWindowActor *self, ClutterFrameInfo *frame_info, gint64 presentation_time); diff --git a/src/compositor/meta-window-actor-wayland.c b/src/compositor/meta-window-actor-wayland.c index c41d85f33..a287fdcba 100644 --- a/src/compositor/meta-window-actor-wayland.c +++ b/src/compositor/meta-window-actor-wayland.c @@ -119,12 +119,14 @@ meta_window_actor_wayland_queue_frame_drawn (MetaWindowActor *actor, } static void -meta_window_actor_wayland_before_paint (MetaWindowActor *actor) +meta_window_actor_wayland_before_paint (MetaWindowActor *actor, + ClutterStageView *stage_view) { } static void -meta_window_actor_wayland_after_paint (MetaWindowActor *actor) +meta_window_actor_wayland_after_paint (MetaWindowActor *actor, + ClutterStageView *stage_view) { } diff --git a/src/compositor/meta-window-actor-x11.c b/src/compositor/meta-window-actor-x11.c index b79e014d1..a2bc1d939 100644 --- a/src/compositor/meta-window-actor-x11.c +++ b/src/compositor/meta-window-actor-x11.c @@ -25,6 +25,7 @@ #include "compositor/meta-window-actor-x11.h" #include "backends/meta-logical-monitor.h" +#include "clutter/clutter-frame-clock.h" #include "compositor/compositor-private.h" #include "compositor/meta-cullable.h" #include "compositor/meta-shaped-texture-private.h" @@ -58,6 +59,8 @@ struct _MetaWindowActorX11 guint send_frame_messages_timer; int64_t frame_drawn_time; + gboolean pending_schedule_update_now; + ClutterFrameClock *frame_clock; gulong repaint_scheduled_id; gulong size_changed_id; @@ -372,8 +375,8 @@ meta_window_actor_x11_frame_complete (MetaWindowActor *actor, g_warning ("%s: Frame has assigned frame counter but no frame drawn time", window->desc); if (G_UNLIKELY (frame->frame_counter < frame_counter)) - g_warning ("%s: frame_complete callback never occurred for frame %" G_GINT64_FORMAT, - window->desc, frame->frame_counter); + g_debug ("%s: frame_complete callback never occurred for frame %" G_GINT64_FORMAT, + window->desc, frame->frame_counter); actor_x11->frames = g_list_delete_link (actor_x11->frames, l); send_frame_timings (actor_x11, frame, frame_info, presentation_time); @@ -451,8 +454,10 @@ meta_window_actor_x11_queue_frame_drawn (MetaWindowActor *actor, if (skip_sync_delay) { - ClutterActor *stage = clutter_actor_get_stage (CLUTTER_ACTOR (actor_x11)); - clutter_stage_skip_sync_delay (CLUTTER_STAGE (stage)); + if (actor_x11->frame_clock) + clutter_frame_clock_schedule_update_now (actor_x11->frame_clock); + else + actor_x11->pending_schedule_update_now = TRUE; } if (!actor_x11->repaint_scheduled) @@ -473,9 +478,11 @@ meta_window_actor_x11_queue_frame_drawn (MetaWindowActor *actor, * before_paint/after_paint functions get called, enabling us to * send a _NET_WM_FRAME_DRAWN. We do a 1-pixel redraw to get * consistent timing with non-empty frames. If the window - * is completely obscured we fire off the send_frame_messages timeout. + * is completely obscured, or completely off screen we fire off the + * send_frame_messages timeout. */ - if (is_obscured) + if (is_obscured || + !clutter_actor_peek_stage_views (CLUTTER_ACTOR (actor))) { queue_send_frame_messages_timeout (actor_x11); } @@ -1226,7 +1233,21 @@ handle_updates (MetaWindowActorX11 *actor_x11) } static void -meta_window_actor_x11_before_paint (MetaWindowActor *actor) +handle_stage_views_changed (MetaWindowActorX11 *actor_x11) +{ + ClutterActor *actor = CLUTTER_ACTOR (actor_x11); + + actor_x11->frame_clock = clutter_actor_pick_frame_clock (actor); + if (actor_x11->frame_clock && actor_x11->pending_schedule_update_now) + { + clutter_frame_clock_schedule_update_now (actor_x11->frame_clock); + actor_x11->pending_schedule_update_now = FALSE; + } +} + +static void +meta_window_actor_x11_before_paint (MetaWindowActor *actor, + ClutterStageView *stage_view) { MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor); @@ -1304,7 +1325,8 @@ meta_window_actor_x11_paint (ClutterActor *actor, } static void -meta_window_actor_x11_after_paint (MetaWindowActor *actor) +meta_window_actor_x11_after_paint (MetaWindowActor *actor, + ClutterStageView *stage_view) { MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor); MetaWindow *window; @@ -1641,6 +1663,9 @@ meta_window_actor_x11_init (MetaWindowActorX11 *self) /* We do this now since we might be going right back into the frozen state. */ g_signal_connect (self, "thawed", G_CALLBACK (handle_updates), NULL); + g_signal_connect (self, "stage-views-changed", + G_CALLBACK (handle_stage_views_changed), NULL); + self->shadow_factory = meta_shadow_factory_get_default (); self->shadow_factory_changed_handler_id = g_signal_connect_swapped (self->shadow_factory, diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index 5e4b07ab6..8d2548fbb 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -1021,21 +1021,23 @@ meta_window_actor_sync_visibility (MetaWindowActor *self) } void -meta_window_actor_before_paint (MetaWindowActor *self) +meta_window_actor_before_paint (MetaWindowActor *self, + ClutterStageView *stage_view) { if (meta_window_actor_is_destroyed (self)) return; - META_WINDOW_ACTOR_GET_CLASS (self)->before_paint (self); + META_WINDOW_ACTOR_GET_CLASS (self)->before_paint (self, stage_view); } void -meta_window_actor_after_paint (MetaWindowActor *self) +meta_window_actor_after_paint (MetaWindowActor *self, + ClutterStageView *stage_view) { MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self); - META_WINDOW_ACTOR_GET_CLASS (self)->after_paint (self); + META_WINDOW_ACTOR_GET_CLASS (self)->after_paint (self, stage_view); if (meta_window_actor_is_destroyed (self)) return; diff --git a/src/tests/clutter/conform/actor-clone.c b/src/tests/clutter/conform/actor-clone.c index 6a27c5199..582ddbbf3 100644 --- a/src/tests/clutter/conform/actor-clone.c +++ b/src/tests/clutter/conform/actor-clone.c @@ -7,6 +7,7 @@ static void on_presented (ClutterStage *stage, + ClutterStageView *view, ClutterFrameInfo *frame_info, gboolean *was_presented) { diff --git a/src/tests/stage-view-tests.c b/src/tests/stage-view-tests.c index 76da1db45..65bfe52bd 100644 --- a/src/tests/stage-view-tests.c +++ b/src/tests/stage-view-tests.c @@ -121,8 +121,9 @@ meta_test_stage_views_exist (void) } static void -on_after_paint (ClutterStage *stage, - gboolean *was_painted) +on_after_paint (ClutterStage *stage, + ClutterStageView *view, + gboolean *was_painted) { *was_painted = TRUE; } diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index 30d3979ba..705b37c19 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -196,6 +196,7 @@ meta_wayland_compositor_update (MetaWaylandCompositor *compositor, static void on_after_update (ClutterStage *stage, + ClutterStageView *stage_view, MetaWaylandCompositor *compositor) { GList *l; @@ -209,6 +210,7 @@ on_after_update (ClutterStage *stage, GList *l_cur = l; MetaWaylandSurface *surface = l->data; MetaSurfaceActor *actor; + GList *stage_views; MetaWaylandActorSurface *actor_surface; l = l->next; @@ -221,6 +223,10 @@ on_after_update (ClutterStage *stage, meta_surface_actor_is_obscured (actor)) continue; + stage_views = clutter_actor_peek_stage_views (CLUTTER_ACTOR (actor)); + if (!g_list_find (stage_views, stage_view)) + continue; + actor_surface = META_WAYLAND_ACTOR_SURFACE (surface->role); meta_wayland_actor_surface_emit_frame_callbacks (actor_surface, now_us / 1000);