CanvasGL vs CairoGL on batch

The design and implementation of CanvasGL and CairoGL are very similar because both process 2D vector graphics drawing calls using GPU. However, the performance of CanvasGL is better in many cases because CanvasGL can batch more drawing calls than CairoGL.


1. What Batch is

Drawing calls can be categorized into two groups: 1) drawing calls of 2D vector graphics API and 2) glDrawElement and glDrawArray of OpenGL. Drawing call batch in the context of CanvasGL implementation means the minimization of glDrawElement and glDrawArray calls.

Drawing call batch is possible because CanvasGL defers actual drawing as long as possible. When fillPath() is called 10 times, CanvasGL does not perform 10 OpenGL drawing calls. It tries to accumulate drawing calls and performs drawing using minimal number of OpenGL drawing calls.

For example, Liquid Particle draws 600 circles each frame. This means CairoGL performs 600 glDrawElement OpenGL calls per frame while CanvasGL accumulates 600 fillPath() and performs only one glDrawElement and one glDrawArray per frame.


2. Why OpenGL Drawing Calls Should Be Batched

An OpenGL drawing call consumes a lot of CPU time. The amount of work is fixed regardless of the number of vertexes. Therefore, a single drawing call should convey as many vertexes as possible. Refer to “Batch, Batch, Batch: What Does It Really Mean?” from NVidia for the details of this technique.


3. Why CanvasGL Can Batch Drawing Calls

There are two reasons why CanvasGL can batch drawing calls.

1. CanvasGL can defer drawing calls as long as possible because CanvasGL supports only HTML5 Canvas. HTML5 Canvas does not need to update the screen for each drawing call. For example, it is not necessary to update the screen every time a circle is drawn in Liquid Particle. Only a single update is required after drawing all 600 circles.

So a vector graphics implementation which supports only HTML5 Canvas can defer all the drawing calls until eglSwapBuffer is performed. CanvasGL analyzes every drawing call requested until eglSwapBuffer and performs drawing with minimal number of OpenGL drawing calls.

2. Batch is more efficient because CanvasGL supports only a small set of API. There are 6 primitives which are supported by CanvasGL: path, image, font, gradient, pattern and shadow. On the other hand, general purpose 2D vector graphics libraries support a rich set of features. Primitives have more complex properties and various filters are also provided.

To batch efficiently, different primitives must be drawn with the same shader program. Drawing calls with different shaders cannot be accumulated. CanvasGL can draw all HTML5 Canvas primitives with only two shader pipelines: 1) pipeline to draw solid color and image, 2) pipeline to draw gradient and pattern. For example, a font with gradient and shadow can be drawn with a single pipeline. It is not easy to support many features with a single unified sharer pipeline. We need more shaders to support more features, which means it is hard to make drawing call batch efficient.


4. Why CairoGL Can’t Batch Drawing Calls

These are the exact opposites of why CanvasGL can batch drawing calls.

1. CairoGL cannot defer drawing calls. Cairo is the most popular 2D vector graphics library which has a large number of users. 2D vector graphics libraries are usually required to update the screen as soon as a drawing call is requested. For example, CairoGL must update the screen or a buffer 600 times to draw a single frame of Liquid Particle.

2. CairoGL supports a rich set of features. Implementing batch for CairoGL is a vast amount of work. CairoGL needs a batch manager which knows all the Cairo features, but practically it is very hard to create such a batch manager.

Leave a Reply

Your email address will not be published. Required fields are marked *

16 + 14 =