Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ vars = {
# Dart is: https://github.com/dart-lang/sdk/blob/master/DEPS.
# You can use //tools/dart/create_updated_flutter_deps.py to produce
# updated revision list of existing dependencies.
'dart_revision': 'ecf9ce8ef42de11033801b2870e8b310c3722902',
'dart_revision': '7c148d029de32590a8d0d332bf807d25929f080e',

# WARNING: DO NOT EDIT MANUALLY
# The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py
Expand Down
1 change: 1 addition & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,7 @@ FILE: ../../../flutter/shell/common/pointer_data_dispatcher.cc
FILE: ../../../flutter/shell/common/pointer_data_dispatcher.h
FILE: ../../../flutter/shell/common/rasterizer.cc
FILE: ../../../flutter/shell/common/rasterizer.h
FILE: ../../../flutter/shell/common/rasterizer_unittests.cc
FILE: ../../../flutter/shell/common/run_configuration.cc
FILE: ../../../flutter/shell/common/run_configuration.h
FILE: ../../../flutter/shell/common/serialization_callbacks.cc
Expand Down
1 change: 1 addition & 0 deletions shell/common/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ if (enable_unittests) {
"input_events_unittests.cc",
"persistent_cache_unittests.cc",
"pipeline_unittests.cc",
"rasterizer_unittests.cc",
"shell_unittests.cc",
"skp_shader_warmup_unittests.cc",
]
Expand Down
6 changes: 3 additions & 3 deletions shell/common/rasterizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,7 @@ void Rasterizer::Draw(fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline) {
consume_result = PipelineConsumeResult::MoreAvailable;
}

// Merging the thread as we know the next `Draw` should be run on the platform
// thread.
// EndFrame should perform cleanups for the external_view_embedder.
if (surface_ != nullptr && surface_->GetExternalViewEmbedder() != nullptr) {
surface_->GetExternalViewEmbedder()->EndFrame(should_resubmit_frame,
raster_thread_merger_);
Expand Down Expand Up @@ -464,7 +463,8 @@ RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) {
raster_status == RasterStatus::kSkipAndRetry) {
return raster_status;
}
if (external_view_embedder != nullptr) {
if (external_view_embedder != nullptr &&
(!raster_thread_merger_ || raster_thread_merger_->IsMerged())) {
FML_DCHECK(!frame->IsSubmitted());
external_view_embedder->SubmitFrame(surface_->GetContext(),
std::move(frame));
Expand Down
264 changes: 264 additions & 0 deletions shell/common/rasterizer_unittests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
// 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.

#define FML_USED_ON_EMBEDDER

#include "flutter/shell/common/rasterizer.h"

#include "flutter/shell/common/thread_host.h"
#include "flutter/testing/testing.h"
#include "gmock/gmock.h"

using testing::_;
using testing::ByMove;
using testing::Return;
using testing::ReturnRef;

namespace flutter {
namespace {
class MockDelegate : public Rasterizer::Delegate {
public:
MOCK_METHOD1(OnFrameRasterized, void(const FrameTiming& frame_timing));
MOCK_METHOD0(GetFrameBudget, fml::Milliseconds());
MOCK_CONST_METHOD0(GetLatestFrameTargetTime, fml::TimePoint());
MOCK_CONST_METHOD0(GetTaskRunners, const TaskRunners&());
MOCK_CONST_METHOD0(GetIsGpuDisabledSyncSwitch,
std::shared_ptr<fml::SyncSwitch>());
};

class MockSurface : public Surface {
public:
MOCK_METHOD0(IsValid, bool());
MOCK_METHOD1(AcquireFrame,
std::unique_ptr<SurfaceFrame>(const SkISize& size));
MOCK_CONST_METHOD0(GetRootTransformation, SkMatrix());
MOCK_METHOD0(GetContext, GrDirectContext*());
MOCK_METHOD0(GetExternalViewEmbedder, ExternalViewEmbedder*());
MOCK_METHOD0(MakeRenderContextCurrent, std::unique_ptr<GLContextResult>());
MOCK_METHOD0(ClearRenderContext, bool());
};

class MockExternalViewEmbedder : public ExternalViewEmbedder {
public:
MOCK_METHOD0(GetRootCanvas, SkCanvas*());
MOCK_METHOD0(CancelFrame, void());
MOCK_METHOD4(BeginFrame,
void(SkISize frame_size,
GrDirectContext* context,
double device_pixel_ratio,
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger));
MOCK_METHOD2(PrerollCompositeEmbeddedView,
void(int view_id, std::unique_ptr<EmbeddedViewParams> params));
MOCK_METHOD1(PostPrerollAction,
PostPrerollResult(
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger));
MOCK_METHOD0(GetCurrentCanvases, std::vector<SkCanvas*>());
MOCK_METHOD1(CompositeEmbeddedView, SkCanvas*(int view_id));
MOCK_METHOD2(SubmitFrame,
void(GrDirectContext* context,
std::unique_ptr<SurfaceFrame> frame));
MOCK_METHOD2(EndFrame,
void(bool should_resubmit_frame,
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger));
MOCK_METHOD0(SupportsDynamicThreadMerging, bool());
};
} // namespace

TEST(RasterizerTest, create) {
MockDelegate delegate;
auto rasterizer = std::make_unique<Rasterizer>(delegate);
EXPECT_TRUE(rasterizer != nullptr);
}

TEST(RasterizerTest, drawEmptyPipeline) {
std::string test_name =
::testing::UnitTest::GetInstance()->current_test_info()->name();
ThreadHost thread_host("io.flutter.test." + test_name + ".",
ThreadHost::Type::Platform | ThreadHost::Type::GPU |
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());
MockDelegate delegate;
ON_CALL(delegate, GetTaskRunners()).WillByDefault(ReturnRef(task_runners));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<MockSurface>();
rasterizer->Setup(std::move(surface));
fml::AutoResetWaitableEvent latch;
thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
auto pipeline = fml::AdoptRef(new Pipeline<LayerTree>(/*depth=*/10));
rasterizer->Draw(pipeline, nullptr);
latch.Signal();
});
latch.Wait();
}

TEST(RasterizerTest,
drawWithExternalViewEmbedderExternalViewEmbedderSubmitFrameCalled) {
std::string test_name =
::testing::UnitTest::GetInstance()->current_test_info()->name();
ThreadHost thread_host("io.flutter.test." + test_name + ".",
ThreadHost::Type::Platform | ThreadHost::Type::GPU |
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());
MockDelegate delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
EXPECT_CALL(delegate, OnFrameRasterized(_));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<MockSurface>();

MockExternalViewEmbedder external_view_embedder;
EXPECT_CALL(*surface, GetExternalViewEmbedder())
.WillRepeatedly(Return(&external_view_embedder));

auto surface_frame = std::make_unique<SurfaceFrame>(
/*surface=*/nullptr, /*supports_readback=*/true,
/*submit_callback=*/[](const SurfaceFrame&, SkCanvas*) { return true; });
EXPECT_CALL(*surface, AcquireFrame(SkISize()))
.WillOnce(Return(ByMove(std::move(surface_frame))));

EXPECT_CALL(external_view_embedder,
BeginFrame(/*frame_size=*/SkISize(), /*context=*/nullptr,
/*device_pixel_ratio=*/2.0,
/*raster_thread_merger=*/
fml::RefPtr<fml::RasterThreadMerger>(nullptr)))
.Times(1);
EXPECT_CALL(external_view_embedder, SubmitFrame).Times(1);
EXPECT_CALL(
external_view_embedder,
EndFrame(/*should_resubmit_frame=*/false,
/*raster_thread_merger=*/fml::RefPtr<fml::RasterThreadMerger>(
nullptr)))
.Times(1);

rasterizer->Setup(std::move(surface));
fml::AutoResetWaitableEvent latch;
thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
auto pipeline = fml::AdoptRef(new Pipeline<LayerTree>(/*depth=*/10));
auto layer_tree = std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
/*device_pixel_ratio=*/2.0f);
bool result = pipeline->Produce().Complete(std::move(layer_tree));
EXPECT_TRUE(result);
auto no_discard = [](LayerTree&) { return false; };
rasterizer->Draw(pipeline, no_discard);
latch.Signal();
});
latch.Wait();
}

