Skip to content

Commit

Permalink
[Impeller] Enable SDF approximation when drawing mask blurred solid R…
Browse files Browse the repository at this point in the history
…ects and RRects (flutter#35151)
  • Loading branch information
bdero authored Aug 4, 2022
1 parent 2944653 commit 86d862d
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 17 deletions.
43 changes: 43 additions & 0 deletions impeller/aiks/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
#include "impeller/aiks/canvas.h"

#include <algorithm>
#include <optional>

#include "flutter/fml/logging.h"
#include "impeller/aiks/paint_pass_delegate.h"
#include "impeller/entity/contents/atlas_contents.h"
#include "impeller/entity/contents/clip_contents.h"
#include "impeller/entity/contents/rrect_shadow_contents.h"
#include "impeller/entity/contents/text_contents.h"
#include "impeller/entity/contents/texture_contents.h"
#include "impeller/entity/contents/vertices_contents.h"
Expand Down Expand Up @@ -146,10 +148,51 @@ void Canvas::DrawPaint(Paint paint) {
GetCurrentPass().AddEntity(std::move(entity));
}

bool Canvas::AttemptDrawBlurredRRect(const Rect& rect,
Scalar corner_radius,
Paint& paint) {
if (!paint.mask_blur_descriptor.has_value() ||
paint.mask_blur_descriptor->style != FilterContents::BlurStyle::kNormal ||
paint.style != Paint::Style::kFill) {
return false;
}

// For symmetrically mask blurred solid RRects, absorb the mask blur and use
// a faster SDF approximation.

auto contents = std::make_shared<RRectShadowContents>();
contents->SetColor(paint.color);
contents->SetSigma(paint.mask_blur_descriptor->sigma);
contents->SetRRect(rect, corner_radius);

paint.mask_blur_descriptor = std::nullopt;

Entity entity;
entity.SetTransformation(GetCurrentTransformation());
entity.SetStencilDepth(GetStencilDepth());
entity.SetBlendMode(paint.blend_mode);
entity.SetContents(paint.WithFilters(std::move(contents)));

GetCurrentPass().AddEntity(std::move(entity));

return true;
}

void Canvas::DrawRect(Rect rect, Paint paint) {
if (AttemptDrawBlurredRRect(rect, 0, paint)) {
return;
}
DrawPath(PathBuilder{}.AddRect(rect).TakePath(), std::move(paint));
}

void Canvas::DrawRRect(Rect rect, Scalar corner_radius, Paint paint) {
if (AttemptDrawBlurredRRect(rect, corner_radius, paint)) {
return;
}
DrawPath(PathBuilder{}.AddRoundedRect(rect, corner_radius).TakePath(),
std::move(paint));
}

void Canvas::DrawCircle(Point center, Scalar radius, Paint paint) {
DrawPath(PathBuilder{}.AddCircle(center, radius).TakePath(),
std::move(paint));
Expand Down
6 changes: 6 additions & 0 deletions impeller/aiks/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ class Canvas {

void DrawRect(Rect rect, Paint paint);

void DrawRRect(Rect rect, Scalar corner_radius, Paint paint);

void DrawCircle(Point center, Scalar radius, Paint paint);

void DrawImage(std::shared_ptr<Image> image,
Expand Down Expand Up @@ -126,6 +128,10 @@ class Canvas {

void RestoreClip();

bool AttemptDrawBlurredRRect(const Rect& rect,
Scalar corner_radius,
Paint& paint);

FML_DISALLOW_COPY_AND_ASSIGN(Canvas);
};

Expand Down
15 changes: 12 additions & 3 deletions impeller/aiks/paint.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ std::shared_ptr<Contents> Paint::WithFilters(
std::optional<bool> is_solid_color) const {
bool is_solid_color_val = is_solid_color.value_or(!contents);

if (mask_filter.has_value()) {
const MaskFilterProc& filter = mask_filter.value();
input = filter(FilterInput::Make(input), is_solid_color_val);
if (mask_blur_descriptor.has_value()) {
input = mask_blur_descriptor->CreateMaskBlur(FilterInput::Make(input),
is_solid_color_val);
}

if (image_filter.has_value()) {
Expand All @@ -61,4 +61,13 @@ std::shared_ptr<Contents> Paint::WithFilters(
return input;
}

std::shared_ptr<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
FilterInput::Ref input,
bool is_solid_color) const {
if (is_solid_color) {
return FilterContents::MakeGaussianBlur(input, sigma, sigma, style);
}
return FilterContents::MakeBorderMaskBlur(input, sigma, sigma, style);
}

} // namespace impeller
10 changes: 9 additions & 1 deletion impeller/aiks/paint.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ struct Paint {
kStroke,
};

struct MaskBlurDescriptor {
FilterContents::BlurStyle style;
Sigma sigma;

std::shared_ptr<FilterContents> CreateMaskBlur(FilterInput::Ref input,
bool is_solid_color) const;
};

Color color = Color::Black();
std::shared_ptr<PathContents> contents;

Expand All @@ -42,7 +50,7 @@ struct Paint {

std::optional<ImageFilterProc> image_filter;
std::optional<ColorFilterProc> color_filter;
std::optional<MaskFilterProc> mask_filter;
std::optional<MaskBlurDescriptor> mask_blur_descriptor;

/// @brief Wrap this paint's configured filters to the given contents.
/// @param[in] input The contents to wrap with paint's filters.
Expand Down
23 changes: 10 additions & 13 deletions impeller/display_list/display_list_dispatcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -345,22 +345,16 @@ static FilterContents::BlurStyle ToBlurStyle(SkBlurStyle blur_style) {
void DisplayListDispatcher::setMaskFilter(const flutter::DlMaskFilter* filter) {
// Needs https://github.com/flutter/flutter/issues/95434
if (filter == nullptr) {
paint_.mask_filter = std::nullopt;
paint_.mask_blur_descriptor = std::nullopt;
return;
}
switch (filter->type()) {
case flutter::DlMaskFilterType::kBlur: {
auto blur = filter->asBlur();

auto style = ToBlurStyle(blur->style());
auto sigma = Sigma(blur->sigma());

paint_.mask_filter = [style, sigma](FilterInput::Ref input,
bool is_solid_color) {
if (is_solid_color) {
return FilterContents::MakeGaussianBlur(input, sigma, sigma, style);
}
return FilterContents::MakeBorderMaskBlur(input, sigma, sigma, style);
paint_.mask_blur_descriptor = {
.style = ToBlurStyle(blur->style()),
.sigma = Sigma(blur->sigma()),
};
break;
}
Expand Down Expand Up @@ -709,8 +703,7 @@ void DisplayListDispatcher::drawLine(const SkPoint& p0, const SkPoint& p1) {

// |flutter::Dispatcher|
void DisplayListDispatcher::drawRect(const SkRect& rect) {
auto path = PathBuilder{}.AddRect(ToRect(rect)).TakePath();
canvas_.DrawPath(std::move(path), paint_);
canvas_.DrawRect(ToRect(rect), paint_);
}

// |flutter::Dispatcher|
Expand All @@ -727,7 +720,11 @@ void DisplayListDispatcher::drawCircle(const SkPoint& center, SkScalar radius) {

// |flutter::Dispatcher|
void DisplayListDispatcher::drawRRect(const SkRRect& rrect) {
canvas_.DrawPath(ToPath(rrect), paint_);
if (rrect.isSimple()) {
canvas_.DrawRRect(ToRect(rrect.rect()), rrect.getSimpleRadii().fX, paint_);
} else {
canvas_.DrawPath(ToPath(rrect), paint_);
}
}

// |flutter::Dispatcher|
Expand Down

0 comments on commit 86d862d

Please sign in to comment.