Jump to content

Canvas rendering and JS code optimization


Recommended Posts

Hi all,

as already title points out, this will be once more a thread about different possible ways to optimize performance of Canvas rendering and JS code execution.

I hope I will not get too long with everything. At the same time I hope this thread will help a lot of other dev enthusiasts to optimize their games as much as possible. In the end, we all love playing flawless gameplay :)

I'm creating some sort of Match3 game for desktop and mobile devices, and I'm using Phaser CE (v2.11.0). This work week will be reserved for doing and trying out different optimization options, and I hope you can give me advice about which changes should bring me the biggest performance boost for my game. I will list a few options, which I think could be beneficial for improving the performance. What I'm trying to figure out, is how big of a performance boost will I get out with such a change, and what is the best way to measure performance changes, How to figure out if some change improved or worsened game behavior. For now I'm tracking FPS, DrawCalls, and from Chrome Task Manager Memory Footprint, GPU Memory and JS Memory. One think that I still need to look up and learn is how to make use of Performance and Memory tabs from DevTools - does anyone know for any good tutorial?

So, let's start:

Adapting the game size to the actual devices screen size is beneficial. You can right away notice change in reserved GPU Memory size. My system checks devices screen size, and then picks one of the four different supported resolutions -> 1080p, 720p, MID size, and LOW size resolution. It then also auto picks appropriate pre-scaled assets. Afterwards it's scales the whole game up or down to fit the entire screen (i'm keeping the AR).
Methods for those are: ScaleManager.setUserScale(...) and ScaleManger.setGameSize(..)

The game has one full screen fully opaque background image. It is pretty straightforward placing and positioning the BG image with help of CSS as its own DOM element placed behind the canvas. One of the things you should not forget though is setting the canvas transparent property to true. All good and fine, until I saw funky behavior of my animations that were using Blending Modes. Suddenly there were some strange black borders visible ((you can check the provided short video)). So I'm left with:
a) use CSS bg image (using transparent Canvas bg), and not be able to use effects done with help of Blend Modes
b) bg image is still drawn with Canvas and I can still use Blend Modes
How could I now check or measure the performance difference using one or other approach (bg image with CSS, or rendered with Canvas)?

I've noticed that Phaser supports working with round pixels --> Phaser.Game.Renderer.renderSession.roundPixels. Enabling this option f**k-ed up my translations and scalings, because you were able to notice annoying flickering. I could do nothing else but disabling it. What I'm now doing is to manually Math.floor values wherever I don't see any issues afterwards.
Once more, how big of an impact has this on the performance? Let's say that the game has like 60 sprites on the stage, half of them in constant movement.  

You are able to set through Phaser.Game.Time.desiredFPS property a frame rate for the whole game. As far as I'm aware of this can bring you some improvements to the game in a way that the renderer does not need to draw the whole game 60 times per second but only 30 times for example. It can be beneficial if you can notice some lagging, and probably can be used set to default 30 FPS for mobile devices if your game isn't heavy physics dependent? 
I would like to know something else regarding the desired FPS, is in Phaser a simple option for setting different frame rate per Phaser.Group? For example, I have my whole User Interface in one Phaser.Group,  which does not need to be updated 60FPS, but would be perfectly enough to set it to 20FPS.

This is one of the more classical ones, which should every developer be aware of. Use compressed textures wherever possible if possible. Why if? Some compression formats can f**k up the quality of your images, depends on the number of details, gradients, transparency, etc...But it significantly reduces memory footprint, and improves performance. 
I'm already using and compressing Atlases , where there is a possibility to do it (read: minimal artifacts).

6. Phaser.Sprite vs Phaser.Image
How do those two perform? If I do not need any physics on my objects, will I get any boost using only Phaser.Image type instead of Phaser.Sprite? The main difference between those two is that Sprite has additional 3 or 4 components on it? Again if I change all my objects from Sprite to Image, how to measure performance changes?

