-
-
Notifications
You must be signed in to change notification settings - Fork 21.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[3.x] Add shader tracking & precomp #80345
base: 3.x
Are you sure you want to change the base?
Conversation
Where is the speed up coming from on the initial run? Is it just from moving the compilation time to the main menu instead of doing it on the first frame? |
Pretty much. If you start any project without already having the compiled shaders in your driver cache you spend a significant amount of time getting them ready. The goal of this PR is to move that time to the main menu to reduce the intensity of ingame stutters. I am currently on vacation to deal with an ongoing family emergency, but I should be available for the next rendering meeting. Would be happy to go into more detail during that. |
Error err = fa->_open(p_file_path, FileAccess::READ); | ||
ERR_FAIL_COND_V_MSG(err, err, "ShaderPreLoader cannot open file '" + p_file_path + "'. Check user read permissions & the file location."); | ||
|
||
//Load shader code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//Load shader code | |
// Load shader code. |
Comment style nitpick
String current_shader_code = ""; | ||
for (String line = fa->get_line(); !fa->eof_reached(); line = fa->get_line()) { | ||
if (line.begins_with(SHADER_CODE_MARKER)) { | ||
// Start of a new shader |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Start of a new shader | |
// Start of a new shader. |
if (line.begins_with(SHADER_CODE_MARKER)) { | ||
// Start of a new shader | ||
if (current_shader_id) { | ||
//store prev shader |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//store prev shader | |
// Store previous shader. |
} | ||
code_map->insert(current_shader_id, current_shader_code); | ||
|
||
//Load shader permutations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//Load shader permutations | |
// Load shader permutations. |
Map<uint32_t, String> canvas_shader_code; | ||
Map<uint32_t, String> particle_shader_code; | ||
|
||
//Store all used action hashes and actions for a given shader code hash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//Store all used action hashes and actions for a given shader code hash | |
// Store all used action hashes and actions for a given shader code hash. |
} | ||
|
||
ShaderTrackerGLES3::~ShaderTrackerGLES3() { | ||
FileAccessCompressed *fa_spatial = memnew(FileAccessCompressed); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In cases like this you can just declare a stack-lived variable: FileAccessCompressed fa_spatial;
.
You can handle its lifetime either by scoping or just reusing the same variable. (Or explicitly closing.)
This PR adds a launch flag (
--track-shaders
) that can be used to generate a list of all used shaders during the playtesting and QA process. In addition functions are provided that make it possible to load these shadderlists from code and use them to prepopulate the devices shader cache.I should note that this solution is not quite as elegant as I would like it to be, I am basically generating massive text files containing both the shader's code as well as any additional information that is necessary to compile it. Earlier drafts of this PR attempted to be smarter about this and only store the necessary options, while referencing the shader's source files instead and also trying to automatically infer information from the scene files. However, as I came across more and more edge cases it quickly escalated in complexity until it became nigh unmaintainable.
This, admittedly dumber and brute force-y, approach on the other hand works far better than it has any right to. I have tested it on both windows and linux without any problems and even managed to get the lists themselves to be fairly small (they have a lot of duplicated substrings, which means that compressing them turned out to be quite efficient). All the shaderlists for the tps demo come in at less than 40KB.
Using this PR
--track-shaders
launch flag.Performance
On my laptop this PR reduced the initial loading times for new shaders to roughly a third of what it was before during a cold launch. According to my benchmarks my laptop usually spends around 15,14 seconds in total to load and compile all the necessary shaders for the TPS demo. By using this PR I got those times down to around 5,97 seconds.
Note that this PR will not result in any additional performance gains during subsequent runs!
When testing this PR make sure you delete all cached shaders on your device before every launch. This depends a lot on your platform but the usual suspects are godot's built in cache, your driver's cache and maybe your operating system's cache.
A note on 4.x
We will need something similar to this in 4.x. However, I am cautiously optimistic that the shaders are handled better in 4.x (you would not believe how many string operations we are performing across multiple cpp files just to prepare a shader for compilation.) so we might be able to come up with a solution that is more elegant than this.
From what I have gathered while talking to W4 employees at the conference I believe that they plan to implement something like this anyways for console support, so for now I will leave 4.x to them.
This PR was sponsored by Ramatak with 💚