| Flutter Impeller |

solid_rrect_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_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 SolidRRectBlurContents::SolidRRectBlurContents() = default;
30
31 SolidRRectBlurContents::~SolidRRectBlurContents() = default;
32
33 void SolidRRectBlurContents::SetRRect(std::optional<Rect> rect,
34 Size corner_radii) {
35 rect_ = rect;
36 corner_radii_ = corner_radii;
37 }
38
39 void SolidRRectBlurContents::SetSigma(Sigma sigma) {
40 sigma_ = sigma;
41 }
42
43 void SolidRRectBlurContents::SetColor(Color color) {
44 color_ = color.Premultiply();
45 }
46
47 Color SolidRRectBlurContents::GetColor() const {
48 return color_;
49 }
50
51 static Point eccentricity(Point v, double sInverse) {
52 Point vOverS = v * sInverse * 0.5;
53 Point vOverS_squared = -(vOverS * vOverS);
54 return {std::exp(vOverS_squared.x), std::exp(vOverS_squared.y)};
55 }
56
57 static Scalar kTwoOverSqrtPi = 2.0 / std::sqrt(kPi);
58
59 // use crate::math::compute_erf7;
60 static Scalar computeErf7(Scalar x) {
61 x *= kTwoOverSqrtPi;
62 float xx = x * x;
63 x = x + (0.24295 + (0.03395 + 0.0104 * xx) * xx) * (x * xx);
64 return x / sqrt(1.0 + x * x);
65 }
66
67 static Point NegPos(Scalar v) {
68 return {std::min(v, 0.0f), std::max(v, 0.0f)};
69 }
70
71 static bool SetupFragInfo(
72 RRectBlurPipeline::FragmentShader::FragInfo& frag_info,
73 Scalar blurSigma,
74 Point center,
75 Point rSize,
76 Scalar radius) {
77 Scalar sigma = std::max(blurSigma * kSqrt2, 1.f);
78
79 frag_info.center = rSize * 0.5f;
80 frag_info.minEdge = std::min(rSize.x, rSize.y);
81 double rMax = 0.5 * frag_info.minEdge;
82 double r0 = std::min(std::hypot(radius, sigma * 1.15), rMax);
83 frag_info.r1 = std::min(std::hypot(radius, sigma * 2.0), rMax);
84
85 frag_info.exponent = 2.0 * frag_info.r1 / r0;
86
87 frag_info.sInv = 1.0 / sigma;
88
89 // Pull in long end (make less eccentric).
90 Point eccentricV = eccentricity(rSize, frag_info.sInv);
91 double delta = 1.25 * sigma * (eccentricV.x - eccentricV.y);
92 rSize += NegPos(delta);
93
94 frag_info.adjust = rSize * 0.5 - frag_info.r1;
95 frag_info.exponentInv = 1.0 / frag_info.exponent;
96 frag_info.scale =
97 0.5 * computeErf7(frag_info.sInv * 0.5 *
98 (std::max(rSize.x, rSize.y) - 0.5 * radius));
99
100 return frag_info.center.IsFinite() && //
101 frag_info.adjust.IsFinite() && //
102 std::isfinite(frag_info.minEdge) && //
103 std::isfinite(frag_info.r1) && //
104 std::isfinite(frag_info.exponent) && //
105 std::isfinite(frag_info.sInv) && //
106 std::isfinite(frag_info.exponentInv) && //
107 std::isfinite(frag_info.scale);
108 }
109
110 std::optional<Rect> SolidRRectBlurContents::GetCoverage(
111 const Entity& entity) const {
112 if (!rect_.has_value()) {
113 return std::nullopt;
114 }
115
116 Scalar radius = PadForSigma(sigma_.sigma);
117
118 return rect_->Expand(radius).TransformBounds(entity.GetTransform());
119 }
120
121 bool SolidRRectBlurContents::Render(const ContentContext& renderer,
122 const Entity& entity,
123 RenderPass& pass) const {
124 if (!rect_.has_value()) {
125 return true;
126 }
127
128 using VS = RRectBlurPipeline::VertexShader;
129 using FS = RRectBlurPipeline::FragmentShader;
130
131 // Clamp the max kernel width/height to 1000 to limit the extent
132 // of the blur and to kEhCloseEnough to prevent NaN calculations
133 // trying to evaluate a Guassian distribution with a sigma of 0.
134 Scalar blur_sigma = std::clamp(sigma_.sigma, kEhCloseEnough, 250.0f);
135 // Increase quality by making the radius a bit bigger than the typical
136 // sigma->radius conversion we use for slower blurs.
137 Scalar blur_radius = PadForSigma(blur_sigma);
138 Rect positive_rect = rect_->GetPositive();
139 Scalar left = -blur_radius;
140 Scalar top = -blur_radius;
141 Scalar right = positive_rect.GetWidth() + blur_radius;
142 Scalar bottom = positive_rect.GetHeight() + blur_radius;
143
144 std::array<VS::PerVertexData, 4> vertices = {
145 VS::PerVertexData{Point(left, top)},
146 VS::PerVertexData{Point(right, top)},
147 VS::PerVertexData{Point(left, bottom)},
148 VS::PerVertexData{Point(right, bottom)},
149 };
150
151 ContentContextOptions opts = OptionsFromPassAndEntity(pass, entity);
152 opts.primitive_type = PrimitiveType::kTriangleStrip;
153 Color color = color_;
154 if (entity.GetBlendMode() == BlendMode::kClear) {
155 opts.is_for_rrect_blur_clear = true;
156 color = Color::White();
157 }
158
159 VS::FrameInfo frame_info;
160 frame_info.mvp = Entity::GetShaderTransform(
161 entity.GetShaderClipDepth(), pass,
162 entity.GetTransform() *
163 Matrix::MakeTranslation(positive_rect.GetOrigin()));
164
165 FS::FragInfo frag_info;
166 frag_info.color = color;
167 Scalar radius = std::min(std::clamp(corner_radii_.width, kEhCloseEnough,
168 positive_rect.GetWidth() * 0.5f),
169 std::clamp(corner_radii_.height, kEhCloseEnough,
170 positive_rect.GetHeight() * 0.5f));
171 if (!SetupFragInfo(frag_info, blur_sigma, positive_rect.GetCenter(),
172 Point(positive_rect.GetSize()), radius)) {
173 return true;
174 }
175
176 auto& host_buffer = renderer.GetTransientsBuffer();
177 pass.SetCommandLabel("RRect Shadow");
178 pass.SetPipeline(renderer.GetRRectBlurPipeline(opts));
179 pass.SetVertexBuffer(CreateVertexBuffer(vertices, host_buffer));
180
181 VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
182 FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
183
184 if (!pass.Draw().ok()) {
185 return false;
186 }
187
188 return true;
189 }
190
191 bool SolidRRectBlurContents::ApplyColorFilter(
192 const ColorFilterProc& color_filter_proc) {
193 color_ = color_filter_proc(color_);
194 return true;
195 }
196
197 } // namespace impeller
impeller::Sigma::sigma
Scalar sigma
Definition: sigma.h:33
impeller::RenderPipelineHandle::FragmentShader
FragmentShader_ FragmentShader
Definition: pipeline.h:114
impeller::Entity::GetShaderTransform
Matrix GetShaderTransform(const RenderPass &pass) const
Get the vertex shader transform used for drawing this Entity.
Definition: entity.cc:48
impeller::Entity::GetShaderClipDepth
float GetShaderClipDepth() const
Definition: entity.cc:88
impeller::TPoint::y
Type y
Definition: point.h:31
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::kSqrt2
constexpr float kSqrt2
Definition: constants.h:47
impeller::Entity::GetTransform
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition: entity.cc:44
entity.h
impeller::Color
Definition: color.h:123
impeller::SolidRRectBlurContents::GetColor
Color GetColor() const
Definition: solid_rrect_blur_contents.cc:47
impeller::kEhCloseEnough
constexpr float kEhCloseEnough
Definition: constants.h:56
impeller::VS
GlyphAtlasPipeline::VertexShader VS
Definition: text_contents.cc:25
impeller::SolidRRectBlurContents::SetSigma
void SetSigma(Sigma sigma)
Definition: solid_rrect_blur_contents.cc:39
impeller::SolidRRectBlurContents::SetColor
void SetColor(Color color)
Definition: solid_rrect_blur_contents.cc:43
impeller::kPi
constexpr float kPi
Definition: constants.h:26
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::computeErf7
static Scalar computeErf7(Scalar x)
Definition: solid_rrect_blur_contents.cc:60
impeller::SolidRRectBlurContents::SolidRRectBlurContents
SolidRRectBlurContents()
impeller::TRect::GetCenter
constexpr Point GetCenter() const
Get the center point as a |Point|.
Definition: rect.h:386
impeller::TRect::GetHeight
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
Definition: rect.h:351
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
x
int32_t x
Definition: dl_golden_unittests.cc:443
impeller::RenderPass::SetCommandLabel
virtual void SetCommandLabel(std::string_view label)
The debugging label to use for the command.
Definition: render_pass.cc:97
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:324
impeller::RenderPass::Draw
virtual fml::Status Draw()
Record the currently pending command.
Definition: render_pass.cc:208
impeller::Entity
Definition: entity.h:20
impeller::OptionsFromPassAndEntity
ContentContextOptions OptionsFromPassAndEntity(const RenderPass &pass, const Entity &entity)
Definition: contents.cc:34
impeller::TSize< Scalar >
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
render_pass.h
impeller::NegPos
static Point NegPos(Scalar v)
Definition: solid_rrect_blur_contents.cc:67
impeller::BlendMode::kClear
@ kClear
impeller::CreateVertexBuffer
VertexBuffer CreateVertexBuffer(std::array< VertexType, size > input, HostBuffer &host_buffer)
Create an index-less vertex buffer from a fixed size array.
Definition: vertex_buffer_builder.h:24
impeller::SetupFragInfo
static bool SetupFragInfo(RRectBlurPipeline::FragmentShader::FragInfo &frag_info, Scalar blurSigma, Point center, Point rSize, Scalar radius)
Definition: solid_rrect_blur_contents.cc:71
impeller::Contents::ColorFilterProc
std::function< Color(Color)> ColorFilterProc
Definition: contents.h:35
impeller::TRect::GetWidth
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
Definition: rect.h:345
impeller::kTwoOverSqrtPi
static Scalar kTwoOverSqrtPi
Definition: solid_rrect_blur_contents.cc:57
impeller::RenderPipelineHandle::VertexShader
VertexShader_ VertexShader
Definition: pipeline.h:113
impeller::Color::White
static constexpr Color White()
Definition: color.h:263
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::ContentContextOptions::is_for_rrect_blur_clear
bool is_for_rrect_blur_clear
Definition: content_context.h:341
impeller::SolidRRectBlurContents::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_blur_contents.cc:191
impeller::TSize::width
Type width
Definition: size.h:28
impeller::Entity::GetBlendMode
BlendMode GetBlendMode() const
Definition: entity.cc:101
impeller::TPoint::x
Type x
Definition: point.h:30
impeller::ContentContextOptions::primitive_type
PrimitiveType primitive_type
Definition: content_context.h:336
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:30
content_context.h
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:331
constants.h
impeller::TPoint
Definition: point.h:27
impeller::SolidRRectBlurContents::Render
bool Render(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
Definition: solid_rrect_blur_contents.cc:121
blur_radius
Vector2 blur_radius
Blur radius in source pixels based on scaled_sigma.
Definition: gaussian_blur_filter_contents.cc:84
impeller::SolidRRectBlurContents::SetRRect
void SetRRect(std::optional< Rect > rect, Size corner_radii={})
Definition: solid_rrect_blur_contents.cc:33
color.h
impeller::RenderPass::SetPipeline
virtual void SetPipeline(PipelineRef pipeline)
The pipeline to use for this command.
Definition: render_pass.cc:86
impeller::TSize::height
Type height
Definition: size.h:29
impeller::eccentricity
static Point eccentricity(Point v, double sInverse)
Definition: solid_rrect_blur_contents.cc:51
impeller::SolidRRectBlurContents::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_blur_contents.cc:110
impeller::ContentContextOptions
Definition: content_context.h:279
impeller
Definition: allocation.cc:12
impeller::FS
GlyphAtlasPipeline::FragmentShader FS
Definition: text_contents.cc:26
impeller::ContentContext::GetRRectBlurPipeline
PipelineRef GetRRectBlurPipeline(ContentContextOptions opts) const
Definition: content_context.h:444
solid_rrect_blur_contents.h
impeller::ContentContext
Definition: content_context.h:371
impeller::Color::Premultiply
constexpr Color Premultiply() const
Definition: color.h:211
impeller::TRect
Definition: rect.h:122
impeller::ContentContext::GetTransientsBuffer
HostBuffer & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
Definition: content_context.h:866
vertex_buffer_builder.h
impeller::SolidRRectBlurContents::~SolidRRectBlurContents
~SolidRRectBlurContents() override