twemoji icon indicating copy to clipboard operation
twemoji copied to clipboard

Optimizations for real-time vector renderers

Open EricLengyel opened this issue 4 years ago • 4 comments

I am the author of a real-time GPU font rendering library called Slug. It draws glyphs directly from their original contours (the quadratic Bézier curves) by calculating winding numbers in a pixel shader. Slug is frequently used in environments like video games where text can change in size or be viewed from a different perspective 60+ times per second, so it never saves pixel images for any particular glyph transforms. Because it is always rendering from the source data, its performance is directly related to the complexity of the glyph geometry itself. I have noticed that many of the Twemoji graphics files can be optimized in the following ways to increase performance when used with this kind of renderer.

  • Minimize the number of control points. This reduces raw computation in the pixel shader. I see numerous opportunities do to this without changing the appearance of an emoji because there are extra curves in one layer that are completely hidden by another layer on top of it.
  • Minimize the area covered by each color layer. This goes with the previous point. When there are extra invisible curves, they tend to make a layer occupy more space than necessary. Chopping them down to size increases performance.
  • Minimize the number of color layers produced in the final font. This reduces the amount of overdraw when emoji are rendered as stacks of polygons. Improvements can often by made here by simply making sure that layers having the same color are adjacent in the drawing order whenever possible.
  • Prefer straight, perfectly horizontal or vertical lines where possible. These have half the rendering cost of any other curve. There are often opportunities to take advantage of this when closing a contour for one layer where it is obscured by higher layer.

As an example, consider U+01F923. The left image below shows the graphics currently being used, and the right image shows graphics that have been optimized. Three modifications have been made:

  1. Unnecessary control points have been removed for the eyes where they are obscured by the teardrops.
  2. The curves at the corners of the mouth behind the teardrops have been turned into exact horizontal and vertical lines.
  3. The brown-colored mouth and eye layers have been rearranged so they are adjacent in the stacking order. They were previously separated by the white part of the mouth. This eliminates a layer in the final TTF file.

Most times, similar optimizations are rather easy to make, and in addition to boosting rendering performance, they reduce the size of the resulting TTF file. If you're interested, I can begin submitting pull requests for optimized SVG files. Many of them contain much larger opportunities than this example in at least one of the ways listed above.

EmojiExample

EricLengyel avatar Mar 23 '21 21:03 EricLengyel

I believe there should be two sets of SVG files, one very structured and thus readable and editable, the other optimized for size and speed.

Crissov avatar Mar 24 '21 08:03 Crissov

U+01F92C is an example in which a significant optimization is a no-brainer. It has a mouth that is completely hidden by a foreground layer! This is just wasting rendering time for no reason.

EmojiEx2

EricLengyel avatar Mar 24 '21 20:03 EricLengyel

(Almost?) all cooks also have something similar: they all have two sets of spoons, one brown and one grey. The grey one is completely unused.

Miepee avatar May 31 '22 11:05 Miepee

What if someone wants to do something where it's convenient to keep all the occluded geometry and layers (e.g. some sort of UI animation where the different layers lag behind while an emoji is being dragged, similar to some Android launchers when you drag an app icon around)? All the nasty optimized geometry would be exposed, and the original set would have to be dug up and manually merged from older commits which is a pain.

I quite like the idea of instead having two sets, like @Crissov said.

Zi7ar21 avatar Sep 07 '22 22:09 Zi7ar21