perf: Speed up texture replacment#9
Conversation
When I profile my save with HUDReplacer installed (+ZTheme) it takes about 1.5s as part of every scene switch. Most of that time was spent iterating over the `images` dictionary again and again for every loaded texture. This commit gets the overhead of HUDReplacer down to ~130ms (on my save). There are a bunch of linked changes here, most of which are needed in order to make the whole thing work. I'll walk through these one by one. 1. The first thing is an overhaul of how the replacement info is stored. There are now two dictionaries: a global set of replacements, and a set of per-scene replacement dictionaries. These are keyed off of the image name, and have a list of all the available replacements for that image name, ordered by priority. This means that we can parse all the available texture replacements at startup and then not have to worry about needing to parse them again. We also pre-parse the texture filenames into their basename and size, if available. This means that we can actually just look them up by name, instead of having to search everything. As a bonus, I have added a ModuleManagerPostLoad call to load the textures so that it happens during the loading screen, instead of during the black screen when switching to the main screen. 2. Next, I have rewritten ReplaceTextures to take advantage of the new dictionary. There's a bit of extra work, because we need to deal with the fact that the replacements could possibly be either in the global dictionary or the scene-specific one. This all gets wrapped up in the GetMatchingReplacement methods. I have used the priority I saved from the first step to disambiguate. If that doesn't I just pick the scene specific one. This is a small behaviour change but I don't think it will matter in practice. 3. Caching. With the two changes above the runtime goes down to about 300ms - which is split 50/50 between reading textures off disk and loading them into a Texture2D. To speed this up I added a cachedTextureBytes field to ReplacementInfo. This makes it so the disk read can be avoided the next time the replacement is used. I have also made a couple of small changes and/or bugfixes as I was going through: - LoadTextures now emits useful error messages if the config node is invalid or if the format of the file name is wrong, instead of crashing. - ReplaceTextures now picks the texture with the highest priority, instead of the one with the lowest.
8b2d4d0 to
bf4def5
Compare
|
I will take a look at this later today. Thank you very much! |
|
This seems pretty good :) Would you be interested in taking over the development of this mod? I am currently not able to spend much time on KSP, so in case of future issues/improvements it would be great if someone else could continue working on it. I will of course change the licensing file to allow for this. If not, I'll just merge this update and release it. |
|
I actually would be interested in taking over maintenance. Before this can happen though you will need to update the license. My recommendation is to pick either MIT or GPLv3+, but you can check out https://choosealicense.com/ for info. I haven't adopted any mods before so I asked around a bit. The ideal way to do this seems to be for you to transfer the repository to me (and then I can take care of getting it into the |
|
First of all, I'll get the mod changed to GPLv3+ since I've wanted to do that anyway. Just gotta figure out how I get it updated for ckan as well. From there on I would assume you can just fork the repo and ask the ckan people to change the metadata to your new version? The only thing left is to create a new separate forum post and distribute the mod there I think. If ckan points to your repo then it will automatically have new versions downloaded from there instead. |
|
Alrighty, I have forked this repo over to https://github.com/KSPModStewards/HUDReplacer. When I get some time this weekend I will make a new release, the new forum post, and then ping you on discord to point the old post to the new one. Other than that, though, I think that's everything. |
|
New forum thread is up! https://forum.kerbalspaceprogram.com/topic/229134-112x-hudreplacer/. Next up is to update the CKAN metadata. I may need you to drop in the CKAN PR thread, we'll see. When you get a chance I'd appreciate if you can add a link to the OP in the old thread pointing people to the new one. |
With @UltraJohn's permission I am adopting HUDReplacer. See the discussion here for more details UltraJohn/HUDReplacer#9 This commit changes the following: - Point the CKAN repository to KSPModStewards/HUDReplacer - Point the forum thread to the new forum thread - Update the author field to list both UltraJohn and me
* Adopt HUDReplacer into KSPModStewards With @UltraJohn's permission I am adopting HUDReplacer. See the discussion here for more details UltraJohn/HUDReplacer#9 This commit changes the following: - Point the CKAN repository to KSPModStewards/HUDReplacer - Point the forum thread to the new forum thread - Update the author field to list both UltraJohn and me * Fix author list --------- Co-authored-by: HebaruSan <HebaruSan@users.noreply.github.com>
|
Awesome! I've made a post directing to your new thread. Let me know if there's anything else needed. Good luck and thank you! |
|
I think that's all! I'll close this PR now in favour of KSPModStewards#1. |
When I profile my save with HUDReplacer installed (+ZTheme) it takes about 1.5s as part of every scene switch. Most of that time was spent iterating over the
imagesdictionary again and again for every loaded texture.This commit gets the overhead of HUDReplacer down to ~140ms (on my save).
I'm not sure if this entirely fixes issue #7, since there are still things that can be improved. It does make things drastically better though.
There are a bunch of linked changes here, most of which are needed in order to make the whole thing work. I'll walk through these one by one.
The first thing is an overhaul of how the replacement info is stored. There are now two dictionaries: a global set of replacements, and a set of per-scene replacement dictionaries. These are keyed off of the image name, and have a list of all the available replacements for that image name, ordered by priority.
This means that we can parse all the available texture replacements at startup and then not have to worry about needing to parse them again.
We also pre-parse the texture filenames into their basename and size, if available. This means that we can actually just look them up by name, instead of having to search everything.
As a bonus, I have added a ModuleManagerPostLoad call to load the textures so that it happens during the loading screen, instead of during the black screen when switching to the main screen.
Next, I have rewritten ReplaceTextures to take advantage of the new dictionary. There's a bit of extra work, because we need to deal with the fact that the replacements could possibly be either in the global dictionary or the scene-specific one. This all gets wrapped up in the GetMatchingReplacement methods. I have used the priority I saved from the first step to disambiguate. If that doesn't I just pick the scene specific one.
This is a small behaviour change but I don't think it will matter in practice.
Caching. With the two changes above the runtime goes down to about 300ms - which is split 50/50 between reading textures off disk and loading them into a Texture2D. To speed this up I added a cachedTextureBytes field to ReplacementInfo. This makes it so the disk read can be avoided the next time the replacement is used.
I have also made a couple of small changes and/or bugfixes as I was going through:
Flame Graphs
Before. Note that

HUDReplacer.Awaketakes 1.5s here.After. Now it takes 140ms.
