Vector graphics provides good quality image. However, it has performance issues in the embedded system whose CPU resources is limited. In this article, we will discuss some approaches to provide optimal performance for the embedded system.
A SVG file can be rendered in the following steps.
In MadButterfly, a SVG file is transcoded into C function calls to create vector elements. Therefore, step 1 is not in the runtime. The step 2 is actually done by the cairo. The generated C source is actually function calls to the cairo. The translator will translate the parameters of the SVG into those for the cairo. Since the cairo API is in floating number. This may introduce some performance for system without FPU.
The final step is to create bitmap from the cairo object. This is done by the backend of the cairo.This step usually spend most of the time.
Therefore, we have two issues here.
Although the cairo API is in floating point, its internal convert most floating point number to fixed point number. It uses floating point only in the matrix operation. Therefore, we can use fixed point directly when the matrix operation is not required.
If the matrix operation is not used, we can generate everything in fixed point. Even the matrix is used, we can do the matrix operation in the convert time and generate converted data to the cairo. The SVG translator must be smarter to determine the matrix for each elements and then apply it to the path data before it is converted into C function call.
In this way, we can use the fixed point cairo API to avoid convertion. In this way, no any floating point calculation is used in the render stage. Since this is done in the translation time, no load at the embedded system at all.
The cairo will use pixman to generate bitmap data. This is the most significant stage. Even worse, whenevery the screen is refreshed, this rendering will be redo again.
There are two strategies to eliminate this issue.
These method will be disabled by default for quality issue. We will provide an API mb_object_set_bitmapcache to change the cache policy. If the bitmap cache is enabled, it will use the bitmap generated in the translation time. If the bitmap is not available, we will render for one time and cache the result for future use.
If the bitmap cache is disabled, the pixman will be called to generate the bitmap. In addition, the bitmap cache will be cleared.
If the bitmapcache is enabled, the matrix operation will be applied to the bitmap. For example, if we scale it by half, we will scale the bitmap by half. This will degrade the quality of the image. It will be an issue especially when we enlarge or rotate the image.
However, since a lot of hardware support bitblt function, we can rely on it to draw the image in highest performance. This is the trade-off must be choiced by the users.
SVG allows each group and element define a transform matrix, which will be applied to the leaf elements recursively. For the system without FPU, this indicate a lot of floating point calculation.Therefore, the cairo is actually do some minial optimization to detect the unity matrix or translation matrix. If these are found, it will not perform the real matrix operation.
The matrix optimization here has two meaning.
Except the simple unity and translationoptimization of cairo, we can define more optimization. For example, we can apply tolerate for small scale or translation or rotate. For example,
(1.001,0,0,1.001,0,0)
will be treated as 1.001 scale in both x and y direction. However, it won't take any effect for regular screen. Therefore, we can transfoirm it to be (1,0,0,1,0,0) and then remove it.
In addition to the optimization, we can calculate the final matrix in the translation time.
For example, if we have
<g id="aaa" transform="2 0 0 2 0 0">
<g id="ccc" transform="3 0 0 3 0 0">
</g>
</g>
The final matrix apply to group ccc is (6 0 0 6 0 0). We can set this result in the element ccc so that we know its 6 times scale and do some optimization based on it. The transformation of all group will be removed.
<g id="aaa">
<g id="ccc" transform="6 0 0 6 0 0">
</g>
</g>
This will generate exactly the same result as the original one. However, we don't need to calculate matrix in the runtime.