From ac5289a37f86c24e00f005d66b31a85d3bd31fc5 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 15 Nov 2022 16:28:06 -0800 Subject: [PATCH 01/16] [Impeller] use uniform array for more efficient small gradients --- impeller/entity/BUILD.gn | 1 + impeller/entity/contents/content_context.cc | 2 + impeller/entity/contents/content_context.h | 9 +++ .../entity/contents/gradient_generator.cc | 5 +- impeller/entity/contents/gradient_generator.h | 6 +- .../contents/linear_gradient_contents.cc | 64 ++++++++++++++++++- .../contents/linear_gradient_contents.h | 11 ++++ .../contents/radial_gradient_contents.cc | 4 +- .../contents/sweep_gradient_contents.cc | 4 +- .../shaders/linear_gradient_fixed_fill.frag | 47 ++++++++++++++ impeller/geometry/gradient.cc | 45 +++++++------ impeller/geometry/gradient.h | 1 + 12 files changed, 171 insertions(+), 28 deletions(-) create mode 100644 impeller/entity/shaders/linear_gradient_fixed_fill.frag diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 1175f5daef889..f315b6ef98022 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -42,6 +42,7 @@ impeller_shaders("entity_shaders") { "shaders/linear_to_srgb_filter.frag", "shaders/linear_to_srgb_filter.vert", "shaders/linear_gradient_fill.frag", + "shaders/linear_gradient_fixed_fill.frag", "shaders/morphology_filter.frag", "shaders/morphology_filter.vert", "shaders/position_color.vert", diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index dbc6fec50527e..1b76a00bec4d3 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -155,6 +155,8 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); linear_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); + linear_gradient_fixed_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); radial_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); sweep_gradient_fill_pipelines_[{}] = diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 07c875bfe5a74..5e0661c628633 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -63,6 +63,7 @@ #include "impeller/entity/vertices.frag.h" #include "impeller/entity/yuv_to_rgb_filter.frag.h" #include "impeller/entity/yuv_to_rgb_filter.vert.h" +#include "impeller/entity/linear_gradient_fixed_fill.frag.h" #include "impeller/renderer/formats.h" #include "impeller/renderer/pipeline.h" @@ -76,6 +77,8 @@ namespace impeller { using LinearGradientFillPipeline = RenderPipelineT; +using LinearGradientFixedFillPipeline = + RenderPipelineT; using SolidFillPipeline = RenderPipelineT; using RadialGradientFillPipeline = @@ -210,6 +213,11 @@ class ContentContext { return GetPipeline(linear_gradient_fill_pipelines_, opts); } + std::shared_ptr> GetLinearGradientFixedFillPipeline( + ContentContextOptions opts) const { + return GetPipeline(linear_gradient_fixed_fill_pipelines_, opts); + } + std::shared_ptr> GetRadialGradientFillPipeline( ContentContextOptions opts) const { return GetPipeline(radial_gradient_fill_pipelines_, opts); @@ -414,6 +422,7 @@ class ContentContext { // map. mutable Variants solid_fill_pipelines_; mutable Variants linear_gradient_fill_pipelines_; + mutable Variants linear_gradient_fixed_fill_pipelines_; mutable Variants radial_gradient_fill_pipelines_; mutable Variants sweep_gradient_fill_pipelines_; mutable Variants rrect_blur_pipelines_; diff --git a/impeller/entity/contents/gradient_generator.cc b/impeller/entity/contents/gradient_generator.cc index f5fd4c70343fb..6a53719a90594 100644 --- a/impeller/entity/contents/gradient_generator.cc +++ b/impeller/entity/contents/gradient_generator.cc @@ -8,7 +8,6 @@ #include "flutter/fml/logging.h" #include "impeller/entity/contents/content_context.h" -#include "impeller/geometry/gradient.h" #include "impeller/renderer/context.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/texture.h" @@ -16,10 +15,8 @@ namespace impeller { std::shared_ptr CreateGradientTexture( - const std::vector& colors, - const std::vector& stops, + const GradientData& gradient_data, const std::shared_ptr& context) { - auto gradient_data = CreateGradientBuffer(colors, stops); if (gradient_data.texture_size == 0) { FML_DLOG(ERROR) << "Invalid gradient data."; return nullptr; diff --git a/impeller/entity/contents/gradient_generator.h b/impeller/entity/contents/gradient_generator.h index 1110da56837ea..15e1ec4f1447b 100644 --- a/impeller/entity/contents/gradient_generator.h +++ b/impeller/entity/contents/gradient_generator.h @@ -13,6 +13,7 @@ #include "impeller/geometry/color.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" +#include "impeller/geometry/gradient.h" namespace impeller { @@ -20,11 +21,10 @@ class Context; /** * @brief Create a host visible texture that contains the gradient defined - * by the provided colors and stops. + * by the provided gradient data. */ std::shared_ptr CreateGradientTexture( - const std::vector& colors, - const std::vector& stops, + const GradientData& gradient_data, const std::shared_ptr& context); } // namespace impeller diff --git a/impeller/entity/contents/linear_gradient_contents.cc b/impeller/entity/contents/linear_gradient_contents.cc index 52973daff34f1..42b55e2af94a3 100644 --- a/impeller/entity/contents/linear_gradient_contents.cc +++ b/impeller/entity/contents/linear_gradient_contents.cc @@ -47,11 +47,22 @@ void LinearGradientContents::SetTileMode(Entity::TileMode tile_mode) { bool LinearGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { + auto gradient_data = CreateGradientBuffer(colors_, stops_); + if (gradient_data.texture_size < 16) { + return RenderTexture(gradient_data, renderer, entity, pass); + } + return RenderFixed(gradient_data, renderer, entity, pass); +} + +bool LinearGradientContents::RenderTexture(const GradientData& gradient_data, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { using VS = LinearGradientFillPipeline::VertexShader; using FS = LinearGradientFillPipeline::FragmentShader; auto gradient_texture = - CreateGradientTexture(colors_, stops_, renderer.GetContext()); + CreateGradientTexture(gradient_data, renderer.GetContext()); if (gradient_texture == nullptr) { return false; } @@ -106,4 +117,55 @@ bool LinearGradientContents::Render(const ContentContext& renderer, return true; } +bool LinearGradientContents::RenderFixed(const GradientData& gradient_data, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = LinearGradientFixedFillPipeline::VertexShader; + using FS = LinearGradientFixedFillPipeline::FragmentShader; + + FS::GradientInfo gradient_info; + gradient_info.start_point = start_point_; + gradient_info.end_point = end_point_; + gradient_info.tile_mode = static_cast(tile_mode_); + gradient_info.alpha = GetAlpha(); + gradient_info.colors_length = gradient_data.texture_size; + for (auto i = 0u; i < gradient_data.colors.size(); i++) { + gradient_info.colors[i] = gradient_data.colors[i]; + } + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + frame_info.matrix = GetInverseMatrix(); + + Command cmd; + cmd.label = "LinearGradientFixedFill"; + cmd.stencil_reference = entity.GetStencilDepth(); + + auto geometry_result = + GetGeometry()->GetPositionBuffer(renderer, entity, pass); + auto options = OptionsFromPassAndEntity(pass, entity); + if (geometry_result.prevent_overdraw) { + options.stencil_compare = CompareFunction::kEqual; + options.stencil_operation = StencilOperation::kIncrementClamp; + } + options.primitive_type = geometry_result.type; + cmd.pipeline = renderer.GetLinearGradientFixedFillPipeline(options); + + cmd.BindVertices(geometry_result.vertex_buffer); + FS::BindGradientInfo( + cmd, pass.GetTransientsBuffer().EmplaceUniform(gradient_info)); + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + + if (!pass.AddCommand(std::move(cmd))) { + return false; + } + + if (geometry_result.prevent_overdraw) { + return ClipRestoreContents().Render(renderer, entity, pass); + } + return true; +} + } // namespace impeller diff --git a/impeller/entity/contents/linear_gradient_contents.h b/impeller/entity/contents/linear_gradient_contents.h index fbc9ec15f545d..4bb7c09e0385a 100644 --- a/impeller/entity/contents/linear_gradient_contents.h +++ b/impeller/entity/contents/linear_gradient_contents.h @@ -13,6 +13,7 @@ #include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/color.h" +#include "impeller/geometry/gradient.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" @@ -42,6 +43,16 @@ class LinearGradientContents final : public ColorSourceContents { void SetTileMode(Entity::TileMode tile_mode); private: + bool RenderTexture(const GradientData& gradient_data, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + + bool RenderFixed(const GradientData& gradient_data, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + Point start_point_; Point end_point_; std::vector colors_; diff --git a/impeller/entity/contents/radial_gradient_contents.cc b/impeller/entity/contents/radial_gradient_contents.cc index d21dc540fb7dc..c0188aa8eba8f 100644 --- a/impeller/entity/contents/radial_gradient_contents.cc +++ b/impeller/entity/contents/radial_gradient_contents.cc @@ -12,6 +12,7 @@ #include "impeller/entity/geometry.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/sampler_library.h" +#include "impeller/geometry/gradient.h" namespace impeller { @@ -50,8 +51,9 @@ bool RadialGradientContents::Render(const ContentContext& renderer, using VS = RadialGradientFillPipeline::VertexShader; using FS = RadialGradientFillPipeline::FragmentShader; + auto gradient_data = CreateGradientBuffer(colors_, stops_); auto gradient_texture = - CreateGradientTexture(colors_, stops_, renderer.GetContext()); + CreateGradientTexture(gradient_data, renderer.GetContext()); if (gradient_texture == nullptr) { return false; } diff --git a/impeller/entity/contents/sweep_gradient_contents.cc b/impeller/entity/contents/sweep_gradient_contents.cc index 43ae975ffd3dd..01be6fda01d51 100644 --- a/impeller/entity/contents/sweep_gradient_contents.cc +++ b/impeller/entity/contents/sweep_gradient_contents.cc @@ -11,6 +11,7 @@ #include "impeller/entity/entity.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/sampler_library.h" +#include "impeller/geometry/gradient.h" namespace impeller { @@ -55,8 +56,9 @@ bool SweepGradientContents::Render(const ContentContext& renderer, using VS = SweepGradientFillPipeline::VertexShader; using FS = SweepGradientFillPipeline::FragmentShader; + auto gradient_data = CreateGradientBuffer(colors_, stops_); auto gradient_texture = - CreateGradientTexture(colors_, stops_, renderer.GetContext()); + CreateGradientTexture(gradient_data, renderer.GetContext()); if (gradient_texture == nullptr) { return false; } diff --git a/impeller/entity/shaders/linear_gradient_fixed_fill.frag b/impeller/entity/shaders/linear_gradient_fixed_fill.frag new file mode 100644 index 0000000000000..c01a0c7580f17 --- /dev/null +++ b/impeller/entity/shaders/linear_gradient_fixed_fill.frag @@ -0,0 +1,47 @@ +// 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 + +uniform GradientInfo { + vec2 start_point; + vec2 end_point; + float alpha; + float tile_mode; + float colors_length; + vec4 colors[16]; +} gradient_info; + +in vec2 v_position; + +out vec4 frag_color; + +void main() { + float len = length(gradient_info.end_point - gradient_info.start_point); + float dot = dot( + v_position - gradient_info.start_point, + gradient_info.end_point - gradient_info.start_point + ); + float t = dot / (len * len); + if ((t < 0.0 || t > 1.0) && gradient_info.tile_mode == kTileModeDecal) { + frag_color = vec4(0); + return; + } + + t = IPFloatTile(t, gradient_info.tile_mode); + if (gradient_info.colors_length == 2) { + frag_color = mix(gradient_info.colors[0], gradient_info.colors[1], t); + return; + } + if (t == 1.0) { + frag_color = gradient_info.colors[int(gradient_info.colors_length) - 1]; + return; + } + + float rough_index = gradient_info.colors_length * t; + float lower_index = floor(rough_index); + float scale = rough_index - lower_index; + + frag_color = mix(gradient_info.colors[int(lower_index)], gradient_info.colors[int(lower_index + 1)], scale); +} diff --git a/impeller/geometry/gradient.cc b/impeller/geometry/gradient.cc index 086d90c2e68b4..40a539dba6079 100644 --- a/impeller/geometry/gradient.cc +++ b/impeller/geometry/gradient.cc @@ -9,12 +9,16 @@ namespace impeller { -static void AppendColor(const Color& color, std::vector* colors) { - auto converted = color.ToR8G8B8A8(); - colors->push_back(converted[0]); - colors->push_back(converted[1]); - colors->push_back(converted[2]); - colors->push_back(converted[3]); +static void AppendColor(const Color& color, GradientData* data) { + if (data->texture_size > 16) { + auto converted = color.ToR8G8B8A8(); + data->color_bytes.push_back(converted[0]); + data->color_bytes.push_back(converted[1]); + data->color_bytes.push_back(converted[2]); + data->color_bytes.push_back(converted[3]); + } else { + data->colors.push_back(color); + } } GradientData CreateGradientBuffer(const std::vector& colors, @@ -43,12 +47,20 @@ GradientData CreateGradientBuffer(const std::vector& colors, texture_size = std::min( static_cast(std::round(1.0 / minimum_delta)) + 1, 1024u); } - std::vector color_stop_channels; - color_stop_channels.reserve(texture_size * 4); + GradientData data = { + .color_bytes = {}, + .colors = {}, + .texture_size = texture_size, + }; + if (texture_size > 16) { + data.color_bytes.reserve(texture_size * 4); + } else { + data.colors.reserve(texture_size); + } if (texture_size == colors.size() && colors.size() <= 1024) { for (auto i = 0u; i < colors.size(); i++) { - AppendColor(colors[i], &color_stop_channels); + AppendColor(colors[i], &data); } } else { Color previous_color = colors[0]; @@ -56,7 +68,7 @@ GradientData CreateGradientBuffer(const std::vector& colors, auto previous_color_index = 0; // The first index is always equal to the first color, exactly. - AppendColor(previous_color, &color_stop_channels); + AppendColor(previous_color, &data); for (auto i = 1u; i < texture_size - 1; i++) { auto scaled_i = i / (texture_size - 1.0); @@ -64,7 +76,7 @@ GradientData CreateGradientBuffer(const std::vector& colors, auto next_stop = stops[previous_color_index + 1]; // We're almost exactly equal to the next stop. if (ScalarNearlyEqual(scaled_i, next_stop)) { - AppendColor(next_color, &color_stop_channels); + AppendColor(next_color, &data); previous_color = next_color; previous_stop = next_stop; @@ -74,7 +86,7 @@ GradientData CreateGradientBuffer(const std::vector& colors, auto t = (scaled_i - previous_stop) / (next_stop - previous_stop); auto mixed_color = Color::lerp(previous_color, next_color, t); - AppendColor(mixed_color, &color_stop_channels); + AppendColor(mixed_color, &data); } else { // We've slightly overshot the previous stop. previous_color = next_color; @@ -86,16 +98,13 @@ GradientData CreateGradientBuffer(const std::vector& colors, auto t = (scaled_i - previous_stop) / (next_stop - previous_stop); auto mixed_color = Color::lerp(previous_color, next_color, t); - AppendColor(mixed_color, &color_stop_channels); + AppendColor(mixed_color, &data); } } // The last index is always equal to the last color, exactly. - AppendColor(colors.back(), &color_stop_channels); + AppendColor(colors.back(), &data); } - return GradientData{ - .color_bytes = std::move(color_stop_channels), - .texture_size = texture_size, - }; + return data; } } // namespace impeller diff --git a/impeller/geometry/gradient.h b/impeller/geometry/gradient.h index d9f943de77177..aec240d91e252 100644 --- a/impeller/geometry/gradient.h +++ b/impeller/geometry/gradient.h @@ -16,6 +16,7 @@ namespace impeller { // If texture_size is 0 then the gradient is invalid. struct GradientData { std::vector color_bytes; + std::vector colors; uint32_t texture_size; }; From a99311789db2d8af7bd0eba65ca815841c861fc3 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 15 Nov 2022 16:29:19 -0800 Subject: [PATCH 02/16] ++ --- impeller/entity/contents/content_context.h | 12 +++++++----- impeller/entity/contents/gradient_generator.h | 2 +- impeller/entity/contents/linear_gradient_contents.cc | 2 +- impeller/entity/contents/radial_gradient_contents.cc | 2 +- impeller/entity/contents/sweep_gradient_contents.cc | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 5e0661c628633..73e43a988714b 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -44,6 +44,7 @@ #include "impeller/entity/glyph_atlas_sdf.vert.h" #include "impeller/entity/gradient_fill.vert.h" #include "impeller/entity/linear_gradient_fill.frag.h" +#include "impeller/entity/linear_gradient_fixed_fill.frag.h" #include "impeller/entity/linear_to_srgb_filter.frag.h" #include "impeller/entity/linear_to_srgb_filter.vert.h" #include "impeller/entity/morphology_filter.frag.h" @@ -63,7 +64,6 @@ #include "impeller/entity/vertices.frag.h" #include "impeller/entity/yuv_to_rgb_filter.frag.h" #include "impeller/entity/yuv_to_rgb_filter.vert.h" -#include "impeller/entity/linear_gradient_fixed_fill.frag.h" #include "impeller/renderer/formats.h" #include "impeller/renderer/pipeline.h" @@ -78,7 +78,8 @@ namespace impeller { using LinearGradientFillPipeline = RenderPipelineT; using LinearGradientFixedFillPipeline = - RenderPipelineT; + RenderPipelineT; using SolidFillPipeline = RenderPipelineT; using RadialGradientFillPipeline = @@ -213,8 +214,8 @@ class ContentContext { return GetPipeline(linear_gradient_fill_pipelines_, opts); } - std::shared_ptr> GetLinearGradientFixedFillPipeline( - ContentContextOptions opts) const { + std::shared_ptr> + GetLinearGradientFixedFillPipeline(ContentContextOptions opts) const { return GetPipeline(linear_gradient_fixed_fill_pipelines_, opts); } @@ -422,7 +423,8 @@ class ContentContext { // map. mutable Variants solid_fill_pipelines_; mutable Variants linear_gradient_fill_pipelines_; - mutable Variants linear_gradient_fixed_fill_pipelines_; + mutable Variants + linear_gradient_fixed_fill_pipelines_; mutable Variants radial_gradient_fill_pipelines_; mutable Variants sweep_gradient_fill_pipelines_; mutable Variants rrect_blur_pipelines_; diff --git a/impeller/entity/contents/gradient_generator.h b/impeller/entity/contents/gradient_generator.h index 15e1ec4f1447b..2074d2a3e0440 100644 --- a/impeller/entity/contents/gradient_generator.h +++ b/impeller/entity/contents/gradient_generator.h @@ -11,9 +11,9 @@ #include "flutter/fml/macros.h" #include "flutter/impeller/renderer/texture.h" #include "impeller/geometry/color.h" +#include "impeller/geometry/gradient.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" -#include "impeller/geometry/gradient.h" namespace impeller { diff --git a/impeller/entity/contents/linear_gradient_contents.cc b/impeller/entity/contents/linear_gradient_contents.cc index 42b55e2af94a3..c0ccd04f64e2a 100644 --- a/impeller/entity/contents/linear_gradient_contents.cc +++ b/impeller/entity/contents/linear_gradient_contents.cc @@ -48,7 +48,7 @@ bool LinearGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { auto gradient_data = CreateGradientBuffer(colors_, stops_); - if (gradient_data.texture_size < 16) { + if (gradient_data.texture_size > 16) { return RenderTexture(gradient_data, renderer, entity, pass); } return RenderFixed(gradient_data, renderer, entity, pass); diff --git a/impeller/entity/contents/radial_gradient_contents.cc b/impeller/entity/contents/radial_gradient_contents.cc index c0188aa8eba8f..d09fd154ff685 100644 --- a/impeller/entity/contents/radial_gradient_contents.cc +++ b/impeller/entity/contents/radial_gradient_contents.cc @@ -10,9 +10,9 @@ #include "impeller/entity/contents/gradient_generator.h" #include "impeller/entity/entity.h" #include "impeller/entity/geometry.h" +#include "impeller/geometry/gradient.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/sampler_library.h" -#include "impeller/geometry/gradient.h" namespace impeller { diff --git a/impeller/entity/contents/sweep_gradient_contents.cc b/impeller/entity/contents/sweep_gradient_contents.cc index 01be6fda01d51..76aec138728df 100644 --- a/impeller/entity/contents/sweep_gradient_contents.cc +++ b/impeller/entity/contents/sweep_gradient_contents.cc @@ -9,9 +9,9 @@ #include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/gradient_generator.h" #include "impeller/entity/entity.h" +#include "impeller/geometry/gradient.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/sampler_library.h" -#include "impeller/geometry/gradient.h" namespace impeller { From 1e0b407889619d5dde2ce5ad585adba16e6f423d Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 16 Nov 2022 17:31:09 -0800 Subject: [PATCH 03/16] Make this work on Android --- .../compiler/shader_lib/impeller/BUILD.gn | 1 + .../shader_lib/impeller/gradient.glsl | 35 +++++++++ impeller/entity/BUILD.gn | 2 + impeller/entity/contents/content_context.cc | 10 ++- impeller/entity/contents/content_context.h | 38 ++++++++-- .../contents/linear_gradient_contents.cc | 9 ++- .../contents/linear_gradient_contents.h | 2 + .../contents/radial_gradient_contents.cc | 70 ++++++++++++++++- .../contents/radial_gradient_contents.h | 13 ++++ .../contents/sweep_gradient_contents.cc | 75 ++++++++++++++++++- .../entity/contents/sweep_gradient_contents.h | 13 ++++ .../shaders/linear_gradient_fixed_fill.frag | 30 ++------ .../shaders/radial_gradient_fixed_fill.frag | 29 +++++++ .../shaders/sweep_gradient_fixed_fill.frag | 34 +++++++++ impeller/geometry/gradient.cc | 4 +- impeller/geometry/gradient.h | 6 ++ 16 files changed, 335 insertions(+), 36 deletions(-) create mode 100644 impeller/compiler/shader_lib/impeller/gradient.glsl create mode 100644 impeller/entity/shaders/radial_gradient_fixed_fill.frag create mode 100644 impeller/entity/shaders/sweep_gradient_fixed_fill.frag diff --git a/impeller/compiler/shader_lib/impeller/BUILD.gn b/impeller/compiler/shader_lib/impeller/BUILD.gn index 5d7e85c6bd009..99ca69f472f7c 100644 --- a/impeller/compiler/shader_lib/impeller/BUILD.gn +++ b/impeller/compiler/shader_lib/impeller/BUILD.gn @@ -9,6 +9,7 @@ copy("impeller") { "color.glsl", "constants.glsl", "gaussian.glsl", + "gradient.glsl", "texture.glsl", "transform.glsl", "types.glsl", diff --git a/impeller/compiler/shader_lib/impeller/gradient.glsl b/impeller/compiler/shader_lib/impeller/gradient.glsl new file mode 100644 index 0000000000000..ee689d12bd7f8 --- /dev/null +++ b/impeller/compiler/shader_lib/impeller/gradient.glsl @@ -0,0 +1,35 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GRADIENT_GLSL_ +#define GRADIENT_GLSL_ + +#include + +#define FIXED_GRADIENT_SIZE 16 + +/// Compute a gradient color from a buffer of up to 16 colors. +/// +/// The provided value for `t` will be processed according to the `tile_mode`. +/// If the `tile_mode` is decal and t is less than 0 or greater than 1, vec4(0) +/// will be returned. +vec4 IPComputeFixedGradient(float t, vec4[FIXED_GRADIENT_SIZE] colors, float colors_length, float tile_mode) { + if ((t < 0.0 || t > 1.0) && tile_mode == kTileModeDecal) { + return vec4(0); + } + + t = IPFloatTile(t, tile_mode); + if (colors_length == 2) { + return mix(colors[0], colors[1], t); + } + + float rough_index = colors_length * t; + float lower_index = floor(rough_index); + int upper_index = int(ceil(rough_index)); + float scale = rough_index - lower_index; + + return mix(colors[int(lower_index)], colors[upper_index], scale); +} + +#endif diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index f315b6ef98022..ecff571707766 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -49,6 +49,7 @@ impeller_shaders("entity_shaders") { "shaders/position_uv.vert", "shaders/position.vert", "shaders/radial_gradient_fill.frag", + "shaders/radial_gradient_fixed_fill.frag", "shaders/rrect_blur.vert", "shaders/rrect_blur.frag", "shaders/runtime_effect.vert", @@ -57,6 +58,7 @@ impeller_shaders("entity_shaders") { "shaders/srgb_to_linear_filter.frag", "shaders/srgb_to_linear_filter.vert", "shaders/sweep_gradient_fill.frag", + "shaders/sweep_gradient_fixed_fill.frag", "shaders/texture_fill.frag", "shaders/texture_fill.vert", "shaders/tiled_texture_fill.frag", diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 1b76a00bec4d3..19f4d56ef19b8 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -155,10 +155,16 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); linear_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); - linear_gradient_fixed_fill_pipelines_[{}] = - CreateDefaultPipeline(*context_); radial_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); +#ifndef FML_OS_ANDROID + linear_gradient_fixed_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); + radial_gradient_fixed_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); + sweep_gradient_fixed_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); +#endif // FML_OS_ANDROID sweep_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); rrect_blur_pipelines_[{}] = diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 73e43a988714b..aedc07507a3df 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -50,6 +50,7 @@ #include "impeller/entity/morphology_filter.frag.h" #include "impeller/entity/morphology_filter.vert.h" #include "impeller/entity/radial_gradient_fill.frag.h" +#include "impeller/entity/radial_gradient_fixed_fill.frag.h" #include "impeller/entity/rrect_blur.frag.h" #include "impeller/entity/rrect_blur.vert.h" #include "impeller/entity/solid_fill.frag.h" @@ -57,6 +58,7 @@ #include "impeller/entity/srgb_to_linear_filter.frag.h" #include "impeller/entity/srgb_to_linear_filter.vert.h" #include "impeller/entity/sweep_gradient_fill.frag.h" +#include "impeller/entity/sweep_gradient_fixed_fill.frag.h" #include "impeller/entity/texture_fill.frag.h" #include "impeller/entity/texture_fill.vert.h" #include "impeller/entity/tiled_texture_fill.frag.h" @@ -77,15 +79,23 @@ namespace impeller { using LinearGradientFillPipeline = RenderPipelineT; -using LinearGradientFixedFillPipeline = - RenderPipelineT; using SolidFillPipeline = RenderPipelineT; using RadialGradientFillPipeline = RenderPipelineT; using SweepGradientFillPipeline = RenderPipelineT; +#ifndef FML_OS_ANDROID +using LinearGradientFixedFillPipeline = + RenderPipelineT; +using RadialGradientFixedFillPipeline = + RenderPipelineT; +using SweepGradientFixedFillPipeline = + RenderPipelineT; +#endif // FML_OS_ANDROID using BlendPipeline = RenderPipelineT; using RRectBlurPipeline = RenderPipelineT; @@ -214,11 +224,23 @@ class ContentContext { return GetPipeline(linear_gradient_fill_pipelines_, opts); } +#ifndef FML_OS_ANDROID std::shared_ptr> GetLinearGradientFixedFillPipeline(ContentContextOptions opts) const { return GetPipeline(linear_gradient_fixed_fill_pipelines_, opts); } + std::shared_ptr> + GetRadialGradientFixedFillPipeline(ContentContextOptions opts) const { + return GetPipeline(radial_gradient_fixed_fill_pipelines_, opts); + } + + std::shared_ptr> + GetSweepGradientFixedFillPipeline(ContentContextOptions opts) const { + return GetPipeline(sweep_gradient_fixed_fill_pipelines_, opts); + } +#endif // FML_OS_ANDROID + std::shared_ptr> GetRadialGradientFillPipeline( ContentContextOptions opts) const { return GetPipeline(radial_gradient_fill_pipelines_, opts); @@ -423,10 +445,16 @@ class ContentContext { // map. mutable Variants solid_fill_pipelines_; mutable Variants linear_gradient_fill_pipelines_; - mutable Variants - linear_gradient_fixed_fill_pipelines_; mutable Variants radial_gradient_fill_pipelines_; mutable Variants sweep_gradient_fill_pipelines_; +#ifndef FML_OS_ANDROID + mutable Variants + linear_gradient_fixed_fill_pipelines_; + mutable Variants + radial_gradient_fixed_fill_pipelines_; + mutable Variants + sweep_gradient_fixed_fill_pipelines_; +#endif // FML_OS_ANDROID mutable Variants rrect_blur_pipelines_; mutable Variants texture_blend_pipelines_; mutable Variants texture_pipelines_; diff --git a/impeller/entity/contents/linear_gradient_contents.cc b/impeller/entity/contents/linear_gradient_contents.cc index c0ccd04f64e2a..5614b585661f8 100644 --- a/impeller/entity/contents/linear_gradient_contents.cc +++ b/impeller/entity/contents/linear_gradient_contents.cc @@ -47,11 +47,16 @@ void LinearGradientContents::SetTileMode(Entity::TileMode tile_mode) { bool LinearGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { +#ifdef FML_OS_ANDROID auto gradient_data = CreateGradientBuffer(colors_, stops_); - if (gradient_data.texture_size > 16) { + return RenderTexture(gradient_data, renderer, entity, pass); +#else + auto gradient_data = CreateGradientBuffer(colors_, stops_); + if (gradient_data.texture_size > FIXED_GRADIENT_SIZE) { return RenderTexture(gradient_data, renderer, entity, pass); } return RenderFixed(gradient_data, renderer, entity, pass); +#endif // FML_OS_ANDROID } bool LinearGradientContents::RenderTexture(const GradientData& gradient_data, @@ -117,6 +122,7 @@ bool LinearGradientContents::RenderTexture(const GradientData& gradient_data, return true; } +#ifndef FML_OS_ANDROID bool LinearGradientContents::RenderFixed(const GradientData& gradient_data, const ContentContext& renderer, const Entity& entity, @@ -167,5 +173,6 @@ bool LinearGradientContents::RenderFixed(const GradientData& gradient_data, } return true; } +#endif // FML_OS_ANDROID } // namespace impeller diff --git a/impeller/entity/contents/linear_gradient_contents.h b/impeller/entity/contents/linear_gradient_contents.h index 4bb7c09e0385a..33143f0d86114 100644 --- a/impeller/entity/contents/linear_gradient_contents.h +++ b/impeller/entity/contents/linear_gradient_contents.h @@ -48,10 +48,12 @@ class LinearGradientContents final : public ColorSourceContents { const Entity& entity, RenderPass& pass) const; +#ifndef FML_OS_ANDROID bool RenderFixed(const GradientData& gradient_data, const ContentContext& renderer, const Entity& entity, RenderPass& pass) const; +#endif // FML_OS_ANDROID Point start_point_; Point end_point_; diff --git a/impeller/entity/contents/radial_gradient_contents.cc b/impeller/entity/contents/radial_gradient_contents.cc index d09fd154ff685..b1a75a22ee1b1 100644 --- a/impeller/entity/contents/radial_gradient_contents.cc +++ b/impeller/entity/contents/radial_gradient_contents.cc @@ -48,10 +48,78 @@ const std::vector& RadialGradientContents::GetStops() const { bool RadialGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { +#ifdef FML_OS_ANDROID + auto gradient_data = CreateGradientBuffer(colors_, stops_); + return RenderTexture(gradient_data, renderer, entity, pass); +#else + auto gradient_data = CreateGradientBuffer(colors_, stops_); + if (gradient_data.texture_size > FIXED_GRADIENT_SIZE) { + return RenderTexture(gradient_data, renderer, entity, pass); + } + return RenderFixed(gradient_data, renderer, entity, pass); +#endif // FML_OS_ANDROID +} + +#ifndef FML_OS_ANDROID +bool RadialGradientContents::RenderFixed(const GradientData& gradient_data, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = RadialGradientFixedFillPipeline::VertexShader; + using FS = RadialGradientFixedFillPipeline::FragmentShader; + + FS::GradientInfo gradient_info; + gradient_info.center = center_; + gradient_info.radius = radius_; + gradient_info.tile_mode = static_cast(tile_mode_); + gradient_info.alpha = GetAlpha(); + gradient_info.colors_length = gradient_data.texture_size; + for (auto i = 0u; i < gradient_data.colors.size(); i++) { + gradient_info.colors[i] = gradient_data.colors[i]; + } + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + frame_info.matrix = GetInverseMatrix(); + + Command cmd; + cmd.label = "RadialGradientFixedFill"; + cmd.stencil_reference = entity.GetStencilDepth(); + + auto geometry_result = + GetGeometry()->GetPositionBuffer(renderer, entity, pass); + auto options = OptionsFromPassAndEntity(pass, entity); + if (geometry_result.prevent_overdraw) { + options.stencil_compare = CompareFunction::kEqual; + options.stencil_operation = StencilOperation::kIncrementClamp; + } + options.primitive_type = geometry_result.type; + cmd.pipeline = renderer.GetRadialGradientFixedFillPipeline(options); + + cmd.BindVertices(geometry_result.vertex_buffer); + FS::BindGradientInfo( + cmd, pass.GetTransientsBuffer().EmplaceUniform(gradient_info)); + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + + if (!pass.AddCommand(std::move(cmd))) { + return false; + } + + if (geometry_result.prevent_overdraw) { + return ClipRestoreContents().Render(renderer, entity, pass); + } + return true; +} +#endif // FML_OS_ANDROID + +bool RadialGradientContents::RenderTexture(const GradientData& gradient_data, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { using VS = RadialGradientFillPipeline::VertexShader; using FS = RadialGradientFillPipeline::FragmentShader; - auto gradient_data = CreateGradientBuffer(colors_, stops_); auto gradient_texture = CreateGradientTexture(gradient_data, renderer.GetContext()); if (gradient_texture == nullptr) { diff --git a/impeller/entity/contents/radial_gradient_contents.h b/impeller/entity/contents/radial_gradient_contents.h index af659e6b8292f..f4890b5247b7b 100644 --- a/impeller/entity/contents/radial_gradient_contents.h +++ b/impeller/entity/contents/radial_gradient_contents.h @@ -14,6 +14,7 @@ #include "impeller/geometry/color.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" +#include "impeller/geometry/gradient.h" namespace impeller { @@ -41,6 +42,18 @@ class RadialGradientContents final : public ColorSourceContents { void SetTileMode(Entity::TileMode tile_mode); private: + bool RenderTexture(const GradientData& gradient_data, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + +#ifndef FML_OS_ANDROID + bool RenderFixed(const GradientData& gradient_data, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; +#endif // FML_OS_ANDROID + Point center_; Scalar radius_; std::vector colors_; diff --git a/impeller/entity/contents/sweep_gradient_contents.cc b/impeller/entity/contents/sweep_gradient_contents.cc index 76aec138728df..101cb3eb5e884 100644 --- a/impeller/entity/contents/sweep_gradient_contents.cc +++ b/impeller/entity/contents/sweep_gradient_contents.cc @@ -51,12 +51,81 @@ const std::vector& SweepGradientContents::GetStops() const { } bool SweepGradientContents::Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { + const Entity& entity, + RenderPass& pass) const { +#ifdef FML_OS_ANDROID + auto gradient_data = CreateGradientBuffer(colors_, stops_); + return RenderTexture(gradient_data, renderer, entity, pass); +#else + auto gradient_data = CreateGradientBuffer(colors_, stops_); + if (gradient_data.texture_size > FIXED_GRADIENT_SIZE) { + return RenderTexture(gradient_data, renderer, entity, pass); + } + return RenderFixed(gradient_data, renderer, entity, pass); +#endif // FML_OS_ANDROID +} + +#ifndef FML_OS_ANDROID +bool SweepGradientContents::RenderFixed(const GradientData& gradient_data, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = SweepGradientFixedFillPipeline::VertexShader; + using FS = SweepGradientFixedFillPipeline::FragmentShader; + + FS::GradientInfo gradient_info; + gradient_info.center = center_; + gradient_info.bias = bias_; + gradient_info.scale = scale_; + gradient_info.tile_mode = static_cast(tile_mode_); + gradient_info.alpha = GetAlpha(); + gradient_info.colors_length = gradient_data.texture_size; + for (auto i = 0u; i < gradient_data.colors.size(); i++) { + gradient_info.colors[i] = gradient_data.colors[i]; + } + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + frame_info.matrix = GetInverseMatrix(); + + Command cmd; + cmd.label = "SweepGradientFixedFill"; + cmd.stencil_reference = entity.GetStencilDepth(); + auto geometry_result = + GetGeometry()->GetPositionBuffer(renderer, entity, pass); + + auto options = OptionsFromPassAndEntity(pass, entity); + if (geometry_result.prevent_overdraw) { + options.stencil_compare = CompareFunction::kEqual; + options.stencil_operation = StencilOperation::kIncrementClamp; + } + options.primitive_type = geometry_result.type; + cmd.pipeline = renderer.GetSweepGradientFixedFillPipeline(options); + + cmd.BindVertices(geometry_result.vertex_buffer); + FS::BindGradientInfo( + cmd, pass.GetTransientsBuffer().EmplaceUniform(gradient_info)); + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + + if (!pass.AddCommand(std::move(cmd))) { + return false; + } + + if (geometry_result.prevent_overdraw) { + return ClipRestoreContents().Render(renderer, entity, pass); + } + return true; +} +#endif // FML_OS_ANDROID + +bool SweepGradientContents::RenderTexture(const GradientData& gradient_data, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { using VS = SweepGradientFillPipeline::VertexShader; using FS = SweepGradientFillPipeline::FragmentShader; - auto gradient_data = CreateGradientBuffer(colors_, stops_); auto gradient_texture = CreateGradientTexture(gradient_data, renderer.GetContext()); if (gradient_texture == nullptr) { diff --git a/impeller/entity/contents/sweep_gradient_contents.h b/impeller/entity/contents/sweep_gradient_contents.h index a25c2f090cb66..eb68212690ba6 100644 --- a/impeller/entity/contents/sweep_gradient_contents.h +++ b/impeller/entity/contents/sweep_gradient_contents.h @@ -15,6 +15,7 @@ #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" #include "impeller/geometry/scalar.h" +#include "impeller/geometry/gradient.h" namespace impeller { @@ -42,6 +43,18 @@ class SweepGradientContents final : public ColorSourceContents { const std::vector& GetStops() const; private: + bool RenderTexture(const GradientData& gradient_data, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + +#ifndef FML_OS_ANDROID + bool RenderFixed(const GradientData& gradient_data, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; +#endif // FML_OS_ANDROID + Point center_; Scalar bias_; Scalar scale_; diff --git a/impeller/entity/shaders/linear_gradient_fixed_fill.frag b/impeller/entity/shaders/linear_gradient_fixed_fill.frag index c01a0c7580f17..a630477e3eb4c 100644 --- a/impeller/entity/shaders/linear_gradient_fixed_fill.frag +++ b/impeller/entity/shaders/linear_gradient_fixed_fill.frag @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include +#include uniform GradientInfo { vec2 start_point; @@ -10,7 +10,7 @@ uniform GradientInfo { float alpha; float tile_mode; float colors_length; - vec4 colors[16]; + vec4 colors[FIXED_GRADIENT_SIZE]; } gradient_info; in vec2 v_position; @@ -24,24 +24,10 @@ void main() { gradient_info.end_point - gradient_info.start_point ); float t = dot / (len * len); - if ((t < 0.0 || t > 1.0) && gradient_info.tile_mode == kTileModeDecal) { - frag_color = vec4(0); - return; - } - - t = IPFloatTile(t, gradient_info.tile_mode); - if (gradient_info.colors_length == 2) { - frag_color = mix(gradient_info.colors[0], gradient_info.colors[1], t); - return; - } - if (t == 1.0) { - frag_color = gradient_info.colors[int(gradient_info.colors_length) - 1]; - return; - } - - float rough_index = gradient_info.colors_length * t; - float lower_index = floor(rough_index); - float scale = rough_index - lower_index; - - frag_color = mix(gradient_info.colors[int(lower_index)], gradient_info.colors[int(lower_index + 1)], scale); + frag_color = IPComputeFixedGradient( + t, + gradient_info.colors, + gradient_info.colors_length, + gradient_info.tile_mode); + frag_color = vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; } diff --git a/impeller/entity/shaders/radial_gradient_fixed_fill.frag b/impeller/entity/shaders/radial_gradient_fixed_fill.frag new file mode 100644 index 0000000000000..9f959463a5f35 --- /dev/null +++ b/impeller/entity/shaders/radial_gradient_fixed_fill.frag @@ -0,0 +1,29 @@ +// 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 + +uniform GradientInfo { + vec2 center; + float radius; + float tile_mode; + float alpha; + float colors_length; + vec4 colors[FIXED_GRADIENT_SIZE]; +} gradient_info; + +in vec2 v_position; + +out vec4 frag_color; + +void main() { + float len = length(v_position - gradient_info.center); + float t = len / gradient_info.radius; + frag_color = IPComputeFixedGradient( + t, + gradient_info.colors, + gradient_info.colors_length, + gradient_info.tile_mode); + frag_color = vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; +} diff --git a/impeller/entity/shaders/sweep_gradient_fixed_fill.frag b/impeller/entity/shaders/sweep_gradient_fixed_fill.frag new file mode 100644 index 0000000000000..7c9594c604722 --- /dev/null +++ b/impeller/entity/shaders/sweep_gradient_fixed_fill.frag @@ -0,0 +1,34 @@ +// 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 + +uniform GradientInfo { + vec2 center; + float bias; + float scale; + float tile_mode; + float alpha; + float colors_length; + vec4 colors[FIXED_GRADIENT_SIZE]; +} gradient_info; + +in vec2 v_position; + +out vec4 frag_color; + +void main() { + vec2 coord = v_position - gradient_info.center; + float angle = atan(-coord.y, -coord.x); + + float t = (angle * k1Over2Pi + 0.5 + gradient_info.bias) * gradient_info.scale; + frag_color = IPComputeFixedGradient( + t, + gradient_info.colors, + gradient_info.colors_length, + gradient_info.tile_mode + ); + frag_color = vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; +} diff --git a/impeller/geometry/gradient.cc b/impeller/geometry/gradient.cc index 40a539dba6079..051ea6ae13a3c 100644 --- a/impeller/geometry/gradient.cc +++ b/impeller/geometry/gradient.cc @@ -10,7 +10,7 @@ namespace impeller { static void AppendColor(const Color& color, GradientData* data) { - if (data->texture_size > 16) { + if (data->texture_size > FIXED_GRADIENT_SIZE) { auto converted = color.ToR8G8B8A8(); data->color_bytes.push_back(converted[0]); data->color_bytes.push_back(converted[1]); @@ -52,7 +52,7 @@ GradientData CreateGradientBuffer(const std::vector& colors, .colors = {}, .texture_size = texture_size, }; - if (texture_size > 16) { + if (texture_size > FIXED_GRADIENT_SIZE) { data.color_bytes.reserve(texture_size * 4); } else { data.colors.reserve(texture_size); diff --git a/impeller/geometry/gradient.h b/impeller/geometry/gradient.h index aec240d91e252..ed81f11d867a4 100644 --- a/impeller/geometry/gradient.h +++ b/impeller/geometry/gradient.h @@ -13,6 +13,12 @@ namespace impeller { +#ifdef FML_OS_ANDROID +constexpr uint32_t FIXED_GRADIENT_SIZE = 0; +#else +constexpr uint32_t FIXED_GRADIENT_SIZE = 16; +#endif // FML_OS_ANDROID + // If texture_size is 0 then the gradient is invalid. struct GradientData { std::vector color_bytes; From 6464e6305d53d12df772c4630752b287555e252a Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 16 Nov 2022 17:31:40 -0800 Subject: [PATCH 04/16] ++ --- impeller/entity/contents/linear_gradient_contents.h | 2 +- impeller/entity/contents/radial_gradient_contents.h | 4 ++-- impeller/entity/contents/sweep_gradient_contents.cc | 12 ++++++------ impeller/entity/contents/sweep_gradient_contents.h | 4 ++-- impeller/geometry/gradient.h | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/impeller/entity/contents/linear_gradient_contents.h b/impeller/entity/contents/linear_gradient_contents.h index 33143f0d86114..8edea0e6419df 100644 --- a/impeller/entity/contents/linear_gradient_contents.h +++ b/impeller/entity/contents/linear_gradient_contents.h @@ -53,7 +53,7 @@ class LinearGradientContents final : public ColorSourceContents { const ContentContext& renderer, const Entity& entity, RenderPass& pass) const; -#endif // FML_OS_ANDROID +#endif // FML_OS_ANDROID Point start_point_; Point end_point_; diff --git a/impeller/entity/contents/radial_gradient_contents.h b/impeller/entity/contents/radial_gradient_contents.h index f4890b5247b7b..8240eb1c5a3f1 100644 --- a/impeller/entity/contents/radial_gradient_contents.h +++ b/impeller/entity/contents/radial_gradient_contents.h @@ -12,9 +12,9 @@ #include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/color.h" +#include "impeller/geometry/gradient.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" -#include "impeller/geometry/gradient.h" namespace impeller { @@ -52,7 +52,7 @@ class RadialGradientContents final : public ColorSourceContents { const ContentContext& renderer, const Entity& entity, RenderPass& pass) const; -#endif // FML_OS_ANDROID +#endif // FML_OS_ANDROID Point center_; Scalar radius_; diff --git a/impeller/entity/contents/sweep_gradient_contents.cc b/impeller/entity/contents/sweep_gradient_contents.cc index 101cb3eb5e884..710d2902c137d 100644 --- a/impeller/entity/contents/sweep_gradient_contents.cc +++ b/impeller/entity/contents/sweep_gradient_contents.cc @@ -51,8 +51,8 @@ const std::vector& SweepGradientContents::GetStops() const { } bool SweepGradientContents::Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { + const Entity& entity, + RenderPass& pass) const { #ifdef FML_OS_ANDROID auto gradient_data = CreateGradientBuffer(colors_, stops_); return RenderTexture(gradient_data, renderer, entity, pass); @@ -67,9 +67,9 @@ bool SweepGradientContents::Render(const ContentContext& renderer, #ifndef FML_OS_ANDROID bool SweepGradientContents::RenderFixed(const GradientData& gradient_data, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { using VS = SweepGradientFixedFillPipeline::VertexShader; using FS = SweepGradientFixedFillPipeline::FragmentShader; @@ -117,7 +117,7 @@ bool SweepGradientContents::RenderFixed(const GradientData& gradient_data, } return true; } -#endif // FML_OS_ANDROID +#endif // FML_OS_ANDROID bool SweepGradientContents::RenderTexture(const GradientData& gradient_data, const ContentContext& renderer, diff --git a/impeller/entity/contents/sweep_gradient_contents.h b/impeller/entity/contents/sweep_gradient_contents.h index eb68212690ba6..2699b36036427 100644 --- a/impeller/entity/contents/sweep_gradient_contents.h +++ b/impeller/entity/contents/sweep_gradient_contents.h @@ -12,10 +12,10 @@ #include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/color.h" +#include "impeller/geometry/gradient.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" #include "impeller/geometry/scalar.h" -#include "impeller/geometry/gradient.h" namespace impeller { @@ -53,7 +53,7 @@ class SweepGradientContents final : public ColorSourceContents { const ContentContext& renderer, const Entity& entity, RenderPass& pass) const; -#endif // FML_OS_ANDROID +#endif // FML_OS_ANDROID Point center_; Scalar bias_; diff --git a/impeller/geometry/gradient.h b/impeller/geometry/gradient.h index ed81f11d867a4..a6cb910b26070 100644 --- a/impeller/geometry/gradient.h +++ b/impeller/geometry/gradient.h @@ -17,7 +17,7 @@ namespace impeller { constexpr uint32_t FIXED_GRADIENT_SIZE = 0; #else constexpr uint32_t FIXED_GRADIENT_SIZE = 16; -#endif // FML_OS_ANDROID +#endif // FML_OS_ANDROID // If texture_size is 0 then the gradient is invalid. struct GradientData { From c6764e1fd492123b8c69b74c36f75b5206a5f622 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 16 Nov 2022 17:45:26 -0800 Subject: [PATCH 05/16] ++ --- ci/licenses_golden/licenses_flutter | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 64749254d96d5..5c9dce041f500 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1115,6 +1115,7 @@ FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/branching.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/color.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/constants.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/gaussian.glsl +FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/gradient.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/texture.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/transform.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/types.glsl @@ -1285,6 +1286,7 @@ FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.frag FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.vert FILE: ../../../flutter/impeller/entity/shaders/gradient_fill.vert FILE: ../../../flutter/impeller/entity/shaders/linear_gradient_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/linear_gradient_fixed_fill.frag FILE: ../../../flutter/impeller/entity/shaders/linear_to_srgb_filter.frag FILE: ../../../flutter/impeller/entity/shaders/linear_to_srgb_filter.vert FILE: ../../../flutter/impeller/entity/shaders/morphology_filter.frag @@ -1293,6 +1295,7 @@ FILE: ../../../flutter/impeller/entity/shaders/position.vert FILE: ../../../flutter/impeller/entity/shaders/position_color.vert FILE: ../../../flutter/impeller/entity/shaders/position_uv.vert FILE: ../../../flutter/impeller/entity/shaders/radial_gradient_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/radial_gradient_fixed_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 @@ -1301,6 +1304,7 @@ FILE: ../../../flutter/impeller/entity/shaders/solid_fill.vert FILE: ../../../flutter/impeller/entity/shaders/srgb_to_linear_filter.frag FILE: ../../../flutter/impeller/entity/shaders/srgb_to_linear_filter.vert FILE: ../../../flutter/impeller/entity/shaders/sweep_gradient_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/sweep_gradient_fixed_fill.frag FILE: ../../../flutter/impeller/entity/shaders/texture_fill.frag FILE: ../../../flutter/impeller/entity/shaders/texture_fill.vert FILE: ../../../flutter/impeller/entity/shaders/tiled_texture_fill.frag From ad2913d9d34f7a6fb65d57fb79ee5fb5e0ab964f Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 16 Nov 2022 18:05:49 -0800 Subject: [PATCH 06/16] ++ --- impeller/geometry/geometry_unittests.cc | 9 ++++++--- impeller/geometry/geometry_unittests.h | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index 9392b12947cbb..a50445af8552a 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -1761,7 +1761,7 @@ TEST(GeometryTest, Gradient) { auto gradient = CreateGradientBuffer(colors, stops); - ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, colors); + ASSERT_COLORS_NEAR(gradient.colors, colors); ASSERT_EQ(gradient.texture_size, 2u); } @@ -1784,7 +1784,7 @@ TEST(GeometryTest, Gradient) { auto gradient = CreateGradientBuffer(colors, stops); - ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, colors); + ASSERT_COLORS_NEAR(gradient.colors, colors); ASSERT_EQ(gradient.texture_size, 4u); } @@ -1802,7 +1802,7 @@ TEST(GeometryTest, Gradient) { Color::lerp(Color::Blue(), Color::Green(), 0.6666), Color::Green(), }; - ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, lerped_colors); + ASSERT_COLORS_NEAR(gradient.colors, lerped_colors); ASSERT_EQ(gradient.texture_size, 5u); } @@ -1818,6 +1818,9 @@ TEST(GeometryTest, Gradient) { auto gradient = CreateGradientBuffer(colors, stops); ASSERT_EQ(gradient.texture_size, 1024u); + // Large gradients use color buffer for textures + ASSERT_EQ(gradient.colors.size(), 0u); + ASSERT_EQ(gradient.color_bytes.size(), 1024u * 4); } } diff --git a/impeller/geometry/geometry_unittests.h b/impeller/geometry/geometry_unittests.h index 4407ad85479c5..38911bd9672bd 100644 --- a/impeller/geometry/geometry_unittests.h +++ b/impeller/geometry/geometry_unittests.h @@ -131,6 +131,23 @@ inline ::testing::AssertionResult ColorBufferNear( return ::testing::AssertionSuccess(); } +inline ::testing::AssertionResult ColorsNear(std::vector a, + std::vector b) { + if (a.size() != b.size()) { + return ::testing::AssertionFailure() << "Colors length does not match"; + } + for (auto i = 0u; i < b.size(); i++) { + auto equal = + NumberNear(a[i].red, b[i].red) && NumberNear(a[i].green, b[i].green) && + NumberNear(a[i].blue, b[i].blue) && NumberNear(a[i].alpha, b[i].alpha); + + if (!equal) { + ::testing::AssertionFailure() << "Colors are not equal."; + } + } + return ::testing::AssertionSuccess(); +} + #define ASSERT_MATRIX_NEAR(a, b) ASSERT_PRED2(&::MatrixNear, a, b) #define ASSERT_QUATERNION_NEAR(a, b) ASSERT_PRED2(&::QuaternionNear, a, b) #define ASSERT_RECT_NEAR(a, b) ASSERT_PRED2(&::RectNear, a, b) @@ -141,3 +158,4 @@ inline ::testing::AssertionResult ColorBufferNear( #define ASSERT_SIZE_NEAR(a, b) ASSERT_PRED2(&::SizeNear, a, b) #define ASSERT_ARRAY_4_NEAR(a, b) ASSERT_PRED2(&::Array4Near, a, b) #define ASSERT_COLOR_BUFFER_NEAR(a, b) ASSERT_PRED2(&::ColorBufferNear, a, b) +#define ASSERT_COLORS_NEAR(a, b) ASSERT_PRED2(&::ColorsNear, a, b) \ No newline at end of file From 6205d7864b433a478521bdbd36d8e2dc022b113e Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 17 Nov 2022 10:38:55 -0800 Subject: [PATCH 07/16] compiler support and basic feature detection --- impeller/compiler/compiler.cc | 8 +- impeller/compiler/impellerc_main.cc | 1 + .../shader_lib/impeller/gradient.glsl | 23 ++--- impeller/compiler/source_options.h | 1 + impeller/compiler/switches.cc | 6 +- impeller/compiler/switches.h | 1 + impeller/entity/BUILD.gn | 20 +++- impeller/entity/contents/backend_features.h | 21 ++++ impeller/entity/contents/content_context.cc | 25 +++-- impeller/entity/contents/content_context.h | 21 ++-- .../contents/linear_gradient_contents.cc | 37 +++---- .../contents/linear_gradient_contents.h | 12 +-- .../contents/radial_gradient_contents.cc | 37 +++---- .../contents/radial_gradient_contents.h | 13 +-- .../contents/sweep_gradient_contents.cc | 37 +++---- .../entity/contents/sweep_gradient_contents.h | 12 +-- .../shaders/linear_gradient_fixed_fill.frag | 20 ++-- .../shaders/radial_gradient_fixed_fill.frag | 20 ++-- .../shaders/sweep_gradient_fixed_fill.frag | 22 +++-- impeller/geometry/geometry_unittests.cc | 8 +- impeller/geometry/gradient.cc | 98 ++++++++++++++++--- impeller/geometry/gradient.h | 26 +++-- impeller/playground/BUILD.gn | 1 + impeller/tools/impeller.gni | 11 +++ 24 files changed, 306 insertions(+), 175 deletions(-) create mode 100644 impeller/entity/contents/backend_features.h diff --git a/impeller/compiler/compiler.cc b/impeller/compiler/compiler.cc index c2397c521edc0..783f4cf5091b4 100644 --- a/impeller/compiler/compiler.cc +++ b/impeller/compiler/compiler.cc @@ -45,10 +45,14 @@ static CompilerBackend CreateGLSLCompiler(const spirv_cross::ParsedIR& ir, sl_options.force_zero_initialized_variables = true; sl_options.vertex.fixup_clipspace = true; if (source_options.target_platform == TargetPlatform::kOpenGLES) { - sl_options.version = 100; + sl_options.version = source_options.gles_language_version > 0 + ? source_options.gles_language_version + : 100; sl_options.es = true; } else { - sl_options.version = 120; + sl_options.version = source_options.gles_language_version > 0 + ? source_options.gles_language_version + : 120; sl_options.es = false; } gl_compiler->set_common_options(sl_options); diff --git a/impeller/compiler/impellerc_main.cc b/impeller/compiler/impellerc_main.cc index 9d4bf89172e52..e75f78d8c232a 100644 --- a/impeller/compiler/impellerc_main.cc +++ b/impeller/compiler/impellerc_main.cc @@ -72,6 +72,7 @@ bool Main(const fml::CommandLine& command_line) { options.entry_point_name = EntryPointFunctionNameFromSourceName( switches.source_file_name, options.type, options.source_language); options.json_format = switches.json_format; + options.gles_language_version = switches.gles_language_version; Reflector::Options reflector_options; reflector_options.target_platform = switches.target_platform; diff --git a/impeller/compiler/shader_lib/impeller/gradient.glsl b/impeller/compiler/shader_lib/impeller/gradient.glsl index ee689d12bd7f8..d349487f6848b 100644 --- a/impeller/compiler/shader_lib/impeller/gradient.glsl +++ b/impeller/compiler/shader_lib/impeller/gradient.glsl @@ -7,29 +7,22 @@ #include -#define FIXED_GRADIENT_SIZE 16 - -/// Compute a gradient color from a buffer of up to 16 colors. +/// Compute the indexes and mix coefficient used to mix colors for an +/// arbitrarily sized color gradient. /// -/// The provided value for `t` will be processed according to the `tile_mode`. -/// If the `tile_mode` is decal and t is less than 0 or greater than 1, vec4(0) -/// will be returned. -vec4 IPComputeFixedGradient(float t, vec4[FIXED_GRADIENT_SIZE] colors, float colors_length, float tile_mode) { - if ((t < 0.0 || t > 1.0) && tile_mode == kTileModeDecal) { - return vec4(0); - } - - t = IPFloatTile(t, tile_mode); +/// The returned values are the lower index, upper index, and mix +/// coefficient. +vec3 IPComputeFixedGradientValues(float t, float colors_length) { if (colors_length == 2) { - return mix(colors[0], colors[1], t); + return vec3(0, 1, t); } float rough_index = colors_length * t; float lower_index = floor(rough_index); - int upper_index = int(ceil(rough_index)); + float upper_index = ceil(rough_index); float scale = rough_index - lower_index; - return mix(colors[int(lower_index)], colors[upper_index], scale); + return vec3(lower_index, upper_index, scale); } #endif diff --git a/impeller/compiler/source_options.h b/impeller/compiler/source_options.h index 921ee5cb5c494..ccd264562a3d0 100644 --- a/impeller/compiler/source_options.h +++ b/impeller/compiler/source_options.h @@ -24,6 +24,7 @@ struct SourceOptions { std::vector include_dirs; std::string file_name = "main.glsl"; std::string entry_point_name = "main"; + uint32_t gles_language_version = 100; std::vector defines; bool json_format = false; diff --git a/impeller/compiler/switches.cc b/impeller/compiler/switches.cc index 25caa1c968fe5..894d7f0bb3a60 100644 --- a/impeller/compiler/switches.cc +++ b/impeller/compiler/switches.cc @@ -66,6 +66,7 @@ void Switches::PrintHelp(std::ostream& stream) { stream << "[optional,multiple] --include=" << std::endl; stream << "[optional,multiple] --define=" << std::endl; stream << "[optional] --depfile=" << std::endl; + stream << "[optional] --gles-language-verision=" << std::endl; stream << "[optional] --json" << std::endl; } @@ -120,7 +121,10 @@ Switches::Switches(const fml::CommandLine& command_line) reflection_cc_name( command_line.GetOptionValueWithDefault("reflection-cc", "")), depfile_path(command_line.GetOptionValueWithDefault("depfile", "")), - json_format(command_line.HasOption("json")) { + json_format(command_line.HasOption("json")), + gles_language_version( + stoi(command_line.GetOptionValueWithDefault("gles-language-version", + "0"))) { if (!working_directory || !working_directory->is_valid()) { return; } diff --git a/impeller/compiler/switches.h b/impeller/compiler/switches.h index 95d7b4d1701d5..34f64e8c367ca 100644 --- a/impeller/compiler/switches.h +++ b/impeller/compiler/switches.h @@ -33,6 +33,7 @@ struct Switches { std::vector defines; bool json_format; SourceLanguage source_language = SourceLanguage::kUnknown; + uint32_t gles_language_version; Switches(); diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index ecff571707766..d490f38974a7a 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -42,14 +42,12 @@ impeller_shaders("entity_shaders") { "shaders/linear_to_srgb_filter.frag", "shaders/linear_to_srgb_filter.vert", "shaders/linear_gradient_fill.frag", - "shaders/linear_gradient_fixed_fill.frag", "shaders/morphology_filter.frag", "shaders/morphology_filter.vert", "shaders/position_color.vert", "shaders/position_uv.vert", "shaders/position.vert", "shaders/radial_gradient_fill.frag", - "shaders/radial_gradient_fixed_fill.frag", "shaders/rrect_blur.vert", "shaders/rrect_blur.frag", "shaders/runtime_effect.vert", @@ -58,7 +56,6 @@ impeller_shaders("entity_shaders") { "shaders/srgb_to_linear_filter.frag", "shaders/srgb_to_linear_filter.vert", "shaders/sweep_gradient_fill.frag", - "shaders/sweep_gradient_fixed_fill.frag", "shaders/texture_fill.frag", "shaders/texture_fill.vert", "shaders/tiled_texture_fill.frag", @@ -69,6 +66,22 @@ impeller_shaders("entity_shaders") { ] } + +impeller_shaders("modern_entity_shaders") { + name = "modern" + + if (impeller_enable_opengles) { + gles_language_version = "460" + } + + shaders = [ + "shaders/linear_gradient_fixed_fill.frag", + "shaders/radial_gradient_fixed_fill.frag", + "shaders/sweep_gradient_fixed_fill.frag", + ] +} + + impeller_component("entity") { sources = [ "contents/atlas_contents.cc", @@ -149,6 +162,7 @@ impeller_component("entity") { public_deps = [ ":entity_shaders", + ":modern_entity_shaders", "../archivist", "../image", "../renderer", diff --git a/impeller/entity/contents/backend_features.h b/impeller/entity/contents/backend_features.h new file mode 100644 index 0000000000000..525ce3146ad7e --- /dev/null +++ b/impeller/entity/contents/backend_features.h @@ -0,0 +1,21 @@ +// 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. + +#pragma once + +namespace impeller { + +/// @brief A struct for describing available backend features for runtime +/// selection. +struct BackendFeatures { + bool ssbo_support; +}; + +/// @brief feature sets available on most but not all modern hardware. +constexpr BackendFeatures kModernBackendFeatures = {.ssbo_support = true}; + +/// @brief Lowest common denominator feature sets. +constexpr BackendFeatures kLegacyBackendFeatures = {.ssbo_support = false}; + +} // namespace impeller \ No newline at end of file diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 19f4d56ef19b8..2ec95ffa98bf5 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -150,6 +150,11 @@ ContentContext::ContentContext(std::shared_ptr context) if (!context_ || !context_->IsValid()) { return; } +#ifdef FML_OS_ANDROID + backend_features_ = kLegacyBackendFeatures; +#else + backend_features_ = kModernBackendFeatures; +#endif // FML_OS_ANDROID solid_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); @@ -157,14 +162,14 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); radial_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); -#ifndef FML_OS_ANDROID - linear_gradient_fixed_fill_pipelines_[{}] = - CreateDefaultPipeline(*context_); - radial_gradient_fixed_fill_pipelines_[{}] = - CreateDefaultPipeline(*context_); - sweep_gradient_fixed_fill_pipelines_[{}] = - CreateDefaultPipeline(*context_); -#endif // FML_OS_ANDROID + if (backend_features_.ssbo_support) { + linear_gradient_fixed_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); + radial_gradient_fixed_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); + sweep_gradient_fixed_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); + } sweep_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); rrect_blur_pipelines_[{}] = @@ -311,4 +316,8 @@ std::shared_ptr ContentContext::GetContext() const { return context_; } +const BackendFeatures& ContentContext::GetBackendFeatures() const { + return backend_features_; +} + } // namespace impeller diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index aedc07507a3df..a8087af362320 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -44,13 +44,11 @@ #include "impeller/entity/glyph_atlas_sdf.vert.h" #include "impeller/entity/gradient_fill.vert.h" #include "impeller/entity/linear_gradient_fill.frag.h" -#include "impeller/entity/linear_gradient_fixed_fill.frag.h" #include "impeller/entity/linear_to_srgb_filter.frag.h" #include "impeller/entity/linear_to_srgb_filter.vert.h" #include "impeller/entity/morphology_filter.frag.h" #include "impeller/entity/morphology_filter.vert.h" #include "impeller/entity/radial_gradient_fill.frag.h" -#include "impeller/entity/radial_gradient_fixed_fill.frag.h" #include "impeller/entity/rrect_blur.frag.h" #include "impeller/entity/rrect_blur.vert.h" #include "impeller/entity/solid_fill.frag.h" @@ -58,7 +56,6 @@ #include "impeller/entity/srgb_to_linear_filter.frag.h" #include "impeller/entity/srgb_to_linear_filter.vert.h" #include "impeller/entity/sweep_gradient_fill.frag.h" -#include "impeller/entity/sweep_gradient_fixed_fill.frag.h" #include "impeller/entity/texture_fill.frag.h" #include "impeller/entity/texture_fill.vert.h" #include "impeller/entity/tiled_texture_fill.frag.h" @@ -75,6 +72,12 @@ #include "impeller/typographer/glyph_atlas.h" +#include "impeller/entity/linear_gradient_fixed_fill.frag.h" +#include "impeller/entity/radial_gradient_fixed_fill.frag.h" +#include "impeller/entity/sweep_gradient_fixed_fill.frag.h" + +#include "impeller/entity/contents/backend_features.h" + namespace impeller { using LinearGradientFillPipeline = @@ -85,7 +88,6 @@ using RadialGradientFillPipeline = RenderPipelineT; using SweepGradientFillPipeline = RenderPipelineT; -#ifndef FML_OS_ANDROID using LinearGradientFixedFillPipeline = RenderPipelineT; @@ -95,7 +97,6 @@ using RadialGradientFixedFillPipeline = using SweepGradientFixedFillPipeline = RenderPipelineT; -#endif // FML_OS_ANDROID using BlendPipeline = RenderPipelineT; using RRectBlurPipeline = RenderPipelineT; @@ -224,22 +225,23 @@ class ContentContext { return GetPipeline(linear_gradient_fill_pipelines_, opts); } -#ifndef FML_OS_ANDROID std::shared_ptr> GetLinearGradientFixedFillPipeline(ContentContextOptions opts) const { + FML_DCHECK(backend_features_.ssbo_support); return GetPipeline(linear_gradient_fixed_fill_pipelines_, opts); } std::shared_ptr> GetRadialGradientFixedFillPipeline(ContentContextOptions opts) const { + FML_DCHECK(backend_features_.ssbo_support); return GetPipeline(radial_gradient_fixed_fill_pipelines_, opts); } std::shared_ptr> GetSweepGradientFixedFillPipeline(ContentContextOptions opts) const { + FML_DCHECK(backend_features_.ssbo_support); return GetPipeline(sweep_gradient_fixed_fill_pipelines_, opts); } -#endif // FML_OS_ANDROID std::shared_ptr> GetRadialGradientFillPipeline( ContentContextOptions opts) const { @@ -422,6 +424,8 @@ class ContentContext { std::shared_ptr GetGlyphAtlasContext() const; + const BackendFeatures& GetBackendFeatures() const; + using SubpassCallback = std::function; @@ -447,14 +451,12 @@ class ContentContext { mutable Variants linear_gradient_fill_pipelines_; mutable Variants radial_gradient_fill_pipelines_; mutable Variants sweep_gradient_fill_pipelines_; -#ifndef FML_OS_ANDROID mutable Variants linear_gradient_fixed_fill_pipelines_; mutable Variants radial_gradient_fixed_fill_pipelines_; mutable Variants sweep_gradient_fixed_fill_pipelines_; -#endif // FML_OS_ANDROID mutable Variants rrect_blur_pipelines_; mutable Variants texture_blend_pipelines_; mutable Variants texture_pipelines_; @@ -522,6 +524,7 @@ class ContentContext { bool is_valid_ = false; std::shared_ptr tessellator_; std::shared_ptr glyph_atlas_context_; + BackendFeatures backend_features_; FML_DISALLOW_COPY_AND_ASSIGN(ContentContext); }; diff --git a/impeller/entity/contents/linear_gradient_contents.cc b/impeller/entity/contents/linear_gradient_contents.cc index 5614b585661f8..f861152535a98 100644 --- a/impeller/entity/contents/linear_gradient_contents.cc +++ b/impeller/entity/contents/linear_gradient_contents.cc @@ -47,25 +47,19 @@ void LinearGradientContents::SetTileMode(Entity::TileMode tile_mode) { bool LinearGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { -#ifdef FML_OS_ANDROID - auto gradient_data = CreateGradientBuffer(colors_, stops_); - return RenderTexture(gradient_data, renderer, entity, pass); -#else - auto gradient_data = CreateGradientBuffer(colors_, stops_); - if (gradient_data.texture_size > FIXED_GRADIENT_SIZE) { - return RenderTexture(gradient_data, renderer, entity, pass); + if (renderer.GetBackendFeatures().ssbo_support) { + return RenderSSBO(renderer, entity, pass); } - return RenderFixed(gradient_data, renderer, entity, pass); -#endif // FML_OS_ANDROID + return RenderTexture(renderer, entity, pass); } -bool LinearGradientContents::RenderTexture(const GradientData& gradient_data, - const ContentContext& renderer, +bool LinearGradientContents::RenderTexture(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { using VS = LinearGradientFillPipeline::VertexShader; using FS = LinearGradientFillPipeline::FragmentShader; + auto gradient_data = CreateGradientBuffer(colors_, stops_); auto gradient_texture = CreateGradientTexture(gradient_data, renderer.GetContext()); if (gradient_texture == nullptr) { @@ -122,11 +116,9 @@ bool LinearGradientContents::RenderTexture(const GradientData& gradient_data, return true; } -#ifndef FML_OS_ANDROID -bool LinearGradientContents::RenderFixed(const GradientData& gradient_data, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { +bool LinearGradientContents::RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { using VS = LinearGradientFixedFillPipeline::VertexShader; using FS = LinearGradientFixedFillPipeline::FragmentShader; @@ -135,10 +127,13 @@ bool LinearGradientContents::RenderFixed(const GradientData& gradient_data, gradient_info.end_point = end_point_; gradient_info.tile_mode = static_cast(tile_mode_); gradient_info.alpha = GetAlpha(); - gradient_info.colors_length = gradient_data.texture_size; - for (auto i = 0u; i < gradient_data.colors.size(); i++) { - gradient_info.colors[i] = gradient_data.colors[i]; - } + + auto& host_buffer = pass.GetTransientsBuffer(); + auto colors = CreateGradientColors(colors_, stops_).value_or(colors_); + + gradient_info.colors_length = colors.size(); + auto color_buffer = host_buffer.Emplace( + colors.data(), colors.size() * sizeof(Color), alignof(Color)); VS::FrameInfo frame_info; frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * @@ -162,6 +157,7 @@ bool LinearGradientContents::RenderFixed(const GradientData& gradient_data, cmd.BindVertices(geometry_result.vertex_buffer); FS::BindGradientInfo( cmd, pass.GetTransientsBuffer().EmplaceUniform(gradient_info)); + FS::BindColorData(cmd, color_buffer); VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); if (!pass.AddCommand(std::move(cmd))) { @@ -173,6 +169,5 @@ bool LinearGradientContents::RenderFixed(const GradientData& gradient_data, } return true; } -#endif // FML_OS_ANDROID } // namespace impeller diff --git a/impeller/entity/contents/linear_gradient_contents.h b/impeller/entity/contents/linear_gradient_contents.h index 8edea0e6419df..2a2fd1c6c6632 100644 --- a/impeller/entity/contents/linear_gradient_contents.h +++ b/impeller/entity/contents/linear_gradient_contents.h @@ -43,17 +43,13 @@ class LinearGradientContents final : public ColorSourceContents { void SetTileMode(Entity::TileMode tile_mode); private: - bool RenderTexture(const GradientData& gradient_data, - const ContentContext& renderer, + bool RenderTexture(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const; -#ifndef FML_OS_ANDROID - bool RenderFixed(const GradientData& gradient_data, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const; -#endif // FML_OS_ANDROID + bool RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; Point start_point_; Point end_point_; diff --git a/impeller/entity/contents/radial_gradient_contents.cc b/impeller/entity/contents/radial_gradient_contents.cc index b1a75a22ee1b1..17558f6e50f3f 100644 --- a/impeller/entity/contents/radial_gradient_contents.cc +++ b/impeller/entity/contents/radial_gradient_contents.cc @@ -48,23 +48,15 @@ const std::vector& RadialGradientContents::GetStops() const { bool RadialGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { -#ifdef FML_OS_ANDROID - auto gradient_data = CreateGradientBuffer(colors_, stops_); - return RenderTexture(gradient_data, renderer, entity, pass); -#else - auto gradient_data = CreateGradientBuffer(colors_, stops_); - if (gradient_data.texture_size > FIXED_GRADIENT_SIZE) { - return RenderTexture(gradient_data, renderer, entity, pass); + if (renderer.GetBackendFeatures().ssbo_support) { + return RenderSSBO(renderer, entity, pass); } - return RenderFixed(gradient_data, renderer, entity, pass); -#endif // FML_OS_ANDROID + return RenderTexture(renderer, entity, pass); } -#ifndef FML_OS_ANDROID -bool RadialGradientContents::RenderFixed(const GradientData& gradient_data, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { +bool RadialGradientContents::RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { using VS = RadialGradientFixedFillPipeline::VertexShader; using FS = RadialGradientFixedFillPipeline::FragmentShader; @@ -73,10 +65,13 @@ bool RadialGradientContents::RenderFixed(const GradientData& gradient_data, gradient_info.radius = radius_; gradient_info.tile_mode = static_cast(tile_mode_); gradient_info.alpha = GetAlpha(); - gradient_info.colors_length = gradient_data.texture_size; - for (auto i = 0u; i < gradient_data.colors.size(); i++) { - gradient_info.colors[i] = gradient_data.colors[i]; - } + + auto& host_buffer = pass.GetTransientsBuffer(); + auto colors = CreateGradientColors(colors_, stops_).value_or(colors_); + + gradient_info.colors_length = colors.size(); + auto color_buffer = host_buffer.Emplace( + colors.data(), colors.size() * sizeof(Color), alignof(Color)); VS::FrameInfo frame_info; frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * @@ -100,6 +95,7 @@ bool RadialGradientContents::RenderFixed(const GradientData& gradient_data, cmd.BindVertices(geometry_result.vertex_buffer); FS::BindGradientInfo( cmd, pass.GetTransientsBuffer().EmplaceUniform(gradient_info)); + FS::BindColorData(cmd, color_buffer); VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); if (!pass.AddCommand(std::move(cmd))) { @@ -111,15 +107,14 @@ bool RadialGradientContents::RenderFixed(const GradientData& gradient_data, } return true; } -#endif // FML_OS_ANDROID -bool RadialGradientContents::RenderTexture(const GradientData& gradient_data, - const ContentContext& renderer, +bool RadialGradientContents::RenderTexture(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { using VS = RadialGradientFillPipeline::VertexShader; using FS = RadialGradientFillPipeline::FragmentShader; + auto gradient_data = CreateGradientBuffer(colors_, stops_); auto gradient_texture = CreateGradientTexture(gradient_data, renderer.GetContext()); if (gradient_texture == nullptr) { diff --git a/impeller/entity/contents/radial_gradient_contents.h b/impeller/entity/contents/radial_gradient_contents.h index 8240eb1c5a3f1..6cb611d1ee68a 100644 --- a/impeller/entity/contents/radial_gradient_contents.h +++ b/impeller/entity/contents/radial_gradient_contents.h @@ -42,18 +42,13 @@ class RadialGradientContents final : public ColorSourceContents { void SetTileMode(Entity::TileMode tile_mode); private: - bool RenderTexture(const GradientData& gradient_data, - const ContentContext& renderer, + bool RenderTexture(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const; -#ifndef FML_OS_ANDROID - bool RenderFixed(const GradientData& gradient_data, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const; -#endif // FML_OS_ANDROID - + bool RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; Point center_; Scalar radius_; std::vector colors_; diff --git a/impeller/entity/contents/sweep_gradient_contents.cc b/impeller/entity/contents/sweep_gradient_contents.cc index 710d2902c137d..fec86f844e958 100644 --- a/impeller/entity/contents/sweep_gradient_contents.cc +++ b/impeller/entity/contents/sweep_gradient_contents.cc @@ -53,23 +53,15 @@ const std::vector& SweepGradientContents::GetStops() const { bool SweepGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { -#ifdef FML_OS_ANDROID - auto gradient_data = CreateGradientBuffer(colors_, stops_); - return RenderTexture(gradient_data, renderer, entity, pass); -#else - auto gradient_data = CreateGradientBuffer(colors_, stops_); - if (gradient_data.texture_size > FIXED_GRADIENT_SIZE) { - return RenderTexture(gradient_data, renderer, entity, pass); + if (renderer.GetBackendFeatures().ssbo_support) { + return RenderSSBO(renderer, entity, pass); } - return RenderFixed(gradient_data, renderer, entity, pass); -#endif // FML_OS_ANDROID + return RenderTexture(renderer, entity, pass); } -#ifndef FML_OS_ANDROID -bool SweepGradientContents::RenderFixed(const GradientData& gradient_data, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { +bool SweepGradientContents::RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { using VS = SweepGradientFixedFillPipeline::VertexShader; using FS = SweepGradientFixedFillPipeline::FragmentShader; @@ -79,10 +71,13 @@ bool SweepGradientContents::RenderFixed(const GradientData& gradient_data, gradient_info.scale = scale_; gradient_info.tile_mode = static_cast(tile_mode_); gradient_info.alpha = GetAlpha(); - gradient_info.colors_length = gradient_data.texture_size; - for (auto i = 0u; i < gradient_data.colors.size(); i++) { - gradient_info.colors[i] = gradient_data.colors[i]; - } + + auto& host_buffer = pass.GetTransientsBuffer(); + auto colors = CreateGradientColors(colors_, stops_).value_or(colors_); + + gradient_info.colors_length = colors.size(); + auto color_buffer = host_buffer.Emplace( + colors.data(), colors.size() * sizeof(Color), alignof(Color)); VS::FrameInfo frame_info; frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * @@ -106,6 +101,7 @@ bool SweepGradientContents::RenderFixed(const GradientData& gradient_data, cmd.BindVertices(geometry_result.vertex_buffer); FS::BindGradientInfo( cmd, pass.GetTransientsBuffer().EmplaceUniform(gradient_info)); + FS::BindColorData(cmd, color_buffer); VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); if (!pass.AddCommand(std::move(cmd))) { @@ -117,15 +113,14 @@ bool SweepGradientContents::RenderFixed(const GradientData& gradient_data, } return true; } -#endif // FML_OS_ANDROID -bool SweepGradientContents::RenderTexture(const GradientData& gradient_data, - const ContentContext& renderer, +bool SweepGradientContents::RenderTexture(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { using VS = SweepGradientFillPipeline::VertexShader; using FS = SweepGradientFillPipeline::FragmentShader; + auto gradient_data = CreateGradientBuffer(colors_, stops_); auto gradient_texture = CreateGradientTexture(gradient_data, renderer.GetContext()); if (gradient_texture == nullptr) { diff --git a/impeller/entity/contents/sweep_gradient_contents.h b/impeller/entity/contents/sweep_gradient_contents.h index 2699b36036427..94c448cc22961 100644 --- a/impeller/entity/contents/sweep_gradient_contents.h +++ b/impeller/entity/contents/sweep_gradient_contents.h @@ -43,17 +43,13 @@ class SweepGradientContents final : public ColorSourceContents { const std::vector& GetStops() const; private: - bool RenderTexture(const GradientData& gradient_data, - const ContentContext& renderer, + bool RenderTexture(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const; -#ifndef FML_OS_ANDROID - bool RenderFixed(const GradientData& gradient_data, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const; -#endif // FML_OS_ANDROID + bool RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; Point center_; Scalar bias_; diff --git a/impeller/entity/shaders/linear_gradient_fixed_fill.frag b/impeller/entity/shaders/linear_gradient_fixed_fill.frag index a630477e3eb4c..e8cc761c9046b 100644 --- a/impeller/entity/shaders/linear_gradient_fixed_fill.frag +++ b/impeller/entity/shaders/linear_gradient_fixed_fill.frag @@ -3,6 +3,11 @@ // found in the LICENSE file. #include +#include + +readonly buffer ColorData { + vec4 colors[]; +} color_data; uniform GradientInfo { vec2 start_point; @@ -10,7 +15,6 @@ uniform GradientInfo { float alpha; float tile_mode; float colors_length; - vec4 colors[FIXED_GRADIENT_SIZE]; } gradient_info; in vec2 v_position; @@ -24,10 +28,14 @@ void main() { gradient_info.end_point - gradient_info.start_point ); float t = dot / (len * len); - frag_color = IPComputeFixedGradient( - t, - gradient_info.colors, - gradient_info.colors_length, - gradient_info.tile_mode); + + if ((t < 0.0 || t > 1.0) && gradient_info.tile_mode == kTileModeDecal) { + frag_color = vec4(0); + return; + } + t = IPFloatTile(t, gradient_info.tile_mode); + vec3 values = IPComputeFixedGradientValues(t, gradient_info.colors_length); + + frag_color = mix(color_data.colors[int(values.x)], color_data.colors[int(values.y)], values.z); frag_color = vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; } diff --git a/impeller/entity/shaders/radial_gradient_fixed_fill.frag b/impeller/entity/shaders/radial_gradient_fixed_fill.frag index 9f959463a5f35..b6ce052286102 100644 --- a/impeller/entity/shaders/radial_gradient_fixed_fill.frag +++ b/impeller/entity/shaders/radial_gradient_fixed_fill.frag @@ -3,6 +3,11 @@ // found in the LICENSE file. #include +#include + +readonly buffer ColorData { + vec4 colors[]; +} color_data; uniform GradientInfo { vec2 center; @@ -10,7 +15,6 @@ uniform GradientInfo { float tile_mode; float alpha; float colors_length; - vec4 colors[FIXED_GRADIENT_SIZE]; } gradient_info; in vec2 v_position; @@ -20,10 +24,14 @@ out vec4 frag_color; void main() { float len = length(v_position - gradient_info.center); float t = len / gradient_info.radius; - frag_color = IPComputeFixedGradient( - t, - gradient_info.colors, - gradient_info.colors_length, - gradient_info.tile_mode); + + if ((t < 0.0 || t > 1.0) && gradient_info.tile_mode == kTileModeDecal) { + frag_color = vec4(0); + return; + } + t = IPFloatTile(t, gradient_info.tile_mode); + vec3 values = IPComputeFixedGradientValues(t, gradient_info.colors_length); + + frag_color = mix(color_data.colors[int(values.x)], color_data.colors[int(values.y)], values.z); frag_color = vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; } diff --git a/impeller/entity/shaders/sweep_gradient_fixed_fill.frag b/impeller/entity/shaders/sweep_gradient_fixed_fill.frag index 7c9594c604722..129f4aa95c467 100644 --- a/impeller/entity/shaders/sweep_gradient_fixed_fill.frag +++ b/impeller/entity/shaders/sweep_gradient_fixed_fill.frag @@ -4,6 +4,11 @@ #include #include +#include + +readonly buffer ColorData { + vec4 colors[]; +} color_data; uniform GradientInfo { vec2 center; @@ -12,7 +17,6 @@ uniform GradientInfo { float tile_mode; float alpha; float colors_length; - vec4 colors[FIXED_GRADIENT_SIZE]; } gradient_info; in vec2 v_position; @@ -22,13 +26,15 @@ out vec4 frag_color; void main() { vec2 coord = v_position - gradient_info.center; float angle = atan(-coord.y, -coord.x); - float t = (angle * k1Over2Pi + 0.5 + gradient_info.bias) * gradient_info.scale; - frag_color = IPComputeFixedGradient( - t, - gradient_info.colors, - gradient_info.colors_length, - gradient_info.tile_mode - ); + + if ((t < 0.0 || t > 1.0) && gradient_info.tile_mode == kTileModeDecal) { + frag_color = vec4(0); + return; + } + t = IPFloatTile(t, gradient_info.tile_mode); + vec3 values = IPComputeFixedGradientValues(t, gradient_info.colors_length); + + frag_color = mix(color_data.colors[int(values.x)], color_data.colors[int(values.y)], values.z); frag_color = vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; } diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index a50445af8552a..d19664bdd06c0 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -1761,7 +1761,7 @@ TEST(GeometryTest, Gradient) { auto gradient = CreateGradientBuffer(colors, stops); - ASSERT_COLORS_NEAR(gradient.colors, colors); + ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, colors); ASSERT_EQ(gradient.texture_size, 2u); } @@ -1784,7 +1784,7 @@ TEST(GeometryTest, Gradient) { auto gradient = CreateGradientBuffer(colors, stops); - ASSERT_COLORS_NEAR(gradient.colors, colors); + ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, colors); ASSERT_EQ(gradient.texture_size, 4u); } @@ -1802,7 +1802,7 @@ TEST(GeometryTest, Gradient) { Color::lerp(Color::Blue(), Color::Green(), 0.6666), Color::Green(), }; - ASSERT_COLORS_NEAR(gradient.colors, lerped_colors); + ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, lerped_colors); ASSERT_EQ(gradient.texture_size, 5u); } @@ -1818,8 +1818,6 @@ TEST(GeometryTest, Gradient) { auto gradient = CreateGradientBuffer(colors, stops); ASSERT_EQ(gradient.texture_size, 1024u); - // Large gradients use color buffer for textures - ASSERT_EQ(gradient.colors.size(), 0u); ASSERT_EQ(gradient.color_bytes.size(), 1024u * 4); } } diff --git a/impeller/geometry/gradient.cc b/impeller/geometry/gradient.cc index 051ea6ae13a3c..00dcc045ef8a5 100644 --- a/impeller/geometry/gradient.cc +++ b/impeller/geometry/gradient.cc @@ -10,15 +10,11 @@ namespace impeller { static void AppendColor(const Color& color, GradientData* data) { - if (data->texture_size > FIXED_GRADIENT_SIZE) { - auto converted = color.ToR8G8B8A8(); - data->color_bytes.push_back(converted[0]); - data->color_bytes.push_back(converted[1]); - data->color_bytes.push_back(converted[2]); - data->color_bytes.push_back(converted[3]); - } else { - data->colors.push_back(color); - } + auto converted = color.ToR8G8B8A8(); + data->color_bytes.push_back(converted[0]); + data->color_bytes.push_back(converted[1]); + data->color_bytes.push_back(converted[2]); + data->color_bytes.push_back(converted[3]); } GradientData CreateGradientBuffer(const std::vector& colors, @@ -49,14 +45,9 @@ GradientData CreateGradientBuffer(const std::vector& colors, } GradientData data = { .color_bytes = {}, - .colors = {}, .texture_size = texture_size, }; - if (texture_size > FIXED_GRADIENT_SIZE) { - data.color_bytes.reserve(texture_size * 4); - } else { - data.colors.reserve(texture_size); - } + data.color_bytes.reserve(texture_size * 4); if (texture_size == colors.size() && colors.size() <= 1024) { for (auto i = 0u; i < colors.size(); i++) { @@ -107,4 +98,81 @@ GradientData CreateGradientBuffer(const std::vector& colors, return data; } +std::optional> CreateGradientColors( + const std::vector& colors, + const std::vector& stops) { + FML_DCHECK(stops.size() == colors.size()); + + if (stops.size() == 2) { + // Use original buffer. + return std::nullopt; + } + + uint32_t color_count; + auto minimum_delta = 1.0; + for (size_t i = 1; i < stops.size(); i++) { + auto value = stops[i] - stops[i - 1]; + // Smaller than kEhCloseEnough + if (value < 0.0001) { + continue; + } + if (value < minimum_delta) { + minimum_delta = value; + } + // Avoid creating buffers that are absurdly large due to stops that are + // very close together. + color_count = std::min( + static_cast(std::round(1.0 / minimum_delta)) + 1, 1024u); + } + + if (color_count == colors.size()) { + // Use original buffer. + return std::nullopt; + } + + std::vector data; + data.reserve(color_count); + + Color previous_color = colors[0]; + auto previous_stop = 0.0; + auto previous_color_index = 0; + + // The first index is always equal to the first color, exactly. + data.push_back(colors[0]); + + for (auto i = 1u; i < color_count - 1; i++) { + auto scaled_i = i / (color_count - 1.0); + Color next_color = colors[previous_color_index + 1]; + auto next_stop = stops[previous_color_index + 1]; + // We're almost exactly equal to the next stop. + if (ScalarNearlyEqual(scaled_i, next_stop)) { + data.push_back(next_color); + + previous_color = next_color; + previous_stop = next_stop; + previous_color_index += 1; + } else if (scaled_i < next_stop) { + // We're still between the current stop and the next stop. + auto t = (scaled_i - previous_stop) / (next_stop - previous_stop); + auto mixed_color = Color::lerp(previous_color, next_color, t); + + data.push_back(mixed_color); + } else { + // We've slightly overshot the previous stop. + previous_color = next_color; + previous_stop = next_stop; + previous_color_index += 1; + next_color = colors[previous_color_index + 1]; + auto next_stop = stops[previous_color_index + 1]; + + auto t = (scaled_i - previous_stop) / (next_stop - previous_stop); + auto mixed_color = Color::lerp(previous_color, next_color, t); + data.push_back(mixed_color); + } + // The last index is always equal to the last color, exactly. + data.push_back(colors.back()); + } + return data; +} + } // namespace impeller diff --git a/impeller/geometry/gradient.h b/impeller/geometry/gradient.h index a6cb910b26070..2d8e737adab35 100644 --- a/impeller/geometry/gradient.h +++ b/impeller/geometry/gradient.h @@ -13,22 +13,15 @@ namespace impeller { -#ifdef FML_OS_ANDROID -constexpr uint32_t FIXED_GRADIENT_SIZE = 0; -#else -constexpr uint32_t FIXED_GRADIENT_SIZE = 16; -#endif // FML_OS_ANDROID - // If texture_size is 0 then the gradient is invalid. struct GradientData { std::vector color_bytes; - std::vector colors; uint32_t texture_size; }; /** - * @brief Populate a vector with the interpolated colors for the linear gradient - * described colors and stops. + * @brief Populate a vector with the interpolated color bytes for the linear + * gradient described by colors and stops. * * @param colors * @param stops @@ -37,4 +30,19 @@ struct GradientData { GradientData CreateGradientBuffer(const std::vector& colors, const std::vector& stops); +/** + * @brief Populate a vector with the interpolated colors for the linear gradient + * described by colors and stops. + * + * If the returned result is std::nullopt, the original color buffer can be used + * instead. + * + * @param colors + * @param stops + * @return GradientData + */ +std::optional> CreateGradientColors( + const std::vector& colors, + const std::vector& stops); + } // namespace impeller diff --git a/impeller/playground/BUILD.gn b/impeller/playground/BUILD.gn index 68ba55aa46045..627160f7def96 100644 --- a/impeller/playground/BUILD.gn +++ b/impeller/playground/BUILD.gn @@ -40,6 +40,7 @@ impeller_component("playground") { public_deps = [ "../entity:entity_shaders", + "../entity:modern_entity_shaders", "../fixtures:shader_fixtures", "../renderer", "imgui:imgui_impeller_backend", diff --git a/impeller/tools/impeller.gni b/impeller/tools/impeller.gni index 38495962cdfed..2a47a990a65dd 100644 --- a/impeller/tools/impeller.gni +++ b/impeller/tools/impeller.gni @@ -240,6 +240,10 @@ template("impellerc") { if (defined(invoker.json) && invoker.json) { json = invoker.json } + gles_language_version = "100" + if (defined(invoker.gles_language_version)) { + gles_language_version = invoker.gles_language_version + } # Not needed on every path. not_needed([ @@ -277,6 +281,7 @@ template("impellerc") { "--include={{source_dir}}", "--include=$shader_lib_dir", "--depfile=$depfile_intermediate_path", + "--gles-language-version=$gles_language_version", "$shader_target_flag", ] @@ -459,6 +464,9 @@ template("impeller_shaders_gles") { impellerc(impellerc_gles) { shaders = invoker.shaders sl_file_extension = "gles" + if (defined(invoker.gles_language_version)) { + gles_language_version = invoker.gles_language_version + } # Metal reflectors generate a superset of information. if (impeller_enable_metal || impeller_enable_vulkan) { @@ -571,6 +579,9 @@ template("impeller_shaders") { gles_shaders = "gles_$target_name" impeller_shaders_gles(gles_shaders) { name = invoker.name + if (defined(invoker.gles_language_version)) { + gles_language_version = invoker.gles_language_version + } if (defined(invoker.gles_exclusions)) { shaders = invoker.shaders - invoker.gles_exclusions } else { From 0693dbdfcec48c9e6a52c7817615455872aeb817 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 17 Nov 2022 10:40:11 -0800 Subject: [PATCH 08/16] ++ --- impeller/entity/BUILD.gn | 2 -- 1 file changed, 2 deletions(-) diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index d490f38974a7a..8426a19e46b68 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -66,7 +66,6 @@ impeller_shaders("entity_shaders") { ] } - impeller_shaders("modern_entity_shaders") { name = "modern" @@ -81,7 +80,6 @@ impeller_shaders("modern_entity_shaders") { ] } - impeller_component("entity") { sources = [ "contents/atlas_contents.cc", From da02aea47341722b76f9c7c17500e9e2fdbbc446 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 17 Nov 2022 11:14:01 -0800 Subject: [PATCH 09/16] ++ --- impeller/entity/contents/backend_features.h | 2 +- impeller/geometry/geometry_unittests.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/impeller/entity/contents/backend_features.h b/impeller/entity/contents/backend_features.h index 525ce3146ad7e..f8ea75b134a50 100644 --- a/impeller/entity/contents/backend_features.h +++ b/impeller/entity/contents/backend_features.h @@ -18,4 +18,4 @@ constexpr BackendFeatures kModernBackendFeatures = {.ssbo_support = true}; /// @brief Lowest common denominator feature sets. constexpr BackendFeatures kLegacyBackendFeatures = {.ssbo_support = false}; -} // namespace impeller \ No newline at end of file +} // namespace impeller diff --git a/impeller/geometry/geometry_unittests.h b/impeller/geometry/geometry_unittests.h index 38911bd9672bd..84d960293d379 100644 --- a/impeller/geometry/geometry_unittests.h +++ b/impeller/geometry/geometry_unittests.h @@ -158,4 +158,4 @@ inline ::testing::AssertionResult ColorsNear(std::vector a, #define ASSERT_SIZE_NEAR(a, b) ASSERT_PRED2(&::SizeNear, a, b) #define ASSERT_ARRAY_4_NEAR(a, b) ASSERT_PRED2(&::Array4Near, a, b) #define ASSERT_COLOR_BUFFER_NEAR(a, b) ASSERT_PRED2(&::ColorBufferNear, a, b) -#define ASSERT_COLORS_NEAR(a, b) ASSERT_PRED2(&::ColorsNear, a, b) \ No newline at end of file +#define ASSERT_COLORS_NEAR(a, b) ASSERT_PRED2(&::ColorsNear, a, b) From 377b3e57b795a3009639543e6353162f073b1946 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 17 Nov 2022 11:48:38 -0800 Subject: [PATCH 10/16] rename to ssbo_fill, move to context --- impeller/entity/BUILD.gn | 6 +-- impeller/entity/contents/content_context.cc | 21 +++----- impeller/entity/contents/content_context.h | 51 +++++++++---------- .../contents/linear_gradient_contents.cc | 8 +-- .../contents/radial_gradient_contents.cc | 8 +-- .../contents/sweep_gradient_contents.cc | 8 +-- ...ll.frag => linear_gradient_ssbo_fill.frag} | 0 ...ll.frag => radial_gradient_ssbo_fill.frag} | 0 ...ill.frag => sweep_gradient_ssbo_fill.frag} | 0 .../renderer/backend/gles/context_gles.cc | 5 ++ impeller/renderer/backend/gles/context_gles.h | 3 ++ impeller/renderer/backend/metal/context_mtl.h | 3 ++ .../renderer/backend/metal/context_mtl.mm | 5 ++ .../renderer/backend/vulkan/context_vk.cc | 5 ++ impeller/renderer/backend/vulkan/context_vk.h | 3 ++ .../contents => renderer}/backend_features.h | 0 impeller/renderer/context.h | 3 ++ 17 files changed, 74 insertions(+), 55 deletions(-) rename impeller/entity/shaders/{linear_gradient_fixed_fill.frag => linear_gradient_ssbo_fill.frag} (100%) rename impeller/entity/shaders/{radial_gradient_fixed_fill.frag => radial_gradient_ssbo_fill.frag} (100%) rename impeller/entity/shaders/{sweep_gradient_fixed_fill.frag => sweep_gradient_ssbo_fill.frag} (100%) rename impeller/{entity/contents => renderer}/backend_features.h (100%) diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 8426a19e46b68..ecba665e6617a 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -74,9 +74,9 @@ impeller_shaders("modern_entity_shaders") { } shaders = [ - "shaders/linear_gradient_fixed_fill.frag", - "shaders/radial_gradient_fixed_fill.frag", - "shaders/sweep_gradient_fixed_fill.frag", + "shaders/linear_gradient_ssbo_fill.frag", + "shaders/radial_gradient_ssbo_fill.frag", + "shaders/sweep_gradient_ssbo_fill.frag", ] } diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 2ec95ffa98bf5..fa6c6782f40cb 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -150,11 +150,6 @@ ContentContext::ContentContext(std::shared_ptr context) if (!context_ || !context_->IsValid()) { return; } -#ifdef FML_OS_ANDROID - backend_features_ = kLegacyBackendFeatures; -#else - backend_features_ = kModernBackendFeatures; -#endif // FML_OS_ANDROID solid_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); @@ -162,13 +157,13 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); radial_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); - if (backend_features_.ssbo_support) { - linear_gradient_fixed_fill_pipelines_[{}] = - CreateDefaultPipeline(*context_); - radial_gradient_fixed_fill_pipelines_[{}] = - CreateDefaultPipeline(*context_); - sweep_gradient_fixed_fill_pipelines_[{}] = - CreateDefaultPipeline(*context_); + if (context_->GetBackendFeatures().ssbo_support) { + linear_gradient_ssbo_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); + radial_gradient_ssbo_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); + sweep_gradient_ssbo_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); } sweep_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); @@ -317,7 +312,7 @@ std::shared_ptr ContentContext::GetContext() const { } const BackendFeatures& ContentContext::GetBackendFeatures() const { - return backend_features_; + return context_->GetBackendFeatures(); } } // namespace impeller diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index a8087af362320..661ac5a58a9d0 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -72,11 +72,9 @@ #include "impeller/typographer/glyph_atlas.h" -#include "impeller/entity/linear_gradient_fixed_fill.frag.h" -#include "impeller/entity/radial_gradient_fixed_fill.frag.h" -#include "impeller/entity/sweep_gradient_fixed_fill.frag.h" - -#include "impeller/entity/contents/backend_features.h" +#include "impeller/entity/linear_gradient_ssbo_fill.frag.h" +#include "impeller/entity/radial_gradient_ssbo_fill.frag.h" +#include "impeller/entity/sweep_gradient_ssbo_fill.frag.h" namespace impeller { @@ -88,15 +86,15 @@ using RadialGradientFillPipeline = RenderPipelineT; using SweepGradientFillPipeline = RenderPipelineT; -using LinearGradientFixedFillPipeline = +using LinearGradientSSBOFillPipeline = RenderPipelineT; -using RadialGradientFixedFillPipeline = + LinearGradientSsboFillFragmentShader>; +using RadialGradientSSBOFillPipeline = RenderPipelineT; -using SweepGradientFixedFillPipeline = + RadialGradientSsboFillFragmentShader>; +using SweepGradientSSBOFillPipeline = RenderPipelineT; + SweepGradientSsboFillFragmentShader>; using BlendPipeline = RenderPipelineT; using RRectBlurPipeline = RenderPipelineT; @@ -226,21 +224,21 @@ class ContentContext { } std::shared_ptr> - GetLinearGradientFixedFillPipeline(ContentContextOptions opts) const { - FML_DCHECK(backend_features_.ssbo_support); - return GetPipeline(linear_gradient_fixed_fill_pipelines_, opts); + GetLinearGradientSSBOFillPipeline(ContentContextOptions opts) const { + FML_DCHECK(GetBackendFeatures().ssbo_support); + return GetPipeline(linear_gradient_ssbo_fill_pipelines_, opts); } std::shared_ptr> - GetRadialGradientFixedFillPipeline(ContentContextOptions opts) const { - FML_DCHECK(backend_features_.ssbo_support); - return GetPipeline(radial_gradient_fixed_fill_pipelines_, opts); + GetRadialGradientSSBOFillPipeline(ContentContextOptions opts) const { + FML_DCHECK(GetBackendFeatures().ssbo_support); + return GetPipeline(radial_gradient_ssbo_fill_pipelines_, opts); } std::shared_ptr> - GetSweepGradientFixedFillPipeline(ContentContextOptions opts) const { - FML_DCHECK(backend_features_.ssbo_support); - return GetPipeline(sweep_gradient_fixed_fill_pipelines_, opts); + GetSweepGradientSSBOFillPipeline(ContentContextOptions opts) const { + FML_DCHECK(GetBackendFeatures().ssbo_support); + return GetPipeline(sweep_gradient_ssbo_fill_pipelines_, opts); } std::shared_ptr> GetRadialGradientFillPipeline( @@ -451,12 +449,12 @@ class ContentContext { mutable Variants linear_gradient_fill_pipelines_; mutable Variants radial_gradient_fill_pipelines_; mutable Variants sweep_gradient_fill_pipelines_; - mutable Variants - linear_gradient_fixed_fill_pipelines_; - mutable Variants - radial_gradient_fixed_fill_pipelines_; - mutable Variants - sweep_gradient_fixed_fill_pipelines_; + mutable Variants + linear_gradient_ssbo_fill_pipelines_; + mutable Variants + radial_gradient_ssbo_fill_pipelines_; + mutable Variants + sweep_gradient_ssbo_fill_pipelines_; mutable Variants rrect_blur_pipelines_; mutable Variants texture_blend_pipelines_; mutable Variants texture_pipelines_; @@ -524,7 +522,6 @@ class ContentContext { bool is_valid_ = false; std::shared_ptr tessellator_; std::shared_ptr glyph_atlas_context_; - BackendFeatures backend_features_; FML_DISALLOW_COPY_AND_ASSIGN(ContentContext); }; diff --git a/impeller/entity/contents/linear_gradient_contents.cc b/impeller/entity/contents/linear_gradient_contents.cc index f861152535a98..688c18ccdd449 100644 --- a/impeller/entity/contents/linear_gradient_contents.cc +++ b/impeller/entity/contents/linear_gradient_contents.cc @@ -119,8 +119,8 @@ bool LinearGradientContents::RenderTexture(const ContentContext& renderer, bool LinearGradientContents::RenderSSBO(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { - using VS = LinearGradientFixedFillPipeline::VertexShader; - using FS = LinearGradientFixedFillPipeline::FragmentShader; + using VS = LinearGradientSSBOFillPipeline::VertexShader; + using FS = LinearGradientSSBOFillPipeline::FragmentShader; FS::GradientInfo gradient_info; gradient_info.start_point = start_point_; @@ -141,7 +141,7 @@ bool LinearGradientContents::RenderSSBO(const ContentContext& renderer, frame_info.matrix = GetInverseMatrix(); Command cmd; - cmd.label = "LinearGradientFixedFill"; + cmd.label = "LinearGradientSSBOFill"; cmd.stencil_reference = entity.GetStencilDepth(); auto geometry_result = @@ -152,7 +152,7 @@ bool LinearGradientContents::RenderSSBO(const ContentContext& renderer, options.stencil_operation = StencilOperation::kIncrementClamp; } options.primitive_type = geometry_result.type; - cmd.pipeline = renderer.GetLinearGradientFixedFillPipeline(options); + cmd.pipeline = renderer.GetLinearGradientSSBOFillPipeline(options); cmd.BindVertices(geometry_result.vertex_buffer); FS::BindGradientInfo( diff --git a/impeller/entity/contents/radial_gradient_contents.cc b/impeller/entity/contents/radial_gradient_contents.cc index 17558f6e50f3f..40d7c3777c99a 100644 --- a/impeller/entity/contents/radial_gradient_contents.cc +++ b/impeller/entity/contents/radial_gradient_contents.cc @@ -57,8 +57,8 @@ bool RadialGradientContents::Render(const ContentContext& renderer, bool RadialGradientContents::RenderSSBO(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { - using VS = RadialGradientFixedFillPipeline::VertexShader; - using FS = RadialGradientFixedFillPipeline::FragmentShader; + using VS = RadialGradientSSBOFillPipeline::VertexShader; + using FS = RadialGradientSSBOFillPipeline::FragmentShader; FS::GradientInfo gradient_info; gradient_info.center = center_; @@ -79,7 +79,7 @@ bool RadialGradientContents::RenderSSBO(const ContentContext& renderer, frame_info.matrix = GetInverseMatrix(); Command cmd; - cmd.label = "RadialGradientFixedFill"; + cmd.label = "RadialGradientSSBOFill"; cmd.stencil_reference = entity.GetStencilDepth(); auto geometry_result = @@ -90,7 +90,7 @@ bool RadialGradientContents::RenderSSBO(const ContentContext& renderer, options.stencil_operation = StencilOperation::kIncrementClamp; } options.primitive_type = geometry_result.type; - cmd.pipeline = renderer.GetRadialGradientFixedFillPipeline(options); + cmd.pipeline = renderer.GetRadialGradientSSBOFillPipeline(options); cmd.BindVertices(geometry_result.vertex_buffer); FS::BindGradientInfo( diff --git a/impeller/entity/contents/sweep_gradient_contents.cc b/impeller/entity/contents/sweep_gradient_contents.cc index fec86f844e958..666e6c51de151 100644 --- a/impeller/entity/contents/sweep_gradient_contents.cc +++ b/impeller/entity/contents/sweep_gradient_contents.cc @@ -62,8 +62,8 @@ bool SweepGradientContents::Render(const ContentContext& renderer, bool SweepGradientContents::RenderSSBO(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { - using VS = SweepGradientFixedFillPipeline::VertexShader; - using FS = SweepGradientFixedFillPipeline::FragmentShader; + using VS = SweepGradientSSBOFillPipeline::VertexShader; + using FS = SweepGradientSSBOFillPipeline::FragmentShader; FS::GradientInfo gradient_info; gradient_info.center = center_; @@ -85,7 +85,7 @@ bool SweepGradientContents::RenderSSBO(const ContentContext& renderer, frame_info.matrix = GetInverseMatrix(); Command cmd; - cmd.label = "SweepGradientFixedFill"; + cmd.label = "SweepGradientSSBOFill"; cmd.stencil_reference = entity.GetStencilDepth(); auto geometry_result = GetGeometry()->GetPositionBuffer(renderer, entity, pass); @@ -96,7 +96,7 @@ bool SweepGradientContents::RenderSSBO(const ContentContext& renderer, options.stencil_operation = StencilOperation::kIncrementClamp; } options.primitive_type = geometry_result.type; - cmd.pipeline = renderer.GetSweepGradientFixedFillPipeline(options); + cmd.pipeline = renderer.GetSweepGradientSSBOFillPipeline(options); cmd.BindVertices(geometry_result.vertex_buffer); FS::BindGradientInfo( diff --git a/impeller/entity/shaders/linear_gradient_fixed_fill.frag b/impeller/entity/shaders/linear_gradient_ssbo_fill.frag similarity index 100% rename from impeller/entity/shaders/linear_gradient_fixed_fill.frag rename to impeller/entity/shaders/linear_gradient_ssbo_fill.frag diff --git a/impeller/entity/shaders/radial_gradient_fixed_fill.frag b/impeller/entity/shaders/radial_gradient_ssbo_fill.frag similarity index 100% rename from impeller/entity/shaders/radial_gradient_fixed_fill.frag rename to impeller/entity/shaders/radial_gradient_ssbo_fill.frag diff --git a/impeller/entity/shaders/sweep_gradient_fixed_fill.frag b/impeller/entity/shaders/sweep_gradient_ssbo_fill.frag similarity index 100% rename from impeller/entity/shaders/sweep_gradient_fixed_fill.frag rename to impeller/entity/shaders/sweep_gradient_ssbo_fill.frag diff --git a/impeller/renderer/backend/gles/context_gles.cc b/impeller/renderer/backend/gles/context_gles.cc index e6234c642038e..e539249ed2d7e 100644 --- a/impeller/renderer/backend/gles/context_gles.cc +++ b/impeller/renderer/backend/gles/context_gles.cc @@ -137,4 +137,9 @@ bool ContextGLES::SupportsOffscreenMSAA() const { return false; } +// |Context| +const BackendFeatures& ContextGLES::GetBackendFeatures() const { + return kLegacyBackendFeatures; +} + } // namespace impeller diff --git a/impeller/renderer/backend/gles/context_gles.h b/impeller/renderer/backend/gles/context_gles.h index 138843a7fb7a3..9e23e1900608c 100644 --- a/impeller/renderer/backend/gles/context_gles.h +++ b/impeller/renderer/backend/gles/context_gles.h @@ -73,6 +73,9 @@ class ContextGLES final : public Context, // |Context| bool SupportsOffscreenMSAA() const override; + // |Context| + const BackendFeatures& GetBackendFeatures() const override; + FML_DISALLOW_COPY_AND_ASSIGN(ContextGLES); }; diff --git a/impeller/renderer/backend/metal/context_mtl.h b/impeller/renderer/backend/metal/context_mtl.h index 1ba4740d09525..df6089f618e3f 100644 --- a/impeller/renderer/backend/metal/context_mtl.h +++ b/impeller/renderer/backend/metal/context_mtl.h @@ -76,6 +76,9 @@ class ContextMTL final : public Context, // |Context| bool SupportsOffscreenMSAA() const override; + // |Context| + const BackendFeatures& GetBackendFeatures() const override; + std::shared_ptr CreateCommandBufferInQueue( id queue) const; diff --git a/impeller/renderer/backend/metal/context_mtl.mm b/impeller/renderer/backend/metal/context_mtl.mm index 379b7cf52fb5f..faedec8e5bf2b 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -247,4 +247,9 @@ return true; } +// |Context| +const BackendFeatures& ContextMTL::GetBackendFeatures() const { + return kModernBackendFeatures; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index 58508e8793d75..2505d449388f7 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -24,6 +24,7 @@ #include "impeller/renderer/backend/vulkan/surface_producer_vk.h" #include "impeller/renderer/backend/vulkan/swapchain_details_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" +#include "impeller/renderer/backend_features.h" VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE @@ -588,4 +589,8 @@ PixelFormat ContextVK::GetColorAttachmentPixelFormat() const { return ToPixelFormat(surface_format_); } +const BackendFeatures& ContextVK::GetBackendFeatures() const { + return kModernBackendFeatures; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index f99ef0e28d41b..530dab701a267 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -125,6 +125,9 @@ class ContextVK final : public Context, public BackendCast { // |Context| bool SupportsOffscreenMSAA() const override; + // |Context| + const BackendFeatures& GetBackendFeatures() const override; + FML_DISALLOW_COPY_AND_ASSIGN(ContextVK); }; diff --git a/impeller/entity/contents/backend_features.h b/impeller/renderer/backend_features.h similarity index 100% rename from impeller/entity/contents/backend_features.h rename to impeller/renderer/backend_features.h diff --git a/impeller/renderer/context.h b/impeller/renderer/context.h index 8ba839b8612c0..9d0fd7113a67e 100644 --- a/impeller/renderer/context.h +++ b/impeller/renderer/context.h @@ -8,6 +8,7 @@ #include #include "flutter/fml/macros.h" +#include "impeller/renderer/backend_features.h" #include "impeller/renderer/formats.h" namespace impeller { @@ -52,6 +53,8 @@ class Context : public std::enable_shared_from_this { virtual bool SupportsOffscreenMSAA() const = 0; + virtual const BackendFeatures& GetBackendFeatures() const = 0; + protected: Context(); From b8434363df123bbfa7cfef70140ae04f6aff44a9 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 17 Nov 2022 12:08:57 -0800 Subject: [PATCH 11/16] ++ --- ci/licenses_golden/licenses_flutter | 7 ++++--- impeller/geometry/gradient.cc | 9 ++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 9bf6e216731d9..7efed8ccd042e 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1292,7 +1292,7 @@ FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.frag FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.vert FILE: ../../../flutter/impeller/entity/shaders/gradient_fill.vert FILE: ../../../flutter/impeller/entity/shaders/linear_gradient_fill.frag -FILE: ../../../flutter/impeller/entity/shaders/linear_gradient_fixed_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/linear_gradient_ssbo_fill.frag FILE: ../../../flutter/impeller/entity/shaders/linear_to_srgb_filter.frag FILE: ../../../flutter/impeller/entity/shaders/linear_to_srgb_filter.vert FILE: ../../../flutter/impeller/entity/shaders/morphology_filter.frag @@ -1301,7 +1301,7 @@ FILE: ../../../flutter/impeller/entity/shaders/position.vert FILE: ../../../flutter/impeller/entity/shaders/position_color.vert FILE: ../../../flutter/impeller/entity/shaders/position_uv.vert FILE: ../../../flutter/impeller/entity/shaders/radial_gradient_fill.frag -FILE: ../../../flutter/impeller/entity/shaders/radial_gradient_fixed_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/radial_gradient_ssbo_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 @@ -1310,7 +1310,7 @@ FILE: ../../../flutter/impeller/entity/shaders/solid_fill.vert FILE: ../../../flutter/impeller/entity/shaders/srgb_to_linear_filter.frag FILE: ../../../flutter/impeller/entity/shaders/srgb_to_linear_filter.vert FILE: ../../../flutter/impeller/entity/shaders/sweep_gradient_fill.frag -FILE: ../../../flutter/impeller/entity/shaders/sweep_gradient_fixed_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/sweep_gradient_ssbo_fill.frag FILE: ../../../flutter/impeller/entity/shaders/texture_fill.frag FILE: ../../../flutter/impeller/entity/shaders/texture_fill.vert FILE: ../../../flutter/impeller/entity/shaders/tiled_texture_fill.frag @@ -1451,6 +1451,7 @@ FILE: ../../../flutter/impeller/renderer/backend/metal/vertex_descriptor_mtl.h FILE: ../../../flutter/impeller/renderer/backend/metal/vertex_descriptor_mtl.mm FILE: ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk.h +FILE: ../../../flutter/impeller/renderer/backend_features.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/blit_pass_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/blit_pass_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc diff --git a/impeller/geometry/gradient.cc b/impeller/geometry/gradient.cc index 00dcc045ef8a5..6d3c381f0ead5 100644 --- a/impeller/geometry/gradient.cc +++ b/impeller/geometry/gradient.cc @@ -108,7 +108,6 @@ std::optional> CreateGradientColors( return std::nullopt; } - uint32_t color_count; auto minimum_delta = 1.0; for (size_t i = 1; i < stops.size(); i++) { auto value = stops[i] - stops[i - 1]; @@ -119,11 +118,11 @@ std::optional> CreateGradientColors( if (value < minimum_delta) { minimum_delta = value; } - // Avoid creating buffers that are absurdly large due to stops that are - // very close together. - color_count = std::min( - static_cast(std::round(1.0 / minimum_delta)) + 1, 1024u); } + // Avoid creating buffers that are absurdly large due to stops that are + // very close together. + uint32_t color_count = std::min( + static_cast(std::round(1.0 / minimum_delta)) + 1, 1024u); if (color_count == colors.size()) { // Use original buffer. From 652553e72f6587d3c85af85167a1232d2af06ea0 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 17 Nov 2022 12:11:34 -0800 Subject: [PATCH 12/16] ++ --- impeller/tools/impeller.gni | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/impeller/tools/impeller.gni b/impeller/tools/impeller.gni index 2a47a990a65dd..dfb1156151314 100644 --- a/impeller/tools/impeller.gni +++ b/impeller/tools/impeller.gni @@ -240,10 +240,6 @@ template("impellerc") { if (defined(invoker.json) && invoker.json) { json = invoker.json } - gles_language_version = "100" - if (defined(invoker.gles_language_version)) { - gles_language_version = invoker.gles_language_version - } # Not needed on every path. not_needed([ @@ -281,10 +277,14 @@ template("impellerc") { "--include={{source_dir}}", "--include=$shader_lib_dir", "--depfile=$depfile_intermediate_path", - "--gles-language-version=$gles_language_version", "$shader_target_flag", ] + if (defined(invoker.gles_language_version)) { + gles_language_version = invoker.gles_language_version + args += ["--gles-language-version=$gles_language_version"] + } + if (json) { args += [ "--json" ] } From 21cc74a0ce7abeb05b068ae4573faed349719db0 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 17 Nov 2022 12:12:01 -0800 Subject: [PATCH 13/16] ++ --- impeller/tools/impeller.gni | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impeller/tools/impeller.gni b/impeller/tools/impeller.gni index dfb1156151314..aeb3f162a172d 100644 --- a/impeller/tools/impeller.gni +++ b/impeller/tools/impeller.gni @@ -282,7 +282,7 @@ template("impellerc") { if (defined(invoker.gles_language_version)) { gles_language_version = invoker.gles_language_version - args += ["--gles-language-version=$gles_language_version"] + args += [ "--gles-language-version=$gles_language_version" ] } if (json) { From 283957aff8092cce09bc71c063a199eb48b40051 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 17 Nov 2022 12:24:34 -0800 Subject: [PATCH 14/16] tests --- impeller/geometry/geometry_unittests.cc | 68 +++++++++++++++++++++++++ impeller/geometry/gradient.cc | 4 +- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index d19664bdd06c0..0292ffac4f58b 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -1822,5 +1822,73 @@ TEST(GeometryTest, Gradient) { } } +TEST(GeometryTest, GradientSSBO) { + { + // Simple 2 color gradient produces std::nullopt, as original + // color vector should be used. + std::vector colors = {Color::Red(), Color::Blue()}; + std::vector stops = {0.0, 1.0}; + + auto gradient = CreateGradientColors(colors, stops); + + ASSERT_EQ(gradient, std::nullopt); + } + + { + // Gradient with duplicate stops does not create an empty texture. + std::vector colors = {Color::Red(), Color::Yellow(), Color::Black(), + Color::Blue()}; + std::vector stops = {0.0, 0.25, 0.25, 1.0}; + + auto gradient = CreateGradientColors(colors, stops); + ASSERT_EQ(gradient.value().size(), 5u); + } + + { + // Simple N color gradient produces color buffer containing exactly those + // values. + std::vector colors = {Color::Red(), Color::Blue(), Color::Green(), + Color::White()}; + std::vector stops = {0.0, 0.33, 0.66, 1.0}; + + auto gradient = CreateGradientColors(colors, stops); + + ASSERT_EQ(gradient, std::nullopt); + } + + { + // Gradient with color stops will lerp and scale buffer. + std::vector colors = {Color::Red(), Color::Blue(), Color::Green()}; + std::vector stops = {0.0, 0.25, 1.0}; + + auto gradient = CreateGradientColors(colors, stops); + + std::vector lerped_colors = { + Color::Red(), + Color::Blue(), + Color::lerp(Color::Blue(), Color::Green(), 0.3333), + Color::lerp(Color::Blue(), Color::Green(), 0.6666), + Color::Green(), + }; + + ASSERT_COLORS_NEAR(gradient.value(), lerped_colors); + ASSERT_EQ(gradient.value().size(), 5u); + } + + { + // Gradient size is capped at 1024. + std::vector colors = {}; + std::vector stops = {}; + for (auto i = 0u; i < 1025; i++) { + colors.push_back(Color::Blue()); + stops.push_back(i / 1025.0); + } + + auto gradient = CreateGradientColors(colors, stops); + + ASSERT_EQ(gradient.value().size(), 1024u); + } +} + } // namespace testing } // namespace impeller diff --git a/impeller/geometry/gradient.cc b/impeller/geometry/gradient.cc index 6d3c381f0ead5..e668827e80ea4 100644 --- a/impeller/geometry/gradient.cc +++ b/impeller/geometry/gradient.cc @@ -168,9 +168,9 @@ std::optional> CreateGradientColors( auto mixed_color = Color::lerp(previous_color, next_color, t); data.push_back(mixed_color); } - // The last index is always equal to the last color, exactly. - data.push_back(colors.back()); } + // The last index is always equal to the last color, exactly. + data.push_back(colors.back()); return data; } From 642a3e972df52831318aff9637f362a26757bd8c Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 17 Nov 2022 13:06:41 -0800 Subject: [PATCH 15/16] ++ --- ci/licenses_golden/licenses_flutter | 2 +- impeller/compiler/code_gen_template.h | 1 - impeller/compiler/shader_lib/impeller/gradient.glsl | 6 +----- impeller/playground/backend/metal/playground_impl_mtl.mm | 3 +++ .../darwin/graphics/FlutterDarwinContextMetalImpeller.mm | 3 +++ 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 7efed8ccd042e..14ffe3d669c09 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1451,7 +1451,6 @@ FILE: ../../../flutter/impeller/renderer/backend/metal/vertex_descriptor_mtl.h FILE: ../../../flutter/impeller/renderer/backend/metal/vertex_descriptor_mtl.mm FILE: ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk.h -FILE: ../../../flutter/impeller/renderer/backend_features.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/blit_pass_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/blit_pass_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -1495,6 +1494,7 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/texture_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/vertex_descriptor_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/vertex_descriptor_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/vk.h +FILE: ../../../flutter/impeller/renderer/backend_features.h FILE: ../../../flutter/impeller/renderer/blit_command.cc FILE: ../../../flutter/impeller/renderer/blit_command.h FILE: ../../../flutter/impeller/renderer/blit_pass.cc diff --git a/impeller/compiler/code_gen_template.h b/impeller/compiler/code_gen_template.h index 8ce9f4f233b49..d2708052d1838 100644 --- a/impeller/compiler/code_gen_template.h +++ b/impeller/compiler/code_gen_template.h @@ -202,7 +202,6 @@ using Shader = {{camel_case(shader_name)}}{{camel_case(shader_stage)}}Shader; // Sanity checks for {{def.name}} {% if last(def.members).array_elements == 0 %} static_assert(std::is_standard_layout_v>); -static_assert(sizeof(Shader::{{def.name}}<0>) == {{def.byte_length}}); {% for member in def.members %} static_assert(offsetof(Shader::{{def.name}}<0>, {{member.name}}) == {{member.offset}}); {% endfor %} diff --git a/impeller/compiler/shader_lib/impeller/gradient.glsl b/impeller/compiler/shader_lib/impeller/gradient.glsl index d349487f6848b..2c64edd35098b 100644 --- a/impeller/compiler/shader_lib/impeller/gradient.glsl +++ b/impeller/compiler/shader_lib/impeller/gradient.glsl @@ -13,11 +13,7 @@ /// The returned values are the lower index, upper index, and mix /// coefficient. vec3 IPComputeFixedGradientValues(float t, float colors_length) { - if (colors_length == 2) { - return vec3(0, 1, t); - } - - float rough_index = colors_length * t; + float rough_index = (colors_length - 1) * t; float lower_index = floor(rough_index); float upper_index = ceil(rough_index); float scale = rough_index - lower_index; diff --git a/impeller/playground/backend/metal/playground_impl_mtl.mm b/impeller/playground/backend/metal/playground_impl_mtl.mm index 1a66beac6c0ab..c400e62a9f7a5 100644 --- a/impeller/playground/backend/metal/playground_impl_mtl.mm +++ b/impeller/playground/backend/metal/playground_impl_mtl.mm @@ -15,6 +15,7 @@ #include "flutter/fml/mapping.h" #include "impeller/entity/mtl/entity_shaders.h" +#include "impeller/entity/mtl/modern_shaders.h" #include "impeller/fixtures/mtl/fixtures_shaders.h" #include "impeller/playground/imgui/mtl/imgui_shaders.h" #include "impeller/renderer/backend/metal/context_mtl.h" @@ -33,6 +34,8 @@ return { std::make_shared(impeller_entity_shaders_data, impeller_entity_shaders_length), + std::make_shared(impeller_modern_shaders_data, + impeller_modern_shaders_length), std::make_shared(impeller_fixtures_shaders_data, impeller_fixtures_shaders_length), std::make_shared(impeller_imgui_shaders_data, diff --git a/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm b/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm index a75711c2b4441..1d8ef818db3ce 100644 --- a/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm +++ b/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm @@ -7,6 +7,7 @@ #include "flutter/common/graphics/persistent_cache.h" #include "flutter/fml/logging.h" #include "flutter/impeller/entity/mtl/entity_shaders.h" +#include "impeller/entity/mtl/modern_shaders.h" #include "flutter/impeller/renderer/backend/metal/context_mtl.h" #include "flutter/shell/common/context_options.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" @@ -17,6 +18,8 @@ std::vector> shader_mappings = { std::make_shared(impeller_entity_shaders_data, impeller_entity_shaders_length), + std::make_shared(impeller_modern_shaders_data, + impeller_modern_shaders_length), }; auto context = impeller::ContextMTL::Create(shader_mappings, "Impeller Library"); if (!context) { From ace492f75f814a5d1d93d3ed5932c35ce8bac0d3 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 17 Nov 2022 13:07:05 -0800 Subject: [PATCH 16/16] ++ --- .../darwin/graphics/FlutterDarwinContextMetalImpeller.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm b/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm index 1d8ef818db3ce..1ab7dcd51d3c4 100644 --- a/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm +++ b/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm @@ -7,10 +7,10 @@ #include "flutter/common/graphics/persistent_cache.h" #include "flutter/fml/logging.h" #include "flutter/impeller/entity/mtl/entity_shaders.h" -#include "impeller/entity/mtl/modern_shaders.h" #include "flutter/impeller/renderer/backend/metal/context_mtl.h" #include "flutter/shell/common/context_options.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" +#include "impeller/entity/mtl/modern_shaders.h" FLUTTER_ASSERT_ARC