TEST(
RasterizerTest,
drawWithExternalViewEmbedderAndThreadMergerNotMergedExternalViewEmbedderSubmitFrameNotCalled) {
std::string test_name =
::testing::UnitTest::GetInstance()->current_test_info()->name();
ThreadHost thread_host("io.flutter.test." + test_name + ".",
ThreadHost::Type::Platform | ThreadHost::Type::GPU |
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());
MockDelegate delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
EXPECT_CALL(delegate, OnFrameRasterized(_));
auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<MockSurface>();
MockExternalViewEmbedder external_view_embedder;
EXPECT_CALL(*surface, GetExternalViewEmbedder())
.WillRepeatedly(Return(&external_view_embedder));
EXPECT_CALL(external_view_embedder, SupportsDynamicThreadMerging)
.WillRepeatedly(Return(true));
auto surface_frame = std::make_unique<SurfaceFrame>(
/*surface=*/nullptr, /*supports_readback=*/true,
/*submit_callback=*/[](const SurfaceFrame&, SkCanvas*) { return true; });
EXPECT_CALL(*surface, AcquireFrame(SkISize()))
.WillOnce(Return(ByMove(std::move(surface_frame))));

EXPECT_CALL(external_view_embedder,
BeginFrame(/*frame_size=*/SkISize(), /*context=*/nullptr,
/*device_pixel_ratio=*/2.0,
/*raster_thread_merger=*/_))
.Times(1);
EXPECT_CALL(external_view_embedder, SubmitFrame).Times(0);
EXPECT_CALL(external_view_embedder, EndFrame(/*should_resubmit_frame=*/false,
/*raster_thread_merger=*/_))
.Times(1);

rasterizer->Setup(std::move(surface));
fml::AutoResetWaitableEvent latch;
thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
auto pipeline = fml::AdoptRef(new Pipeline<LayerTree>(/*depth=*/10));
auto layer_tree = std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
/*device_pixel_ratio=*/2.0f);
bool result = pipeline->Produce().Complete(std::move(layer_tree));
EXPECT_TRUE(result);
auto no_discard = [](LayerTree&) { return false; };
rasterizer->Draw(pipeline, no_discard);
latch.Signal();
});
latch.Wait();
}

