-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[skrifa] Implement an optimized fill_glyph
operation
#754
Conversation
c8cfff3
to
46621c9
Compare
fill_glyph
operation
cd22c92
to
1cc4339
Compare
In COLRv0/v1 drawing clients may gain a performance benefit from filling a shape (with a solid or gradient fill) instead of performing a clip + unbounded fill in sequence. Allow clients to do that using a fill_glyph() operation that combines the two. Implement this using a temporary painter that speculatively traverses the glyph tree down from a `PaintGlyph` operation collecting potential transforms along the way. New behavior shows clearly in new baselines for tests added in googlefonts#758 that nest `PaintGlyph` tables and cover mixed situations in which the optimization succeeds for a leaf but fails for the `PaintGlyph` at a layer above, and demonstrate recording transforms along the way. Fixes googlefonts#746.
I would like to send this for review now. This is still a nested painter-based implementation. I have opted for now not to change signatures of the draw functions to return a Result and thus potentially be able to cancel drawing, as I believe this realizes the performance benefit and we would have yet to discover pathological situations in which there are deeply nested trees behind a Please let me know if this works for you or if there are strong opinions about a different approach. I am open to revisiting this, but for now, this definitely meets the mark in terms of benchmark results as shared in the chat. An API change to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this!
I’m happy to land with the nested traversal since it works and seems to hit our performance targets. Upon further thought, I’m not too excited about complicating the API with cancellation. If we do encounter deeply nested graphs under a clip glyph, I’d prefer to implement the procedural matching instead which wouldn’t require changing the API.
I noted one request for a change and a couple nits. Otherwise lgtm!
skrifa/src/color/mod.rs
Outdated
fn fill_glyph( | ||
&mut self, | ||
_glyph_id: GlyphId, | ||
_transform: Transform, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be called brush_transform
just to further signify that it applies to the brush and not the clip.
Also, optional: make the transform optional :) I suspect this will be identity most of the time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a) Renamed to brush_transform
and updated arg name in documentation.
b) Transform turned into Option<Transform>
- I wasn't sure if you prefer to have that be expressed in the test results as an empty string - for now I left testing to dump an identity matrix in that case, instead of special casing the None situation, but agree this might be helpful for clients. Let me know if you want changes on the testing side. On the Skia side I am also making this a default matrix in the callbacks to C++.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your approach looks good to me. Thanks for making the change.
@@ -25,6 +27,23 @@ pub struct Transform { | |||
pub dy: f32, | |||
} | |||
|
|||
impl MulAssign for Transform { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize we don’t strictly need it here but this will be exposed publicly and having an implementation of MulAssign without Mul feels a bit weird.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a Mul
implementation, moved the logic into that and made the MulAssign
implementation based on the former - hope that's what's usually done. Not sure I need the clone()
there, but I guess I need some sort of temporary value at least?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also derive Copy
for Transform
which would remove the need for the clone. I’m good either way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add that.
1cc4339
to
1fce038
Compare
1fce038
to
8bccec3
Compare
...and always assume the method is callable when traversing.
Contains [0] for an optimized combined glyph fill operation. Include patch updates for read-fonts and font-types along the way. Followed instructions in [1], but passed "skrifa" argument to gnrt update step to restrict the change to the Skrifa roll. [0] googlefonts/fontations#754 [1] https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/rust.md#updating-existing-third_party-crates Bug: 1516634 Change-Id: I5ec7d163196476ed790cc9467b5893583d69795c Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5224635 Commit-Queue: Dominik Röttsches <drott@chromium.org> Auto-Submit: Dominik Röttsches <drott@chromium.org> Reviewed-by: danakj <danakj@chromium.org> Cr-Commit-Position: refs/heads/main@{#1251673}
In COLRv0/v1 drawing clients may gain a performance benefit from filling
a shape (with a solid or gradient fill) instead of performing a clip +
unbounded fill in sequence.
Allow clients to do that using a fill_glyph() operation that combines
the two.
Implement this using a temporary painter that speculatively traverses
the glyph tree down from a
PaintGlyph
operation collecting potentialtransforms along the way.
New behavior shows clearly in new baselines for tests added in #758 that
nest
PaintGlyph
tables and cover mixed situations inwhich the optimization succeeds for a leaf but fails for the
PaintGlyph
at a layer above, and demonstrate recording transformsalong the way.
Fixes #746.