Jump to content

Babylon performance Issue


BabarJulien
 Share

Recommended Posts

I've been doing some profiling while creating a pretty large number of objects in the scene, mainly LinesMeshes and some Planes with DynamicTextures to draw 2d Text.

It seems that there are a few places where we perform O(n) search or iteration that causes creation time to grow linearly with the number of already existing objects.

examples :

 - when adding a Mesh to the scene

        public getGeometryByID(id: string): Nullable<Geometry> {
            for (var index = 0; index < this.geometries.length; index++) {
                if (this.geometries[index].id === id) {
                    return this.geometries[index];
                }
            }

            return null;
        }

=> keeping up-to-date a map Id to Geometry could fix this.

 

 - when updating the world matrix

            for (var mesh of this.getScene().meshes) {
                if (!mesh.subMeshes) {
                    continue;
                }
                for (var subMesh of mesh.subMeshes) {
                    if (subMesh.getMaterial() !== this) {
                        continue;
                    }

                    if (!subMesh._materialDefines) {
                        continue;
                    }

                    func(subMesh._materialDefines);
                }
            }

(first note : I'm not expert in Javascript VM JItter, but it might be worth storing this.getScene().meshes in a local variable to prevent a call to getScene at each iteration).

If possible, adding the info in the Mesh whether all subMeshes have been already made dirty might prevent this code from browsing all the subMeshes several times

Whe checking the callstack, I get into that code from TransformNode.computeWordMatrix which is called each time a mesh is created, and each time I manually call computeWorldMatrix in case the parenting did change (I want the world bounding box), and also each time I set DynamicTexture's hasAlpha to true (to draw 2D text).

 

Also, I spend some time cloning LinesMesh since it does not support createInstance yet, it would be great to add this ! 😁

image.png.71c4fa8cb03f8096c005d9e06b49e6e0.png

Please let me know if there are existing ways to prevent all those redundant computation to happen. For you info, I'm adding a lot of objects between two frames (I mean, between two calls to scene.render())

Link to comment
Share on other sites

I am not sure how much the getGeometryByID() change would help, because I do not even see getGeometryByID(), broken out in your profile data.  I assume it is somewhere in Scene.pushGeometry().  Scene.pushGeometry(), along with the 2 functions broken out inside it, have a really high % of self time to total time. Does not leave a huge amount for getGeometryById().

The doubly nested loops are usually places which merit looking at.  In another lifetime, I used a language with line level profiling, APL.  Function level just kind of sucks.  In this case though, the number of meshes which have multimaterials is small, so the inner loop is usually only called once.  Something like this might be good from a es6 standpoint, but I have my doubts it will change performance a lot.

const meshes = this.getScene().meshes;
for (const mesh of meshes) {
    ...
}

  In the case of LineMeshes, it is using a shaderMaterial, so that would have to  be changed.  Changing LinesMesh to use a StandardMaterial was talked about before.  I was initially sub-classing LinesMesh for Hair, but I eventually gave up in favor of Mesh due to lack of thickness control.  Do not remember what was said, but searching 'Hair LinesMesh' may be helpful.

Link to comment
Share on other sites

Hello Julien!

These are good findings. You will feel our struggle regarding optimization soon :) Here for instance, if we want to  optimize the getGeometryByID we need to sacrifice on memory footprint and then other users will complain that they are not using this function a lot so they do not want to pay the price you ask them to pay :). Here I will probably suggest that you override the function to make it closer to your needs directly

For the getScene, this is the magic of TypeScript. Here is the code generated:

        Material.prototype._markAllSubMeshesAsDirty = function (func) {
            for (var _i = 0, _a = this.getScene().meshes; _i < _a.length; _i++) {
                var mesh = _a[_i];
                if (!mesh.subMeshes) {
                    continue;
                }
                for (var _b = 0, _c = mesh.subMeshes; _b < _c.length; _b++) {
                    var subMesh = _c[_b];
                    if (subMesh.getMaterial() !== this) {
                        continue;
                    }
                    if (!subMesh._materialDefines) {
                        continue;
                    }
                    func(subMesh._materialDefines);
                }
            }
        };

You can see that the getScene is actually called once :)

ComputeWorldMatrix is a complex beast. It is full of caching to make sure the cost is controlled but it needs to be called when you need it :) You can always call mesh.freezeWorldMatrix() to annihilate its cost

 

Hope this helps!

 

Link to comment
Share on other sites

The only way I can think of for doing this for es5 transpile is:   that the spec for es6 says the expression after the 'of' is only evaluated once.  That makes sense, you do not want code being written where something in the loop changes the number of items of the expression.

If not then the es5 code is a bug, for 2 reasons:

  • The function only runs once & es6 code runs every time
  • As stupid as it would be to do, just calling it had some side-effect
Link to comment
Share on other sites

Hi

@Deltakosh


I have much more performance troubles when set the alpha property of a lot of Dynamic Textures (to draw 2d text) :

image.thumb.png.01f228560af4be4fa7fbe8f0019245bc.png

 

Do you know if this kind of issue is being tackled in the WIP performance improvement you mentioned ? If not, is there a way to work around that ? (I'd like to avoid having a modified version of babylon).

 

Thanks

Julien

 

 

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.

Guest
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.

Loading...
 Share

  • Recently Browsing   0 members

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