TEST(
RasterizerTest,
drawWithExternalViewEmbedderAndThreadsMergedExternalViewEmbedderSubmitFrameCalled) {
std::string test_name =
::testing::UnitTest::GetInstance()->current_test_info()->name();
ThreadHost thread_host("io.flutter.test." + test_name + ".",
ThreadHost::Type::Platform | ThreadHost::Type::GPU |
ThreadHost::Type::IO | ThreadHost::Type::UI);
fml::MessageLoop::EnsureInitializedForCurrentThread();
TaskRunners task_runners("test",
fml::MessageLoop::GetCurrent().GetTaskRunner(),
fml::MessageLoop::GetCurrent().GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());

MockDelegate delegate;
EXPECT_CALL(delegate, GetTaskRunners())
.WillRepeatedly(ReturnRef(task_runners));
EXPECT_CALL(delegate, OnFrameRasterized(_));

auto rasterizer = std::make_unique<Rasterizer>(delegate);
auto surface = std::make_unique<MockSurface>();

MockExternalViewEmbedder external_view_embedder;
EXPECT_CALL(*surface, GetExternalViewEmbedder())
.WillRepeatedly(Return(&external_view_embedder));

auto surface_frame = std::make_unique<SurfaceFrame>(
/*surface=*/nullptr, /*supports_readback=*/true,
/*submit_callback=*/[](const SurfaceFrame&, SkCanvas*) { return true; });
EXPECT_CALL(*surface, AcquireFrame(SkISize()))
.WillOnce(Return(ByMove(std::move(surface_frame))));
EXPECT_CALL(external_view_embedder, SupportsDynamicThreadMerging)
.WillRepeatedly(Return(true));

EXPECT_CALL(external_view_embedder,
BeginFrame(/*frame_size=*/SkISize(), /*context=*/nullptr,
/*device_pixel_ratio=*/2.0,
/*raster_thread_merger=*/_))
.Times(1);
EXPECT_CALL(external_view_embedder, SubmitFrame).Times(1);
EXPECT_CALL(external_view_embedder, EndFrame(/*should_resubmit_frame=*/false,
/*raster_thread_merger=*/_))
.Times(1);

rasterizer->Setup(std::move(surface));

auto pipeline = fml::AdoptRef(new Pipeline<LayerTree>(/*depth=*/10));
auto layer_tree = std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
/*device_pixel_ratio=*/2.0f);
bool result = pipeline->Produce().Complete(std::move(layer_tree));
EXPECT_TRUE(result);
auto no_discard = [](LayerTree&) { return false; };
rasterizer->Draw(pipeline, no_discard);
}
} // namespace flutter
24 changes: 17 additions & 7 deletions shell/common/shell_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1052,20 +1052,25 @@ TEST_F(ShellTest,
auto settings = CreateSettingsForFixture();
fml::AutoResetWaitableEvent end_frame_latch;
std::shared_ptr<ShellTestExternalViewEmbedder> external_view_embedder;

fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger_ref;
auto end_frame_callback =
[&](bool should_resubmit_frame,
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
external_view_embedder->UpdatePostPrerollResult(
PostPrerollResult::kSuccess);
if (!raster_thread_merger_ref) {
raster_thread_merger_ref = raster_thread_merger;
}
if (should_resubmit_frame && !raster_thread_merger->IsMerged()) {
raster_thread_merger->MergeWithLease(10);
external_view_embedder->UpdatePostPrerollResult(
PostPrerollResult::kSuccess);
}
end_frame_latch.Signal();
};
external_view_embedder = std::make_shared<ShellTestExternalViewEmbedder>(
end_frame_callback, PostPrerollResult::kResubmitFrame, true);

auto shell = CreateShell(std::move(settings), GetTaskRunnersForFixture(),
false, external_view_embedder);

PlatformViewNotifyCreated(shell.get());

auto configuration = RunConfiguration::InferFromSettings(settings);
Expand All @@ -1075,13 +1080,18 @@ TEST_F(ShellTest,
ASSERT_EQ(0, external_view_embedder->GetSubmittedFrameCount());

PumpOneFrame(shell.get());
// `EndFrame` changed the post preroll result to `kSuccess`.
// `EndFrame` changed the post preroll result to `kSuccess` and merged the
// threads. During the frame, the threads are not merged, So no
// `external_view_embedder->GetSubmittedFrameCount()` is called.
end_frame_latch.Wait();
ASSERT_EQ(1, external_view_embedder->GetSubmittedFrameCount());
ASSERT_TRUE(raster_thread_merger_ref->IsMerged());
ASSERT_EQ(0, external_view_embedder->GetSubmittedFrameCount());

// This is the resubmitted frame, which threads are also merged.
end_frame_latch.Wait();
ASSERT_EQ(2, external_view_embedder->GetSubmittedFrameCount());
ASSERT_EQ(1, external_view_embedder->GetSubmittedFrameCount());

PlatformViewNotifyDestroyed(shell.get());
DestroyShell(std::move(shell));
}

Expand Down
Loading