mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] add basic culling checks during text frame dispatcher. (flutter/engine#55168)
Fixes https://github.com/flutter/flutter/issues/155133 Dl dispatching still relies on cull rects computed during that dispatch process. Make sure that the text frame dispatcher doesn't populate text frames that are way offscreen. This culling is more conservative than the rendering dispatcher. We'd need to do some refactoring so the logic isn't repeated multiple times.
This commit is contained in:
parent
d68ee6e60e
commit
dd7948b2fe
@ -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(
|
||||
|
||||
@ -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<flutter::DisplayList> 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<Texture> DisplayListToTexture(
|
||||
const sk_sp<flutter::DisplayList>& display_list,
|
||||
ISize size,
|
||||
@ -1553,8 +1610,8 @@ std::shared_ptr<Texture> 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,
|
||||
|
||||
@ -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<Matrix> stack_;
|
||||
// note: cull rects are always in the global coordinate space.
|
||||
std::vector<Rect> cull_rect_state_;
|
||||
bool has_image_filter_ = false;
|
||||
Paint paint_;
|
||||
};
|
||||
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -73,8 +73,11 @@ sk_sp<DlImage> 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,
|
||||
|
||||
@ -120,8 +120,9 @@ std::unique_ptr<SurfaceFrame> 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(
|
||||
|
||||
@ -171,8 +171,10 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromCAMetalLa
|
||||
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 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromMTLTextur
|
||||
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(
|
||||
|
||||
@ -81,8 +81,9 @@ std::unique_ptr<SurfaceFrame> 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(
|
||||
|
||||
@ -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(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user