| Flutter Impeller |

solid_rrect_like_blur_contents.cc
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 #include "impeller/entity/contents/solid_rrect_like_blur_contents.h"
6 #include <optional>
7
8 #include "impeller/entity/contents/content_context.h"
9 #include "impeller/entity/entity.h"
10 #include "impeller/geometry/color.h"
11 #include "impeller/geometry/constants.h"
12 #include "impeller/renderer/render_pass.h"
13 #include "impeller/renderer/vertex_buffer_builder.h"
14
15 namespace impeller {
16
17 namespace {
18 // Generous padding to make sure blurs with large sigmas are fully visible. Used
19 // to expand the geometry around the rrect. Larger sigmas have more subtle
20 // gradients so they need larger padding to avoid hard cutoffs. Sigma is
21 // maximized to 3.5 since that should cover 99.95% of all samples. 3.0 should
22 // cover 99.7% but that was seen to be not enough for large sigmas.
23 Scalar PadForSigma(Scalar sigma) {
24 Scalar scalar = std::min((1.0f / 47.6f) * sigma + 2.5f, 3.5f);
25 return sigma * scalar;
26 }
27 } // namespace
28
29 SolidRRectLikeBlurContents::SolidRRectLikeBlurContents() = default;
30
31 SolidRRectLikeBlurContents::~SolidRRectLikeBlurContents() = default;
32
33 void SolidRRectLikeBlurContents::SetShape(Rect rect, Scalar corner_radius) {
34 rect_ = rect;
35 corner_radius_ = corner_radius;
36 }
37
38 void SolidRRectLikeBlurContents::SetSigma(Sigma sigma) {
39 sigma_ = sigma;
40 }
41
42 void SolidRRectLikeBlurContents::SetColor(Color color) {
43 color_ = color.Premultiply();
44 }
45
46 Color SolidRRectLikeBlurContents::GetColor() const {
47 return color_;
48 }
49
50 static Point eccentricity(Point v, double sInverse) {
51 Point vOverS = v * sInverse * 0.5;
52 Point vOverS_squared = -(vOverS * vOverS);
53 return {std::exp(vOverS_squared.x), std::exp(vOverS_squared.y)};
54 }
55
56 static Scalar kTwoOverSqrtPi = 2.0 / std::sqrt(kPi);
57
58 // use crate::math::compute_erf7;
59 static Scalar computeErf7(Scalar x) {
60 x *= kTwoOverSqrtPi;
61 float xx = x * x;
62 x = x + (0.24295 + (0.03395 + 0.0104 * xx) * xx) * (x * xx);
63 return x / sqrt(1.0 + x * x);
64 }
65
66 static Point NegPos(Scalar v) {
67 return {std::min(v, 0.0f), std::max(v, 0.0f)};
68 }
69
70 bool SolidRRectLikeBlurContents::PopulateFragContext(PassContext& pass_context,
71 Scalar blurSigma,
72 Point center,
73 Point rSize,
74 Scalar radius) {
75 Scalar sigma = std::max(blurSigma * kSqrt2, 1.f);
76
77 pass_context.center = rSize * 0.5f;
78 pass_context.minEdge = std::min(rSize.x, rSize.y);
79 double rMax = 0.5 * pass_context.minEdge;
80 double r0 = std::min(std::hypot(radius, sigma * 1.15), rMax);
81 pass_context.r1 = std::min(std::hypot(radius, sigma * 2.0), rMax);
82
83 pass_context.exponent = 2.0 * pass_context.r1 / r0;
84
85 pass_context.sInv = 1.0 / sigma;
86
87 // Pull in long end (make less eccentric).
88 Point eccentricV = eccentricity(rSize, pass_context.sInv);
89 double delta = 1.25 * sigma * (eccentricV.x - eccentricV.y);
90 rSize += NegPos(delta);
91
92 pass_context.adjust = rSize * 0.5 - pass_context.r1;
93 pass_context.exponentInv = 1.0 / pass_context.exponent;
94 pass_context.scale =
95 0.5 * computeErf7(pass_context.sInv * 0.5 *
96 (std::max(rSize.x, rSize.y) - 0.5 * radius));
97
98 return pass_context.center.IsFinite() && //
99 pass_context.adjust.IsFinite() && //
100 std::isfinite(pass_context.minEdge) && //
101 std::isfinite(pass_context.r1) && //
102 std::isfinite(pass_context.exponent) && //
103 std::isfinite(pass_context.sInv) && //
104 std::isfinite(pass_context.exponentInv) && //
105 std::isfinite(pass_context.scale);
106 }
107
108 std::optional<Rect> SolidRRectLikeBlurContents::GetCoverage(
109 const Entity& entity) const {
110 Scalar radius = PadForSigma(sigma_.sigma);
111
112 return rect_.Expand(radius).TransformBounds(entity.GetTransform());
113 }
114
115 bool SolidRRectLikeBlurContents::Render(const ContentContext& renderer,
116 const Entity& entity,
117 RenderPass& pass) const {
118 using VS = RrectLikeBlurVertexShader;
119
120 Matrix basis_invert = entity.GetTransform().Basis().Invert();
121 Vector2 max_sigmas =
122 Vector2((basis_invert * Vector2(500.f, 0.f)).GetLength(),
123 (basis_invert * Vector2(0.f, 500.f)).GetLength());
124 Scalar max_sigma = std::min(max_sigmas.x, max_sigmas.y);
125 // Clamp the max kernel width/height to 1000 (@ 2x) to limit the extent
126 // of the blur and to kEhCloseEnough to prevent NaN calculations
127 // trying to evaluate a Gaussian distribution with a sigma of 0.
128 auto blur_sigma = std::clamp(sigma_.sigma, kEhCloseEnough, max_sigma);
129 // Increase quality by making the radius a bit bigger than the typical
130 // sigma->radius conversion we use for slower blurs.
131 Scalar blur_radius = PadForSigma(blur_sigma);
132 Rect positive_rect = rect_.GetPositive();
133 Scalar left = -blur_radius;
134 Scalar top = -blur_radius;
135 Scalar right = positive_rect.GetWidth() + blur_radius;
136 Scalar bottom = positive_rect.GetHeight() + blur_radius;
137
138 ContentContextOptions opts = OptionsFromPassAndEntity(pass, entity);
139 opts.primitive_type = PrimitiveType::kTriangleStrip;
140 Color color = color_;
141 if (entity.GetBlendMode() == BlendMode::kClear) {
142 opts.is_for_rrect_blur_clear = true;
143 color = Color::White();
144 }
145
146 std::array<VS::PerVertexData, 4> vertices = {
147 VS::PerVertexData{Point(left, top)},
148 VS::PerVertexData{Point(right, top)},
149 VS::PerVertexData{Point(left, bottom)},
150 VS::PerVertexData{Point(right, bottom)},
151 };
152
153 PassContext pass_context = {
154 .opts = opts,
155 };
156
157 Scalar radius = std::min(std::clamp(corner_radius_, kEhCloseEnough,
158 positive_rect.GetWidth() * 0.5f),
159 std::clamp(corner_radius_, kEhCloseEnough,
160 positive_rect.GetHeight() * 0.5f));
161 if (!PopulateFragContext(pass_context, blur_sigma, positive_rect.GetCenter(),
162 Point(positive_rect.GetSize()), radius)) {
163 return true;
164 }
165
166 if (!SetPassInfo(pass, renderer, pass_context)) {
167 return true;
168 }
169
170 VS::FrameInfo frame_info;
171 frame_info.mvp = Entity::GetShaderTransform(
172 entity.GetShaderClipDepth(), pass,
173 entity.GetTransform() *
174 Matrix::MakeTranslation(positive_rect.GetOrigin()));
175
176 auto& data_host_buffer = renderer.GetTransientsDataBuffer();
177 pass.SetVertexBuffer(CreateVertexBuffer(vertices, data_host_buffer));
178 VS::BindFrameInfo(pass, data_host_buffer.EmplaceUniform(frame_info));
179
180 if (!pass.Draw().ok()) {
181 return false;
182 }
183
184 return true;
185 }
186
187 bool SolidRRectLikeBlurContents::ApplyColorFilter(
188 const ColorFilterProc& color_filter_proc) {
189 color_ = color_filter_proc(color_);
190 return true;
191 }
192
193 Vector4 SolidRRectLikeBlurContents::Concat(Vector2& a, Vector2& b) {
194 return {a.x, a.y, b.x, b.y};
195 }
196
197 } // namespace impeller
impeller::ContentContext
Definition: content_context.h:122
impeller::ContentContext::GetTransientsDataBuffer
HostBuffer & GetTransientsDataBuffer() const
Retrieve the current host buffer for transient storage of other non-index data.
Definition: content_context.h:299
impeller::Contents::ColorFilterProc
std::function< Color(Color)> ColorFilterProc
Definition: contents.h:35
impeller::Entity
Definition: entity.h:26
impeller::Entity::GetShaderTransform
Matrix GetShaderTransform(const RenderPass &pass) const
Definition: entity.cc:50
impeller::Entity::GetBlendMode
BlendMode GetBlendMode() const
Definition: entity.cc:102
impeller::Entity::GetTransform
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition: entity.cc:46
impeller::Entity::GetShaderClipDepth
float GetShaderClipDepth() const
Definition: entity.cc:90
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:30
impeller::RenderPass::SetVertexBuffer
virtual bool SetVertexBuffer(VertexBuffer buffer)
Specify the vertex and index buffer to use for this command.
Definition: render_pass.cc:127
impeller::RenderPass::Draw
virtual fml::Status Draw()
Record the currently pending command.
Definition: render_pass.cc:208
impeller::SolidRRectLikeBlurContents::SetShape
void SetShape(Rect rect, Scalar corner_radius)
Definition: solid_rrect_like_blur_contents.cc:33
impeller::SolidRRectLikeBlurContents::GetCoverage
std::optional< Rect > GetCoverage(const Entity &entity) const override
Get the area of the render pass that will be affected when this contents is rendered.
Definition: solid_rrect_like_blur_contents.cc:108
impeller::SolidRRectLikeBlurContents::~SolidRRectLikeBlurContents
~SolidRRectLikeBlurContents() override
impeller::SolidRRectLikeBlurContents::SetPassInfo
virtual bool SetPassInfo(RenderPass &pass, const ContentContext &renderer, PassContext &pass_context) const =0
impeller::SolidRRectLikeBlurContents::Render
bool Render(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
Definition: solid_rrect_like_blur_contents.cc:115
impeller::SolidRRectLikeBlurContents::SetSigma
void SetSigma(Sigma sigma)
Definition: solid_rrect_like_blur_contents.cc:38
impeller::SolidRRectLikeBlurContents::GetColor
Color GetColor() const
Definition: solid_rrect_like_blur_contents.cc:46
impeller::SolidRRectLikeBlurContents::ApplyColorFilter
bool ApplyColorFilter(const ColorFilterProc &color_filter_proc) override
If possible, applies a color filter to this contents inputs on the CPU.
Definition: solid_rrect_like_blur_contents.cc:187
impeller::SolidRRectLikeBlurContents::Concat
static Vector4 Concat(Vector2 &a, Vector2 &b)
Definition: solid_rrect_like_blur_contents.cc:193
impeller::SolidRRectLikeBlurContents::SolidRRectLikeBlurContents
SolidRRectLikeBlurContents()
impeller::SolidRRectLikeBlurContents::SetColor
void SetColor(Color color) override
Definition: solid_rrect_like_blur_contents.cc:42
color.h
content_context.h
x
int32_t x
Definition: dl_golden_unittests.cc:458
entity.h
blur_radius
Vector2 blur_radius
Blur radius in source pixels based on scaled_sigma.
Definition: gaussian_blur_filter_contents.cc:85
constants.h
impeller::saturated::b
SI b
Definition: saturated_math.h:87
impeller
Definition: allocation.cc:12
impeller::computeErf7
static Scalar computeErf7(Scalar x)
Definition: solid_rrect_like_blur_contents.cc:59
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::Vector2
Point Vector2
Definition: point.h:429
impeller::kPi
constexpr float kPi
Definition: constants.h:26
impeller::Scalar
float Scalar
Definition: scalar.h:19
impeller::kEhCloseEnough
constexpr float kEhCloseEnough
Definition: constants.h:57
impeller::NegPos
static Point NegPos(Scalar v)
Definition: solid_rrect_like_blur_contents.cc:66
impeller::Point
TPoint< Scalar > Point
Definition: point.h:425
impeller::CreateVertexBuffer
VertexBuffer CreateVertexBuffer(std::array< VertexType, size > input, HostBuffer &data_host_buffer)
Create an index-less vertex buffer from a fixed size array.
Definition: vertex_buffer_builder.h:24
impeller::eccentricity
static Point eccentricity(Point v, double sInverse)
Definition: solid_rrect_like_blur_contents.cc:50
impeller::BlendMode::kClear
@ kClear
impeller::kTwoOverSqrtPi
static Scalar kTwoOverSqrtPi
Definition: solid_rrect_like_blur_contents.cc:56
impeller::kSqrt2
constexpr float kSqrt2
Definition: constants.h:47
impeller::VS
LinePipeline::VertexShader VS
Definition: line_contents.cc:13
impeller::OptionsFromPassAndEntity
ContentContextOptions OptionsFromPassAndEntity(const RenderPass &pass, const Entity &entity)
Definition: contents.cc:34
render_pass.h
solid_rrect_like_blur_contents.h
impeller::Color
Definition: color.h:124
impeller::Color::White
static constexpr Color White()
Definition: color.h:264
impeller::Color::Premultiply
constexpr Color Premultiply() const
Definition: color.h:212
impeller::ContentContextOptions
Definition: content_context.h:40
impeller::ContentContextOptions::primitive_type
PrimitiveType primitive_type
Definition: content_context.h:81
impeller::ContentContextOptions::is_for_rrect_blur_clear
bool is_for_rrect_blur_clear
Definition: content_context.h:85
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::Matrix::Basis
constexpr Matrix Basis() const
The Matrix without its w components (without translation).
Definition: matrix.h:239
impeller::Matrix::Invert
Matrix Invert() const
Definition: matrix.cc:99
impeller::Sigma
In filters that use Gaussian distributions, "sigma" is a size of one standard deviation in terms of t...
Definition: sigma.h:32
impeller::Sigma::sigma
Scalar sigma
Definition: sigma.h:33
impeller::SolidRRectLikeBlurContents::PassContext
Definition: solid_rrect_like_blur_contents.h:56
impeller::SolidRRectLikeBlurContents::PassContext::opts
ContentContextOptions opts
Definition: solid_rrect_like_blur_contents.h:58
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::TRect::Expand
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
Definition: rect.h:618
impeller::TRect::TransformBounds
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition: rect.h:472
impeller::TRect::GetHeight
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
Definition: rect.h:347
impeller::TRect::GetOrigin
constexpr TPoint< Type > GetOrigin() const
Returns the upper left corner of the rectangle as specified by the left/top or x/y values when it was...
Definition: rect.h:320
impeller::TRect::GetSize
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle which may be negative in either width or height and may have been c...
Definition: rect.h:327
impeller::TRect::GetPositive
constexpr TRect GetPositive() const
Get a version of this rectangle that has a non-negative size.
Definition: rect.h:398
impeller::TRect::GetWidth
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
Definition: rect.h:341
impeller::TRect::GetCenter
constexpr Point GetCenter() const
Get the center point as a |Point|.
Definition: rect.h:382
impeller::Vector4
Definition: vector.h:232
vertex_buffer_builder.h