mirror of
https://github.com/ppy/osu.git
synced 2025-01-28 14:12:55 +08:00
Reduce number of redundant control points displayed on summary timeline
As pointed out in https://github.com/ppy/osu/discussions/16435, beatmaps with too many control points (usually added via external automation apps) could cause the lazer editor to grind to a halt. The overheads here are mostly from the GL side. An eventual goal would be to render this in a smarter way, rather than using thousands of drawables. Until that, this optimisation should help reduce the overhead by omitting control points in close proximity that are redundant for display purposes. I've tried to contain this in the display logic directly, with the goal that it can be ripped out as fast as it was added. Certainly required more changes than I hoped for, but I don't think it's too ugly.
This commit is contained in:
parent
70f56cd0c9
commit
c64a919a9d
@ -31,7 +31,16 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
||||
|
||||
case NotifyCollectionChangedAction.Add:
|
||||
foreach (var group in args.NewItems.OfType<ControlPointGroup>())
|
||||
{
|
||||
// as an optimisation, don't add a visualisation if there are already groups with the same types in close proximity.
|
||||
// for newly added control points (ie. lazer editor first where group is added empty) we always skip for simplicity.
|
||||
// that is fine, because cases where this is causing a performance issue are mostly where external tools were used to create an insane number of points.
|
||||
// if (Children.Any(g => Math.Abs(g.Group.Time - group.Time) < 1000 && g.IsRedundant(group)))
|
||||
// continue;
|
||||
|
||||
Add(new GroupVisualisation(group));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
@ -39,7 +48,20 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
||||
{
|
||||
var matching = Children.SingleOrDefault(gv => gv.Group == group);
|
||||
|
||||
matching?.Expire();
|
||||
if (matching != null)
|
||||
matching.Expire();
|
||||
else
|
||||
{
|
||||
// due to the add optimisation above, if a point is deleted which wasn't being displayed we need to recreate all points
|
||||
// to guarantee an accurate representation.
|
||||
//
|
||||
// note that the case where control point (type) is added or removed from a non-displayed group is not handled correctly.
|
||||
// this is an edge case which shouldn't affect the user too badly. we may flatted control point groups in the future
|
||||
// which would allow this to be handled better.
|
||||
Clear();
|
||||
foreach (var g in controlPointGroups)
|
||||
Add(new GroupVisualisation(g));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -9,7 +9,7 @@ using osu.Game.Screens.Edit.Components.Timelines.Summary.Visualisations;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
||||
{
|
||||
public class ControlPointVisualisation : PointVisualisation
|
||||
public class ControlPointVisualisation : PointVisualisation, IControlPointVisualisationRedundant
|
||||
{
|
||||
protected readonly ControlPoint Point;
|
||||
|
||||
@ -26,5 +26,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
||||
{
|
||||
Colour = Point.GetRepresentingColour(colours);
|
||||
}
|
||||
|
||||
public bool IsRedundant(ControlPoint other) => other.GetType() == Point.GetType();
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ using osu.Game.Screens.Edit.Components.Timelines.Summary.Visualisations;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
||||
{
|
||||
public class EffectPointVisualisation : CompositeDrawable
|
||||
public class EffectPointVisualisation : CompositeDrawable, IControlPointVisualisationRedundant
|
||||
{
|
||||
private readonly EffectControlPoint effect;
|
||||
private Bindable<bool> kiai;
|
||||
@ -68,5 +68,8 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
// kiai sections display duration, so are required to be visualised.
|
||||
public bool IsRedundant(ControlPoint other) => (other as EffectControlPoint)?.KiaiMode == effect.KiaiMode;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -23,12 +24,8 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
||||
|
||||
Group = group;
|
||||
X = (float)group.Time;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
// Run in constructor so IsRedundant calls can work correctly.
|
||||
controlPoints.BindTo(Group.ControlPoints);
|
||||
controlPoints.BindCollectionChanged((_, __) =>
|
||||
{
|
||||
@ -60,5 +57,13 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For display purposes, check whether the proposed group is made redundant by this visualisation group.
|
||||
/// </summary>
|
||||
/// <param name="other"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsRedundant(ControlPointGroup other) =>
|
||||
other.ControlPoints.Any(c => InternalChildren.OfType<IControlPointVisualisationRedundant>().Any(c2 => c2.IsRedundant(c)));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
||||
{
|
||||
public interface IControlPointVisualisationRedundant
|
||||
{
|
||||
bool IsRedundant(ControlPoint other);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user