Skip LayerTree::Preroll LayerTree::Paint & Swapbuffer when frame_damage is empty (flutter/engine#32351)

This commit is contained in:
linxuebin 2022-04-14 11:59:04 +08:00 committed by GitHub
parent 1c5491a601
commit 1dbe7a6cd5
4 changed files with 145 additions and 1 deletions

View File

@ -12,6 +12,7 @@ namespace flutter {
std::optional<SkRect> FrameDamage::ComputeClipRect(
flutter::LayerTree& layer_tree) {
TRACE_EVENT0("flutter", "FrameDamage::ComputeClipRect");
if (layer_tree.root_layer()) {
PaintRegionMap empty_paint_region_map;
DiffContext context(layer_tree.frame_size(),
@ -118,6 +119,10 @@ RasterStatus CompositorContext::ScopedFrame::Raster(
std::optional<SkRect> clip_rect =
frame_damage ? frame_damage->ComputeClipRect(layer_tree) : std::nullopt;
if (frame_damage && frame_damage->GetFrameDamage() &&
frame_damage->GetFrameDamage()->isEmpty()) {
return RasterStatus::kDiscarded;
}
bool root_needs_readback = layer_tree.Preroll(
*this, ignore_raster_cache, clip_rect ? *clip_rect : kGiantRect);
bool needs_save_layer = root_needs_readback && !surface_supports_readback();

View File

@ -287,6 +287,7 @@ if (enable_unittests) {
"//flutter/shell/profiling:profiling_unittests",
"//flutter/shell/version",
"//flutter/testing:fixture_test",
"//flutter/testing:skia",
"//third_party/googletest:gmock",
]

View File

@ -601,7 +601,8 @@ RasterStatus Rasterizer::DrawToSurfaceUnsafe(
damage.get() // frame damage
);
if (raster_status == RasterStatus::kFailed ||
raster_status == RasterStatus::kSkipAndRetry) {
raster_status == RasterStatus::kSkipAndRetry ||
raster_status == RasterStatus::kDiscarded) {
return raster_status;
}

View File

@ -13,6 +13,9 @@
#include "flutter/shell/common/thread_host.h"
#include "flutter/testing/testing.h"
#include "flow/layers/container_layer.h"
#include "flow/layers/physical_shape_layer.h"
#include "flutter/testing/mock_canvas.h"
#include "gmock/gmock.h"
using testing::_;
@ -726,4 +729,138 @@ TEST(
latch.Wait();
}
TEST(RasterizerTest, drawWithFrameDamageIsEmpty) {
std::string test_name =
::testing::UnitTest::GetInstance()->current_test_info()->name();
ThreadHost thread_host("io.flutter.test." + test_name + ".",
ThreadHost::Type::Platform | ThreadHost::Type::RASTER |
ThreadHost::Type::IO | ThreadHost::Type::UI);
TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
fml::AutoResetWaitableEvent latch;
thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
CompositorContext compositor_context;
flutter::testing::MockCanvas canvas;
auto compositor_frame = compositor_context.AcquireFrame(
nullptr, &canvas, nullptr, SkMatrix(), false, true, nullptr, nullptr);
auto last_layer_tree =
std::make_unique<LayerTree>(/*frame_size=*/SkISize::Make(100, 100),
/*device_pixel_ratio=*/2.0f);
// Use container as the root layer and PhysicalShapeLayer as the child
// layer. Frame size is 100 x 100 PhysicalShapeLayer's size is 50 x 50 The
// frame_damage is 50,50 in the first frame, and the frame_damage is empty
// in the second frame
auto last_root_layer = std::make_shared<ContainerLayer>();
auto last_child = std::make_shared<PhysicalShapeLayer>(
SK_ColorBLACK, SK_ColorBLACK,
0.0f, // elevation
SkPath::Rect(SkRect::MakeIWH(50, 50), SkPathDirection::kCCW, 0),
Clip::none);
last_root_layer.get()->Add(last_child);
last_layer_tree->set_root_layer(last_root_layer);
auto layer_tree = std::make_unique<LayerTree>(
/*frame_size=*/SkISize::Make(100, 100), /*device_pixel_ratio=*/2.0f);
auto cur_root_layer = std::make_shared<ContainerLayer>();
auto cur_child = std::make_shared<PhysicalShapeLayer>(
SK_ColorBLACK, SK_ColorBLACK,
0.0f, // elevation
SkPath::Rect(SkRect::MakeIWH(50, 50), SkPathDirection::kCCW, 0),
Clip::none);
cur_child.get()->AssignOldLayer(last_child.get());
cur_root_layer.get()->Add(cur_child);
layer_tree->set_root_layer(cur_root_layer);
// Draw Last Frame
std::unique_ptr<FrameDamage> last_damage = std::make_unique<FrameDamage>();
RasterStatus last_raster_status =
compositor_frame->Raster(*last_layer_tree.get(), // layer tree
false, // ignore raster cache
last_damage.get() // frame damage
);
EXPECT_EQ(last_raster_status, RasterStatus::kSuccess);
// Draw Current Frame
std::unique_ptr<FrameDamage> cur_damage = std::make_unique<FrameDamage>();
cur_damage->SetPreviousLayerTree(last_layer_tree.get());
cur_damage->AddAdditonalDamage(SkIRect());
RasterStatus cur_raster_status =
compositor_frame->Raster(*layer_tree.get(), // layer tree
false, // ignore raster cache
cur_damage.get() // frame damage
);
EXPECT_EQ(cur_raster_status, RasterStatus::kDiscarded);
latch.Signal();
});
latch.Wait();
}
TEST(RasterizerTest, drawWithFrameDamageIsNotEmpty) {
std::string test_name =
::testing::UnitTest::GetInstance()->current_test_info()->name();
ThreadHost thread_host("io.flutter.test." + test_name + ".",
ThreadHost::Type::Platform | ThreadHost::Type::RASTER |
ThreadHost::Type::IO | ThreadHost::Type::UI);
TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
fml::AutoResetWaitableEvent latch;
thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
CompositorContext compositor_context;
flutter::testing::MockCanvas canvas;
auto compositor_frame = compositor_context.AcquireFrame(
nullptr, &canvas, nullptr, SkMatrix(), false, true, nullptr, nullptr);
auto last_layer_tree =
std::make_unique<LayerTree>(/*frame_size=*/SkISize::Make(100, 100),
/*device_pixel_ratio=*/2.0f);
// Use container as the root layer and PhysicalShapeLayer as the child
// layer. Frame size is 100 x 100 PhysicalShapeLayer's size is 50 x 50 The
// frame_damage is 50,50 in the first frame, and the frame_damage is 50,50
// in the second frame
auto last_root_layer = std::make_shared<ContainerLayer>();
auto last_child = std::make_shared<PhysicalShapeLayer>(
SK_ColorBLACK, SK_ColorBLACK,
0.0f, // elevation
SkPath::Rect(SkRect::MakeIWH(50, 50), SkPathDirection::kCCW, 0),
Clip::none);
last_root_layer.get()->Add(last_child);
last_layer_tree->set_root_layer(last_root_layer);
auto layer_tree = std::make_unique<LayerTree>(
/*frame_size=*/SkISize::Make(100, 100), /*device_pixel_ratio=*/2.0f);
auto cur_root_layer = std::make_shared<ContainerLayer>();
auto cur_child = std::make_shared<PhysicalShapeLayer>(
SK_ColorBLACK, SK_ColorBLACK,
0.0f, // elevation
SkPath::Rect(SkRect::MakeIWH(50, 50), SkPathDirection::kCCW, 0),
Clip::none);
cur_root_layer.get()->Add(cur_child);
layer_tree->set_root_layer(cur_root_layer);
// Draw Last Frame
std::unique_ptr<FrameDamage> last_damage = std::make_unique<FrameDamage>();
RasterStatus last_raster_status =
compositor_frame->Raster(*last_layer_tree.get(), // layer tree
false, // ignore raster cache
last_damage.get() // frame damage
);
EXPECT_EQ(last_raster_status, RasterStatus::kSuccess);
// Draw Current Frame
std::unique_ptr<FrameDamage> cur_damage = std::make_unique<FrameDamage>();
cur_damage->SetPreviousLayerTree(last_layer_tree.get());
RasterStatus cur_raster_status =
compositor_frame->Raster(*layer_tree.get(), // layer tree
false, // ignore raster cache
cur_damage.get() // frame damage
);
EXPECT_EQ(cur_raster_status, RasterStatus::kSuccess);
latch.Signal();
});
latch.Wait();
}
} // namespace flutter