| Flutter Impeller |

gaussian_blur_filter_contents.h
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef FLUTTER_IMPELLER_ENTITY_CONTENTS_FILTERS_GAUSSIAN_BLUR_FILTER_CONTENTS_H_
6 #define FLUTTER_IMPELLER_ENTITY_CONTENTS_FILTERS_GAUSSIAN_BLUR_FILTER_CONTENTS_H_
7
8 #include <optional>
9 #include "impeller/entity/contents/content_context.h"
10 #include "impeller/entity/contents/filters/filter_contents.h"
11 #include "impeller/entity/geometry/geometry.h"
12 #include "impeller/geometry/color.h"
13
14 namespace impeller {
15
16 // Comes from gaussian.frag.
17 static constexpr int32_t kGaussianBlurMaxKernelSize = 50;
18
19 static_assert(sizeof(GaussianBlurPipeline::FragmentShader::KernelSamples) ==
20 sizeof(Vector4) * kGaussianBlurMaxKernelSize + sizeof(Vector4));
21
22 struct BlurParameters {
23 Point blur_uv_offset;
24 Scalar blur_sigma;
25 int blur_radius;
26 int step_size;
27 bool apply_unpremultiply;
28 };
29
30 struct KernelSample {
31 Vector2 uv_offset;
32 float coefficient;
33 };
34
35 /// A larger mirror of GaussianBlurPipeline::FragmentShader::KernelSamples.
36 ///
37 /// This is a mirror of GaussianBlurPipeline::FragmentShader::KernelSamples that
38 /// can hold 2x the max kernel size since it will get reduced with the lerp
39 /// hack.
40 struct KernelSamples {
41 static constexpr int kMaxKernelSize = kGaussianBlurMaxKernelSize * 2;
42 int sample_count;
43 KernelSample samples[kMaxKernelSize];
44 };
45
46 KernelSamples GenerateBlurInfo(BlurParameters parameters);
47
48 /// This will shrink the size of a kernel by roughly half by sampling between
49 /// samples and relying on linear interpolation between the samples.
50 GaussianBlurPipeline::FragmentShader::KernelSamples LerpHackKernelSamples(
51 KernelSamples samples);
52
53 /// Performs a bidirectional Gaussian blur.
54 //
55 // ## Implementation notes
56 //
57 // The blur is implemented as a three-pass process:
58 // 1. A downsampling pass. This is used for performance optimization on large
59 // blurs.
60 // 2. A Y-direction blur pass (in canvas coordinates).
61 // 3. An X-direction blur pass (in canvas coordinates).
62 //
63 // ### Lerp Hack
64 //
65 // The blur passes use a "lerp hack" to optimize the number of texture
66 // samples. This technique takes advantage of the hardware's free linear
67 // interpolation during texture sampling. It allows for the use of a kernel
68 // that is half the size of what would be mathematically required, achieving an
69 // equivalent effect as long as the sampling points are correctly aligned.
70 //
71 // ### Bounded vs. Unbounded Blur
72 //
73 // The behavior of the blur changes depending on whether the `bounds` parameter
74 // is set.
75 //
76 // - Unbounded (standard) blur: The blur kernel samples all pixels, and
77 // the `tile_mode` determines how to handle edges.
78 //
79 // - Bounded blur: This mode is used to implement iOS-style blurs where
80 // the blur effect is constrained to a specific rectangle. The process is
81 // modified as follows:
82 // - During the downsampling pass, pixels outside the `bounds` are treated
83 // as transparent black.
84 // - The two blur passes proceed normally, but thanks to the lerp hack and
85 // linear interpolation, when a sample falls between an in-bounds pixel
86 // and an out-of-bounds (transparent black) pixel, the out-of-bounds
87 // pixel contributes nothing to the result.
88 // - The final pass includes an opaque unpremultiply step to counteract the
89 // varying alpha introduced by the weights.
90 class GaussianBlurFilterContents final : public FilterContents {
91 public:
92 explicit GaussianBlurFilterContents(Scalar sigma_x,
93 Scalar sigma_y,
94 Entity::TileMode tile_mode,
95 std::optional<Rect> bounds,
96 BlurStyle mask_blur_style,
97 const Geometry* mask_geometry = nullptr);
98
99 std::optional<Rect> GetBounds() const { return bounds_; }
100 Scalar GetSigmaX() const { return sigma_.x; }
101 Scalar GetSigmaY() const { return sigma_.y; }
102
103 // |FilterContents|
104 std::optional<Rect> GetFilterSourceCoverage(
105 const Matrix& effect_transform,
106 const Rect& output_limit) const override;
107
108 // |FilterContents|
109 std::optional<Rect> GetFilterCoverage(
110 const FilterInput::Vector& inputs,
111 const Entity& entity,
112 const Matrix& effect_transform) const override;
113
114 /// Given a sigma (standard deviation) calculate the blur radius (1/2 the
115 /// kernel size).
116 static Scalar CalculateBlurRadius(Scalar sigma);
117
118 /// Calculate the UV coordinates for rendering the filter_input.
119 /// @param filter_input The FilterInput that should be rendered.
120 /// @param entity The associated entity for the filter_input.
121 /// @param source_rect The rect in source coordinates to convert to uvs.
122 /// @param texture_size The rect to convert in source coordinates.
123 static Quad CalculateUVs(const std::shared_ptr<FilterInput>& filter_input,
124 const Entity& entity,
125 const Rect& source_rect,
126 const ISize& texture_size);
127
128 /// Calculate the scale factor for the downsample pass given a sigma value.
129 ///
130 /// Visible for testing.
131 static Scalar CalculateScale(Scalar sigma);
132
133 /// Scales down the sigma value to match Skia's behavior.
134 ///
135 /// effective_blur_radius = CalculateBlurRadius(ScaleSigma(sigma_));
136 ///
137 /// This function was calculated by observing Skia's behavior. Its blur at
138 /// 500 seemed to be 0.15. Since we clamp at 500 I solved the quadratic
139 /// equation that puts the minima there and a f(0)=1.
140 static Scalar ScaleSigma(Scalar sigma);
141
142 private:
143 // |FilterContents|
144 std::optional<Entity> RenderFilter(
145 const FilterInput::Vector& input_textures,
146 const ContentContext& renderer,
147 const Entity& entity,
148 const Matrix& effect_transform,
149 const Rect& coverage,
150 const std::optional<Rect>& coverage_hint) const override;
151
152 const Vector2 sigma_ = Vector2(0.0, 0.0);
153 const Entity::TileMode tile_mode_;
154 const std::optional<Rect> bounds_ = std::nullopt;
155 const BlurStyle mask_blur_style_;
156 const Geometry* mask_geometry_ = nullptr;
157 };
158
159 } // namespace impeller
160
161 #endif // FLUTTER_IMPELLER_ENTITY_CONTENTS_FILTERS_GAUSSIAN_BLUR_FILTER_CONTENTS_H_
impeller::ContentContext
Definition: content_context.h:122
impeller::Entity
Definition: entity.h:26
impeller::Entity::TileMode
TileMode
Definition: entity.h:48
impeller::FilterContents
Definition: filter_contents.h:24
impeller::FilterContents::BlurStyle
BlurStyle
Definition: filter_contents.h:28
impeller::FilterInput::Vector
std::vector< FilterInput::Ref > Vector
Definition: filter_input.h:33
impeller::GaussianBlurFilterContents
Performs a bidirectional Gaussian blur.
Definition: gaussian_blur_filter_contents.h:90
impeller::GaussianBlurFilterContents::GetBounds
std::optional< Rect > GetBounds() const
Definition: gaussian_blur_filter_contents.h:99
impeller::GaussianBlurFilterContents::GetSigmaX
Scalar GetSigmaX() const
Definition: gaussian_blur_filter_contents.h:100
impeller::GaussianBlurFilterContents::GaussianBlurFilterContents
GaussianBlurFilterContents(Scalar sigma_x, Scalar sigma_y, Entity::TileMode tile_mode, std::optional< Rect > bounds, BlurStyle mask_blur_style, const Geometry *mask_geometry=nullptr)
Definition: gaussian_blur_filter_contents.cc:767
impeller::GaussianBlurFilterContents::GetSigmaY
Scalar GetSigmaY() const
Definition: gaussian_blur_filter_contents.h:101
impeller::GaussianBlurFilterContents::CalculateBlurRadius
static Scalar CalculateBlurRadius(Scalar sigma)
Definition: gaussian_blur_filter_contents.cc:1019
impeller::GaussianBlurFilterContents::ScaleSigma
static Scalar ScaleSigma(Scalar sigma)
Definition: gaussian_blur_filter_contents.cc:1039
impeller::GaussianBlurFilterContents::GetFilterSourceCoverage
std::optional< Rect > GetFilterSourceCoverage(const Matrix &effect_transform, const Rect &output_limit) const override
Internal utility method for |GetSourceCoverage| that computes the inverse effect of this transform on...
Definition: gaussian_blur_filter_contents.cc:813
impeller::GaussianBlurFilterContents::GetFilterCoverage
std::optional< Rect > GetFilterCoverage(const FilterInput::Vector &inputs, const Entity &entity, const Matrix &effect_transform) const override
Internal utility method for |GetLocalCoverage| that computes the output coverage of this filter acros...
Definition: gaussian_blur_filter_contents.cc:824
impeller::GaussianBlurFilterContents::CalculateScale
static Scalar CalculateScale(Scalar sigma)
Definition: gaussian_blur_filter_contents.cc:786
impeller::GaussianBlurFilterContents::CalculateUVs
static Quad CalculateUVs(const std::shared_ptr< FilterInput > &filter_input, const Entity &entity, const Rect &source_rect, const ISize &texture_size)
Definition: gaussian_blur_filter_contents.cc:1023
impeller::Geometry
Definition: geometry.h:50
color.h
content_context.h
filter_contents.h
geometry.h
impeller
Definition: allocation.cc:12
impeller::Vector2
Point Vector2
Definition: point.h:429
impeller::kGaussianBlurMaxKernelSize
static constexpr int32_t kGaussianBlurMaxKernelSize
Definition: gaussian_blur_filter_contents.h:17
impeller::Scalar
float Scalar
Definition: scalar.h:19
impeller::GenerateBlurInfo
KernelSamples GenerateBlurInfo(BlurParameters parameters)
Definition: gaussian_blur_filter_contents.cc:1049
impeller::Quad
std::array< Point, 4 > Quad
Definition: point.h:430
impeller::LerpHackKernelSamples
GaussianBlurPipeline::FragmentShader::KernelSamples LerpHackKernelSamples(KernelSamples parameters)
Definition: gaussian_blur_filter_contents.cc:1096
impeller::BlurParameters
Definition: gaussian_blur_filter_contents.h:22
impeller::BlurParameters::blur_uv_offset
Point blur_uv_offset
Definition: gaussian_blur_filter_contents.h:23
impeller::BlurParameters::apply_unpremultiply
bool apply_unpremultiply
Definition: gaussian_blur_filter_contents.h:27
impeller::BlurParameters::step_size
int step_size
Definition: gaussian_blur_filter_contents.h:26
impeller::BlurParameters::blur_radius
int blur_radius
Definition: gaussian_blur_filter_contents.h:25
impeller::BlurParameters::blur_sigma
Scalar blur_sigma
Definition: gaussian_blur_filter_contents.h:24
impeller::KernelSample
Definition: gaussian_blur_filter_contents.h:30
impeller::KernelSample::uv_offset
Vector2 uv_offset
Definition: gaussian_blur_filter_contents.h:31
impeller::KernelSample::coefficient
float coefficient
Definition: gaussian_blur_filter_contents.h:32
impeller::KernelSamples
Definition: gaussian_blur_filter_contents.h:40
impeller::KernelSamples::kMaxKernelSize
static constexpr int kMaxKernelSize
Definition: gaussian_blur_filter_contents.h:41
impeller::KernelSamples::samples
KernelSample samples[kMaxKernelSize]
Definition: gaussian_blur_filter_contents.h:43
impeller::KernelSamples::sample_count
int sample_count
Definition: gaussian_blur_filter_contents.h:42
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::TPoint< Scalar >
impeller::TPoint::y
Type y
Definition: point.h:32
impeller::TPoint::x
Type x
Definition: point.h:31
impeller::TRect< Scalar >
impeller::TSize
Definition: size.h:25
impeller::Vector4
Definition: vector.h:232