Move Sigma<->Radius conversion to geometry (flutter/engine#35069)

This commit is contained in:
Brandon DeRosier 2022-08-01 18:05:05 -07:00 committed by GitHub
parent 95be540845
commit 91d348e6e3
7 changed files with 89 additions and 60 deletions

View File

@ -654,6 +654,8 @@ FILE: ../../../flutter/impeller/geometry/rect.h
FILE: ../../../flutter/impeller/geometry/scalar.h
FILE: ../../../flutter/impeller/geometry/shear.cc
FILE: ../../../flutter/impeller/geometry/shear.h
FILE: ../../../flutter/impeller/geometry/sigma.cc
FILE: ../../../flutter/impeller/geometry/sigma.h
FILE: ../../../flutter/impeller/geometry/size.cc
FILE: ../../../flutter/impeller/geometry/size.h
FILE: ../../../flutter/impeller/geometry/type_traits.cc

View File

@ -21,6 +21,7 @@
#include "impeller/geometry/path.h"
#include "impeller/geometry/path_builder.h"
#include "impeller/geometry/scalar.h"
#include "impeller/geometry/sigma.h"
#include "impeller/geometry/vertices.h"
#include "impeller/renderer/formats.h"
#include "impeller/typographer/backends/skia/text_frame_skia.h"
@ -324,7 +325,7 @@ void DisplayListDispatcher::setMaskFilter(const flutter::DlMaskFilter* filter) {
auto blur = filter->asBlur();
auto style = ToBlurStyle(blur->style());
auto sigma = FilterContents::Sigma(blur->sigma());
auto sigma = Sigma(blur->sigma());
paint_.mask_filter = [style, sigma](FilterInput::Ref input,
bool is_solid_color) {
@ -350,8 +351,8 @@ static std::optional<Paint::ImageFilterProc> ToImageFilterProc(
switch (filter->type()) {
case flutter::DlImageFilterType::kBlur: {
auto blur = filter->asBlur();
auto sigma_x = FilterContents::Sigma(blur->sigma_x());
auto sigma_y = FilterContents::Sigma(blur->sigma_y());
auto sigma_x = Sigma(blur->sigma_x());
auto sigma_y = Sigma(blur->sigma_y());
if (blur->tile_mode() != flutter::DlTileMode::kClamp) {
// TODO(105072): Implement tile mode for blur filter.

View File

@ -11,6 +11,7 @@
#include "impeller/entity/contents/filters/inputs/filter_input.h"
#include "impeller/entity/entity.h"
#include "impeller/geometry/sigma.h"
#include "impeller/renderer/formats.h"
namespace impeller {
@ -30,57 +31,6 @@ class FilterContents : public Contents {
kInner,
};
/// For filters that use a Gaussian distribution, this is the `Radius` size to
/// use per `Sigma` (standard deviation).
///
/// This cutoff (sqrt(3)) is taken from Flutter and Skia (where the
/// multiplicative inverse of this constant is used (1 / sqrt(3)):
/// https://api.flutter.dev/flutter/dart-ui/Shadow/convertRadiusToSigma.html
///
/// In practice, this value is somewhat arbitrary, and can be changed to a
/// higher number to integrate more of the Gaussian function and render higher
/// quality blurs (with exponentially diminishing returns for the same sigma
/// input). Making this value any lower results in a noticable loss of
/// quality in the blur.
constexpr static float kKernelRadiusPerSigma = 1.73205080757;
struct Radius;
/// @brief In filters that use Gaussian distributions, "sigma" is a size of
/// one standard deviation in terms of the local space pixel grid of
/// the filter input. In other words, this determines how wide the
/// distribution stretches.
struct Sigma {
Scalar sigma = 0.0;
constexpr Sigma() = default;
explicit constexpr Sigma(Scalar p_sigma) : sigma(p_sigma) {}
constexpr operator Radius() const {
return Radius{sigma > 0.5f ? (sigma - 0.5f) * kKernelRadiusPerSigma
: 0.0f};
};
};
/// @brief For convolution filters, the "radius" is the size of the
/// convolution kernel to use on the local space pixel grid of the
/// filter input.
/// For Gaussian blur kernels, this unit has a linear
/// relationship with `Sigma`. See `kKernelRadiusPerSigma` for
/// details on how this relationship works.
struct Radius {
Scalar radius = 0.0;
constexpr Radius() = default;
explicit constexpr Radius(Scalar p_radius) : radius(p_radius) {}
constexpr operator Sigma() const {
return Sigma{radius > 0 ? radius / kKernelRadiusPerSigma + 0.5f : 0.0f};
};
};
static std::shared_ptr<FilterContents> MakeBlend(
Entity::BlendMode blend_mode,
FilterInput::Vector inputs,

View File

@ -20,6 +20,7 @@
#include "impeller/entity/entity_playground.h"
#include "impeller/geometry/geometry_unittests.h"
#include "impeller/geometry/path_builder.h"
#include "impeller/geometry/sigma.h"
#include "impeller/playground/playground.h"
#include "impeller/playground/widgets.h"
#include "impeller/renderer/render_pass.h"
@ -913,13 +914,11 @@ TEST_P(EntityTest, GaussianBlurFilter) {
}
auto blur = FilterContents::MakeGaussianBlur(
FilterInput::Make(input), FilterContents::Sigma{blur_amount[0]},
FilterContents::Sigma{blur_amount[1]},
FilterInput::Make(input), Sigma{blur_amount[0]}, Sigma{blur_amount[1]},
blur_styles[selected_blur_style]);
auto mask_blur = FilterContents::MakeBorderMaskBlur(
FilterInput::Make(input), FilterContents::Sigma{blur_amount[0]},
FilterContents::Sigma{blur_amount[1]},
FilterInput::Make(input), Sigma{blur_amount[0]}, Sigma{blur_amount[1]},
blur_styles[selected_blur_style]);
auto ctm = Matrix::MakeScale(GetContentScale()) *
@ -1033,8 +1032,7 @@ TEST_P(EntityTest, BorderMaskBlurCoverageIsCorrect) {
PathBuilder{}.AddRect(Rect::MakeXYWH(0, 0, 300, 400)).TakePath());
fill->SetColor(Color::CornflowerBlue());
auto border_mask_blur = FilterContents::MakeBorderMaskBlur(
FilterInput::Make(fill), FilterContents::Radius{3},
FilterContents::Radius{4});
FilterInput::Make(fill), Radius{3}, Radius{4});
{
Entity e;

View File

@ -29,6 +29,8 @@ impeller_component("geometry") {
"scalar.h",
"shear.cc",
"shear.h",
"sigma.cc",
"sigma.h",
"size.cc",
"size.h",
"type_traits.cc",

View File

@ -0,0 +1,19 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "impeller/geometry/sigma.h"
#include <sstream>
namespace impeller {
Sigma::operator Radius() const {
return Radius{sigma > 0.5f ? (sigma - 0.5f) * kKernelRadiusPerSigma : 0.0f};
}
Radius::operator Sigma() const {
return Sigma{radius > 0 ? radius / kKernelRadiusPerSigma + 0.5f : 0.0f};
}
} // namespace impeller

View File

@ -0,0 +1,57 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include "impeller/geometry/scalar.h"
namespace impeller {
/// For filters that use a Gaussian distribution, this is the `Radius` size to
/// use per `Sigma` (standard deviation).
///
/// This cutoff (sqrt(3)) is taken from Flutter and Skia (where the
/// multiplicative inverse of this constant is used (1 / sqrt(3)):
/// https://api.flutter.dev/flutter/dart-ui/Shadow/convertRadiusToSigma.html
///
/// In practice, this value is somewhat arbitrary, and can be changed to a
/// higher number to integrate more of the Gaussian function and render higher
/// quality blurs (with exponentially diminishing returns for the same sigma
/// input). Making this value any lower results in a noticable loss of
/// quality in the blur.
constexpr static float kKernelRadiusPerSigma = 1.73205080757;
struct Radius;
/// @brief In filters that use Gaussian distributions, "sigma" is a size of
/// one standard deviation in terms of the local space pixel grid of
/// the filter input. In other words, this determines how wide the
/// distribution stretches.
struct Sigma {
Scalar sigma = 0.0;
constexpr Sigma() = default;
explicit constexpr Sigma(Scalar p_sigma) : sigma(p_sigma) {}
operator Radius() const; // NOLINT(google-explicit-constructor)
};
/// @brief For convolution filters, the "radius" is the size of the
/// convolution kernel to use on the local space pixel grid of the
/// filter input.
/// For Gaussian blur kernels, this unit has a linear
/// relationship with `Sigma`. See `kKernelRadiusPerSigma` for
/// details on how this relationship works.
struct Radius {
Scalar radius = 0.0;
constexpr Radius() = default;
explicit constexpr Radius(Scalar p_radius) : radius(p_radius) {}
operator Sigma() const; // NOLINT(google-explicit-constructor)
};
} // namespace impeller