Canvas API calls vs. matrix computing

JavaScript performance comparison

Test case created

Preparation code

<canvas width="640" height="480" id="canvas1"></canvas>
<canvas width="640" height="480" id="canvas2"></canvas>
<script>
Benchmark.prototype.setup = function() {
    var transform2d = (function() {
      var matrix = new Float32Array(6) || new Array(6),
        maxStackDepth = 512 * matrix.length,
        matrixStack = new Float32Array(maxStackDepth) || new Array(maxStackDepth),
        currentPos = 0,
        i;
   
      function identity() {
        matrix[0] = 1;
        matrix[2] = 0;
        matrix[4] = 0;
        matrix[1] = 0;
        matrix[3] = 1;
        matrix[5] = 0;
      }
   
      function translate(x, y) {
        matrix[4] += matrix[0] * x + matrix[2] * y;
        matrix[5] += matrix[1] * x + matrix[3] * y;
      }
   
      function scale(sx, sy) {
        matrix[0] *= sx;
        matrix[1] *= sx;
        matrix[2] *= sy;
        matrix[3] *= sy;
      }
   
      function rotate(a) {
        var cos = Math.cos(a),
          sin = Math.sin(a),
          mAA = matrix[0] * cos + matrix[2] * sin,
          mAB = matrix[1] * cos + matrix[3] * sin,
          mBA = -matrix[0] * sin + matrix[2] * cos,
          mBB = -matrix[1] * sin + matrix[3] * cos;
   
        matrix[0] = mAA;
        matrix[1] = mAB;
        matrix[2] = mBA;
        matrix[3] = mBB;
      }
   
      function push() {
        matrixStack[currentPos++] = matrix[0];
        matrixStack[currentPos++] = matrix[1];
        matrixStack[currentPos++] = matrix[2];
        matrixStack[currentPos++] = matrix[3];
        matrixStack[currentPos++] = matrix[4];
        matrixStack[currentPos++] = matrix[5];
      }
   
      function pop() {
        matrix[5] = matrixStack[--currentPos];
        matrix[4] = matrixStack[--currentPos];
        matrix[3] = matrixStack[--currentPos];
        matrix[2] = matrixStack[--currentPos];
        matrix[1] = matrixStack[--currentPos];
        matrix[0] = matrixStack[--currentPos];
      }
   
      function transformContext(ctx) {
        ctx.setTransform(matrix[0], matrix[1], matrix[2],
          matrix[3], matrix[4], matrix[5]);
      }
   
      return {
        transformContext: transformContext,
        identity: identity,
        translate: translate,
        scale: scale,
        rotate: rotate,
        push: push,
        pop: pop,
        matrix: matrix
      };
    }());
   
    var canvas1 = document.querySelector('#canvas1'),
      ctx1 = canvas1.getContext('2d'),
      canvas2 = document.querySelector('#canvas2'),
      ctx2 = canvas2.getContext('2d');
   
    ctx1.fillStyle = 'black';
    ctx2.fillStyle = 'black';
   
    transform2d.identity();
};
</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
Matrix with push/pop
transform2d.push();
transform2d.translate(canvas1.width / 2, canvas1.height / 2);
transform2d.push();
transform2d.rotate(Math.PI / 4);
transform2d.translate(-10, -10);
transform2d.transformContext(ctx1);
ctx1.fillRect(0, 0, 20, 20);
transform2d.pop();

transform2d.push();
transform2d.rotate(-Math.PI / 3);
transform2d.scale(4, 4);
transform2d.translate(-10, -10);
transform2d.transformContext(ctx1);
ctx1.fillRect(0, 0, 20, 20);
transform2d.pop();
transform2d.pop();
pending…
Canvas API with save/restore
ctx2.save();
ctx2.translate(canvas2.width / 2, canvas2.height / 2);
ctx2.save();
ctx2.rotate(Math.PI / 4);
ctx2.translate(-10, -10);

ctx2.fillRect(0, 0, 20, 20);
ctx2.restore();

ctx2.save();
ctx2.rotate(-Math.PI / 3);
ctx2.scale(4, 4);
ctx2.translate(-10, -10);

ctx2.fillRect(0, 0, 20, 20);
ctx2.restore();
ctx2.restore();
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment