slaylines / canvas-engines-comparison

Performance comparison of different canvas rendering engines.
https://benchmarks.slaylines.io
MIT License
779 stars 84 forks source link

CanvasKit can be much faster #42

Open norbert-gaulia opened 2 years ago

norbert-gaulia commented 2 years ago

latest canvaskit-wasm ^0.35.0 has a beast webGPU surface and new CanvasKit.RuntimeEffect

by using custom vertices array and a single uniform color it can spin 1M quads of varying size and positions no problem,

Varying color quads (change color every quad) spins 50k-100k comfortably even if you recompile shader every few hundred passes.

It goes something like this:

 const spiralSkSL = `
    uniform float4 in_colors0;
    half4 main(float2 p) {
        return in_colors0;
    }`;

 const effect = CanvasKit.RuntimeEffect.Make(spiralSkSL);
  let shader = effect.makeShader(
      [
          1, 0, 0, 0.8
      ]);
let vpaint = new CanvasKit.Paint();
vpaint.setShader(shader);

let allPoints = [];
const addPoint = (bbx, bby, bbw, bbh,) => {
    allPoints.push(
        bbx, bby,
        bbx + bbw, bby,
        bbx, bby + bbh,

        bbx + bbw, bby,
        bbx, bby + bbh,
        bbx + bbw, bby + bbh);
}

  function drawFrame(canvas) {
            canvas.clear(CanvasKit.TRANSPARENT);

            allPoints = [];
            let x0 = 0;
            let y0 = 0;

            vpaint.setShader(effect.makeShader([
                1, 0, 0, 0.8
            ]));

            for (let j = 0; j < 100000; j++) {
                addPoint(x0, y0, 3, 3);
                x0 += 4;
                if (x0 > 2000) {
                    x0 = 0;
                    y0 +=4;
                }
                if (j > 1 && j % 10000 === 0) {
                    let vertices = CanvasKit.MakeVertices(CanvasKit.VertexMode.Triangles,
                        allPoints, null, null,
                        false /*isVolatile*/);
                    canvas.drawVertices(vertices, CanvasKit.BlendMode.Dst, vpaint);
                    allPoints = [];

                    vertices.delete();
                    shader.delete();
                    shader = effect.makeShader([
                        Math.random(), Math.random(), Math.random(), 1
                    ]);
                    vpaint.setShader(shader);
                }
            }
            surface.requestAnimationFrame(drawFrame);
        }

        surface.requestAnimationFrame(drawFrame);
}

Not to mention that this way you will have all skia infrastructure along with font manager.

Canvaskit source has a lot of great examples;

mkalygin commented 2 years ago

Thanks @norbertas-gaulia, this looks really interesting. We'll consider adding CanvasKit WebGPU example to the comparison unless you want to make a PR. 😄

norbert-gaulia commented 2 years ago

For Webgpu i guess need a bit to wait it's still buggy as hell, but same method will work on webgl2 api just as good, ill try to make PR when i have more time. Btw there is DeckGL fork managing 1M quads which is pretty much the same approach.