Skip to content
This repository has been archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller] RRect blur improvements #38417

Merged
merged 1 commit into from
Dec 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions impeller/compiler/shader_lib/impeller/constants.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@ const float kSqrtTwoPi = 2.50662827463;
// sqrt(2) / 2 == 1 / sqrt(2)
const float kHalfSqrtTwo = 0.70710678118;

// sqrt(3)
const float kSqrtThree = 1.73205080757;

#endif
20 changes: 11 additions & 9 deletions impeller/compiler/shader_lib/impeller/gaussian.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,23 @@ vec2 IPVec2Erf(vec2 x) {
return sign(x) * (1 - 1 / (b * b * b * b));
}

/// Indefinite integral of the Gaussian function (with constant range 0->1).
/// The indefinite integral of the Gaussian function.
/// Uses a very close approximation of Erf.
float IPGaussianIntegral(float x, float sigma) {
// ( 1 + erf( x * (sqrt(2) / (2 * sigma) ) ) / 2
// Because this sigmoid is always > 1, we remap it (n * 1.07 - 0.07)
// so that it always fades to zero before it reaches the blur radius.
return 0.535 * IPErf(x * (kHalfSqrtTwo / sigma)) + 0.465;
return (1 + IPErf(x * (kHalfSqrtTwo / sigma))) * 0.5;
}

/// Vec2 variation for the indefinite integral of the Gaussian function (with
/// constant range 0->1).
/// Vec2 variation for the indefinite integral of the Gaussian function.
/// Uses a very close approximation of Erf.
vec2 IPVec2GaussianIntegral(vec2 x, float sigma) {
// ( 1 + erf( x * (sqrt(2) / (2 * sigma) ) ) / 2
// Because this sigmoid is always > 1, we remap it (n * 1.07 - 0.07)
// so that it always fades to zero before it reaches the blur radius.
return 0.535 * IPVec2Erf(x * (kHalfSqrtTwo / sigma)) + 0.465;
return (1 + IPVec2Erf(x * (kHalfSqrtTwo / sigma))) * 0.5;
}

/// Simpler (but less accurate) approximation of the Gaussian integral.
vec2 IPVec2FastGaussianIntegral(vec2 x, float sigma) {
return 1 / (1 + exp(-kSqrtThree / sigma * x));
}

/// Simple logistic sigmoid with a domain of [-1, 1] and range of [0, 1].
Expand Down
4 changes: 2 additions & 2 deletions impeller/entity/contents/rrect_shadow_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ std::optional<Rect> RRectShadowContents::GetCoverage(
return std::nullopt;
}

Scalar radius = Radius{sigma_}.radius;
Scalar radius = sigma_.sigma * 2;

auto ltrb = rect_->GetLTRB();
Rect bounds = Rect::MakeLTRB(ltrb[0] - radius, ltrb[1] - radius,
Expand All @@ -59,7 +59,7 @@ bool RRectShadowContents::Render(const ContentContext& renderer,

VertexBufferBuilder<VS::PerVertexData> vtx_builder;

auto blur_radius = Radius{sigma_}.radius;
auto blur_radius = sigma_.sigma * 2;
auto positive_rect = rect_->GetPositive();
{
auto left = -blur_radius;
Expand Down
6 changes: 3 additions & 3 deletions impeller/entity/shaders/rrect_blur.frag
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ in vec2 v_position;

out vec4 frag_color;

const int kSampleCount = 5;
const int kSampleCount = 4;

float RRectDistance(vec2 sample_position, vec2 half_size) {
vec2 space = abs(sample_position) - half_size + frag_info.corner_radius;
Expand All @@ -37,8 +37,8 @@ float RRectShadowX(vec2 sample_position, vec2 half_size) {
sqrt(max(0, frag_info.corner_radius * frag_info.corner_radius -
space * space));

// Map the linear distance field to the analytical Gaussian integral.
vec2 integral = IPVec2GaussianIntegral(
// Map the linear distance field to the approximate Gaussian integral.
vec2 integral = IPVec2FastGaussianIntegral(
sample_position.x + vec2(-rrect_distance, rrect_distance),
frag_info.blur_sigma);
return integral.y - integral.x;
Expand Down