Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
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
7 changes: 6 additions & 1 deletion impeller/compiler/shader_lib/impeller/gaussian.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ f16vec2 IPVec2GaussianIntegral(f16vec2 x, float16_t sigma) {
}

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

/// Simpler (but less accurate) approximation of the Gaussian integral.
f16vec2 IPHalfVec2FastGaussianIntegral(f16vec2 x, float16_t sigma) {
return 1.0hf / (1.0hf + exp(float16_t(-kSqrtThree) / sigma * x));
}

Expand Down
65 changes: 31 additions & 34 deletions impeller/entity/shaders/rrect_blur.frag
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

uniform FragInfo {
f16vec4 color;
f16vec2 rect_size;
float16_t blur_sigma;
float16_t corner_radius;
vec2 rect_size;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and elsewhere, mark these as highp so the issue is fixed for Vulkan too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

err, not elsewhere, but like, in the declaration.

float blur_sigma;
float corner_radius;
}
frag_info;

Expand All @@ -19,50 +19,47 @@ out f16vec4 frag_color;

const int kSampleCount = 4;

float16_t RRectDistance(f16vec2 sample_position, f16vec2 half_size) {
f16vec2 space = abs(sample_position) - half_size + frag_info.corner_radius;
return length(max(space, float16_t(0.0hf))) +
min(max(space.x, space.y), float16_t(0.0hf)) - frag_info.corner_radius;
float16_t RRectDistance(vec2 sample_position, vec2 half_size) {
vec2 space = abs(sample_position) - half_size + frag_info.corner_radius;
return float16_t(length(max(space, 0.0)) + min(max(space.x, space.y), 0.0) -
frag_info.corner_radius);
}

/// Closed form unidirectional rounded rect blur mask solution using the
/// analytical Gaussian integral (with approximated erf).
float16_t RRectBlurX(f16vec2 sample_position, f16vec2 half_size) {
float RRectBlurX(vec2 sample_position, vec2 half_size) {
// Compute the X direction distance field (not incorporating the Y distance)
// for the rounded rect.
float16_t space =
min(float16_t(0.0hf),
half_size.y - frag_info.corner_radius - abs(sample_position.y));
float16_t rrect_distance =
float space =
min(0.0, half_size.y - frag_info.corner_radius - abs(sample_position.y));
float rrect_distance =
half_size.x - frag_info.corner_radius +
sqrt(max(
float16_t(0.0hf),
frag_info.corner_radius * frag_info.corner_radius - space * space));
sqrt(max(0.0, frag_info.corner_radius * frag_info.corner_radius -
space * space));

// Map the linear distance field to the approximate Gaussian integral.
f16vec2 integral = IPVec2FastGaussianIntegral(
sample_position.x + f16vec2(-rrect_distance, rrect_distance),
frag_info.blur_sigma);
vec2 integral = IPVec2FastGaussianIntegral(
float(sample_position.x) + vec2(-rrect_distance, rrect_distance),
float(frag_info.blur_sigma));
return integral.y - integral.x;
}

float16_t RRectBlur(f16vec2 sample_position, f16vec2 half_size) {
float RRectBlur(vec2 sample_position, vec2 half_size) {
// Limit the sampling range to 3 standard deviations in the Y direction from
// the kernel center to incorporate 99.7% of the color contribution.
float16_t half_sampling_range = frag_info.blur_sigma * 3.0hf;
float half_sampling_range = frag_info.blur_sigma * 3.0;

float16_t begin_y =
max(-half_sampling_range, sample_position.y - half_size.y);
float16_t end_y = min(half_sampling_range, sample_position.y + half_size.y);
float16_t interval = (end_y - begin_y) / float16_t(kSampleCount);
float begin_y = max(-half_sampling_range, sample_position.y - half_size.y);
float end_y = min(half_sampling_range, sample_position.y + half_size.y);
float interval = (end_y - begin_y) / kSampleCount;

// Sample the X blur kSampleCount times, weighted by the Gaussian function.
float16_t result = 0.0hf;
float result = 0.0;
for (int sample_i = 0; sample_i < kSampleCount; sample_i++) {
float16_t y = begin_y + interval * (float16_t(sample_i) + 0.5hf);
result += RRectBlurX(f16vec2(sample_position.x, sample_position.y - y),
half_size) *
IPHalfGaussian(y, frag_info.blur_sigma) * interval;
float y = begin_y + interval * (float(sample_i) + 0.5);
result +=
RRectBlurX(vec2(sample_position.x, sample_position.y - y), half_size) *
IPGaussian(float(y), float(frag_info.blur_sigma)) * interval;
}

return result;
Expand All @@ -71,12 +68,12 @@ float16_t RRectBlur(f16vec2 sample_position, f16vec2 half_size) {
void main() {
frag_color = frag_info.color;

f16vec2 half_size = frag_info.rect_size * 0.5hf;
f16vec2 sample_position = f16vec2(v_position) - half_size;
vec2 half_size = frag_info.rect_size * 0.5;
vec2 sample_position = v_position - half_size;

if (frag_info.blur_sigma > 0.0hf) {
frag_color *= RRectBlur(sample_position, half_size);
if (frag_info.blur_sigma > 0.0) {
frag_color *= float16_t(RRectBlur(sample_position, half_size));
} else {
frag_color *= -RRectDistance(sample_position, half_size);
frag_color *= float16_t(-RRectDistance(sample_position, half_size));
}
}