OpenRA / OpenRA/OpenRA

Do not let Render return an `IEnumerable`

Open
#21,282 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Idea/Wishlist Performance
Dominant language
C#
Stars
17.4k
Forks
3k
Avg merge
1d 12h
Merged PRs (30d)
14

Description

Proposal to let the various Render functions like Actor.Render not return an IEnumerable.

Rather to pass an extra function argument i.e. IRenderContext to which IRenderables can be added. i.e. void Render(..., IRenderContext rc) { rc.Add(renderable); } or less clean void Render(..., ICollection<IRenderable> desList).

Code comments that that it was deliberately choses to return IEnumerable to allow for deferred calls to IRenderable and to possibly have less resource usage and allow the use of yield.

In practice WorldRenderere.GenerateRenderables will add all IRenderables to a lit and sort them by z-index.

About 1.7% of CPU time is spent in ordering by z-index in the Linq OrderedEnumerable.

Motivation:

  • Renderables can be added to a list of pre allocated sized - size can grow based on last render.
  • No allocation of IEnumerables, and IEnumerators.
  • No calling of Enumerables<IRenderable> and Add/InsertRange on the enumerables
  • No allocation of a KeyMap by OrderedEnumerables as returned by LINQ OrderBy. Used for Quicksort. i.e. https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,2598
  • Quicksort can take place on the list if IRenderables directly.
  • In general, a lot less Linq and Enumerable overhead
  • Comments in GenerateRendables mentions to avoid Linq, yet OrderyBy is still used.

About 1.7% CPU time is spent in sorting the IRenderables - only when showing the shell map. Another 1%+ seems to be spent in calling Add|InsertRange on the renderableBuffer list.

   - 13.08% instance void [OpenRA.Game] OpenRA.Graphics.WorldRenderer::GenerateRenderables()[Optimized]                                                                                                                                                  ▒
      - 9.35% instance void [System.Private.CoreLib] System.Collections.Generic.List`1[System.__Canon]::InsertRange(int32,class System.Collections.Generic.IEnumerable`1<!0>)[OptimizedTier1]                                                            ▒
         - 7.65% instance bool [OpenRA.Game] OpenRA.Actor+<Renderables>d__75::MoveNext()[Optimized]                                                                                                                                                      ▒
            - 5.89% instance bool [OpenRA.Mods.Common] OpenRA.Mods.Common.Traits.Render.RenderSprites+<Render>d__12::MoveNext()[Optimized]                                                                                                               ▒
               - 3.32% instance class OpenRA.Graphics.IRenderable[] [OpenRA.Game] OpenRA.Graphics.AnimationWithOffset::Render(class OpenRA.Actor,class OpenRA.Graphics.PaletteReference)[OptimizedTier1]                                                 ▒
                    1.76% instance class OpenRA.Graphics.IRenderable[] [OpenRA.Game] OpenRA.Graphics.Animation::Render(valuetype OpenRA.WPos,valuetype OpenRA.WVec&,int32,class OpenRA.Graphics.PaletteReference)[OptimizedTier1]                        ▒
      - 1.69% instance bool [System.Linq] System.Linq.OrderedEnumerable`1+<GetEnumerator>d__17[System.__Canon]::MoveNext()[OptimizedTier1]                                                                                                               ▒
         - instance int32[] [System.Linq] System.Linq.EnumerableSorter`1[System.__Canon]::Sort(!0[],int32)[OptimizedTier1]                                                                                                                               ▒
            - 1.26% instance void [System.Linq] System.Linq.EnumerableSorter`2[System.__Canon,System.Int32]::QuickSort(int32[],int32,int32)[OptimizedTier1]                                                                                              ▒
                 void [System.Private.CoreLib] System.Collections.Generic.ArraySortHelper`1[System.Int32]::Sort(valuetype System.Span`1<!0>,class System.Comparison`1<!0>)[OptimizedTier1]                                                               ▒
               - void [System.Private.CoreLib] System.Collections.Generic.ArraySortHelper`1[System.Int32]::IntroSort(valuetype System.Span`1<!0>,int32,class System.Comparison`1<!0>)[OptimizedTier1]                                                    ▒
                  - 1.12% void [System.Private.CoreLib] System.Collections.Generic.ArraySortHelper`1[System.Int32]::IntroSort(valuetype System.Span`1<!0>,int32,class System.Comparison`1<!0>)[OptimizedTier1]                                           ▒
                       0.65% void [System.Private.CoreLib] System.Collections.Generic.ArraySortHelper`1[System.Int32]::IntroSort(valuetype System.Span`1<!0>,int32,class System.Comparison`1<!0>)[OptimizedTier1]                                        ▒
        0.59% instance class [System.Runtime]System.Collections.Generic.IEnumerable`1<class OpenRA.Graphics.IRenderable> [OpenRA.Game] OpenRA.Actor::Render(class OpenRA.Graphics.WorldRenderer)[Optimized]   

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with WorldRenderer.GenerateRenderables and Actor.Render, then trace the Render methods named in the profile, including RenderSprites.Render, AnimationWithOffset.Render, and Animation.Render. The work is done when renderables no longer rely on the proposed IEnumerable-based flow, while generation and z-index ordering retain their existing behavior and the reported allocation and sorting overhead is reduced.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
game-dev, performance
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.