CreateJS / EaselJS

The Easel Javascript library provides a full, hierarchical display list, a core interaction model, and helper classes to make working with the HTML5 Canvas element much easier.
http://createjs.com/
MIT License
8.14k stars 1.97k forks source link

stagegl 8x performance drop on low end phones ? #890

Open neurall opened 7 years ago

neurall commented 7 years ago

Hi guys. I know stagegl is in early stages. And we are glad that 2d stage can be moved to webgl easily just by changing stage to stagegl. The most important idea to move everything to webgl was performance gain. Due to text and single spritesheet limits we had all mostly static gui in 2d canvas rendered over heavily animated gl canvas Good thing is game somehow works just by simple stage->stagegl word change as mentioned in docs. Unfortunately animations run fast(15 fps framerate anim param seems ignored) also masking doesnt work but must importantly we are seeing nearly 8x drop in fps on low end devices where we need fps most. The main culprit is I guess inefficient buffersubdata upload to gpu every frame (due to bad drivers on cheap devices ?). having static vertices and modifying them each frame with shader constants each frame is faster at least on my desktop measurements it was 10 times faster. I am attaching screenshot how much time it took to render two stages (samsung s3 mini) on old and one merged stage on new createjs

createjs_1 8 2

createjs_next

lannymcnie commented 7 years ago

I responded regarding framerate in your other thread

Unfortunately animations run fast(15 fps framerate anim param seems ignored) also masking doesnt work

https://github.com/CreateJS/EaselJS/issues/888

Did that help?

DavidHGillen commented 7 years ago

having static vertices and modifying them each frame with shader constants each frame

From an architectural point of view, this is not a possibility. The amount of information needed to correctly position each card when stored in a hierarchical display tree requires JavaScript computation or using that much GPU overhead you loose every gain you would get. We push what we can off to the GPU. One of our shortlist items is a "Particle" container, this will have a shallow depth negating the hierarchical position expenses, allowing us to push more onto the GPU and get more speed out.

Usually low end device performance issues come from a problem with too many textures, as texture send rate to the GPU is one of the biggest killers for performance in WebGL, I want to make sure something like that isn't what's going on. Could you turn on StagelGL.vocalDebug = true; and give me a block of what your run-time output of this is console.log("Draw["+ this._drawID +":"+ this._batchID +"] : "+ this.batchReason); ? Vocal debug will make it say that every render, so don't worry about entering the code yourself.

Furthermore, if it really is an efficiency problem with the vertex buffer you could try adjusting the StageGL.DEFAULT_MAX_BATCH_SIZE, this is intended to be externally configurable but I haven't got all my i's dotted and t's crossed for that yet. So you might need to edit the .js file. It controls how much data is being updated to the vertex buffer so depending upon why your batches are ending(the data I asked for above) a smaller or larger number might help? We found pretty good performance with most devices at this value, but if adjusting it yields good results for you I'll prioritize making it configurable.

neurall commented 7 years ago

thx David. I am new at company and lot of our games are quite old and it looks they were written without any form of Redraw Regions with global stage,update. They were written in a hurry. Problem is how I refactor them for efficient mobile use. I wish It was at That time written without global stage.update but unless we implement some form of complex Redraw Regions we are stuck with redrawing all sprites every frame which is extremely inefficient and with a lot of overdraw. I am contemplating at least some form of scene reordering. disabling glclear. rendering static stuff(mostly 12% from canvas edges and border graphics) just once and calling update only on changed stuff. but pretty much 70% of our screen is changing all the time.

Anyway I am trying various DEFAULT_MAX_BATCH_SIZE values And maximum I got is 3 fps from value 1000

Draw[1486:2917] : drawFinish createjs-2017.06.20.combined.js:10897 Draw[1487:2918] : textureOverflow createjs-2017.06.20.combined.js:10897 Draw[1487:2919] : drawFinish createjs-2017.06.20.combined.js:10897 Draw[1488:2920] : textureOverflow createjs-2017.06.20.combined.js:10897 Draw[1488:2921] : drawFinish createjs-2017.06.20.combined.js:10897 Draw[1489:2922] : textureOverflow createjs-2017.06.20.combined.js:10897 Draw[1489:2923] : drawFinish createjs-2017.06.20.combined.js:10897 Draw[1490:2924] : textureOverflow createjs-2017.06.20.combined.js:10897 Draw[1490:2925] : drawFinish createjs-2017.06.20.combined.js:10897 Draw[1491:2926] : textureOverflow createjs-2017.06.20.combined.js:10897 Draw[1491:2927] : drawFinish createjs-2017.06.20.combined.js:10897 Draw[1492:2928] : textureOverflow createjs-2017.06.20.combined.js:10897 Draw[1492:2929] : drawFinish createjs-2017.06.20.combined.js:10897 Draw[1493:2930] : textureOverflow createjs-2017.06.20.combined.js:10897 Draw[1493:2931] : drawFinish

neurall commented 7 years ago

lannymcnie those animations i responded in #888 . thx a lot it was my fault. Sorry about that. ;(

DavidHGillen commented 7 years ago

you are hitting a "textureOverflow" but only one, if there was any way to reduce the number of specific new textures I might recommend that, but that doesn't seem like an easy win for 8x. Was this taken on the problem device? as different hardware has different texture overflow points.

Then again I might also recommend the exact opposite of less textures given one of your other comments. From what I gather sometimes you're drawing a lot of static elements some times and would love a way to not have to not update them? Have you looked into our cache() api?

For the cost of a new texture you can pre-render everything in a container and never worry about rendering it again until something changes, and then you can just updateCache. Caching is also the mechanism to draw unsupported content on StageGL, but you can use a StageGL to draw the cache and avoid a lot of texture streaming issues. In fact if all the uses of an image are in a cache it no longer gets loaded and could save you from overflowing that way.

var cont = new createjs.Container();
... add things to container...
stagegl.addChild(cont); // we have to do this first otherwise we can't re-use our StageGL instance to perform the cache
cont.cache(0,0, 200,200, 1, {useGL:"stage"}); // cache the appearance of the container using its parent StageGL

Caching isn't wise for something that's under constant animation as it just makes drawing it harder because it's updated every tick, but for something updating sparsely, then it is a huge win most of the time.

Hope it helps.

neurall commented 7 years ago

Yes I am still working on this low end device (samsung galaxy s3 mini).

We are already using caching due to texts requiring it in stagegl. Ie we converted all our text rendering to call .cache(bounds) after .text=. we collect bounds just once since they dont change. Yes the text bounds were off but thankfully just height so we just grow height by 20% so i guess we have like 10% ? waste but this is nothing compared to rest of overdraw happening and cached texts render now.

I guess some overdraw can be mitigated by flattening to one texture as you proposed. problems are those dirty areas. since dynamic text can be over multiple areas that would need to be updated too.

Thx for the tip I try what can be cached. But first I will try to draw static stuff just once by disabling glclear if there is any and. I guess set visible = false on sprites that didnt change from last scene update.