Skip to content

Commit 5b81baa

Browse files
Skip LayerTree::Preroll LayerTree::Paint & Swapbuffer when frame_damage is empty (flutter#32351)
1 parent 9688057 commit 5b81baa

File tree

4 files changed

+145
-1
lines changed

4 files changed

+145
-1
lines changed

flow/compositor_context.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace flutter {
1212

1313
std::optional<SkRect> FrameDamage::ComputeClipRect(
1414
flutter::LayerTree& layer_tree) {
15+
TRACE_EVENT0("flutter", "FrameDamage::ComputeClipRect");
1516
if (layer_tree.root_layer()) {
1617
PaintRegionMap empty_paint_region_map;
1718
DiffContext context(layer_tree.frame_size(),
@@ -118,6 +119,10 @@ RasterStatus CompositorContext::ScopedFrame::Raster(
118119
std::optional<SkRect> clip_rect =
119120
frame_damage ? frame_damage->ComputeClipRect(layer_tree) : std::nullopt;
120121

122+
if (frame_damage && frame_damage->GetFrameDamage() &&
123+
frame_damage->GetFrameDamage()->isEmpty()) {
124+
return RasterStatus::kDiscarded;
125+
}
121126
bool root_needs_readback = layer_tree.Preroll(
122127
*this, ignore_raster_cache, clip_rect ? *clip_rect : kGiantRect);
123128
bool needs_save_layer = root_needs_readback && !surface_supports_readback();

shell/common/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ if (enable_unittests) {
287287
"//flutter/shell/profiling:profiling_unittests",
288288
"//flutter/shell/version",
289289
"//flutter/testing:fixture_test",
290+
"//flutter/testing:skia",
290291
"//third_party/googletest:gmock",
291292
]
292293

shell/common/rasterizer.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,8 @@ RasterStatus Rasterizer::DrawToSurfaceUnsafe(
601601
damage.get() // frame damage
602602
);
603603
if (raster_status == RasterStatus::kFailed ||
604-
raster_status == RasterStatus::kSkipAndRetry) {
604+
raster_status == RasterStatus::kSkipAndRetry ||
605+
raster_status == RasterStatus::kDiscarded) {
605606
return raster_status;
606607
}
607608

shell/common/rasterizer_unittests.cc

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
#include "flutter/shell/common/thread_host.h"
1414
#include "flutter/testing/testing.h"
1515

16+
#include "flow/layers/container_layer.h"
17+
#include "flow/layers/physical_shape_layer.h"
18+
#include "flutter/testing/mock_canvas.h"
1619
#include "gmock/gmock.h"
1720

1821
using testing::_;
@@ -726,4 +729,138 @@ TEST(
726729
latch.Wait();
727730
}
728731

732+
TEST(RasterizerTest, drawWithFrameDamageIsEmpty) {
733+
std::string test_name =
734+
::testing::UnitTest::GetInstance()->current_test_info()->name();
735+
ThreadHost thread_host("io.flutter.test." + test_name + ".",
736+
ThreadHost::Type::Platform | ThreadHost::Type::RASTER |
737+
ThreadHost::Type::IO | ThreadHost::Type::UI);
738+
TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
739+
thread_host.raster_thread->GetTaskRunner(),
740+
thread_host.ui_thread->GetTaskRunner(),
741+
thread_host.io_thread->GetTaskRunner());
742+
fml::AutoResetWaitableEvent latch;
743+
thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
744+
CompositorContext compositor_context;
745+
flutter::testing::MockCanvas canvas;
746+
auto compositor_frame = compositor_context.AcquireFrame(
747+
nullptr, &canvas, nullptr, SkMatrix(), false, true, nullptr, nullptr);
748+
auto last_layer_tree =
749+
std::make_unique<LayerTree>(/*frame_size=*/SkISize::Make(100, 100),
750+
/*device_pixel_ratio=*/2.0f);
751+
// Use container as the root layer and PhysicalShapeLayer as the child
752+
// layer. Frame size is 100 x 100 PhysicalShapeLayer's size is 50 x 50 The
753+
// frame_damage is 50,50 in the first frame, and the frame_damage is empty
754+
// in the second frame
755+
auto last_root_layer = std::make_shared<ContainerLayer>();
756+
auto last_child = std::make_shared<PhysicalShapeLayer>(
757+
SK_ColorBLACK, SK_ColorBLACK,
758+
0.0f, // elevation
759+
SkPath::Rect(SkRect::MakeIWH(50, 50), SkPathDirection::kCCW, 0),
760+
Clip::none);
761+
last_root_layer.get()->Add(last_child);
762+
last_layer_tree->set_root_layer(last_root_layer);
763+
764+
auto layer_tree = std::make_unique<LayerTree>(
765+
/*frame_size=*/SkISize::Make(100, 100), /*device_pixel_ratio=*/2.0f);
766+
auto cur_root_layer = std::make_shared<ContainerLayer>();
767+
auto cur_child = std::make_shared<PhysicalShapeLayer>(
768+
SK_ColorBLACK, SK_ColorBLACK,
769+
0.0f, // elevation
770+
SkPath::Rect(SkRect::MakeIWH(50, 50), SkPathDirection::kCCW, 0),
771+
Clip::none);
772+
cur_child.get()->AssignOldLayer(last_child.get());
773+
cur_root_layer.get()->Add(cur_child);
774+
layer_tree->set_root_layer(cur_root_layer);
775+
776+
// Draw Last Frame
777+
std::unique_ptr<FrameDamage> last_damage = std::make_unique<FrameDamage>();
778+
RasterStatus last_raster_status =
779+
compositor_frame->Raster(*last_layer_tree.get(), // layer tree
780+
false, // ignore raster cache
781+
last_damage.get() // frame damage
782+
);
783+
EXPECT_EQ(last_raster_status, RasterStatus::kSuccess);
784+
785+
// Draw Current Frame
786+
std::unique_ptr<FrameDamage> cur_damage = std::make_unique<FrameDamage>();
787+
cur_damage->SetPreviousLayerTree(last_layer_tree.get());
788+
cur_damage->AddAdditonalDamage(SkIRect());
789+
RasterStatus cur_raster_status =
790+
compositor_frame->Raster(*layer_tree.get(), // layer tree
791+
false, // ignore raster cache
792+
cur_damage.get() // frame damage
793+
);
794+
EXPECT_EQ(cur_raster_status, RasterStatus::kDiscarded);
795+
latch.Signal();
796+
});
797+
latch.Wait();
798+
}
799+
800+
TEST(RasterizerTest, drawWithFrameDamageIsNotEmpty) {
801+
std::string test_name =
802+
::testing::UnitTest::GetInstance()->current_test_info()->name();
803+
ThreadHost thread_host("io.flutter.test." + test_name + ".",
804+
ThreadHost::Type::Platform | ThreadHost::Type::RASTER |
805+
ThreadHost::Type::IO | ThreadHost::Type::UI);
806+
TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
807+
thread_host.raster_thread->GetTaskRunner(),
808+
thread_host.ui_thread->GetTaskRunner(),
809+
thread_host.io_thread->GetTaskRunner());
810+
fml::AutoResetWaitableEvent latch;
811+
thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
812+
CompositorContext compositor_context;
813+
flutter::testing::MockCanvas canvas;
814+
auto compositor_frame = compositor_context.AcquireFrame(
815+
nullptr, &canvas, nullptr, SkMatrix(), false, true, nullptr, nullptr);
816+
auto last_layer_tree =
817+
std::make_unique<LayerTree>(/*frame_size=*/SkISize::Make(100, 100),
818+
/*device_pixel_ratio=*/2.0f);
819+
// Use container as the root layer and PhysicalShapeLayer as the child
820+
// layer. Frame size is 100 x 100 PhysicalShapeLayer's size is 50 x 50 The
821+
// frame_damage is 50,50 in the first frame, and the frame_damage is 50,50
822+
// in the second frame
823+
auto last_root_layer = std::make_shared<ContainerLayer>();
824+
auto last_child = std::make_shared<PhysicalShapeLayer>(
825+
SK_ColorBLACK, SK_ColorBLACK,
826+
0.0f, // elevation
827+
SkPath::Rect(SkRect::MakeIWH(50, 50), SkPathDirection::kCCW, 0),
828+
Clip::none);
829+
last_root_layer.get()->Add(last_child);
830+
last_layer_tree->set_root_layer(last_root_layer);
831+
832+
auto layer_tree = std::make_unique<LayerTree>(
833+
/*frame_size=*/SkISize::Make(100, 100), /*device_pixel_ratio=*/2.0f);
834+
auto cur_root_layer = std::make_shared<ContainerLayer>();
835+
auto cur_child = std::make_shared<PhysicalShapeLayer>(
836+
SK_ColorBLACK, SK_ColorBLACK,
837+
0.0f, // elevation
838+
SkPath::Rect(SkRect::MakeIWH(50, 50), SkPathDirection::kCCW, 0),
839+
Clip::none);
840+
cur_root_layer.get()->Add(cur_child);
841+
layer_tree->set_root_layer(cur_root_layer);
842+
843+
// Draw Last Frame
844+
std::unique_ptr<FrameDamage> last_damage = std::make_unique<FrameDamage>();
845+
RasterStatus last_raster_status =
846+
compositor_frame->Raster(*last_layer_tree.get(), // layer tree
847+
false, // ignore raster cache
848+
last_damage.get() // frame damage
849+
);
850+
EXPECT_EQ(last_raster_status, RasterStatus::kSuccess);
851+
852+
// Draw Current Frame
853+
std::unique_ptr<FrameDamage> cur_damage = std::make_unique<FrameDamage>();
854+
cur_damage->SetPreviousLayerTree(last_layer_tree.get());
855+
RasterStatus cur_raster_status =
856+
compositor_frame->Raster(*layer_tree.get(), // layer tree
857+
false, // ignore raster cache
858+
cur_damage.get() // frame damage
859+
);
860+
EXPECT_EQ(cur_raster_status, RasterStatus::kSuccess);
861+
latch.Signal();
862+
});
863+
latch.Wait();
864+
}
865+
729866
} // namespace flutter

0 commit comments

Comments
 (0)