diff --git a/osu.Framework/Graphics/Containers/Container.cs b/osu.Framework/Graphics/Containers/Container.cs index 2d2b7e0161..6aa740f788 100644 --- a/osu.Framework/Graphics/Containers/Container.cs +++ b/osu.Framework/Graphics/Containers/Container.cs @@ -20,6 +20,8 @@ using System.Linq; using osu.Framework.Extensions.TypeExtensions; using osu.Framework.MathUtils; +using osu.Framework.Threading; +using osu.Framework.Statistics; namespace osu.Framework.Graphics.Containers { @@ -91,11 +93,19 @@ private void loadChild(Drawable child) child.Parent = this; } + protected override void LoadComplete() + { + schedulerAfterChildren?.SetCurrentThread(MainThread); + base.LoadComplete(); + } + protected override void Dispose(bool isDisposing) { InternalChildren?.ForEach(c => c.Dispose()); OnAutoSize = null; + schedulerAfterChildren?.Dispose(); + schedulerAfterChildren = null; base.Dispose(isDisposing); } @@ -339,6 +349,10 @@ protected void AddInternal(IEnumerable range) #region Updating (per-frame periodic) + private Scheduler schedulerAfterChildren; + + protected Scheduler SchedulerAfterChildren => schedulerAfterChildren ?? (schedulerAfterChildren = new Scheduler(MainThread)); + /// /// Updates the life status of according to their /// property. @@ -388,6 +402,11 @@ public override bool UpdateSubTree() foreach (Drawable child in internalChildren.AliveItems) if (child.IsLoaded) child.UpdateSubTree(); + if (schedulerAfterChildren != null) + { + int amountScheduledTasks = schedulerAfterChildren.Update(); + FrameStatistics.Increment(StatisticsCounterType.ScheduleInvk, amountScheduledTasks); + } UpdateAfterChildren(); updateChildrenSizeDependencies(); @@ -613,6 +632,8 @@ public override Drawable Delay(double duration, bool propagateChildren = false) return this; } + public ScheduledDelegate ScheduleAfterChildren(Action action) => SchedulerAfterChildren.AddDelayed(action, TransformDelay); + public override void Flush(bool propagateChildren = false, Type flushType = null) { base.Flush(propagateChildren, flushType); diff --git a/osu.Framework/Graphics/Drawable.cs b/osu.Framework/Graphics/Drawable.cs index 10b6432435..4ef17ef872 100644 --- a/osu.Framework/Graphics/Drawable.cs +++ b/osu.Framework/Graphics/Drawable.cs @@ -210,8 +210,8 @@ private bool loadComplete() { if (loadState < LoadState.Loaded) return false; - mainThread = Thread.CurrentThread; - scheduler?.SetCurrentThread(mainThread); + MainThread = Thread.CurrentThread; + scheduler?.SetCurrentThread(MainThread); Invalidate(); loadState = LoadState.Alive; @@ -314,13 +314,13 @@ public virtual int Compare(Drawable x, Drawable y) internal event Action OnInvalidate; private Scheduler scheduler; - private Thread mainThread; + internal Thread MainThread { get; private set; } /// /// A lazily-initialized scheduler used to schedule tasks to be invoked in future s calls. /// The tasks are invoked at the beginning of the method before anything else. /// - protected Scheduler Scheduler => scheduler ?? (scheduler = new Scheduler(mainThread)); + protected Scheduler Scheduler => scheduler ?? (scheduler = new Scheduler(MainThread)); private LifetimeList transforms; @@ -377,7 +377,7 @@ public virtual bool UpdateSubTree() if (loadState < LoadState.Alive) if (!loadComplete()) return false; - transformDelay = 0; + TransformDelay = 0; //todo: this should be moved to after the IsVisible condition once we have TOL for transforms (and some better logic). updateTransforms(); @@ -1931,7 +1931,7 @@ public IMouseState Clone() #region Transforms - private double transformDelay; + internal double TransformDelay { get; private set; } public virtual void ClearTransforms(bool propagateChildren = false) { @@ -1943,11 +1943,11 @@ public virtual Drawable Delay(double duration, bool propagateChildren = false) { if (duration == 0) return this; - transformDelay += duration; + TransformDelay += duration; return this; } - public ScheduledDelegate Schedule(Action action) => Scheduler.AddDelayed(action, transformDelay); + public ScheduledDelegate Schedule(Action action) => Scheduler.AddDelayed(action, TransformDelay); /// /// Flush specified transforms, using the last available values (ignoring current clock time). @@ -1979,7 +1979,7 @@ public virtual void Flush(bool propagateChildren = false, Type flushType = null) public virtual Drawable DelayReset() { - Delay(-transformDelay); + Delay(-TransformDelay); return this; } @@ -2000,14 +2000,14 @@ public virtual Drawable DelayReset() /// Absolute sequences should never be nested inside another existing sequence. public TransformSequence BeginAbsoluteSequence(double startOffset = 0, bool recursive = false) { - if (transformDelay != 0) throw new InvalidOperationException($"Cannot use {nameof(BeginAbsoluteSequence)} with a non-zero transform delay already present"); + if (TransformDelay != 0) throw new InvalidOperationException($"Cannot use {nameof(BeginAbsoluteSequence)} with a non-zero transform delay already present"); return new TransformSequence(this, -(Clock?.CurrentTime ?? 0) + startOffset, recursive); } public void Loop(float delay = 0) { foreach (var t in Transforms) - t.Loop(Math.Max(0, transformDelay + delay - t.Duration)); + t.Loop(Math.Max(0, TransformDelay + delay - t.Duration)); } /// @@ -2069,7 +2069,7 @@ public virtual void Show() /// /// The time to use for starting transforms which support /// - protected double TransformStartTime => (Clock?.CurrentTime ?? 0) + transformDelay; + protected double TransformStartTime => (Clock?.CurrentTime ?? 0) + TransformDelay; public void TransformTo(Func currentValue, TValue newValue, double duration, EasingTypes easing, Transform transform) where TValue : struct, IEquatable { @@ -2087,7 +2087,7 @@ public virtual void Show() TValue startValue = currentValue(); - if (transformDelay == 0) + if (TransformDelay == 0) { Transforms.RemoveAll(t => t.GetType() == type); @@ -2124,7 +2124,7 @@ private void addTransform(ITransform transform) } //we have no duration and do not need to be delayed, so we can just apply ourselves and be gone. - bool canApplyInstant = transform.Duration == 0 && transformDelay == 0; + bool canApplyInstant = transform.Duration == 0 && TransformDelay == 0; //we should also immediately apply any transforms that have already started to avoid potentially applying them one frame too late. if (canApplyInstant || transform.StartTime < Time.Current)