-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] Add mask blur style support to the RRect blur fast path. #51250
Changes from 3 commits
e21a452
79b6c8a
6108b8b
086ace4
a1d91e2
8e95fe4
9caf72a
67b9e61
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -308,41 +308,121 @@ void Canvas::DrawPaint(const Paint& paint) { | |
| } | ||
|
|
||
| bool Canvas::AttemptDrawBlurredRRect(const Rect& rect, | ||
| Size corner_radius, | ||
| Size corner_radii, | ||
| const Paint& paint) { | ||
| if (paint.color_source.GetType() != ColorSource::Type::kColor || | ||
| paint.style != Paint::Style::kFill) { | ||
| return false; | ||
| } | ||
|
|
||
| if (!paint.mask_blur_descriptor.has_value() || | ||
| paint.mask_blur_descriptor->style != FilterContents::BlurStyle::kNormal) { | ||
| if (!paint.mask_blur_descriptor.has_value()) { | ||
| return false; | ||
| } | ||
|
|
||
| // A blur sigma that is not positive enough should not result in a blur. | ||
| if (paint.mask_blur_descriptor->sigma.sigma <= kEhCloseEnough) { | ||
| return false; | ||
| } | ||
|
|
||
| Paint new_paint = paint; | ||
|
|
||
| // For symmetrically mask blurred solid RRects, absorb the mask blur and use | ||
| // a faster SDF approximation. | ||
|
|
||
| auto contents = std::make_shared<SolidRRectBlurContents>(); | ||
| contents->SetColor(new_paint.color); | ||
| contents->SetSigma(new_paint.mask_blur_descriptor->sigma); | ||
| contents->SetRRect(rect, corner_radius); | ||
| Paint rrect_paint = paint; | ||
|
|
||
| // Absorb the color filter, if any. | ||
| if (rrect_paint.HasColorFilter()) { | ||
| rrect_paint.color = | ||
| rrect_paint.GetColorFilter()->GetCPUColorFilterProc()(paint.color); | ||
| rrect_paint.color_filter = nullptr; | ||
| rrect_paint.invert_colors = false; | ||
|
||
| } | ||
|
|
||
| // In some cases, we need to render the mask blur to a separate layer. | ||
| // | ||
| // 1. If the blur style is normal, we'll be drawing using one draw call and | ||
| // no clips. And so we can just wrap the RRect contents with the | ||
| // ImageFilter, which will get applied to the result as per usual. | ||
| // | ||
| // 2. If the blur style is solid, we combine the non-blurred RRect with the | ||
| // blurred RRect via two separate draw calls, and so we need to defer any | ||
| // fancy blending, translucency, or image filtering until after these two | ||
| // draws have been combined in a separate layer. | ||
| // | ||
| // 3. If the blur style is outer or inner, we apply the blur style via a | ||
| // clip. The ImageFilter needs to be applied to the mask blurred result. | ||
| // And so if there's an ImageFilter, we need to defer applying it until | ||
| // after the clipped RRect blur has been drawn to a separate texture. | ||
| // However, since there's only one draw call that produces color, we | ||
| // don't need to worry about the blend mode or translucency (unlike with | ||
| // BlurStyle::kSolid). | ||
| // | ||
| if ((rrect_paint.mask_blur_descriptor->style != | ||
| FilterContents::BlurStyle::kNormal && | ||
| rrect_paint.image_filter) || | ||
| (rrect_paint.mask_blur_descriptor->style == | ||
| FilterContents::BlurStyle::kSolid && | ||
| (!rrect_paint.color.IsOpaque() || | ||
| rrect_paint.blend_mode != BlendMode::kSourceOver))) { | ||
| // Defer the alpha, blend mode, and image filter to a separate layer. | ||
| SaveLayer({.color = Color::White().WithAlpha(rrect_paint.color.alpha), | ||
| .blend_mode = rrect_paint.blend_mode, | ||
| .image_filter = rrect_paint.image_filter}); | ||
| rrect_paint.color = rrect_paint.color.WithAlpha(1); | ||
| rrect_paint.blend_mode = BlendMode::kSourceOver; | ||
| rrect_paint.image_filter = nullptr; | ||
| } else { | ||
| Save(); | ||
| } | ||
|
|
||
| new_paint.mask_blur_descriptor = std::nullopt; | ||
| auto draw_blurred_rrect = [this, &rect, &corner_radii, &rrect_paint]() { | ||
| auto contents = std::make_shared<SolidRRectBlurContents>(); | ||
|
|
||
| Entity entity; | ||
| entity.SetTransform(GetCurrentTransform()); | ||
| entity.SetClipDepth(GetClipDepth()); | ||
| entity.SetBlendMode(new_paint.blend_mode); | ||
| entity.SetContents(new_paint.WithFilters(std::move(contents))); | ||
| contents->SetColor(rrect_paint.color); | ||
| contents->SetSigma(rrect_paint.mask_blur_descriptor->sigma); | ||
| contents->SetRRect(rect, corner_radii); | ||
|
|
||
| AddEntityToCurrentPass(std::move(entity)); | ||
| Entity blurred_rrect_entity; | ||
| blurred_rrect_entity.SetTransform(GetCurrentTransform()); | ||
| blurred_rrect_entity.SetClipDepth(GetClipDepth()); | ||
| blurred_rrect_entity.SetBlendMode(rrect_paint.blend_mode); | ||
|
|
||
| rrect_paint.mask_blur_descriptor = std::nullopt; | ||
| blurred_rrect_entity.SetContents( | ||
| rrect_paint.WithFilters(std::move(contents))); | ||
| AddEntityToCurrentPass(std::move(blurred_rrect_entity)); | ||
| }; | ||
|
|
||
| switch (rrect_paint.mask_blur_descriptor->style) { | ||
| case FilterContents::BlurStyle::kNormal: { | ||
| draw_blurred_rrect(); | ||
| break; | ||
| } | ||
| case FilterContents::BlurStyle::kSolid: { | ||
| // First, draw the blurred RRect. | ||
| draw_blurred_rrect(); | ||
| // Then, draw the non-blurred RRect on top. | ||
| Entity entity; | ||
| entity.SetTransform(GetCurrentTransform()); | ||
| entity.SetClipDepth(GetClipDepth()); | ||
| entity.SetBlendMode(rrect_paint.blend_mode); | ||
| entity.SetContents(CreateContentsForGeometryWithFilters( | ||
| rrect_paint, Geometry::MakeRoundRect(rect, corner_radii))); | ||
| AddEntityToCurrentPass(std::move(entity)); | ||
| break; | ||
| } | ||
| case FilterContents::BlurStyle::kOuter: { | ||
| ClipRRect(rect, corner_radii, Entity::ClipOperation::kDifference); | ||
| draw_blurred_rrect(); | ||
| break; | ||
| } | ||
| case FilterContents::BlurStyle::kInner: { | ||
| ClipRRect(rect, corner_radii, Entity::ClipOperation::kIntersect); | ||
| draw_blurred_rrect(); | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| Restore(); | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
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.
Oh wait, can you put these in aiks_blur_unittests, please? I wish I had a better way to force the sorting of this.
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.
Done.