hiloteam / Hilo

A Cross-end HTML5 Game development solution
https://hiloteam.github.io/
MIT License
5.94k stars 863 forks source link

Improve Text performance #74

Closed ErosZy closed 7 years ago

ErosZy commented 7 years ago

我们在执行弹幕性能测试时发现:

  1. Text在cache后没有使用缓存造成性能低下
  2. Text.measureFontHeight方法使用了DOM的方式,尽管absolute,但仍然会对html进行reflow,修改为pixi.js的像素计算的方式后会有更好的性能

修改后在我的mac上性能提升比较明显(air 2013 Chrome浏览器全屏分辨率,从左到右移动,不同速度):

  1. n个相同字符串("Hello World!Hilo是一款HTML5 2D游戏引擎,欢迎使用"):1000(58-60fps), 2000(35-40fps); 3000(25-28fps); 4000(18-20fps),性能与pixi.js相近
  2. n个不完全相同字符串(''+Math.random()):1000(44-55fps), 1400(15-23fps) 与未加prepare模块的pixi.js相近

同时初始化时没有进行DOM的addChild和removeChild以及offsetHeight操作的,其显示速度也与之前相比有很大的提升。

06wj commented 7 years ago

感谢pr,我测试下。 ps:提交代码时不要提交build的代码

ErosZy commented 7 years ago

修改了部分的Text代码,抽出了measureWidth防止_draw的时候两次计算,修复了draw cache后存在的一些bug问题及与DOM需要兼容的部分

ErosZy commented 7 years ago

CanvasRender的draw部分,修改为优先使用_cacheCanvas而不是image,drawImage传入canvas在内部是GPU的二进制拷贝,而image需要进行一层decode。修改后对比pixi.js,Text部分性能基本一致,还会高一点(windows i7核显,5000个在25fps左右,10000个在15fps左右)。

ErosZy commented 7 years ago

附上测试的例子:

      function init(){
            var gameContainer = document.getElementById("game-container");
            var stageWidth = 800;
            var stageHeight = 600;
            var renderType = 'canvas';

            var stage = new Hilo.Stage({
                renderType: renderType,
                container: gameContainer,
                width: stageWidth,
                height: stageHeight
            });

            //start stage ticker
            var ticker = new Hilo.Ticker(60);
            ticker.addTick(stage);
            ticker.start();

            var font = "14px arial";

            //text view
            var arr = [];
            for(var i = 0; i < 5000; i++){
                var text = new Hilo.Text({
                    font: font,
                    text: ''+Math.random(),
                    width: 250,
                    height: 40,
                    maxWidth: 250,
                    x: stageWidth * Math.random() - stageWidth,
                    y: stageHeight * Math.random()
                });

                text.speed = Math.random() * 10;
                text.cache(true);
                text.addTo(stage);
                arr.push(text);
            }

            ticker.addTick({
                tick: function(){
                    for(var i = 0, len = arr.length; i < len; i++){
                        if(arr[i].x < 0 || arr[i].x >= stageWidth){
                            arr[i].visible = false;
                        }else{
                            arr[i].visible = true;
                        }

                        if(arr[i].x >= stageWidth){
                            arr[i].x = stageWidth * Math.random() - stageWidth;
                        }

                        arr[i].x += arr[i].speed;
                    }
                }
            })
        }