Jump to content

Material push mode: The new big optimization


Recommended Posts

Hello team!

Since the very first version of Babylon.js materials are working in a pull mode. This means that every time a mesh needs to be rendered, its material has to ask the engine about a lot of information in order to compile the best shader possible for the given mesh.

For instance, here is an incomplete list of states required to compile a shader:

- Lights affecting the mesh (taking in account inclusion and exclusion lists and masks)

- Textures and channels (including associated parameters like parallax for bump or reflection mode for reflections)

- Fog, clip planes, point rendering or wireframe

- Mesh attributes (does the mesh contains UV? tangent? colors?)

This leads to a pretty expensive function named Material.isReady.

Due to the previous reasons, the function is really CPU intensive. Here is for instance the profile of the "materials" playground:


The highlighted functions are part of the IsReady root function. The scene is extremely simple and you can see that the isReady is taking almost 13% of the CPU time

While it was ok because of the complexity of the task assigned to this function, I decided recently to change it to a clever model: The push mode.

When a material is in this mode, instead of asking on every frame for every state, the states will push updates to the material when they change.

Obviously the performance boost is immense. Look at the same profile with the new mode:


We are now at 2.51%. On bigger scene like Sponza, this function could take up to 30%:


And now with the new mechanism:


ONLY 3%!!!!!!!!!!

But obviously with such a big change, there will be some bugs.. So please use this thread to report any issue with StandardMaterial.

If everything is fine, I'll update the PBR to push mode in one or two weeks.

Associated PR: https://github.com/BabylonJS/Babylon.js/pull/1959/

Link to comment
Share on other sites

Hello @Deltakosh,

I'm currently working on implementing UBO (uniform buffer objects), and i merged the most recent changes about StandardMaterial becoming a PushMaterial.

Everything is now working fine, but I'm encountering performance issues against the unmerged version.

My focus currently goes onto frozen materials, since they are the most optimized way to use UBO : 1 uniform buffer per material, which is static.


I've tested with a simple scene with 1600 visible spheres, each one having a different material, lit by a moving HemiLight, here are the results :


UNMERGED (StandardMaterial is still NOT a PushMaterial), with FROZEN materials :



MERGED (StandardMaterial IS a PushMaterial), with FROZEN materials : 



MERGED (StandardMaterial IS a PushMaterial), with UNFROZEN materials : 



As you can see on profiles, a lot of time is spent on getter functions, most likely because they contain 

get: function () {
    return this["_" + key];

which is really slow in JS.


So my question is : do you have any idea on how to prevent that slow-down to happen on frozen materials ? Maybe i am missing something in my UBO implementation code to deal with that ?

Btw, It's really likely that unfrozen material spend less time in "isReady" functions, so are still more optimized despite the heavy "get" functions. 


Thanks for your kind advices ;)

Link to comment
Share on other sites

We are indeed far better :) No more intensive CPU usage because of getters and GC.

I also took the initiative of replacing disableLighting and cameraColorCurves by their respective private properties _disableLighting and _cameraColorCurves.


Thanks for you help, I'll keep you updated of the following implementation of UBO for materials.

Link to comment
Share on other sites

  • 2 weeks later...
4 minutes ago, reddozen said:

Is this in the latest nightly build?


As far as I know, yes material push mode is in the latest build for Standard Material.
Not for PBRMaterial yet.
And materials from materialsLibrary (water, fur, etc.) also are in push mode. :)

Link to comment
Share on other sites

  • 1 year later...


Hey I'm not sure I understand.  

The standardMaterial in 3.3 alpha is a push material?  Or is it, its own?, oh or did you mean standardMaterial implements pushMaterial or idk, I'm very curious...

I see that push material has its own contructor but I can't seem to set a colour to it with diffuseColor, emmisiveColor, or ambientColor.

There also doesn't seem to be a doc on the pushMaterial so I'm assuming its only meant to be part of standard material?

Also is this an effective way to increase performance of only a handful of materials or is this only for large amounts?  Say 5 different materials?  Assuming the lighting changes and nothing else(used material.freeze()).




Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...