diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 2f977feca6b7d..e24267ab487ff 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -32,6 +32,7 @@ ../../../flutter/display_list/benchmarking/dl_complexity_unittests.cc ../../../flutter/display_list/display_list_unittests.cc ../../../flutter/display_list/dl_color_unittests.cc +../../../flutter/display_list/dl_op_spy_unittests.cc ../../../flutter/display_list/dl_paint_unittests.cc ../../../flutter/display_list/dl_vertices_unittests.cc ../../../flutter/display_list/effects/dl_color_filter_unittests.cc @@ -215,7 +216,6 @@ ../../../flutter/runtime/type_conversions_unittests.cc ../../../flutter/shell/common/animator_unittests.cc ../../../flutter/shell/common/context_options_unittests.cc -../../../flutter/shell/common/dl_op_spy_unittests.cc ../../../flutter/shell/common/engine_unittests.cc ../../../flutter/shell/common/fixtures ../../../flutter/shell/common/input_events_unittests.cc diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 5c55d6239f579..e54f19b2d83ea 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -731,6 +731,8 @@ ORIGIN: ../../../flutter/display_list/dl_op_receiver.cc + ../../../flutter/LICEN ORIGIN: ../../../flutter/display_list/dl_op_receiver.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/dl_op_records.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/dl_op_records.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/dl_op_spy.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/dl_op_spy.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/dl_paint.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/dl_paint.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/dl_sampling_options.h + ../../../flutter/LICENSE @@ -787,6 +789,8 @@ ORIGIN: ../../../flutter/flow/instrumentation.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flow/instrumentation.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flow/layer_snapshot_store.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flow/layer_snapshot_store.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/flow/layers/aiks_layer.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/flow/layers/aiks_layer.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flow/layers/backdrop_filter_layer.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flow/layers/backdrop_filter_layer.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/flow/layers/cacheable_layer.cc + ../../../flutter/LICENSE @@ -1153,6 +1157,8 @@ ORIGIN: ../../../flutter/impeller/core/texture_descriptor.cc + ../../../flutter/ ORIGIN: ../../../flutter/impeller/core/texture_descriptor.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/core/vertex_buffer.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/core/vertex_buffer.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/display_list/dl_aiks_canvas.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/display_list/dl_aiks_canvas.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/display_list/dl_dispatcher.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/display_list/dl_dispatcher.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/display_list/dl_image_impeller.cc + ../../../flutter/LICENSE @@ -2210,8 +2216,6 @@ ORIGIN: ../../../flutter/shell/common/display.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/common/display.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/common/display_manager.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/common/display_manager.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/common/dl_op_spy.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/common/dl_op_spy.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/common/engine.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/common/engine.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/common/pipeline.cc + ../../../flutter/LICENSE @@ -3441,6 +3445,8 @@ FILE: ../../../flutter/display_list/dl_op_receiver.cc FILE: ../../../flutter/display_list/dl_op_receiver.h FILE: ../../../flutter/display_list/dl_op_records.cc FILE: ../../../flutter/display_list/dl_op_records.h +FILE: ../../../flutter/display_list/dl_op_spy.cc +FILE: ../../../flutter/display_list/dl_op_spy.h FILE: ../../../flutter/display_list/dl_paint.cc FILE: ../../../flutter/display_list/dl_paint.h FILE: ../../../flutter/display_list/dl_sampling_options.h @@ -3497,6 +3503,8 @@ FILE: ../../../flutter/flow/instrumentation.cc FILE: ../../../flutter/flow/instrumentation.h FILE: ../../../flutter/flow/layer_snapshot_store.cc FILE: ../../../flutter/flow/layer_snapshot_store.h +FILE: ../../../flutter/flow/layers/aiks_layer.cc +FILE: ../../../flutter/flow/layers/aiks_layer.h FILE: ../../../flutter/flow/layers/backdrop_filter_layer.cc FILE: ../../../flutter/flow/layers/backdrop_filter_layer.h FILE: ../../../flutter/flow/layers/cacheable_layer.cc @@ -3863,6 +3871,8 @@ FILE: ../../../flutter/impeller/core/texture_descriptor.cc FILE: ../../../flutter/impeller/core/texture_descriptor.h FILE: ../../../flutter/impeller/core/vertex_buffer.cc FILE: ../../../flutter/impeller/core/vertex_buffer.h +FILE: ../../../flutter/impeller/display_list/dl_aiks_canvas.cc +FILE: ../../../flutter/impeller/display_list/dl_aiks_canvas.h FILE: ../../../flutter/impeller/display_list/dl_dispatcher.cc FILE: ../../../flutter/impeller/display_list/dl_dispatcher.h FILE: ../../../flutter/impeller/display_list/dl_image_impeller.cc @@ -4925,8 +4935,6 @@ FILE: ../../../flutter/shell/common/display.cc FILE: ../../../flutter/shell/common/display.h FILE: ../../../flutter/shell/common/display_manager.cc FILE: ../../../flutter/shell/common/display_manager.h -FILE: ../../../flutter/shell/common/dl_op_spy.cc -FILE: ../../../flutter/shell/common/dl_op_spy.h FILE: ../../../flutter/shell/common/engine.cc FILE: ../../../flutter/shell/common/engine.h FILE: ../../../flutter/shell/common/pipeline.cc diff --git a/display_list/BUILD.gn b/display_list/BUILD.gn index 97c9683511b61..07067e3150647 100644 --- a/display_list/BUILD.gn +++ b/display_list/BUILD.gn @@ -39,6 +39,8 @@ source_set("display_list") { "dl_op_receiver.h", "dl_op_records.cc", "dl_op_records.h", + "dl_op_spy.cc", + "dl_op_spy.h", "dl_paint.cc", "dl_paint.h", "dl_sampling_options.h", @@ -107,6 +109,7 @@ if (enable_unittests) { "benchmarking/dl_complexity_unittests.cc", "display_list_unittests.cc", "dl_color_unittests.cc", + "dl_op_spy_unittests.cc", "dl_paint_unittests.cc", "dl_vertices_unittests.cc", "effects/dl_color_filter_unittests.cc", diff --git a/display_list/display_list.cc b/display_list/display_list.cc index e06bcf246d3d4..73f593d135b18 100644 --- a/display_list/display_list.cc +++ b/display_list/display_list.cc @@ -34,7 +34,7 @@ DisplayList::DisplayList(DisplayListStorage&& storage, bool can_apply_group_opacity, bool is_ui_thread_safe, bool modifies_transparent_black, - sk_sp rtree) + std::shared_ptr rtree) : storage_(std::move(storage)), byte_count_(byte_count), op_count_(op_count), diff --git a/display_list/display_list.h b/display_list/display_list.h index 668a247d5596f..5b6c2e321cd0a 100644 --- a/display_list/display_list.h +++ b/display_list/display_list.h @@ -254,7 +254,7 @@ class DisplayList : public SkRefCnt { const SkRect& bounds() const { return bounds_; } bool has_rtree() const { return rtree_ != nullptr; } - sk_sp rtree() const { return rtree_; } + std::shared_ptr rtree() const { return rtree_; } bool Equals(const DisplayList* other) const; bool Equals(const DisplayList& other) const { return Equals(&other); } @@ -288,7 +288,7 @@ class DisplayList : public SkRefCnt { bool can_apply_group_opacity, bool is_ui_thread_safe, bool modifies_transparent_black, - sk_sp rtree); + std::shared_ptr rtree); static uint32_t next_unique_id(); @@ -308,7 +308,7 @@ class DisplayList : public SkRefCnt { const bool is_ui_thread_safe_; const bool modifies_transparent_black_; - const sk_sp rtree_; + const std::shared_ptr rtree_; void Dispatch(DlOpReceiver& ctx, uint8_t* ptr, diff --git a/display_list/display_list_unittests.cc b/display_list/display_list_unittests.cc index bef888bcf8633..db84b0b36bf06 100644 --- a/display_list/display_list_unittests.cc +++ b/display_list/display_list_unittests.cc @@ -2130,7 +2130,7 @@ TEST_F(DisplayListTest, FlatDrawPointsProducesBounds) { } } -static void test_rtree(const sk_sp& rtree, +static void test_rtree(const std::shared_ptr& rtree, const SkRect& query, std::vector expected_rects, const std::vector& expected_indices) { diff --git a/display_list/dl_builder.cc b/display_list/dl_builder.cc index b78145c124f42..abddd1cd54228 100644 --- a/display_list/dl_builder.cc +++ b/display_list/dl_builder.cc @@ -1208,6 +1208,13 @@ void DisplayListBuilder::DrawAtlas(const sk_sp& atlas, } } +void DisplayListBuilder::DrawImpellerPicture( + const std::shared_ptr& picture, + SkScalar opacity) { + FML_LOG(ERROR) << "Cannot draw Impeller Picture in to a a display list."; + FML_DCHECK(false); +} + void DisplayListBuilder::DrawDisplayList(const sk_sp display_list, SkScalar opacity) { if (!SkScalarIsFinite(opacity) || opacity <= SK_ScalarNearlyZero || diff --git a/display_list/dl_builder.h b/display_list/dl_builder.h index ab0bce0db3c38..90a11597b9e4e 100644 --- a/display_list/dl_builder.h +++ b/display_list/dl_builder.h @@ -216,6 +216,12 @@ class DisplayListBuilder final : public virtual DlCanvas, DlImageSampling sampling, const SkRect* cullRect, const DlPaint* paint = nullptr) override; + + // |DlCanvas| + void DrawImpellerPicture( + const std::shared_ptr& picture, + SkScalar opacity = SK_Scalar1) override; + // |DlCanvas| void DrawDisplayList(const sk_sp display_list, SkScalar opacity = SK_Scalar1) override; @@ -701,7 +707,7 @@ class DisplayListBuilder final : public virtual DlCanvas, return accumulator_->bounds(); } - sk_sp rtree() { + std::shared_ptr rtree() { FML_DCHECK(layer_stack_.size() == 1); if (is_unbounded()) { FML_LOG(INFO) << "returning partial rtree for unbounded DisplayList"; diff --git a/display_list/dl_canvas.h b/display_list/dl_canvas.h index 8fad40d23466f..af2c5a7e732de 100644 --- a/display_list/dl_canvas.h +++ b/display_list/dl_canvas.h @@ -18,6 +18,10 @@ #include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/core/SkTextBlob.h" +namespace impeller { +struct Picture; +} // namespace impeller + namespace flutter { // The primary class used to express rendering operations in the @@ -59,7 +63,12 @@ class DlCanvas { const DlImageFilter* backdrop = nullptr) = 0; virtual void Restore() = 0; virtual int GetSaveCount() const = 0; - virtual void RestoreToCount(int restore_count) = 0; + virtual void RestoreToCount(int restore_count) { + FML_DCHECK(restore_count <= GetSaveCount()); + while (restore_count < GetSaveCount() && GetSaveCount() > 1) { + Restore(); + } + } virtual void Translate(SkScalar tx, SkScalar ty) = 0; virtual void Scale(SkScalar sx, SkScalar sy) = 0; @@ -199,6 +208,9 @@ class DlCanvas { const DlPaint* paint = nullptr) = 0; virtual void DrawDisplayList(const sk_sp display_list, SkScalar opacity = SK_Scalar1) = 0; + virtual void DrawImpellerPicture( + const std::shared_ptr& picture, + SkScalar opacity = SK_Scalar1) = 0; virtual void DrawTextBlob(const sk_sp& blob, SkScalar x, SkScalar y, diff --git a/shell/common/dl_op_spy.cc b/display_list/dl_op_spy.cc similarity index 99% rename from shell/common/dl_op_spy.cc rename to display_list/dl_op_spy.cc index 15910fc2e85de..6597bfd847cad 100644 --- a/shell/common/dl_op_spy.cc +++ b/display_list/dl_op_spy.cc @@ -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 "flutter/shell/common/dl_op_spy.h" +#include "flutter/display_list/dl_op_spy.h" namespace flutter { diff --git a/shell/common/dl_op_spy.h b/display_list/dl_op_spy.h similarity index 96% rename from shell/common/dl_op_spy.h rename to display_list/dl_op_spy.h index 1cb29ff7219aa..30a05786fad06 100644 --- a/shell/common/dl_op_spy.h +++ b/display_list/dl_op_spy.h @@ -2,8 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_DISPLAY_LIST_DL_OP_SPY_H_ -#define FLUTTER_DISPLAY_LIST_DL_OP_SPY_H_ +#pragma once #include "flutter/display_list/dl_op_receiver.h" #include "flutter/display_list/utils/dl_receiver_utils.h" @@ -105,5 +104,3 @@ class DlOpSpy final : public virtual DlOpReceiver, }; } // namespace flutter - -#endif // FLUTTER_DISPLAY_LIST_DL_OP_SPY_H_ diff --git a/shell/common/dl_op_spy_unittests.cc b/display_list/dl_op_spy_unittests.cc similarity index 99% rename from shell/common/dl_op_spy_unittests.cc rename to display_list/dl_op_spy_unittests.cc index 7aaac1cbe52a8..b1d65989d1498 100644 --- a/shell/common/dl_op_spy_unittests.cc +++ b/display_list/dl_op_spy_unittests.cc @@ -4,7 +4,7 @@ #include "flutter/display_list/display_list.h" #include "flutter/display_list/dl_builder.h" -#include "flutter/shell/common/dl_op_spy.h" +#include "flutter/display_list/dl_op_spy.h" #include "flutter/testing/testing.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkRSXform.h" diff --git a/display_list/geometry/dl_rtree.h b/display_list/geometry/dl_rtree.h index f12486edcce76..31f22ee477104 100644 --- a/display_list/geometry/dl_rtree.h +++ b/display_list/geometry/dl_rtree.h @@ -25,7 +25,7 @@ namespace flutter { /// - Query for a set of non-overlapping rectangles that are joined /// from the original rectangles that intersect a query rect /// @see |searchAndConsolidateRects| -class DlRTree : public SkRefCnt { +class DlRTree { private: static constexpr int kMaxChildren = 11; diff --git a/display_list/skia/dl_sk_canvas.cc b/display_list/skia/dl_sk_canvas.cc index 842f4593035ba..a7a3c9f7cc8f8 100644 --- a/display_list/skia/dl_sk_canvas.cc +++ b/display_list/skia/dl_sk_canvas.cc @@ -335,6 +335,13 @@ void DlSkCanvasAdapter::DrawAtlas(const sk_sp& atlas, ToSk(sampling), cullRect, sk_paint()); } +void DlSkCanvasAdapter::DrawImpellerPicture( + const std::shared_ptr& picture, + SkScalar opacity) { + FML_LOG(ERROR) << "Cannot draw Impeller Picture in to a Skia canvas."; + FML_DCHECK(false); +} + void DlSkCanvasAdapter::DrawDisplayList(const sk_sp display_list, SkScalar opacity) { const int restore_count = delegate_->getSaveCount(); diff --git a/display_list/skia/dl_sk_canvas.h b/display_list/skia/dl_sk_canvas.h index af774b74342f0..f253d0a918b10 100644 --- a/display_list/skia/dl_sk_canvas.h +++ b/display_list/skia/dl_sk_canvas.h @@ -136,6 +136,9 @@ class DlSkCanvasAdapter final : public virtual DlCanvas { DlImageSampling sampling, const SkRect* cullRect, const DlPaint* paint = nullptr) override; + void DrawImpellerPicture( + const std::shared_ptr& picture, + SkScalar opacity = SK_Scalar1) override; void DrawDisplayList(const sk_sp display_list, SkScalar opacity = SK_Scalar1) override; void DrawTextBlob(const sk_sp& blob, diff --git a/display_list/utils/dl_bounds_accumulator.cc b/display_list/utils/dl_bounds_accumulator.cc index 34750ed4bd529..e609dc43baf4d 100644 --- a/display_list/utils/dl_bounds_accumulator.cc +++ b/display_list/utils/dl_bounds_accumulator.cc @@ -125,10 +125,11 @@ SkRect RTreeBoundsAccumulator::bounds() const { return accumulator.bounds(); } -sk_sp RTreeBoundsAccumulator::rtree() const { +std::shared_ptr RTreeBoundsAccumulator::rtree() const { FML_DCHECK(saved_offsets_.empty()); - return sk_make_sp(rects_.data(), rects_.size(), rect_indices_.data(), - [](int id) { return id >= 0; }); + return std::make_shared(rects_.data(), rects_.size(), + rect_indices_.data(), + [](int id) { return id >= 0; }); } } // namespace flutter diff --git a/display_list/utils/dl_bounds_accumulator.h b/display_list/utils/dl_bounds_accumulator.h index db4ceda2698b6..5e2067f1894da 100644 --- a/display_list/utils/dl_bounds_accumulator.h +++ b/display_list/utils/dl_bounds_accumulator.h @@ -84,7 +84,7 @@ class BoundsAccumulator { virtual SkRect bounds() const = 0; - virtual sk_sp rtree() const = 0; + virtual std::shared_ptr rtree() const = 0; virtual BoundsAccumulatorType type() const = 0; }; @@ -112,7 +112,7 @@ class RectBoundsAccumulator final : public virtual BoundsAccumulator { return BoundsAccumulatorType::kRect; } - sk_sp rtree() const override { return nullptr; } + std::shared_ptr rtree() const override { return nullptr; } private: class AccumulationRect { @@ -151,7 +151,7 @@ class RTreeBoundsAccumulator final : public virtual BoundsAccumulator { SkRect bounds() const override; - sk_sp rtree() const override; + std::shared_ptr rtree() const override; BoundsAccumulatorType type() const override { return BoundsAccumulatorType::kRTree; diff --git a/flow/BUILD.gn b/flow/BUILD.gn index a394ea08d9406..e5a215e4d3f34 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -22,6 +22,8 @@ source_set("flow") { "instrumentation.h", "layer_snapshot_store.cc", "layer_snapshot_store.h", + "layers/aiks_layer.cc", + "layers/aiks_layer.h", "layers/backdrop_filter_layer.cc", "layers/backdrop_filter_layer.h", "layers/cacheable_layer.cc", diff --git a/flow/embedded_views.cc b/flow/embedded_views.cc index 086882b76adf4..90ba06b73e9f5 100644 --- a/flow/embedded_views.cc +++ b/flow/embedded_views.cc @@ -3,9 +3,45 @@ // found in the LICENSE file. #include "flutter/flow/embedded_views.h" +#include "flutter/display_list/dl_op_spy.h" namespace flutter { +#if IMPELLER_SUPPORTS_RENDERING +ImpellerEmbedderViewSlice::ImpellerEmbedderViewSlice(SkRect view_bounds) { + canvas_ = std::make_unique( + /*bounds=*/view_bounds); +} + +DlCanvas* ImpellerEmbedderViewSlice::canvas() { + return canvas_ ? canvas_.get() : nullptr; +} + +void ImpellerEmbedderViewSlice::end_recording() { + picture_ = + std::make_shared(canvas_->EndRecordingAsPicture()); + canvas_.reset(); +} + +std::list ImpellerEmbedderViewSlice::searchNonOverlappingDrawnRects( + const SkRect& query) const { + FML_DCHECK(picture_); + return picture_->rtree->searchAndConsolidateRects(query); +} + +void ImpellerEmbedderViewSlice::render_into(DlCanvas* canvas) { + canvas->DrawImpellerPicture(picture_); +} + +bool ImpellerEmbedderViewSlice::recording_ended() { + return canvas_ == nullptr; +} + +bool ImpellerEmbedderViewSlice::renders_anything() { + return !picture_->rtree->bounds().isEmpty(); +} +#endif // IMPELLER_SUPPORTS_RENDERING + DisplayListEmbedderViewSlice::DisplayListEmbedderViewSlice(SkRect view_bounds) { builder_ = std::make_unique( /*bounds=*/view_bounds, @@ -30,10 +66,6 @@ void DisplayListEmbedderViewSlice::render_into(DlCanvas* canvas) { canvas->DrawDisplayList(display_list_); } -void DisplayListEmbedderViewSlice::dispatch(DlOpReceiver& receiver) { - display_list_->Dispatch(receiver); -} - bool DisplayListEmbedderViewSlice::is_empty() { return display_list_->bounds().isEmpty(); } @@ -42,6 +74,12 @@ bool DisplayListEmbedderViewSlice::recording_ended() { return builder_ == nullptr; } +bool DisplayListEmbedderViewSlice::renders_anything() { + DlOpSpy dl_op_spy; + display_list_->Dispatch(dl_op_spy); + return dl_op_spy.did_draw() && !is_empty(); +} + void ExternalViewEmbedder::SubmitFrame( GrDirectContext* context, const std::shared_ptr& aiks_context, diff --git a/flow/embedded_views.h b/flow/embedded_views.h index 6985c37e5b8c0..ccaac58255225 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -340,11 +340,33 @@ class EmbedderViewSlice { virtual std::list searchNonOverlappingDrawnRects( const SkRect& query) const = 0; virtual void render_into(DlCanvas* canvas) = 0; + virtual bool recording_ended() = 0; + virtual bool renders_anything() = 0; }; +#if IMPELLER_SUPPORTS_RENDERING +class ImpellerEmbedderViewSlice : public EmbedderViewSlice { + public: + explicit ImpellerEmbedderViewSlice(SkRect view_bounds); + ~ImpellerEmbedderViewSlice() override = default; + + DlCanvas* canvas() override; + void end_recording() override; + std::list searchNonOverlappingDrawnRects( + const SkRect& query) const override; + void render_into(DlCanvas* canvas) override; + bool recording_ended() override; + bool renders_anything() override; + + private: + std::unique_ptr canvas_; + std::shared_ptr picture_; +}; +#endif + class DisplayListEmbedderViewSlice : public EmbedderViewSlice { public: - DisplayListEmbedderViewSlice(SkRect view_bounds); + explicit DisplayListEmbedderViewSlice(SkRect view_bounds); ~DisplayListEmbedderViewSlice() override = default; DlCanvas* canvas() override; @@ -352,9 +374,9 @@ class DisplayListEmbedderViewSlice : public EmbedderViewSlice { std::list searchNonOverlappingDrawnRects( const SkRect& query) const override; void render_into(DlCanvas* canvas) override; - void dispatch(DlOpReceiver& receiver); bool is_empty(); - bool recording_ended(); + bool recording_ended() override; + bool renders_anything() override; private: std::unique_ptr builder_; diff --git a/flow/layers/aiks_layer.cc b/flow/layers/aiks_layer.cc new file mode 100644 index 0000000000000..652c735b7327d --- /dev/null +++ b/flow/layers/aiks_layer.cc @@ -0,0 +1,61 @@ +// 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 "flutter/flow/layers/aiks_layer.h" + +#include + +namespace flutter { + +AiksLayer::AiksLayer(const SkPoint& offset, + const std::shared_ptr& picture) + : offset_(offset), picture_(picture) { +#if IMPELLER_SUPPORTS_RENDERING + if (picture_) { + auto bounds = picture_->pass->GetElementsCoverage(std::nullopt) + .value_or(impeller::Rect()); + bounds_ = SkRect::MakeXYWH(bounds.origin.x + offset_.x(), + bounds.origin.y + offset.y(), bounds.size.width, + bounds.size.height); + } +#endif +} + +void AiksLayer::Diff(DiffContext* context, const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + context->PushTransform(SkMatrix::Translate(offset_.x(), offset_.y())); + context->AddLayerBounds(bounds_); + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +void AiksLayer::Preroll(PrerollContext* frame) { + // There is no opacity peepholing to do here because Impeller handles that + // in the Entities, and this layer will never participate in raster caching. + FML_DCHECK(!frame->raster_cache); + set_paint_bounds(bounds_); +} + +void AiksLayer::Paint(PaintContext& context) const { + FML_DCHECK(needs_painting(context)); + + auto mutator = context.state_stack.save(); + mutator.translate(offset_.x(), offset_.y()); + + FML_DCHECK(!context.raster_cache); + + SkScalar opacity = context.state_stack.outstanding_opacity(); + + if (context.enable_leaf_layer_tracing) { + // TODO(dnfield): Decide if we need to capture this for Impeller. + // We can't do this the same way as on the Skia backend, because Impeller + // does not expose primitives for flushing things down to the GPU without + // also allocating a texture. + // https://github.com/flutter/flutter/issues/131941 + FML_LOG(ERROR) << "Leaf layer tracing unsupported for Impeller."; + } + + context.canvas->DrawImpellerPicture(picture_, opacity); +} + +} // namespace flutter diff --git a/flow/layers/aiks_layer.h b/flow/layers/aiks_layer.h new file mode 100644 index 0000000000000..17c467e87a2f5 --- /dev/null +++ b/flow/layers/aiks_layer.h @@ -0,0 +1,40 @@ +// 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 + +#include + +#include "flutter/flow/layers/layer.h" + +#if IMPELLER_SUPPORTS_RENDERING +#include "impeller/aiks/picture.h" // nogncheck +#else // IMPELLER_SUPPORTS_RENDERING +namespace impeller { +struct Picture; +} // namespace impeller +#endif // !IMPELLER_SUPPORTS_RENDERING + +namespace flutter { + +class AiksLayer : public Layer { + public: + AiksLayer(const SkPoint& offset, + const std::shared_ptr& picture); + + void Diff(DiffContext* context, const Layer* old_layer) override; + + void Preroll(PrerollContext* frame) override; + + void Paint(PaintContext& context) const override; + + private: + SkPoint offset_; + SkRect bounds_; + std::shared_ptr picture_; + + FML_DISALLOW_COPY_AND_ASSIGN(AiksLayer); +}; + +} // namespace flutter diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index e8aea74efd78b..68ca2bdc6091d 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -155,6 +155,69 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame, } } +std::shared_ptr LayerTree::FlattenToImpellerPicture( + const SkRect& bounds, + const std::shared_ptr& texture_registry) { +#if IMPELLER_SUPPORTS_RENDERING + TRACE_EVENT0("flutter", "LayerTree::FlattenToImpellerPicture"); + + impeller::DlAiksCanvas canvas(bounds); + + const FixedRefreshRateStopwatch unused_stopwatch; + + LayerStateStack preroll_state_stack; + // No root surface transformation. So assume identity. + preroll_state_stack.set_preroll_delegate(bounds); + PrerollContext preroll_context{ + // clang-format off + .raster_cache = nullptr, + .gr_context = nullptr, + .view_embedder = nullptr, + .state_stack = preroll_state_stack, + .dst_color_space = nullptr, + .surface_needs_readback = false, + .raster_time = unused_stopwatch, + .ui_time = unused_stopwatch, + .texture_registry = texture_registry, + // clang-format on + }; + + LayerStateStack paint_state_stack; + paint_state_stack.set_delegate(&canvas); + PaintContext paint_context = { + // clang-format off + .state_stack = paint_state_stack, + .canvas = &canvas, + .gr_context = nullptr, + .dst_color_space = nullptr, + .view_embedder = nullptr, + .raster_time = unused_stopwatch, + .ui_time = unused_stopwatch, + .texture_registry = texture_registry, + .raster_cache = nullptr, + .layer_snapshot_store = nullptr, + .enable_leaf_layer_tracing = false, + // clang-format on + }; + + // Even if we don't have a root layer, we still need to create an empty + // picture. + if (root_layer_) { + root_layer_->Preroll(&preroll_context); + + // The needs painting flag may be set after the preroll. So check it after. + if (root_layer_->needs_painting(paint_context)) { + root_layer_->Paint(paint_context); + } + } + + return std::make_shared( + canvas.EndRecordingAsPicture()); +#else // IMPELLER_SUPPORTS_RENDERING + return nullptr; +#endif // !IMPELLER_SUPPORTS_RENDERING +} + sk_sp LayerTree::Flatten( const SkRect& bounds, const std::shared_ptr& texture_registry, diff --git a/flow/layers/layer_tree.h b/flow/layers/layer_tree.h index 5f573da2099a0..c4f204afae117 100644 --- a/flow/layers/layer_tree.h +++ b/flow/layers/layer_tree.h @@ -54,6 +54,10 @@ class LayerTree { const std::shared_ptr& texture_registry = nullptr, GrDirectContext* gr_context = nullptr); + std::shared_ptr FlattenToImpellerPicture( + const SkRect& bounds, + const std::shared_ptr& texture_registry); + Layer* root_layer() const { return root_layer_.get(); } const SkISize& frame_size() const { return frame_size_; } diff --git a/flow/raster_cache.cc b/flow/raster_cache.cc index 92f22f8123cfc..9932ac5f966b4 100644 --- a/flow/raster_cache.cc +++ b/flow/raster_cache.cc @@ -27,7 +27,7 @@ namespace flutter { RasterCacheResult::RasterCacheResult(sk_sp image, const SkRect& logical_rect, const char* type, - sk_sp rtree) + std::shared_ptr rtree) : image_(std::move(image)), logical_rect_(logical_rect), flow_(type), @@ -77,7 +77,7 @@ RasterCache::RasterCache(size_t access_threshold, /// @note Procedure doesn't copy all closures. std::unique_ptr RasterCache::Rasterize( const RasterCache::Context& context, - sk_sp rtree, + std::shared_ptr rtree, const std::function& draw_function, const std::function& draw_checkerboard) const { @@ -119,7 +119,7 @@ bool RasterCache::UpdateCacheEntry( const RasterCacheKeyID& id, const Context& raster_cache_context, const std::function& render_function, - sk_sp rtree) const { + std::shared_ptr rtree) const { RasterCacheKey key = RasterCacheKey(id, raster_cache_context.matrix); Entry& entry = cache_[key]; if (!entry.image) { diff --git a/flow/raster_cache.h b/flow/raster_cache.h index a00508f84d0af..acda6269f15e6 100644 --- a/flow/raster_cache.h +++ b/flow/raster_cache.h @@ -29,7 +29,7 @@ class RasterCacheResult { RasterCacheResult(sk_sp image, const SkRect& logical_rect, const char* type, - sk_sp rtree = nullptr); + std::shared_ptr rtree = nullptr); virtual ~RasterCacheResult() = default; @@ -49,7 +49,7 @@ class RasterCacheResult { sk_sp image_; SkRect logical_rect_; fml::tracing::TraceFlow flow_; - sk_sp rtree_; + std::shared_ptr rtree_; }; class Layer; @@ -129,7 +129,7 @@ class RasterCache { std::unique_ptr Rasterize( const RasterCache::Context& context, - sk_sp rtree, + std::shared_ptr rtree, const std::function& draw_function, const std::function& draw_checkerboard) const; @@ -244,7 +244,7 @@ class RasterCache { bool UpdateCacheEntry(const RasterCacheKeyID& id, const Context& raster_cache_context, const std::function& render_function, - sk_sp rtree = nullptr) const; + std::shared_ptr rtree = nullptr) const; private: struct Entry { diff --git a/flow/surface_frame.cc b/flow/surface_frame.cc index dd1b98d33b8b2..874152571a119 100644 --- a/flow/surface_frame.cc +++ b/flow/surface_frame.cc @@ -5,6 +5,7 @@ #include "flutter/flow/surface_frame.h" #include +#include #include #include "flutter/fml/logging.h" @@ -31,9 +32,13 @@ SurfaceFrame::SurfaceFrame(sk_sp surface, canvas_ = &adapter_; } else if (display_list_fallback) { FML_DCHECK(!frame_size.isEmpty()); - dl_builder_ = - sk_make_sp(SkRect::Make(frame_size), true); - canvas_ = dl_builder_.get(); +#if IMPELLER_SUPPORTS_RENDERING + aiks_canvas_ = + std::make_shared(SkRect::Make(frame_size)); + canvas_ = aiks_canvas_.get(); +#else + FML_DCHECK(false); +#endif // IMPELLER_SUPPORTS_RENDERING } } @@ -72,9 +77,14 @@ bool SurfaceFrame::PerformSubmit() { return false; } -sk_sp SurfaceFrame::BuildDisplayList() { - TRACE_EVENT0("impeller", "SurfaceFrame::BuildDisplayList"); - return dl_builder_ ? dl_builder_->Build() : nullptr; +std::shared_ptr SurfaceFrame::GetImpellerPicture() { +#if IMPELLER_SUPPORTS_RENDERING + return std::make_shared( + aiks_canvas_->EndRecordingAsPicture()); +#else + FML_DCHECK(false); + return nullptr; +#endif // IMPELLER_SUPPORTS_RENDERING } } // namespace flutter diff --git a/flow/surface_frame.h b/flow/surface_frame.h index 1abf75e573223..b653729e3ed5d 100644 --- a/flow/surface_frame.h +++ b/flow/surface_frame.h @@ -14,6 +14,14 @@ #include "flutter/fml/macros.h" #include "flutter/fml/time/time_point.h" +#if IMPELLER_SUPPORTS_RENDERING +#include "impeller/display_list/dl_aiks_canvas.h" // nogncheck +#else // IMPELLER_SUPPORTS_RENDERINGÆ’ +namespace impeller { +class DlAiksCanvas; +} // namespace impeller +#endif // !IMPELLER_SUPPORTS_RENDERING + #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkSurface.h" @@ -97,14 +105,14 @@ class SurfaceFrame { } const SubmitInfo& submit_info() const { return submit_info_; } - sk_sp BuildDisplayList(); + std::shared_ptr GetImpellerPicture(); private: bool submitted_ = false; DlSkCanvasAdapter adapter_; - sk_sp dl_builder_; sk_sp surface_; + std::shared_ptr aiks_canvas_; DlCanvas* canvas_ = nullptr; FramebufferInfo framebuffer_info_; SubmitInfo submit_info_; diff --git a/flow/surface_frame_unittests.cc b/flow/surface_frame_unittests.cc index 0f6f9ba3081fc..540981bfaf8f9 100644 --- a/flow/surface_frame_unittests.cc +++ b/flow/surface_frame_unittests.cc @@ -22,6 +22,7 @@ TEST(FlowTest, SurfaceFrameDoesNotSubmitInDtor) { surface_frame.reset(); } +#if IMPELLER_SUPPORTS_RENDERING TEST(FlowTest, SurfaceFrameDoesNotHaveEmptyCanvas) { SurfaceFrame::FramebufferInfo framebuffer_info; SurfaceFrame frame( @@ -33,5 +34,6 @@ TEST(FlowTest, SurfaceFrameDoesNotHaveEmptyCanvas) { EXPECT_FALSE(frame.Canvas()->GetLocalClipBounds().isEmpty()); EXPECT_FALSE(frame.Canvas()->QuickReject(SkRect::MakeLTRB(10, 10, 50, 50))); } +#endif // IMPELLER_SUPPORTS_RENDERING } // namespace flutter diff --git a/impeller/aiks/BUILD.gn b/impeller/aiks/BUILD.gn index d63facbd642fd..c760dfc58bfa6 100644 --- a/impeller/aiks/BUILD.gn +++ b/impeller/aiks/BUILD.gn @@ -32,7 +32,10 @@ impeller_component("aiks") { "../geometry", ] - deps = [ "//flutter/fml" ] + deps = [ + "//flutter/display_list", + "//flutter/fml", + ] } impeller_component("aiks_playground") { diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 84cb7544fdcd7..b5820817a6dd3 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -8,6 +8,7 @@ #include #include +#include "display_list/geometry/dl_rtree.h" #include "flutter/fml/logging.h" #include "impeller/aiks/paint_pass_delegate.h" #include "impeller/entity/contents/atlas_contents.h" @@ -19,6 +20,7 @@ #include "impeller/entity/contents/vertices_contents.h" #include "impeller/entity/geometry/geometry.h" #include "impeller/geometry/path_builder.h" +#include "include/core/SkRect.h" namespace impeller { @@ -493,6 +495,19 @@ Picture Canvas::EndRecordingAsPicture() { Picture picture; picture.pass = std::move(base_pass_); + std::vector rects; + picture.pass->IterateAllEntities([&rects](const Entity& entity) { + auto coverage = entity.GetCoverage(); + if (coverage.has_value()) { + rects.push_back(SkRect::MakeLTRB(coverage->GetLeft(), coverage->GetTop(), + coverage->GetRight(), + coverage->GetBottom())); + } + return true; + }); + picture.rtree = + std::make_shared(rects.data(), rects.size()); + Reset(); Initialize(initial_cull_rect_); diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index 84f1c486bc30f..9854c01196171 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -64,6 +64,8 @@ class Canvas { ~Canvas(); + std::optional BaseCullRect() const { return initial_cull_rect_; } + void Save(); void SaveLayer(const Paint& paint, diff --git a/impeller/aiks/picture.h b/impeller/aiks/picture.h index f4e8a640efa9a..bb769000a10ae 100644 --- a/impeller/aiks/picture.h +++ b/impeller/aiks/picture.h @@ -8,6 +8,7 @@ #include #include +#include "display_list/geometry/dl_rtree.h" #include "flutter/fml/macros.h" #include "impeller/aiks/aiks_context.h" #include "impeller/aiks/image.h" @@ -18,6 +19,7 @@ namespace impeller { struct Picture { std::unique_ptr pass; + std::shared_ptr rtree; std::optional Snapshot(AiksContext& context); diff --git a/impeller/display_list/BUILD.gn b/impeller/display_list/BUILD.gn index f27e8f52ad2dd..177401d430700 100644 --- a/impeller/display_list/BUILD.gn +++ b/impeller/display_list/BUILD.gn @@ -22,6 +22,8 @@ impeller_component("skia_conversions") { impeller_component("display_list") { sources = [ + "dl_aiks_canvas.cc", + "dl_aiks_canvas.h", "dl_dispatcher.cc", "dl_dispatcher.h", "dl_image_impeller.cc", diff --git a/impeller/display_list/dl_aiks_canvas.cc b/impeller/display_list/dl_aiks_canvas.cc new file mode 100644 index 0000000000000..004fc4bdcb1b7 --- /dev/null +++ b/impeller/display_list/dl_aiks_canvas.cc @@ -0,0 +1,1191 @@ +// 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 "impeller/display_list/dl_aiks_canvas.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "flutter/fml/logging.h" +#include "flutter/fml/trace_event.h" +#include "impeller/aiks/color_filter.h" +#include "impeller/core/formats.h" +#include "impeller/display_list/dl_image_impeller.h" +#include "impeller/display_list/dl_vertices_geometry.h" +#include "impeller/display_list/nine_patch_converter.h" +#include "impeller/display_list/skia_conversions.h" +#include "impeller/entity/contents/conical_gradient_contents.h" +#include "impeller/entity/contents/filters/filter_contents.h" +#include "impeller/entity/contents/filters/inputs/filter_input.h" +#include "impeller/entity/contents/linear_gradient_contents.h" +#include "impeller/entity/contents/radial_gradient_contents.h" +#include "impeller/entity/contents/runtime_effect_contents.h" +#include "impeller/entity/contents/scene_contents.h" +#include "impeller/entity/contents/sweep_gradient_contents.h" +#include "impeller/entity/contents/tiled_texture_contents.h" +#include "impeller/entity/entity.h" +#include "impeller/entity/geometry/geometry.h" +#include "impeller/geometry/path.h" +#include "impeller/geometry/path_builder.h" +#include "impeller/geometry/scalar.h" +#include "impeller/geometry/sigma.h" +#include "impeller/typographer/backends/skia/text_frame_skia.h" + +namespace impeller { + +#define UNIMPLEMENTED \ + FML_DLOG(ERROR) << "Unimplemented detail in " << __FUNCTION__; + +DlAiksCanvas::DlAiksCanvas(const SkRect& cull_rect, bool prepare_rtree) + : canvas_(skia_conversions::ToRect(cull_rect)) { + if (prepare_rtree) { + accumulator_ = std::make_unique(); + } +} + +DlAiksCanvas::DlAiksCanvas(const SkIRect& cull_rect, bool prepare_rtree) + : DlAiksCanvas(SkRect::Make(cull_rect), prepare_rtree) {} + +DlAiksCanvas::~DlAiksCanvas() = default; + +static Paint::Style ToStyle(flutter::DlDrawStyle style) { + switch (style) { + case flutter::DlDrawStyle::kFill: + return Paint::Style::kFill; + case flutter::DlDrawStyle::kStroke: + return Paint::Style::kStroke; + case flutter::DlDrawStyle::kStrokeAndFill: + UNIMPLEMENTED; + break; + } + return Paint::Style::kFill; +} + +static Cap ToStrokeCap(flutter::DlStrokeCap cap) { + switch (cap) { + case flutter::DlStrokeCap::kButt: + return Cap::kButt; + case flutter::DlStrokeCap::kRound: + return Cap::kRound; + case flutter::DlStrokeCap::kSquare: + return Cap::kSquare; + } + FML_UNREACHABLE(); +} + +static Matrix ToMatrix(const SkMatrix& m) { + return Matrix{ + // clang-format off + m[0], m[3], 0, m[6], + m[1], m[4], 0, m[7], + 0, 0, 1, 0, + m[2], m[5], 0, m[8], + // clang-format on + }; +} + +static Matrix ToMatrix(const SkM44& m) { + return Matrix{ + // clang-format off + m.rc(0, 0), m.rc(1, 0), m.rc(2, 0), m.rc(3, 0), + m.rc(0, 1), m.rc(1, 1), m.rc(2, 1), m.rc(3, 1), + m.rc(0, 2), m.rc(1, 2), m.rc(2, 2), m.rc(3, 2), + m.rc(0, 3), m.rc(1, 3), m.rc(2, 3), m.rc(3, 3), + // clang-format on + }; +} + +static Join ToStrokeJoin(flutter::DlStrokeJoin join) { + switch (join) { + case flutter::DlStrokeJoin::kMiter: + return Join::kMiter; + case flutter::DlStrokeJoin::kRound: + return Join::kRound; + case flutter::DlStrokeJoin::kBevel: + return Join::kBevel; + } + FML_UNREACHABLE(); +} + +static impeller::SamplerDescriptor ToSamplerDescriptor( + const flutter::DlImageSampling options) { + impeller::SamplerDescriptor desc; + switch (options) { + case flutter::DlImageSampling::kNearestNeighbor: + desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kNearest; + desc.label = "Nearest Sampler"; + break; + case flutter::DlImageSampling::kLinear: + // Impeller doesn't support cubic sampling, but linear is closer to correct + // than nearest for this case. + case flutter::DlImageSampling::kCubic: + desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kLinear; + desc.label = "Linear Sampler"; + break; + case flutter::DlImageSampling::kMipmapLinear: + desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kLinear; + desc.mip_filter = impeller::MipFilter::kLinear; + desc.label = "Mipmap Linear Sampler"; + break; + } + return desc; +} + +static impeller::SamplerDescriptor ToSamplerDescriptor( + const flutter::DlFilterMode options) { + impeller::SamplerDescriptor desc; + switch (options) { + case flutter::DlFilterMode::kNearest: + desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kNearest; + desc.label = "Nearest Sampler"; + break; + case flutter::DlFilterMode::kLinear: + desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kLinear; + desc.label = "Linear Sampler"; + break; + default: + break; + } + return desc; +} + +static FilterContents::BlurStyle ToBlurStyle(flutter::DlBlurStyle blur_style) { + switch (blur_style) { + case flutter::DlBlurStyle::kNormal: + return FilterContents::BlurStyle::kNormal; + case flutter::DlBlurStyle::kSolid: + return FilterContents::BlurStyle::kSolid; + case flutter::DlBlurStyle::kOuter: + return FilterContents::BlurStyle::kOuter; + case flutter::DlBlurStyle::kInner: + return FilterContents::BlurStyle::kInner; + } +} + +static std::optional ToMaskBlurDescriptor( + const flutter::DlMaskFilter* filter) { + if (filter == nullptr) { + return std::nullopt; + } + switch (filter->type()) { + case flutter::DlMaskFilterType::kBlur: { + auto blur = filter->asBlur(); + + return Paint::MaskBlurDescriptor{ + .style = ToBlurStyle(blur->style()), + .sigma = Sigma(blur->sigma()), + }; + } + } + + return std::nullopt; +} + +static BlendMode ToBlendMode(flutter::DlBlendMode mode) { + switch (mode) { + case flutter::DlBlendMode::kClear: + return BlendMode::kClear; + case flutter::DlBlendMode::kSrc: + return BlendMode::kSource; + case flutter::DlBlendMode::kDst: + return BlendMode::kDestination; + case flutter::DlBlendMode::kSrcOver: + return BlendMode::kSourceOver; + case flutter::DlBlendMode::kDstOver: + return BlendMode::kDestinationOver; + case flutter::DlBlendMode::kSrcIn: + return BlendMode::kSourceIn; + case flutter::DlBlendMode::kDstIn: + return BlendMode::kDestinationIn; + case flutter::DlBlendMode::kSrcOut: + return BlendMode::kSourceOut; + case flutter::DlBlendMode::kDstOut: + return BlendMode::kDestinationOut; + case flutter::DlBlendMode::kSrcATop: + return BlendMode::kSourceATop; + case flutter::DlBlendMode::kDstATop: + return BlendMode::kDestinationATop; + case flutter::DlBlendMode::kXor: + return BlendMode::kXor; + case flutter::DlBlendMode::kPlus: + return BlendMode::kPlus; + case flutter::DlBlendMode::kModulate: + return BlendMode::kModulate; + case flutter::DlBlendMode::kScreen: + return BlendMode::kScreen; + case flutter::DlBlendMode::kOverlay: + return BlendMode::kOverlay; + case flutter::DlBlendMode::kDarken: + return BlendMode::kDarken; + case flutter::DlBlendMode::kLighten: + return BlendMode::kLighten; + case flutter::DlBlendMode::kColorDodge: + return BlendMode::kColorDodge; + case flutter::DlBlendMode::kColorBurn: + return BlendMode::kColorBurn; + case flutter::DlBlendMode::kHardLight: + return BlendMode::kHardLight; + case flutter::DlBlendMode::kSoftLight: + return BlendMode::kSoftLight; + case flutter::DlBlendMode::kDifference: + return BlendMode::kDifference; + case flutter::DlBlendMode::kExclusion: + return BlendMode::kExclusion; + case flutter::DlBlendMode::kMultiply: + return BlendMode::kMultiply; + case flutter::DlBlendMode::kHue: + return BlendMode::kHue; + case flutter::DlBlendMode::kSaturation: + return BlendMode::kSaturation; + case flutter::DlBlendMode::kColor: + return BlendMode::kColor; + case flutter::DlBlendMode::kLuminosity: + return BlendMode::kLuminosity; + } + FML_UNREACHABLE(); +} + +static Entity::TileMode ToTileMode(flutter::DlTileMode tile_mode) { + switch (tile_mode) { + case flutter::DlTileMode::kClamp: + return Entity::TileMode::kClamp; + case flutter::DlTileMode::kRepeat: + return Entity::TileMode::kRepeat; + case flutter::DlTileMode::kMirror: + return Entity::TileMode::kMirror; + case flutter::DlTileMode::kDecal: + return Entity::TileMode::kDecal; + } +} + +static Color ToColor(const flutter::DlColor& color) { + return { + color.getRedF(), + color.getGreenF(), + color.getBlueF(), + color.getAlphaF(), + }; +} + +static std::vector ToColors(const flutter::DlColor colors[], int count) { + auto result = std::vector(); + if (colors == nullptr) { + return result; + } + for (int i = 0; i < count; i++) { + result.push_back(skia_conversions::ToColor(colors[i])); + } + return result; +} + +// Convert display list colors + stops into impeller colors and stops, taking +// care to ensure that the stops always start with 0.0 and end with 1.0. +template +static void ConvertStops(T* gradient, + std::vector* colors, + std::vector* stops) { + FML_DCHECK(gradient->stop_count() >= 2); + + auto* dl_colors = gradient->colors(); + auto* dl_stops = gradient->stops(); + if (dl_stops[0] != 0.0) { + colors->emplace_back(skia_conversions::ToColor(dl_colors[0])); + stops->emplace_back(0); + } + for (auto i = 0; i < gradient->stop_count(); i++) { + colors->emplace_back(skia_conversions::ToColor(dl_colors[i])); + stops->emplace_back(dl_stops[i]); + } + if (stops->back() != 1.0) { + colors->emplace_back(colors->back()); + stops->emplace_back(1.0); + } +} + +static std::optional ToColorSourceType( + flutter::DlColorSourceType type) { + switch (type) { + case flutter::DlColorSourceType::kColor: + return ColorSource::Type::kColor; + case flutter::DlColorSourceType::kImage: + return ColorSource::Type::kImage; + case flutter::DlColorSourceType::kLinearGradient: + return ColorSource::Type::kLinearGradient; + case flutter::DlColorSourceType::kRadialGradient: + return ColorSource::Type::kRadialGradient; + case flutter::DlColorSourceType::kConicalGradient: + return ColorSource::Type::kConicalGradient; + case flutter::DlColorSourceType::kSweepGradient: + return ColorSource::Type::kSweepGradient; + case flutter::DlColorSourceType::kRuntimeEffect: + return ColorSource::Type::kRuntimeEffect; +#ifdef IMPELLER_ENABLE_3D + case flutter::DlColorSourceType::kScene: + return ColorSource::Type::kScene; +#endif // IMPELLER_ENABLE_3D + } +} + +ColorSource ToColorSource(const flutter::DlColorSource* source, Paint* paint) { + if (!source) { + return ColorSource::MakeColor(); + } + + std::optional type = ToColorSourceType(source->type()); + + if (!type.has_value()) { + FML_LOG(ERROR) << "Requested ColorSourceType::kUnknown"; + return ColorSource::MakeColor(); + } + + switch (type.value()) { + case ColorSource::Type::kColor: { + const flutter::DlColorColorSource* color = source->asColor(); + FML_DCHECK(color); + FML_DCHECK(paint); + paint->color = ToColor(color->color()); + return ColorSource::MakeColor(); + } + case ColorSource::Type::kLinearGradient: { + const flutter::DlLinearGradientColorSource* linear = + source->asLinearGradient(); + FML_DCHECK(linear); + auto start_point = skia_conversions::ToPoint(linear->start_point()); + auto end_point = skia_conversions::ToPoint(linear->end_point()); + std::vector colors; + std::vector stops; + ConvertStops(linear, &colors, &stops); + + auto tile_mode = ToTileMode(linear->tile_mode()); + auto matrix = ToMatrix(linear->matrix()); + + return ColorSource::MakeLinearGradient( + start_point, end_point, std::move(colors), std::move(stops), + tile_mode, matrix); + } + case ColorSource::Type::kConicalGradient: { + const flutter::DlConicalGradientColorSource* conical_gradient = + source->asConicalGradient(); + FML_DCHECK(conical_gradient); + Point center = skia_conversions::ToPoint(conical_gradient->end_center()); + SkScalar radius = conical_gradient->end_radius(); + Point focus_center = + skia_conversions::ToPoint(conical_gradient->start_center()); + SkScalar focus_radius = conical_gradient->start_radius(); + std::vector colors; + std::vector stops; + ConvertStops(conical_gradient, &colors, &stops); + + auto tile_mode = ToTileMode(conical_gradient->tile_mode()); + auto matrix = ToMatrix(conical_gradient->matrix()); + + return ColorSource::MakeConicalGradient(center, radius, std::move(colors), + std::move(stops), focus_center, + focus_radius, tile_mode, matrix); + } + case ColorSource::Type::kRadialGradient: { + const flutter::DlRadialGradientColorSource* radialGradient = + source->asRadialGradient(); + FML_DCHECK(radialGradient); + auto center = skia_conversions::ToPoint(radialGradient->center()); + auto radius = radialGradient->radius(); + std::vector colors; + std::vector stops; + ConvertStops(radialGradient, &colors, &stops); + + auto tile_mode = ToTileMode(radialGradient->tile_mode()); + auto matrix = ToMatrix(radialGradient->matrix()); + return ColorSource::MakeRadialGradient(center, radius, std::move(colors), + std::move(stops), tile_mode, + matrix); + } + case ColorSource::Type::kSweepGradient: { + const flutter::DlSweepGradientColorSource* sweepGradient = + source->asSweepGradient(); + FML_DCHECK(sweepGradient); + + auto center = skia_conversions::ToPoint(sweepGradient->center()); + auto start_angle = Degrees(sweepGradient->start()); + auto end_angle = Degrees(sweepGradient->end()); + std::vector colors; + std::vector stops; + ConvertStops(sweepGradient, &colors, &stops); + + auto tile_mode = ToTileMode(sweepGradient->tile_mode()); + auto matrix = ToMatrix(sweepGradient->matrix()); + return ColorSource::MakeSweepGradient(center, start_angle, end_angle, + std::move(colors), std::move(stops), + tile_mode, matrix); + } + case ColorSource::Type::kImage: { + const flutter::DlImageColorSource* image_color_source = source->asImage(); + FML_DCHECK(image_color_source && + image_color_source->image()->impeller_texture()); + auto texture = image_color_source->image()->impeller_texture(); + auto x_tile_mode = ToTileMode(image_color_source->horizontal_tile_mode()); + auto y_tile_mode = ToTileMode(image_color_source->vertical_tile_mode()); + auto desc = ToSamplerDescriptor(image_color_source->sampling()); + auto matrix = ToMatrix(image_color_source->matrix()); + return ColorSource::MakeImage(texture, x_tile_mode, y_tile_mode, desc, + matrix); + } + case ColorSource::Type::kRuntimeEffect: { + const flutter::DlRuntimeEffectColorSource* runtime_effect_color_source = + source->asRuntimeEffect(); + auto runtime_stage = + runtime_effect_color_source->runtime_effect()->runtime_stage(); + auto uniform_data = runtime_effect_color_source->uniform_data(); + auto samplers = runtime_effect_color_source->samplers(); + + std::vector texture_inputs; + + for (auto& sampler : samplers) { + if (sampler == nullptr) { + return ColorSource::MakeColor(); + } + auto* image = sampler->asImage(); + if (!sampler->asImage()) { + UNIMPLEMENTED; + return ColorSource::MakeColor(); + } + FML_DCHECK(image->image()->impeller_texture()); + texture_inputs.push_back({ + .sampler_descriptor = ToSamplerDescriptor(image->sampling()), + .texture = image->image()->impeller_texture(), + }); + } + + return ColorSource::MakeRuntimeEffect(runtime_stage, uniform_data, + texture_inputs); + } + case ColorSource::Type::kScene: { +#ifdef IMPELLER_ENABLE_3D + const flutter::DlSceneColorSource* scene_color_source = source->asScene(); + std::shared_ptr scene_node = + scene_color_source->scene_node(); + Matrix camera_transform = scene_color_source->camera_matrix(); + + return ColorSource::MakeScene(scene_node, camera_transform); +#else // IMPELLER_ENABLE_3D + FML_LOG(ERROR) << "ColorSourceType::kScene can only be used if Impeller " + "Scene is enabled."; + return ColorSource::MakeColor(); +#endif // IMPELLER_ENABLE_3D + } + } +} + +static std::shared_ptr ToColorFilter( + const flutter::DlColorFilter* filter) { + if (filter == nullptr) { + return nullptr; + } + switch (filter->type()) { + case flutter::DlColorFilterType::kBlend: { + auto dl_blend = filter->asBlend(); + auto blend_mode = ToBlendMode(dl_blend->mode()); + auto color = skia_conversions::ToColor(dl_blend->color()); + return ColorFilter::MakeBlend(blend_mode, color); + } + case flutter::DlColorFilterType::kMatrix: { + const flutter::DlMatrixColorFilter* dl_matrix = filter->asMatrix(); + impeller::ColorMatrix color_matrix; + dl_matrix->get_matrix(color_matrix.array); + return ColorFilter::MakeMatrix(color_matrix); + } + case flutter::DlColorFilterType::kSrgbToLinearGamma: + return ColorFilter::MakeSrgbToLinear(); + case flutter::DlColorFilterType::kLinearToSrgbGamma: + return ColorFilter::MakeLinearToSrgb(); + } + return nullptr; +} + +static Paint::ImageFilterProc ToImageFilterProc( + const flutter::DlImageFilter* filter) { + if (filter == nullptr) { + return nullptr; + } + + switch (filter->type()) { + case flutter::DlImageFilterType::kBlur: { + auto blur = filter->asBlur(); + auto sigma_x = Sigma(blur->sigma_x()); + auto sigma_y = Sigma(blur->sigma_y()); + auto tile_mode = ToTileMode(blur->tile_mode()); + + return [sigma_x, sigma_y, tile_mode](const FilterInput::Ref& input, + const Matrix& effect_transform, + bool is_subpass) { + return FilterContents::MakeGaussianBlur( + input, sigma_x, sigma_y, FilterContents::BlurStyle::kNormal, + tile_mode, effect_transform); + }; + + break; + } + case flutter::DlImageFilterType::kDilate: { + auto dilate = filter->asDilate(); + FML_DCHECK(dilate); + if (dilate->radius_x() < 0 || dilate->radius_y() < 0) { + return nullptr; + } + auto radius_x = Radius(dilate->radius_x()); + auto radius_y = Radius(dilate->radius_y()); + return [radius_x, radius_y](FilterInput::Ref input, + const Matrix& effect_transform, + bool is_subpass) { + return FilterContents::MakeMorphology( + std::move(input), radius_x, radius_y, + FilterContents::MorphType::kDilate, effect_transform); + }; + break; + } + case flutter::DlImageFilterType::kErode: { + auto erode = filter->asErode(); + FML_DCHECK(erode); + if (erode->radius_x() < 0 || erode->radius_y() < 0) { + return nullptr; + } + auto radius_x = Radius(erode->radius_x()); + auto radius_y = Radius(erode->radius_y()); + return [radius_x, radius_y](FilterInput::Ref input, + const Matrix& effect_transform, + bool is_subpass) { + return FilterContents::MakeMorphology( + std::move(input), radius_x, radius_y, + FilterContents::MorphType::kErode, effect_transform); + }; + break; + } + case flutter::DlImageFilterType::kMatrix: { + auto matrix_filter = filter->asMatrix(); + FML_DCHECK(matrix_filter); + auto matrix = ToMatrix(matrix_filter->matrix()); + auto desc = ToSamplerDescriptor(matrix_filter->sampling()); + return [matrix, desc](FilterInput::Ref input, + const Matrix& effect_transform, bool is_subpass) { + return FilterContents::MakeMatrixFilter(std::move(input), matrix, desc, + effect_transform, is_subpass); + }; + break; + } + case flutter::DlImageFilterType::kCompose: { + auto compose = filter->asCompose(); + FML_DCHECK(compose); + auto outer = compose->outer(); + auto inner = compose->inner(); + auto outer_proc = ToImageFilterProc(outer.get()); + auto inner_proc = ToImageFilterProc(inner.get()); + if (!outer_proc) { + return inner_proc; + } + if (!inner_proc) { + return outer_proc; + } + FML_DCHECK(outer_proc && inner_proc); + return [outer_filter = outer_proc, inner_filter = inner_proc]( + FilterInput::Ref input, const Matrix& effect_transform, + bool is_subpass) { + auto contents = + inner_filter(std::move(input), effect_transform, is_subpass); + contents = outer_filter(FilterInput::Make(contents), effect_transform, + is_subpass); + return contents; + }; + break; + } + case flutter::DlImageFilterType::kColorFilter: { + auto color_filter_image_filter = filter->asColorFilter(); + FML_DCHECK(color_filter_image_filter); + auto color_filter = + ToColorFilter(color_filter_image_filter->color_filter().get()); + if (!color_filter) { + return nullptr; + } + return [color_filter](FilterInput::Ref input, + const Matrix& effect_transform, bool is_subpass) { + // When color filters are used as image filters, set the color filter's + // "absorb opacity" flag to false. For image filters, the snapshot + // opacity needs to be deferred until the result of the filter chain is + // being blended with the layer. + return color_filter->WrapWithGPUColorFilter(std::move(input), false); + }; + break; + } + case flutter::DlImageFilterType::kLocalMatrix: { + auto local_matrix_filter = filter->asLocalMatrix(); + FML_DCHECK(local_matrix_filter); + auto internal_filter = local_matrix_filter->image_filter(); + FML_DCHECK(internal_filter); + + auto image_filter_proc = ToImageFilterProc(internal_filter.get()); + if (!image_filter_proc) { + return nullptr; + } + + auto matrix = ToMatrix(local_matrix_filter->matrix()); + + return [matrix, filter_proc = image_filter_proc]( + FilterInput::Ref input, const Matrix& effect_transform, + bool is_subpass) { + std::shared_ptr filter = + filter_proc(std::move(input), effect_transform, is_subpass); + return FilterContents::MakeLocalMatrixFilter(FilterInput::Make(filter), + matrix); + }; + break; + } + } +} + +static Paint ToPaint(const flutter::DlPaint& dl_paint) { + Paint paint; + paint.style = ToStyle(dl_paint.getDrawStyle()); + paint.color = ToColor(dl_paint.getColor()); + paint.stroke_width = dl_paint.getStrokeWidth(); + paint.stroke_miter = dl_paint.getStrokeMiter(); + paint.stroke_cap = ToStrokeCap(dl_paint.getStrokeCap()); + paint.stroke_join = ToStrokeJoin(dl_paint.getStrokeJoin()); + paint.color_source = ToColorSource(dl_paint.getColorSourcePtr(), &paint); + paint.color_filter = ToColorFilter(dl_paint.getColorFilterPtr()); + paint.invert_colors = dl_paint.isInvertColors(); + paint.blend_mode = ToBlendMode(dl_paint.getBlendMode()); + if (dl_paint.getPathEffect()) { + UNIMPLEMENTED; + } + paint.mask_blur_descriptor = + ToMaskBlurDescriptor(dl_paint.getMaskFilterPtr()); + paint.image_filter = ToImageFilterProc(dl_paint.getImageFilterPtr()); + return paint; +} + +static Paint ToPaint(const flutter::DlPaint* dl_paint) { + if (!dl_paint) { + return Paint(); + } + return ToPaint(*dl_paint); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::Save() { + canvas_.Save(); + if (accumulator_) { + accumulator_->save(); + } +} + +// |flutter::DlCanvas| +void DlAiksCanvas::SaveLayer(const SkRect* bounds, + const flutter::DlPaint* paint, + const flutter::DlImageFilter* backdrop) { + if (!paint) { + return; + } + canvas_.SaveLayer(ToPaint(paint), skia_conversions::ToRect(bounds), + ToImageFilterProc(backdrop)); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::Restore() { + canvas_.Restore(); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::Translate(SkScalar tx, SkScalar ty) { + canvas_.Translate({tx, ty, 0.0}); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::Scale(SkScalar sx, SkScalar sy) { + canvas_.Scale({sx, sy, 1.0}); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::Rotate(SkScalar degrees) { + canvas_.Rotate(Degrees{degrees}); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::Skew(SkScalar sx, SkScalar sy) { + canvas_.Skew(sx, sy); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::Transform2DAffine(SkScalar mxx, + SkScalar mxy, + SkScalar mxt, + SkScalar myx, + SkScalar myy, + SkScalar myt) { + // clang-format off + TransformFullPerspective( + mxx, mxy, 0, mxt, + myx, myy, 0, myt, + 0 , 0, 1, 0, + 0 , 0, 0, 1 + ); + // clang-format on +} + +// |flutter::DlCanvas| +void DlAiksCanvas::TransformFullPerspective(SkScalar mxx, + SkScalar mxy, + SkScalar mxz, + SkScalar mxt, + SkScalar myx, + SkScalar myy, + SkScalar myz, + SkScalar myt, + SkScalar mzx, + SkScalar mzy, + SkScalar mzz, + SkScalar mzt, + SkScalar mwx, + SkScalar mwy, + SkScalar mwz, + SkScalar mwt) { + // The order of arguments is row-major but Impeller matrices are + // column-major. + // clang-format off + auto xformation = Matrix{ + mxx, myx, mzx, mwx, + mxy, myy, mzy, mwy, + mxz, myz, mzz, mwz, + mxt, myt, mzt, mwt + }; + // clang-format on + canvas_.Transform(xformation); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::TransformReset() { + canvas_.ResetTransform(); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::Transform(const SkMatrix* matrix) { + if (!matrix) { + return; + } + canvas_.Transform(ToMatrix(*matrix)); +} + +void DlAiksCanvas::Transform(const SkM44* matrix44) { + if (!matrix44) { + return; + } + canvas_.Transform(ToMatrix(*matrix44)); +} + +static Entity::ClipOperation ToClipOperation( + flutter::DlCanvas::ClipOp clip_op) { + switch (clip_op) { + case flutter::DlCanvas::ClipOp::kDifference: + return Entity::ClipOperation::kDifference; + case flutter::DlCanvas::ClipOp::kIntersect: + return Entity::ClipOperation::kIntersect; + } +} + +// |flutter::DlCanvas| +void DlAiksCanvas::ClipRect(const SkRect& rect, ClipOp clip_op, bool is_aa) { + canvas_.ClipRect(skia_conversions::ToRect(rect), ToClipOperation(clip_op)); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::ClipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) { + if (rrect.isSimple()) { + canvas_.ClipRRect(skia_conversions::ToRect(rrect.rect()), + rrect.getSimpleRadii().fX, ToClipOperation(clip_op)); + } else { + canvas_.ClipPath(skia_conversions::ToPath(rrect), ToClipOperation(clip_op)); + } +} + +// |flutter::DlCanvas| +void DlAiksCanvas::ClipPath(const SkPath& path, ClipOp clip_op, bool is_aa) { + canvas_.ClipPath(skia_conversions::ToPath(path), ToClipOperation(clip_op)); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawColor(flutter::DlColor color, + flutter::DlBlendMode dl_mode) { + Paint paint; + paint.color = skia_conversions::ToColor(color); + paint.blend_mode = ToBlendMode(dl_mode); + canvas_.DrawPaint(paint); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawPaint(const flutter::DlPaint& paint) { + canvas_.DrawPaint(ToPaint(paint)); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawLine(const SkPoint& p0, + const SkPoint& p1, + const flutter::DlPaint& paint) { + auto path = + PathBuilder{} + .AddLine(skia_conversions::ToPoint(p0), skia_conversions::ToPoint(p1)) + .SetConvexity(Convexity::kConvex) + .TakePath(); + auto aiks_paint = ToPaint(paint); + aiks_paint.style = Paint::Style::kStroke; + canvas_.DrawPath(path, aiks_paint); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawRect(const SkRect& rect, const flutter::DlPaint& paint) { + canvas_.DrawRect(skia_conversions::ToRect(rect), ToPaint(paint)); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawOval(const SkRect& bounds, + const flutter::DlPaint& paint) { + if (bounds.width() == bounds.height()) { + canvas_.DrawCircle(skia_conversions::ToPoint(bounds.center()), + bounds.width() * 0.5, ToPaint(paint)); + } else { + auto path = PathBuilder{} + .AddOval(skia_conversions::ToRect(bounds)) + .SetConvexity(Convexity::kConvex) + .TakePath(); + canvas_.DrawPath(path, ToPaint(paint)); + } +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawCircle(const SkPoint& center, + SkScalar radius, + const flutter::DlPaint& paint) { + canvas_.DrawCircle(skia_conversions::ToPoint(center), radius, ToPaint(paint)); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawRRect(const SkRRect& rrect, + const flutter::DlPaint& paint) { + if (rrect.isSimple()) { + canvas_.DrawRRect(skia_conversions::ToRect(rrect.rect()), + rrect.getSimpleRadii().fX, ToPaint(paint)); + } else { + canvas_.DrawPath(skia_conversions::ToPath(rrect), ToPaint(paint)); + } +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawDRRect(const SkRRect& outer, + const SkRRect& inner, + const flutter::DlPaint& paint) { + PathBuilder builder; + builder.AddPath(skia_conversions::ToPath(outer)); + builder.AddPath(skia_conversions::ToPath(inner)); + canvas_.DrawPath(builder.TakePath(FillType::kOdd), ToPaint(paint)); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawPath(const SkPath& path, const flutter::DlPaint& paint) { + SkRect rect; + SkRRect rrect; + SkRect oval; + if (path.isRect(&rect)) { + canvas_.DrawRect(skia_conversions::ToRect(rect), ToPaint(paint)); + } else if (path.isRRect(&rrect) && rrect.isSimple()) { + canvas_.DrawRRect(skia_conversions::ToRect(rrect.rect()), + rrect.getSimpleRadii().fX, ToPaint(paint)); + } else if (path.isOval(&oval) && oval.width() == oval.height()) { + canvas_.DrawCircle(skia_conversions::ToPoint(oval.center()), + oval.width() * 0.5, ToPaint(paint)); + } else { + canvas_.DrawPath(skia_conversions::ToPath(path), ToPaint(paint)); + } +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawArc(const SkRect& oval_bounds, + SkScalar start_degrees, + SkScalar sweep_degrees, + bool use_center, + const flutter::DlPaint& paint) { + PathBuilder builder; + builder.AddArc(skia_conversions::ToRect(oval_bounds), Degrees(start_degrees), + Degrees(sweep_degrees), use_center); + canvas_.DrawPath(builder.TakePath(), ToPaint(paint)); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawPoints(PointMode mode, + uint32_t count, + const SkPoint points[], + const flutter::DlPaint& paint) { + auto aiks_paint = ToPaint(paint); + switch (mode) { + case flutter::DlCanvas::PointMode::kPoints: { + // Cap::kButt is also treated as a square. + auto point_style = aiks_paint.stroke_cap == Cap::kRound + ? PointStyle::kRound + : PointStyle::kSquare; + auto radius = aiks_paint.stroke_width; + if (radius > 0) { + radius /= 2.0; + } + canvas_.DrawPoints(skia_conversions::ToPoints(points, count), radius, + aiks_paint, point_style); + } break; + case flutter::DlCanvas::PointMode::kLines: + for (uint32_t i = 1; i < count; i += 2) { + Point p0 = skia_conversions::ToPoint(points[i - 1]); + Point p1 = skia_conversions::ToPoint(points[i]); + auto path = PathBuilder{}.AddLine(p0, p1).TakePath(); + canvas_.DrawPath(path, aiks_paint); + } + break; + case flutter::DlCanvas::PointMode::kPolygon: + if (count > 1) { + Point p0 = skia_conversions::ToPoint(points[0]); + for (uint32_t i = 1; i < count; i++) { + Point p1 = skia_conversions::ToPoint(points[i]); + auto path = PathBuilder{}.AddLine(p0, p1).TakePath(); + canvas_.DrawPath(path, aiks_paint); + p0 = p1; + } + } + break; + } +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawVertices(const flutter::DlVertices* vertices, + flutter::DlBlendMode dl_mode, + const flutter::DlPaint& paint) { + canvas_.DrawVertices(DlVerticesGeometry::MakeVertices(vertices), + ToBlendMode(dl_mode), ToPaint(paint)); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawImage(const sk_sp& image, + const SkPoint point, + flutter::DlImageSampling sampling, + const flutter::DlPaint* paint) { + if (!image) { + return; + } + + auto texture = image->impeller_texture(); + if (!texture) { + return; + } + + const auto size = texture->GetSize(); + const auto src = SkRect::MakeWH(size.width, size.height); + const auto dest = + SkRect::MakeXYWH(point.fX, point.fY, size.width, size.height); + + DrawImageRect(image, // image + src, // source rect + dest, // destination rect + sampling, // sampling options + paint, // paint + SrcRectConstraint::kStrict // constraint + ); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawImageRect(const sk_sp& image, + const SkRect& src, + const SkRect& dst, + flutter::DlImageSampling sampling, + const flutter::DlPaint* paint, + SrcRectConstraint constraint) { + canvas_.DrawImageRect( + std::make_shared(image->impeller_texture()), // image + skia_conversions::ToRect(src), // source rect + skia_conversions::ToRect(dst), // destination rect + ToPaint(paint), // paint + ToSamplerDescriptor(sampling) // sampling + ); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawImageNine(const sk_sp& image, + const SkIRect& center, + const SkRect& dst, + flutter::DlFilterMode filter, + const flutter::DlPaint* paint) { + NinePatchConverter converter = {}; + auto aiks_paint = ToPaint(paint); + converter.DrawNinePatch( + std::make_shared(image->impeller_texture()), + Rect::MakeLTRB(center.fLeft, center.fTop, center.fRight, center.fBottom), + skia_conversions::ToRect(dst), ToSamplerDescriptor(filter), &canvas_, + &aiks_paint); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawAtlas(const sk_sp& atlas, + const SkRSXform xform[], + const SkRect tex[], + const flutter::DlColor colors[], + int count, + flutter::DlBlendMode mode, + flutter::DlImageSampling sampling, + const SkRect* cull_rect, + const flutter::DlPaint* paint) { + canvas_.DrawAtlas(std::make_shared(atlas->impeller_texture()), + skia_conversions::ToRSXForms(xform, count), + skia_conversions::ToRects(tex, count), + ToColors(colors, count), ToBlendMode(mode), + ToSamplerDescriptor(sampling), + skia_conversions::ToRect(cull_rect), ToPaint(paint)); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawDisplayList( + const sk_sp display_list, + SkScalar opacity) { + FML_DCHECK(false); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawImpellerPicture( + const std::shared_ptr& picture, + SkScalar opacity) { + if (!picture) { + return; + } + FML_DCHECK(opacity == 1); + canvas_.DrawPicture(*picture); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawTextBlob(const sk_sp& blob, + SkScalar x, + SkScalar y, + const flutter::DlPaint& paint) { + canvas_.DrawTextFrame(TextFrameFromTextBlob(blob), // + impeller::Point{x, y}, // + ToPaint(paint) // + ); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::DrawShadow(const SkPath& path, + const flutter::DlColor color, + const SkScalar elevation, + bool transparent_occluder, + SkScalar dpr) { + Color spot_color = skia_conversions::ToColor(color); + spot_color.alpha *= 0.25; + + // Compute the spot color -- ported from SkShadowUtils::ComputeTonalColors. + { + Scalar max = + std::max(std::max(spot_color.red, spot_color.green), spot_color.blue); + Scalar min = + std::min(std::min(spot_color.red, spot_color.green), spot_color.blue); + Scalar luminance = (min + max) * 0.5; + + Scalar alpha_adjust = + (2.6f + (-2.66667f + 1.06667f * spot_color.alpha) * spot_color.alpha) * + spot_color.alpha; + Scalar color_alpha = + (3.544762f + (-4.891428f + 2.3466f * luminance) * luminance) * + luminance; + color_alpha = std::clamp(alpha_adjust * color_alpha, 0.0f, 1.0f); + + Scalar greyscale_alpha = + std::clamp(spot_color.alpha * (1 - 0.4f * luminance), 0.0f, 1.0f); + + Scalar color_scale = color_alpha * (1 - greyscale_alpha); + Scalar tonal_alpha = color_scale + greyscale_alpha; + Scalar unpremul_scale = tonal_alpha != 0 ? color_scale / tonal_alpha : 0; + spot_color = Color(unpremul_scale * spot_color.red, + unpremul_scale * spot_color.green, + unpremul_scale * spot_color.blue, tonal_alpha); + } + + Vector3 light_position(0, -1, 1); + Scalar occluder_z = dpr * elevation; + + constexpr Scalar kLightRadius = 800 / 600; // Light radius / light height + + Paint paint; + paint.style = Paint::Style::kFill; + paint.color = spot_color; + paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{ + .style = FilterContents::BlurStyle::kNormal, + .sigma = Radius{kLightRadius * occluder_z / + canvas_.GetCurrentTransformation().GetScale().y}, + }; + + canvas_.Save(); + canvas_.PreConcat( + Matrix::MakeTranslation(Vector2(0, -occluder_z * light_position.y))); + + SkRect rect; + SkRRect rrect; + SkRect oval; + if (path.isRect(&rect)) { + canvas_.DrawRect(skia_conversions::ToRect(rect), paint); + } else if (path.isRRect(&rrect) && rrect.isSimple()) { + canvas_.DrawRRect(skia_conversions::ToRect(rrect.rect()), + rrect.getSimpleRadii().fX, paint); + } else if (path.isOval(&oval) && oval.width() == oval.height()) { + canvas_.DrawCircle(skia_conversions::ToPoint(oval.center()), + oval.width() * 0.5, paint); + } else { + canvas_.DrawPath(skia_conversions::ToPath(path), paint); + } + + canvas_.Restore(); +} + +// |flutter::DlCanvas| +bool DlAiksCanvas::QuickReject(const SkRect& bounds) const { + auto maybe_cull_rect = canvas_.GetCurrentLocalCullingBounds(); + if (!maybe_cull_rect.has_value()) { + return false; + } + auto cull_rect = maybe_cull_rect.value(); + if (cull_rect.IsEmpty() || bounds.isEmpty()) { + return true; + } + auto transform = canvas_.GetCurrentTransformation(); + // There are no fast paths right now to checking whther impeller::Matrix can + // be inverted. Skip that check. + if (transform.HasPerspective()) { + return false; + } + + return !skia_conversions::ToRect(bounds).IntersectsWithRect(cull_rect); +} + +// |flutter::DlCanvas| +void DlAiksCanvas::RestoreToCount(int restore_count) { + canvas_.RestoreToCount(restore_count); +} + +// |flutter::DlCanvas| +SkISize DlAiksCanvas::GetBaseLayerSize() const { + auto size = canvas_.BaseCullRect().value_or(Rect::Giant()).size.Round(); + return SkISize::Make(size.width, size.height); +} + +// |flutter::DlCanvas| +SkImageInfo DlAiksCanvas::GetImageInfo() const { + SkISize size = GetBaseLayerSize(); + return SkImageInfo::MakeUnknown(size.width(), size.height()); +} + +Picture DlAiksCanvas::EndRecordingAsPicture() { + return canvas_.EndRecordingAsPicture(); +} + +} // namespace impeller diff --git a/impeller/display_list/dl_aiks_canvas.h b/impeller/display_list/dl_aiks_canvas.h new file mode 100644 index 0000000000000..e4878c521fa0c --- /dev/null +++ b/impeller/display_list/dl_aiks_canvas.h @@ -0,0 +1,242 @@ +// 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 + +#include "flutter/display_list/dl_canvas.h" +#include "flutter/display_list/geometry/dl_rtree.h" +#include "flutter/display_list/utils/dl_bounds_accumulator.h" +#include "flutter/fml/macros.h" +#include "impeller/aiks/canvas.h" +#include "impeller/aiks/paint.h" +#include "impeller/display_list/skia_conversions.h" + +namespace impeller { + +class DlAiksCanvas final : public flutter::DlCanvas { + public: + DlAiksCanvas(); + + explicit DlAiksCanvas(const SkRect& cull_rect, bool prepare_tree = false); + + explicit DlAiksCanvas(const SkIRect& cull_rect, bool prepare_rtree = false); + + ~DlAiksCanvas(); + + Picture EndRecordingAsPicture(); + + // |DlCanvas| + SkISize GetBaseLayerSize() const override; + // |DlCanvas| + SkImageInfo GetImageInfo() const override; + + // |DlCanvas| + void Save() override; + + // |DlCanvas| + void SaveLayer(const SkRect* bounds, + const flutter::DlPaint* paint = nullptr, + const flutter::DlImageFilter* backdrop = nullptr) override; + // |DlCanvas| + void Restore() override; + // |DlCanvas| + int GetSaveCount() const override { return canvas_.GetSaveCount(); } + // |DlCanvas| + void RestoreToCount(int restore_count) override; + + // |DlCanvas| + void Translate(SkScalar tx, SkScalar ty) override; + // |DlCanvas| + void Scale(SkScalar sx, SkScalar sy) override; + // |DlCanvas| + void Rotate(SkScalar degrees) override; + // |DlCanvas| + void Skew(SkScalar sx, SkScalar sy) override; + + // clang-format off + // 2x3 2D affine subset of a 4x4 transform in row major order + // |DlCanvas| + void Transform2DAffine(SkScalar mxx, SkScalar mxy, SkScalar mxt, + SkScalar myx, SkScalar myy, SkScalar myt) override; + // full 4x4 transform in row major order + // |DlCanvas| + void TransformFullPerspective( + SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt, + SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt, + SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt, + SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) override; + // clang-format on + // |DlCanvas| + void TransformReset() override; + // |DlCanvas| + void Transform(const SkMatrix* matrix) override; + // |DlCanvas| + void Transform(const SkM44* matrix44) override; + // |DlCanvas| + void SetTransform(const SkMatrix* matrix) override { + TransformReset(); + Transform(matrix); + } + // |DlCanvas| + void SetTransform(const SkM44* matrix44) override { + TransformReset(); + Transform(matrix44); + } + using flutter::DlCanvas::Transform; + + /// Returns the 4x4 full perspective transform representing all transform + /// operations executed so far in this DisplayList within the enclosing + /// save stack. + // |DlCanvas| + SkM44 GetTransformFullPerspective() const override { + return skia_conversions::ToSkM44(canvas_.GetCurrentTransformation()); + } + /// Returns the 3x3 partial perspective transform representing all transform + /// operations executed so far in this DisplayList within the enclosing + /// save stack. + // |DlCanvas| + SkMatrix GetTransform() const override { + return skia_conversions::ToSkMatrix(canvas_.GetCurrentTransformation()); + } + + // |DlCanvas| + void ClipRect(const SkRect& rect, + ClipOp clip_op = ClipOp::kIntersect, + bool is_aa = false) override; + // |DlCanvas| + void ClipRRect(const SkRRect& rrect, + ClipOp clip_op = ClipOp::kIntersect, + bool is_aa = false) override; + // |DlCanvas| + void ClipPath(const SkPath& path, + ClipOp clip_op = ClipOp::kIntersect, + bool is_aa = false) override; + + /// Conservative estimate of the bounds of all outstanding clip operations + /// measured in the coordinate space within which this DisplayList will + /// be rendered. + // |DlCanvas| + SkRect GetDestinationClipBounds() const override { + auto rect = canvas_.GetCurrentLocalCullingBounds().value_or(Rect::Giant()); + return SkRect::MakeLTRB(rect.GetLeft(), rect.GetTop(), rect.GetRight(), + rect.GetBottom()); + } + /// Conservative estimate of the bounds of all outstanding clip operations + /// transformed into the local coordinate space in which currently + /// recorded rendering operations are interpreted. + // |DlCanvas| + SkRect GetLocalClipBounds() const override { + auto rect = canvas_.GetCurrentLocalCullingBounds().value_or(Rect::Giant()); + return SkRect::MakeLTRB(rect.GetLeft(), rect.GetTop(), rect.GetRight(), + rect.GetBottom()); + } + + /// Return true iff the supplied bounds are easily shown to be outside + /// of the current clip bounds. This method may conservatively return + /// false if it cannot make the determination. + // |DlCanvas| + bool QuickReject(const SkRect& bounds) const override; + + // |DlCanvas| + void DrawPaint(const flutter::DlPaint& paint) override; + // |DlCanvas| + void DrawColor(flutter::DlColor color, flutter::DlBlendMode mode) override; + // |DlCanvas| + void DrawLine(const SkPoint& p0, + const SkPoint& p1, + const flutter::DlPaint& paint) override; + // |DlCanvas| + void DrawRect(const SkRect& rect, const flutter::DlPaint& paint) override; + // |DlCanvas| + void DrawOval(const SkRect& bounds, const flutter::DlPaint& paint) override; + // |DlCanvas| + void DrawCircle(const SkPoint& center, + SkScalar radius, + const flutter::DlPaint& paint) override; + // |DlCanvas| + void DrawRRect(const SkRRect& rrect, const flutter::DlPaint& paint) override; + // |DlCanvas| + void DrawDRRect(const SkRRect& outer, + const SkRRect& inner, + const flutter::DlPaint& paint) override; + // |DlCanvas| + void DrawPath(const SkPath& path, const flutter::DlPaint& paint) override; + // |DlCanvas| + void DrawArc(const SkRect& bounds, + SkScalar start, + SkScalar sweep, + bool useCenter, + const flutter::DlPaint& paint) override; + // |DlCanvas| + void DrawPoints(PointMode mode, + uint32_t count, + const SkPoint pts[], + const flutter::DlPaint& paint) override; + // |DlCanvas| + void DrawVertices(const flutter::DlVertices* vertices, + flutter::DlBlendMode mode, + const flutter::DlPaint& paint) override; + using flutter::DlCanvas::DrawVertices; + // |DlCanvas| + void DrawImage(const sk_sp& image, + const SkPoint point, + flutter::DlImageSampling sampling, + const flutter::DlPaint* paint = nullptr) override; + // |DlCanvas| + void DrawImageRect( + const sk_sp& image, + const SkRect& src, + const SkRect& dst, + flutter::DlImageSampling sampling, + const flutter::DlPaint* paint = nullptr, + SrcRectConstraint constraint = SrcRectConstraint::kFast) override; + using flutter::DlCanvas::DrawImageRect; + // |DlCanvas| + void DrawImageNine(const sk_sp& image, + const SkIRect& center, + const SkRect& dst, + flutter::DlFilterMode filter, + const flutter::DlPaint* paint = nullptr) override; + // |DlCanvas| + void DrawAtlas(const sk_sp& atlas, + const SkRSXform xform[], + const SkRect tex[], + const flutter::DlColor colors[], + int count, + flutter::DlBlendMode mode, + flutter::DlImageSampling sampling, + const SkRect* cullRect, + const flutter::DlPaint* paint = nullptr) override; + // |DlCanvas| + void DrawDisplayList(const sk_sp display_list, + SkScalar opacity = SK_Scalar1) override; + + // |DlCanvas| + void DrawImpellerPicture( + const std::shared_ptr& picture, + SkScalar opacity = SK_Scalar1) override; + + // |DlCanvas| + void DrawTextBlob(const sk_sp& blob, + SkScalar x, + SkScalar y, + const flutter::DlPaint& paint) override; + // |DlCanvas| + void DrawShadow(const SkPath& path, + const flutter::DlColor color, + const SkScalar elevation, + bool transparent_occluder, + SkScalar dpr) override; + + // |DlCanvas| + void Flush() override {} + + private: + Canvas canvas_; + std::unique_ptr accumulator_; + + FML_DISALLOW_COPY_AND_ASSIGN(DlAiksCanvas); +}; + +} // namespace impeller diff --git a/impeller/display_list/skia_conversions.h b/impeller/display_list/skia_conversions.h index c56cf298a932f..286edaa569fb8 100644 --- a/impeller/display_list/skia_conversions.h +++ b/impeller/display_list/skia_conversions.h @@ -7,12 +7,15 @@ #include "display_list/dl_color.h" #include "impeller/core/formats.h" #include "impeller/geometry/color.h" +#include "impeller/geometry/matrix.h" #include "impeller/geometry/path.h" #include "impeller/geometry/path_builder.h" #include "impeller/geometry/point.h" #include "impeller/geometry/rect.h" #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColorType.h" +#include "third_party/skia/include/core/SkM44.h" +#include "third_party/skia/include/core/SkMatrix.h" #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkPoint.h" #include "third_party/skia/include/core/SkRRect.h" @@ -46,5 +49,29 @@ Path PathDataFromTextBlob(const sk_sp& blob); std::optional ToPixelFormat(SkColorType type); +constexpr SkM44 ToSkM44(const Matrix& matrix) { + // SkM44 construction is in row major order (even though it stores the data in + // column major). + // clang-format off + return SkM44( + matrix.vec[0].x, matrix.vec[1].x, matrix.vec[2].x, matrix.vec[3].x, + matrix.vec[0].y, matrix.vec[1].y, matrix.vec[2].y, matrix.vec[3].y, + matrix.vec[0].z, matrix.vec[1].z, matrix.vec[2].z, matrix.vec[3].z, + matrix.vec[0].w, matrix.vec[1].w, matrix.vec[2].w, matrix.vec[3].w + ); + // clang-format on +} + +constexpr SkMatrix ToSkMatrix(const Matrix& matrix) { + // SkMatrix is in row major order. + // clang-format off + return SkMatrix::MakeAll( + matrix.vec[0].x, matrix.vec[1].x, matrix.vec[3].x, + matrix.vec[0].y, matrix.vec[1].y, matrix.vec[3].y, + matrix.vec[0].w, matrix.vec[1].w, matrix.vec[3].w + ); + /// clang-format on +} + } // namespace skia_conversions } // namespace impeller diff --git a/impeller/entity/entity_pass.h b/impeller/entity/entity_pass.h index 54eb84de7ab7c..6afcaaf52309c 100644 --- a/impeller/entity/entity_pass.h +++ b/impeller/entity/entity_pass.h @@ -31,7 +31,6 @@ class EntityPass { /// When the element is a child `EntityPass`, it may be rendered to an /// offscreen texture and converted into an `Entity` that draws the texture /// into the current pass, or its children may be collapsed into the current - /// /// `EntityPass`. Elements are converted to Entities in /// `GetEntityForElement()`. using Element = std::variant>; diff --git a/impeller/geometry/rect.h b/impeller/geometry/rect.h index 0bda6140d95b9..03c7874774b3c 100644 --- a/impeller/geometry/rect.h +++ b/impeller/geometry/rect.h @@ -72,6 +72,11 @@ struct TRect { return TRect::MakeLTRB(left, top, right, bottom); } + constexpr static TRect Giant() { + // See flutter::kGiantRect. + return TRect::MakeLTRB(-1E9, -1E9, 1E9, 1E9); + } + constexpr static TRect MakeMaximum() { return TRect::MakeLTRB(-std::numeric_limits::infinity(), -std::numeric_limits::infinity(), diff --git a/impeller/geometry/sigma.h b/impeller/geometry/sigma.h index c909128be4baa..c66b570e77eb9 100644 --- a/impeller/geometry/sigma.h +++ b/impeller/geometry/sigma.h @@ -20,7 +20,7 @@ namespace impeller { /// quality blurs (with exponentially diminishing returns for the same sigma /// input). Making this value any lower results in a noticable loss of /// quality in the blur. -constexpr static float kKernelRadiusPerSigma = 1.73205080757; +constexpr static float kKernelRadiusPerSigma = 1.73205080757f; struct Radius; @@ -29,7 +29,7 @@ struct Radius; /// the filter input. In other words, this determines how wide the /// distribution stretches. struct Sigma { - Scalar sigma = 0.0; + Scalar sigma = 0.0f; constexpr Sigma() = default; @@ -45,7 +45,7 @@ struct Sigma { /// relationship with `Sigma`. See `kKernelRadiusPerSigma` for /// details on how this relationship works. struct Radius { - Scalar radius = 0.0; + Scalar radius = 0.0f; constexpr Radius() = default; diff --git a/impeller/tools/impeller.gni b/impeller/tools/impeller.gni index 2c20acf26d590..04cc3249a7fd3 100644 --- a/impeller/tools/impeller.gni +++ b/impeller/tools/impeller.gni @@ -12,13 +12,15 @@ declare_args() { flutter_runtime_mode == "debug" || flutter_runtime_mode == "profile" # Whether the Metal backend is enabled. - impeller_enable_metal = is_mac || is_ios + impeller_enable_metal = (is_mac || is_ios) && target_os != "fuchsia" # Whether the OpenGLES backend is enabled. - impeller_enable_opengles = is_linux || is_win || is_android + impeller_enable_opengles = + (is_linux || is_win || is_android) && target_os != "fuchsia" # Whether the Vulkan backend is enabled. - impeller_enable_vulkan = is_linux || is_win || is_android + impeller_enable_vulkan = + (is_linux || is_win || is_android) && target_os != "fuchsia" # Whether to use a prebuilt impellerc. # If this is the empty string, impellerc will be built. diff --git a/lib/ui/compositing/scene.cc b/lib/ui/compositing/scene.cc index 17d00ea794c2a..fd76614f01764 100644 --- a/lib/ui/compositing/scene.cc +++ b/lib/ui/compositing/scene.cc @@ -89,13 +89,13 @@ static sk_sp CreateDeferredImage( bool impeller, std::unique_ptr layer_tree, fml::TaskRunnerAffineWeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner, + const fml::RefPtr& raster_task_runner, fml::RefPtr unref_queue) { #if IMPELLER_SUPPORTS_RENDERING if (impeller) { return DlDeferredImageGPUImpeller::Make(std::move(layer_tree), std::move(snapshot_delegate), - std::move(raster_task_runner)); + raster_task_runner); } #endif // IMPELLER_SUPPORTS_RENDERING @@ -122,8 +122,7 @@ void Scene::RasterizeToImage(uint32_t width, auto image = CanvasImage::Create(); auto dl_image = CreateDeferredImage( dart_state->IsImpellerEnabled(), BuildLayerTree(width, height), - std::move(snapshot_delegate), std::move(raster_task_runner), - std::move(unref_queue)); + std::move(snapshot_delegate), raster_task_runner, std::move(unref_queue)); image->set_image(dl_image); image->AssociateWithDartWrapper(raw_image_handle); } diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc index ec0d59cb0d4e0..e47a42944c73d 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -4,6 +4,7 @@ #include "flutter/lib/ui/compositing/scene_builder.h" +#include "flutter/flow/layers/aiks_layer.h" #include "flutter/flow/layers/backdrop_filter_layer.h" #include "flutter/flow/layers/clip_path_layer.h" #include "flutter/flow/layers/clip_rect_layer.h" @@ -226,6 +227,15 @@ void SceneBuilder::addPicture(double dx, SkPoint::Make(SafeNarrow(dx), SafeNarrow(dy)), picture->display_list(), !!(hints & 1), !!(hints & 2)); AddLayer(std::move(layer)); + return; + } + + auto impeller_picture = picture->impeller_picture(); + if (impeller_picture) { + auto layer = std::make_unique( + SkPoint::Make(SafeNarrow(dx), SafeNarrow(dy)), + std::move(impeller_picture)); + AddLayer(std::move(layer)); } } diff --git a/lib/ui/painting/canvas.cc b/lib/ui/painting/canvas.cc index 403a4c3f440a1..7a8c9b612fd78 100644 --- a/lib/ui/painting/canvas.cc +++ b/lib/ui/painting/canvas.cc @@ -6,7 +6,7 @@ #include -#include "flutter/display_list/dl_builder.h" +#include "flutter/display_list/dl_canvas.h" #include "flutter/lib/ui/floating_point.h" #include "flutter/lib/ui/painting/image.h" #include "flutter/lib/ui/painting/image_filter.h" @@ -39,18 +39,18 @@ void Canvas::Create(Dart_Handle wrapper, fml::MakeRefCounted(recorder->BeginRecording( SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), SafeNarrow(right), SafeNarrow(bottom)))); + FML_DCHECK(canvas->dl_canvas_); recorder->set_canvas(canvas); canvas->AssociateWithDartWrapper(wrapper); } -Canvas::Canvas(sk_sp builder) - : display_list_builder_(std::move(builder)) {} +Canvas::Canvas(DlCanvas* canvas) : dl_canvas_(canvas) {} Canvas::~Canvas() {} void Canvas::save() { - if (display_list_builder_) { - builder()->Save(); + if (dl_canvas_) { + dl_canvas_->Save(); } } @@ -59,12 +59,12 @@ void Canvas::saveLayerWithoutBounds(Dart_Handle paint_objects, Paint paint(paint_objects, paint_data); FML_DCHECK(paint.isNotNull()); - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; const DlPaint* save_paint = paint.paint(dl_paint, kSaveLayerWithPaintFlags); FML_DCHECK(save_paint); TRACE_EVENT0("flutter", "ui.Canvas::saveLayer (Recorded)"); - builder()->SaveLayer(nullptr, save_paint); + dl_canvas_->SaveLayer(nullptr, save_paint); } } @@ -79,65 +79,65 @@ void Canvas::saveLayer(double left, FML_DCHECK(paint.isNotNull()); SkRect bounds = SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), SafeNarrow(right), SafeNarrow(bottom)); - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; const DlPaint* save_paint = paint.paint(dl_paint, kSaveLayerWithPaintFlags); FML_DCHECK(save_paint); TRACE_EVENT0("flutter", "ui.Canvas::saveLayer (Recorded)"); - builder()->SaveLayer(&bounds, save_paint); + dl_canvas_->SaveLayer(&bounds, save_paint); } } void Canvas::restore() { - if (display_list_builder_) { - builder()->Restore(); + if (dl_canvas_) { + dl_canvas_->Restore(); } } int Canvas::getSaveCount() { - if (display_list_builder_) { - return builder()->GetSaveCount(); + if (dl_canvas_) { + return dl_canvas_->GetSaveCount(); } else { return 0; } } void Canvas::restoreToCount(int count) { - if (display_list_builder_ && count < getSaveCount()) { - builder()->RestoreToCount(count); + if (dl_canvas_ && count < getSaveCount()) { + dl_canvas_->RestoreToCount(count); } } void Canvas::translate(double dx, double dy) { - if (display_list_builder_) { - builder()->Translate(SafeNarrow(dx), SafeNarrow(dy)); + if (dl_canvas_) { + dl_canvas_->Translate(SafeNarrow(dx), SafeNarrow(dy)); } } void Canvas::scale(double sx, double sy) { - if (display_list_builder_) { - builder()->Scale(SafeNarrow(sx), SafeNarrow(sy)); + if (dl_canvas_) { + dl_canvas_->Scale(SafeNarrow(sx), SafeNarrow(sy)); } } void Canvas::rotate(double radians) { - if (display_list_builder_) { - builder()->Rotate(SafeNarrow(radians) * 180.0f / static_cast(M_PI)); + if (dl_canvas_) { + dl_canvas_->Rotate(SafeNarrow(radians) * 180.0f / static_cast(M_PI)); } } void Canvas::skew(double sx, double sy) { - if (display_list_builder_) { - builder()->Skew(SafeNarrow(sx), SafeNarrow(sy)); + if (dl_canvas_) { + dl_canvas_->Skew(SafeNarrow(sx), SafeNarrow(sy)); } } void Canvas::transform(const tonic::Float64List& matrix4) { // The Float array stored by Dart Matrix4 is in column-major order // Both DisplayList and SkM44 constructor take row-major matrix order - if (display_list_builder_) { + if (dl_canvas_) { // clang-format off - builder()->TransformFullPerspective( + dl_canvas_->TransformFullPerspective( SafeNarrow(matrix4[ 0]), SafeNarrow(matrix4[ 4]), SafeNarrow(matrix4[ 8]), SafeNarrow(matrix4[12]), SafeNarrow(matrix4[ 1]), SafeNarrow(matrix4[ 5]), SafeNarrow(matrix4[ 9]), SafeNarrow(matrix4[13]), SafeNarrow(matrix4[ 2]), SafeNarrow(matrix4[ 6]), SafeNarrow(matrix4[10]), SafeNarrow(matrix4[14]), @@ -147,8 +147,8 @@ void Canvas::transform(const tonic::Float64List& matrix4) { } void Canvas::getTransform(Dart_Handle matrix4_handle) { - if (display_list_builder_) { - SkM44 sk_m44 = builder()->GetTransformFullPerspective(); + if (dl_canvas_) { + SkM44 sk_m44 = dl_canvas_->GetTransformFullPerspective(); SkScalar m44_values[16]; // The Float array stored by Dart Matrix4 is in column-major order sk_m44.getColMajor(m44_values); @@ -165,17 +165,18 @@ void Canvas::clipRect(double left, double bottom, DlCanvas::ClipOp clipOp, bool doAntiAlias) { - if (display_list_builder_) { - builder()->ClipRect(SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), - SafeNarrow(right), SafeNarrow(bottom)), - clipOp, doAntiAlias); + if (dl_canvas_) { + dl_canvas_->ClipRect( + SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), SafeNarrow(right), + SafeNarrow(bottom)), + clipOp, doAntiAlias); } } void Canvas::clipRRect(const RRect& rrect, bool doAntiAlias) { - if (display_list_builder_) { - builder()->ClipRRect(rrect.sk_rrect, DlCanvas::ClipOp::kIntersect, - doAntiAlias); + if (dl_canvas_) { + dl_canvas_->ClipRRect(rrect.sk_rrect, DlCanvas::ClipOp::kIntersect, + doAntiAlias); } } @@ -185,16 +186,16 @@ void Canvas::clipPath(const CanvasPath* path, bool doAntiAlias) { ToDart("Canvas.clipPath called with non-genuine Path.")); return; } - if (display_list_builder_) { - builder()->ClipPath(path->path(), DlCanvas::ClipOp::kIntersect, - doAntiAlias); + if (dl_canvas_) { + dl_canvas_->ClipPath(path->path(), DlCanvas::ClipOp::kIntersect, + doAntiAlias); } } void Canvas::getDestinationClipBounds(Dart_Handle rect_handle) { - if (display_list_builder_) { + if (dl_canvas_) { auto rect = tonic::Float64List(rect_handle); - SkRect bounds = builder()->GetDestinationClipBounds(); + SkRect bounds = dl_canvas_->GetDestinationClipBounds(); rect[0] = bounds.fLeft; rect[1] = bounds.fTop; rect[2] = bounds.fRight; @@ -203,9 +204,9 @@ void Canvas::getDestinationClipBounds(Dart_Handle rect_handle) { } void Canvas::getLocalClipBounds(Dart_Handle rect_handle) { - if (display_list_builder_) { + if (dl_canvas_) { auto rect = tonic::Float64List(rect_handle); - SkRect bounds = builder()->GetLocalClipBounds(); + SkRect bounds = dl_canvas_->GetLocalClipBounds(); rect[0] = bounds.fLeft; rect[1] = bounds.fTop; rect[2] = bounds.fRight; @@ -214,8 +215,8 @@ void Canvas::getLocalClipBounds(Dart_Handle rect_handle) { } void Canvas::drawColor(SkColor color, DlBlendMode blend_mode) { - if (display_list_builder_) { - builder()->DrawColor(color, blend_mode); + if (dl_canvas_) { + dl_canvas_->DrawColor(color, blend_mode); } } @@ -228,12 +229,12 @@ void Canvas::drawLine(double x1, Paint paint(paint_objects, paint_data); FML_DCHECK(paint.isNotNull()); - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; paint.paint(dl_paint, kDrawLineFlags); - builder()->DrawLine(SkPoint::Make(SafeNarrow(x1), SafeNarrow(y1)), - SkPoint::Make(SafeNarrow(x2), SafeNarrow(y2)), - dl_paint); + dl_canvas_->DrawLine(SkPoint::Make(SafeNarrow(x1), SafeNarrow(y1)), + SkPoint::Make(SafeNarrow(x2), SafeNarrow(y2)), + dl_paint); } } @@ -241,7 +242,7 @@ void Canvas::drawPaint(Dart_Handle paint_objects, Dart_Handle paint_data) { Paint paint(paint_objects, paint_data); FML_DCHECK(paint.isNotNull()); - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; paint.paint(dl_paint, kDrawPaintFlags); std::shared_ptr filter = dl_paint.getImageFilter(); @@ -250,7 +251,7 @@ void Canvas::drawPaint(Dart_Handle paint_objects, Dart_Handle paint_data) { // present that cannot be replaced by an SkColorFilter. TRACE_EVENT0("flutter", "ui.Canvas::saveLayer (Recorded)"); } - builder()->DrawPaint(dl_paint); + dl_canvas_->DrawPaint(dl_paint); } } @@ -263,12 +264,13 @@ void Canvas::drawRect(double left, Paint paint(paint_objects, paint_data); FML_DCHECK(paint.isNotNull()); - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; paint.paint(dl_paint, kDrawRectFlags); - builder()->DrawRect(SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), - SafeNarrow(right), SafeNarrow(bottom)), - dl_paint); + dl_canvas_->DrawRect( + SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), SafeNarrow(right), + SafeNarrow(bottom)), + dl_paint); } } @@ -278,10 +280,10 @@ void Canvas::drawRRect(const RRect& rrect, Paint paint(paint_objects, paint_data); FML_DCHECK(paint.isNotNull()); - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; paint.paint(dl_paint, kDrawRRectFlags); - builder()->DrawRRect(rrect.sk_rrect, dl_paint); + dl_canvas_->DrawRRect(rrect.sk_rrect, dl_paint); } } @@ -292,10 +294,10 @@ void Canvas::drawDRRect(const RRect& outer, Paint paint(paint_objects, paint_data); FML_DCHECK(paint.isNotNull()); - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; paint.paint(dl_paint, kDrawDRRectFlags); - builder()->DrawDRRect(outer.sk_rrect, inner.sk_rrect, dl_paint); + dl_canvas_->DrawDRRect(outer.sk_rrect, inner.sk_rrect, dl_paint); } } @@ -308,12 +310,13 @@ void Canvas::drawOval(double left, Paint paint(paint_objects, paint_data); FML_DCHECK(paint.isNotNull()); - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; paint.paint(dl_paint, kDrawOvalFlags); - builder()->DrawOval(SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), - SafeNarrow(right), SafeNarrow(bottom)), - dl_paint); + dl_canvas_->DrawOval( + SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), SafeNarrow(right), + SafeNarrow(bottom)), + dl_paint); } } @@ -325,11 +328,11 @@ void Canvas::drawCircle(double x, Paint paint(paint_objects, paint_data); FML_DCHECK(paint.isNotNull()); - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; paint.paint(dl_paint, kDrawCircleFlags); - builder()->DrawCircle(SkPoint::Make(SafeNarrow(x), SafeNarrow(y)), - SafeNarrow(radius), dl_paint); + dl_canvas_->DrawCircle(SkPoint::Make(SafeNarrow(x), SafeNarrow(y)), + SafeNarrow(radius), dl_paint); } } @@ -345,12 +348,12 @@ void Canvas::drawArc(double left, Paint paint(paint_objects, paint_data); FML_DCHECK(paint.isNotNull()); - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; paint.paint(dl_paint, useCenter // ? kDrawArcWithCenterFlags : kDrawArcNoCenterFlags); - builder()->DrawArc( + dl_canvas_->DrawArc( SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), SafeNarrow(right), SafeNarrow(bottom)), SafeNarrow(startAngle) * 180.0f / static_cast(M_PI), @@ -370,10 +373,10 @@ void Canvas::drawPath(const CanvasPath* path, ToDart("Canvas.drawPath called with non-genuine Path.")); return; } - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; paint.paint(dl_paint, kDrawPathFlags); - builder()->DrawPath(path->path(), dl_paint); + dl_canvas_->DrawPath(path->path(), dl_paint); } } @@ -400,11 +403,11 @@ Dart_Handle Canvas::drawImage(const CanvasImage* image, } auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex); - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; const DlPaint* opt_paint = paint.paint(dl_paint, kDrawImageWithPaintFlags); - builder()->DrawImage(dl_image, SkPoint::Make(SafeNarrow(x), SafeNarrow(y)), - sampling, opt_paint); + dl_canvas_->DrawImage(dl_image, SkPoint::Make(SafeNarrow(x), SafeNarrow(y)), + sampling, opt_paint); } return Dart_Null(); } @@ -442,12 +445,12 @@ Dart_Handle Canvas::drawImageRect(const CanvasImage* image, SkRect dst = SkRect::MakeLTRB(SafeNarrow(dst_left), SafeNarrow(dst_top), SafeNarrow(dst_right), SafeNarrow(dst_bottom)); auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex); - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; const DlPaint* opt_paint = paint.paint(dl_paint, kDrawImageRectWithPaintFlags); - builder()->DrawImageRect(dl_image, src, dst, sampling, opt_paint, - DlCanvas::SrcRectConstraint::kFast); + dl_canvas_->DrawImageRect(dl_image, src, dst, sampling, opt_paint, + DlCanvas::SrcRectConstraint::kFast); } return Dart_Null(); } @@ -487,11 +490,11 @@ Dart_Handle Canvas::drawImageNine(const CanvasImage* image, SkRect dst = SkRect::MakeLTRB(SafeNarrow(dst_left), SafeNarrow(dst_top), SafeNarrow(dst_right), SafeNarrow(dst_bottom)); auto filter = ImageFilter::FilterModeFromIndex(bitmapSamplingIndex); - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; const DlPaint* opt_paint = paint.paint(dl_paint, kDrawImageNineWithPaintFlags); - builder()->DrawImageNine(dl_image, icenter, dst, filter, opt_paint); + dl_canvas_->DrawImageNine(dl_image, icenter, dst, filter, opt_paint); } return Dart_Null(); } @@ -502,12 +505,20 @@ void Canvas::drawPicture(Picture* picture) { ToDart("Canvas.drawPicture called with non-genuine Picture.")); return; } + + if (!dl_canvas_) { + return; + } + if (picture->display_list()) { - if (display_list_builder_) { - builder()->DrawDisplayList(picture->display_list()); - } + dl_canvas_->DrawDisplayList(picture->display_list()); } else { - FML_DCHECK(false); + auto impeller_picture = picture->impeller_picture(); + if (impeller_picture) { + dl_canvas_->DrawImpellerPicture(impeller_picture); + } else { + FML_DCHECK(false); + } } } @@ -521,7 +532,7 @@ void Canvas::drawPoints(Dart_Handle paint_objects, "SkPoint doesn't use floats."); FML_DCHECK(paint.isNotNull()); - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; switch (point_mode) { case DlCanvas::PointMode::kPoints: @@ -534,10 +545,10 @@ void Canvas::drawPoints(Dart_Handle paint_objects, paint.paint(dl_paint, kDrawPointsAsPolygonFlags); break; } - builder()->DrawPoints(point_mode, - points.num_elements() / 2, // SkPoints have 2 floats - reinterpret_cast(points.data()), - dl_paint); + dl_canvas_->DrawPoints(point_mode, + points.num_elements() / 2, // SkPoints have 2 floats + reinterpret_cast(points.data()), + dl_paint); } } @@ -553,10 +564,10 @@ void Canvas::drawVertices(const Vertices* vertices, return; } FML_DCHECK(paint.isNotNull()); - if (display_list_builder_) { + if (dl_canvas_) { DlPaint dl_paint; paint.paint(dl_paint, kDrawVerticesFlags); - builder()->DrawVertices(vertices->vertices(), blend_mode, dl_paint); + dl_canvas_->DrawVertices(vertices->vertices(), blend_mode, dl_paint); } } @@ -591,7 +602,7 @@ Dart_Handle Canvas::drawAtlas(Dart_Handle paint_objects, auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex); FML_DCHECK(paint.isNotNull()); - if (display_list_builder_) { + if (dl_canvas_) { tonic::Float32List transforms(transforms_handle); tonic::Float32List rects(rects_handle); tonic::Int32List colors(colors_handle); @@ -599,7 +610,7 @@ Dart_Handle Canvas::drawAtlas(Dart_Handle paint_objects, DlPaint dl_paint; const DlPaint* opt_paint = paint.paint(dl_paint, kDrawAtlasWithPaintFlags); - builder()->DrawAtlas( + dl_canvas_->DrawAtlas( dl_image, reinterpret_cast(transforms.data()), reinterpret_cast(rects.data()), reinterpret_cast(colors.data()), @@ -626,7 +637,7 @@ void Canvas::drawShadow(const CanvasPath* path, ->get_window(0) ->viewport_metrics() .device_pixel_ratio); - if (display_list_builder_) { + if (dl_canvas_) { // The DrawShadow mechanism results in non-public operations to be // performed on the canvas involving an SkDrawShadowRec. Since we // cannot include the header that defines that structure, we cannot @@ -634,13 +645,13 @@ void Canvas::drawShadow(const CanvasPath* path, // that situation we bypass the canvas interface and inject the // shadow parameters directly into the underlying DisplayList. // See: https://bugs.chromium.org/p/skia/issues/detail?id=12125 - builder()->DrawShadow(path->path(), color, SafeNarrow(elevation), - transparentOccluder, dpr); + dl_canvas_->DrawShadow(path->path(), color, SafeNarrow(elevation), + transparentOccluder, dpr); } } void Canvas::Invalidate() { - display_list_builder_ = nullptr; + dl_canvas_ = nullptr; if (dart_wrapper()) { ClearDartWrapper(); } diff --git a/lib/ui/painting/canvas.h b/lib/ui/painting/canvas.h index 20ab1c9eafa9d..d735e875c840f 100644 --- a/lib/ui/painting/canvas.h +++ b/lib/ui/painting/canvas.h @@ -186,12 +186,12 @@ class Canvas : public RefCountedDartWrappable, DisplayListOpFlags { void Invalidate(); - DisplayListBuilder* builder() { return display_list_builder_.get(); } + DlCanvas* dl_canvas() { return dl_canvas_; } private: - explicit Canvas(sk_sp builder); + explicit Canvas(DlCanvas* canvas); - sk_sp display_list_builder_; + DlCanvas* dl_canvas_; }; } // namespace flutter diff --git a/lib/ui/painting/display_list_deferred_image_gpu_impeller.cc b/lib/ui/painting/display_list_deferred_image_gpu_impeller.cc index 0c2a7de57cca4..11692cd711860 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu_impeller.cc +++ b/lib/ui/painting/display_list_deferred_image_gpu_impeller.cc @@ -6,6 +6,7 @@ #include +#include "display_list_deferred_image_gpu_impeller.h" #include "flutter/fml/make_copyable.h" namespace flutter { @@ -13,22 +14,33 @@ namespace flutter { sk_sp DlDeferredImageGPUImpeller::Make( std::unique_ptr layer_tree, fml::TaskRunnerAffineWeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner) { + const fml::RefPtr& raster_task_runner) { return sk_sp(new DlDeferredImageGPUImpeller( DlDeferredImageGPUImpeller::ImageWrapper::Make( std::move(layer_tree), std::move(snapshot_delegate), - std::move(raster_task_runner)))); + raster_task_runner))); } sk_sp DlDeferredImageGPUImpeller::Make( sk_sp display_list, const SkISize& size, fml::TaskRunnerAffineWeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner) { + const fml::RefPtr& raster_task_runner) { return sk_sp(new DlDeferredImageGPUImpeller( DlDeferredImageGPUImpeller::ImageWrapper::Make( std::move(display_list), size, std::move(snapshot_delegate), - std::move(raster_task_runner)))); + raster_task_runner))); +} + +sk_sp DlDeferredImageGPUImpeller::Make( + const std::shared_ptr& impeller_picture, + const SkISize& size, + fml::TaskRunnerAffineWeakPtr snapshot_delegate, + const fml::RefPtr& raster_task_runner) { + return sk_sp(new DlDeferredImageGPUImpeller( + DlDeferredImageGPUImpeller::ImageWrapper::Make( + impeller_picture, size, std::move(snapshot_delegate), + raster_task_runner))); } DlDeferredImageGPUImpeller::DlDeferredImageGPUImpeller( @@ -96,22 +108,41 @@ DlDeferredImageGPUImpeller::ImageWrapper::Make( sk_sp display_list, const SkISize& size, fml::TaskRunnerAffineWeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner) { - auto wrapper = std::shared_ptr(new ImageWrapper( - std::move(display_list), size, std::move(snapshot_delegate), - std::move(raster_task_runner))); + const fml::RefPtr& raster_task_runner) { + auto wrapper = std::shared_ptr( + new ImageWrapper(std::move(display_list), size, + std::move(snapshot_delegate), raster_task_runner)); wrapper->SnapshotDisplayList(); return wrapper; } +std::shared_ptr +DlDeferredImageGPUImpeller::ImageWrapper::Make( + const std::shared_ptr& impeller_picture, + const SkISize& size, + fml::TaskRunnerAffineWeakPtr snapshot_delegate, + const fml::RefPtr& raster_task_runner) { + auto wrapper = std::shared_ptr(new ImageWrapper(size)); + wrapper->SnapshotPicture(impeller_picture, std::move(snapshot_delegate), + raster_task_runner); + return wrapper; +} + std::shared_ptr DlDeferredImageGPUImpeller::ImageWrapper::Make( std::unique_ptr layer_tree, fml::TaskRunnerAffineWeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner) { - auto wrapper = std::shared_ptr(new ImageWrapper( - nullptr, layer_tree->frame_size(), std::move(snapshot_delegate), - std::move(raster_task_runner))); + const fml::RefPtr& raster_task_runner) { + if (layer_tree) { + auto wrapper = std::shared_ptr( + new ImageWrapper(layer_tree->frame_size())); + wrapper->SnapshotLayer(std::move(layer_tree), std::move(snapshot_delegate), + raster_task_runner); + return wrapper; + } + auto wrapper = std::shared_ptr( + new ImageWrapper(sk_sp(), layer_tree->frame_size(), + std::move(snapshot_delegate), raster_task_runner)); wrapper->SnapshotDisplayList(std::move(layer_tree)); return wrapper; } @@ -126,14 +157,84 @@ DlDeferredImageGPUImpeller::ImageWrapper::ImageWrapper( snapshot_delegate_(std::move(snapshot_delegate)), raster_task_runner_(std::move(raster_task_runner)) {} -DlDeferredImageGPUImpeller::ImageWrapper::~ImageWrapper() { +DlDeferredImageGPUImpeller::ImageWrapper::ImageWrapper(const SkISize& size) + : size_(size) {} + +void DlDeferredImageGPUImpeller::ImageWrapper::SnapshotPicture( + const std::shared_ptr& impeller_picture, + fml::TaskRunnerAffineWeakPtr snapshot_delegate, + const fml::RefPtr& raster_task_runner) { + fml::TaskRunner::RunNowOrPostTask( + raster_task_runner, + fml::MakeCopyable([weak_this = weak_from_this(), impeller_picture, + snapshot_delegate = std::move(snapshot_delegate)]() { + TRACE_EVENT0("flutter", "SnapshotPicture (impeller)"); + auto wrapper = weak_this.lock(); + if (!wrapper) { + return; + } + if (!snapshot_delegate) { + return; + } + + wrapper->texture_registry_ = snapshot_delegate->GetTextureRegistry(); + + auto snapshot = snapshot_delegate->MakeRasterSnapshot(impeller_picture, + wrapper->size_); + if (!snapshot) { + std::scoped_lock lock(wrapper->error_mutex_); + wrapper->error_ = "Failed to create snapshot."; + return; + } + wrapper->texture_ = snapshot->impeller_texture(); + })); +} + +void DlDeferredImageGPUImpeller::ImageWrapper::SnapshotLayer( + std::unique_ptr layer_tree, + fml::TaskRunnerAffineWeakPtr snapshot_delegate, + const fml::RefPtr& raster_task_runner) { fml::TaskRunner::RunNowOrPostTask( - raster_task_runner_, [id = reinterpret_cast(this), - texture_registry = std::move(texture_registry_)]() { - if (texture_registry) { - texture_registry->UnregisterContextListener(id); + raster_task_runner, + fml::MakeCopyable([weak_this = weak_from_this(), + layer_tree = std::move(layer_tree), + snapshot_delegate = std::move(snapshot_delegate)]() { + TRACE_EVENT0("flutter", "SnapshotLayer (impeller)"); + auto wrapper = weak_this.lock(); + if (!wrapper) { + return; + } + if (!snapshot_delegate) { + return; } - }); + + wrapper->texture_registry_ = snapshot_delegate->GetTextureRegistry(); + + auto impeller_picture = layer_tree->FlattenToImpellerPicture( + SkRect::MakeWH(wrapper->size_.width(), wrapper->size_.height()), + wrapper->texture_registry_); + auto snapshot = snapshot_delegate->MakeRasterSnapshot(impeller_picture, + wrapper->size_); + if (!snapshot) { + std::scoped_lock lock(wrapper->error_mutex_); + wrapper->error_ = "Failed to create snapshot."; + return; + } + wrapper->texture_ = snapshot->impeller_texture(); + })); +} + +DlDeferredImageGPUImpeller::ImageWrapper::~ImageWrapper() { + if (display_list_) { + fml::TaskRunner::RunNowOrPostTask( + raster_task_runner_, + [id = reinterpret_cast(this), + texture_registry = std::move(texture_registry_)]() { + if (texture_registry) { + texture_registry->UnregisterContextListener(id); + } + }); + } } void DlDeferredImageGPUImpeller::ImageWrapper::OnGrContextCreated() { @@ -142,8 +243,9 @@ void DlDeferredImageGPUImpeller::ImageWrapper::OnGrContextCreated() { } void DlDeferredImageGPUImpeller::ImageWrapper::OnGrContextDestroyed() { - // Impeller textures do not have threading requirements for deletion, and - texture_.reset(); + if (display_list_) { + texture_.reset(); + } } bool DlDeferredImageGPUImpeller::ImageWrapper::isTextureBacked() const { @@ -152,6 +254,7 @@ bool DlDeferredImageGPUImpeller::ImageWrapper::isTextureBacked() const { void DlDeferredImageGPUImpeller::ImageWrapper::SnapshotDisplayList( std::unique_ptr layer_tree) { + FML_DCHECK(display_list_ || layer_tree); fml::TaskRunner::RunNowOrPostTask( raster_task_runner_, fml::MakeCopyable([weak_this = weak_from_this(), diff --git a/lib/ui/painting/display_list_deferred_image_gpu_impeller.h b/lib/ui/painting/display_list_deferred_image_gpu_impeller.h index caed73a7c86f8..2e57f1ba7ce12 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu_impeller.h +++ b/lib/ui/painting/display_list_deferred_image_gpu_impeller.h @@ -20,13 +20,19 @@ class DlDeferredImageGPUImpeller final : public DlImage { static sk_sp Make( std::unique_ptr layer_tree, fml::TaskRunnerAffineWeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner); + const fml::RefPtr& raster_task_runner); static sk_sp Make( sk_sp display_list, const SkISize& size, fml::TaskRunnerAffineWeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner); + const fml::RefPtr& raster_task_runner); + + static sk_sp Make( + const std::shared_ptr& impeller_picture, + const SkISize& size, + fml::TaskRunnerAffineWeakPtr snapshot_delegate, + const fml::RefPtr& raster_task_runner); // |DlImage| ~DlDeferredImageGPUImpeller() override; @@ -67,12 +73,18 @@ class DlDeferredImageGPUImpeller final : public DlImage { sk_sp display_list, const SkISize& size, fml::TaskRunnerAffineWeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner); + const fml::RefPtr& raster_task_runner); + + static std::shared_ptr Make( + const std::shared_ptr& impeller_picture, + const SkISize& size, + fml::TaskRunnerAffineWeakPtr snapshot_delegate, + const fml::RefPtr& raster_task_runner); static std::shared_ptr Make( std::unique_ptr layer_tree, fml::TaskRunnerAffineWeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner); + const fml::RefPtr& raster_task_runner); bool isTextureBacked() const; @@ -101,6 +113,18 @@ class DlDeferredImageGPUImpeller final : public DlImage { fml::TaskRunnerAffineWeakPtr snapshot_delegate, fml::RefPtr raster_task_runner); + explicit ImageWrapper(const SkISize& size); + + void SnapshotPicture( + const std::shared_ptr& impeller_picture, + fml::TaskRunnerAffineWeakPtr snapshot_delegate, + const fml::RefPtr& raster_task_runner); + + void SnapshotLayer( + std::unique_ptr layer_tree, + fml::TaskRunnerAffineWeakPtr snapshot_delegate, + const fml::RefPtr& raster_task_runner); + // If a layer tree is provided, it will be flattened during the raster // thread task spawned by this method. After being flattened into a display // list, the image wrapper will be updated to hold this display list and the diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index 74c7b0dc78141..08c1ceb553497 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -16,9 +16,6 @@ #endif // IMPELLER_SUPPORTS_RENDERING #include "flutter/lib/ui/painting/display_list_image_gpu.h" #include "third_party/tonic/converter/dart_converter.h" -#include "third_party/tonic/dart_args.h" -#include "third_party/tonic/dart_binding_macros.h" -#include "third_party/tonic/dart_library_natives.h" #include "third_party/tonic/dart_persistent_value.h" #include "third_party/tonic/logging/dart_invoke.h" @@ -27,48 +24,53 @@ namespace flutter { IMPLEMENT_WRAPPERTYPEINFO(ui, Picture); fml::RefPtr Picture::Create(Dart_Handle dart_handle, - sk_sp display_list) { - FML_DCHECK(display_list->isUIThreadSafe()); - auto canvas_picture = fml::MakeRefCounted(std::move(display_list)); + DisplayListOrPicture picture) { + auto canvas_picture = fml::MakeRefCounted(std::move(picture)); canvas_picture->AssociateWithDartWrapper(dart_handle); return canvas_picture; } -Picture::Picture(sk_sp display_list) - : display_list_(std::move(display_list)) {} +Picture::Picture(DisplayListOrPicture picture) : picture_(std::move(picture)) {} Picture::~Picture() = default; Dart_Handle Picture::toImage(uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { - if (!display_list_) { + if (!impeller_picture() && !display_list()) { return tonic::ToDart("Picture is null"); } - return RasterizeToImage(display_list_, width, height, raw_image_callback); + return RasterizeToImage(width, height, raw_image_callback); } void Picture::toImageSync(uint32_t width, uint32_t height, Dart_Handle raw_image_handle) { - FML_DCHECK(display_list_); - RasterizeToImageSync(display_list_, width, height, raw_image_handle); + FML_DCHECK(impeller_picture() || display_list()); + RasterizeToImageSync(width, height, raw_image_handle); } static sk_sp CreateDeferredImage( bool impeller, sk_sp display_list, + const std::shared_ptr& impeller_picture, uint32_t width, uint32_t height, fml::TaskRunnerAffineWeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner, + const fml::RefPtr& raster_task_runner, fml::RefPtr unref_queue) { #if IMPELLER_SUPPORTS_RENDERING if (impeller) { + if (display_list) { + return DlDeferredImageGPUImpeller::Make( + std::move(display_list), SkISize::Make(width, height), + std::move(snapshot_delegate), raster_task_runner); + } + FML_DCHECK(impeller_picture); return DlDeferredImageGPUImpeller::Make( - std::move(display_list), SkISize::Make(width, height), - std::move(snapshot_delegate), std::move(raster_task_runner)); + impeller_picture, SkISize::Make(width, height), + std::move(snapshot_delegate), raster_task_runner); } #endif // IMPELLER_SUPPORTS_RENDERING @@ -79,66 +81,126 @@ static sk_sp CreateDeferredImage( raster_task_runner, std::move(unref_queue)); } -// static -void Picture::RasterizeToImageSync(sk_sp display_list, - uint32_t width, +void Picture::RasterizeToImageSync(uint32_t width, uint32_t height, Dart_Handle raw_image_handle) { auto* dart_state = UIDartState::Current(); if (!dart_state) { return; } + auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner(); auto unref_queue = dart_state->GetSkiaUnrefQueue(); auto snapshot_delegate = dart_state->GetSnapshotDelegate(); - auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner(); auto image = CanvasImage::Create(); auto dl_image = CreateDeferredImage( - dart_state->IsImpellerEnabled(), std::move(display_list), width, height, - std::move(snapshot_delegate), std::move(raster_task_runner), + dart_state->IsImpellerEnabled(), display_list(), impeller_picture(), + width, height, std::move(snapshot_delegate), raster_task_runner, std::move(unref_queue)); + image->set_image(dl_image); image->AssociateWithDartWrapper(raw_image_handle); } void Picture::dispose() { - display_list_.reset(); + picture_ = sk_sp(nullptr); ClearDartWrapper(); } size_t Picture::GetAllocationSize() const { - if (display_list_) { - return display_list_->bytes() + sizeof(Picture); - } else { - return sizeof(Picture); + auto size = sizeof(Picture); + if (display_list()) { + size += display_list()->bytes(); } + // TODO(dnfield): Add support to EntityPass to get its allocation size. + return size; } -Dart_Handle Picture::RasterizeToImage(const sk_sp& display_list, - uint32_t width, +Dart_Handle Picture::RasterizeToImage(uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { - return DoRasterizeToImage(display_list, nullptr, width, height, - raw_image_callback); + return DoRasterizeToImage(width, height, raw_image_callback); } Dart_Handle Picture::RasterizeLayerTreeToImage( std::unique_ptr layer_tree, Dart_Handle raw_image_callback) { FML_DCHECK(layer_tree != nullptr); - auto frame_size = layer_tree->frame_size(); - return DoRasterizeToImage(nullptr, std::move(layer_tree), frame_size.width(), - frame_size.height(), raw_image_callback); + auto* dart_state = UIDartState::Current(); + auto image_callback = std::make_unique( + dart_state, raw_image_callback); + auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner(); + auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner(); + + auto unref_queue = dart_state->GetSkiaUnrefQueue(); + auto snapshot_delegate = dart_state->GetSnapshotDelegate(); + + // We can't create an image on this task runner because we don't have a + // graphics context. Even if we did, it would be slow anyway. Also, this + // thread owns the sole reference to the layer tree. So we do it in the + // raster thread. + + auto ui_task = + // The static leak checker gets confused by the use of + // fml::MakeCopyable. + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) + fml::MakeCopyable([image_callback = std::move(image_callback), + unref_queue](sk_sp image) mutable { + auto dart_state = image_callback->dart_state().lock(); + if (!dart_state) { + // The root isolate could have died in the meantime. + return; + } + tonic::DartState::Scope scope(dart_state); + + if (!image) { + tonic::DartInvoke(image_callback->Get(), {Dart_Null()}); + return; + } + + if (!image->isUIThreadSafe()) { + // All images with impeller textures should already be safe. + FML_DCHECK(image->impeller_texture() == nullptr); + image = + DlImageGPU::Make({image->skia_image(), std::move(unref_queue)}); + } + + auto dart_image = CanvasImage::Create(); + dart_image->set_image(image); + auto* raw_dart_image = tonic::ToDart(dart_image); + + // All done! + tonic::DartInvoke(image_callback->Get(), {raw_dart_image}); + + // image_callback is associated with the Dart isolate and must be + // deleted on the UI thread. + image_callback.reset(); + }); + + // Kick things off on the raster rask runner. + fml::TaskRunner::RunNowOrPostTask( + raster_task_runner, + fml::MakeCopyable([ui_task_runner, snapshot_delegate, ui_task, + layer_tree = std::move(layer_tree)]() mutable { + sk_sp image; + auto display_list = layer_tree->Flatten( + SkRect::MakeXYWH(0, 0, layer_tree->frame_size().width(), + layer_tree->frame_size().height()), + snapshot_delegate->GetTextureRegistry(), + snapshot_delegate->GetGrContext()); + + image = snapshot_delegate->MakeRasterSnapshot(display_list, + layer_tree->frame_size()); + fml::TaskRunner::RunNowOrPostTask( + ui_task_runner, [ui_task, image]() { ui_task(image); }); + })); + + return Dart_Null(); } -Dart_Handle Picture::DoRasterizeToImage(const sk_sp& display_list, - std::unique_ptr layer_tree, - uint32_t width, +Dart_Handle Picture::DoRasterizeToImage(uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { - // Either display_list or layer_tree should be provided. - FML_DCHECK((display_list == nullptr) != (layer_tree == nullptr)); - if (Dart_IsNull(raw_image_callback) || !Dart_IsClosure(raw_image_callback)) { return tonic::ToDart("Image callback was invalid"); } @@ -150,9 +212,10 @@ Dart_Handle Picture::DoRasterizeToImage(const sk_sp& display_list, auto* dart_state = UIDartState::Current(); auto image_callback = std::make_unique( dart_state, raw_image_callback); - auto unref_queue = dart_state->GetSkiaUnrefQueue(); auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner(); auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner(); + + auto unref_queue = dart_state->GetSkiaUnrefQueue(); auto snapshot_delegate = dart_state->GetSnapshotDelegate(); // We can't create an image on this task runner because we don't have a @@ -161,7 +224,8 @@ Dart_Handle Picture::DoRasterizeToImage(const sk_sp& display_list, // raster thread. auto ui_task = - // The static leak checker gets confused by the use of fml::MakeCopyable. + // The static leak checker gets confused by the use of + // fml::MakeCopyable. // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) fml::MakeCopyable([image_callback = std::move(image_callback), unref_queue](sk_sp image) mutable { @@ -199,22 +263,18 @@ Dart_Handle Picture::DoRasterizeToImage(const sk_sp& display_list, // Kick things off on the raster rask runner. fml::TaskRunner::RunNowOrPostTask( raster_task_runner, - fml::MakeCopyable([ui_task_runner, snapshot_delegate, display_list, width, - height, ui_task, - layer_tree = std::move(layer_tree)]() mutable { + fml::MakeCopyable([ui_task_runner, snapshot_delegate, + display_list = display_list(), + impeller_picture = impeller_picture(), width, height, + ui_task]() mutable { auto picture_bounds = SkISize::Make(width, height); sk_sp image; - if (layer_tree) { - FML_DCHECK(picture_bounds == layer_tree->frame_size()); - auto display_list = - layer_tree->Flatten(SkRect::MakeWH(width, height), - snapshot_delegate->GetTextureRegistry(), - snapshot_delegate->GetGrContext()); - + if (display_list) { image = snapshot_delegate->MakeRasterSnapshot(display_list, picture_bounds); } else { - image = snapshot_delegate->MakeRasterSnapshot(display_list, + FML_DCHECK(impeller_picture); + image = snapshot_delegate->MakeRasterSnapshot(impeller_picture, picture_bounds); } diff --git a/lib/ui/painting/picture.h b/lib/ui/painting/picture.h index 6d41cbe8dad68..696de61b2230c 100644 --- a/lib/ui/painting/picture.h +++ b/lib/ui/painting/picture.h @@ -5,15 +5,29 @@ #ifndef FLUTTER_LIB_UI_PAINTING_PICTURE_H_ #define FLUTTER_LIB_UI_PAINTING_PICTURE_H_ +#include + #include "flutter/display_list/display_list.h" #include "flutter/flow/layers/layer_tree.h" #include "flutter/lib/ui/dart_wrapper.h" #include "flutter/lib/ui/painting/image.h" #include "flutter/lib/ui/ui_dart_state.h" +#include "third_party/skia/include/core/SkPicture.h" + +#if IMPELLER_SUPPORTS_RENDERING +#include "impeller/aiks/picture.h" // nogncheck +#else // IMPELLER_SUPPORTS_RENDERING +namespace impeller { +struct Picture; +} // namespace impeller +#endif // !IMPELLER_SUPPORTS_RENDERING namespace flutter { class Canvas; +using DisplayListOrPicture = + std::variant, std::shared_ptr>; + class Picture : public RefCountedDartWrappable { DEFINE_WRAPPERTYPEINFO(); FML_FRIEND_MAKE_REF_COUNTED(Picture); @@ -21,9 +35,22 @@ class Picture : public RefCountedDartWrappable { public: ~Picture() override; static fml::RefPtr Create(Dart_Handle dart_handle, - sk_sp display_list); - - sk_sp display_list() const { return display_list_; } + DisplayListOrPicture picture); + + const sk_sp display_list() const { + if (std::holds_alternative>(picture_)) { + return std::get>(picture_); + } + return nullptr; + } + + std::shared_ptr impeller_picture() const { + if (std::holds_alternative>( + picture_)) { + return std::get>(picture_); + } + return nullptr; + } Dart_Handle toImage(uint32_t width, uint32_t height, @@ -37,34 +64,26 @@ class Picture : public RefCountedDartWrappable { size_t GetAllocationSize() const; - static void RasterizeToImageSync(sk_sp display_list, - uint32_t width, - uint32_t height, - Dart_Handle raw_image_handle); - - static Dart_Handle RasterizeToImage(const sk_sp& display_list, - uint32_t width, - uint32_t height, - Dart_Handle raw_image_callback); - static Dart_Handle RasterizeLayerTreeToImage( std::unique_ptr layer_tree, Dart_Handle raw_image_callback); - // Callers may provide either a display list or a layer tree, but not both. - // - // If a layer tree is provided, it will be flattened on the raster thread, and - // picture_bounds should be the layer tree's frame_size(). - static Dart_Handle DoRasterizeToImage(const sk_sp& display_list, - std::unique_ptr layer_tree, - uint32_t width, - uint32_t height, - Dart_Handle raw_image_callback); - private: - explicit Picture(sk_sp display_list); + explicit Picture(DisplayListOrPicture picture); + + DisplayListOrPicture picture_; + + void RasterizeToImageSync(uint32_t width, + uint32_t height, + Dart_Handle raw_image_handle); + + Dart_Handle RasterizeToImage(uint32_t width, + uint32_t height, + Dart_Handle raw_image_callback); - sk_sp display_list_; + Dart_Handle DoRasterizeToImage(uint32_t width, + uint32_t height, + Dart_Handle raw_image_callback); }; } // namespace flutter diff --git a/lib/ui/painting/picture_recorder.cc b/lib/ui/painting/picture_recorder.cc index a99b5e5855e40..88e1e6844ee5a 100644 --- a/lib/ui/painting/picture_recorder.cc +++ b/lib/ui/painting/picture_recorder.cc @@ -6,6 +6,7 @@ #include "flutter/lib/ui/painting/canvas.h" #include "flutter/lib/ui/painting/picture.h" +#include "impeller/display_list/skia_conversions.h" // nogncheck #include "third_party/tonic/converter/dart_converter.h" #include "third_party/tonic/dart_args.h" #include "third_party/tonic/dart_binding_macros.h" @@ -25,21 +26,39 @@ PictureRecorder::PictureRecorder() {} PictureRecorder::~PictureRecorder() {} -sk_sp PictureRecorder::BeginRecording(SkRect bounds) { - display_list_builder_ = - sk_make_sp(bounds, /*prepare_rtree=*/true); - return display_list_builder_; +DlCanvas* PictureRecorder::BeginRecording(SkRect bounds) { +#if IMPELLER_SUPPORTS_RENDERING + if (UIDartState::Current()->IsImpellerEnabled()) { + dl_aiks_canvas_ = std::make_shared(bounds); + return dl_aiks_canvas_.get(); + } else { +#endif // IMPELLER_SUPPORTS_RENDERING + builder_ = sk_make_sp(bounds, /*prepare_rtree=*/true); + return builder_.get(); +#if IMPELLER_SUPPORTS_RENDERING + } +#endif // IMPELLER_SUPPORTS_RENDERING } fml::RefPtr PictureRecorder::endRecording(Dart_Handle dart_picture) { if (!canvas_) { return nullptr; } - fml::RefPtr picture; - picture = Picture::Create(dart_picture, display_list_builder_->Build()); - display_list_builder_ = nullptr; +#if IMPELLER_SUPPORTS_RENDERING + if (UIDartState::Current()->IsImpellerEnabled()) { + picture = Picture::Create(dart_picture, + std::make_shared( + dl_aiks_canvas_->EndRecordingAsPicture())); + dl_aiks_canvas_ = nullptr; + } else { +#endif + picture = Picture::Create(dart_picture, builder_->Build()); + builder_ = nullptr; +#if IMPELLER_SUPPORTS_RENDERING + } +#endif // IMPELLER_SUPPORTS_RENDERING canvas_->Invalidate(); canvas_ = nullptr; diff --git a/lib/ui/painting/picture_recorder.h b/lib/ui/painting/picture_recorder.h index c5046a424a6ac..ff0c3790d5fca 100644 --- a/lib/ui/painting/picture_recorder.h +++ b/lib/ui/painting/picture_recorder.h @@ -5,9 +5,19 @@ #ifndef FLUTTER_LIB_UI_PAINTING_PICTURE_RECORDER_H_ #define FLUTTER_LIB_UI_PAINTING_PICTURE_RECORDER_H_ +#include + #include "flutter/display_list/dl_builder.h" #include "flutter/lib/ui/dart_wrapper.h" +#if IMPELLER_SUPPORTS_RENDERING +#include "impeller/display_list/dl_aiks_canvas.h" // nogncheck +#else // IMPELLER_SUPPORTS_RENDERING +namespace impeller { +class DlAiksCanvas; +} // namespace impeller +#endif // !IMPELLER_SUPPORTS_RENDERING + namespace flutter { class Canvas; class Picture; @@ -21,7 +31,7 @@ class PictureRecorder : public RefCountedDartWrappable { ~PictureRecorder() override; - sk_sp BeginRecording(SkRect bounds); + DlCanvas* BeginRecording(SkRect bounds); fml::RefPtr endRecording(Dart_Handle dart_picture); void set_canvas(fml::RefPtr canvas) { canvas_ = std::move(canvas); } @@ -29,7 +39,8 @@ class PictureRecorder : public RefCountedDartWrappable { private: PictureRecorder(); - sk_sp display_list_builder_; + std::shared_ptr dl_aiks_canvas_; + sk_sp builder_; fml::RefPtr canvas_; }; diff --git a/lib/ui/snapshot_delegate.h b/lib/ui/snapshot_delegate.h index 2c3677d8551a8..d82f39e66cf56 100644 --- a/lib/ui/snapshot_delegate.h +++ b/lib/ui/snapshot_delegate.h @@ -70,6 +70,10 @@ class SnapshotDelegate { virtual sk_sp MakeRasterSnapshot(sk_sp display_list, SkISize picture_size) = 0; + virtual sk_sp MakeRasterSnapshot( + const std::shared_ptr& picture, + SkISize picture_size) = 0; + virtual sk_sp ConvertToRasterImage(sk_sp image) = 0; }; diff --git a/lib/ui/text/paragraph.cc b/lib/ui/text/paragraph.cc index 624ed145dcf38..4c75bdef96d93 100644 --- a/lib/ui/text/paragraph.cc +++ b/lib/ui/text/paragraph.cc @@ -64,9 +64,9 @@ void Paragraph::paint(Canvas* canvas, double x, double y) { return; } - DisplayListBuilder* builder = canvas->builder(); - if (builder) { - m_paragraph->Paint(builder, x, y); + DlCanvas* dl_canvas = canvas->dl_canvas(); + if (dl_canvas) { + m_paragraph->Paint(dl_canvas, x, y); } } diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index c5a4db91e4333..978aaa7d1e690 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -85,8 +85,6 @@ source_set("common") { "context_options.h", "display_manager.cc", "display_manager.h", - "dl_op_spy.cc", - "dl_op_spy.h", "engine.cc", "engine.h", "pipeline.cc", @@ -294,7 +292,6 @@ if (enable_unittests) { sources = [ "animator_unittests.cc", "context_options_unittests.cc", - "dl_op_spy_unittests.cc", "engine_unittests.cc", "input_events_unittests.cc", "persistent_cache_unittests.cc", diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index d7d1338c1a533..0674299db2c0e 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -372,6 +372,12 @@ sk_sp Rasterizer::MakeRasterSnapshot(sk_sp display_list, return snapshot_controller_->MakeRasterSnapshot(display_list, picture_size); } +sk_sp Rasterizer::MakeRasterSnapshot( + const std::shared_ptr& picture, + SkISize picture_size) { + return snapshot_controller_->MakeRasterSnapshot(picture, picture_size); +} + sk_sp Rasterizer::ConvertToRasterImage(sk_sp image) { TRACE_EVENT0("flutter", __FUNCTION__); return snapshot_controller_->ConvertToRasterImage(image); diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index b17242342c084..f6783c5e92d42 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -509,6 +509,11 @@ class Rasterizer final : public SnapshotDelegate, sk_sp MakeRasterSnapshot(sk_sp display_list, SkISize picture_size) override; + // |SnapshotDelegate| + sk_sp MakeRasterSnapshot( + const std::shared_ptr& picture, + SkISize picture_size) override; + // |SnapshotDelegate| sk_sp ConvertToRasterImage(sk_sp image) override; diff --git a/shell/common/snapshot_controller.h b/shell/common/snapshot_controller.h index c402c3ec709fa..a5709f9d2d226 100644 --- a/shell/common/snapshot_controller.h +++ b/shell/common/snapshot_controller.h @@ -42,6 +42,10 @@ class SnapshotController { virtual sk_sp MakeRasterSnapshot(sk_sp display_list, SkISize size) = 0; + virtual sk_sp MakeRasterSnapshot( + const std::shared_ptr& picture, + SkISize size) = 0; + virtual sk_sp ConvertToRasterImage(sk_sp image) = 0; protected: diff --git a/shell/common/snapshot_controller_impeller.cc b/shell/common/snapshot_controller_impeller.cc index ea68bd91188a4..79c3bf5c65095 100644 --- a/shell/common/snapshot_controller_impeller.cc +++ b/shell/common/snapshot_controller_impeller.cc @@ -30,13 +30,36 @@ sk_sp SnapshotControllerImpeller::MakeRasterSnapshot( return result; } +sk_sp SnapshotControllerImpeller::MakeRasterSnapshot( + const std::shared_ptr& picture, + SkISize size) { + sk_sp result; + if (!picture) { + return result; + } + GetDelegate().GetIsGpuDisabledSyncSwitch()->Execute( + fml::SyncSwitch::Handlers() + .SetIfTrue([&] { + // Do nothing. + }) + .SetIfFalse([&] { result = DoMakeRasterSnapshot(*picture, size); })); + + return result; +} + sk_sp SnapshotControllerImpeller::DoMakeRasterSnapshot( const sk_sp& display_list, SkISize size) { TRACE_EVENT0("flutter", __FUNCTION__); impeller::DlDispatcher dispatcher; display_list->Dispatch(dispatcher); - impeller::Picture picture = dispatcher.EndRecordingAsPicture(); + return DoMakeRasterSnapshot(dispatcher.EndRecordingAsPicture(), size); +} + +sk_sp SnapshotControllerImpeller::DoMakeRasterSnapshot( + const impeller::Picture& picture, + SkISize size) { + TRACE_EVENT0("flutter", __FUNCTION__); auto context = GetDelegate().GetAiksContext(); if (context) { auto max_size = context->GetContext() diff --git a/shell/common/snapshot_controller_impeller.h b/shell/common/snapshot_controller_impeller.h index d9f1d632e3553..5bd40a969597f 100644 --- a/shell/common/snapshot_controller_impeller.h +++ b/shell/common/snapshot_controller_impeller.h @@ -18,12 +18,19 @@ class SnapshotControllerImpeller : public SnapshotController { sk_sp MakeRasterSnapshot(sk_sp display_list, SkISize size) override; + sk_sp MakeRasterSnapshot( + const std::shared_ptr& picture, + SkISize size) override; + sk_sp ConvertToRasterImage(sk_sp image) override; private: sk_sp DoMakeRasterSnapshot(const sk_sp& display_list, SkISize size); + sk_sp DoMakeRasterSnapshot(const impeller::Picture& picture, + SkISize size); + FML_DISALLOW_COPY_AND_ASSIGN(SnapshotControllerImpeller); }; diff --git a/shell/common/snapshot_controller_skia.cc b/shell/common/snapshot_controller_skia.cc index fe7897f38d178..096dfac614666 100644 --- a/shell/common/snapshot_controller_skia.cc +++ b/shell/common/snapshot_controller_skia.cc @@ -137,6 +137,13 @@ sk_sp SnapshotControllerSkia::MakeRasterSnapshot( }); } +sk_sp SnapshotControllerSkia::MakeRasterSnapshot( + const std::shared_ptr& picture, + SkISize size) { + FML_DCHECK(false); + return sk_sp(); +} + sk_sp SnapshotControllerSkia::ConvertToRasterImage( sk_sp image) { // If the rasterizer does not have a surface with a GrContext, then it will diff --git a/shell/common/snapshot_controller_skia.h b/shell/common/snapshot_controller_skia.h index 8be1d8e1ec274..09a48a4251a36 100644 --- a/shell/common/snapshot_controller_skia.h +++ b/shell/common/snapshot_controller_skia.h @@ -18,6 +18,10 @@ class SnapshotControllerSkia : public SnapshotController { sk_sp MakeRasterSnapshot(sk_sp display_list, SkISize size) override; + sk_sp MakeRasterSnapshot( + const std::shared_ptr& picture, + SkISize size) override; + virtual sk_sp ConvertToRasterImage(sk_sp image) override; private: diff --git a/shell/gpu/gpu_surface_gl_impeller.cc b/shell/gpu/gpu_surface_gl_impeller.cc index 84372944eb6d4..8b6f335778968 100644 --- a/shell/gpu/gpu_surface_gl_impeller.cc +++ b/shell/gpu/gpu_surface_gl_impeller.cc @@ -5,7 +5,6 @@ #include "flutter/shell/gpu/gpu_surface_gl_impeller.h" #include "flutter/fml/make_copyable.h" -#include "flutter/impeller/display_list/dl_dispatcher.h" #include "flutter/impeller/renderer/backend/gles/surface_gles.h" #include "flutter/impeller/renderer/renderer.h" @@ -100,27 +99,14 @@ std::unique_ptr GPUSurfaceGLImpeller::AcquireFrame( return false; } - auto display_list = surface_frame.BuildDisplayList(); - if (!display_list) { - FML_LOG(ERROR) << "Could not build display list for surface frame."; - return false; - } - - auto cull_rect = - surface->GetTargetRenderPassDescriptor().GetRenderTargetSize(); - impeller::Rect dl_cull_rect = impeller::Rect::MakeSize(cull_rect); - impeller::DlDispatcher impeller_dispatcher(dl_cull_rect); - display_list->Dispatch( - impeller_dispatcher, - SkIRect::MakeWH(cull_rect.width, cull_rect.height)); - auto picture = impeller_dispatcher.EndRecordingAsPicture(); + auto picture = surface_frame.GetImpellerPicture(); return renderer->Render( std::move(surface), fml::MakeCopyable( [aiks_context, picture = std::move(picture)]( impeller::RenderTarget& render_target) -> bool { - return aiks_context->Render(picture, render_target); + return aiks_context->Render(*picture, render_target); })); }); diff --git a/shell/gpu/gpu_surface_metal_impeller.mm b/shell/gpu/gpu_surface_metal_impeller.mm index 32b2f28325394..d20e2ed698fd6 100644 --- a/shell/gpu/gpu_surface_metal_impeller.mm +++ b/shell/gpu/gpu_surface_metal_impeller.mm @@ -11,7 +11,6 @@ #include "flutter/fml/make_copyable.h" #include "flutter/fml/mapping.h" #include "flutter/fml/trace_event.h" -#include "flutter/impeller/display_list/dl_dispatcher.h" #include "flutter/impeller/renderer/backend/metal/surface_mtl.h" static_assert(!__has_feature(objc_arc), "ARC must be disabled."); @@ -113,12 +112,6 @@ return false; } - auto display_list = surface_frame.BuildDisplayList(); - if (!display_list) { - FML_LOG(ERROR) << "Could not build display list for surface frame."; - return false; - } - if (!disable_partial_repaint_) { uintptr_t texture = reinterpret_cast(last_texture); @@ -148,17 +141,13 @@ return surface->Present(); } - impeller::IRect cull_rect = surface->coverage(); - SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.size.width, cull_rect.size.height); - impeller::DlDispatcher impeller_dispatcher(cull_rect); - display_list->Dispatch(impeller_dispatcher, sk_cull_rect); - auto picture = impeller_dispatcher.EndRecordingAsPicture(); + auto picture = surface_frame.GetImpellerPicture(); return renderer->Render( std::move(surface), fml::MakeCopyable([aiks_context, picture = std::move(picture)]( impeller::RenderTarget& render_target) -> bool { - return aiks_context->Render(picture, render_target); + return aiks_context->Render(*picture, render_target); })); }); @@ -211,12 +200,6 @@ return false; } - auto display_list = surface_frame.BuildDisplayList(); - if (!display_list) { - FML_LOG(ERROR) << "Could not build display list for surface frame."; - return false; - } - if (!disable_partial_repaint_) { uintptr_t texture_ptr = reinterpret_cast(mtl_texture); @@ -246,17 +229,13 @@ return surface->Present(); } - impeller::IRect cull_rect = surface->coverage(); - SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.size.width, cull_rect.size.height); - impeller::DlDispatcher impeller_dispatcher(cull_rect); - display_list->Dispatch(impeller_dispatcher, sk_cull_rect); - auto picture = impeller_dispatcher.EndRecordingAsPicture(); + auto picture = surface_frame.GetImpellerPicture(); return renderer->Render( std::move(surface), fml::MakeCopyable([aiks_context, picture = std::move(picture)]( impeller::RenderTarget& render_target) -> bool { - return aiks_context->Render(picture, render_target); + return aiks_context->Render(*picture, render_target); })); delegate->PresentTexture(texture_info); diff --git a/shell/gpu/gpu_surface_vulkan_impeller.cc b/shell/gpu/gpu_surface_vulkan_impeller.cc index 42c5f1d53c61e..d182b00334fd7 100644 --- a/shell/gpu/gpu_surface_vulkan_impeller.cc +++ b/shell/gpu/gpu_surface_vulkan_impeller.cc @@ -5,7 +5,6 @@ #include "flutter/shell/gpu/gpu_surface_vulkan_impeller.h" #include "flutter/fml/make_copyable.h" -#include "flutter/impeller/display_list/dl_dispatcher.h" #include "flutter/impeller/renderer/renderer.h" #include "impeller/renderer/backend/vulkan/surface_context_vk.h" #include "impeller/renderer/surface.h" @@ -67,27 +66,14 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( return false; } - auto display_list = surface_frame.BuildDisplayList(); - if (!display_list) { - FML_LOG(ERROR) << "Could not build display list for surface frame."; - return false; - } - - auto cull_rect = - surface->GetTargetRenderPassDescriptor().GetRenderTargetSize(); - impeller::Rect dl_cull_rect = impeller::Rect::MakeSize(cull_rect); - impeller::DlDispatcher impeller_dispatcher(dl_cull_rect); - display_list->Dispatch( - impeller_dispatcher, - SkIRect::MakeWH(cull_rect.width, cull_rect.height)); - auto picture = impeller_dispatcher.EndRecordingAsPicture(); + auto picture = surface_frame.GetImpellerPicture(); return renderer->Render( std::move(surface), fml::MakeCopyable( [aiks_context, picture = std::move(picture)]( impeller::RenderTarget& render_target) -> bool { - return aiks_context->Render(picture, render_target); + return aiks_context->Render(*picture, render_target); })); }); diff --git a/shell/platform/android/external_view_embedder/external_view_embedder.cc b/shell/platform/android/external_view_embedder/external_view_embedder.cc index d29a80eb16a8c..10fc5fc4d27a8 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder.cc @@ -12,13 +12,15 @@ AndroidExternalViewEmbedder::AndroidExternalViewEmbedder( const AndroidContext& android_context, std::shared_ptr jni_facade, std::shared_ptr surface_factory, - const TaskRunners& task_runners) + const TaskRunners& task_runners, + bool enable_impeller) : ExternalViewEmbedder(), android_context_(android_context), jni_facade_(std::move(jni_facade)), surface_factory_(std::move(surface_factory)), surface_pool_(std::make_unique()), - task_runners_(task_runners) {} + task_runners_(task_runners), + enable_impeller_(enable_impeller) {} // |ExternalViewEmbedder| void AndroidExternalViewEmbedder::PrerollCompositeEmbeddedView( @@ -29,7 +31,11 @@ void AndroidExternalViewEmbedder::PrerollCompositeEmbeddedView( SkRect view_bounds = SkRect::Make(frame_size_); std::unique_ptr view; - view = std::make_unique(view_bounds); + if (enable_impeller_) { + view = std::make_unique(view_bounds); + } else { + view = std::make_unique(view_bounds); + } slices_.insert_or_assign(view_id, std::move(view)); composition_order_.push_back(view_id); diff --git a/shell/platform/android/external_view_embedder/external_view_embedder.h b/shell/platform/android/external_view_embedder/external_view_embedder.h index 400b43fb91a89..0f1d69e955d48 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.h +++ b/shell/platform/android/external_view_embedder/external_view_embedder.h @@ -32,7 +32,8 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder { const AndroidContext& android_context, std::shared_ptr jni_facade, std::shared_ptr surface_factory, - const TaskRunners& task_runners); + const TaskRunners& task_runners, + bool enable_impeller); // |ExternalViewEmbedder| void PrerollCompositeEmbeddedView( @@ -123,6 +124,8 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder { // The number of platform views in the previous frame. int64_t previous_frame_view_count_; + bool enable_impeller_ = false; + // Destroys the surfaces created from the surface factory. // This method schedules a task on the platform thread, and waits for // the task until it completes. diff --git a/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc b/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc index e6417a08f0800..40d9e9fd526b5 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc @@ -107,7 +107,7 @@ TaskRunners GetTaskRunnersForFixture() { TEST(AndroidExternalViewEmbedder, CompositeEmbeddedView) { auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware); auto embedder = std::make_unique( - android_context, nullptr, nullptr, GetTaskRunnersForFixture()); + android_context, nullptr, nullptr, GetTaskRunnersForFixture(), false); ASSERT_EQ(nullptr, embedder->CompositeEmbeddedView(0)); embedder->PrerollCompositeEmbeddedView( @@ -123,7 +123,7 @@ TEST(AndroidExternalViewEmbedder, CompositeEmbeddedView) { TEST(AndroidExternalViewEmbedder, CancelFrame) { auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware); auto embedder = std::make_unique( - android_context, nullptr, nullptr, GetTaskRunnersForFixture()); + android_context, nullptr, nullptr, GetTaskRunnersForFixture(), false); embedder->PrerollCompositeEmbeddedView( 0, std::make_unique()); @@ -136,7 +136,7 @@ TEST(AndroidExternalViewEmbedder, RasterizerRunsOnPlatformThread) { auto jni_mock = std::make_shared(); auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware); auto embedder = std::make_unique( - android_context, jni_mock, nullptr, GetTaskRunnersForFixture()); + android_context, jni_mock, nullptr, GetTaskRunnersForFixture(), false); fml::Thread rasterizer_thread("rasterizer"); auto raster_thread_merger = @@ -170,7 +170,7 @@ TEST(AndroidExternalViewEmbedder, RasterizerRunsOnRasterizerThread) { auto jni_mock = std::make_shared(); auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware); auto embedder = std::make_unique( - android_context, jni_mock, nullptr, GetTaskRunnersForFixture()); + android_context, jni_mock, nullptr, GetTaskRunnersForFixture(), false); fml::Thread rasterizer_thread("rasterizer"); auto raster_thread_merger = @@ -191,7 +191,7 @@ TEST(AndroidExternalViewEmbedder, PlatformViewRect) { auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware); auto embedder = std::make_unique( - android_context, jni_mock, nullptr, GetTaskRunnersForFixture()); + android_context, jni_mock, nullptr, GetTaskRunnersForFixture(), false); fml::Thread rasterizer_thread("rasterizer"); auto raster_thread_merger = GetThreadMergerFromPlatformThread(&rasterizer_thread); @@ -219,7 +219,7 @@ TEST(AndroidExternalViewEmbedder, PlatformViewRectChangedParams) { auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware); auto embedder = std::make_unique( - android_context, jni_mock, nullptr, GetTaskRunnersForFixture()); + android_context, jni_mock, nullptr, GetTaskRunnersForFixture(), false); fml::Thread rasterizer_thread("rasterizer"); auto raster_thread_merger = GetThreadMergerFromPlatformThread(&rasterizer_thread); @@ -295,7 +295,8 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame) { return android_surface_mock; }); auto embedder = std::make_unique( - *android_context, jni_mock, surface_factory, GetTaskRunnersForFixture()); + *android_context, jni_mock, surface_factory, GetTaskRunnersForFixture(), + false); auto raster_thread_merger = GetThreadMergerFromPlatformThread(); @@ -494,7 +495,8 @@ TEST(AndroidExternalViewEmbedder, OverlayCoverTwoPlatformViews) { return android_surface_mock; }); auto embedder = std::make_unique( - *android_context, jni_mock, surface_factory, GetTaskRunnersForFixture()); + *android_context, jni_mock, surface_factory, GetTaskRunnersForFixture(), + false); auto raster_thread_merger = GetThreadMergerFromPlatformThread(); @@ -592,7 +594,8 @@ TEST(AndroidExternalViewEmbedder, SubmitFrameOverlayComposition) { return android_surface_mock; }); auto embedder = std::make_unique( - *android_context, jni_mock, surface_factory, GetTaskRunnersForFixture()); + *android_context, jni_mock, surface_factory, GetTaskRunnersForFixture(), + false); auto raster_thread_merger = GetThreadMergerFromPlatformThread(); @@ -695,7 +698,8 @@ TEST(AndroidExternalViewEmbedder, SubmitFramePlatformViewWithoutAnyOverlay) { return android_surface_mock; }); auto embedder = std::make_unique( - *android_context, jni_mock, surface_factory, GetTaskRunnersForFixture()); + *android_context, jni_mock, surface_factory, GetTaskRunnersForFixture(), + false); auto raster_thread_merger = GetThreadMergerFromPlatformThread(); @@ -735,7 +739,7 @@ TEST(AndroidExternalViewEmbedder, DoesNotCallJNIPlatformThreadOnlyMethods) { auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware); auto embedder = std::make_unique( - android_context, jni_mock, nullptr, GetTaskRunnersForFixture()); + android_context, jni_mock, nullptr, GetTaskRunnersForFixture(), false); // While on the raster thread, don't make JNI calls as these methods can only // run on the platform thread. @@ -784,7 +788,8 @@ TEST(AndroidExternalViewEmbedder, DestroyOverlayLayersOnSizeChange) { }); auto embedder = std::make_unique( - *android_context, jni_mock, surface_factory, GetTaskRunnersForFixture()); + *android_context, jni_mock, surface_factory, GetTaskRunnersForFixture(), + false); fml::Thread rasterizer_thread("rasterizer"); auto raster_thread_merger = GetThreadMergerFromPlatformThread(&rasterizer_thread); @@ -872,7 +877,8 @@ TEST(AndroidExternalViewEmbedder, DoesNotDestroyOverlayLayersOnSizeChange) { }); auto embedder = std::make_unique( - *android_context, jni_mock, surface_factory, GetTaskRunnersForFixture()); + *android_context, jni_mock, surface_factory, GetTaskRunnersForFixture(), + false); // ------------------ First frame ------------------ // { @@ -930,7 +936,7 @@ TEST(AndroidExternalViewEmbedder, SupportsDynamicThreadMerging) { auto jni_mock = std::make_shared(); auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware); auto embedder = std::make_unique( - android_context, jni_mock, nullptr, GetTaskRunnersForFixture()); + android_context, jni_mock, nullptr, GetTaskRunnersForFixture(), false); ASSERT_TRUE(embedder->SupportsDynamicThreadMerging()); } @@ -938,7 +944,7 @@ TEST(AndroidExternalViewEmbedder, DisableThreadMerger) { auto jni_mock = std::make_shared(); auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware); auto embedder = std::make_unique( - android_context, jni_mock, nullptr, GetTaskRunnersForFixture()); + android_context, jni_mock, nullptr, GetTaskRunnersForFixture(), false); fml::Thread platform_thread("platform"); auto raster_thread_merger = GetThreadMergerFromRasterThread(&platform_thread); @@ -994,7 +1000,8 @@ TEST(AndroidExternalViewEmbedder, Teardown) { }); auto embedder = std::make_unique( - *android_context, jni_mock, surface_factory, GetTaskRunnersForFixture()); + *android_context, jni_mock, surface_factory, GetTaskRunnersForFixture(), + false); fml::Thread rasterizer_thread("rasterizer"); auto raster_thread_merger = GetThreadMergerFromPlatformThread(&rasterizer_thread); @@ -1037,7 +1044,7 @@ TEST(AndroidExternalViewEmbedder, TeardownDoesNotCallJNIMethod) { auto android_context = std::make_shared(AndroidRenderingAPI::kSoftware); auto embedder = std::make_unique( - *android_context, jni_mock, nullptr, GetTaskRunnersForFixture()); + *android_context, jni_mock, nullptr, GetTaskRunnersForFixture(), false); EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces()).Times(0); embedder->Teardown(); diff --git a/shell/platform/android/platform_view_android.cc b/shell/platform/android/platform_view_android.cc index ff941ef81dc3c..fa5ca62ca0135 100644 --- a/shell/platform/android/platform_view_android.cc +++ b/shell/platform/android/platform_view_android.cc @@ -336,7 +336,8 @@ std::unique_ptr PlatformViewAndroid::CreateRenderingSurface() { std::shared_ptr PlatformViewAndroid::CreateExternalViewEmbedder() { return std::make_shared( - *android_context_, jni_facade_, surface_factory_, task_runners_); + *android_context_, jni_facade_, surface_factory_, task_runners_, + delegate_.OnPlatformViewGetSettings().enable_impeller); } // |PlatformView| diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index b5a29314bb2ae..5bedef5da5a47 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -1309,7 +1309,7 @@ InferExternalViewEmbedderFromArgs(const FlutterCompositor* compositor, return {std::make_unique( avoid_backing_store_cache, create_render_target_callback, - present_callback), + present_callback, enable_impeller), false}; } diff --git a/shell/platform/embedder/embedder_external_view.cc b/shell/platform/embedder/embedder_external_view.cc index 4075b3875cf7f..fcb436865a74b 100644 --- a/shell/platform/embedder/embedder_external_view.cc +++ b/shell/platform/embedder/embedder_external_view.cc @@ -4,13 +4,8 @@ #include "flutter/shell/platform/embedder/embedder_external_view.h" -#include "flutter/display_list/dl_builder.h" +#include "flow/embedded_views.h" #include "flutter/fml/trace_event.h" -#include "flutter/shell/common/dl_op_spy.h" - -#ifdef IMPELLER_SUPPORTS_RENDERING -#include "impeller/display_list/dl_dispatcher.h" // nogncheck -#endif // IMPELLER_SUPPORTS_RENDERING namespace flutter { @@ -23,21 +18,37 @@ static SkISize TransformedSurfaceSize(const SkISize& size, EmbedderExternalView::EmbedderExternalView( const SkISize& frame_size, - const SkMatrix& surface_transformation) - : EmbedderExternalView(frame_size, surface_transformation, {}, nullptr) {} + const SkMatrix& surface_transformation, + bool enable_impeller) + : EmbedderExternalView(frame_size, + surface_transformation, + {}, + nullptr, + enable_impeller) {} EmbedderExternalView::EmbedderExternalView( const SkISize& frame_size, const SkMatrix& surface_transformation, ViewIdentifier view_identifier, - std::unique_ptr params) + std::unique_ptr params, + bool enable_impeller) : render_surface_size_( TransformedSurfaceSize(frame_size, surface_transformation)), surface_transformation_(surface_transformation), view_identifier_(view_identifier), - embedded_view_params_(std::move(params)), - slice_(std::make_unique( - SkRect::Make(frame_size))) {} + embedded_view_params_(std::move(params)) { +#if IMPELLER_SUPPORTS_RENDERING + if (enable_impeller) { + slice_ = + std::make_unique(SkRect::Make(frame_size)); + } else { +#endif // IMPELLER_SUPPORTS_RENDERING + slice_ = std::make_unique( + SkRect::Make(frame_size)); +#if IMPELLER_SUPPORTS_RENDERING + } +#endif // IMPELLER_SUPPORTS_RENDERING +} EmbedderExternalView::~EmbedderExternalView() = default; @@ -67,9 +78,7 @@ bool EmbedderExternalView::HasEngineRenderedContents() { return has_engine_rendered_contents_.value(); } TryEndRecording(); - DlOpSpy dl_op_spy; - slice_->dispatch(dl_op_spy); - has_engine_rendered_contents_ = dl_op_spy.did_draw() && !slice_->is_empty(); + has_engine_rendered_contents_ = slice_->renders_anything(); return has_engine_rendered_contents_.value(); } @@ -94,13 +103,12 @@ bool EmbedderExternalView::Render(const EmbedderRenderTarget& render_target) { if (impeller_target) { auto aiks_context = render_target.GetAiksContext(); - auto dl_builder = DisplayListBuilder(); - dl_builder.SetTransform(&surface_transformation_); - slice_->render_into(&dl_builder); + impeller::DlAiksCanvas dl_canvas( + SkRect::Make(render_target.GetRenderTargetSize())); + dl_canvas.SetTransform(&surface_transformation_); + slice_->render_into(&dl_canvas); - auto dispatcher = impeller::DlDispatcher(); - dispatcher.drawDisplayList(dl_builder.Build(), 1); - return aiks_context->Render(dispatcher.EndRecordingAsPicture(), + return aiks_context->Render(dl_canvas.EndRecordingAsPicture(), *impeller_target); } #endif // IMPELLER_SUPPORTS_RENDERING diff --git a/shell/platform/embedder/embedder_external_view.h b/shell/platform/embedder/embedder_external_view.h index 2b8e26d200155..e4187b4edffee 100644 --- a/shell/platform/embedder/embedder_external_view.h +++ b/shell/platform/embedder/embedder_external_view.h @@ -82,12 +82,14 @@ class EmbedderExternalView { ViewIdentifier::Equal>; EmbedderExternalView(const SkISize& frame_size, - const SkMatrix& surface_transformation); + const SkMatrix& surface_transformation, + bool enable_impeller); EmbedderExternalView(const SkISize& frame_size, const SkMatrix& surface_transformation, ViewIdentifier view_identifier, - std::unique_ptr params); + std::unique_ptr params, + bool enable_impeller); ~EmbedderExternalView(); @@ -118,7 +120,7 @@ class EmbedderExternalView { const SkMatrix surface_transformation_; ViewIdentifier view_identifier_; std::unique_ptr embedded_view_params_; - std::unique_ptr slice_; + std::unique_ptr slice_; std::optional has_engine_rendered_contents_; FML_DISALLOW_COPY_AND_ASSIGN(EmbedderExternalView); diff --git a/shell/platform/embedder/embedder_external_view_embedder.cc b/shell/platform/embedder/embedder_external_view_embedder.cc index f87d451a6af26..1b328ff84fa8d 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.cc +++ b/shell/platform/embedder/embedder_external_view_embedder.cc @@ -16,8 +16,10 @@ namespace flutter { EmbedderExternalViewEmbedder::EmbedderExternalViewEmbedder( bool avoid_backing_store_cache, const CreateRenderTargetCallback& create_render_target_callback, - const PresentCallback& present_callback) - : avoid_backing_store_cache_(avoid_backing_store_cache), + const PresentCallback& present_callback, + bool enable_impeller) + : enable_impeller_(enable_impeller), + avoid_backing_store_cache_(avoid_backing_store_cache), create_render_target_callback_(create_render_target_callback), present_callback_(present_callback) { FML_DCHECK(create_render_target_callback_); @@ -65,7 +67,7 @@ void EmbedderExternalViewEmbedder::BeginFrame( EmbedderExternalView::ViewIdentifier{}; pending_views_[kRootViewIdentifier] = std::make_unique( - pending_frame_size_, pending_surface_transformation_); + pending_frame_size_, pending_surface_transformation_, enable_impeller_); composition_order_.push_back(kRootViewIdentifier); } @@ -80,7 +82,8 @@ void EmbedderExternalViewEmbedder::PrerollCompositeEmbeddedView( pending_frame_size_, // frame size pending_surface_transformation_, // surface xformation vid, // view identifier - std::move(params) // embedded view params + std::move(params), // embedded view params + enable_impeller_ // enable_impeller ); composition_order_.push_back(vid); } diff --git a/shell/platform/embedder/embedder_external_view_embedder.h b/shell/platform/embedder/embedder_external_view_embedder.h index 014f7393c416e..6446fa085cefc 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.h +++ b/shell/platform/embedder/embedder_external_view_embedder.h @@ -58,7 +58,8 @@ class EmbedderExternalViewEmbedder final : public ExternalViewEmbedder { EmbedderExternalViewEmbedder( bool avoid_backing_store_cache, const CreateRenderTargetCallback& create_render_target_callback, - const PresentCallback& present_callback); + const PresentCallback& present_callback, + bool enable_impeller); //---------------------------------------------------------------------------- /// @brief Collects the external view embedder. @@ -104,6 +105,7 @@ class EmbedderExternalViewEmbedder final : public ExternalViewEmbedder { DlCanvas* GetRootCanvas() override; private: + bool enable_impeller_ = false; const bool avoid_backing_store_cache_; const CreateRenderTargetCallback create_render_target_callback_; const PresentCallback present_callback_; diff --git a/testing/mock_canvas.cc b/testing/mock_canvas.cc index 75b03107e2a75..bd9d321fc2500 100644 --- a/testing/mock_canvas.cc +++ b/testing/mock_canvas.cc @@ -193,6 +193,14 @@ void MockCanvas::DrawImage(const sk_sp& image, } } +void MockCanvas::DrawImpellerPicture( + const std::shared_ptr& picture, + SkScalar opacity) { + draw_calls_.emplace_back( + DrawCall{.layer = current_layer_, + .data = DrawImpellerPictureData{picture, opacity}}); +} + void MockCanvas::DrawDisplayList(const sk_sp display_list, SkScalar opacity) { draw_calls_.emplace_back( @@ -462,6 +470,16 @@ std::ostream& operator<<(std::ostream& os, << data.options; } +bool operator==(const MockCanvas::DrawImpellerPictureData& a, + const MockCanvas::DrawImpellerPictureData& b) { + return a.picture == b.picture && a.opacity == b.opacity; +} + +std::ostream& operator<<(std::ostream& os, + const MockCanvas::DrawImpellerPictureData& data) { + return os << "[Impeller picture] " << data.opacity; +} + bool operator==(const MockCanvas::DrawDisplayListData& a, const MockCanvas::DrawDisplayListData& b) { return a.display_list->Equals(b.display_list) && a.opacity == b.opacity; diff --git a/testing/mock_canvas.h b/testing/mock_canvas.h index 71260d5b8755f..64d9a725f99ce 100644 --- a/testing/mock_canvas.h +++ b/testing/mock_canvas.h @@ -95,6 +95,11 @@ class MockCanvas final : public DlCanvas { DlPaint paint; }; + struct DrawImpellerPictureData { + std::shared_ptr picture; + SkScalar opacity; + }; + struct DrawDisplayListData { sk_sp display_list; SkScalar opacity; @@ -142,6 +147,7 @@ class MockCanvas final : public DlCanvas { DrawTextData, DrawImageDataNoPaint, DrawImageData, + DrawImpellerPictureData, DrawDisplayListData, DrawShadowData, ClipRectData, @@ -266,7 +272,9 @@ class MockCanvas final : public DlCanvas { DlImageSampling sampling, const SkRect* cullRect, const DlPaint* paint = nullptr) override; - + void DrawImpellerPicture( + const std::shared_ptr& picture, + SkScalar opacity = SK_Scalar1) override; void DrawDisplayList(const sk_sp display_list, SkScalar opacity) override; void DrawTextBlob(const sk_sp& blob, @@ -327,6 +335,11 @@ extern bool operator==(const MockCanvas::DrawImageDataNoPaint& a, const MockCanvas::DrawImageDataNoPaint& b); extern std::ostream& operator<<(std::ostream& os, const MockCanvas::DrawImageDataNoPaint& data); +extern std::ostream& operator<<( + std::ostream& os, + const MockCanvas::DrawImpellerPictureData& data); +extern bool operator==(const MockCanvas::DrawImpellerPictureData& a, + const MockCanvas::DrawImpellerPictureData& b); extern bool operator==(const MockCanvas::DrawDisplayListData& a, const MockCanvas::DrawDisplayListData& b); extern std::ostream& operator<<(std::ostream& os, diff --git a/third_party/txt/src/skia/paragraph_skia.cc b/third_party/txt/src/skia/paragraph_skia.cc index c909a34daef6a..c01ac2a3c83d6 100644 --- a/third_party/txt/src/skia/paragraph_skia.cc +++ b/third_party/txt/src/skia/paragraph_skia.cc @@ -45,9 +45,9 @@ txt::FontStyle GetTxtFontStyle(SkFontStyle::Slant font_slant) { class DisplayListParagraphPainter : public skt::ParagraphPainter { public: - DisplayListParagraphPainter(DisplayListBuilder* builder, + DisplayListParagraphPainter(DlCanvas* canvas, const std::vector& dl_paints) - : builder_(builder), dl_paints_(dl_paints) {} + : canvas_(canvas), dl_paints_(dl_paints) {} DlPaint toDlPaint(const DecorationStyle& decor_style, DlDrawStyle draw_style = DlDrawStyle::kStroke) { @@ -76,7 +76,7 @@ class DisplayListParagraphPainter : public skt::ParagraphPainter { } size_t paint_id = std::get(paint); FML_DCHECK(paint_id < dl_paints_.size()); - builder_->DrawTextBlob(blob, x, y, dl_paints_[paint_id]); + canvas_->DrawTextBlob(blob, x, y, dl_paints_[paint_id]); } void drawTextShadow(const sk_sp& blob, @@ -93,24 +93,24 @@ class DisplayListParagraphPainter : public skt::ParagraphPainter { DlBlurMaskFilter filter(DlBlurStyle::kNormal, blur_sigma, false); paint.setMaskFilter(&filter); } - builder_->DrawTextBlob(blob, x, y, paint); + canvas_->DrawTextBlob(blob, x, y, paint); } void drawRect(const SkRect& rect, const SkPaintOrID& paint) override { size_t paint_id = std::get(paint); FML_DCHECK(paint_id < dl_paints_.size()); - builder_->DrawRect(rect, dl_paints_[paint_id]); + canvas_->DrawRect(rect, dl_paints_[paint_id]); } void drawFilledRect(const SkRect& rect, const DecorationStyle& decor_style) override { DlPaint paint = toDlPaint(decor_style, DlDrawStyle::kFill); - builder_->DrawRect(rect, paint); + canvas_->DrawRect(rect, paint); } void drawPath(const SkPath& path, const DecorationStyle& decor_style) override { - builder_->DrawPath(path, toDlPaint(decor_style)); + canvas_->DrawPath(path, toDlPaint(decor_style)); } void drawLine(SkScalar x0, @@ -118,24 +118,24 @@ class DisplayListParagraphPainter : public skt::ParagraphPainter { SkScalar x1, SkScalar y1, const DecorationStyle& decor_style) override { - builder_->DrawLine(SkPoint::Make(x0, y0), SkPoint::Make(x1, y1), - toDlPaint(decor_style)); + canvas_->DrawLine(SkPoint::Make(x0, y0), SkPoint::Make(x1, y1), + toDlPaint(decor_style)); } void clipRect(const SkRect& rect) override { - builder_->ClipRect(rect, DlCanvas::ClipOp::kIntersect, false); + canvas_->ClipRect(rect, DlCanvas::ClipOp::kIntersect, false); } void translate(SkScalar dx, SkScalar dy) override { - builder_->Translate(dx, dy); + canvas_->Translate(dx, dy); } - void save() override { builder_->Save(); } + void save() override { canvas_->Save(); } - void restore() override { builder_->Restore(); } + void restore() override { canvas_->Restore(); } private: - DisplayListBuilder* builder_; + DlCanvas* canvas_; const std::vector& dl_paints_; }; @@ -222,7 +222,7 @@ void ParagraphSkia::Layout(double width) { paragraph_->layout(width); } -bool ParagraphSkia::Paint(DisplayListBuilder* builder, double x, double y) { +bool ParagraphSkia::Paint(DlCanvas* builder, double x, double y) { DisplayListParagraphPainter painter(builder, dl_paints_); paragraph_->paint(&painter, x, y); return true; diff --git a/third_party/txt/src/skia/paragraph_skia.h b/third_party/txt/src/skia/paragraph_skia.h index 8fa1314209049..7167573572eda 100644 --- a/third_party/txt/src/skia/paragraph_skia.h +++ b/third_party/txt/src/skia/paragraph_skia.h @@ -53,7 +53,7 @@ class ParagraphSkia : public Paragraph { void Layout(double width) override; - bool Paint(flutter::DisplayListBuilder* builder, double x, double y) override; + bool Paint(flutter::DlCanvas* canvas, double x, double y) override; std::vector GetRectsForRange( size_t start, diff --git a/third_party/txt/src/txt/paragraph.h b/third_party/txt/src/txt/paragraph.h index 2d736fb3935c5..5c4e374ddc585 100644 --- a/third_party/txt/src/txt/paragraph.h +++ b/third_party/txt/src/txt/paragraph.h @@ -18,7 +18,7 @@ #ifndef LIB_TXT_SRC_PARAGRAPH_H_ #define LIB_TXT_SRC_PARAGRAPH_H_ -#include "flutter/display_list/dl_builder.h" +#include "flutter/display_list/dl_canvas.h" #include "line_metrics.h" #include "paragraph_style.h" #include "third_party/skia/include/core/SkRect.h" @@ -143,11 +143,9 @@ class Paragraph { // before Painting and getting any statistics from this class. virtual void Layout(double width) = 0; - // Paints the laid out text onto the supplied DisplayListBuilder at + // Paints the laid out text onto the supplied DlCanvas at // (x, y) offset from the origin. Only valid after Layout() is called. - virtual bool Paint(flutter::DisplayListBuilder* builder, - double x, - double y) = 0; + virtual bool Paint(flutter::DlCanvas* canvas, double x, double y) = 0; // Returns a vector of bounding boxes that enclose all text between start and // end glyph indexes, including start and excluding end.