Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CanvasRenderingContext2D.drawImage() very slow in Chrome on large canvas

I'm currently developing a web client (HTML5 and JavaScript) for my city building game project. The client interacts through SignalR with a web server written in C#/.NET, on which all the game logic resides.

The implementation requires quite a large map which is implemented by a set of canvas elements that represent different layers. The actual drawing of the map consists of drawing 25x25px cells, some of which are animated. That means that there's a lot of small 'drawImage'-invocations taking place on the '2D contexts'.

The current implementation works fine and smooth in Mozilla Firefox, Internet Explorer and Edge. It is however tremendously slow on Google Chrome, most likely due to the fact that the implementation does not play nice with its hardware accelerated rendering.

Acquisition of the tile cell .PNG-images are done through downloading them from the web server and storing them in in-memory 'Image'-objects. From there, I draw them directly to the canvas when necessary. If my current research is done correctly this is where the bottleneck resides; the source 'Image'-objects reside in CPU-memory whereas the target Canvas-element is optimized for GPU-memory access, resulting in a lot of swapping.

I have tried moving the 'Image'-objects to a large off-screen 'buffer' canvas (large enough so that the hardware acceleration is supposed to kick in on Chrome) but this does not produce a noticable difference: https://github.com/Miragecoder/Urbanization/commit/86ac62a785b233eea28c53b8a7d474ef92ffc283

I have also tried implementing deferred invocations of the 'drawImage'-function through requestAnimationFrame but this too did not produce noticeable differences.

I have the following questions:

  • Do I understand the problem correctly?
  • What can I do to improve the performance of the web client?

Some links to questions I have researched but so far with no result:

  • HTML5 Canvas slow on Chrome, but fast on FireFox
  • https://gamedev.stackexchange.com/questions/32221/huge-performance-difference-when-using-drawimage-with-img-vs-canvas
  • https://code.google.com/p/chromium/issues/detail?id=170021
  • Google Chrome hardware acceleration making game run slow
like image 320
Rob Wijkstra Avatar asked Dec 12 '15 14:12

Rob Wijkstra


1 Answers

Your main problem seems to be the number of different Image-objects you use to draw to the canvas. You absolutely should use a Textureatlas, putting as many graphics as possible in a single image.

You should then render your sprites from as few main-images as possible by specifying the relevant rectangle:

void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

instead of the whole image:

void ctx.drawImage(image, dx, dy);

see CanvasRenderingContext2D.drawImage() for details. This way, you avoid too many context switches. As Blindman67 mentioned, you should be careful to switch between texture atlases as few times as possible - for example, you may want to use a single texture atlas for all your rendering to canvas1, another one for all your images for canvas2 etc.

like image 102
T Grando Avatar answered Oct 22 '22 03:10

T Grando