1

I have written a Windows 8 game metro style using Javascript. I have a problem that makes the game too slow when I set gameContext with shadow or transparent.

ctx.shadowColor="black";
ctx.shadowBlur = 10; 

ctx.globalCompositeOperation = "lighter";
ctx.globalAlpha = 0.3;

How can I improve the game's performance?

Simon Adcock
  • 3,554
  • 3
  • 25
  • 41
goose
  • 47
  • 1
  • 8

2 Answers2

5

Well…

Don’t use shadows because they are the enemy of performance: http://www.html5rocks.com/en/tutorials/canvas/performance/

But, you can get shadowed results without using shadows!

You can dramatically speed up your draws by saving your objects as cached images. Below is a comparision of drawing with shadows versus drawing a cached image. Drawing with cached images is hundreds of times faster then drawing with shadows.

enter image description here

Here is code and a Fiddle: http://jsfiddle.net/m1erickson/7YcaC/

<!DOCTYPE HTML>
<html>
  <head>
    <style>
      body { margin: 0px; padding: 20px; }
      canvas { border: 1px solid red; margin:10px; }
    </style>
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
  </head>
  <body>
    <p id="shadow">Redraw using shadows</p>
    <canvas id="myCanvas1" width="220" height="120"></canvas><br/>
    <p id="cache">Redraw using a cached image</p>
    <canvas id="myCanvas2" width="220" height="120"></canvas>
    <script>
      var canvas1 = document.getElementById('myCanvas1');
      var context1 = canvas1.getContext('2d');
      var canvas2 = document.getElementById('myCanvas2');
      var context2 = canvas2.getContext('2d');

      // create a cache image of the shadowed rectangle
      draw1();
      var image=new Image();
      image.src=canvas1.toDataURL();

      var t1=new Date().getTime();
      console.log(t1);
      for(var i=0;i<100;i++){ draw1(); }
      var t2=new Date().getTime();
      console.log(t2);
      for(var i=0;i<100;i++){ draw2(); }
      var t3=new Date().getTime();    
      console.log(t3);
      alert((t2-t1)+"/"+(t3-t2));
      $("#shadow").text("Redraw using shadows took "+(t2-t1)+" ms");
      $("#cache").text("Redraw using cached image took "+(t3-t2)+" ms");

      function draw1(){
          context1.clearRect(0,0,220,120);
          canvas1.width=220;
          canvas1.height=120;
          context1.rect(10, 10, 200, 100);
          context1.fillStyle = 'red';
          context1.shadowColor = 'black';
          context1.shadowBlur = 10;
          context1.shadowOffsetX = 5;
          context1.shadowOffsetY = 5;
          context1.fill();
      }

      function draw2(){
          context2.clearRect(0,0,220,120);
          context2.drawImage(image,0,0);
      }

    </script>
  </body>
</html>
markE
  • 102,905
  • 11
  • 164
  • 176
  • Thanks markE, Better way is use Photoshop to transparent and shadow image. – goose Mar 30 '13 at 05:38
  • 2
    If you run the jsfiddle in 2020, their performance is nearly identical. On my machine running Chrome 81 `draw1()` takes 3ms and `draw2()` takes 2ms. I assume this is because canvas graphics are GPU accelerate by default today, whereas in 2013 this was not always the case. – sloreti May 27 '20 at 18:54
1

I am not sure but this sometimes helps, Add this to your css

canvas
{
    -webkit-transform3d: translate(0,0,0);
    -moz-transform3d: translate(0,0,0);
    transform3d: translate(0,0,0);
}

What this actually does is that it forces the browser to use GPU to render the canvas. And hence increase in the performance. Unfortunately, this fix is only for browsers which support 3d transformations.

Parthik Gosar
  • 10,998
  • 3
  • 24
  • 16