From e6b3c034eac67f189cfc5771ca4f6a218f489a75 Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Fri, 24 May 2024 10:40:53 -0700 Subject: [PATCH] [Impeller] sped up the linear gradient by moving calculations to the cpu (flutter/engine#53007) issue: https://github.com/flutter/flutter/issues/148496 The linked issue showed us as ALU bound with the linear gradient, this should relieve some of that pressure. Tests: There is already existing golden tests for this, this just changed the performance, no new functionality. ## summary of math improvements: - (num_colors - 1) * division -> multiplication - (num_colors - 1) * subtractions removed - removes 1 `dot()` - 1 division -> multiplication - 1 subtraction removed [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- .../impeller/entity/contents/gradient_generator.cc | 10 ++++++++-- .../impeller/entity/contents/gradient_generator.h | 5 ++++- .../entity/contents/linear_gradient_contents.cc | 12 ++++++++++++ .../gradients/linear_gradient_ssbo_fill.frag | 13 +++++++------ engine/src/flutter/impeller/tools/malioc.json | 12 ++++++------ 5 files changed, 37 insertions(+), 15 deletions(-) diff --git a/engine/src/flutter/impeller/entity/contents/gradient_generator.cc b/engine/src/flutter/impeller/entity/contents/gradient_generator.cc index 2d6431ee8b8..90f489dcfa4 100644 --- a/engine/src/flutter/impeller/entity/contents/gradient_generator.cc +++ b/engine/src/flutter/impeller/entity/contents/gradient_generator.cc @@ -54,9 +54,15 @@ std::vector CreateGradientColors(const std::vector& colors, const std::vector& stops) { FML_DCHECK(stops.size() == colors.size()); - std::vector result(stops.size()); + std::vector result; + result.reserve(stops.size()); + Scalar last_stop = 0; for (auto i = 0u; i < stops.size(); i++) { - result[i] = {.color = colors[i], .stop = stops[i]}; + Scalar delta = stops[i] - last_stop; + Scalar inverse_delta = delta == 0.0f ? 0.0 : 1.0 / delta; + result.emplace_back(StopData{ + .color = colors[i], .stop = stops[i], .inverse_delta = inverse_delta}); + last_stop = stops[i]; } return result; } diff --git a/engine/src/flutter/impeller/entity/contents/gradient_generator.h b/engine/src/flutter/impeller/entity/contents/gradient_generator.h index f6d6213d8cf..db48829126e 100644 --- a/engine/src/flutter/impeller/entity/contents/gradient_generator.h +++ b/engine/src/flutter/impeller/entity/contents/gradient_generator.h @@ -28,9 +28,12 @@ std::shared_ptr CreateGradientTexture( struct StopData { Color color; Scalar stop; - Padding<12> _padding_; + Scalar inverse_delta; + Padding<8> _padding_; }; +static_assert(sizeof(StopData) == 32); + /** * @brief Populate a vector with the color and stop data for a gradient * diff --git a/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.cc b/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.cc index 99f2c79055f..891f6439981 100644 --- a/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.cc @@ -113,6 +113,15 @@ bool LinearGradientContents::RenderTexture(const ContentContext& renderer, }); } +namespace { +Scalar CalculateInverseDotStartToEnd(Point start_point, Point end_point) { + Point start_to_end = end_point - start_point; + Scalar dot = + (start_to_end.x * start_to_end.x + start_to_end.y * start_to_end.y); + return dot == 0.0f ? 0.0f : 1.0f / dot; +} +} // namespace + bool LinearGradientContents::RenderSSBO(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { @@ -135,6 +144,9 @@ bool LinearGradientContents::RenderSSBO(const ContentContext& renderer, frag_info.tile_mode = static_cast(tile_mode_); frag_info.decal_border_color = decal_border_color_; frag_info.alpha = GetOpacityFactor(); + frag_info.start_to_end = end_point_ - start_point_; + frag_info.inverse_dot_start_to_end = + CalculateInverseDotStartToEnd(start_point_, end_point_); auto& host_buffer = renderer.GetTransientsBuffer(); auto colors = CreateGradientColors(colors_, stops_); diff --git a/engine/src/flutter/impeller/entity/shaders/gradients/linear_gradient_ssbo_fill.frag b/engine/src/flutter/impeller/entity/shaders/gradients/linear_gradient_ssbo_fill.frag index e64c33b4d12..00d5d5529fa 100644 --- a/engine/src/flutter/impeller/entity/shaders/gradients/linear_gradient_ssbo_fill.frag +++ b/engine/src/flutter/impeller/entity/shaders/gradients/linear_gradient_ssbo_fill.frag @@ -12,6 +12,7 @@ precision mediump float; struct ColorPoint { vec4 color; float stop; + float inverse_delta; }; layout(std140) readonly buffer ColorData { @@ -26,6 +27,8 @@ uniform FragInfo { float tile_mode; vec4 decal_border_color; int colors_length; + highp vec2 start_to_end; + float inverse_dot_start_to_end; } frag_info; @@ -34,10 +37,9 @@ highp in vec2 v_position; out vec4 frag_color; void main() { - highp vec2 start_to_end = frag_info.end_point - frag_info.start_point; highp vec2 start_to_position = v_position - frag_info.start_point; - highp float t = - dot(start_to_position, start_to_end) / dot(start_to_end, start_to_end); + highp float t = dot(start_to_position, frag_info.start_to_end) * + frag_info.inverse_dot_start_to_end; if ((t < 0.0 || t > 1.0) && frag_info.tile_mode == kTileModeDecal) { frag_color = frag_info.decal_border_color; @@ -48,11 +50,10 @@ void main() { ColorPoint prev_point = color_data.colors[i - 1]; ColorPoint current_point = color_data.colors[i]; if (t >= prev_point.stop && t <= current_point.stop) { - float delta = (current_point.stop - prev_point.stop); - if (delta < 0.001) { + if (current_point.inverse_delta > 1000.0) { frag_color = current_point.color; } else { - float ratio = (t - prev_point.stop) / delta; + float ratio = (t - prev_point.stop) * current_point.inverse_delta; frag_color = mix(prev_point.color, current_point.color, ratio); } break; diff --git a/engine/src/flutter/impeller/tools/malioc.json b/engine/src/flutter/impeller/tools/malioc.json index 35b83ea0ee6..47994f75c0f 100644 --- a/engine/src/flutter/impeller/tools/malioc.json +++ b/engine/src/flutter/impeller/tools/malioc.json @@ -5737,7 +5737,7 @@ "uses_late_zs_update": false, "variants": { "Main": { - "fp16_arithmetic": 35, + "fp16_arithmetic": 37, "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ @@ -5778,10 +5778,10 @@ "load_store" ], "total_cycles": [ - 0.75, - 0.421875, - 0.75, - 0.625, + 0.71875, + 0.40625, + 0.71875, + 0.5625, 4.0, 0.25, 0.0 @@ -5790,7 +5790,7 @@ "stack_spill_bytes": 0, "thread_occupancy": 100, "uniform_registers_used": 24, - "work_registers_used": 17 + "work_registers_used": 21 } } }