7

I'm trying to write a simple raycaster using an HTML5 canvas and I'm getting abysmal framerates. Firefox's profiler reports 80% of my runtime is spent in context2d.fillRect(), which I'm using per column for floors and ceilings and per pixel on the textured walls. I came across this question, and found that fillRect was faster than 1x1 px pictures by 40% on chrome and 4% on firefox. They mention how it's still calculating alpha stuff, although I'd assume if the alpha is 1 it'd have a pass through for opaque rendering? Are there any other methods for doing a lot of rectangle and pixel blitting with javascript I should try out?

Community
  • 1
  • 1
zacaj
  • 1,987
  • 1
  • 19
  • 39
  • Actually, I think you should try WebGL. As far as I know, WebGL has more browsers with hardware acceleration than canvas 2d. – wendelbsilva Aug 11 '13 at 01:34
  • 1
    Canvas 2d is not really perfected in browsers yet in terms of performance, it varies hugely between browsers. I'm sure it will improve in the future. But until then i would say use WebGL as mentioned above. I'm also convinced it'll replace Flash completely. – Sir Aug 11 '13 at 01:35
  • is webgl enabled by default in browsers nowadays? I'd been using canvas with the hope for better compatability – zacaj Aug 11 '13 at 01:39
  • @zacaj check this [website](http://caniuse.com/webgl). They have a list of webgl compatibility. Of course this do not take in consideration that some graphic cards blacklisted. – wendelbsilva Aug 11 '13 at 01:48
  • drawImage might be faster, hard to tell with no code. – rlemon Aug 11 '13 at 02:24
  • @rlemon do you mean constructing the whole image in memory and then blitting it using drawimage or making the rectangles and then blitting them individually with drawimage? – zacaj Aug 11 '13 at 02:52
  • I assume there is a lot of repeating shapes. Or all repeating shapes, and are the different colors? FillStyle changes are more expensive than fill. also see this http://jsperf.com/canvas-draw-image-vs-fill-rect/5 – rlemon Aug 11 '13 at 12:24
  • 2
    Need to see some code. Depending on how you are doing it createImageData + putImageData are *much* faster than fillRect heres a quick example that displays over 20k particles http://www.somethinghitme.com/projects/masspart/ – Loktar Aug 11 '13 at 17:44
  • Following on @wendelbsilva, ProcessingJS works with WebGL and its quite nice to use. – fartagaintuxedo Aug 25 '13 at 17:25
  • I am not exactly sure I understand what you are asking, If I am correct though these links may be of some help to you. 1:http://gotoandlearn.com/play.php?id=144 2:http://jsperf.com/canvas-image-blitting – VivecVelothian Sep 23 '13 at 02:14
  • I found out that fillRect is much slower when you have the page visible. If you switch to another tab and then comes back to the page it's much faster (10x sometimes) – stallingOne Feb 22 '18 at 11:26

2 Answers2

3

A solution I have found to this is to put the fillRect() call inside a path each time you call it:

canvasContext.beginPath();
canvasContext.rect(1, 1, 10, 10);
canvasContext.fill();
canvasContext.closePath();

It seems that the call to rect() adds to the path of the previous rect() call, if used incorrectly this can lead to a memory leak or a buildup of resource usage.

BBales
  • 6,588
  • 3
  • 16
  • 19
  • fillRect method does create a temporary Path object, it doesn't add anything to previously set path, and in your code the closePath() call is not needed – Kaiido Jan 20 '17 at 07:25
  • fill() + rect() take up ~30% when I run profiler on my js vs just doing a fillRect() takes up ~20% – Octopus Jun 13 '17 at 04:46
  • I don't know why this works, but it works. In my case, I found that replacing the pattern I was using with a solid color also fixed the performance issues, but then, of course, it looked wrong. This takes the drawing operation from > 20ms for just a small fillRect to < 1ms without any visual changes. – Nathan Friedly Sep 14 '22 at 20:50
1

There are two solutions that you could try in order to reduce the CPU usage of your renderings.

Try using requestAnimationFrame in order for your browser to render your canvas graphics whenever it is ready and especially only when the user has the canvas tab opened in the browser. More info: https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame

Second solution, depending on whether part or all of your content is dynamic, is to pre-render portions of your canvas on other "hidden" canvas in memory with JavaScript (for instance you split your main canvas in 4 sub canvas then only have to draw 4 elements on screen).

PS: If you're on a mac using Firefox combined with multiple canvas renderings will boost your CPU usage compared to Chrome

Hope this helps

Alex
  • 565
  • 2
  • 6
  • 17