Skip to content
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

Link WebGL shaders immediately after compilation #6076

Merged
merged 1 commit into from
Feb 21, 2024

Conversation

mvaligursky
Copy link
Contributor

@mvaligursky mvaligursky commented Feb 21, 2024

Based on #5914, thanks @erikdubbelboer for the work on this.

I tested and confirmed the behaviour on Chrome (and also Safari) has changed compared to my findings in https://github.com/mvaligursky/webgl-parallel_shader_compile

Chrome can now compile 50 large shaders without locking the main thead (as long as the result is not needed), unlike before. Likely some change in ANGLE, as that's where the expected fix was supposed to land.

It seems link right after compile step is beneficial. Before, we would trigger compilation step on all shaders in a pass, and then trigger linking on all of them, to get the best speed. Now it seems no work is done during compile step (on Chrome), and so unless we call the link step, browser does not start the compilation at all.

By this change we're gaining little time it takes to trigger the compilation for all shaders - this time now seems to be used to link the first few shaders.

I also stripped out some code managing the delayed linking, as that is no longer needed.

@mvaligursky mvaligursky self-assigned this Feb 21, 2024
@mvaligursky mvaligursky added performance Relating to load times or frame rate area: graphics Graphics related issue labels Feb 21, 2024
@mvaligursky mvaligursky requested a review from a team February 21, 2024 16:20
@mvaligursky mvaligursky merged commit cac7efc into main Feb 21, 2024
7 checks passed
@mvaligursky mvaligursky deleted the mv-webgl-shader-compilation-updates branch February 21, 2024 16:31
@Maksims
Copy link
Contributor

Maksims commented Feb 21, 2024

Perhaps with changes in ANGLE, async shader compilation potentially works now?

@mvaligursky
Copy link
Contributor Author

yep, based on my test project https://github.com/mvaligursky/webgl-parallel_shader_compile running on up to date Chrome (121) async compilation is finally useful, main thread framerate is now solid even though we compile lots of large shaders.

And so I'm thinking how to use it.

My current plan (still thinking about it) would be to add some flag to the material (public API), to indicate that any meshes using this material can be skipped from being rendered if the shader is not compiledyet. People would need to set it, by default likely false to not force any changes to existing projects.

I'd check for this flag inside forward-renderer render loop, but for the forward pass only. So ignored for shadow, picker and similar. Also would need to disable it for lightmapper. The thinking here is that shadow / picker shaders are fast to compile, and we handle 'render once' and similar there, so sometimes we do not want to skip rendering (don't want the mesh missing in render-once shadow map). On the other hand, forward shaders are slow to compile, so we specifically want to skip those.

I'll try something like this and see what benefits we get.

@Maksims
Copy link
Contributor

Maksims commented Feb 21, 2024

My previous attempt to implement it was pretty much as you've described: it would force compile for certain types of variants (shadowmaps, pickers, etc). And provide a way to async compile for materials.

Also, you would start the compilation of shaders as early as possible during the preloading stage.

Also, I thought if you would call material.update, you could provide a callback, so you can know when it was compiled.
Something like:

material.async = true;
material.chunk.endPS = shaderCode;
material.update((err) => {
    // shader has been recompiled
});

This gives control to the developer and also provides a way to implement some loading bars or spinners.

Also a global counter of a number of shaders that are currently compiling - would be good.

@mvaligursky
Copy link
Contributor Author

Not sure a callback is super useful, as we compile multiple variants based on lights / passes / mesh vertex format and similar, not a single shader.

The same goes for compiling shaders during loading - at that point we do not now how the material will be used - what layers it needs to collect the lights from, what are the scene settings going to be at the time we need to render it. This is hard to do. I was looking at restoring the functionality of the shader cache we have .. dump those, and those we can precompile. But there are several issues there the way shader generation works for different platforms, that could cause shaders not needed for the platform to be compiled. Again, non trivial solution here would be needed.

@MAG-AdrianMeredith
Copy link
Contributor

MAG-AdrianMeredith commented Feb 22, 2024

Thanks for all your hard work everyone. From a UX perspective I'd like to be able to have the ability for a "compile shaders" stage during loading so that we can load up the assets of the scene then pre-eptively compile as much as possible. We previously attempted this by disabling culling on the camera to force everything to draw (but its currently disable as our lod system kept triggering it).

Even if it only catches some of the shaders that are needed it would still be useful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: graphics Graphics related issue performance Relating to load times or frame rate
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants