From 585ebdd0e0798616a3777376de1515fad651ea40 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 12 Jun 2023 18:43:58 -0700 Subject: [PATCH 1/3] [Impeller] Use 32 bit for positional stuff in the rrect blur --- .../shader_lib/impeller/gaussian.glsl | 7 +- impeller/entity/shaders/rrect_blur.frag | 65 +++++++++---------- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/impeller/compiler/shader_lib/impeller/gaussian.glsl b/impeller/compiler/shader_lib/impeller/gaussian.glsl index e98cdc6298c69..f5ab4b9c7bdb7 100644 --- a/impeller/compiler/shader_lib/impeller/gaussian.glsl +++ b/impeller/compiler/shader_lib/impeller/gaussian.glsl @@ -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)); } diff --git a/impeller/entity/shaders/rrect_blur.frag b/impeller/entity/shaders/rrect_blur.frag index 3f72925573050..8a12da3e42fad 100644 --- a/impeller/entity/shaders/rrect_blur.frag +++ b/impeller/entity/shaders/rrect_blur.frag @@ -7,9 +7,9 @@ uniform FragInfo { f16vec4 color; - f16vec2 rect_size; - float16_t blur_sigma; - float16_t corner_radius; + vec2 rect_size; + float blur_sigma; + float corner_radius; } frag_info; @@ -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; @@ -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)); } } From a6c0488a411d3bf9feed4ee379acaebde8c13120 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Sat, 17 Jun 2023 21:46:40 -0700 Subject: [PATCH 2/3] highp --- impeller/entity/shaders/rrect_blur.frag | 45 +++++++++++++------------ 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/impeller/entity/shaders/rrect_blur.frag b/impeller/entity/shaders/rrect_blur.frag index 8a12da3e42fad..d8bc90e14fee6 100644 --- a/impeller/entity/shaders/rrect_blur.frag +++ b/impeller/entity/shaders/rrect_blur.frag @@ -7,59 +7,60 @@ uniform FragInfo { f16vec4 color; - vec2 rect_size; - float blur_sigma; - float corner_radius; + highp vec2 rect_size; + highp float blur_sigma; + highp float corner_radius; } frag_info; -in vec2 v_position; +in highp vec2 v_position; out f16vec4 frag_color; const int kSampleCount = 4; -float16_t RRectDistance(vec2 sample_position, vec2 half_size) { - vec2 space = abs(sample_position) - half_size + frag_info.corner_radius; +float16_t RRectDistance(highp vec2 sample_position, highp vec2 half_size) { + highp 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). -float RRectBlurX(vec2 sample_position, vec2 half_size) { +highp float RRectBlurX(highp vec2 sample_position, highp vec2 half_size) { // Compute the X direction distance field (not incorporating the Y distance) // for the rounded rect. - float space = + highp float space = min(0.0, half_size.y - frag_info.corner_radius - abs(sample_position.y)); - float rrect_distance = + highp float rrect_distance = half_size.x - frag_info.corner_radius + sqrt(max(0.0, frag_info.corner_radius * frag_info.corner_radius - space * space)); // Map the linear distance field to the approximate Gaussian integral. - vec2 integral = IPVec2FastGaussianIntegral( - float(sample_position.x) + vec2(-rrect_distance, rrect_distance), - float(frag_info.blur_sigma)); + highp vec2 integral = IPVec2FastGaussianIntegral( + sample_position.x + vec2(-rrect_distance, rrect_distance), + frag_info.blur_sigma); return integral.y - integral.x; } -float RRectBlur(vec2 sample_position, vec2 half_size) { +highp float RRectBlur(highp vec2 sample_position, highp 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. - float half_sampling_range = frag_info.blur_sigma * 3.0; + highp float half_sampling_range = frag_info.blur_sigma * 3.0; - 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; + highp float begin_y = + max(-half_sampling_range, sample_position.y - half_size.y); + highp float end_y = min(half_sampling_range, sample_position.y + half_size.y); + highp float interval = (end_y - begin_y) / kSampleCount; // Sample the X blur kSampleCount times, weighted by the Gaussian function. - float result = 0.0; + highp float result = 0.0; for (int sample_i = 0; sample_i < kSampleCount; sample_i++) { - float y = begin_y + interval * (float(sample_i) + 0.5); + highp 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; + IPGaussian(y, frag_info.blur_sigma) * interval; } return result; @@ -68,8 +69,8 @@ float RRectBlur(vec2 sample_position, vec2 half_size) { void main() { frag_color = frag_info.color; - vec2 half_size = frag_info.rect_size * 0.5; - vec2 sample_position = v_position - half_size; + highp vec2 half_size = frag_info.rect_size * 0.5; + highp vec2 sample_position = v_position - half_size; if (frag_info.blur_sigma > 0.0) { frag_color *= float16_t(RRectBlur(sample_position, half_size)); From 6ac2ef4e47837981d1a608fcfc73551df44de0c4 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Sat, 17 Jun 2023 21:47:01 -0700 Subject: [PATCH 3/3] Revert "highp" This reverts commit a6c0488a411d3bf9feed4ee379acaebde8c13120. --- impeller/entity/shaders/rrect_blur.frag | 45 ++++++++++++------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/impeller/entity/shaders/rrect_blur.frag b/impeller/entity/shaders/rrect_blur.frag index d8bc90e14fee6..8a12da3e42fad 100644 --- a/impeller/entity/shaders/rrect_blur.frag +++ b/impeller/entity/shaders/rrect_blur.frag @@ -7,60 +7,59 @@ uniform FragInfo { f16vec4 color; - highp vec2 rect_size; - highp float blur_sigma; - highp float corner_radius; + vec2 rect_size; + float blur_sigma; + float corner_radius; } frag_info; -in highp vec2 v_position; +in vec2 v_position; out f16vec4 frag_color; const int kSampleCount = 4; -float16_t RRectDistance(highp vec2 sample_position, highp vec2 half_size) { - highp vec2 space = abs(sample_position) - half_size + 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). -highp float RRectBlurX(highp vec2 sample_position, highp vec2 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. - highp float space = + float space = min(0.0, half_size.y - frag_info.corner_radius - abs(sample_position.y)); - highp float rrect_distance = + float rrect_distance = half_size.x - frag_info.corner_radius + sqrt(max(0.0, frag_info.corner_radius * frag_info.corner_radius - space * space)); // Map the linear distance field to the approximate Gaussian integral. - highp vec2 integral = IPVec2FastGaussianIntegral( - sample_position.x + vec2(-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; } -highp float RRectBlur(highp vec2 sample_position, highp vec2 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. - highp float half_sampling_range = frag_info.blur_sigma * 3.0; + float half_sampling_range = frag_info.blur_sigma * 3.0; - highp float begin_y = - max(-half_sampling_range, sample_position.y - half_size.y); - highp float end_y = min(half_sampling_range, sample_position.y + half_size.y); - highp float interval = (end_y - begin_y) / 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. - highp float result = 0.0; + float result = 0.0; for (int sample_i = 0; sample_i < kSampleCount; sample_i++) { - highp float y = begin_y + interval * (float(sample_i) + 0.5); + float y = begin_y + interval * (float(sample_i) + 0.5); result += RRectBlurX(vec2(sample_position.x, sample_position.y - y), half_size) * - IPGaussian(y, frag_info.blur_sigma) * interval; + IPGaussian(float(y), float(frag_info.blur_sigma)) * interval; } return result; @@ -69,8 +68,8 @@ highp float RRectBlur(highp vec2 sample_position, highp vec2 half_size) { void main() { frag_color = frag_info.color; - highp vec2 half_size = frag_info.rect_size * 0.5; - highp vec2 sample_position = 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.0) { frag_color *= float16_t(RRectBlur(sample_position, half_size));