Skip to content

glifo: Simplify COLR glyph handling#1605

Draft
LaurenzV wants to merge 1 commit into
mainfrom
laurenz/colr_simplify
Draft

glifo: Simplify COLR glyph handling#1605
LaurenzV wants to merge 1 commit into
mainfrom
laurenz/colr_simplify

Conversation

@LaurenzV
Copy link
Copy Markdown
Collaborator

Initially, in Vello CPU, any COLR glyph would first be rendered into an intermediate pixmap and that pixmap would then be rendered into the surface. Because of this, in case there was a skewing factor in the glyph, instead of just rasterizing the glyph at its normal font size, we would apply an additional scaling factor such that it would be rasterized at a higher solution, avoiding aliasing artifacts that arise from the skewing.

However, since the most recent changes, things are different: By default, glyphs are always directly rendered into a surface. Glyphs are only cached if they don't have any skewing factor (if in the future we decide that we also want glyph caching for rotated glyphs, we can easily just fold this into the font size again). Therefore, this additional scaling procedure becomes unnecessary. By doing so, the code becomes a easier to understand (in my opinion).

As a nice side effect, this PR also fixes a discrepancy between cached and non-cached rendering that existed previously:

rec.mp4

As you can see, previously (on the left) cached and non-cached glyphs would have slightly different positions. Now, they seem to have the same position. I must confess I don't fully understand why this was the case, but the tests don't lie! 😄

@nicoburns
Copy link
Copy Markdown
Contributor

Does this apply to regular skewed glyphs? I imagine skewed COLR glyphs are pretty uncommon. But skewed regular glyphs for "fake italic" would be significantly more common.

@LaurenzV
Copy link
Copy Markdown
Collaborator Author

Nope, it only applies for cached glyphs. And caching i never applied if a glyph is skewed.

@LaurenzV LaurenzV requested a review from grebmeg April 29, 2026 12:30
@laurenz-canva laurenz-canva deleted the laurenz/colr_simplify branch April 30, 2026 09:07
@LaurenzV LaurenzV restored the laurenz/colr_simplify branch April 30, 2026 09:13
@LaurenzV
Copy link
Copy Markdown
Collaborator Author

Sorry, that was an accident 😅

@LaurenzV LaurenzV reopened this Apr 30, 2026
Comment thread glifo/src/glyph.rs
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this approach has two problems:

  1. Intermediate pixmap is sized in font units, not device pixels:

bbox comes from bounding_box(..., Size::unscaled()), and create_colr_glyph uses it directly:

let (pix_width, pix_height) = (
    metrics.bbox.width().ceil() as u16,
    metrics.bbox.height().ceil() as u16,
);
let draw_transform = Affine::translate((-metrics.bbox.x0, -metrics.bbox.y0));

draw_transform has no scale, so 1 font unit → 1 texel. For Noto Color Emoji that's huge texture regardless of font size. On main the same glyph should use much less space.

  1. Atlas caching is silently disabled in insert_and_render_colr:

supports_atlas_caching requires [a, d] ≈ [1, -1]. On main, the outer transform cancelled the scale baked into metrics.transform. The new outer transform drops that cancellation, so any non-unit scale flows straight through.

I added a println! to the UnsupportedTransform branch and it fires for every glyph in random_text scene example (I only added colr glyphs there). Cache rejected unconditionally, full colr paint repeats every frame.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uff, thanks for catching that. 😔 I guess that explains why the cached tests all changed... Would be nice if there were some way of more easily telling whether caching was used or not.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree, the caching not working doesn’t seem consistent with the intention of enabling the cache. I don’t have a solid answer here, but it’d be nice to provide at least some hint about it. Ideally, we could track cases where caching somehow breaks even when it’s enabled. At the very least, maybe we could add a warning in dev mode?

@LaurenzV LaurenzV marked this pull request as draft May 7, 2026 15:04
pull Bot pushed a commit to Mu-L/vello that referenced this pull request May 22, 2026
As was evidenced in linebender#1605, it is pretty easy to make changes to the
caching logic and then accidentally break the whole caching mechanism.

To hopefully provide some safe-guarding against this, this PR adds 6
unit tests, each ensuring that the different configurations for
outline/bitmap/COLR glyphs result in the expected usage of the cache. In
case atlas caching is disabled, the cache should stay untouched. In case
it's enabled, the glyphs should actually end up landing in the cache.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants