Skip to content
This repository has been archived by the owner on Feb 25, 2025. It is now read-only.

Commit

Permalink
[Impeller] Limit rrect blur kernel to 1000x1000 (#42269)
Browse files Browse the repository at this point in the history
Impose the same large limit as the slower 2-pass blur.

Also renames "RRectShadow" to the much less ambiguous "SolidRRectBlur".

Before, a large enough blur sigma would result in nothing getting drawn. The Gaussian integral seems to be working fine against 16bit ops, so no adjustments were needed in the shader.

![Screenshot 2023-05-23 at 4 08 41 PM](https://github.com/flutter/engine/assets/919017/108e01ce-2cf1-4bc9-b51b-7f4ad7288fac)
  • Loading branch information
bdero authored May 24, 2023
1 parent 1f964fa commit eebcf36
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 43 deletions.
8 changes: 4 additions & 4 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1213,14 +1213,14 @@ ORIGIN: ../../../flutter/impeller/entity/contents/linear_gradient_contents.cc +
ORIGIN: ../../../flutter/impeller/entity/contents/linear_gradient_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/radial_gradient_contents.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/radial_gradient_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/rrect_shadow_contents.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/rrect_shadow_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/runtime_effect_contents.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/runtime_effect_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/scene_contents.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/scene_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/solid_color_contents.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/solid_color_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/solid_rrect_blur_contents.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/solid_rrect_blur_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/sweep_gradient_contents.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/sweep_gradient_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/text_contents.cc + ../../../flutter/LICENSE
Expand Down Expand Up @@ -3854,14 +3854,14 @@ FILE: ../../../flutter/impeller/entity/contents/linear_gradient_contents.cc
FILE: ../../../flutter/impeller/entity/contents/linear_gradient_contents.h
FILE: ../../../flutter/impeller/entity/contents/radial_gradient_contents.cc
FILE: ../../../flutter/impeller/entity/contents/radial_gradient_contents.h
FILE: ../../../flutter/impeller/entity/contents/rrect_shadow_contents.cc
FILE: ../../../flutter/impeller/entity/contents/rrect_shadow_contents.h
FILE: ../../../flutter/impeller/entity/contents/runtime_effect_contents.cc
FILE: ../../../flutter/impeller/entity/contents/runtime_effect_contents.h
FILE: ../../../flutter/impeller/entity/contents/scene_contents.cc
FILE: ../../../flutter/impeller/entity/contents/scene_contents.h
FILE: ../../../flutter/impeller/entity/contents/solid_color_contents.cc
FILE: ../../../flutter/impeller/entity/contents/solid_color_contents.h
FILE: ../../../flutter/impeller/entity/contents/solid_rrect_blur_contents.cc
FILE: ../../../flutter/impeller/entity/contents/solid_rrect_blur_contents.h
FILE: ../../../flutter/impeller/entity/contents/sweep_gradient_contents.cc
FILE: ../../../flutter/impeller/entity/contents/sweep_gradient_contents.h
FILE: ../../../flutter/impeller/entity/contents/text_contents.cc
Expand Down
13 changes: 13 additions & 0 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2246,6 +2246,19 @@ TEST_P(AiksTest, CanRenderDestructiveSaveLayer) {
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, CanRenderMaskBlurHugeSigma) {
Canvas canvas;
canvas.DrawCircle({400, 400}, 300,
{.color = Color::Green(),
.mask_blur_descriptor = Paint::MaskBlurDescriptor{
.style = FilterContents::BlurStyle::kNormal,
.sigma = Sigma(99999),
}});
canvas.Restore();

ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, CanRenderBackdropBlurInteractive) {
auto callback = [&](AiksContext& renderer, RenderTarget& render_target) {
auto [a, b] = IMPELLER_PLAYGROUND_LINE(Point(50, 50), Point(300, 200), 30,
Expand Down
4 changes: 2 additions & 2 deletions impeller/aiks/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include "impeller/entity/contents/atlas_contents.h"
#include "impeller/entity/contents/clip_contents.h"
#include "impeller/entity/contents/color_source_text_contents.h"
#include "impeller/entity/contents/rrect_shadow_contents.h"
#include "impeller/entity/contents/solid_rrect_blur_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 @@ -199,7 +199,7 @@ bool Canvas::AttemptDrawBlurredRRect(const Rect& rect,
// For symmetrically mask blurred solid RRects, absorb the mask blur and use
// a faster SDF approximation.

auto contents = std::make_shared<RRectShadowContents>();
auto contents = std::make_shared<SolidRRectBlurContents>();
contents->SetColor(new_paint.color);
contents->SetSigma(new_paint.mask_blur_descriptor->sigma);
contents->SetRRect(rect, corner_radius);
Expand Down
20 changes: 10 additions & 10 deletions impeller/display_list/dl_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#include "impeller/display_list/dl_dispatcher.h"
#include "impeller/display_list/dl_image_impeller.h"
#include "impeller/display_list/dl_playground.h"
#include "impeller/entity/contents/rrect_shadow_contents.h"
#include "impeller/entity/contents/solid_rrect_blur_contents.h"
#include "impeller/geometry/constants.h"
#include "impeller/geometry/point.h"
#include "impeller/geometry/scalar.h"
Expand Down Expand Up @@ -844,21 +844,21 @@ TEST_P(DisplayListTest, TransparentShadowProducesCorrectColor) {
dispatcher.drawDisplayList(dl, 1);
auto picture = dispatcher.EndRecordingAsPicture();

std::shared_ptr<RRectShadowContents> rrect_shadow;
picture.pass->IterateAllEntities([&rrect_shadow](Entity& entity) {
std::shared_ptr<SolidRRectBlurContents> rrect_blur;
picture.pass->IterateAllEntities([&rrect_blur](Entity& entity) {
if (ScalarNearlyEqual(entity.GetTransformation().GetScale().x, 1.618f)) {
rrect_shadow =
std::static_pointer_cast<RRectShadowContents>(entity.GetContents());
rrect_blur = std::static_pointer_cast<SolidRRectBlurContents>(
entity.GetContents());
return false;
}
return true;
});

ASSERT_NE(rrect_shadow, nullptr);
ASSERT_EQ(rrect_shadow->GetColor().red, 0);
ASSERT_EQ(rrect_shadow->GetColor().green, 0);
ASSERT_EQ(rrect_shadow->GetColor().blue, 0);
ASSERT_EQ(rrect_shadow->GetColor().alpha, 0);
ASSERT_NE(rrect_blur, nullptr);
ASSERT_EQ(rrect_blur->GetColor().red, 0);
ASSERT_EQ(rrect_blur->GetColor().green, 0);
ASSERT_EQ(rrect_blur->GetColor().blue, 0);
ASSERT_EQ(rrect_blur->GetColor().alpha, 0);
}

// Draw a hexagon using triangle fan
Expand Down
4 changes: 2 additions & 2 deletions impeller/entity/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -197,14 +197,14 @@ impeller_component("entity") {
"contents/linear_gradient_contents.h",
"contents/radial_gradient_contents.cc",
"contents/radial_gradient_contents.h",
"contents/rrect_shadow_contents.cc",
"contents/rrect_shadow_contents.h",
"contents/runtime_effect_contents.cc",
"contents/runtime_effect_contents.h",
"contents/scene_contents.cc",
"contents/scene_contents.h",
"contents/solid_color_contents.cc",
"contents/solid_color_contents.h",
"contents/solid_rrect_blur_contents.cc",
"contents/solid_rrect_blur_contents.h",
"contents/sweep_gradient_contents.cc",
"contents/sweep_gradient_contents.h",
"contents/text_contents.cc",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "impeller/entity/contents/rrect_shadow_contents.h"
#include "impeller/entity/contents/solid_rrect_blur_contents.h"
#include <optional>

#include "impeller/entity/contents/content_context.h"
Expand All @@ -16,29 +16,29 @@

namespace impeller {

RRectShadowContents::RRectShadowContents() = default;
SolidRRectBlurContents::SolidRRectBlurContents() = default;

RRectShadowContents::~RRectShadowContents() = default;
SolidRRectBlurContents::~SolidRRectBlurContents() = default;

void RRectShadowContents::SetRRect(std::optional<Rect> rect,
Scalar corner_radius) {
void SolidRRectBlurContents::SetRRect(std::optional<Rect> rect,
Scalar corner_radius) {
rect_ = rect;
corner_radius_ = corner_radius;
}

void RRectShadowContents::SetSigma(Sigma sigma) {
void SolidRRectBlurContents::SetSigma(Sigma sigma) {
sigma_ = sigma;
}

void RRectShadowContents::SetColor(Color color) {
void SolidRRectBlurContents::SetColor(Color color) {
color_ = color.Premultiply();
}

Color RRectShadowContents::GetColor() const {
Color SolidRRectBlurContents::GetColor() const {
return color_;
}

std::optional<Rect> RRectShadowContents::GetCoverage(
std::optional<Rect> SolidRRectBlurContents::GetCoverage(
const Entity& entity) const {
if (!rect_.has_value()) {
return std::nullopt;
Expand All @@ -52,9 +52,9 @@ std::optional<Rect> RRectShadowContents::GetCoverage(
return bounds.TransformBounds(entity.GetTransformation());
};

bool RRectShadowContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
bool SolidRRectBlurContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
if (!rect_.has_value()) {
return true;
}
Expand All @@ -64,7 +64,11 @@ bool RRectShadowContents::Render(const ContentContext& renderer,

VertexBufferBuilder<VS::PerVertexData> vtx_builder;

auto blur_radius = sigma_.sigma * 2;
// Clamp the max kernel width/height to 1000.
auto blur_sigma = std::min(sigma_.sigma, 250.0f);
// Increase quality by make the radius a bit bigger than the typical
// sigma->radius conversion we use for slower blurs.
auto blur_radius = blur_sigma * 2;
auto positive_rect = rect_->GetPositive();
{
auto left = -blur_radius;
Expand Down Expand Up @@ -99,7 +103,7 @@ bool RRectShadowContents::Render(const ContentContext& renderer,

FS::FragInfo frag_info;
frag_info.color = color_;
frag_info.blur_sigma = sigma_.sigma;
frag_info.blur_sigma = blur_sigma;
frag_info.rect_size = Point(positive_rect.size);
frag_info.corner_radius =
std::min(corner_radius_, std::min(positive_rect.size.width / 2.0f,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ class Path;
class HostBuffer;
struct VertexBuffer;

class RRectShadowContents final : public Contents {
/// @brief Draws a fast solid color blur of an rounded rectangle. Only supports
/// RRects with fully symmetrical radii. Also produces correct results for
/// rectangles (corner_radius=0) and circles (corner_radius=width/2=height/2).
class SolidRRectBlurContents final : public Contents {
public:
RRectShadowContents();
SolidRRectBlurContents();

~RRectShadowContents() override;
~SolidRRectBlurContents() override;

void SetRRect(std::optional<Rect> rect, Scalar corner_radius = 0);

Expand All @@ -47,7 +50,7 @@ class RRectShadowContents final : public Contents {

Color color_;

FML_DISALLOW_COPY_AND_ASSIGN(RRectShadowContents);
FML_DISALLOW_COPY_AND_ASSIGN(SolidRRectBlurContents);
};

} // namespace impeller
4 changes: 2 additions & 2 deletions impeller/entity/entity_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
#include "impeller/entity/contents/filters/inputs/filter_input.h"
#include "impeller/entity/contents/linear_gradient_contents.h"
#include "impeller/entity/contents/radial_gradient_contents.h"
#include "impeller/entity/contents/rrect_shadow_contents.h"
#include "impeller/entity/contents/runtime_effect_contents.h"
#include "impeller/entity/contents/solid_color_contents.h"
#include "impeller/entity/contents/solid_rrect_blur_contents.h"
#include "impeller/entity/contents/sweep_gradient_contents.h"
#include "impeller/entity/contents/text_contents.h"
#include "impeller/entity/contents/texture_contents.h"
Expand Down Expand Up @@ -1711,7 +1711,7 @@ TEST_P(EntityTest, RRectShadowTest) {
auto rect =
Rect::MakeLTRB(top_left.x, top_left.y, bottom_right.x, bottom_right.y);

auto contents = std::make_unique<RRectShadowContents>();
auto contents = std::make_unique<SolidRRectBlurContents>();
contents->SetRRect(rect, corner_radius);
contents->SetColor(color);
contents->SetSigma(Radius(blur_radius));
Expand Down
10 changes: 5 additions & 5 deletions impeller/entity/shaders/rrect_blur.frag
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ float16_t RRectDistance(f16vec2 sample_position, f16vec2 half_size) {

/// Closed form unidirectional rounded rect blur mask solution using the
/// analytical Gaussian integral (with approximated erf).
float16_t RRectShadowX(f16vec2 sample_position, f16vec2 half_size) {
float16_t RRectBlurX(f16vec2 sample_position, f16vec2 half_size) {
// Compute the X direction distance field (not incorporating the Y distance)
// for the rounded rect.
float16_t space =
Expand All @@ -46,7 +46,7 @@ float16_t RRectShadowX(f16vec2 sample_position, f16vec2 half_size) {
return integral.y - integral.x;
}

float16_t RRectShadow(f16vec2 sample_position, f16vec2 half_size) {
float16_t RRectBlur(f16vec2 sample_position, f16vec2 half_size) {
// Limit the sampling range to 3 standard deviations in the Y direction from
// the kernel center to incorporate 99.7% of the color contribution.
float16_t half_sampling_range = frag_info.blur_sigma * 3.0hf;
Expand All @@ -60,8 +60,8 @@ float16_t RRectShadow(f16vec2 sample_position, f16vec2 half_size) {
float16_t result = 0.0hf;
for (int sample_i = 0; sample_i < kSampleCount; sample_i++) {
float16_t y = begin_y + interval * (float16_t(sample_i) + 0.5hf);
result += RRectShadowX(f16vec2(sample_position.x, sample_position.y - y),
half_size) *
result += RRectBlurX(f16vec2(sample_position.x, sample_position.y - y),
half_size) *
IPHalfGaussian(y, frag_info.blur_sigma) * interval;
}

Expand All @@ -75,7 +75,7 @@ void main() {
f16vec2 sample_position = f16vec2(v_position) - half_size;

if (frag_info.blur_sigma > 0.0hf) {
frag_color *= RRectShadow(sample_position, half_size);
frag_color *= RRectBlur(sample_position, half_size);
} else {
frag_color *= -RRectDistance(sample_position, half_size);
}
Expand Down

0 comments on commit eebcf36

Please sign in to comment.