diff --git a/impeller/aiks/aiks_playground.cc b/impeller/aiks/aiks_playground.cc index 882e0d66a99c2..6ad968a27646f 100644 --- a/impeller/aiks/aiks_playground.cc +++ b/impeller/aiks/aiks_playground.cc @@ -90,7 +90,10 @@ bool AiksPlayground::OpenPlaygroundHere( [&renderer, &callback](RenderTarget& render_target) -> bool { #if EXPERIMENTAL_CANVAS auto display_list = callback(); - TextFrameDispatcher collector(renderer.GetContentContext(), Matrix()); + TextFrameDispatcher collector(renderer.GetContentContext(), // + Matrix(), // + Rect::MakeMaximum() // + ); display_list->Dispatch(collector); ExperimentalDlDispatcher impeller_dispatcher( diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index d58a6339aafac..2e1870da19376 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -1368,22 +1368,46 @@ Canvas& ExperimentalDlDispatcher::GetCanvas() { //// Text Frame Dispatcher TextFrameDispatcher::TextFrameDispatcher(const ContentContext& renderer, - const Matrix& initial_matrix) - : renderer_(renderer), matrix_(initial_matrix) {} + const Matrix& initial_matrix, + const Rect cull_rect) + : renderer_(renderer), matrix_(initial_matrix) { + cull_rect_state_.push_back(cull_rect); +} + +TextFrameDispatcher::~TextFrameDispatcher() { + FML_DCHECK(cull_rect_state_.size() == 1); +} void TextFrameDispatcher::save() { stack_.emplace_back(matrix_); + cull_rect_state_.push_back(cull_rect_state_.back()); } void TextFrameDispatcher::saveLayer(const DlRect& bounds, const flutter::SaveLayerOptions options, const flutter::DlImageFilter* backdrop) { save(); + + // This dispatcher does not track enough state to accurately compute + // cull rects with image filters. + auto global_cull_rect = cull_rect_state_.back(); + if (has_image_filter_ || global_cull_rect.IsMaximum()) { + cull_rect_state_.back() = Rect::MakeMaximum(); + } else { + auto global_save_bounds = bounds.TransformBounds(matrix_); + auto new_cull_rect = global_cull_rect.Intersection(global_save_bounds); + if (new_cull_rect.has_value()) { + cull_rect_state_.back() = new_cull_rect.value(); + } else { + cull_rect_state_.back() = Rect::MakeLTRB(0, 0, 0, 0); + } + } } void TextFrameDispatcher::restore() { matrix_ = stack_.back(); stack_.pop_back(); + cull_rect_state_.pop_back(); } void TextFrameDispatcher::translate(DlScalar tx, DlScalar ty) { @@ -1459,6 +1483,15 @@ void TextFrameDispatcher::drawTextFrame( ); } +const Rect TextFrameDispatcher::GetCurrentLocalCullingBounds() const { + auto cull_rect = cull_rect_state_.back(); + if (!cull_rect.IsEmpty() && !cull_rect.IsMaximum()) { + Matrix inverse = matrix_.Invert(); + cull_rect = cull_rect.TransformBounds(inverse); + } + return cull_rect; +} + void TextFrameDispatcher::drawDisplayList( const sk_sp display_list, DlScalar opacity) { @@ -1466,9 +1499,24 @@ void TextFrameDispatcher::drawDisplayList( save(); Paint old_paint = paint_; paint_ = Paint{}; - display_list->Dispatch(*this); + bool old_has_image_filter = has_image_filter_; + has_image_filter_ = false; + + Rect local_cull_bounds = GetCurrentLocalCullingBounds(); + if (local_cull_bounds.IsMaximum()) { + display_list->Dispatch(*this); + } else if (!local_cull_bounds.IsEmpty()) { + IRect cull_rect = IRect::RoundOut(local_cull_bounds); + display_list->Dispatch(*this, SkIRect::MakeLTRB(cull_rect.GetLeft(), // + cull_rect.GetTop(), // + cull_rect.GetRight(), // + cull_rect.GetBottom() // + )); + } + restore(); paint_ = old_paint; + has_image_filter_ = old_has_image_filter; FML_DCHECK(stack_depth == stack_.size()); } @@ -1522,6 +1570,15 @@ void TextFrameDispatcher::setStrokeJoin(flutter::DlStrokeJoin join) { } } +// |flutter::DlOpReceiver| +void TextFrameDispatcher::setImageFilter(const flutter::DlImageFilter* filter) { + if (filter == nullptr) { + has_image_filter_ = false; + } else { + has_image_filter_ = true; + } +} + std::shared_ptr DisplayListToTexture( const sk_sp& display_list, ISize size, @@ -1553,8 +1610,8 @@ std::shared_ptr DisplayListToTexture( } SkIRect sk_cull_rect = SkIRect::MakeWH(size.width, size.height); - impeller::TextFrameDispatcher collector(context.GetContentContext(), - impeller::Matrix()); + impeller::TextFrameDispatcher collector( + context.GetContentContext(), impeller::Matrix(), Rect::MakeSize(size)); display_list->Dispatch(collector, sk_cull_rect); impeller::ExperimentalDlDispatcher impeller_dispatcher( context.GetContentContext(), target, diff --git a/impeller/display_list/dl_dispatcher.h b/impeller/display_list/dl_dispatcher.h index 55694fd61aa1f..61f8efd5a9dca 100644 --- a/impeller/display_list/dl_dispatcher.h +++ b/impeller/display_list/dl_dispatcher.h @@ -14,6 +14,8 @@ #include "impeller/aiks/experimental_canvas.h" #include "impeller/aiks/paint.h" #include "impeller/entity/contents/content_context.h" +#include "impeller/geometry/color.h" +#include "impeller/geometry/rect.h" namespace impeller { @@ -330,7 +332,11 @@ class TextFrameDispatcher : public flutter::IgnoreAttributeDispatchHelper, public flutter::IgnoreDrawDispatchHelper { public: TextFrameDispatcher(const ContentContext& renderer, - const Matrix& initial_matrix); + const Matrix& initial_matrix, + const Rect cull_rect); + + ~TextFrameDispatcher(); + void save() override; void saveLayer(const DlRect& bounds, @@ -386,10 +392,18 @@ class TextFrameDispatcher : public flutter::IgnoreAttributeDispatchHelper, // |flutter::DlOpReceiver| void setStrokeJoin(flutter::DlStrokeJoin join) override; + // |flutter::DlOpReceiver| + void setImageFilter(const flutter::DlImageFilter* filter) override; + private: + const Rect GetCurrentLocalCullingBounds() const; + const ContentContext& renderer_; Matrix matrix_; std::vector stack_; + // note: cull rects are always in the global coordinate space. + std::vector cull_rect_state_; + bool has_image_filter_ = false; Paint paint_; }; diff --git a/impeller/display_list/dl_playground.cc b/impeller/display_list/dl_playground.cc index cf74a095465cd..ee3ee438028ce 100644 --- a/impeller/display_list/dl_playground.cc +++ b/impeller/display_list/dl_playground.cc @@ -49,7 +49,10 @@ bool DlPlayground::OpenPlaygroundHere(DisplayListPlaygroundCallback callback) { auto list = callback(); #if EXPERIMENTAL_CANVAS - TextFrameDispatcher collector(context.GetContentContext(), Matrix()); + TextFrameDispatcher collector(context.GetContentContext(), // + Matrix(), // + Rect::MakeMaximum() // + ); list->Dispatch(collector); ExperimentalDlDispatcher impeller_dispatcher( diff --git a/impeller/toolkit/interop/surface.cc b/impeller/toolkit/interop/surface.cc index 20a2f4c4188a4..d37fad66407f3 100644 --- a/impeller/toolkit/interop/surface.cc +++ b/impeller/toolkit/interop/surface.cc @@ -61,7 +61,8 @@ bool Surface::DrawDisplayList(const DisplayList& dl) const { const auto cull_rect = IRect::MakeSize(surface_->GetSize()); auto skia_cull_rect = SkIRect::MakeWH(cull_rect.GetWidth(), cull_rect.GetHeight()); - impeller::TextFrameDispatcher collector(content_context, impeller::Matrix{}); + impeller::TextFrameDispatcher collector(content_context, impeller::Matrix{}, + Rect::MakeSize(surface_->GetSize())); display_list->Dispatch(collector, skia_cull_rect); impeller::ExperimentalDlDispatcher impeller_dispatcher( diff --git a/shell/common/snapshot_controller_impeller.cc b/shell/common/snapshot_controller_impeller.cc index 2b06c04e4d113..89583f9eafcc0 100644 --- a/shell/common/snapshot_controller_impeller.cc +++ b/shell/common/snapshot_controller_impeller.cc @@ -73,8 +73,11 @@ sk_sp DoMakeRasterSnapshot( ); } - impeller::TextFrameDispatcher collector(context->GetContentContext(), - impeller::Matrix()); + impeller::TextFrameDispatcher collector( + context->GetContentContext(), // + impeller::Matrix(), // + impeller::Rect::MakeSize(render_target_size) // + ); display_list->Dispatch(collector, SkIRect::MakeSize(size)); impeller::ExperimentalDlDispatcher impeller_dispatcher( context->GetContentContext(), target, diff --git a/shell/gpu/gpu_surface_gl_impeller.cc b/shell/gpu/gpu_surface_gl_impeller.cc index cc4d74b3cfbad..7542d040fb946 100644 --- a/shell/gpu/gpu_surface_gl_impeller.cc +++ b/shell/gpu/gpu_surface_gl_impeller.cc @@ -120,8 +120,9 @@ std::unique_ptr GPUSurfaceGLImpeller::AcquireFrame( #if EXPERIMENTAL_CANVAS auto skia_cull_rect = SkIRect::MakeWH(cull_rect.width, cull_rect.height); - impeller::TextFrameDispatcher collector(aiks_context->GetContentContext(), - impeller::Matrix()); + impeller::TextFrameDispatcher collector( + aiks_context->GetContentContext(), impeller::Matrix(), + impeller::Rect::MakeSize(cull_rect)); display_list->Dispatch(collector, skia_cull_rect); impeller::ExperimentalDlDispatcher impeller_dispatcher( diff --git a/shell/gpu/gpu_surface_metal_impeller.mm b/shell/gpu/gpu_surface_metal_impeller.mm index 6e8c43763e092..a842e50a7ebc8 100644 --- a/shell/gpu/gpu_surface_metal_impeller.mm +++ b/shell/gpu/gpu_surface_metal_impeller.mm @@ -171,8 +171,10 @@ surface->SetFrameBoundary(surface_frame.submit_info().frame_boundary); #if EXPERIMENTAL_CANVAS - impeller::TextFrameDispatcher collector(aiks_context->GetContentContext(), - impeller::Matrix()); + impeller::TextFrameDispatcher collector(aiks_context->GetContentContext(), // + impeller::Matrix(), // + impeller::Rect::MakeSize(cull_rect.GetSize()) // + ); display_list->Dispatch(collector, sk_cull_rect); impeller::ExperimentalDlDispatcher impeller_dispatcher( @@ -299,8 +301,10 @@ impeller::IRect cull_rect = surface->coverage(); SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.GetWidth(), cull_rect.GetHeight()); #if EXPERIMENTAL_CANVAS - impeller::TextFrameDispatcher collector(aiks_context->GetContentContext(), - impeller::Matrix()); + impeller::TextFrameDispatcher collector(aiks_context->GetContentContext(), // + impeller::Matrix(), // + impeller::Rect::MakeSize(cull_rect.GetSize()) // + ); display_list->Dispatch(collector, sk_cull_rect); impeller::RenderTarget render_target = surface->GetTargetRenderPassDescriptor(); impeller::ExperimentalDlDispatcher impeller_dispatcher( diff --git a/shell/gpu/gpu_surface_vulkan_impeller.cc b/shell/gpu/gpu_surface_vulkan_impeller.cc index 263c3db64bf7b..d04937edc6b81 100644 --- a/shell/gpu/gpu_surface_vulkan_impeller.cc +++ b/shell/gpu/gpu_surface_vulkan_impeller.cc @@ -81,8 +81,9 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( } #if EXPERIMENTAL_CANVAS - impeller::TextFrameDispatcher collector(aiks_context->GetContentContext(), - impeller::Matrix()); + impeller::TextFrameDispatcher collector( + aiks_context->GetContentContext(), impeller::Matrix(), + impeller::Rect::MakeSize(cull_rect)); display_list->Dispatch(collector, SkIRect::MakeWH(cull_rect.width, cull_rect.height)); impeller::ExperimentalDlDispatcher impeller_dispatcher( diff --git a/shell/platform/embedder/embedder_external_view.cc b/shell/platform/embedder/embedder_external_view.cc index 1111e8a7a8375..9019a417f09e5 100644 --- a/shell/platform/embedder/embedder_external_view.cc +++ b/shell/platform/embedder/embedder_external_view.cc @@ -134,9 +134,11 @@ bool EmbedderExternalView::Render(const EmbedderRenderTarget& render_target, impeller::IRect::MakeSize(impeller_target->GetRenderTargetSize()); SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.GetWidth(), cull_rect.GetHeight()); - - impeller::TextFrameDispatcher collector(aiks_context->GetContentContext(), - impeller::Matrix()); + impeller::TextFrameDispatcher collector( + aiks_context->GetContentContext(), // + impeller::Matrix(), // + impeller::Rect::MakeSize(cull_rect.GetSize()) // + ); display_list->Dispatch(collector, sk_cull_rect); impeller::ExperimentalDlDispatcher impeller_dispatcher(