Is texture.updateSamplingMode causing churn?

We have textures that are dynamically updated. Some of them require us to use BILINEAR_SAMPLINGMODE instead of the default TRILINEAR_SAMPLINGMODE

In order to make sure we have everything looking correct, we loop through all textures and reset to TRILINEAR_SAMPLINGMODE

This appears to have caused a large slowdown when applied to many textures.

Am I right that this is an expensive operation here?

I thought that it would not affect anything to reset the sampling mode but looking at this it appears that there are a lot of potential operations that could be happening. Any advice or best practices?

1 Like

The slow part is line 3522 which generates mipmaps. This function is mainly only used internally and should probably not be used if your mip chain and so on is already ok. Why not relying on the texture function itself which would be safer as this one assumes the texture has been bound and so on.

Also adding @Evgeni_Popov as I ll be in vacation for a bit :slight_smile:

1 Like

The ThinTexture.updateSamplingMode method is calling Engine.updateTextureSamplingMode with false as the generateMipMaps parameter, so calling the function should not take that long…

1 Like

Looking at our code, it appeared that the third param in generating textures was set to false. That refers to noMipmaps which throwing us. In that case, I believe that we were in fact generating mipmaps.

On this, we using the texture object to do the updates, but for specific textures which looked off with the default sampling mode, we are calling texture.updateSamplingMode(Texture.TRILINEAR_SAMPLINGMODE)

I believe that if the texture is created with generateMipmaps then any update to the sampling mode will also generate new mipmaps?

No, the code for updateSampingMode is:

public updateSamplingMode(samplingMode: number): void {
    if (this._texture && this._engine) {
        this._engine.updateTextureSamplingMode(samplingMode, this._texture);
    }
}

And Engine.updateTextureSamplingMode is:

public updateTextureSamplingMode(samplingMode: number, texture: InternalTexture, generateMipMaps: boolean = false): void {
    const target = this._getTextureTarget(texture);
    var filters = this._getSamplingParameters(samplingMode, texture.generateMipMaps || generateMipMaps);

    this._setTextureParameterInteger(target, this._gl.TEXTURE_MAG_FILTER, filters.mag, texture);
    this._setTextureParameterInteger(target, this._gl.TEXTURE_MIN_FILTER, filters.min);

    if (generateMipMaps) {
        texture.generateMipMaps = true;
        this._gl.generateMipmap(target);
    }

    this._bindTextureDirectly(target, null);

    texture.samplingMode = samplingMode;
}

So generateMipMaps = false.

Actually, there’s only the HDRFiltering class which is calling updateTextureSamplingMode and explicitely passing true for the 3rd parameter.

But I see that in our code, we had a value for that was using false as the third arg:

 const tex = new Texture(
`${texturePathFile}.png`,
scene,
false,
true,
Texture.TRILINEAR_SAMPLINGMODE,
() => {
  callback(tex);
},
() => {
  const err = new Error(
    `An error occurred while loading ${texturePathFile}.`,
  );
  logger.simpleError('Texture Loading', err);
  errorHandler?.(err);
},
null,
true,

);

Wouldn’t the explicit false in arg3 propagate down into that if statement in thinEngine?

No, as you can see in the code above. The fact the mipmaps should be generated is taken care somewhere else, not in updateTextureSamplingMode.

As I understand it, allowing to generate the mipmaps in updateTextureSamplingMode does not make a lot of sense to me: the texture sampling mode of a texture does not impact the way the mipmaps are generated, so regenerating them after changing the sampling mode is a null (identity) operation, the mipmaps will remain the same (if they already exist). I think it’s simply a facility for the HDRFiltering class to request generating the mipmaps after having created a texture.

2 Likes

Then the last question is where it says:
this._bindTextureDirectly(target, null);

Is this re-uploading the texture to the GPU, and could a lot of those operations account for a slowdown?

This call unbinds the texture in OpenGL.

I’m not knowledgeable enough in this API to know if it’s a slow or fast operation, though…

Have you tried to profile your code in the Performance tab of your browser? You should be able to see where most of the time is spent.

This is happening on a server using Chromium and we don’t yet have it set up to output performance info. We’re working on that as we speak :slight_smile: