mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
303 lines
13 KiB
C++
303 lines
13 KiB
C++
// 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_METHOD3(
|
|
SubmitFrame,
|
|
void(GrDirectContext* context,
|
|
std::unique_ptr<SurfaceFrame> frame,
|
|
const std::shared_ptr<fml::SyncSwitch>& gpu_disable_sync_switch));
|
|
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::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());
|
|
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::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());
|
|
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>();
|
|
|
|
std::shared_ptr<MockExternalViewEmbedder> external_view_embedder =
|
|
std::make_shared<MockExternalViewEmbedder>();
|
|
rasterizer->SetExternalViewEmbedder(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::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());
|
|
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>();
|
|
std::shared_ptr<MockExternalViewEmbedder> external_view_embedder =
|
|
std::make_shared<MockExternalViewEmbedder>();
|
|
rasterizer->SetExternalViewEmbedder(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::RASTER |
|
|
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>();
|
|
|
|
std::shared_ptr<MockExternalViewEmbedder> external_view_embedder =
|
|
std::make_shared<MockExternalViewEmbedder>();
|
|
rasterizer->SetExternalViewEmbedder(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);
|
|
}
|
|
|
|
TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNoSurfaceIsSet) {
|
|
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());
|
|
MockDelegate delegate;
|
|
EXPECT_CALL(delegate, GetTaskRunners())
|
|
.WillRepeatedly(ReturnRef(task_runners));
|
|
auto rasterizer = std::make_unique<Rasterizer>(delegate);
|
|
|
|
std::shared_ptr<MockExternalViewEmbedder> external_view_embedder =
|
|
std::make_shared<MockExternalViewEmbedder>();
|
|
rasterizer->SetExternalViewEmbedder(external_view_embedder);
|
|
|
|
EXPECT_CALL(
|
|
*external_view_embedder,
|
|
EndFrame(/*should_resubmit_frame=*/false,
|
|
/*raster_thread_merger=*/fml::RefPtr<fml::RasterThreadMerger>(
|
|
nullptr)))
|
|
.Times(0);
|
|
|
|
fml::AutoResetWaitableEvent latch;
|
|
thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
|
|
auto pipeline = fml::AdoptRef(new Pipeline<LayerTree>(/*depth=*/10));
|
|
auto no_discard = [](LayerTree&) { return false; };
|
|
rasterizer->Draw(pipeline, no_discard);
|
|
latch.Signal();
|
|
});
|
|
latch.Wait();
|
|
}
|
|
} // namespace flutter
|