Refactor WorldRenderer to use less allocations
This commit is contained in:
@@ -43,6 +43,8 @@ namespace OpenRA.Graphics
|
|||||||
readonly List<IFinalizedRenderable> preparedOverlayRenderables = new List<IFinalizedRenderable>();
|
readonly List<IFinalizedRenderable> preparedOverlayRenderables = new List<IFinalizedRenderable>();
|
||||||
readonly List<IFinalizedRenderable> preparedAnnotationRenderables = new List<IFinalizedRenderable>();
|
readonly List<IFinalizedRenderable> preparedAnnotationRenderables = new List<IFinalizedRenderable>();
|
||||||
|
|
||||||
|
readonly List<IRenderable> renderablesBuffer = new List<IRenderable>();
|
||||||
|
|
||||||
bool lastDepthPreviewEnabled;
|
bool lastDepthPreviewEnabled;
|
||||||
|
|
||||||
internal WorldRenderer(ModData modData, World world)
|
internal WorldRenderer(ModData modData, World world)
|
||||||
@@ -107,78 +109,117 @@ namespace OpenRA.Graphics
|
|||||||
palettes[name].Palette = pal;
|
palettes[name].Palette = pal;
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<IFinalizedRenderable> GenerateRenderables()
|
// PERF: Avoid LINQ.
|
||||||
|
void GenerateRenderables()
|
||||||
{
|
{
|
||||||
var actors = onScreenActors.Append(World.WorldActor);
|
foreach (var actor in onScreenActors)
|
||||||
if (World.RenderPlayer != null)
|
renderablesBuffer.AddRange(actor.Render(this));
|
||||||
actors = actors.Append(World.RenderPlayer.PlayerActor);
|
|
||||||
|
renderablesBuffer.AddRange(World.WorldActor.Render(this));
|
||||||
|
|
||||||
|
if (World.RenderPlayer != null)
|
||||||
|
renderablesBuffer.AddRange(World.RenderPlayer.PlayerActor.Render(this));
|
||||||
|
|
||||||
var worldRenderables = actors.SelectMany(a => a.Render(this));
|
|
||||||
if (World.OrderGenerator != null)
|
if (World.OrderGenerator != null)
|
||||||
worldRenderables = worldRenderables.Concat(World.OrderGenerator.Render(this, World));
|
renderablesBuffer.AddRange(World.OrderGenerator.Render(this, World));
|
||||||
|
|
||||||
// Unpartitioned effects
|
// Unpartitioned effects
|
||||||
worldRenderables = worldRenderables.Concat(World.UnpartitionedEffects.SelectMany(e => e.Render(this)));
|
foreach (var e in World.UnpartitionedEffects)
|
||||||
|
renderablesBuffer.AddRange(e.Render(this));
|
||||||
|
|
||||||
// Partitioned, currently on-screen effects
|
// Partitioned, currently on-screen effects
|
||||||
var effectRenderables = World.ScreenMap.RenderableEffectsInBox(Viewport.TopLeft, Viewport.BottomRight);
|
foreach (var e in World.ScreenMap.RenderableEffectsInBox(Viewport.TopLeft, Viewport.BottomRight))
|
||||||
worldRenderables = worldRenderables.Concat(effectRenderables.SelectMany(e => e.Render(this)));
|
renderablesBuffer.AddRange(e.Render(this));
|
||||||
|
|
||||||
worldRenderables = worldRenderables.OrderBy(RenderableScreenZPositionComparisonKey);
|
foreach (var renderable in renderablesBuffer.OrderBy(RenderableScreenZPositionComparisonKey))
|
||||||
|
preparedRenderables.Add(renderable.PrepareRender(this));
|
||||||
|
|
||||||
return worldRenderables.Select(r => r.PrepareRender(this));
|
// PERF: Reuse collection to avoid allocations.
|
||||||
|
renderablesBuffer.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<IFinalizedRenderable> GenerateOverlayRenderables()
|
// PERF: Avoid LINQ.
|
||||||
|
void GenerateOverlayRenderables()
|
||||||
{
|
{
|
||||||
var actors = World.ActorsWithTrait<IRenderAboveShroud>()
|
foreach (var a in World.ActorsWithTrait<IRenderAboveShroud>())
|
||||||
.Where(a => a.Actor.IsInWorld && !a.Actor.Disposed && (!a.Trait.SpatiallyPartitionable || onScreenActors.Contains(a.Actor)))
|
{
|
||||||
.SelectMany(a => a.Trait.RenderAboveShroud(a.Actor, this));
|
if (!a.Actor.IsInWorld || a.Actor.Disposed || (a.Trait.SpatiallyPartitionable && !onScreenActors.Contains(a.Actor)))
|
||||||
|
continue;
|
||||||
|
|
||||||
var selected = World.Selection.Actors.Where(a => a.IsInWorld && !a.Disposed)
|
foreach (var renderable in a.Trait.RenderAboveShroud(a.Actor, this))
|
||||||
.SelectMany(a => a.TraitsImplementing<IRenderAboveShroudWhenSelected>()
|
preparedOverlayRenderables.Add(renderable.PrepareRender(this));
|
||||||
.Where(t => !t.SpatiallyPartitionable || onScreenActors.Contains(a))
|
}
|
||||||
.SelectMany(t => t.RenderAboveShroud(a, this)));
|
|
||||||
|
|
||||||
var effects = World.Effects.Select(e => e as IEffectAboveShroud)
|
foreach (var a in World.Selection.Actors)
|
||||||
.Where(e => e != null)
|
{
|
||||||
.SelectMany(e => e.RenderAboveShroud(this));
|
if (!a.IsInWorld || a.Disposed)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var t in a.TraitsImplementing<IRenderAboveShroudWhenSelected>())
|
||||||
|
{
|
||||||
|
if (t.SpatiallyPartitionable && !onScreenActors.Contains(a))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var renderable in t.RenderAboveShroud(a, this))
|
||||||
|
preparedOverlayRenderables.Add(renderable.PrepareRender(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var e in World.Effects)
|
||||||
|
{
|
||||||
|
var ea = e as IEffectAboveShroud;
|
||||||
|
if (ea == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var renderable in ea.RenderAboveShroud(this))
|
||||||
|
preparedOverlayRenderables.Add(renderable.PrepareRender(this));
|
||||||
|
}
|
||||||
|
|
||||||
var orderGenerator = SpriteRenderable.None;
|
|
||||||
if (World.OrderGenerator != null)
|
if (World.OrderGenerator != null)
|
||||||
orderGenerator = World.OrderGenerator.RenderAboveShroud(this, World);
|
foreach (var renderable in World.OrderGenerator.RenderAboveShroud(this, World))
|
||||||
|
preparedOverlayRenderables.Add(renderable.PrepareRender(this));
|
||||||
return actors
|
|
||||||
.Concat(selected)
|
|
||||||
.Concat(effects)
|
|
||||||
.Concat(orderGenerator)
|
|
||||||
.Select(r => r.PrepareRender(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<IFinalizedRenderable> GenerateAnnotationRenderables()
|
// PERF: Avoid LINQ.
|
||||||
|
void GenerateAnnotationRenderables()
|
||||||
{
|
{
|
||||||
var actors = World.ActorsWithTrait<IRenderAnnotations>()
|
foreach (var a in World.ActorsWithTrait<IRenderAnnotations>())
|
||||||
.Where(a => a.Actor.IsInWorld && !a.Actor.Disposed && (!a.Trait.SpatiallyPartitionable || onScreenActors.Contains(a.Actor)))
|
{
|
||||||
.SelectMany(a => a.Trait.RenderAnnotations(a.Actor, this));
|
if (!a.Actor.IsInWorld || a.Actor.Disposed || (a.Trait.SpatiallyPartitionable && !onScreenActors.Contains(a.Actor)))
|
||||||
|
continue;
|
||||||
|
|
||||||
var selected = World.Selection.Actors.Where(a => a.IsInWorld && !a.Disposed)
|
foreach (var renderAnnotation in a.Trait.RenderAnnotations(a.Actor, this))
|
||||||
.SelectMany(a => a.TraitsImplementing<IRenderAnnotationsWhenSelected>()
|
preparedAnnotationRenderables.Add(renderAnnotation.PrepareRender(this));
|
||||||
.Where(t => !t.SpatiallyPartitionable || onScreenActors.Contains(a))
|
}
|
||||||
.SelectMany(t => t.RenderAnnotations(a, this)));
|
|
||||||
|
|
||||||
var effects = World.Effects.Select(e => e as IEffectAnnotation)
|
foreach (var a in World.Selection.Actors)
|
||||||
.Where(e => e != null)
|
{
|
||||||
.SelectMany(e => e.RenderAnnotation(this));
|
if (!a.IsInWorld || a.Disposed)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var t in a.TraitsImplementing<IRenderAnnotationsWhenSelected>())
|
||||||
|
{
|
||||||
|
if (t.SpatiallyPartitionable && !onScreenActors.Contains(a))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var renderAnnotation in t.RenderAnnotations(a, this))
|
||||||
|
preparedAnnotationRenderables.Add(renderAnnotation.PrepareRender(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var e in World.Effects)
|
||||||
|
{
|
||||||
|
var ea = e as IEffectAnnotation;
|
||||||
|
if (ea == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var renderAnnotation in ea.RenderAnnotation(this))
|
||||||
|
preparedAnnotationRenderables.Add(renderAnnotation.PrepareRender(this));
|
||||||
|
}
|
||||||
|
|
||||||
var orderGenerator = SpriteRenderable.None;
|
|
||||||
if (World.OrderGenerator != null)
|
if (World.OrderGenerator != null)
|
||||||
orderGenerator = World.OrderGenerator.RenderAnnotations(this, World);
|
foreach (var renderAnnotation in World.OrderGenerator.RenderAnnotations(this, World))
|
||||||
|
preparedAnnotationRenderables.Add(renderAnnotation.PrepareRender(this));
|
||||||
return actors
|
|
||||||
.Concat(selected)
|
|
||||||
.Concat(effects)
|
|
||||||
.Concat(orderGenerator)
|
|
||||||
.Select(r => r.PrepareRender(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PrepareRenderables()
|
public void PrepareRenderables()
|
||||||
@@ -190,9 +231,11 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
// PERF: Reuse collection to avoid allocations.
|
// PERF: Reuse collection to avoid allocations.
|
||||||
onScreenActors.UnionWith(World.ScreenMap.RenderableActorsInBox(Viewport.TopLeft, Viewport.BottomRight));
|
onScreenActors.UnionWith(World.ScreenMap.RenderableActorsInBox(Viewport.TopLeft, Viewport.BottomRight));
|
||||||
preparedRenderables.AddRange(GenerateRenderables());
|
|
||||||
preparedOverlayRenderables.AddRange(GenerateOverlayRenderables());
|
GenerateRenderables();
|
||||||
preparedAnnotationRenderables.AddRange(GenerateAnnotationRenderables());
|
GenerateOverlayRenderables();
|
||||||
|
GenerateAnnotationRenderables();
|
||||||
|
|
||||||
onScreenActors.Clear();
|
onScreenActors.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,9 +322,12 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
foreach (var b in World.ScreenMap.MouseBounds(World.RenderPlayer))
|
foreach (var b in World.ScreenMap.MouseBounds(World.RenderPlayer))
|
||||||
{
|
{
|
||||||
var points = b.Vertices
|
var points = new float2[b.Vertices.Length];
|
||||||
.Select(p => Viewport.WorldToViewPx(p).ToFloat2())
|
for (var index = 0; index < b.Vertices.Length; index++)
|
||||||
.ToArray();
|
{
|
||||||
|
var vertex = b.Vertices[index];
|
||||||
|
points[index] = Viewport.WorldToViewPx(vertex).ToFloat2();
|
||||||
|
}
|
||||||
|
|
||||||
Game.Renderer.RgbaColorRenderer.DrawPolygon(points, 1, Color.OrangeRed);
|
Game.Renderer.RgbaColorRenderer.DrawPolygon(points, 1, Color.OrangeRed);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user