Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
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>
13
14namespace impeller {
15
16// Comes from gaussian.frag.
17static constexpr int32_t kGaussianBlurMaxKernelSize = 50;
18
19static_assert(sizeof(GaussianBlurPipeline::FragmentShader::KernelSamples) ==
21
29
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.
45
47 GaussianBlurPipeline::FragmentShader::KernelSamples kernel_samples;
48 int32_t sample_count;
49};
50
52
53/// This will shrink the size of a kernel by roughly half by sampling between
54/// samples and relying on linear interpolation between the samples.
56
57/// Performs a bidirectional Gaussian blur.
58//
59// ## Implementation notes
60//
61// The blur is implemented as a three-pass process:
62// 1. A downsampling pass. This is used for performance optimization on large
63// blurs.
64// 2. A Y-direction blur pass (in canvas coordinates).
65// 3. An X-direction blur pass (in canvas coordinates).
66//
67// ### Lerp Hack
68//
69// The blur passes use a "lerp hack" to optimize the number of texture
70// samples. This technique takes advantage of the hardware's free linear
71// interpolation during texture sampling. It allows for the use of a kernel
72// that is half the size of what would be mathematically required, achieving an
73// equivalent effect as long as the sampling points are correctly aligned.
74//
75// ### Bounded vs. Unbounded Blur
76//
77// The behavior of the blur changes depending on whether the `bounds` parameter
78// is set.
79//
80// - Unbounded (standard) blur: The blur kernel samples all pixels, and
81// the `tile_mode` determines how to handle edges.
82//
83// - Bounded blur: This mode is used to implement iOS-style blurs where
84// the blur effect is constrained to a specific rectangle. The process is
85// modified as follows:
86// - During the downsampling pass, pixels outside the `bounds` are treated
87// as transparent black.
88// - The two blur passes proceed normally, but thanks to the lerp hack and
89// linear interpolation, when a sample falls between an in-bounds pixel
90// and an out-of-bounds (transparent black) pixel, the out-of-bounds
91// pixel contributes nothing to the result.
92// - The final pass includes an opaque unpremultiply step to counteract the
93// varying alpha introduced by the weights.
95 public:
96 explicit GaussianBlurFilterContents(Scalar sigma_x,
97 Scalar sigma_y,
98 Entity::TileMode tile_mode,
99 std::optional<Rect> bounds,
100 BlurStyle mask_blur_style,
101 const Geometry* mask_geometry = nullptr);
102
103 std::optional<Rect> GetBounds() const { return bounds_; }
104 Scalar GetSigmaX() const { return sigma_.x; }
105 Scalar GetSigmaY() const { return sigma_.y; }
106
107 // |FilterContents|
108 std::optional<Rect> GetFilterSourceCoverage(
109 const Matrix& effect_transform,
110 const Rect& output_limit) const override;
111
112 // |FilterContents|
113 std::optional<Rect> GetFilterCoverage(
114 const FilterInput::Vector& inputs,
115 const Entity& entity,
116 const Matrix& effect_transform) const override;
117
118 /// Given a sigma (standard deviation) calculate the blur radius (1/2 the
119 /// kernel size).
120 static Scalar CalculateBlurRadius(Scalar sigma);
121
122 /// Calculate the UV coordinates for rendering the filter_input.
123 /// @param filter_input The FilterInput that should be rendered.
124 /// @param entity The associated entity for the filter_input.
125 /// @param source_rect The rect in source coordinates to convert to uvs.
126 /// @param texture_size The rect to convert in source coordinates.
127 static Quad CalculateUVs(const std::shared_ptr<FilterInput>& filter_input,
128 const Entity& entity,
129 const Rect& source_rect,
130 const ISize& texture_size);
131
132 /// Calculate the scale factor for the downsample pass given a sigma value.
133 ///
134 /// Visible for testing.
135 static Scalar CalculateScale(Scalar sigma);
136
137 /// Scales down the sigma value to match Skia's behavior.
138 ///
139 /// effective_blur_radius = CalculateBlurRadius(ScaleSigma(sigma_));
140 ///
141 /// This function was calculated by observing Skia's behavior. Its blur at
142 /// 500 seemed to be 0.15. Since we clamp at 500 I solved the quadratic
143 /// equation that puts the minima there and a f(0)=1.
144 static Scalar ScaleSigma(Scalar sigma);
145
146 private:
147 // |FilterContents|
148 std::optional<Entity> RenderFilter(
149 const FilterInput::Vector& input_textures,
150 const ContentContext& renderer,
151 const Entity& entity,
152 const Matrix& effect_transform,
153 const Rect& coverage,
154 const std::optional<Rect>& coverage_hint) const override;
155
156 const Vector2 sigma_ = Vector2(0.0, 0.0);
157 const Entity::TileMode tile_mode_;
158 const std::optional<Rect> bounds_ = std::nullopt;
159 const BlurStyle mask_blur_style_;
160 const Geometry* mask_geometry_ = nullptr;
161};
162
163} // namespace impeller
164
165#endif // FLUTTER_IMPELLER_ENTITY_CONTENTS_FILTERS_GAUSSIAN_BLUR_FILTER_CONTENTS_H_
std::vector< FilterInput::Ref > Vector
Performs a bidirectional Gaussian blur.
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...
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...
static Quad CalculateUVs(const std::shared_ptr< FilterInput > &filter_input, const Entity &entity, const Rect &source_rect, const ISize &texture_size)
LerpHackResult LerpHackKernelSamples(const KernelSamples &parameters)
Point Vector2
Definition point.h:430
static constexpr int32_t kGaussianBlurMaxKernelSize
float Scalar
Definition scalar.h:19
KernelSamples GenerateBlurInfo(BlurParameters parameters)
std::array< Point, 4 > Quad
Definition point.h:431
KernelSample samples[kMaxKernelSize]
GaussianBlurPipeline::FragmentShader::KernelSamples kernel_samples
A 4x4 matrix using column-major storage.
Definition matrix.h:37