[Impeller] Move gaussian routines into the shader library (flutter/engine#37037)

This commit is contained in:
Brandon DeRosier 2022-10-26 11:37:16 -07:00 committed by GitHub
parent 702a9365bd
commit 2145adbc5a
5 changed files with 46 additions and 28 deletions

View File

@ -1107,6 +1107,7 @@ FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/blending.glsl
FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/branching.glsl
FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/color.glsl
FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/constants.glsl
FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/gaussian.glsl
FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/texture.glsl
FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/transform.glsl
FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/types.glsl

View File

@ -13,4 +13,7 @@ const float k1Over2Pi = 0.1591549430918;
// sqrt(2 * pi)
const float kSqrtTwoPi = 2.50662827463;
// sqrt(2) / 2 == 1 / sqrt(2)
const float kHalfSqrtTwo = 0.70710678118;
#endif

View File

@ -0,0 +1,35 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GAUSSIAN_GLSL_
#define GAUSSIAN_GLSL_
#include <impeller/constants.glsl>
float IPGaussian(float x, float sigma) {
float variance = sigma * sigma;
return exp(-0.5 * x * x / variance) / (kSqrtTwoPi * sigma);
}
/// Abramowitz and Stegun erf approximation.
float IPErf(float x) {
float a = abs(x);
// 0.278393*x + 0.230389*x^2 + 0.078108*x^4 + 1
float b = (0.278393 + (0.230389 + 0.078108 * a * a) * a) * a + 1.0;
return sign(x) * (1 - 1 / (b * b * b * b));
}
vec2 IPVec2Erf(vec2 x) {
return vec2(IPErf(x.x), IPErf(x.y));
}
/// Indefinite integral of the Gaussian function (with constant range 0->1).
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;
}
#endif

View File

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <impeller/gaussian.glsl>
#include <impeller/texture.glsl>
// Constant time mask blur for image borders.
@ -27,30 +28,12 @@ in float v_outer_blur_factor;
out vec4 frag_color;
// Abramowitz and Stegun erf approximation.
float erf(float x) {
float a = abs(x);
// 0.278393*x + 0.230389*x^2 + 0.078108*x^4 + 1
float b = (0.278393 + (0.230389 + 0.078108 * a * a) * a) * a + 1.0;
return sign(x) * (1 - 1 / (b * b * b * b));
}
const float kHalfSqrtTwo = 0.70710678118;
// Indefinite integral of the Gaussian function (with constant range 0->1).
float GaussianIntegral(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 * erf(x * (kHalfSqrtTwo / sigma)) + 0.465;
}
float BoxBlurMask(vec2 uv) {
// LTRB
return GaussianIntegral(uv.x, v_sigma_uv.x) * //
GaussianIntegral(uv.y, v_sigma_uv.y) * //
GaussianIntegral(1 - uv.x, v_sigma_uv.x) * //
GaussianIntegral(1 - uv.y, v_sigma_uv.y);
return IPGaussianIntegral(uv.x, v_sigma_uv.x) * //
IPGaussianIntegral(uv.y, v_sigma_uv.y) * //
IPGaussianIntegral(1 - uv.x, v_sigma_uv.x) * //
IPGaussianIntegral(1 - uv.y, v_sigma_uv.y);
}
void main() {

View File

@ -14,6 +14,7 @@
// level of log2(min_radius).
#include <impeller/constants.glsl>
#include <impeller/gaussian.glsl>
#include <impeller/texture.glsl>
uniform sampler2D texture_sampler;
@ -46,18 +47,13 @@ in vec2 v_src_texture_coords;
out vec4 frag_color;
float Gaussian(float x) {
float variance = frag_info.blur_sigma * frag_info.blur_sigma;
return exp(-0.5 * x * x / variance) / (kSqrtTwoPi * frag_info.blur_sigma);
}
void main() {
vec4 total_color = vec4(0);
float gaussian_integral = 0;
vec2 blur_uv_offset = frag_info.blur_direction / frag_info.texture_size;
for (float i = -frag_info.blur_radius; i <= frag_info.blur_radius; i++) {
float gaussian = Gaussian(i);
float gaussian = IPGaussian(i, frag_info.blur_sigma);
gaussian_integral += gaussian;
total_color +=
gaussian *