From 2fb2e3e70a5544443ac6edb97452b87d8b21ab28 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 8 Nov 2024 10:18:05 -0800 Subject: [PATCH] [Impeller] Switch to uniform arrays for gradient data on non-SSBO hardware (flutter/engine#56441) Currently the most generalized form of the Impeller gradient shaders uses an SSBO to store the gradient information, but SSBO data is not supported on older platforms. To make the capability more general we introduce variants of the gradient shaders that uses uniform arrays which are more widely supported. --- .../ci/licenses_golden/licenses_flutter | 8 + .../aiks_dl_gradient_unittests.cc | 117 +++ engine/src/flutter/impeller/entity/BUILD.gn | 8 +- .../contents/conical_gradient_contents.cc | 55 ++ .../contents/conical_gradient_contents.h | 5 + .../entity/contents/content_context.cc | 6 + .../entity/contents/content_context.h | 45 ++ .../entity/contents/gradient_generator.cc | 27 + .../entity/contents/gradient_generator.h | 22 + .../contents/linear_gradient_contents.cc | 50 ++ .../contents/linear_gradient_contents.h | 4 + .../contents/radial_gradient_contents.cc | 48 ++ .../contents/radial_gradient_contents.h | 5 + .../contents/sweep_gradient_contents.cc | 52 ++ .../entity/contents/sweep_gradient_contents.h | 4 + .../conical_gradient_uniform_fill.frag | 68 ++ .../linear_gradient_uniform_fill.frag | 64 ++ .../radial_gradient_uniform_fill.frag | 64 ++ .../sweep_gradient_uniform_fill.frag | 65 ++ engine/src/flutter/impeller/tools/malioc.json | 742 ++++++++++++++++++ .../testing/impeller_golden_tests_output.txt | 12 + 21 files changed, 1469 insertions(+), 2 deletions(-) create mode 100644 engine/src/flutter/impeller/entity/shaders/gradients/conical_gradient_uniform_fill.frag create mode 100644 engine/src/flutter/impeller/entity/shaders/gradients/linear_gradient_uniform_fill.frag create mode 100644 engine/src/flutter/impeller/entity/shaders/gradients/radial_gradient_uniform_fill.frag create mode 100644 engine/src/flutter/impeller/entity/shaders/gradients/sweep_gradient_uniform_fill.frag diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index f57b0f2e30..f16aa21a78 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -43078,15 +43078,19 @@ ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag + ../../../flu ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/conical_gradient_fill.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/conical_gradient_ssbo_fill.frag + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/conical_gradient_uniform_fill.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/fast_gradient.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/fast_gradient.vert + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/gradient_fill.vert + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/linear_gradient_fill.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/linear_gradient_ssbo_fill.frag + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/linear_gradient_uniform_fill.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/radial_gradient_fill.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/radial_gradient_ssbo_fill.frag + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/radial_gradient_uniform_fill.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_fill.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_ssbo_fill.frag + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_uniform_fill.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/rrect_blur.frag + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/rrect_blur.vert + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/shaders/runtime_effect.vert + ../../../flutter/LICENSE @@ -45940,15 +45944,19 @@ FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert FILE: ../../../flutter/impeller/entity/shaders/gradients/conical_gradient_fill.frag FILE: ../../../flutter/impeller/entity/shaders/gradients/conical_gradient_ssbo_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/gradients/conical_gradient_uniform_fill.frag FILE: ../../../flutter/impeller/entity/shaders/gradients/fast_gradient.frag FILE: ../../../flutter/impeller/entity/shaders/gradients/fast_gradient.vert FILE: ../../../flutter/impeller/entity/shaders/gradients/gradient_fill.vert FILE: ../../../flutter/impeller/entity/shaders/gradients/linear_gradient_fill.frag FILE: ../../../flutter/impeller/entity/shaders/gradients/linear_gradient_ssbo_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/gradients/linear_gradient_uniform_fill.frag FILE: ../../../flutter/impeller/entity/shaders/gradients/radial_gradient_fill.frag FILE: ../../../flutter/impeller/entity/shaders/gradients/radial_gradient_ssbo_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/gradients/radial_gradient_uniform_fill.frag FILE: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_fill.frag FILE: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_ssbo_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_uniform_fill.frag FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.frag FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.vert FILE: ../../../flutter/impeller/entity/shaders/runtime_effect.vert diff --git a/engine/src/flutter/impeller/display_list/aiks_dl_gradient_unittests.cc b/engine/src/flutter/impeller/display_list/aiks_dl_gradient_unittests.cc index 3390a1dec6..3d96f941a5 100644 --- a/engine/src/flutter/impeller/display_list/aiks_dl_gradient_unittests.cc +++ b/engine/src/flutter/impeller/display_list/aiks_dl_gradient_unittests.cc @@ -216,6 +216,123 @@ TEST_P(AiksTest, CanRenderLinearGradientWithOverlappingStopsClamp) { CanRenderLinearGradientWithOverlappingStops(this, DlTileMode::kClamp); } +namespace { +void CanRenderGradientWithIncompleteStops(AiksTest* aiks_test, + DlColorSourceType type) { + const DlTileMode tile_modes[4] = { + DlTileMode::kClamp, + DlTileMode::kRepeat, + DlTileMode::kMirror, + DlTileMode::kDecal, + }; + const DlScalar test_size = 250; + const DlScalar test_border = 25; + const DlScalar gradient_size = 50; + const DlScalar quadrant_size = test_size + test_border * 2; + + DisplayListBuilder builder; + builder.DrawRect(DlRect::MakeWH(quadrant_size * 2, quadrant_size * 2), + DlPaint().setColor(DlColor::kDarkGrey())); + + for (int quadrant = 0; quadrant < 4; quadrant++) { + builder.Save(); + builder.Translate((quadrant & 1) * quadrant_size + test_border, + (quadrant >> 1) * quadrant_size + test_border); + + if (type == DlColorSourceType::kLinearGradient) { + // Alignment lines for the gradient edges/repeats/mirrors/etc. + // (rendered under the gradient so as not to obscure it) + DlPoint center = DlPoint(test_size, test_size) * 0.5; + DlScalar ten_percent = gradient_size * 0.1; + for (int i = gradient_size / 2; i <= test_size / 2; i += gradient_size) { + auto draw_at = [=](DlCanvas& canvas, DlScalar offset, DlColor color) { + DlPaint line_paint; + line_paint.setColor(color); + // strokewidth of 2 straddles the dividing line + line_paint.setStrokeWidth(2.0f); + line_paint.setDrawStyle(DlDrawStyle::kStroke); + + DlPoint along(offset, offset); + DlScalar across_distance = test_size / 2 + 10 - offset; + DlPoint across(across_distance, -across_distance); + + canvas.DrawLine(center - along - across, // + center - along + across, // + line_paint); + canvas.DrawLine(center + along - across, // + center + along + across, // + line_paint); + }; + // White line is at the edge of the gradient + // Grey lines are where the 0.1 and 0.9 color stops land + draw_at(builder, i - ten_percent, DlColor::kMidGrey()); + draw_at(builder, i, DlColor::kWhite()); + draw_at(builder, i + ten_percent, DlColor::kMidGrey()); + } + } + + std::vector colors = { + DlColor::kGreen(), + DlColor::kPurple(), + DlColor::kOrange(), + DlColor::kBlue(), + }; + std::vector stops = {0.1, 0.3, 0.7, 0.9}; + + DlPaint paint; + switch (type) { + case DlColorSourceType::kLinearGradient: + paint.setColorSource(DlColorSource::MakeLinear( + {test_size / 2 - gradient_size / 2, + test_size / 2 - gradient_size / 2}, + {test_size / 2 + gradient_size / 2, + test_size / 2 + gradient_size / 2}, + stops.size(), colors.data(), stops.data(), tile_modes[quadrant])); + break; + case DlColorSourceType::kRadialGradient: + paint.setColorSource(DlColorSource::MakeRadial( + {test_size / 2, test_size / 2}, gradient_size, // + stops.size(), colors.data(), stops.data(), tile_modes[quadrant])); + break; + case DlColorSourceType::kConicalGradient: + paint.setColorSource(DlColorSource::MakeConical( + {test_size / 2, test_size / 2}, 0, + {test_size / 2 + 20, test_size / 2 - 10}, gradient_size, + stops.size(), colors.data(), stops.data(), tile_modes[quadrant])); + break; + case DlColorSourceType::kSweepGradient: + paint.setColorSource(DlColorSource::MakeSweep( + {test_size / 2, test_size / 2}, 0, 45, // + stops.size(), colors.data(), stops.data(), tile_modes[quadrant])); + break; + default: + FML_UNREACHABLE(); + } + + builder.DrawRect(SkRect::MakeXYWH(0, 0, test_size, test_size), paint); + builder.Restore(); + } + + ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build())); +} +} // namespace + +TEST_P(AiksTest, CanRenderLinearGradientWithIncompleteStops) { + CanRenderGradientWithIncompleteStops(this, + DlColorSourceType::kLinearGradient); +} +TEST_P(AiksTest, CanRenderRadialGradientWithIncompleteStops) { + CanRenderGradientWithIncompleteStops(this, + DlColorSourceType::kRadialGradient); +} +TEST_P(AiksTest, CanRenderConicalGradientWithIncompleteStops) { + CanRenderGradientWithIncompleteStops(this, + DlColorSourceType::kConicalGradient); +} +TEST_P(AiksTest, CanRenderSweepGradientWithIncompleteStops) { + CanRenderGradientWithIncompleteStops(this, DlColorSourceType::kSweepGradient); +} + namespace { void CanRenderLinearGradientManyColors(AiksTest* aiks_test, DlTileMode tile_mode) { diff --git a/engine/src/flutter/impeller/entity/BUILD.gn b/engine/src/flutter/impeller/entity/BUILD.gn index 9311d35eb0..48bcb2bc33 100644 --- a/engine/src/flutter/impeller/entity/BUILD.gn +++ b/engine/src/flutter/impeller/entity/BUILD.gn @@ -18,18 +18,22 @@ impeller_shaders("entity_shaders") { "shaders/blending/advanced_blend.frag", "shaders/clip.frag", "shaders/clip.vert", - "shaders/gradients/conical_gradient_fill.frag", "shaders/glyph_atlas.frag", "shaders/glyph_atlas.vert", "shaders/gradients/gradient_fill.vert", + "shaders/gradients/conical_gradient_fill.frag", + "shaders/gradients/conical_gradient_uniform_fill.frag", "shaders/gradients/linear_gradient_fill.frag", + "shaders/gradients/linear_gradient_uniform_fill.frag", "shaders/gradients/radial_gradient_fill.frag", + "shaders/gradients/radial_gradient_uniform_fill.frag", + "shaders/gradients/sweep_gradient_fill.frag", + "shaders/gradients/sweep_gradient_uniform_fill.frag", "shaders/rrect_blur.vert", "shaders/rrect_blur.frag", "shaders/runtime_effect.vert", "shaders/solid_fill.frag", "shaders/solid_fill.vert", - "shaders/gradients/sweep_gradient_fill.frag", "shaders/texture_fill.frag", "shaders/texture_fill.vert", "shaders/texture_uv_fill.vert", diff --git a/engine/src/flutter/impeller/entity/contents/conical_gradient_contents.cc b/engine/src/flutter/impeller/entity/contents/conical_gradient_contents.cc index 82a9bbff5e..85c2b62403 100644 --- a/engine/src/flutter/impeller/entity/contents/conical_gradient_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/conical_gradient_contents.cc @@ -49,12 +49,24 @@ void ConicalGradientContents::SetFocus(std::optional focus, focus_radius_ = radius; } +#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0])) +#define UNIFORM_FRAG_INFO(t) \ + t##GradientUniformFillPipeline::FragmentShader::FragInfo +#define UNIFORM_COLOR_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Conical)::colors) +#define UNIFORM_STOP_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Conical)::stop_pairs) +static_assert(UNIFORM_COLOR_SIZE == kMaxUniformGradientStops); +static_assert(UNIFORM_STOP_SIZE == kMaxUniformGradientStops / 2); + bool ConicalGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { if (renderer.GetDeviceCapabilities().SupportsSSBO()) { return RenderSSBO(renderer, entity, pass); } + if (colors_.size() <= kMaxUniformGradientStops && + stops_.size() <= kMaxUniformGradientStops) { + return RenderUniform(renderer, entity, pass); + } return RenderTexture(renderer, entity, pass); } @@ -107,6 +119,49 @@ bool ConicalGradientContents::RenderSSBO(const ContentContext& renderer, }); } +bool ConicalGradientContents::RenderUniform(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = ConicalGradientUniformFillPipeline::VertexShader; + using FS = ConicalGradientUniformFillPipeline::FragmentShader; + + VS::FrameInfo frame_info; + frame_info.matrix = GetInverseEffectTransform(); + + PipelineBuilderCallback pipeline_callback = + [&renderer](ContentContextOptions options) { + return renderer.GetConicalGradientUniformFillPipeline(options); + }; + return ColorSourceContents::DrawGeometry( + renderer, entity, pass, pipeline_callback, frame_info, + [this, &renderer, &entity](RenderPass& pass) { + FS::FragInfo frag_info; + frag_info.center = center_; + if (focus_) { + frag_info.focus = focus_.value(); + frag_info.focus_radius = focus_radius_; + } else { + frag_info.focus = center_; + frag_info.focus_radius = 0.0; + } + frag_info.radius = radius_; + frag_info.tile_mode = static_cast(tile_mode_); + frag_info.alpha = + GetOpacityFactor() * + GetGeometry()->ComputeAlphaCoverage(entity.GetTransform()); + frag_info.colors_length = PopulateUniformGradientColors( + colors_, stops_, frag_info.colors, frag_info.stop_pairs); + frag_info.decal_border_color = decal_border_color_; + + pass.SetCommandLabel("ConicalGradientUniformFill"); + + FS::BindFragInfo( + pass, renderer.GetTransientsBuffer().EmplaceUniform(frag_info)); + + return true; + }); +} + bool ConicalGradientContents::RenderTexture(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { diff --git a/engine/src/flutter/impeller/entity/contents/conical_gradient_contents.h b/engine/src/flutter/impeller/entity/contents/conical_gradient_contents.h index 16d43c74af..1174722385 100644 --- a/engine/src/flutter/impeller/entity/contents/conical_gradient_contents.h +++ b/engine/src/flutter/impeller/entity/contents/conical_gradient_contents.h @@ -51,6 +51,11 @@ class ConicalGradientContents final : public ColorSourceContents { bool RenderSSBO(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const; + + bool RenderUniform(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + Point center_; Scalar radius_ = 0.0f; std::vector colors_; diff --git a/engine/src/flutter/impeller/entity/contents/content_context.cc b/engine/src/flutter/impeller/entity/contents/content_context.cc index fe1725e5a8..b3cc2d9932 100644 --- a/engine/src/flutter/impeller/entity/contents/content_context.cc +++ b/engine/src/flutter/impeller/entity/contents/content_context.cc @@ -308,6 +308,12 @@ ContentContext::ContentContext( conical_gradient_ssbo_fill_pipelines_.CreateDefault(*context_, options); sweep_gradient_ssbo_fill_pipelines_.CreateDefault(*context_, options); } else { + linear_gradient_uniform_fill_pipelines_.CreateDefault(*context_, options); + radial_gradient_uniform_fill_pipelines_.CreateDefault(*context_, options); + conical_gradient_uniform_fill_pipelines_.CreateDefault(*context_, + options); + sweep_gradient_uniform_fill_pipelines_.CreateDefault(*context_, options); + linear_gradient_fill_pipelines_.CreateDefault(*context_, options); radial_gradient_fill_pipelines_.CreateDefault(*context_, options); conical_gradient_fill_pipelines_.CreateDefault(*context_, options); diff --git a/engine/src/flutter/impeller/entity/contents/content_context.h b/engine/src/flutter/impeller/entity/contents/content_context.h index 69d67b97f4..0cfb4a2623 100644 --- a/engine/src/flutter/impeller/entity/contents/content_context.h +++ b/engine/src/flutter/impeller/entity/contents/content_context.h @@ -56,6 +56,11 @@ #include "impeller/entity/tiled_texture_fill.frag.h" #include "impeller/entity/yuv_to_rgb_filter.frag.h" +#include "impeller/entity/conical_gradient_uniform_fill.frag.h" +#include "impeller/entity/linear_gradient_uniform_fill.frag.h" +#include "impeller/entity/radial_gradient_uniform_fill.frag.h" +#include "impeller/entity/sweep_gradient_uniform_fill.frag.h" + #include "impeller/entity/conical_gradient_ssbo_fill.frag.h" #include "impeller/entity/linear_gradient_ssbo_fill.frag.h" #include "impeller/entity/radial_gradient_ssbo_fill.frag.h" @@ -92,6 +97,18 @@ using ConicalGradientFillPipeline = using SweepGradientFillPipeline = RenderPipelineHandle; +using LinearGradientUniformFillPipeline = + RenderPipelineHandle; +using ConicalGradientUniformFillPipeline = + RenderPipelineHandle; +using RadialGradientUniformFillPipeline = + RenderPipelineHandle; +using SweepGradientUniformFillPipeline = + RenderPipelineHandle; using LinearGradientSSBOFillPipeline = RenderPipelineHandle; @@ -370,6 +387,26 @@ class ContentContext { return GetPipeline(linear_gradient_fill_pipelines_, opts); } + std::shared_ptr> + GetLinearGradientUniformFillPipeline(ContentContextOptions opts) const { + return GetPipeline(linear_gradient_uniform_fill_pipelines_, opts); + } + + std::shared_ptr> + GetRadialGradientUniformFillPipeline(ContentContextOptions opts) const { + return GetPipeline(radial_gradient_uniform_fill_pipelines_, opts); + } + + std::shared_ptr> + GetConicalGradientUniformFillPipeline(ContentContextOptions opts) const { + return GetPipeline(conical_gradient_uniform_fill_pipelines_, opts); + } + + std::shared_ptr> + GetSweepGradientUniformFillPipeline(ContentContextOptions opts) const { + return GetPipeline(sweep_gradient_uniform_fill_pipelines_, opts); + } + std::shared_ptr> GetLinearGradientSSBOFillPipeline(ContentContextOptions opts) const { FML_DCHECK(GetDeviceCapabilities().SupportsSSBO()); @@ -867,6 +904,14 @@ class ContentContext { mutable Variants conical_gradient_fill_pipelines_; mutable Variants sweep_gradient_fill_pipelines_; + mutable Variants + linear_gradient_uniform_fill_pipelines_; + mutable Variants + radial_gradient_uniform_fill_pipelines_; + mutable Variants + conical_gradient_uniform_fill_pipelines_; + mutable Variants + sweep_gradient_uniform_fill_pipelines_; mutable Variants linear_gradient_ssbo_fill_pipelines_; mutable Variants diff --git a/engine/src/flutter/impeller/entity/contents/gradient_generator.cc b/engine/src/flutter/impeller/entity/contents/gradient_generator.cc index 90f489dcfa..8aa1984c52 100644 --- a/engine/src/flutter/impeller/entity/contents/gradient_generator.cc +++ b/engine/src/flutter/impeller/entity/contents/gradient_generator.cc @@ -67,4 +67,31 @@ std::vector CreateGradientColors(const std::vector& colors, return result; } +int PopulateUniformGradientColors( + const std::vector& colors, + const std::vector& stops, + Vector4 frag_info_colors[kMaxUniformGradientStops], + Vector4 frag_info_stop_pairs[kMaxUniformGradientStops / 2]) { + FML_DCHECK(stops.size() == colors.size()); + + Scalar last_stop = 0; + int index = 0; + for (auto i = 0u; i < stops.size() && i < kMaxUniformGradientStops; i++) { + Scalar cur_stop = stops[i]; + Scalar delta = cur_stop - last_stop; + Scalar inverse_delta = delta == 0.0f ? 0.0 : 1.0 / delta; + frag_info_colors[index] = colors[i]; + if ((i & 1) == 0) { + frag_info_stop_pairs[index / 2].x = cur_stop; + frag_info_stop_pairs[index / 2].y = inverse_delta; + } else { + frag_info_stop_pairs[index / 2].z = cur_stop; + frag_info_stop_pairs[index / 2].w = inverse_delta; + } + last_stop = cur_stop; + index++; + } + return index; +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/entity/contents/gradient_generator.h b/engine/src/flutter/impeller/entity/contents/gradient_generator.h index db48829126..fa6dab716f 100644 --- a/engine/src/flutter/impeller/entity/contents/gradient_generator.h +++ b/engine/src/flutter/impeller/entity/contents/gradient_generator.h @@ -44,6 +44,28 @@ static_assert(sizeof(StopData) == 32); std::vector CreateGradientColors(const std::vector& colors, const std::vector& stops); +static constexpr uint32_t kMaxUniformGradientStops = 256u; + +/** + * @brief Populate 2 arrays with the colors and stop data for a gradient + * + * The color data is simply converted to a vec4 format, but the stop data + * is both turned into pairs of {t, inverse_delta} information and also + * stops are themselves paired up into a vec4 format for efficient packing + * in the uniform data. + * + * @param colors colors from gradient + * @param stops stops from gradient + * @param frag_info_colors colors for fragment shader in vec4 format + * @param frag_info_stop_pairs pairs of stop data for shader in vec4 format + * @return count of colors stored + */ +int PopulateUniformGradientColors( + const std::vector& colors, + const std::vector& stops, + Vector4 frag_info_colors[kMaxUniformGradientStops], + Vector4 frag_info_stop_pairs[kMaxUniformGradientStops / 2]); + } // namespace impeller #endif // FLUTTER_IMPELLER_ENTITY_CONTENTS_GRADIENT_GENERATOR_H_ 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 73d533f2d7..7eef8b78fb 100644 --- a/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.cc @@ -186,6 +186,14 @@ bool LinearGradientContents::FastLinearGradient(const ContentContext& renderer, /*force_stencil=*/force_stencil, geom_callback); } +#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0])) +#define UNIFORM_FRAG_INFO(t) \ + t##GradientUniformFillPipeline::FragmentShader::FragInfo +#define UNIFORM_COLOR_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Linear)::colors) +#define UNIFORM_STOP_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Linear)::stop_pairs) +static_assert(UNIFORM_COLOR_SIZE == kMaxUniformGradientStops); +static_assert(UNIFORM_STOP_SIZE == kMaxUniformGradientStops / 2); + bool LinearGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { @@ -198,6 +206,10 @@ bool LinearGradientContents::Render(const ContentContext& renderer, if (renderer.GetDeviceCapabilities().SupportsSSBO()) { return RenderSSBO(renderer, entity, pass); } + if (colors_.size() <= kMaxUniformGradientStops && + stops_.size() <= kMaxUniformGradientStops) { + return RenderUniform(renderer, entity, pass); + } return RenderTexture(renderer, entity, pass); } @@ -310,6 +322,44 @@ bool LinearGradientContents::RenderSSBO(const ContentContext& renderer, }); } +bool LinearGradientContents::RenderUniform(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = LinearGradientUniformFillPipeline::VertexShader; + using FS = LinearGradientUniformFillPipeline::FragmentShader; + + VS::FrameInfo frame_info; + frame_info.matrix = GetInverseEffectTransform(); + + PipelineBuilderCallback pipeline_callback = + [&renderer](ContentContextOptions options) { + return renderer.GetLinearGradientUniformFillPipeline(options); + }; + return ColorSourceContents::DrawGeometry( + renderer, entity, pass, pipeline_callback, frame_info, + [this, &renderer, &entity](RenderPass& pass) { + FS::FragInfo frag_info; + frag_info.start_point = start_point_; + frag_info.start_to_end = end_point_ - start_point_; + frag_info.alpha = + GetOpacityFactor() * + GetGeometry()->ComputeAlphaCoverage(entity.GetTransform()); + frag_info.tile_mode = static_cast(tile_mode_); + frag_info.colors_length = PopulateUniformGradientColors( + colors_, stops_, frag_info.colors, frag_info.stop_pairs); + frag_info.inverse_dot_start_to_end = + CalculateInverseDotStartToEnd(start_point_, end_point_); + frag_info.decal_border_color = decal_border_color_; + + pass.SetCommandLabel("LinearGradientUniformFill"); + + FS::BindFragInfo( + pass, renderer.GetTransientsBuffer().EmplaceUniform(frag_info)); + + return true; + }); +} + bool LinearGradientContents::ApplyColorFilter( const ColorFilterProc& color_filter_proc) { for (Color& color : colors_) { diff --git a/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.h b/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.h index ae2e12f2bf..1aaccb1e43 100644 --- a/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.h +++ b/engine/src/flutter/impeller/entity/contents/linear_gradient_contents.h @@ -53,6 +53,10 @@ class LinearGradientContents final : public ColorSourceContents { const Entity& entity, RenderPass& pass) const; + bool RenderUniform(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + bool FastLinearGradient(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const; diff --git a/engine/src/flutter/impeller/entity/contents/radial_gradient_contents.cc b/engine/src/flutter/impeller/entity/contents/radial_gradient_contents.cc index 31fc52eee3..8fad640b1b 100644 --- a/engine/src/flutter/impeller/entity/contents/radial_gradient_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/radial_gradient_contents.cc @@ -55,12 +55,24 @@ bool RadialGradientContents::IsOpaque(const Matrix& transform) const { return !AppliesAlphaForStrokeCoverage(transform); } +#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0])) +#define UNIFORM_FRAG_INFO(t) \ + t##GradientUniformFillPipeline::FragmentShader::FragInfo +#define UNIFORM_COLOR_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Radial)::colors) +#define UNIFORM_STOP_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Radial)::stop_pairs) +static_assert(UNIFORM_COLOR_SIZE == kMaxUniformGradientStops); +static_assert(UNIFORM_STOP_SIZE == kMaxUniformGradientStops / 2); + bool RadialGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { if (renderer.GetDeviceCapabilities().SupportsSSBO()) { return RenderSSBO(renderer, entity, pass); } + if (colors_.size() <= kMaxUniformGradientStops && + stops_.size() <= kMaxUniformGradientStops) { + return RenderUniform(renderer, entity, pass); + } return RenderTexture(renderer, entity, pass); } @@ -106,6 +118,42 @@ bool RadialGradientContents::RenderSSBO(const ContentContext& renderer, }); } +bool RadialGradientContents::RenderUniform(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = RadialGradientUniformFillPipeline::VertexShader; + using FS = RadialGradientUniformFillPipeline::FragmentShader; + + VS::FrameInfo frame_info; + frame_info.matrix = GetInverseEffectTransform(); + + PipelineBuilderCallback pipeline_callback = + [&renderer](ContentContextOptions options) { + return renderer.GetRadialGradientUniformFillPipeline(options); + }; + return ColorSourceContents::DrawGeometry( + renderer, entity, pass, pipeline_callback, frame_info, + [this, &renderer, &entity](RenderPass& pass) { + FS::FragInfo frag_info; + frag_info.center = center_; + frag_info.radius = radius_; + frag_info.tile_mode = static_cast(tile_mode_); + frag_info.alpha = + GetOpacityFactor() * + GetGeometry()->ComputeAlphaCoverage(entity.GetTransform()); + frag_info.colors_length = PopulateUniformGradientColors( + colors_, stops_, frag_info.colors, frag_info.stop_pairs); + frag_info.decal_border_color = decal_border_color_; + + pass.SetCommandLabel("RadialGradientUniformFill"); + + FS::BindFragInfo( + pass, renderer.GetTransientsBuffer().EmplaceUniform(frag_info)); + + return true; + }); +} + bool RadialGradientContents::RenderTexture(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { diff --git a/engine/src/flutter/impeller/entity/contents/radial_gradient_contents.h b/engine/src/flutter/impeller/entity/contents/radial_gradient_contents.h index 21872d801f..f1cff5813c 100644 --- a/engine/src/flutter/impeller/entity/contents/radial_gradient_contents.h +++ b/engine/src/flutter/impeller/entity/contents/radial_gradient_contents.h @@ -52,6 +52,11 @@ class RadialGradientContents final : public ColorSourceContents { bool RenderSSBO(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const; + + bool RenderUniform(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + Point center_; Scalar radius_; std::vector colors_; diff --git a/engine/src/flutter/impeller/entity/contents/sweep_gradient_contents.cc b/engine/src/flutter/impeller/entity/contents/sweep_gradient_contents.cc index a26d5ac433..1dfa129220 100644 --- a/engine/src/flutter/impeller/entity/contents/sweep_gradient_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/sweep_gradient_contents.cc @@ -61,12 +61,24 @@ bool SweepGradientContents::IsOpaque(const Matrix& transform) const { return !AppliesAlphaForStrokeCoverage(transform); } +#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0])) +#define UNIFORM_FRAG_INFO(t) \ + t##GradientUniformFillPipeline::FragmentShader::FragInfo +#define UNIFORM_COLOR_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Sweep)::colors) +#define UNIFORM_STOP_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Sweep)::stop_pairs) +static_assert(UNIFORM_COLOR_SIZE == kMaxUniformGradientStops); +static_assert(UNIFORM_STOP_SIZE == kMaxUniformGradientStops / 2); + bool SweepGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { if (renderer.GetDeviceCapabilities().SupportsSSBO()) { return RenderSSBO(renderer, entity, pass); } + if (colors_.size() <= kMaxUniformGradientStops && + stops_.size() <= kMaxUniformGradientStops) { + return RenderUniform(renderer, entity, pass); + } return RenderTexture(renderer, entity, pass); } @@ -116,6 +128,46 @@ bool SweepGradientContents::RenderSSBO(const ContentContext& renderer, }); } +bool SweepGradientContents::RenderUniform(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = SweepGradientUniformFillPipeline::VertexShader; + using FS = SweepGradientUniformFillPipeline::FragmentShader; + + VS::FrameInfo frame_info; + frame_info.matrix = GetInverseEffectTransform(); + VS::BindFrameInfo(pass, + renderer.GetTransientsBuffer().EmplaceUniform(frame_info)); + + PipelineBuilderCallback pipeline_callback = + [&renderer](ContentContextOptions options) { + return renderer.GetSweepGradientUniformFillPipeline(options); + }; + return ColorSourceContents::DrawGeometry( + renderer, entity, pass, pipeline_callback, frame_info, + [this, &renderer, &entity](RenderPass& pass) { + FS::FragInfo frag_info; + frag_info.center = center_; + frag_info.bias = bias_; + frag_info.scale = scale_; + frag_info.tile_mode = static_cast(tile_mode_); + frag_info.alpha = + GetOpacityFactor() * + GetGeometry()->ComputeAlphaCoverage(entity.GetTransform()); + frag_info.colors_length = PopulateUniformGradientColors( + colors_, stops_, frag_info.colors, frag_info.stop_pairs); + + frag_info.decal_border_color = decal_border_color_; + + pass.SetCommandLabel("SweepGradientUniformFill"); + + FS::BindFragInfo( + pass, renderer.GetTransientsBuffer().EmplaceUniform(frag_info)); + + return true; + }); +} + bool SweepGradientContents::RenderTexture(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { diff --git a/engine/src/flutter/impeller/entity/contents/sweep_gradient_contents.h b/engine/src/flutter/impeller/entity/contents/sweep_gradient_contents.h index 81e643d660..d145987e19 100644 --- a/engine/src/flutter/impeller/entity/contents/sweep_gradient_contents.h +++ b/engine/src/flutter/impeller/entity/contents/sweep_gradient_contents.h @@ -54,6 +54,10 @@ class SweepGradientContents final : public ColorSourceContents { const Entity& entity, RenderPass& pass) const; + bool RenderUniform(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + Point center_; Scalar bias_; Scalar scale_; diff --git a/engine/src/flutter/impeller/entity/shaders/gradients/conical_gradient_uniform_fill.frag b/engine/src/flutter/impeller/entity/shaders/gradients/conical_gradient_uniform_fill.frag new file mode 100644 index 0000000000..b99f753e98 --- /dev/null +++ b/engine/src/flutter/impeller/entity/shaders/gradients/conical_gradient_uniform_fill.frag @@ -0,0 +1,68 @@ +// 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; + +#include +#include +#include +#include +#include + +uniform FragInfo { + highp vec2 center; + vec2 focus; + float focus_radius; + float radius; + float tile_mode; + float alpha; + float colors_length; + vec4 decal_border_color; + vec4 colors[256]; + vec4 stop_pairs[128]; +} +frag_info; + +highp in vec2 v_position; + +out vec4 frag_color; + +void main() { + vec2 res = IPComputeConicalT(frag_info.focus, frag_info.focus_radius, + frag_info.center, frag_info.radius, v_position); + + float t = res.x; + vec4 result_color = vec4(0); + if (res.y < 0.0 || + ((t < 0.0 || t > 1.0) && frag_info.tile_mode == kTileModeDecal)) { + result_color = frag_info.decal_border_color; + } else { + t = IPFloatTile(t, frag_info.tile_mode); + + vec2 prev_stop = frag_info.stop_pairs[0].xy; + bool even = false; + for (int i = 1; i < frag_info.colors_length; i++) { + // stop_pairs[i/2].xy = values for stop i + // stop_pairs[i/2].zw = values for stop i+1 + vec2 cur_stop = even ? frag_info.stop_pairs[i / 2].xy + : frag_info.stop_pairs[i / 2].zw; + even = !even; + // stop.x == t value + // stop.y == inverse_delta to next stop + if (t >= prev_stop.x && t <= cur_stop.x) { + if (cur_stop.y > 1000.0) { + result_color = frag_info.colors[i]; + } else { + float ratio = (t - prev_stop.x) * cur_stop.y; + result_color = + mix(frag_info.colors[i - 1], frag_info.colors[i], ratio); + } + break; + } + prev_stop = cur_stop; + } + } + + frag_color = IPPremultiply(result_color) * frag_info.alpha; +} diff --git a/engine/src/flutter/impeller/entity/shaders/gradients/linear_gradient_uniform_fill.frag b/engine/src/flutter/impeller/entity/shaders/gradients/linear_gradient_uniform_fill.frag new file mode 100644 index 0000000000..ace605876d --- /dev/null +++ b/engine/src/flutter/impeller/entity/shaders/gradients/linear_gradient_uniform_fill.frag @@ -0,0 +1,64 @@ +// 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; + +#include +#include +#include +#include +#include + +uniform FragInfo { + highp vec2 start_point; + highp vec2 start_to_end; + float alpha; + float tile_mode; + float colors_length; + float inverse_dot_start_to_end; + vec4 decal_border_color; + vec4 colors[256]; + vec4 stop_pairs[128]; +} +frag_info; + +highp in vec2 v_position; + +out vec4 frag_color; + +void main() { + highp vec2 start_to_position = v_position - frag_info.start_point; + 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; + } else { + t = IPFloatTile(t, frag_info.tile_mode); + + vec2 prev_stop = frag_info.stop_pairs[0].xy; + bool even = false; + for (int i = 1; i < frag_info.colors_length; i++) { + // stop_pairs[i/2].xy = values for stop i + // stop_pairs[i/2].zw = values for stop i+1 + vec2 cur_stop = even ? frag_info.stop_pairs[i / 2].xy + : frag_info.stop_pairs[i / 2].zw; + even = !even; + // stop.x == t value + // stop.y == inverse_delta to next stop + if (t >= prev_stop.x && t <= cur_stop.x) { + if (cur_stop.y > 1000.0) { + frag_color = frag_info.colors[i]; + } else { + float ratio = (t - prev_stop.x) * cur_stop.y; + frag_color = mix(frag_info.colors[i - 1], frag_info.colors[i], ratio); + } + break; + } + prev_stop = cur_stop; + } + } + + frag_color = IPPremultiply(frag_color) * frag_info.alpha; +} diff --git a/engine/src/flutter/impeller/entity/shaders/gradients/radial_gradient_uniform_fill.frag b/engine/src/flutter/impeller/entity/shaders/gradients/radial_gradient_uniform_fill.frag new file mode 100644 index 0000000000..f20163e686 --- /dev/null +++ b/engine/src/flutter/impeller/entity/shaders/gradients/radial_gradient_uniform_fill.frag @@ -0,0 +1,64 @@ +// 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; + +#include +#include +#include +#include +#include + +uniform FragInfo { + highp vec2 center; + float radius; + float tile_mode; + float alpha; + float colors_length; + vec4 decal_border_color; + vec4 colors[256]; + vec4 stop_pairs[128]; +} +frag_info; + +highp in vec2 v_position; + +out vec4 frag_color; + +void main() { + float len = length(v_position - frag_info.center); + float t = len / frag_info.radius; + + vec4 result_color = vec4(0); + if ((t < 0.0 || t > 1.0) && frag_info.tile_mode == kTileModeDecal) { + result_color = frag_info.decal_border_color; + } else { + t = IPFloatTile(t, frag_info.tile_mode); + + vec2 prev_stop = frag_info.stop_pairs[0].xy; + bool even = false; + for (int i = 1; i < frag_info.colors_length; i++) { + // stop_pairs[i/2].xy = values for stop i + // stop_pairs[i/2].zw = values for stop i+1 + vec2 cur_stop = even ? frag_info.stop_pairs[i / 2].xy + : frag_info.stop_pairs[i / 2].zw; + even = !even; + // stop.x == t value + // stop.y == inverse_delta to next stop + if (t >= prev_stop.x && t <= cur_stop.x) { + if (cur_stop.y > 1000.0) { + result_color = frag_info.colors[i]; + } else { + float ratio = (t - prev_stop.x) * cur_stop.y; + result_color = + mix(frag_info.colors[i - 1], frag_info.colors[i], ratio); + } + break; + } + prev_stop = cur_stop; + } + } + + frag_color = IPPremultiply(result_color) * frag_info.alpha; +} diff --git a/engine/src/flutter/impeller/entity/shaders/gradients/sweep_gradient_uniform_fill.frag b/engine/src/flutter/impeller/entity/shaders/gradients/sweep_gradient_uniform_fill.frag new file mode 100644 index 0000000000..d25b62c5ba --- /dev/null +++ b/engine/src/flutter/impeller/entity/shaders/gradients/sweep_gradient_uniform_fill.frag @@ -0,0 +1,65 @@ +// 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 +#include +#include + +uniform FragInfo { + highp vec2 center; + float bias; + float scale; + float tile_mode; + float alpha; + float colors_length; + vec4 decal_border_color; + vec4 colors[256]; + vec4 stop_pairs[128]; +} +frag_info; + +highp in vec2 v_position; + +out vec4 frag_color; + +void main() { + vec2 coord = v_position - frag_info.center; + float angle = atan(-coord.y, -coord.x); + float t = (angle * k1Over2Pi + 0.5 + frag_info.bias) * frag_info.scale; + + vec4 result_color = vec4(0); + if ((t < 0.0 || t > 1.0) && frag_info.tile_mode == kTileModeDecal) { + result_color = frag_info.decal_border_color; + } else { + t = IPFloatTile(t, frag_info.tile_mode); + + vec2 prev_stop = frag_info.stop_pairs[0].xy; + bool even = false; + for (int i = 1; i < frag_info.colors_length; i++) { + // stop_pairs[i/2].xy = values for stop i + // stop_pairs[i/2].zw = values for stop i+1 + vec2 cur_stop = even ? frag_info.stop_pairs[i / 2].xy + : frag_info.stop_pairs[i / 2].zw; + even = !even; + // stop.x == t value + // stop.y == inverse_delta to next stop + if (t >= prev_stop.x && t <= cur_stop.x) { + if (cur_stop.y > 1000.0) { + result_color = frag_info.colors[i]; + } else { + float ratio = (t - prev_stop.x) * cur_stop.y; + result_color = + mix(frag_info.colors[i - 1], frag_info.colors[i], ratio); + } + break; + } + prev_stop = cur_stop; + } + } + + frag_color = IPPremultiply(result_color) * frag_info.alpha; +} diff --git a/engine/src/flutter/impeller/tools/malioc.json b/engine/src/flutter/impeller/tools/malioc.json index 21d6567c74..96e0defe7a 100644 --- a/engine/src/flutter/impeller/tools/malioc.json +++ b/engine/src/flutter/impeller/tools/malioc.json @@ -613,6 +613,76 @@ } } }, + "flutter/impeller/entity/conical_gradient_uniform_fill.frag.vkspv": { + "Mali-G78": { + "core": "Mali-G78", + "filename": "flutter/impeller/entity/conical_gradient_uniform_fill.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": 70, + "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": [ + "varying" + ], + "shortest_path_cycles": [ + 0.1875, + 0.0625, + 0.1875, + 0.0, + 0.0, + 0.25, + 0.0 + ], + "total_bound_pipelines": [ + "load_store" + ], + "total_cycles": [ + 1.5499999523162842, + 0.800000011920929, + 1.5499999523162842, + 0.5, + 4.0, + 0.25, + 0.0 + ] + }, + "stack_spill_bytes": 0, + "thread_occupancy": 100, + "uniform_registers_used": 36, + "work_registers_used": 18 + } + } + } + }, "flutter/impeller/entity/fast_gradient.frag.vkspv": { "Mali-G78": { "core": "Mali-G78", @@ -1951,6 +2021,121 @@ } } }, + "flutter/impeller/entity/gles/conical_gradient_uniform_fill.frag.gles": { + "Mali-G78": { + "core": "Mali-G78", + "filename": "flutter/impeller/entity/gles/conical_gradient_uniform_fill.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": 62, + "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": [ + "varying" + ], + "shortest_path_cycles": [ + 0.1875, + 0.0625, + 0.1875, + 0.0, + 0.0, + 0.25, + 0.0 + ], + "total_bound_pipelines": [ + "load_store" + ], + "total_cycles": [ + 1.40625, + 0.84375, + 1.40625, + 0.4375, + 4.0, + 0.25, + 0.0 + ] + }, + "stack_spill_bytes": 0, + "thread_occupancy": 100, + "uniform_registers_used": 38, + "work_registers_used": 21 + } + } + }, + "Mali-T880": { + "core": "Mali-T880", + "filename": "flutter/impeller/entity/gles/conical_gradient_uniform_fill.frag.gles", + "has_uniform_computation": true, + "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" + ], + "shortest_path_cycles": [ + 1.649999976158142, + 1.0, + 0.0 + ], + "total_bound_pipelines": [ + "arithmetic" + ], + "total_cycles": [ + 20.66666603088379, + 4.0, + 0.0 + ] + }, + "thread_occupancy": 100, + "uniform_registers_used": 6, + "work_registers_used": 3 + } + } + } + }, "flutter/impeller/entity/gles/fast_gradient.frag.gles": { "Mali-G78": { "core": "Mali-G78", @@ -3210,6 +3395,121 @@ } } }, + "flutter/impeller/entity/gles/linear_gradient_uniform_fill.frag.gles": { + "Mali-G78": { + "core": "Mali-G78", + "filename": "flutter/impeller/entity/gles/linear_gradient_uniform_fill.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": 13, + "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": [ + "varying" + ], + "shortest_path_cycles": [ + 0.203125, + 0.203125, + 0.171875, + 0.0625, + 0.0, + 0.25, + 0.0 + ], + "total_bound_pipelines": [ + "load_store" + ], + "total_cycles": [ + 0.8125, + 0.46875, + 0.8125, + 0.1875, + 4.0, + 0.25, + 0.0 + ] + }, + "stack_spill_bytes": 0, + "thread_occupancy": 100, + "uniform_registers_used": 12, + "work_registers_used": 21 + } + } + }, + "Mali-T880": { + "core": "Mali-T880", + "filename": "flutter/impeller/entity/gles/linear_gradient_uniform_fill.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" + ], + "shortest_path_cycles": [ + 2.640000104904175, + 1.0, + 0.0 + ], + "total_bound_pipelines": [ + "arithmetic" + ], + "total_cycles": [ + 10.0, + 4.0, + 0.0 + ] + }, + "thread_occupancy": 100, + "uniform_registers_used": 3, + "work_registers_used": 3 + } + } + } + }, "flutter/impeller/entity/gles/linear_to_srgb_filter.frag.gles": { "Mali-G78": { "core": "Mali-G78", @@ -3837,6 +4137,121 @@ } } }, + "flutter/impeller/entity/gles/radial_gradient_uniform_fill.frag.gles": { + "Mali-G78": { + "core": "Mali-G78", + "filename": "flutter/impeller/entity/gles/radial_gradient_uniform_fill.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": 67, + "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": [ + "varying" + ], + "shortest_path_cycles": [ + 0.1875, + 0.171875, + 0.1875, + 0.0625, + 0.0, + 0.25, + 0.0 + ], + "total_bound_pipelines": [ + "load_store" + ], + "total_cycles": [ + 0.762499988079071, + 0.359375, + 0.762499988079071, + 0.1875, + 4.0, + 0.25, + 0.0 + ] + }, + "stack_spill_bytes": 0, + "thread_occupancy": 100, + "uniform_registers_used": 10, + "work_registers_used": 21 + } + } + }, + "Mali-T880": { + "core": "Mali-T880", + "filename": "flutter/impeller/entity/gles/radial_gradient_uniform_fill.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" + ], + "shortest_path_cycles": [ + 2.640000104904175, + 1.0, + 0.0 + ], + "total_bound_pipelines": [ + "arithmetic" + ], + "total_cycles": [ + 9.666666984558105, + 4.0, + 0.0 + ] + }, + "thread_occupancy": 100, + "uniform_registers_used": 2, + "work_registers_used": 3 + } + } + } + }, "flutter/impeller/entity/gles/rrect_blur.frag.gles": { "Mali-G78": { "core": "Mali-G78", @@ -4730,6 +5145,122 @@ } } }, + "flutter/impeller/entity/gles/sweep_gradient_uniform_fill.frag.gles": { + "Mali-G78": { + "core": "Mali-G78", + "filename": "flutter/impeller/entity/gles/sweep_gradient_uniform_fill.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": 0, + "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_fma" + ], + "shortest_path_cycles": [ + 0.375, + 0.375, + 0.25, + 0.3125, + 0.0, + 0.25, + 0.0 + ], + "total_bound_pipelines": [ + "load_store" + ], + "total_cycles": [ + 0.925000011920929, + 0.625, + 0.925000011920929, + 0.4375, + 4.0, + 0.25, + 0.0 + ] + }, + "stack_spill_bytes": 0, + "thread_occupancy": 100, + "uniform_registers_used": 20, + "work_registers_used": 25 + } + } + }, + "Mali-T880": { + "core": "Mali-T880", + "filename": "flutter/impeller/entity/gles/sweep_gradient_uniform_fill.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" + ], + "shortest_path_cycles": [ + 2.9700000286102295, + 1.0, + 0.0 + ], + "total_bound_pipelines": [ + "arithmetic" + ], + "total_cycles": [ + 10.333333015441895, + 5.0, + 0.0 + ] + }, + "thread_occupancy": 100, + "uniform_registers_used": 3, + "work_registers_used": 3 + } + } + } + }, "flutter/impeller/entity/gles/texture_downsample.frag.gles": { "Mali-G78": { "core": "Mali-G78", @@ -6443,6 +6974,76 @@ } } }, + "flutter/impeller/entity/linear_gradient_uniform_fill.frag.vkspv": { + "Mali-G78": { + "core": "Mali-G78", + "filename": "flutter/impeller/entity/linear_gradient_uniform_fill.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": 35, + "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": [ + "varying" + ], + "shortest_path_cycles": [ + 0.15625, + 0.15625, + 0.15625, + 0.0625, + 0.0, + 0.25, + 0.0 + ], + "total_bound_pipelines": [ + "load_store" + ], + "total_cycles": [ + 0.84375, + 0.359375, + 0.84375, + 0.25, + 4.0, + 0.25, + 0.0 + ] + }, + "stack_spill_bytes": 0, + "thread_occupancy": 100, + "uniform_registers_used": 14, + "work_registers_used": 18 + } + } + } + }, "flutter/impeller/entity/linear_to_srgb_filter.frag.vkspv": { "Mali-G78": { "core": "Mali-G78", @@ -6913,6 +7514,76 @@ } } }, + "flutter/impeller/entity/radial_gradient_uniform_fill.frag.vkspv": { + "Mali-G78": { + "core": "Mali-G78", + "filename": "flutter/impeller/entity/radial_gradient_uniform_fill.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": 58, + "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": [ + "varying" + ], + "shortest_path_cycles": [ + 0.171875, + 0.171875, + 0.171875, + 0.0625, + 0.0, + 0.25, + 0.0 + ], + "total_bound_pipelines": [ + "load_store" + ], + "total_cycles": [ + 0.84375, + 0.359375, + 0.84375, + 0.25, + 4.0, + 0.25, + 0.0 + ] + }, + "stack_spill_bytes": 0, + "thread_occupancy": 100, + "uniform_registers_used": 12, + "work_registers_used": 18 + } + } + } + }, "flutter/impeller/entity/rrect_blur.frag.vkspv": { "Mali-G78": { "core": "Mali-G78", @@ -7561,6 +8232,77 @@ } } }, + "flutter/impeller/entity/sweep_gradient_uniform_fill.frag.vkspv": { + "Mali-G78": { + "core": "Mali-G78", + "filename": "flutter/impeller/entity/sweep_gradient_uniform_fill.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": 0, + "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_fma" + ], + "shortest_path_cycles": [ + 0.390625, + 0.390625, + 0.25, + 0.3125, + 0.0, + 0.25, + 0.0 + ], + "total_bound_pipelines": [ + "load_store" + ], + "total_cycles": [ + 0.875, + 0.637499988079071, + 0.875, + 0.5, + 4.0, + 0.25, + 0.0 + ] + }, + "stack_spill_bytes": 0, + "thread_occupancy": 100, + "uniform_registers_used": 20, + "work_registers_used": 23 + } + } + } + }, "flutter/impeller/entity/texture_downsample.frag.vkspv": { "Mali-G78": { "core": "Mali-G78", diff --git a/engine/src/flutter/testing/impeller_golden_tests_output.txt b/engine/src/flutter/testing/impeller_golden_tests_output.txt index 58897eb922..fddecde080 100644 --- a/engine/src/flutter/testing/impeller_golden_tests_output.txt +++ b/engine/src/flutter/testing/impeller_golden_tests_output.txt @@ -289,6 +289,9 @@ impeller_Play_AiksTest_CanRenderColoredRect_Vulkan.png impeller_Play_AiksTest_CanRenderConicalGradientWithDitheringEnabled_Metal.png impeller_Play_AiksTest_CanRenderConicalGradientWithDitheringEnabled_OpenGLES.png impeller_Play_AiksTest_CanRenderConicalGradientWithDitheringEnabled_Vulkan.png +impeller_Play_AiksTest_CanRenderConicalGradientWithIncompleteStops_Metal.png +impeller_Play_AiksTest_CanRenderConicalGradientWithIncompleteStops_OpenGLES.png +impeller_Play_AiksTest_CanRenderConicalGradientWithIncompleteStops_Vulkan.png impeller_Play_AiksTest_CanRenderConicalGradient_Metal.png impeller_Play_AiksTest_CanRenderConicalGradient_OpenGLES.png impeller_Play_AiksTest_CanRenderConicalGradient_Vulkan.png @@ -382,6 +385,9 @@ impeller_Play_AiksTest_CanRenderLinearGradientWayManyColorsClamp_Vulkan.png impeller_Play_AiksTest_CanRenderLinearGradientWithDitheringEnabled_Metal.png impeller_Play_AiksTest_CanRenderLinearGradientWithDitheringEnabled_OpenGLES.png impeller_Play_AiksTest_CanRenderLinearGradientWithDitheringEnabled_Vulkan.png +impeller_Play_AiksTest_CanRenderLinearGradientWithIncompleteStops_Metal.png +impeller_Play_AiksTest_CanRenderLinearGradientWithIncompleteStops_OpenGLES.png +impeller_Play_AiksTest_CanRenderLinearGradientWithIncompleteStops_Vulkan.png impeller_Play_AiksTest_CanRenderLinearGradientWithOverlappingStopsClamp_Metal.png impeller_Play_AiksTest_CanRenderLinearGradientWithOverlappingStopsClamp_OpenGLES.png impeller_Play_AiksTest_CanRenderLinearGradientWithOverlappingStopsClamp_Vulkan.png @@ -412,6 +418,9 @@ impeller_Play_AiksTest_CanRenderRadialGradientManyColors_Vulkan.png impeller_Play_AiksTest_CanRenderRadialGradientWithDitheringEnabled_Metal.png impeller_Play_AiksTest_CanRenderRadialGradientWithDitheringEnabled_OpenGLES.png impeller_Play_AiksTest_CanRenderRadialGradientWithDitheringEnabled_Vulkan.png +impeller_Play_AiksTest_CanRenderRadialGradientWithIncompleteStops_Metal.png +impeller_Play_AiksTest_CanRenderRadialGradientWithIncompleteStops_OpenGLES.png +impeller_Play_AiksTest_CanRenderRadialGradientWithIncompleteStops_Vulkan.png impeller_Play_AiksTest_CanRenderRadialGradient_Metal.png impeller_Play_AiksTest_CanRenderRadialGradient_OpenGLES.png impeller_Play_AiksTest_CanRenderRadialGradient_Vulkan.png @@ -463,6 +472,9 @@ impeller_Play_AiksTest_CanRenderSweepGradientRepeat_Vulkan.png impeller_Play_AiksTest_CanRenderSweepGradientWithDitheringEnabled_Metal.png impeller_Play_AiksTest_CanRenderSweepGradientWithDitheringEnabled_OpenGLES.png impeller_Play_AiksTest_CanRenderSweepGradientWithDitheringEnabled_Vulkan.png +impeller_Play_AiksTest_CanRenderSweepGradientWithIncompleteStops_Metal.png +impeller_Play_AiksTest_CanRenderSweepGradientWithIncompleteStops_OpenGLES.png +impeller_Play_AiksTest_CanRenderSweepGradientWithIncompleteStops_Vulkan.png impeller_Play_AiksTest_CanRenderTextFrameWithFractionScaling_Metal.png impeller_Play_AiksTest_CanRenderTextFrameWithFractionScaling_OpenGLES.png impeller_Play_AiksTest_CanRenderTextFrameWithFractionScaling_Vulkan.png