From aa63d0d282ccb045e5387a53c37fac22ed4fb147 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Tue, 2 Apr 2024 20:42:04 -0700 Subject: [PATCH] [Impeller] make color source a variant instead of a closure. (flutter/engine#51853) This would also me to create a type safe visitor to pull out the data required for https://github.com/flutter/engine/pull/51778 --- .../src/flutter/impeller/aiks/color_source.cc | 264 ++++++++++-------- .../src/flutter/impeller/aiks/color_source.h | 78 +++++- 2 files changed, 220 insertions(+), 122 deletions(-) diff --git a/engine/src/flutter/impeller/aiks/color_source.cc b/engine/src/flutter/impeller/aiks/color_source.cc index b07ac1e0181..da85ce6cb8b 100644 --- a/engine/src/flutter/impeller/aiks/color_source.cc +++ b/engine/src/flutter/impeller/aiks/color_source.cc @@ -5,6 +5,7 @@ #include "impeller/aiks/color_source.h" #include +#include #include #include "impeller/aiks/paint.h" @@ -29,12 +30,132 @@ namespace impeller { -ColorSource::ColorSource() noexcept - : proc_([](const Paint& paint) -> std::shared_ptr { - auto contents = std::make_shared(); - contents->SetColor(paint.color); - return contents; - }){}; +namespace { + +struct CreateContentsVisitor { + explicit CreateContentsVisitor(const Paint& p_paint) : paint(p_paint) {} + + const Paint& paint; + + std::shared_ptr operator()( + const LinearGradientData& data) { + auto contents = std::make_shared(); + contents->SetOpacityFactor(paint.color.alpha); + contents->SetColors(data.colors); + contents->SetStops(data.stops); + contents->SetEndPoints(data.start_point, data.end_point); + contents->SetTileMode(data.tile_mode); + contents->SetEffectTransform(data.effect_transform); + + std::vector bounds{data.start_point, data.end_point}; + auto intrinsic_size = Rect::MakePointBounds(bounds.begin(), bounds.end()); + if (intrinsic_size.has_value()) { + contents->SetColorSourceSize(intrinsic_size->GetSize()); + } + return contents; + } + + std::shared_ptr operator()( + const RadialGradientData& data) { + auto contents = std::make_shared(); + contents->SetOpacityFactor(paint.color.alpha); + contents->SetColors(data.colors); + contents->SetStops(data.stops); + contents->SetCenterAndRadius(data.center, data.radius); + contents->SetTileMode(data.tile_mode); + contents->SetEffectTransform(data.effect_transform); + + auto radius_pt = Point(data.radius, data.radius); + std::vector bounds{data.center + radius_pt, data.center - radius_pt}; + auto intrinsic_size = Rect::MakePointBounds(bounds.begin(), bounds.end()); + if (intrinsic_size.has_value()) { + contents->SetColorSourceSize(intrinsic_size->GetSize()); + } + return contents; + } + + std::shared_ptr operator()( + const ConicalGradientData& data) { + std::shared_ptr contents = + std::make_shared(); + contents->SetOpacityFactor(paint.color.alpha); + contents->SetColors(data.colors); + contents->SetStops(data.stops); + contents->SetCenterAndRadius(data.center, data.radius); + contents->SetTileMode(data.tile_mode); + contents->SetEffectTransform(data.effect_transform); + contents->SetFocus(data.focus_center, data.focus_radius); + + auto radius_pt = Point(data.radius, data.radius); + std::vector bounds{data.center + radius_pt, data.center - radius_pt}; + auto intrinsic_size = Rect::MakePointBounds(bounds.begin(), bounds.end()); + if (intrinsic_size.has_value()) { + contents->SetColorSourceSize(intrinsic_size->GetSize()); + } + return contents; + } + + std::shared_ptr operator()( + const SweepGradientData& data) { + auto contents = std::make_shared(); + contents->SetOpacityFactor(paint.color.alpha); + contents->SetCenterAndAngles(data.center, data.start_angle, data.end_angle); + contents->SetColors(data.colors); + contents->SetStops(data.stops); + contents->SetTileMode(data.tile_mode); + contents->SetEffectTransform(data.effect_transform); + + return contents; + } + + std::shared_ptr operator()(const ImageData& data) { + auto contents = std::make_shared(); + contents->SetOpacityFactor(paint.color.alpha); + contents->SetTexture(data.texture); + contents->SetTileModes(data.x_tile_mode, data.y_tile_mode); + contents->SetSamplerDescriptor(data.sampler_descriptor); + contents->SetEffectTransform(data.effect_transform); + if (paint.color_filter) { + TiledTextureContents::ColorFilterProc filter_proc = + [color_filter = paint.color_filter](FilterInput::Ref input) { + return color_filter->WrapWithGPUColorFilter( + std::move(input), ColorFilterContents::AbsorbOpacity::kNo); + }; + contents->SetColorFilter(filter_proc); + } + contents->SetColorSourceSize(Size::Ceil(data.texture->GetSize())); + return contents; + } + + std::shared_ptr operator()( + const RuntimeEffectData& data) { + auto contents = std::make_shared(); + contents->SetOpacityFactor(paint.color.alpha); + contents->SetRuntimeStage(data.runtime_stage); + contents->SetUniformData(data.uniform_data); + contents->SetTextureInputs(data.texture_inputs); + return contents; + } + + std::shared_ptr operator()(const std::monostate& data) { + auto contents = std::make_shared(); + contents->SetColor(paint.color); + return contents; + } + +#if IMPELLER_ENABLE_3D + std::shared_ptr operator()(const SceneData& data) { + auto contents = std::make_shared(); + contents->SetOpacityFactor(paint.color.alpha); + contents->SetNode(data.scene_node); + contents->SetCameraTransform(data.camera_transform); + return contents; + } +#endif // IMPELLER_ENABLE_3D +}; +} // namespace + +ColorSource::ColorSource() noexcept : color_source_data_(std::monostate()) {} ColorSource::~ColorSource() = default; @@ -50,24 +171,9 @@ ColorSource ColorSource::MakeLinearGradient(Point start_point, Matrix effect_transform) { ColorSource result; result.type_ = Type::kLinearGradient; - result.proc_ = [start_point, end_point, colors = std::move(colors), - stops = std::move(stops), tile_mode, - effect_transform](const Paint& paint) { - auto contents = std::make_shared(); - contents->SetOpacityFactor(paint.color.alpha); - contents->SetColors(colors); - contents->SetStops(stops); - contents->SetEndPoints(start_point, end_point); - contents->SetTileMode(tile_mode); - contents->SetEffectTransform(effect_transform); - - std::vector bounds{start_point, end_point}; - auto intrinsic_size = Rect::MakePointBounds(bounds.begin(), bounds.end()); - if (intrinsic_size.has_value()) { - contents->SetColorSourceSize(intrinsic_size->GetSize()); - } - return contents; - }; + result.color_source_data_ = + LinearGradientData{start_point, end_point, std::move(colors), + std::move(stops), tile_mode, effect_transform}; return result; } @@ -81,27 +187,9 @@ ColorSource ColorSource::MakeConicalGradient(Point center, Matrix effect_transform) { ColorSource result; result.type_ = Type::kConicalGradient; - result.proc_ = [center, radius, colors = std::move(colors), - stops = std::move(stops), focus_center, focus_radius, - tile_mode, effect_transform](const Paint& paint) { - std::shared_ptr contents = - std::make_shared(); - contents->SetOpacityFactor(paint.color.alpha); - contents->SetColors(colors); - contents->SetStops(stops); - contents->SetCenterAndRadius(center, radius); - contents->SetTileMode(tile_mode); - contents->SetEffectTransform(effect_transform); - contents->SetFocus(focus_center, focus_radius); - - auto radius_pt = Point(radius, radius); - std::vector bounds{center + radius_pt, center - radius_pt}; - auto intrinsic_size = Rect::MakePointBounds(bounds.begin(), bounds.end()); - if (intrinsic_size.has_value()) { - contents->SetColorSourceSize(intrinsic_size->GetSize()); - } - return contents; - }; + result.color_source_data_ = ConicalGradientData{ + center, radius, std::move(colors), std::move(stops), + focus_center, focus_radius, tile_mode, effect_transform}; return result; } @@ -113,25 +201,9 @@ ColorSource ColorSource::MakeRadialGradient(Point center, Matrix effect_transform) { ColorSource result; result.type_ = Type::kRadialGradient; - result.proc_ = [center, radius, colors = std::move(colors), - stops = std::move(stops), tile_mode, - effect_transform](const Paint& paint) { - auto contents = std::make_shared(); - contents->SetOpacityFactor(paint.color.alpha); - contents->SetColors(colors); - contents->SetStops(stops); - contents->SetCenterAndRadius(center, radius); - contents->SetTileMode(tile_mode); - contents->SetEffectTransform(effect_transform); - - auto radius_pt = Point(radius, radius); - std::vector bounds{center + radius_pt, center - radius_pt}; - auto intrinsic_size = Rect::MakePointBounds(bounds.begin(), bounds.end()); - if (intrinsic_size.has_value()) { - contents->SetColorSourceSize(intrinsic_size->GetSize()); - } - return contents; - }; + result.color_source_data_ = + RadialGradientData{center, radius, std::move(colors), + std::move(stops), tile_mode, effect_transform}; return result; } @@ -144,19 +216,9 @@ ColorSource ColorSource::MakeSweepGradient(Point center, Matrix effect_transform) { ColorSource result; result.type_ = Type::kSweepGradient; - result.proc_ = [center, start_angle, end_angle, colors = std::move(colors), - stops = std::move(stops), tile_mode, - effect_transform](const Paint& paint) { - auto contents = std::make_shared(); - contents->SetOpacityFactor(paint.color.alpha); - contents->SetCenterAndAngles(center, start_angle, end_angle); - contents->SetColors(colors); - contents->SetStops(stops); - contents->SetTileMode(tile_mode); - contents->SetEffectTransform(effect_transform); - - return contents; - }; + result.color_source_data_ = SweepGradientData{ + center, start_angle, end_angle, std::move(colors), + std::move(stops), tile_mode, effect_transform}; return result; } @@ -167,26 +229,9 @@ ColorSource ColorSource::MakeImage(std::shared_ptr texture, Matrix effect_transform) { ColorSource result; result.type_ = Type::kImage; - result.proc_ = [texture = std::move(texture), x_tile_mode, y_tile_mode, - sampler_descriptor = std::move(sampler_descriptor), - effect_transform](const Paint& paint) { - auto contents = std::make_shared(); - contents->SetOpacityFactor(paint.color.alpha); - contents->SetTexture(texture); - contents->SetTileModes(x_tile_mode, y_tile_mode); - contents->SetSamplerDescriptor(sampler_descriptor); - contents->SetEffectTransform(effect_transform); - if (paint.color_filter) { - TiledTextureContents::ColorFilterProc filter_proc = - [color_filter = paint.color_filter](FilterInput::Ref input) { - return color_filter->WrapWithGPUColorFilter( - std::move(input), ColorFilterContents::AbsorbOpacity::kNo); - }; - contents->SetColorFilter(filter_proc); - } - contents->SetColorSourceSize(Size::Ceil(texture->GetSize())); - return contents; - }; + result.color_source_data_ = + ImageData{std::move(texture), x_tile_mode, y_tile_mode, + std::move(sampler_descriptor), effect_transform}; return result; } @@ -196,17 +241,9 @@ ColorSource ColorSource::MakeRuntimeEffect( std::vector texture_inputs) { ColorSource result; result.type_ = Type::kRuntimeEffect; - result.proc_ = [runtime_stage = std::move(runtime_stage), - uniform_data = std::move(uniform_data), - texture_inputs = - std::move(texture_inputs)](const Paint& paint) { - auto contents = std::make_shared(); - contents->SetOpacityFactor(paint.color.alpha); - contents->SetRuntimeStage(runtime_stage); - contents->SetUniformData(uniform_data); - contents->SetTextureInputs(texture_inputs); - return contents; - }; + result.color_source_data_ = + RuntimeEffectData{std::move(runtime_stage), std::move(uniform_data), + std::move(texture_inputs)}; return result; } @@ -215,14 +252,7 @@ ColorSource ColorSource::MakeScene(std::shared_ptr scene_node, Matrix camera_transform) { ColorSource result; result.type_ = Type::kScene; - result.proc_ = [scene_node = std::move(scene_node), - camera_transform](const Paint& paint) { - auto contents = std::make_shared(); - contents->SetOpacityFactor(paint.color.alpha); - contents->SetNode(scene_node); - contents->SetCameraTransform(camera_transform); - return contents; - }; + result.color_source_data_ = SceneData{scene_node, camera_transform}; return result; } #endif // IMPELLER_ENABLE_3D @@ -233,7 +263,7 @@ ColorSource::Type ColorSource::GetType() const { std::shared_ptr ColorSource::GetContents( const Paint& paint) const { - return proc_(paint); + return std::visit(CreateContentsVisitor{paint}, color_source_data_); } } // namespace impeller diff --git a/engine/src/flutter/impeller/aiks/color_source.h b/engine/src/flutter/impeller/aiks/color_source.h index 868362d99c4..3178467b1fa 100644 --- a/engine/src/flutter/impeller/aiks/color_source.h +++ b/engine/src/flutter/impeller/aiks/color_source.h @@ -7,9 +7,9 @@ #include #include +#include #include -#include "flutter/fml/macros.h" #include "impeller/entity/contents/runtime_effect_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/color.h" @@ -25,6 +25,77 @@ namespace impeller { struct Paint; +struct LinearGradientData { + Point start_point; + Point end_point; + std::vector colors; + std::vector stops; + Entity::TileMode tile_mode; + Matrix effect_transform; +}; + +struct RadialGradientData { + Point center; + Scalar radius; + std::vector colors; + std::vector stops; + Entity::TileMode tile_mode; + Matrix effect_transform; +}; + +struct ConicalGradientData { + Point center; + Scalar radius; + std::vector colors; + std::vector stops; + Point focus_center; + Scalar focus_radius; + Entity::TileMode tile_mode; + Matrix effect_transform; +}; + +struct SweepGradientData { + Point center; + Degrees start_angle; + Degrees end_angle; + std::vector colors; + std::vector stops; + Entity::TileMode tile_mode; + Matrix effect_transform; +}; + +struct ImageData { + std::shared_ptr texture; + Entity::TileMode x_tile_mode; + Entity::TileMode y_tile_mode; + SamplerDescriptor sampler_descriptor; + Matrix effect_transform; +}; + +struct RuntimeEffectData { + std::shared_ptr runtime_stage; + std::shared_ptr> uniform_data; + std::vector texture_inputs; +}; + +#if IMPELLER_ENABLE_3D +struct SceneData { + std::shared_ptr scene_node; + Matrix camera_transform; +}; +#endif // IMPELLER_ENABLE_3D + +using ColorSourceData = std::variant; + class ColorSource { public: enum class Type { @@ -38,9 +109,6 @@ class ColorSource { kScene, }; - using ColorSourceProc = - std::function(const Paint& paint)>; - ColorSource() noexcept; ~ColorSource(); @@ -100,7 +168,7 @@ class ColorSource { private: Type type_ = Type::kColor; - ColorSourceProc proc_; + ColorSourceData color_source_data_; }; } // namespace impeller