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

lighter getProgramCacheKey when using RawShaderMaterials #22650

Merged
merged 3 commits into from
Oct 8, 2021

Conversation

dbuck
Copy link
Contributor

@dbuck dbuck commented Oct 6, 2021

Related issue: #22530

Description

The gist of the problem: each new material instance gets run through this getProgramCacheKey function to see if three needs to build a program for that, or to connect a reference to an existing program.

The getProgramCacheKey function is ‘ok’ for built in shaders, but it has a pretty huge allocation for custom shaders, especially a relatively large ubershader, by way of making the key out of concatenating the full strings of the fragment/vertex shaders.

This wasn’t too much of an issue as long as the materials can be set up front, as it was a one time cost during load, but I'm noticing that with 3d-tiles based streaming, our current method of creating unique ShaderMaterial per tile, each new tile shown is a pretty large memory allocation, and for larger tilesets, where it’s possible to view thousands of tiles over time, this adds up to a healthy amount of GC pressure.

Hash function choice 1000% up for debate, this one was working fairly well, quickly, and with much lower allocation pressure showing in testing.

Before: image

After:
image

The gist of the problem: each new material instance gets run through this getProgramCacheKey function to see if three needs to build a program for that, or to connect a reference to an existing program.

The getProgramCacheKey function is ‘ok’ for built in shaders, but it has a pretty huge allocation for custom shaders, by way of making the key out of concatenating the full strings of the fragment/vertex shaders.

This wasn’t too much of an issue as long as the materials can be set up front, as it was a one time cost during load, but I'm noticing that with 3d-tiles based streaming, our current method of creating unique ShaderMaterial per tile, each new tile shown is a pretty large memory allocation, and for larger tilesets, where it’s possible to view thousands of tiles over time, this adds up to a healthy amount of GC pressure.
Dave Buchhofer added 2 commits October 6, 2021 17:48
The gist of the problem: each new material instance gets run through this getProgramCacheKey function to see if three needs to build a program for that, or to connect a reference to an existing program.

The getProgramCacheKey function is ‘ok’ for built in shaders, but it has a pretty huge allocation for custom shaders, by way of making the key out of concatenating the full strings of the fragment/vertex shaders.

This wasn’t too much of an issue as long as the materials can be set up front, as it was a one time cost during load, but I'm noticing that with 3d-tiles based streaming, our current method of creating unique ShaderMaterial per tile, each new tile shown is a pretty large memory allocation, and for larger tilesets, where it’s possible to view thousands of tiles over time, this adds up to a healthy amount of GC pressure.
The gist of the problem: each new material instance gets run through this getProgramCacheKey function to see if three needs to build a program for that, or to connect a reference to an existing program.

The getProgramCacheKey function is ‘ok’ for built in shaders, but it has a pretty huge allocation for custom shaders, by way of making the key out of concatenating the full strings of the fragment/vertex shaders.

This wasn’t too much of an issue as long as the materials can be set up front, as it was a one time cost during load, but I'm noticing that with 3d-tiles based streaming, our current method of creating unique ShaderMaterial per tile, each new tile shown is a pretty large memory allocation, and for larger tilesets, where it’s possible to view thousands of tiles over time, this adds up to a healthy amount of GC pressure.
@dbuck dbuck marked this pull request as ready for review October 6, 2021 22:15
@mrdoob
Copy link
Owner

mrdoob commented Oct 8, 2021

Very nice! Lets give this a try 👍

@mrdoob mrdoob added this to the r134 milestone Oct 8, 2021
@mrdoob mrdoob merged commit 20e2e54 into mrdoob:dev Oct 8, 2021
@mrdoob
Copy link
Owner

mrdoob commented Oct 8, 2021

Thanks!

@dbuck dbuck deleted the lighter-getProgramCacheKey branch October 8, 2021 11:12
@Usnul
Copy link
Contributor

Usnul commented Nov 2, 2021

Oh man, this is done with good intentions, but it's incorrect. There's a concept of hash collision. What you have created is something that assumes that hash equality is the same as entity equality. Which is just not the case.

To put it simply - currently it's possible for 2 completely different shaders to have IDENTICAL key. Please revert this.

The probability of this happening is very low, if your hash function is good, but very low is not good enough. For comparison, v3 UUID (that is the random variant) has 128 bits, and I have seen collisions of those in real life. Yet here we are dealing with 32 bits only.

@Mugen87
Copy link
Collaborator

Mugen87 commented Nov 3, 2021

The probability of this happening is very low, if your hash function is good, but very low is not good enough.

Indeed, this is a valid point. Hashes should not be used as UUIDs by definition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants