canvaskit-wasm: drawParagraphs performance, and converting SKParagraph to SKTextBlob

Skip to first unread message

Alan Song

Mar 12, 2024, 8:03:34 PMMar 12
to skia-discuss

As discussed in a few places, paragraph is both memory intensive and cpu intensive. This makes it hard to cache (memory overflow) or create on the fly (frame drops). It can be somewhat mitigated by caching surface snapshots that contain rendered results of the paragraphs, but I wonder if there’s a way do make it faster.

Also, drawParagraph is much slower compared to canvas2d fillText as seen in this benchmark where we've pre-extracted the positions of text runs and call fillText to render the same paragraph.

From what I gather, SkParagraph is designed for Flutter, and isn’t used in Chromium. Chromium uses it’s own text shaping and converts glyphs into SKTextBlobs and call drawTextBlobs.

So I wonder if we can use SKParagraph for shaping and create SKTextBlobs with the shaped result, if the resulting TextBlobs aren’t too expensive to cache. Here’s my naive attempt:

const textBlobs: TextBlob[] = [];
const lines = paragraph.getShapedLines();
for (const line of lines) {
  for (const { glyphs, positions } of line.runs) {
    const rsx = new Array(glyphs.length).fill(0).flatMap((_, i) => {
      const x = positions[2 * i];
      const y = positions[2 * i + 1];
      return [1, 0, x, y];
    const blob = CanvasKit.TextBlob.MakeFromRSXformGlyphs(glyphs, rsx, font);



The immediate problem is that hinting is all over the place. Maybe the `positions` in GlyphRun doesn’t include hinting information? 

The other problem would be lack of `typeface` property in GlyphRun, which is necessary to know which exact fallback font was picked for the glyphs. 

I also found this ticket in flutter suggesting to move from drawParagraph to drawGlyphs, but it was closed without clarification what the alternative was. 

I’m curious whether this could be a viable approach - converting paragraphs to text blobs and caching them. SkParagraph would be used as a shaper, which is very hard to implement in js.

Alan Song

Mar 12, 2024, 8:06:55 PMMar 12
to skia-discuss
Sorry I must have brain-farted. By `hinting` I meant `kerning`.

Alan Song

Mar 21, 2024, 8:55:16 PMMar 21
to skia-discuss

Seems the correct way is to cache the paragraph as a SkPicture. It seems to achieve the goal of caching the text blobs, as drawPicture stack trace shows exactly drawTextBlob.,memory-skpicture.ts


For 50k paragraphs, storing paragraphs themselves cost ~1615MB or ~33KB each. Storing pictures cost ~470MB or ~10KB each.

Unfortunately drawPicture of paragraphs are just as slow - but at least we can afford to hold on to the pictures to avoid overhead of paragraph creation.

Reply all
Reply to author
0 new messages