Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

High CPU usage with canvas and requestAnimationFrame

I am facing high CPU usage (30 to 40%) when calling recursively requestAnimationFrame, does anyone has good strategies to lower it down?

Simple example:

var canvas = document.createElement('canvas');
canvas.width = 100;
canvas.height = 20;

var canvasContext = canvas.getContext('2d');
document.body.appendChild(canvas)

var rafId;
function drawLoop(time) {
  canvasContext.clearRect(0, 0, 100, 20);
  canvasContext.fillRect(0, 0, Math.random() * 100 * 1.4, 20);
  rafID = window.requestAnimationFrame(drawLoop);
}

drawLoop();
like image 361
Laurent Avatar asked Feb 08 '15 03:02

Laurent


People also ask

Should I use requestAnimationFrame?

To optimize system and browser resources, it is recommended to use requestAnimationFrame , which requests the browser to execute the code during the next repaint cycle. This allows the system to optimize resources and frame-rate to reduce unnecessary reflow/repaint calls.

Is requestAnimationFrame better than setInterval?

requestAnimationFrame() is much more efficient than setTimeout() or setInterval() , and the result is smoother and more accurate (just check the provided demo and the consumed CPU).


1 Answers

I cannot get this example to do anything to my CPU worth mentioning, but I did manage to get it down by employing these two methods. My CPU was running at about 4-5% running your snippet, by running save / restore on the context that shaved off 2%.Unsure why - because we haven't made any transformations. The latter example just uses the old hacker way of doing this by resetting the canvas.width - this wipes the entire canvas context each time - and should be more expensive - however it got this example down to 1.4%

var canvas = document.createElement('canvas');
canvas.width = 100;
canvas.height = 20;

var canvasContext = canvas.getContext('2d');
document.body.appendChild(canvas)

var rafId;
function drawLoop(time) {
  canvasContext.save();
  canvasContext.clearRect(0, 0, 100, 20);
  canvasContext.fillRect(0, 0, Math.random() * 100 * 1.4, 20);
  canvasContext.restore();
  rafID = window.requestAnimationFrame(drawLoop);
}

drawLoop();
var canvas = document.createElement('canvas');
canvas.width = 100;
canvas.height = 20;

var canvasContext = canvas.getContext('2d');
document.body.appendChild(canvas)

var rafId;
function drawLoop(time) {
  canvas.width = canvas.width;
  canvasContext.fillRect(0, 0, Math.random() * 100 * 1.4, 20);
  rafID = window.requestAnimationFrame(drawLoop);
}

drawLoop();

Now I would need to go into more performance exploration to find out why, or if it actually does anything at all.

However you could employ a different drawing technique, such as just moving a sprite or a mask back and forth over some bitmap data, that will make this much less hard for the renderer to handle. I will not post that here as it goes beyond the scope of this question.

like image 120
Espen Avatar answered Oct 10 '22 11:10

Espen