egret-labs / egret-core

Egret is a brand new open mobile game and application engine which allows you to quickly build mobile games and apps on Android,iOS and Windows.
http://www.egret.com
Other
3.92k stars 795 forks source link

iOS14 H5卡顿问题:部分解决方案(index buffer共享问题) #397

Closed kenkozheng closed 3 years ago

kenkozheng commented 4 years ago

egret默认设置12288大小的index buffer,每次drawcall都使用这个index buffer + offset 方式,一般来说,这是一个优化措施。但对iOS14成了负担,导致性能骤降。

我们游戏项目已自行修改引擎,建议官方尽快修复。 附件是我们自己的修改方案,希望能给官方一些有用参考。

WebGLRenderContext.ts ` public $drawWebGL() { if (this.drawCmdManager.drawDataLen == 0 || this.contextLost) { return; }

        const indices = this.vao.getIndices();
        const vertices = this.vao.getVertices();

        // 非iOS14,正常把整个vertex buffer一次推送
        if (!isIOS14Device) {
            this.uploadVerticesArray(vertices);
        }

        // 有mesh,则使用indicesForMesh
        if (this.vao.isMesh()) {
            this.uploadIndicesArray(this.vao.getMeshIndices());
        }

        let length = this.drawCmdManager.drawDataLen;
        let offset = 0;
        for (let i = 0; i < length; i++) {
            let data = this.drawCmdManager.drawData[i];
            let isDrawCall = data.type == DRAWABLE_TYPE.TEXTURE || data.type == DRAWABLE_TYPE.RECT || data.type == DRAWABLE_TYPE.PUSH_MASK || data.type == DRAWABLE_TYPE.POP_MASK;
            // 如果是ios14,而且不是mesh,则走新的流程渲染,每个drawcall单独推所需最小的index buffer和vertex buffer
            if (isIOS14Device && !this.vao.isMesh() && isDrawCall) {
                this.uploadIndicesArray(indices.subarray(0, data.count * this.vertexCountPerTriangle)); // data.count是三角形数目,*3 就是index数量
                this.uploadVerticesArray(
                    vertices.subarray(
                        offset / this.vertexCountPerTriangle * this.triangleCountPerQuad * this.dataCountPerVertex,
                        (offset + data.count * this.vertexCountPerTriangle) / this.vertexCountPerTriangle * this.triangleCountPerQuad * this.dataCountPerVertex
                    )
                ); // data.count是三角形数目,对应 *3*2/3的顶点数,每个顶点5个值
                this.drawData(data, 0); //每次只推送本次drawcall所需的最小的indexBuffer和vertexBuffer,就没有offset了
                offset += data.count * this.vertexCountPerTriangle; // offset只用于保持egret原有逻辑,索引vao.vertices,取subarray
            } else {
                offset = this.drawData(data, offset);
            }
            // 计算draw call
            if (data.type == DRAWABLE_TYPE.ACT_BUFFER) {
                this.activatedBuffer = data.buffer;
            }
            if (isDrawCall) {
                if (this.activatedBuffer && this.activatedBuffer.$computeDrawCall) {
                    this.activatedBuffer.$drawCalls++;
                }
            }
        }

        // 切换回默认indices
        if (this.vao.isMesh()) {
            this.uploadIndicesArray(this.vao.getIndices());
        }

        // 清空数据
        this.drawCmdManager.clear();
        this.vao.clear();
    }

`

kenkozheng commented 3 years ago

官方5.4版已合入这部分修改。

https://github.com/egret-labs/egret-core/commit/468f549d29420f7127b7b70ab5ef11ed00b5335e