First of all I just stumbled upon that option a few days ago. Guys at Mozilla are mentioning that it should improve the rendering performance. Sadly I don't know enough knowledge to explain why and how it improves rendering. And as far as I know it is supported only on Chrome and Firefox browsers. Would it be worth writing an extra system to do rendering with help of OffScreen canvas? Is anyone using it? What are your thoughts about it?

This is a classic game programming pattern system which I'm already using in my game, for all the moving object, which appear/disappear, and thus optimizing GC. 

I would like to know what performs better. I've created kind of a reflection effect (you can check the provided short video). 
part of the code using Alpha masking:

let reflBMData: Phaser.BitmapData = this.game.make.bitmapData(w, h);
reflBMData.alphaMask(refl_glow, refl_mask);
let reflectionImg: Phaser.Sprite = new Phaser.Sprite(this.game, 0, 0, reflBMData);
reflectionImg.blendMode = Phaser.blendModes.ADD;

let tweenX = this.game.add.tween(refl_glow).to({ x: refl_glow.x + 1500 }, 1500, Phaser.Easing.Linear.None, true, 1000, -1, true);
tweenX.onUpdateCallback(() => { this.reflBMData.alphaMask(refl_glow, refl_mask);  }, this);


part of the code using CropRect

let cropRect: Phaser.Rectangle = new Phaser.Rectangle(0, 0, 0, target.height);
reflImg.crop(cropRect, false);
let tweenX: Phaser.Tween = new Phaser.Tween(cropRect, game, game.tweens).to(
{ width: Math.floor(w) }, duration, Phaser.Easing.Linear.None, autoStart, delay, 0, false);
tweenX.onUpdateCallback((tween: Phaser.Tween, value: number, tweenData: Phaser.TweenData) => {
   reflImg.x = (cropRect.width - w) * 0.5;
}, this);

I would guess that using CropRect is better.


I think this will be enough for now :) So my main questions are: what's the best way to measure performance changes, AND in what order would you sort above mentioned possible ways to improve the game, from most important/beneficial to less important. 

Also, if you think I've missed something that should go into the list, please let me know. Any kind of optimization options are more than welcomed. 

br, mcofko




Link to comment
Share on other sites

For performance comparisons, you can use the browser's FPS meter or the browser's profile tool. It's a little tricky to compare profiles; you have to record identical durations and then compare raw time spent.

3. roundPixels is supposed to help more on less-powerful devices in CANVAS mode. Also interacts with Camera#roundPx.

4. The fps setting is global, as there's only one game loop. If you reduce desiredFps you should probably disable Game#forceSingleRender as well so you're not wasting renders.

6. You should prefer Phaser.Image where you can but the difference is probably very small. Image and Sprite are more similar now than in earlier versions. If you want to squeeze out extra performance here you might modify or remove the preUpdate/postUpdate methods (very carefully).

7. I think Phaser would have to be rewritten to really benefit from Offscreen Canvas.

9. I would guess cropRect, because it's simpler. 

Link to comment
Share on other sites

was hoping the topic would get more traction....

It seems I will need to dig in into different tutorials around web tools and its Memory and Performance profilers. Which browser gives you better options, Chrome or Firefox?

Tnx samme for your feedback. Tnx for pointing out on forceSingleRender, that's quite an important flag. I'll update all Sprites to Images then, maybe I'll get a minimal boost.
2. CSS background - what about here? How much boost would I get here, if most of my target devices will use WebGL rendering (normal (high) - powerful devices)?
9. How expensive operations are actually BlendModes? Their main role is to go trough all image pixels, and apply the correct blend formula equation for each pixel, to get the correct output pixel color?
10. I've noticed a small frame drop each time I've played an animation for the first time (especially an animation using blending modes, or reflection effect done with alpha masking). Would it help if I would create and play an animation offscreen on game initialization? 

p.s.: samme could you explain how  cropRect functionality is working when you applying it on an image living in texture atlas? When I'm moving cropRect position, why does it move the image also?


Link to comment
Share on other sites


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...