KSPModdingLibs/KSPCommunityFixes

Vessels with a large number of crew are slow (presumably animation/portrait updating)

JonnyOThan opened this issue · 3 comments

Saw a report from discord that performance tanks for vessels with 190 kerbals, but it's fine in map mode or without crew. This hints that it's caused by animations or something to do with the portrait system. It should be possible to limit that cost to just the kerbals that are going to be drawn.

what i noticed is that during uncrewed test flights the performance had absolutely no problems,but with the crew of 190 in it the performance is terrible,what i think is going on is that when not in map view it loads all the kerbals and their constant movements,killing performance

Yeah, the portrait related lag has been an issue since quite some time.

I gave a look some time ago, the issue is somewhere in the component and coroutine spaghetti portrait handling mess causing inactive portraits to be updated when they aren't shown under certain circumstances, but I never got to the bottom of it.

image

This is fighting me real hard, the thing is probably one of the worst piece of spaghetti code KSP has...

The issue seems to be that KerbalPortrait.OnEnable() is forcefully enabling all portraits, even hidden ones.
KerbalPortrait is a component living down in the flight UI hierarchy, as an indirect child of the PortraitViewport GameObject, which gets de-activated when switching to map view (and probably in other cases like IVA mode), then re-activated when getting back to flight view.

Activating it then trigger KerbalPortrait.OnEnable(), forcefully enabling all portraits, starting the coroutine handling kerbals animations and portrait renders to a rendertexture, regardless of if the portrait is shown.

There is a separate callback handling activation/deactivation of the portraits that aren't shown when cycling (RectContainment_OnContainmentChanged). The RectContainmentDetector thing is using a pooling approach checking if the portrait rect is visible or not and fire that event, and it maintain some state, but trying to use said state to prevent portrait activation from KerbalPortrait.OnEnable() seemingly has the side effect of preventing correct initialization of the some other stuff, I guess because it prevent the initial OnEnable() call when the component is instantiated, resulting in inactive portraits never becoming activated (or rather, getting stuck in "noise mode") when adding additional slots (but cycling them somehow fix it, I guess because that trigger the OnContainmentChanged callback).

I will have to dig further, maybe there is a simpler approach to fix this...

Edit : actually the issue of portraits getting stuck in "noise mode" seems to happen in stock too, but it's hard to reproduce consistently...

Fix implemented in 1.28