Why isn't canvas 2D context using WebGL under the hood?

Viewed 1368

I have used canvas 2D context quite a lot, and recently started to learn some WebGL as well.

The question in the title came to me when I was working on a tutorial on how to implement context.drawImage() from 2D context in WebGL. The result was something that worked like context.drawImage() (at least pretty close), but was much faster because it was using WebGL.

In theory, I believe everything in canvas 2D context could be emulated in WebGL, resulting in large performance gains. So why isn't it?

I'm defenitely not talking about changing any syntax or anything. I really like the simplicity of 2D context. But why isn't the browser doing what that tutorial did under the hood?

I understand that WebGL doesn't have full support everywhere, but I still think that it could be used if possible, with regular 2D context as fallback.

1 Answers

Canvas2D does use the GPU under the hood using basically the same API as WebGL.

It's likely that if you implement the entire Canvas 2D spec in WebGL it will be a similar speed. Canvas supports things like drawing with patterns, drawing with gradients, clipping paths, lines with arbitrary widths, ends, joins, etc... Add all those features into your Canvas implemented in WebGL and it might a similar speed.

The reason WebGL can be faster is (a) because you can choose not to implement the features you are not going to use and (b) because you can optimize knowing you're only going to use certain features.

As a simple example, in canvas you can draw an image with drawImage(someImageElement, x, y). In WebGL you first have to create a texture from the image, then draw using the texture so you manually manage that texture. Canvas actually has to do the same thing. It had to load the image into a texture in order to draw it (assuming it's GPU based which canvas usually is). But, it has no idea if you're going to draw the image again so it can't keep that image as a texture forever. The simplest implementation would be to copy the image to a texture, draw, then delete the texture. I doubt that is what canvas does, I'm guessing it has some cache of textures it has made from images. But, the point is, it's management of textures is implicit where as in WebGL it's explicit, you have to manually manage the textures yourself.

Another example is drawing shapes. In WebGL you generally decide what shapes to draw at init time, setup all the data needed to draw them, then at render time you just use the shapes you already setup. In Canvas it's more common to draw shapes on the fly meaning each time you want to draw the shape you use moveTo and lineTo commands to plot out the shape, which is effectively doing all the work every time you render instead of like WebGL doing that work only at init time.

It's differences like those that add up to canvas being easier and webgl being faster.

Note: some people have tried to implement canvas2d in WebGL here and here

Related