Fix iOS14 bad performance on Browsers/WebView (Solved)

After a day of debugging, we found that the problem lies in the sharing of vb and ib. For the sake of performance optimization, Creator will share the same vb and ib between multiple drawcalls, each drawcall will use an offset to find the rendered data in the shared vb and ib, but after testing, we found that sharing vb and ib will cause serious performance degradation on iOS 14.

So the way of fix is switch vb and ib after committing drawcall.

details:

> 2.2

Customize the engine and manually merge this pr.

If you don’t want to customize the engine you can also override the methods of MeshBuffer manually in the outermost layer of your project script.

const isIOS14Device = cc.sys.os === cc.sys.OS_IOS && cc.sys.isBrowser && cc.sys.isMobile && /iPhone OS 14/.test(window.navigator.userAgent);
if (isIOS14Device) {
    cc.MeshBuffer.prototype.checkAndSwitchBuffer = function (vertexCount) {
        if (this.vertexOffset + vertexCount > 65535) {
            this.uploadData();
            this._batcher._flush();
        }
    };     
    cc.MeshBuffer.prototype.forwardIndiceStartToOffset = function () {
        this.uploadData();
        this.switchBuffer();
    }  
}

2.1.x

The 2.1.x version is similar, you still need to override the checkAndSwitchBuffer

const isIOS14Device = cc.sys.os === cc.sys.OS_IOS && cc.sys.isBrowser && cc.sys.isMobile && /iPhone OS 14/.test(window.navigator.userAgent);
if (isIOS14Device) {
    cc.MeshBuffer.prototype.checkAndSwitchBuffer = function (vertexCount) {
        if (this.vertexOffset + vertexCount > 65535) {
            this.uploadData();
            this._batcher._flush();
        }
    };    
}

However, forwardIndiceStartToOffset is not implemented in 2.1.x, so you need the following additional operations.
Customize engine and find model-batcher.js and replaces the last three lines in the _flush method likes the following code.

const isIOS14Device = cc.sys.os === cc.sys.OS_IOS && cc.sys.isBrowser && cc.sys.isMobile && /iPhone OS 14/.test(window.navigator.userAgent);

_flush () {
        let material = this.material,
            buffer = this._buffer,
            indiceStart = buffer.indiceStart,
            indiceOffset = buffer.indiceOffset,
            indiceCount = indiceOffset - indiceStart;
        if (!this.walking || !material || indiceCount <= 0) {
            return;
        }

        let effect = material.effect;
        if (!effect) return;

        // Generate ia
        let ia = this._iaPool.add();
        ia._vertexBuffer = buffer._vb;
        ia._indexBuffer = buffer._ib;
        ia._start = indiceStart;
        ia._count = indiceCount;
        
        // Generate model
        let model = this._modelPool.add();
        this._batchedModels.push(model);
        model.sortKey = this._sortKey++;
        model._cullingMask = this.cullingMask;
        model.setNode(this.node);
        model.setEffect(effect, this.customProperties);
        model.setInputAssembler(ia);
        
        this._renderScene.addModel(model);

        if (isIOS14Device) {
              buffer.uploadData();
              buffer.switchBuffer();
        }
        else {
              buffer.byteStart = buffer.byteOffset;
              buffer.indiceStart = buffer.indiceOffset;
              buffer.vertexStart = buffer.vertexOffset;
        }
  },

2.0.x

Customize the engine and use this file mesh-buffer.zip (1.5 KB)
to replace mesh-buffer.js in the engine. Then, do the same process likes the 2.1.x version above.


Note: You need to recompile the engine after customizing the engine in order to take effect. It is recommended to use different phones for full testing after these changes.

6 Likes