Three.js: Eliminating unnecessary Uniform updates

Created on 6 May 2018  路  13Comments  路  Source: mrdoob/three.js

Hello!

Using the WebGL Inspector tool on Chrome I realized that WebGL uniform functions are called even though the uniforms are not changed:
ekran resmi 2018-05-06 11 12 49

I remember watching a guy from Sony talking about how they integrated the WebGL into the PS4 and how eliminating these redundant calls helped them improving the performance. Since WebGL is simply a state machine, calls that make no change in the current state should be ignored. As this can be simply achieved with an IF condition before the WebGL call another idea would be to add dynamic or shouldUpdate flag to the uniforms.

Any opinions, ideas or comments on that?

Enhancement

All 13 comments

Yes, three.js could work in a more efficient way to avoid such redundant calls. Some time ago, I've read in a book (WebGL Insights) an interesting chapter about WebGL engines in context of mobile devices. The author said:

_It (three.js) often does redundant or inefficient updates to the GL state, particularly to uniform values, and due to how it's structured, this is unlikely to improve without some very significant changes._

Babylon.js for instance handles an update of a color3 uniform like this:

Effect.prototype.setColor3 = function(uniformName, color3) {

     if (this._valueCache[uniformName] &&
         this._valueCache[uniformName][0] == color3.r &&
         this._valueCache[uniformName][1] == color3.g &&
         this._valueCache[uniformName][2] == color3.b)
     return this;

     this._cacheFloat3(uniformName, color3.r, color3.g, color3.b);
     this._engine.setColor3(this.getUniform(uniformName), color3);

         return this;
};

I'm not sure the code is up to date but it illustrates the general idea behind a uniform cache. Maybe we can enhance WebGLUniforms in order to implement a similar caching system?

BTW: I think it would be useful if WebGLInfo could count uniform updates/changes per frame.

@oguzeroglu I'd like to rephrase the title since it makes more sense to focus on uniforms in this issue. Prerender optimization is a wide topic and three.js already performs caching to avoid redundant WebGL state changes.

Yes sure, the title makes more sense like this :)

I'm gonna try to experiment with uniform caching this week, I'll post the results here.

I remember watching a guy from Sony talking about how they integrated the WebGL into the PS4

Was this Don Olmstead? Webgl meetup at google a while ago?

It would be useful for something like this to make a meaningful test case. Stress out and cause the most redundancy, and then we could have something to try to optimize.

Was this Don Olmstead? Webgl meetup at google a while ago?

Yes, here's the video: https://www.youtube.com/watch?v=QVvHtWePQdA

It would be useful for something like this to make a meaningful test case. Stress out and cause the most redundancy, and then we could have something to try to optimize.

I don't know the maximum number of allowed uniforms in WebGL, it might be even hardware specific but I'm going to try to test with loads of mat4 uniforms. I hope I can get some sort of FPS drop like that :)

This isn't an issue of maximum allowed uniforms, but more of setting the state of three.js to incur the most uniform changes? I might be misunderstanding something though.

but more of setting the state of three.js to incur the most uniform changes

Well that's the case actually, more the uniforms more the WebGL calls since THREE.js does not seem to do uniform caching. In the screenshot I put to the issue I was not updating fogfar, diffuse etc.

To clarify this: The issue is about only updating uniforms if values actually changed.

I can see it could be easily hacked for ShaderMaterial with something like

material.uniforms = {
    myVar : { type : '...', value : ..., needsUpdate : false },
    ...

and whenever needsUpdate is not set to false, do the call as before.

The idea is to do caching automatically. three.js should only perform an update if values actually changed. Similar to WebGLState.

The needsUpdate flag for uniforms might be redundant at a certain point.

Yeah this is more for the stuff in between calls, like, Camera, is shared by all the shaders, it shouldn't be set in between draw calls.

It seems like the PR fixed it, so I'm closing the issue.

Was this page helpful?
0 / 5 - 0 ratings