From 0899d023776823e18e462b297db10fdcf9431c1b Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Thu, 23 Nov 2017 19:00:28 +0000 Subject: [PATCH] Avoid allocations when generating RadarSignatureCells. The RadarWidget can supply a reusable buffer to each trait to avoid individual traits having to return new enumerables. Additionally, this allows the two traits to avoid LINQ and further allocations as they can manually enumerate and populate the buffer themselves. --- .../Traits/Radar/AppearsOnRadar.cs | 19 ++++++------------- .../Traits/World/EditorActorLayer.cs | 6 ++++-- OpenRA.Mods.Common/TraitsInterfaces.cs | 2 +- OpenRA.Mods.Common/Widgets/RadarWidget.cs | 7 ++++++- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/OpenRA.Mods.Common/Traits/Radar/AppearsOnRadar.cs b/OpenRA.Mods.Common/Traits/Radar/AppearsOnRadar.cs index e23d141c55..344c037125 100644 --- a/OpenRA.Mods.Common/Traits/Radar/AppearsOnRadar.cs +++ b/OpenRA.Mods.Common/Traits/Radar/AppearsOnRadar.cs @@ -30,12 +30,8 @@ namespace OpenRA.Mods.Common.Traits.Radar public class AppearsOnRadar : ConditionalTrait, IRadarSignature { - static readonly IEnumerable> NoCells = Enumerable.Empty>(); IRadarColorModifier modifier; - Color currentColor = Color.Transparent; - Func, Pair> cellToSignature; - public AppearsOnRadar(AppearsOnRadarInfo info) : base(info) { } @@ -45,27 +41,24 @@ namespace OpenRA.Mods.Common.Traits.Radar modifier = self.TraitsImplementing().FirstOrDefault(); } - public IEnumerable> RadarSignatureCells(Actor self) + public void PopulateRadarSignatureCells(Actor self, List> destinationBuffer) { var viewer = self.World.RenderPlayer ?? self.World.LocalPlayer; if (IsTraitDisabled || (viewer != null && !Info.ValidStances.HasStance(self.Owner.Stances[viewer]))) - return NoCells; + return; var color = Game.Settings.Game.UsePlayerStanceColors ? self.Owner.PlayerStanceColor(self) : self.Owner.Color.RGB; if (modifier != null) color = modifier.RadarColorOverride(self, color); if (Info.UseLocation) - return new[] { Pair.New(self.Location, color) }; - - // PERF: Cache cellToSignature delegate to avoid allocations as color does not change often. - if (currentColor != color) { - currentColor = color; - cellToSignature = c => Pair.New(c.First, color); + destinationBuffer.Add(Pair.New(self.Location, color)); + return; } - return self.OccupiesSpace.OccupiedCells().Select(cellToSignature); + foreach (var cell in self.OccupiesSpace.OccupiedCells()) + destinationBuffer.Add(Pair.New(cell.First, color)); } } } \ No newline at end of file diff --git a/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs b/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs index c8d8b83765..7e9e18ee33 100644 --- a/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs @@ -272,9 +272,11 @@ namespace OpenRA.Mods.Common.Traits return nodes; } - public IEnumerable> RadarSignatureCells(Actor self) + public void PopulateRadarSignatureCells(Actor self, List> destinationBuffer) { - return cellMap.SelectMany(c => c.Value.Select(p => Pair.New(c.Key, p.Owner.Color.RGB))); + foreach (var previewsForCell in cellMap) + foreach (var preview in previewsForCell.Value) + destinationBuffer.Add(Pair.New(previewsForCell.Key, preview.Owner.Color.RGB)); } } } diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index e63781d448..d51bdee682 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -354,7 +354,7 @@ namespace OpenRA.Mods.Common.Traits public interface IRadarSignature { - IEnumerable> RadarSignatureCells(Actor self); + void PopulateRadarSignatureCells(Actor self, List> destinationBuffer); } public interface IRadarColorModifier { Color RadarColorOverride(Actor self, Color color); } diff --git a/OpenRA.Mods.Common/Widgets/RadarWidget.cs b/OpenRA.Mods.Common/Widgets/RadarWidget.cs index c12f51938d..bdaf4c8d7d 100644 --- a/OpenRA.Mods.Common/Widgets/RadarWidget.cs +++ b/OpenRA.Mods.Common/Widgets/RadarWidget.cs @@ -15,6 +15,7 @@ using System.Drawing; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; +using OpenRA.Primitives; using OpenRA.Traits; using OpenRA.Widgets; @@ -361,6 +362,8 @@ namespace OpenRA.Mods.Common.Widgets var stride = radarSheet.Size.Width; Array.Clear(radarData, 4 * actorSprite.Bounds.Top * stride, 4 * actorSprite.Bounds.Height * stride); + var cells = new List>(); + unsafe { fixed (byte* colorBytes = &radarData[0]) @@ -372,7 +375,9 @@ namespace OpenRA.Mods.Common.Widgets if (!t.Actor.IsInWorld || world.FogObscures(t.Actor)) continue; - foreach (var cell in t.Trait.RadarSignatureCells(t.Actor)) + cells.Clear(); + t.Trait.PopulateRadarSignatureCells(t.Actor, cells); + foreach (var cell in cells) { if (!world.Map.Contains(cell.First)) continue;