Workaround of WebGLState texture error on iPhone/iPad/MacOS 16.4

Hi, our team create a 3D mixed AR/VR/MR platform MAKAR, which support PC/Mac application for free.

We also create a webXR website with THREE.JS for experiencing the 3D scene.

Recently, our client report some image item can not show normally in newest iOS/macOS safari and chrome( 16.4 ) . But the texture in 3D model and spherical sky object work fine.

By trace the webGL error code, we find that the issue occur when the texture loading with mipmapping or the texture resize by webGLState and the browser use webGL1.

In WebGLTextures.js:

const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( texture.image ) === false;

let image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize );

...

function textureNeedsPowerOfTwo( texture ) {
    if ( isWebGL2 ) return false;
    return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
        ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );
}

if the upper situation occur, WebGLState error :

state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image );

THREE.WebGLState: Error { 
    column: 24,
    line: 26563,
    message: "Type error",
    stack:"texImage2D@[native code]..."
}

We can find out when the image tpye is canvas , this error happen.

Workaround: check the platform and browser version by navigator.userAgent, when the browser is chrome/safari, device is iPhone/iPad/macOS and the browser version is larger than 16.4. Set the “needsPowerOfTwo” be false to prevant this error.

2 Likes

Thank you for sharing! do you know a webkit bug report for this?

My decision.
Texture resolution must be to the power of 2
For example(128, 256, 512, 1024)

Hello, please explain how and where Set the “needsPowerOfTwo” be false ?

Hi, in the script [ WebGLTextures.js ]. There is a function [ uploadTexture ].
Thre original code is

const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( texture.image ) === false; 
1 Like

I couldn’t override this class so easy as it’s imported as node module, but another workaround is to set texture.minFilter = THREE.LinearFilter; which will turn off mipmapping and the need for resizing to a power-of-two.