SVG vs canvas performance

On Sat, Jul 16, 2011 at 3:11 AM, Henri Sivonen <hsivonen@iki.fi> wrote:

> Do you have examples of people choosing <canvas> over SVG for perf
> reasons? Are the perf reasons data-based or merely assumed? Are the perf
> reasons the kind of quality of implementation issues that can be
> considered to be transient and addressed over the next couple of years?
>
> In theory, SVG should be able to outperform <canvas> for painting,
> because the browser engine gets to control how often to repaint, what
> parts to repaint and can avoid intermediate bitmaps when the path
> stroking and filling can be performed nearer hardware and there are
> guaranteed not to be readbacks because the browser knows there aren't
> filters in use.
>
> So in theory, if SVG has performance issues, they should be attributable
> to the DOM. If a sub-DOM is used for accessibility in the <canvas> case,
> then the <canvas> case has a DOM, too.
>

heycam and I talked this through over lunch the other day as a thought
experiment. Basically, we compared what the browser does with the IE
FishTank demo vs what the browser would do with a hypothetical,
naturally-written SVG FishTank demo. (Assuming 2000 fish since everyone
maxes out at 60fps on 1000 fish on high-end systems these days.)

First of all, animating the fishes is a pain in SVG. You either use an SVG
element with an animated image, or an SVG element whose image href you
change constantly. The former approach is hard because you want to be able
to control the animation frame at which each fish starts, and there's no
existing API for that. The latter approach would be hard to make fast since
conceptually you'd be doing a full image load per fish per frame. In theory
we could make it pretty fast, but you'll undoubtedly have more overhead than
you do in canvas where you just pick the frame you want (by choosing the
right source rectangle of the tiled image) and draw it.

The IE FishTank uses tiling; all fish images are stored as subrectangles of
a single large image. This actually translates into performance benefits in
many cases because repeated drawing from the same source image is more easy
to optimize on the GPU (you can just keep appending to a vertex buffer).
Explicit tiling with SVG is a bit more clumsy. It would rule out the
animated image approach above. You'd probably use a fill pattern (or in the
future, media fragments) or possibly a new CSS image value like
-moz-image-rect, extended for use as an SVG paint server (also in the
future). That would all add overhead. Alternatively, we could try to
automatically get the benefit of tiling by cache frequently drawn images
into a single source texture. We'll probably need to do that, but it'll be
quite complex.

Handling transform changes could be an issue. If we unify CSS transforms
with SVG transforms then transform changes would require some level of style
reresolution, which would be significant overhead. If we don't, it's not so
bad, but it still requires DOM manipulation that's heavier-weight than just
varying the parameters to a canvas drawImage call.

For canvas we improved performance noticeably by optimizing window
invalidation. When lots of little things are changing you just want to
redraw the whole window once per frame and not bother tracking invalidation.
We'd need to extend that optimization to SVG and other DOM changes (doable).

Your point about intermediate buffers doesn't really matter too much in IE
FishTank, where we're drawing 2000 fish for every buffer draw, and the
buffer draw is relatively fast (and pipelined). All that matters is how fast
you can draw a given (sub)image with a given transform. We're doing 80,000
drawImages per second in FishTank on Firefox trunk on my laptop, so the
overhead of each draw is significant. Even a single QueryInterface or
dynamic memory allocation per draw can show up on profiles.

Overall I'd say there's a lot we can do to make simple image-blitting
workloads (which covers a lot of games for example) much faster in SVG, but
I'm very doubtful they'll ever be as fast in SVG as in canvas, especially if
the canvas code has been hand-optimized to use explicit tiling. But we can
probably make SVG "fast enough" so that most of the things you would use
canvas for are fast enough in SVG.

Your point about the canvas sub-DOM is relevant. If you require the canvas
implementation to be accessible (and I'm not sure what that would mean for
FishTank), you'll be adding overhead. How much overhead is unclear.

Rob
-- 
"If we claim to be without sin, we deceive ourselves and the truth is not in
us. If we confess our sins, he is faithful and just and will forgive us our
sins and purify us from all unrighteousness. If we claim we have not sinned,
we make him out to be a liar and his word is not in us." [1 John 1:8-10]

Received on Saturday, 16 July 2011 11:30:03 UTC