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) ==
20 sizeof(Vector4) * kGaussianBlurMaxKernelSize + sizeof(Vector4));
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
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.
50GaussianBlurPipeline::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.
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_
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)
Point Vector2
Definition point.h:429
static constexpr int32_t kGaussianBlurMaxKernelSize
float Scalar
Definition scalar.h:19
KernelSamples GenerateBlurInfo(BlurParameters parameters)
std::array< Point, 4 > Quad
Definition point.h:430
GaussianBlurPipeline::FragmentShader::KernelSamples LerpHackKernelSamples(KernelSamples parameters)
KernelSample samples[kMaxKernelSize]
A 4x4 matrix using column-major storage.
Definition matrix.h:37