From d7f832b9d432da3a83c52cc3b9e85a2a9a50f055 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Wed, 3 Jan 2024 15:19:17 -0800 Subject: [PATCH 01/16] [Impeller] made the blur calculate coefficients on the cpu --- ...rectional_gaussian_blur_filter_contents.cc | 19 +++++----- .../filters/gaussian_blur_filter_contents.cc | 21 ++++++++-- .../filters/gaussian_blur_filter_contents.h | 11 ++++++ .../shaders/gaussian_blur/gaussian_blur.glsl | 38 ++++++------------- 4 files changed, 50 insertions(+), 39 deletions(-) diff --git a/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc index 5760d7ac250d2..31482f58ae39b 100644 --- a/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc @@ -21,6 +21,7 @@ #include "impeller/renderer/render_target.h" #include "impeller/renderer/sampler_library.h" #include "impeller/renderer/vertex_buffer_builder.h" +#include "impeller/entity/contents/filters/gaussian_blur_filter_contents.h" namespace impeller { @@ -173,16 +174,16 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( frame_info.texture_sampler_y_coord_scale = input_snapshot->texture->GetYCoordScale(); - FS::BlurInfo frag_info; auto r = Radius{transformed_blur_radius_length}; - frag_info.blur_sigma = Sigma{r}.sigma; - frag_info.blur_radius = std::round(r.radius); - frag_info.step_size = 2.0; - - // The blur direction is in input UV space. - frag_info.blur_uv_offset = - pass_transform.Invert().TransformDirection(Vector2(1, 0)).Normalize() / - Point(input_snapshot->GetCoverage().value().GetSize()); + FS::BlurInfo frag_info = GenerateBlurInfo( + {.blur_uv_offset = + pass_transform.Invert() + .TransformDirection(Vector2(1, 0)) + .Normalize() / + Point(input_snapshot->GetCoverage().value().GetSize()), + .blur_sigma = Sigma{r}.sigma, + .blur_radius = std::round(r.radius), + .step_size = 2.0}); Command cmd; DEBUG_COMMAND_INFO(cmd, SPrintF("Gaussian Blur Filter (Radius=%.2f)", diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 19aa2e46fa32b..49f13d023fb7f 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -120,7 +120,7 @@ fml::StatusOr MakeBlurSubpass( const RenderTarget& input_pass, const SamplerDescriptor& sampler_descriptor, Entity::TileMode tile_mode, - const GaussianBlurFragmentShader::BlurInfo& blur_info, + const BlurParameters& blur_info, std::optional destination_target, const Quad& blur_uvs) { if (blur_info.blur_sigma < kEhCloseEnough) { @@ -170,7 +170,7 @@ fml::StatusOr MakeBlurSubpass( GaussianBlurVertexShader::BindFrameInfo( cmd, host_buffer.EmplaceUniform(frame_info)); GaussianBlurFragmentShader::BindBlurInfo( - cmd, host_buffer.EmplaceUniform(blur_info)); + cmd, host_buffer.EmplaceUniform(GenerateBlurInfo(blur_info))); pass.AddCommand(std::move(cmd)); return true; @@ -346,7 +346,7 @@ std::optional GaussianBlurFilterContents::RenderFilter( fml::StatusOr pass2_out = MakeBlurSubpass(renderer, /*input_pass=*/pass1_out.value(), input_snapshot->sampler_descriptor, tile_mode_, - GaussianBlurFragmentShader::BlurInfo{ + BlurParameters{ .blur_uv_offset = Point(0.0, pass1_pixel_size.y), .blur_sigma = scaled_sigma.y * effective_scalar.y, .blur_radius = blur_radius.y * effective_scalar.y, @@ -367,7 +367,7 @@ std::optional GaussianBlurFilterContents::RenderFilter( fml::StatusOr pass3_out = MakeBlurSubpass(renderer, /*input_pass=*/pass2_out.value(), input_snapshot->sampler_descriptor, tile_mode_, - GaussianBlurFragmentShader::BlurInfo{ + BlurParameters{ .blur_uv_offset = Point(pass1_pixel_size.x, 0.0), .blur_sigma = scaled_sigma.x * effective_scalar.x, .blur_radius = blur_radius.x * effective_scalar.x, @@ -429,4 +429,17 @@ Scalar GaussianBlurFilterContents::ScaleSigma(Scalar sigma) { return clamped * scalar; } +GaussianBlurPipeline::FragmentShader::BlurInfo GenerateBlurInfo( + BlurParameters parameters) { + GaussianBlurPipeline::FragmentShader::BlurInfo result{ + .sample_count = 1, + .samples = {{ + .uv_offset = Point(), + .coefficient = 1.0f, + }}, + }; + + return result; +} + } // namespace impeller diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h index a139771b3f8b1..aa04dd32368e3 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h @@ -6,10 +6,21 @@ #define FLUTTER_IMPELLER_ENTITY_CONTENTS_FILTERS_GAUSSIAN_BLUR_FILTER_CONTENTS_H_ #include +#include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/filters/filter_contents.h" namespace impeller { +struct BlurParameters { + Point blur_uv_offset; + Scalar blur_sigma; + Scalar blur_radius; + Scalar step_size; +}; + +GaussianBlurPipeline::FragmentShader::BlurInfo GenerateBlurInfo( + BlurParameters parameters); + /// Performs a bidirectional Gaussian blur. /// /// This is accomplished by rendering multiple passes in multiple directions. diff --git a/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl b/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl index ebf135a482328..c466647aad6a4 100644 --- a/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl +++ b/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl @@ -20,16 +20,14 @@ uniform f16sampler2D texture_sampler; -uniform BlurInfo { - f16vec2 blur_uv_offset; +struct BlurSample { + f16vec2 uv_offset; + float16_t coefficient; +}; - // The blur sigma and radius have a linear relationship which is defined - // host-side, but both are useful controls here. Sigma (pixels per standard - // deviation) is used to define the gaussian function itself, whereas the - // radius is used to limit how much of the function is integrated. - float blur_sigma; - float16_t blur_radius; - float16_t step_size; +uniform BlurInfo { + int sample_count; + BlurSample samples[24]; } blur_info; @@ -49,24 +47,12 @@ void main() { f16vec4 total_color = f16vec4(0.0hf); float16_t gaussian_integral = 0.0hf; - // Step by 2.0 as a performance optimization, relying on bilinear filtering in - // the sampler to blend the texels. Typically the space between pixels is - // calculated so their blended amounts match the gaussian coefficients. This - // just uses 0.5 as an optimization until the gaussian coefficients are - // calculated and passed in from the cpu. - for (float16_t i = -blur_info.blur_radius; i <= blur_info.blur_radius; - i += blur_info.step_size) { - // Use the 32 bit Gaussian function because the 16 bit variation results in - // quality loss/visible banding. Also, 16 bit variation internally breaks - // down at a moderately high (but still reasonable) blur sigma of >255 when - // computing sigma^2 due to the exponent only having 5 bits. - float16_t gaussian = float16_t(IPGaussian(float(i), blur_info.blur_sigma)); - gaussian_integral += gaussian; + for (int i = 0; i < blur_info.sample_count; ++i) { + float16_t coefficient = blur_info.samples[i].coefficient; + gaussian_integral += coefficient; total_color += - gaussian * Sample(texture_sampler, // sampler - v_texture_coords + blur_info.blur_uv_offset * - i // texture coordinates - ); + coefficient * Sample(texture_sampler, + v_texture_coords + blur_info.samples[i].uv_offset); } frag_color = total_color / gaussian_integral; From 7820590b1fe17ab2712cd02b31f8f24e10efea93 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Wed, 3 Jan 2024 15:42:20 -0800 Subject: [PATCH 02/16] started generating the coefficients --- ...rectional_gaussian_blur_filter_contents.cc | 4 +- .../filters/gaussian_blur_filter_contents.cc | 61 +++++++++++-------- .../filters/gaussian_blur_filter_contents.h | 4 +- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc index 31482f58ae39b..894fedba054a7 100644 --- a/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc @@ -182,8 +182,8 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( .Normalize() / Point(input_snapshot->GetCoverage().value().GetSize()), .blur_sigma = Sigma{r}.sigma, - .blur_radius = std::round(r.radius), - .step_size = 2.0}); + .blur_radius = static_cast(std::round(r.radius)), + .step_size = 2}); Command cmd; DEBUG_COMMAND_INFO(cmd, SPrintF("Gaussian Blur Filter (Radius=%.2f)", diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 49f13d023fb7f..a55b2c349db3e 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -343,16 +343,17 @@ std::optional GaussianBlurFilterContents::RenderFilter( } } - fml::StatusOr pass2_out = - MakeBlurSubpass(renderer, /*input_pass=*/pass1_out.value(), - input_snapshot->sampler_descriptor, tile_mode_, - BlurParameters{ - .blur_uv_offset = Point(0.0, pass1_pixel_size.y), - .blur_sigma = scaled_sigma.y * effective_scalar.y, - .blur_radius = blur_radius.y * effective_scalar.y, - .step_size = 1.0, - }, - /*destination_target=*/std::nullopt, blur_uvs); + fml::StatusOr pass2_out = MakeBlurSubpass( + renderer, /*input_pass=*/pass1_out.value(), + input_snapshot->sampler_descriptor, tile_mode_, + BlurParameters{ + .blur_uv_offset = Point(0.0, pass1_pixel_size.y), + .blur_sigma = scaled_sigma.y * effective_scalar.y, + .blur_radius = + static_cast(std::round(blur_radius.y * effective_scalar.y)), + .step_size = 1, + }, + /*destination_target=*/std::nullopt, blur_uvs); if (!pass2_out.ok()) { return std::nullopt; @@ -364,16 +365,17 @@ std::optional GaussianBlurFilterContents::RenderFilter( ? std::optional(pass1_out.value()) : std::optional(std::nullopt); - fml::StatusOr pass3_out = - MakeBlurSubpass(renderer, /*input_pass=*/pass2_out.value(), - input_snapshot->sampler_descriptor, tile_mode_, - BlurParameters{ - .blur_uv_offset = Point(pass1_pixel_size.x, 0.0), - .blur_sigma = scaled_sigma.x * effective_scalar.x, - .blur_radius = blur_radius.x * effective_scalar.x, - .step_size = 1.0, - }, - pass3_destination, blur_uvs); + fml::StatusOr pass3_out = MakeBlurSubpass( + renderer, /*input_pass=*/pass2_out.value(), + input_snapshot->sampler_descriptor, tile_mode_, + BlurParameters{ + .blur_uv_offset = Point(pass1_pixel_size.x, 0.0), + .blur_sigma = scaled_sigma.x * effective_scalar.x, + .blur_radius = + static_cast(std::round(blur_radius.x * effective_scalar.x)), + .step_size = 1, + }, + pass3_destination, blur_uvs); if (!pass3_out.ok()) { return std::nullopt; @@ -432,12 +434,19 @@ Scalar GaussianBlurFilterContents::ScaleSigma(Scalar sigma) { GaussianBlurPipeline::FragmentShader::BlurInfo GenerateBlurInfo( BlurParameters parameters) { GaussianBlurPipeline::FragmentShader::BlurInfo result{ - .sample_count = 1, - .samples = {{ - .uv_offset = Point(), - .coefficient = 1.0f, - }}, - }; + .sample_count = + ((2 * parameters.blur_radius) / parameters.step_size) + 1}; + FML_CHECK(result.sample_count < 24); + + for (int i = 0; i < result.sample_count; i += parameters.step_size) { + int x = i - parameters.blur_radius; + result.samples[i] = { + .uv_offset = parameters.blur_uv_offset * x, + .coefficient = expf(-0.5f * (x * x) / + (parameters.blur_sigma * parameters.blur_sigma)) / + (sqrtf(2.0f * M_PI) * parameters.blur_sigma), + }; + } return result; } diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h index aa04dd32368e3..1c1b355a16a4a 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h @@ -14,8 +14,8 @@ namespace impeller { struct BlurParameters { Point blur_uv_offset; Scalar blur_sigma; - Scalar blur_radius; - Scalar step_size; + int blur_radius; + int step_size; }; GaussianBlurPipeline::FragmentShader::BlurInfo GenerateBlurInfo( From c737791676329fc500ee60fe7ba6dcf3b8f1496d Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Wed, 3 Jan 2024 15:42:50 -0800 Subject: [PATCH 03/16] format --- ...rectional_gaussian_blur_filter_contents.cc | 163 +++++++++--------- 1 file changed, 82 insertions(+), 81 deletions(-) diff --git a/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc index 894fedba054a7..51cfb5448a04f 100644 --- a/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc @@ -14,6 +14,7 @@ #include "impeller/core/sampler_descriptor.h" #include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/filters/filter_contents.h" +#include "impeller/entity/contents/filters/gaussian_blur_filter_contents.h" #include "impeller/geometry/rect.h" #include "impeller/geometry/scalar.h" #include "impeller/renderer/command_buffer.h" @@ -21,7 +22,6 @@ #include "impeller/renderer/render_target.h" #include "impeller/renderer/sampler_library.h" #include "impeller/renderer/vertex_buffer_builder.h" -#include "impeller/entity/contents/filters/gaussian_blur_filter_contents.h" namespace impeller { @@ -156,87 +156,88 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( /// Render to texture. /// - ContentContext::SubpassCallback subpass_callback = [&](const ContentContext& - renderer, - RenderPass& pass) { - auto& host_buffer = pass.GetTransientsBuffer(); - - VertexBufferBuilder vtx_builder; - vtx_builder.AddVertices({ - {Point(0, 0), input_uvs[0]}, - {Point(1, 0), input_uvs[1]}, - {Point(0, 1), input_uvs[2]}, - {Point(1, 1), input_uvs[3]}, - }); - - VS::FrameInfo frame_info; - frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); - frame_info.texture_sampler_y_coord_scale = - input_snapshot->texture->GetYCoordScale(); - - auto r = Radius{transformed_blur_radius_length}; - FS::BlurInfo frag_info = GenerateBlurInfo( - {.blur_uv_offset = - pass_transform.Invert() - .TransformDirection(Vector2(1, 0)) - .Normalize() / - Point(input_snapshot->GetCoverage().value().GetSize()), - .blur_sigma = Sigma{r}.sigma, - .blur_radius = static_cast(std::round(r.radius)), - .step_size = 2}); - - Command cmd; - DEBUG_COMMAND_INFO(cmd, SPrintF("Gaussian Blur Filter (Radius=%.2f)", - transformed_blur_radius_length)); - cmd.BindVertices(vtx_builder.CreateVertexBuffer(host_buffer)); - - auto options = OptionsFromPass(pass); - options.primitive_type = PrimitiveType::kTriangleStrip; - options.blend_mode = BlendMode::kSource; - auto input_descriptor = input_snapshot->sampler_descriptor; - switch (tile_mode_) { - case Entity::TileMode::kDecal: - if (renderer.GetDeviceCapabilities() - .SupportsDecalSamplerAddressMode()) { - input_descriptor.width_address_mode = SamplerAddressMode::kDecal; - input_descriptor.height_address_mode = SamplerAddressMode::kDecal; + ContentContext::SubpassCallback subpass_callback = + [&](const ContentContext& renderer, RenderPass& pass) { + auto& host_buffer = pass.GetTransientsBuffer(); + + VertexBufferBuilder vtx_builder; + vtx_builder.AddVertices({ + {Point(0, 0), input_uvs[0]}, + {Point(1, 0), input_uvs[1]}, + {Point(0, 1), input_uvs[2]}, + {Point(1, 1), input_uvs[3]}, + }); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); + frame_info.texture_sampler_y_coord_scale = + input_snapshot->texture->GetYCoordScale(); + + auto r = Radius{transformed_blur_radius_length}; + FS::BlurInfo frag_info = GenerateBlurInfo( + {.blur_uv_offset = + pass_transform.Invert() + .TransformDirection(Vector2(1, 0)) + .Normalize() / + Point(input_snapshot->GetCoverage().value().GetSize()), + .blur_sigma = Sigma{r}.sigma, + .blur_radius = static_cast(std::round(r.radius)), + .step_size = 2}); + + Command cmd; + DEBUG_COMMAND_INFO(cmd, SPrintF("Gaussian Blur Filter (Radius=%.2f)", + transformed_blur_radius_length)); + cmd.BindVertices(vtx_builder.CreateVertexBuffer(host_buffer)); + + auto options = OptionsFromPass(pass); + options.primitive_type = PrimitiveType::kTriangleStrip; + options.blend_mode = BlendMode::kSource; + auto input_descriptor = input_snapshot->sampler_descriptor; + switch (tile_mode_) { + case Entity::TileMode::kDecal: + if (renderer.GetDeviceCapabilities() + .SupportsDecalSamplerAddressMode()) { + input_descriptor.width_address_mode = SamplerAddressMode::kDecal; + input_descriptor.height_address_mode = SamplerAddressMode::kDecal; + } + break; + case Entity::TileMode::kClamp: + input_descriptor.width_address_mode = + SamplerAddressMode::kClampToEdge; + input_descriptor.height_address_mode = + SamplerAddressMode::kClampToEdge; + break; + case Entity::TileMode::kMirror: + input_descriptor.width_address_mode = SamplerAddressMode::kMirror; + input_descriptor.height_address_mode = SamplerAddressMode::kMirror; + break; + case Entity::TileMode::kRepeat: + input_descriptor.width_address_mode = SamplerAddressMode::kRepeat; + input_descriptor.height_address_mode = SamplerAddressMode::kRepeat; + break; } - break; - case Entity::TileMode::kClamp: - input_descriptor.width_address_mode = SamplerAddressMode::kClampToEdge; - input_descriptor.height_address_mode = SamplerAddressMode::kClampToEdge; - break; - case Entity::TileMode::kMirror: - input_descriptor.width_address_mode = SamplerAddressMode::kMirror; - input_descriptor.height_address_mode = SamplerAddressMode::kMirror; - break; - case Entity::TileMode::kRepeat: - input_descriptor.width_address_mode = SamplerAddressMode::kRepeat; - input_descriptor.height_address_mode = SamplerAddressMode::kRepeat; - break; - } - input_descriptor.mag_filter = MinMagFilter::kLinear; - input_descriptor.min_filter = MinMagFilter::kLinear; - - bool has_decal_specialization = - tile_mode_ == Entity::TileMode::kDecal && - !renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode(); - - if (has_decal_specialization) { - cmd.pipeline = renderer.GetGaussianBlurDecalPipeline(options); - } else { - cmd.pipeline = renderer.GetGaussianBlurPipeline(options); - } - - FS::BindTextureSampler( - cmd, input_snapshot->texture, - renderer.GetContext()->GetSamplerLibrary()->GetSampler( - input_descriptor)); - VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); - FS::BindBlurInfo(cmd, host_buffer.EmplaceUniform(frag_info)); - - return pass.AddCommand(std::move(cmd)); - }; + input_descriptor.mag_filter = MinMagFilter::kLinear; + input_descriptor.min_filter = MinMagFilter::kLinear; + + bool has_decal_specialization = + tile_mode_ == Entity::TileMode::kDecal && + !renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode(); + + if (has_decal_specialization) { + cmd.pipeline = renderer.GetGaussianBlurDecalPipeline(options); + } else { + cmd.pipeline = renderer.GetGaussianBlurPipeline(options); + } + + FS::BindTextureSampler( + cmd, input_snapshot->texture, + renderer.GetContext()->GetSamplerLibrary()->GetSampler( + input_descriptor)); + VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); + FS::BindBlurInfo(cmd, host_buffer.EmplaceUniform(frag_info)); + + return pass.AddCommand(std::move(cmd)); + }; Vector2 scale; auto scale_curve = [](Scalar radius) { From e0726f540f8714cac8ec66361702aae5e3d36891 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 4 Jan 2024 09:10:45 -0800 Subject: [PATCH 04/16] moved normalization to cpu --- .../contents/filters/gaussian_blur_filter_contents.cc | 7 +++++++ impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl | 4 +--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index a55b2c349db3e..dfbe1d631d68e 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -438,6 +438,7 @@ GaussianBlurPipeline::FragmentShader::BlurInfo GenerateBlurInfo( ((2 * parameters.blur_radius) / parameters.step_size) + 1}; FML_CHECK(result.sample_count < 24); + Scalar tally = 0.0f; for (int i = 0; i < result.sample_count; i += parameters.step_size) { int x = i - parameters.blur_radius; result.samples[i] = { @@ -446,6 +447,12 @@ GaussianBlurPipeline::FragmentShader::BlurInfo GenerateBlurInfo( (parameters.blur_sigma * parameters.blur_sigma)) / (sqrtf(2.0f * M_PI) * parameters.blur_sigma), }; + tally += result.samples[i].coefficient; + } + + // Make sure everything adds up to 1. + for (auto& sample : result.samples) { + sample.coefficient /= tally; } return result; diff --git a/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl b/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl index c466647aad6a4..c53c151bf99aa 100644 --- a/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl +++ b/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl @@ -45,15 +45,13 @@ out f16vec4 frag_color; void main() { f16vec4 total_color = f16vec4(0.0hf); - float16_t gaussian_integral = 0.0hf; for (int i = 0; i < blur_info.sample_count; ++i) { float16_t coefficient = blur_info.samples[i].coefficient; - gaussian_integral += coefficient; total_color += coefficient * Sample(texture_sampler, v_texture_coords + blur_info.samples[i].uv_offset); } - frag_color = total_color / gaussian_integral; + frag_color = total_color; } From 88d0f96d17d0e0707dcd79070f8b6b27de665d05 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 4 Jan 2024 09:14:07 -0800 Subject: [PATCH 05/16] fixed step --- .../entity/contents/filters/gaussian_blur_filter_contents.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index dfbe1d631d68e..dfa96a62578c6 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -439,8 +439,8 @@ GaussianBlurPipeline::FragmentShader::BlurInfo GenerateBlurInfo( FML_CHECK(result.sample_count < 24); Scalar tally = 0.0f; - for (int i = 0; i < result.sample_count; i += parameters.step_size) { - int x = i - parameters.blur_radius; + for (int i = 0; i < result.sample_count; ++i) { + int x = (i * parameters.step_size) - parameters.blur_radius; result.samples[i] = { .uv_offset = parameters.blur_uv_offset * x, .coefficient = expf(-0.5f * (x * x) / From 1b3305b3f80cadb7d0c5052c8401e47993ee9e0b Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 4 Jan 2024 09:21:32 -0800 Subject: [PATCH 06/16] renamed variable to be kernel specific --- ...directional_gaussian_blur_filter_contents.cc | 4 ++-- .../filters/gaussian_blur_filter_contents.cc | 6 +++--- .../filters/gaussian_blur_filter_contents.h | 2 +- .../shaders/gaussian_blur/gaussian_blur.glsl | 17 +++-------------- 4 files changed, 9 insertions(+), 20 deletions(-) diff --git a/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc index 51cfb5448a04f..108521d6d4a46 100644 --- a/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc @@ -174,7 +174,7 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( input_snapshot->texture->GetYCoordScale(); auto r = Radius{transformed_blur_radius_length}; - FS::BlurInfo frag_info = GenerateBlurInfo( + FS::KernelSamples frag_info = GenerateBlurInfo( {.blur_uv_offset = pass_transform.Invert() .TransformDirection(Vector2(1, 0)) @@ -234,7 +234,7 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( renderer.GetContext()->GetSamplerLibrary()->GetSampler( input_descriptor)); VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); - FS::BindBlurInfo(cmd, host_buffer.EmplaceUniform(frag_info)); + FS::BindKernelSamples(cmd, host_buffer.EmplaceUniform(frag_info)); return pass.AddCommand(std::move(cmd)); }; diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index dfa96a62578c6..bb5ee9cb58b6d 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -169,7 +169,7 @@ fml::StatusOr MakeBlurSubpass( linear_sampler_descriptor)); GaussianBlurVertexShader::BindFrameInfo( cmd, host_buffer.EmplaceUniform(frame_info)); - GaussianBlurFragmentShader::BindBlurInfo( + GaussianBlurFragmentShader::BindKernelSamples( cmd, host_buffer.EmplaceUniform(GenerateBlurInfo(blur_info))); pass.AddCommand(std::move(cmd)); @@ -431,9 +431,9 @@ Scalar GaussianBlurFilterContents::ScaleSigma(Scalar sigma) { return clamped * scalar; } -GaussianBlurPipeline::FragmentShader::BlurInfo GenerateBlurInfo( +GaussianBlurPipeline::FragmentShader::KernelSamples GenerateBlurInfo( BlurParameters parameters) { - GaussianBlurPipeline::FragmentShader::BlurInfo result{ + GaussianBlurPipeline::FragmentShader::KernelSamples result{ .sample_count = ((2 * parameters.blur_radius) / parameters.step_size) + 1}; FML_CHECK(result.sample_count < 24); diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h index 1c1b355a16a4a..9d69edafcc004 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h @@ -18,7 +18,7 @@ struct BlurParameters { int step_size; }; -GaussianBlurPipeline::FragmentShader::BlurInfo GenerateBlurInfo( +GaussianBlurPipeline::FragmentShader::KernelSamples GenerateBlurInfo( BlurParameters parameters); /// Performs a bidirectional Gaussian blur. diff --git a/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl b/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl index c53c151bf99aa..ecc631edb2834 100644 --- a/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl +++ b/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl @@ -2,17 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// 1D (directional) gaussian blur. -// -// Paths for future optimization: -// * Remove the uv bounds multiplier in SampleColor by adding optional -// support for SamplerAddressMode::ClampToBorder in the texture sampler. -// * Render both blur passes into a smaller texture than the source image -// (~1/radius size). -// * If doing the small texture render optimization, cache misses can be -// reduced in the first pass by sampling the source textures with a mip -// level of log2(min_radius). - #include #include #include @@ -20,14 +9,14 @@ uniform f16sampler2D texture_sampler; -struct BlurSample { +struct KernelSample { f16vec2 uv_offset; float16_t coefficient; }; -uniform BlurInfo { +uniform KernelSamples { int sample_count; - BlurSample samples[24]; + KernelSample samples[24]; } blur_info; From 337bd13100663dfcbcc99639d09af97d135fd628 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 4 Jan 2024 09:37:12 -0800 Subject: [PATCH 07/16] added new kernel shader --- impeller/entity/BUILD.gn | 2 + impeller/entity/contents/content_context.h | 8 ++++ ...rectional_gaussian_blur_filter_contents.cc | 4 +- .../filters/gaussian_blur_filter_contents.cc | 8 ++-- .../filters/gaussian_blur_filter_contents.h | 2 +- .../entity/shaders/gaussian_blur/kernel.glsl | 46 +++++++++++++++++++ .../shaders/gaussian_blur/kernel_decal.frag | 9 ++++ .../shaders/gaussian_blur/kernel_nodecal.frag | 9 ++++ 8 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 impeller/entity/shaders/gaussian_blur/kernel.glsl create mode 100644 impeller/entity/shaders/gaussian_blur/kernel_decal.frag create mode 100644 impeller/entity/shaders/gaussian_blur/kernel_nodecal.frag diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index f324e6a1fa133..62b671444db02 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -28,6 +28,8 @@ impeller_shaders("entity_shaders") { "shaders/gaussian_blur/gaussian_blur.vert", "shaders/gaussian_blur/gaussian_blur_noalpha_decal.frag", "shaders/gaussian_blur/gaussian_blur_noalpha_nodecal.frag", + "shaders/gaussian_blur/kernel_decal.frag", + "shaders/gaussian_blur/kernel_nodecal.frag", "shaders/glyph_atlas.frag", "shaders/glyph_atlas_color.frag", "shaders/glyph_atlas.vert", diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 98dc447f009fb..6f0236b4a9497 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -67,6 +67,8 @@ #include "impeller/entity/gaussian_blur.vert.h" #include "impeller/entity/gaussian_blur_noalpha_decal.frag.h" #include "impeller/entity/gaussian_blur_noalpha_nodecal.frag.h" +#include "impeller/entity/kernel_decal.frag.h" +#include "impeller/entity/kernel_nodecal.frag.h" #include "impeller/entity/position_color.vert.h" @@ -137,6 +139,12 @@ using GaussianBlurDecalPipeline = using GaussianBlurPipeline = RenderPipelineT; +using KernelDecalPipeline = + RenderPipelineT; +using KernelPipeline = + RenderPipelineT; using BorderMaskBlurPipeline = RenderPipelineT; using MorphologyFilterPipeline = diff --git a/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc index 108521d6d4a46..09aec045b1ba2 100644 --- a/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc @@ -77,8 +77,8 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( const Matrix& effect_transform, const Rect& coverage, const std::optional& coverage_hint) const { - using VS = GaussianBlurPipeline::VertexShader; - using FS = GaussianBlurPipeline::FragmentShader; + using VS = KernelPipeline::VertexShader; + using FS = KernelPipeline::FragmentShader; //---------------------------------------------------------------------------- /// Handle inputs. diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index bb5ee9cb58b6d..4004622a64d97 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -14,8 +14,8 @@ namespace impeller { -using GaussianBlurVertexShader = GaussianBlurPipeline::VertexShader; -using GaussianBlurFragmentShader = GaussianBlurPipeline::FragmentShader; +using GaussianBlurVertexShader = KernelPipeline::VertexShader; +using GaussianBlurFragmentShader = KernelPipeline::FragmentShader; namespace { @@ -431,9 +431,9 @@ Scalar GaussianBlurFilterContents::ScaleSigma(Scalar sigma) { return clamped * scalar; } -GaussianBlurPipeline::FragmentShader::KernelSamples GenerateBlurInfo( +KernelPipeline::FragmentShader::KernelSamples GenerateBlurInfo( BlurParameters parameters) { - GaussianBlurPipeline::FragmentShader::KernelSamples result{ + KernelPipeline::FragmentShader::KernelSamples result{ .sample_count = ((2 * parameters.blur_radius) / parameters.step_size) + 1}; FML_CHECK(result.sample_count < 24); diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h index 9d69edafcc004..1bb594f3e4ae6 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h @@ -18,7 +18,7 @@ struct BlurParameters { int step_size; }; -GaussianBlurPipeline::FragmentShader::KernelSamples GenerateBlurInfo( +KernelPipeline::FragmentShader::KernelSamples GenerateBlurInfo( BlurParameters parameters); /// Performs a bidirectional Gaussian blur. diff --git a/impeller/entity/shaders/gaussian_blur/kernel.glsl b/impeller/entity/shaders/gaussian_blur/kernel.glsl new file mode 100644 index 0000000000000..ecc631edb2834 --- /dev/null +++ b/impeller/entity/shaders/gaussian_blur/kernel.glsl @@ -0,0 +1,46 @@ +// 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. + +#include +#include +#include +#include + +uniform f16sampler2D texture_sampler; + +struct KernelSample { + f16vec2 uv_offset; + float16_t coefficient; +}; + +uniform KernelSamples { + int sample_count; + KernelSample samples[24]; +} +blur_info; + +f16vec4 Sample(f16sampler2D tex, vec2 coords) { +#if ENABLE_DECAL_SPECIALIZATION + return IPHalfSampleDecal(tex, coords); +#else + return texture(tex, coords); +#endif +} + +in vec2 v_texture_coords; + +out f16vec4 frag_color; + +void main() { + f16vec4 total_color = f16vec4(0.0hf); + + for (int i = 0; i < blur_info.sample_count; ++i) { + float16_t coefficient = blur_info.samples[i].coefficient; + total_color += + coefficient * Sample(texture_sampler, + v_texture_coords + blur_info.samples[i].uv_offset); + } + + frag_color = total_color; +} diff --git a/impeller/entity/shaders/gaussian_blur/kernel_decal.frag b/impeller/entity/shaders/gaussian_blur/kernel_decal.frag new file mode 100644 index 0000000000000..114ee133fd068 --- /dev/null +++ b/impeller/entity/shaders/gaussian_blur/kernel_decal.frag @@ -0,0 +1,9 @@ +// 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. + +precision mediump float; + +#define ENABLE_DECAL_SPECIALIZATION 1 + +#include "kernel.glsl" diff --git a/impeller/entity/shaders/gaussian_blur/kernel_nodecal.frag b/impeller/entity/shaders/gaussian_blur/kernel_nodecal.frag new file mode 100644 index 0000000000000..ee87a79d00823 --- /dev/null +++ b/impeller/entity/shaders/gaussian_blur/kernel_nodecal.frag @@ -0,0 +1,9 @@ +// 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. + +precision mediump float; + +#define ENABLE_DECAL_SPECIALIZATION 0 + +#include "kernel.glsl" From 641108e09709ee4cf6122833112a35cc65948ec3 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 4 Jan 2024 09:44:25 -0800 Subject: [PATCH 08/16] fix content context --- impeller/entity/contents/content_context.cc | 2 ++ impeller/entity/contents/content_context.h | 18 ++++++++++++++---- .../filters/gaussian_blur_filter_contents.cc | 4 ++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 886bc54e95225..606420b0ece98 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -336,6 +336,8 @@ ContentContext::ContentContext( options_trianglestrip); gaussian_blur_noalpha_nodecal_pipelines_.CreateDefault(*context_, options_trianglestrip); + kernel_decal_pipelines_.CreateDefault(*context_, options_trianglestrip); + kernel_nodecal_pipelines_.CreateDefault(*context_, options_trianglestrip); border_mask_blur_pipelines_.CreateDefault(*context_, options_trianglestrip); morphology_filter_pipelines_.CreateDefault(*context_, options_trianglestrip, {supports_decal}); diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 6f0236b4a9497..d8217da6d5e35 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -140,11 +140,9 @@ using GaussianBlurPipeline = RenderPipelineT; using KernelDecalPipeline = - RenderPipelineT; + RenderPipelineT; using KernelPipeline = - RenderPipelineT; + RenderPipelineT; using BorderMaskBlurPipeline = RenderPipelineT; using MorphologyFilterPipeline = @@ -455,6 +453,16 @@ class ContentContext { return GetPipeline(gaussian_blur_noalpha_nodecal_pipelines_, opts); } + std::shared_ptr> GetKernelDecalPipeline( + ContentContextOptions opts) const { + return GetPipeline(kernel_decal_pipelines_, opts); + } + + std::shared_ptr> GetKernelPipeline( + ContentContextOptions opts) const { + return GetPipeline(kernel_nodecal_pipelines_, opts); + } + std::shared_ptr> GetBorderMaskBlurPipeline( ContentContextOptions opts) const { return GetPipeline(border_mask_blur_pipelines_, opts); @@ -821,6 +829,8 @@ class ContentContext { gaussian_blur_noalpha_decal_pipelines_; mutable Variants gaussian_blur_noalpha_nodecal_pipelines_; + mutable Variants kernel_decal_pipelines_; + mutable Variants kernel_nodecal_pipelines_; mutable Variants border_mask_blur_pipelines_; mutable Variants morphology_filter_pipelines_; mutable Variants diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 4004622a64d97..d1f1d044cb5e6 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -147,9 +147,9 @@ fml::StatusOr MakeBlurSubpass( if (tile_mode == Entity::TileMode::kDecal && !renderer.GetDeviceCapabilities() .SupportsDecalSamplerAddressMode()) { - cmd.pipeline = renderer.GetGaussianBlurDecalPipeline(options); + cmd.pipeline = renderer.GetKernelDecalPipeline(options); } else { - cmd.pipeline = renderer.GetGaussianBlurPipeline(options); + cmd.pipeline = renderer.GetKernelPipeline(options); } BindVertices(cmd, host_buffer, From de76bf1bb8ac5cbd6a3f9f0e081c5cb2dd13e96d Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 4 Jan 2024 09:48:33 -0800 Subject: [PATCH 09/16] moved the old blur back to the old shader --- ...rectional_gaussian_blur_filter_contents.cc | 166 +++++++++--------- .../shaders/gaussian_blur/gaussian_blur.glsl | 51 ++++-- 2 files changed, 121 insertions(+), 96 deletions(-) diff --git a/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc index 09aec045b1ba2..5760d7ac250d2 100644 --- a/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc @@ -14,7 +14,6 @@ #include "impeller/core/sampler_descriptor.h" #include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/filters/filter_contents.h" -#include "impeller/entity/contents/filters/gaussian_blur_filter_contents.h" #include "impeller/geometry/rect.h" #include "impeller/geometry/scalar.h" #include "impeller/renderer/command_buffer.h" @@ -77,8 +76,8 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( const Matrix& effect_transform, const Rect& coverage, const std::optional& coverage_hint) const { - using VS = KernelPipeline::VertexShader; - using FS = KernelPipeline::FragmentShader; + using VS = GaussianBlurPipeline::VertexShader; + using FS = GaussianBlurPipeline::FragmentShader; //---------------------------------------------------------------------------- /// Handle inputs. @@ -156,88 +155,87 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( /// Render to texture. /// - ContentContext::SubpassCallback subpass_callback = - [&](const ContentContext& renderer, RenderPass& pass) { - auto& host_buffer = pass.GetTransientsBuffer(); - - VertexBufferBuilder vtx_builder; - vtx_builder.AddVertices({ - {Point(0, 0), input_uvs[0]}, - {Point(1, 0), input_uvs[1]}, - {Point(0, 1), input_uvs[2]}, - {Point(1, 1), input_uvs[3]}, - }); - - VS::FrameInfo frame_info; - frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); - frame_info.texture_sampler_y_coord_scale = - input_snapshot->texture->GetYCoordScale(); - - auto r = Radius{transformed_blur_radius_length}; - FS::KernelSamples frag_info = GenerateBlurInfo( - {.blur_uv_offset = - pass_transform.Invert() - .TransformDirection(Vector2(1, 0)) - .Normalize() / - Point(input_snapshot->GetCoverage().value().GetSize()), - .blur_sigma = Sigma{r}.sigma, - .blur_radius = static_cast(std::round(r.radius)), - .step_size = 2}); - - Command cmd; - DEBUG_COMMAND_INFO(cmd, SPrintF("Gaussian Blur Filter (Radius=%.2f)", - transformed_blur_radius_length)); - cmd.BindVertices(vtx_builder.CreateVertexBuffer(host_buffer)); - - auto options = OptionsFromPass(pass); - options.primitive_type = PrimitiveType::kTriangleStrip; - options.blend_mode = BlendMode::kSource; - auto input_descriptor = input_snapshot->sampler_descriptor; - switch (tile_mode_) { - case Entity::TileMode::kDecal: - if (renderer.GetDeviceCapabilities() - .SupportsDecalSamplerAddressMode()) { - input_descriptor.width_address_mode = SamplerAddressMode::kDecal; - input_descriptor.height_address_mode = SamplerAddressMode::kDecal; - } - break; - case Entity::TileMode::kClamp: - input_descriptor.width_address_mode = - SamplerAddressMode::kClampToEdge; - input_descriptor.height_address_mode = - SamplerAddressMode::kClampToEdge; - break; - case Entity::TileMode::kMirror: - input_descriptor.width_address_mode = SamplerAddressMode::kMirror; - input_descriptor.height_address_mode = SamplerAddressMode::kMirror; - break; - case Entity::TileMode::kRepeat: - input_descriptor.width_address_mode = SamplerAddressMode::kRepeat; - input_descriptor.height_address_mode = SamplerAddressMode::kRepeat; - break; + ContentContext::SubpassCallback subpass_callback = [&](const ContentContext& + renderer, + RenderPass& pass) { + auto& host_buffer = pass.GetTransientsBuffer(); + + VertexBufferBuilder vtx_builder; + vtx_builder.AddVertices({ + {Point(0, 0), input_uvs[0]}, + {Point(1, 0), input_uvs[1]}, + {Point(0, 1), input_uvs[2]}, + {Point(1, 1), input_uvs[3]}, + }); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); + frame_info.texture_sampler_y_coord_scale = + input_snapshot->texture->GetYCoordScale(); + + FS::BlurInfo frag_info; + auto r = Radius{transformed_blur_radius_length}; + frag_info.blur_sigma = Sigma{r}.sigma; + frag_info.blur_radius = std::round(r.radius); + frag_info.step_size = 2.0; + + // The blur direction is in input UV space. + frag_info.blur_uv_offset = + pass_transform.Invert().TransformDirection(Vector2(1, 0)).Normalize() / + Point(input_snapshot->GetCoverage().value().GetSize()); + + Command cmd; + DEBUG_COMMAND_INFO(cmd, SPrintF("Gaussian Blur Filter (Radius=%.2f)", + transformed_blur_radius_length)); + cmd.BindVertices(vtx_builder.CreateVertexBuffer(host_buffer)); + + auto options = OptionsFromPass(pass); + options.primitive_type = PrimitiveType::kTriangleStrip; + options.blend_mode = BlendMode::kSource; + auto input_descriptor = input_snapshot->sampler_descriptor; + switch (tile_mode_) { + case Entity::TileMode::kDecal: + if (renderer.GetDeviceCapabilities() + .SupportsDecalSamplerAddressMode()) { + input_descriptor.width_address_mode = SamplerAddressMode::kDecal; + input_descriptor.height_address_mode = SamplerAddressMode::kDecal; } - input_descriptor.mag_filter = MinMagFilter::kLinear; - input_descriptor.min_filter = MinMagFilter::kLinear; - - bool has_decal_specialization = - tile_mode_ == Entity::TileMode::kDecal && - !renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode(); - - if (has_decal_specialization) { - cmd.pipeline = renderer.GetGaussianBlurDecalPipeline(options); - } else { - cmd.pipeline = renderer.GetGaussianBlurPipeline(options); - } - - FS::BindTextureSampler( - cmd, input_snapshot->texture, - renderer.GetContext()->GetSamplerLibrary()->GetSampler( - input_descriptor)); - VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); - FS::BindKernelSamples(cmd, host_buffer.EmplaceUniform(frag_info)); - - return pass.AddCommand(std::move(cmd)); - }; + break; + case Entity::TileMode::kClamp: + input_descriptor.width_address_mode = SamplerAddressMode::kClampToEdge; + input_descriptor.height_address_mode = SamplerAddressMode::kClampToEdge; + break; + case Entity::TileMode::kMirror: + input_descriptor.width_address_mode = SamplerAddressMode::kMirror; + input_descriptor.height_address_mode = SamplerAddressMode::kMirror; + break; + case Entity::TileMode::kRepeat: + input_descriptor.width_address_mode = SamplerAddressMode::kRepeat; + input_descriptor.height_address_mode = SamplerAddressMode::kRepeat; + break; + } + input_descriptor.mag_filter = MinMagFilter::kLinear; + input_descriptor.min_filter = MinMagFilter::kLinear; + + bool has_decal_specialization = + tile_mode_ == Entity::TileMode::kDecal && + !renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode(); + + if (has_decal_specialization) { + cmd.pipeline = renderer.GetGaussianBlurDecalPipeline(options); + } else { + cmd.pipeline = renderer.GetGaussianBlurPipeline(options); + } + + FS::BindTextureSampler( + cmd, input_snapshot->texture, + renderer.GetContext()->GetSamplerLibrary()->GetSampler( + input_descriptor)); + VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); + FS::BindBlurInfo(cmd, host_buffer.EmplaceUniform(frag_info)); + + return pass.AddCommand(std::move(cmd)); + }; Vector2 scale; auto scale_curve = [](Scalar radius) { diff --git a/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl b/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl index ecc631edb2834..ebf135a482328 100644 --- a/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl +++ b/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl @@ -2,6 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// 1D (directional) gaussian blur. +// +// Paths for future optimization: +// * Remove the uv bounds multiplier in SampleColor by adding optional +// support for SamplerAddressMode::ClampToBorder in the texture sampler. +// * Render both blur passes into a smaller texture than the source image +// (~1/radius size). +// * If doing the small texture render optimization, cache misses can be +// reduced in the first pass by sampling the source textures with a mip +// level of log2(min_radius). + #include #include #include @@ -9,14 +20,16 @@ uniform f16sampler2D texture_sampler; -struct KernelSample { - f16vec2 uv_offset; - float16_t coefficient; -}; +uniform BlurInfo { + f16vec2 blur_uv_offset; -uniform KernelSamples { - int sample_count; - KernelSample samples[24]; + // The blur sigma and radius have a linear relationship which is defined + // host-side, but both are useful controls here. Sigma (pixels per standard + // deviation) is used to define the gaussian function itself, whereas the + // radius is used to limit how much of the function is integrated. + float blur_sigma; + float16_t blur_radius; + float16_t step_size; } blur_info; @@ -34,13 +47,27 @@ out f16vec4 frag_color; void main() { f16vec4 total_color = f16vec4(0.0hf); + float16_t gaussian_integral = 0.0hf; - for (int i = 0; i < blur_info.sample_count; ++i) { - float16_t coefficient = blur_info.samples[i].coefficient; + // Step by 2.0 as a performance optimization, relying on bilinear filtering in + // the sampler to blend the texels. Typically the space between pixels is + // calculated so their blended amounts match the gaussian coefficients. This + // just uses 0.5 as an optimization until the gaussian coefficients are + // calculated and passed in from the cpu. + for (float16_t i = -blur_info.blur_radius; i <= blur_info.blur_radius; + i += blur_info.step_size) { + // Use the 32 bit Gaussian function because the 16 bit variation results in + // quality loss/visible banding. Also, 16 bit variation internally breaks + // down at a moderately high (but still reasonable) blur sigma of >255 when + // computing sigma^2 due to the exponent only having 5 bits. + float16_t gaussian = float16_t(IPGaussian(float(i), blur_info.blur_sigma)); + gaussian_integral += gaussian; total_color += - coefficient * Sample(texture_sampler, - v_texture_coords + blur_info.samples[i].uv_offset); + gaussian * Sample(texture_sampler, // sampler + v_texture_coords + blur_info.blur_uv_offset * + i // texture coordinates + ); } - frag_color = total_color; + frag_color = total_color / gaussian_integral; } From 3d333b7b1dbe41aa67a7076bb42c61a9e4b5fd2e Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 4 Jan 2024 10:11:41 -0800 Subject: [PATCH 10/16] added test --- ...gaussian_blur_filter_contents_unittests.cc | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc index 4350c9318b7c3..20d582932dc5d 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc @@ -381,5 +381,31 @@ TEST(GaussianBlurFilterContentsTest, CalculateSigmaForBlurRadius) { EXPECT_NEAR(sigma, derived_sigma, 0.01f); } +TEST(GaussianBlurFilterContentsTest, Coefficients) { + BlurParameters parameters = {.blur_uv_offset = Point(1, 0), + .blur_sigma = 1, + .blur_radius = 5, + .step_size = 1}; + KernelPipeline::FragmentShader::KernelSamples samples = + GenerateBlurInfo(parameters); + EXPECT_EQ(samples.sample_count, 11); + + // Coefficients should add up to 1. + Scalar tally = 0; + for (const KernelPipeline::FragmentShader::KernelSample& sample : + samples.samples) { + tally += sample.coefficient; + } + EXPECT_FLOAT_EQ(tally, 1.0f); + + // Verify the shape of the curve. + for (int i = 0; i < 5; ++i) { + EXPECT_FLOAT_EQ(samples.samples[i].coefficient, + samples.samples[10 - i].coefficient); + EXPECT_TRUE(samples.samples[i + 1].coefficient > + samples.samples[i].coefficient); + } +} + } // namespace testing } // namespace impeller From 08582014494f0881ee3350905ce86018354e16ff Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 4 Jan 2024 10:29:27 -0800 Subject: [PATCH 11/16] lint? licenses --- ci/licenses_golden/licenses_flutter | 6 ++++++ .../contents/filters/gaussian_blur_filter_contents.cc | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 9a1de1da99d92..8485580423b23 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -5231,6 +5231,9 @@ ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur.gls ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur.vert + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_decal.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_nodecal.frag + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel.glsl + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel_decal.frag + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel_nodecal.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/geometry/points.comp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/geometry/uv.comp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag + ../../../flutter/LICENSE @@ -8041,6 +8044,9 @@ FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur.vert FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_decal.frag FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur_noalpha_nodecal.frag +FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel.glsl +FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel_decal.frag +FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur/kernel_nodecal.frag FILE: ../../../flutter/impeller/entity/shaders/geometry/points.comp FILE: ../../../flutter/impeller/entity/shaders/geometry/uv.comp FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index d1f1d044cb5e6..962728d9d4300 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -441,7 +441,7 @@ KernelPipeline::FragmentShader::KernelSamples GenerateBlurInfo( Scalar tally = 0.0f; for (int i = 0; i < result.sample_count; ++i) { int x = (i * parameters.step_size) - parameters.blur_radius; - result.samples[i] = { + result.samples[i] = KernelPipeline::FragmentShader::KernelSample{ .uv_offset = parameters.blur_uv_offset * x, .coefficient = expf(-0.5f * (x * x) / (parameters.blur_sigma * parameters.blur_sigma)) / From d9ee2b92ee5a6ebdc4425e1ede759b7bbb6aeb32 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 4 Jan 2024 10:43:54 -0800 Subject: [PATCH 12/16] lint? --- .../entity/contents/filters/gaussian_blur_filter_contents.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 962728d9d4300..004938ce2e4d8 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -434,8 +434,9 @@ Scalar GaussianBlurFilterContents::ScaleSigma(Scalar sigma) { KernelPipeline::FragmentShader::KernelSamples GenerateBlurInfo( BlurParameters parameters) { KernelPipeline::FragmentShader::KernelSamples result{ - .sample_count = - ((2 * parameters.blur_radius) / parameters.step_size) + 1}; + .sample_count = ((2 * parameters.blur_radius) / parameters.step_size) + 1, + .samples = {}, + }; FML_CHECK(result.sample_count < 24); Scalar tally = 0.0f; From 204806b978865ce12ef81c6cc24449980344721f Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 4 Jan 2024 10:58:46 -0800 Subject: [PATCH 13/16] lint? --- .../contents/filters/gaussian_blur_filter_contents.cc | 7 +++---- .../filters/gaussian_blur_filter_contents_unittests.cc | 5 ++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 004938ce2e4d8..f6382d852ca6e 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -433,10 +433,9 @@ Scalar GaussianBlurFilterContents::ScaleSigma(Scalar sigma) { KernelPipeline::FragmentShader::KernelSamples GenerateBlurInfo( BlurParameters parameters) { - KernelPipeline::FragmentShader::KernelSamples result{ - .sample_count = ((2 * parameters.blur_radius) / parameters.step_size) + 1, - .samples = {}, - }; + KernelPipeline::FragmentShader::KernelSamples result; + result.sample_count = + ((2 * parameters.blur_radius) / parameters.step_size) + 1; FML_CHECK(result.sample_count < 24); Scalar tally = 0.0f; diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc index 20d582932dc5d..08f00f4f72efa 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc @@ -392,9 +392,8 @@ TEST(GaussianBlurFilterContentsTest, Coefficients) { // Coefficients should add up to 1. Scalar tally = 0; - for (const KernelPipeline::FragmentShader::KernelSample& sample : - samples.samples) { - tally += sample.coefficient; + for (int i = 0; i < samples.sample_count; ++i) { + tally += samples.samples[i].coefficient; } EXPECT_FLOAT_EQ(tally, 1.0f); From dbcbd68a399c460b89f094111b81dcda0ad9e707 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 4 Jan 2024 12:28:29 -0800 Subject: [PATCH 14/16] moved away from float16 for the uniform --- impeller/entity/shaders/gaussian_blur/kernel.glsl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/impeller/entity/shaders/gaussian_blur/kernel.glsl b/impeller/entity/shaders/gaussian_blur/kernel.glsl index ecc631edb2834..57f0de0a61183 100644 --- a/impeller/entity/shaders/gaussian_blur/kernel.glsl +++ b/impeller/entity/shaders/gaussian_blur/kernel.glsl @@ -10,8 +10,8 @@ uniform f16sampler2D texture_sampler; struct KernelSample { - f16vec2 uv_offset; - float16_t coefficient; + vec2 uv_offset; + float coefficient; }; uniform KernelSamples { @@ -36,7 +36,7 @@ void main() { f16vec4 total_color = f16vec4(0.0hf); for (int i = 0; i < blur_info.sample_count; ++i) { - float16_t coefficient = blur_info.samples[i].coefficient; + float16_t coefficient = float16_t(blur_info.samples[i].coefficient); total_color += coefficient * Sample(texture_sampler, v_texture_coords + blur_info.samples[i].uv_offset); From 4f9f21a2ddcd44406c82dc22b404a022d965bf14 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 4 Jan 2024 12:56:43 -0800 Subject: [PATCH 15/16] include for windows --- impeller/entity/BUILD.gn | 1 + .../entity/contents/filters/gaussian_blur_filter_contents.cc | 2 ++ 2 files changed, 3 insertions(+) diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 62b671444db02..4dd5d9fe19eb3 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -247,6 +247,7 @@ impeller_component("entity") { } deps = [ "//flutter/fml" ] + defines = [ "_USE_MATH_DEFINES" ] } impeller_component("entity_test_helpers") { diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index f6382d852ca6e..22fbce32ce1ce 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -4,6 +4,8 @@ #include "impeller/entity/contents/filters/gaussian_blur_filter_contents.h" +#include + #include "impeller/entity/contents/content_context.h" #include "impeller/entity/texture_fill.frag.h" #include "impeller/entity/texture_fill.vert.h" From 3b49690c08e2f2ac4133cb47f188766d7924a34d Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Thu, 4 Jan 2024 13:48:12 -0800 Subject: [PATCH 16/16] malioc --- impeller/tools/malioc.json | 376 +++++++++++++++++++++++++++++++++++++ 1 file changed, 376 insertions(+) diff --git a/impeller/tools/malioc.json b/impeller/tools/malioc.json index c4f82b8a27cb2..5c7698ea0178c 100644 --- a/impeller/tools/malioc.json +++ b/impeller/tools/malioc.json @@ -4029,6 +4029,240 @@ } } }, + "flutter/impeller/entity/gles/kernel_decal.frag.gles": { + "Mali-G78": { + "core": "Mali-G78", + "filename": "flutter/impeller/entity/gles/kernel_decal.frag.gles", + "has_side_effects": false, + "has_uniform_computation": true, + "modifies_coverage": false, + "reads_color_buffer": false, + "type": "Fragment", + "uses_late_zs_test": false, + "uses_late_zs_update": false, + "variants": { + "Main": { + "fp16_arithmetic": 66, + "has_stack_spilling": false, + "performance": { + "longest_path_bound_pipelines": [ + null + ], + "longest_path_cycles": [ + null, + null, + null, + null, + null, + null, + null + ], + "pipelines": [ + "arith_total", + "arith_fma", + "arith_cvt", + "arith_sfu", + "load_store", + "varying", + "texture" + ], + "shortest_path_bound_pipelines": [ + "arith_total", + "arith_cvt" + ], + "shortest_path_cycles": [ + 0.078125, + 0.0, + 0.078125, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "total_bound_pipelines": [ + "load_store" + ], + "total_cycles": [ + 0.359375, + 0.0625, + 0.359375, + 0.1875, + 2.0, + 0.25, + 0.25 + ] + }, + "stack_spill_bytes": 0, + "thread_occupancy": 100, + "uniform_registers_used": 4, + "work_registers_used": 19 + } + } + }, + "Mali-T880": { + "core": "Mali-T880", + "filename": "flutter/impeller/entity/gles/kernel_decal.frag.gles", + "has_uniform_computation": false, + "type": "Fragment", + "variants": { + "Main": { + "has_stack_spilling": false, + "performance": { + "longest_path_bound_pipelines": [ + null + ], + "longest_path_cycles": [ + null, + null, + null + ], + "pipelines": [ + "arithmetic", + "load_store", + "texture" + ], + "shortest_path_bound_pipelines": [ + "arithmetic", + "load_store" + ], + "shortest_path_cycles": [ + 1.0, + 1.0, + 0.0 + ], + "total_bound_pipelines": [ + "arithmetic" + ], + "total_cycles": [ + 3.6666667461395264, + 3.0, + 1.0 + ] + }, + "thread_occupancy": 100, + "uniform_registers_used": 1, + "work_registers_used": 3 + } + } + } + }, + "flutter/impeller/entity/gles/kernel_nodecal.frag.gles": { + "Mali-G78": { + "core": "Mali-G78", + "filename": "flutter/impeller/entity/gles/kernel_nodecal.frag.gles", + "has_side_effects": false, + "has_uniform_computation": true, + "modifies_coverage": false, + "reads_color_buffer": false, + "type": "Fragment", + "uses_late_zs_test": false, + "uses_late_zs_update": false, + "variants": { + "Main": { + "fp16_arithmetic": 50, + "has_stack_spilling": false, + "performance": { + "longest_path_bound_pipelines": [ + null + ], + "longest_path_cycles": [ + null, + null, + null, + null, + null, + null, + null + ], + "pipelines": [ + "arith_total", + "arith_fma", + "arith_cvt", + "arith_sfu", + "load_store", + "varying", + "texture" + ], + "shortest_path_bound_pipelines": [ + "arith_total", + "arith_cvt" + ], + "shortest_path_cycles": [ + 0.078125, + 0.0, + 0.078125, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "total_bound_pipelines": [ + "load_store" + ], + "total_cycles": [ + 0.25, + 0.0625, + 0.25, + 0.0, + 2.0, + 0.25, + 0.25 + ] + }, + "stack_spill_bytes": 0, + "thread_occupancy": 100, + "uniform_registers_used": 4, + "work_registers_used": 19 + } + } + }, + "Mali-T880": { + "core": "Mali-T880", + "filename": "flutter/impeller/entity/gles/kernel_nodecal.frag.gles", + "has_uniform_computation": false, + "type": "Fragment", + "variants": { + "Main": { + "has_stack_spilling": false, + "performance": { + "longest_path_bound_pipelines": [ + null + ], + "longest_path_cycles": [ + null, + null, + null + ], + "pipelines": [ + "arithmetic", + "load_store", + "texture" + ], + "shortest_path_bound_pipelines": [ + "arithmetic", + "load_store" + ], + "shortest_path_cycles": [ + 1.0, + 1.0, + 0.0 + ], + "total_bound_pipelines": [ + "arithmetic" + ], + "total_cycles": [ + 2.3333332538604736, + 2.0, + 1.0 + ] + }, + "thread_occupancy": 100, + "uniform_registers_used": 1, + "work_registers_used": 3 + } + } + } + }, "flutter/impeller/entity/gles/linear_gradient_fill.frag.gles": { "Mali-G78": { "core": "Mali-G78", @@ -7720,6 +7954,148 @@ } } }, + "flutter/impeller/entity/kernel_decal.frag.vkspv": { + "Mali-G78": { + "core": "Mali-G78", + "filename": "flutter/impeller/entity/kernel_decal.frag.vkspv", + "has_side_effects": false, + "has_uniform_computation": true, + "modifies_coverage": false, + "reads_color_buffer": false, + "type": "Fragment", + "uses_late_zs_test": false, + "uses_late_zs_update": false, + "variants": { + "Main": { + "fp16_arithmetic": 66, + "has_stack_spilling": false, + "performance": { + "longest_path_bound_pipelines": [ + null + ], + "longest_path_cycles": [ + null, + null, + null, + null, + null, + null, + null + ], + "pipelines": [ + "arith_total", + "arith_fma", + "arith_cvt", + "arith_sfu", + "load_store", + "varying", + "texture" + ], + "shortest_path_bound_pipelines": [ + "arith_total", + "arith_cvt" + ], + "shortest_path_cycles": [ + 0.09375, + 0.0, + 0.09375, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "total_bound_pipelines": [ + "load_store" + ], + "total_cycles": [ + 0.34375, + 0.0625, + 0.34375, + 0.1875, + 1.0, + 0.25, + 0.25 + ] + }, + "stack_spill_bytes": 0, + "thread_occupancy": 100, + "uniform_registers_used": 4, + "work_registers_used": 17 + } + } + } + }, + "flutter/impeller/entity/kernel_nodecal.frag.vkspv": { + "Mali-G78": { + "core": "Mali-G78", + "filename": "flutter/impeller/entity/kernel_nodecal.frag.vkspv", + "has_side_effects": false, + "has_uniform_computation": true, + "modifies_coverage": false, + "reads_color_buffer": false, + "type": "Fragment", + "uses_late_zs_test": false, + "uses_late_zs_update": false, + "variants": { + "Main": { + "fp16_arithmetic": 50, + "has_stack_spilling": false, + "performance": { + "longest_path_bound_pipelines": [ + null + ], + "longest_path_cycles": [ + null, + null, + null, + null, + null, + null, + null + ], + "pipelines": [ + "arith_total", + "arith_fma", + "arith_cvt", + "arith_sfu", + "load_store", + "varying", + "texture" + ], + "shortest_path_bound_pipelines": [ + "arith_total", + "arith_cvt" + ], + "shortest_path_cycles": [ + 0.09375, + 0.0, + 0.09375, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "total_bound_pipelines": [ + "load_store" + ], + "total_cycles": [ + 0.21875, + 0.0625, + 0.21875, + 0.0, + 1.0, + 0.25, + 0.25 + ] + }, + "stack_spill_bytes": 0, + "thread_occupancy": 100, + "uniform_registers_used": 4, + "work_registers_used": 11 + } + } + } + }, "flutter/impeller/entity/linear_gradient_fill.frag.vkspv": { "Mali-G78": { "core": "Mali-G78",