Flutter Engine
 
Loading...
Searching...
No Matches
rasterizer_unittests.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#define FML_USED_ON_EMBEDDER
6
9
10#include <memory>
11#include <optional>
12
18
19#include "third_party/skia/include/core/SkColorSpace.h"
20#include "third_party/skia/include/core/SkSurface.h"
21#include "third_party/skia/include/gpu/ganesh/GrTypes.h"
22#include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h"
23
24#include "gmock/gmock.h"
25
26using testing::_;
27using testing::ByMove;
28using testing::NiceMock;
29using testing::Return;
30using testing::ReturnRef;
31
32namespace flutter {
33namespace {
34
35constexpr float kDevicePixelRatio = 2.0f;
36constexpr int64_t kImplicitViewId = 0;
37
38std::vector<std::unique_ptr<LayerTreeTask>> SingleLayerTreeList(
39 int64_t view_id,
40 std::unique_ptr<LayerTree> layer_tree,
41 float pixel_ratio) {
42 std::vector<std::unique_ptr<LayerTreeTask>> tasks;
43 tasks.push_back(std::make_unique<LayerTreeTask>(
44 view_id, std::move(layer_tree), pixel_ratio));
45 return tasks;
46}
47
48class MockDelegate : public Rasterizer::Delegate {
49 public:
50 MOCK_METHOD(void,
51 OnFrameRasterized,
52 (const FrameTiming& frame_timing),
53 (override));
54 MOCK_METHOD(fml::Milliseconds, GetFrameBudget, (), (override));
55 MOCK_METHOD(fml::TimePoint, GetLatestFrameTargetTime, (), (const, override));
56 MOCK_METHOD(const TaskRunners&, GetTaskRunners, (), (const, override));
58 GetParentRasterThreadMerger,
59 (),
60 (const, override));
61 MOCK_METHOD(std::shared_ptr<const fml::SyncSwitch>,
62 GetIsGpuDisabledSyncSwitch,
63 (),
64 (const, override));
65 MOCK_METHOD(const Settings&, GetSettings, (), (const, override));
66 MOCK_METHOD(bool,
67 ShouldDiscardLayerTree,
68 (int64_t, const flutter::LayerTree&),
69 (override));
70};
71
72class MockSurface : public Surface {
73 public:
74 MOCK_METHOD(bool, IsValid, (), (override));
75 MOCK_METHOD(std::unique_ptr<SurfaceFrame>,
76 AcquireFrame,
77 (const DlISize& size),
78 (override));
79 MOCK_METHOD(DlMatrix, GetRootTransformation, (), (const, override));
80 MOCK_METHOD(GrDirectContext*, GetContext, (), (override));
81 MOCK_METHOD(std::unique_ptr<GLContextResult>,
82 MakeRenderContextCurrent,
83 (),
84 (override));
85 MOCK_METHOD(bool, ClearRenderContext, (), (override));
86 MOCK_METHOD(bool, AllowsDrawingWhenGpuDisabled, (), (const, override));
87};
88
89class MockExternalViewEmbedder : public ExternalViewEmbedder {
90 public:
91 MOCK_METHOD(DlCanvas*, GetRootCanvas, (), (override));
92 MOCK_METHOD(void, CancelFrame, (), (override));
93 MOCK_METHOD(
94 void,
95 BeginFrame,
96 (GrDirectContext * context,
97 const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger),
98 (override));
99 MOCK_METHOD(void,
100 PrepareFlutterView,
101 (DlISize frame_size, double device_pixel_ratio),
102 (override));
103 MOCK_METHOD(void,
104 PrerollCompositeEmbeddedView,
105 (int64_t view_id, std::unique_ptr<EmbeddedViewParams> params),
106 (override));
107 MOCK_METHOD(
109 PostPrerollAction,
110 (const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger),
111 (override));
112 MOCK_METHOD(DlCanvas*, CompositeEmbeddedView, (int64_t view_id), (override));
113 MOCK_METHOD(void,
114 SubmitFlutterView,
115 (int64_t flutter_view_id,
116 GrDirectContext* context,
117 const std::shared_ptr<impeller::AiksContext>& aiks_context,
118 std::unique_ptr<SurfaceFrame> frame),
119 (override));
120 MOCK_METHOD(
121 void,
122 EndFrame,
123 (bool should_resubmit_frame,
124 const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger),
125 (override));
126 MOCK_METHOD(bool, SupportsDynamicThreadMerging, (), (override));
127};
128} // namespace
129
130TEST(RasterizerTest, create) {
131 NiceMock<MockDelegate> delegate;
132 Settings settings;
133 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
134 auto rasterizer = std::make_unique<Rasterizer>(delegate);
135 EXPECT_TRUE(rasterizer != nullptr);
136}
137
138TEST(RasterizerTest, isAiksContextInitialized) {
139 NiceMock<MockDelegate> delegate;
140 Settings settings;
141 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
142 auto rasterizer = std::make_shared<Rasterizer>(delegate);
143
144 EXPECT_TRUE(rasterizer != nullptr);
145 std::shared_ptr<SnapshotController::Delegate> snapshot_delegate = rasterizer;
146
147 EXPECT_FALSE(snapshot_delegate->IsAiksContextInitialized());
148}
149
150static std::unique_ptr<FrameTimingsRecorder> CreateFinishedBuildRecorder(
151 fml::TimePoint timestamp) {
152 std::unique_ptr<FrameTimingsRecorder> recorder =
153 std::make_unique<FrameTimingsRecorder>();
154 recorder->RecordVsync(timestamp, timestamp);
155 recorder->RecordBuildStart(timestamp);
156 recorder->RecordBuildEnd(timestamp);
157 return recorder;
158}
159
160static std::unique_ptr<FrameTimingsRecorder> CreateFinishedBuildRecorder() {
162}
163
164TEST(RasterizerTest, drawEmptyPipeline) {
165 std::string test_name =
166 ::testing::UnitTest::GetInstance()->current_test_info()->name();
167 ThreadHost thread_host("io.flutter.test." + test_name + ".",
171 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
172 thread_host.raster_thread->GetTaskRunner(),
173 thread_host.ui_thread->GetTaskRunner(),
174 thread_host.io_thread->GetTaskRunner());
175 NiceMock<MockDelegate> delegate;
176 Settings settings;
177 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
178 ON_CALL(delegate, GetTaskRunners()).WillByDefault(ReturnRef(task_runners));
179 auto rasterizer = std::make_unique<Rasterizer>(delegate);
180 auto surface = std::make_unique<NiceMock<MockSurface>>();
181 EXPECT_CALL(*surface, MakeRenderContextCurrent())
182 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
183 rasterizer->Setup(std::move(surface));
185 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
186 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
187 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
188 rasterizer->Draw(pipeline);
189 latch.Signal();
190 });
191 latch.Wait();
192}
193
194TEST(RasterizerTest,
195 drawWithExternalViewEmbedderExternalViewEmbedderSubmitFrameCalled) {
196 std::string test_name =
197 ::testing::UnitTest::GetInstance()->current_test_info()->name();
198 ThreadHost thread_host("io.flutter.test." + test_name + ".",
202 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
203 thread_host.raster_thread->GetTaskRunner(),
204 thread_host.ui_thread->GetTaskRunner(),
205 thread_host.io_thread->GetTaskRunner());
206 NiceMock<MockDelegate> delegate;
207 Settings settings;
208 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
209 EXPECT_CALL(delegate, GetTaskRunners())
210 .WillRepeatedly(ReturnRef(task_runners));
211 EXPECT_CALL(delegate, OnFrameRasterized(_));
212 auto rasterizer = std::make_unique<Rasterizer>(delegate);
213 auto surface = std::make_unique<NiceMock<MockSurface>>();
214
215 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
216 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
217 rasterizer->SetExternalViewEmbedder(external_view_embedder);
218
219 SurfaceFrame::FramebufferInfo framebuffer_info;
220 framebuffer_info.supports_readback = true;
221
222 auto surface_frame = std::make_unique<SurfaceFrame>(
223 /*surface=*/
224 nullptr, framebuffer_info,
225 /*encode_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
226 /*submit_callback=*/[](const SurfaceFrame&) { return true; },
227 /*frame_size=*/DlISize(800, 600));
228 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true));
229 EXPECT_CALL(*surface, AcquireFrame(DlISize()))
230 .WillOnce(Return(ByMove(std::move(surface_frame))));
231 EXPECT_CALL(*surface, MakeRenderContextCurrent())
232 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
233
234 EXPECT_CALL(*external_view_embedder,
235 BeginFrame(/*context=*/nullptr,
236 /*raster_thread_merger=*/
238 .Times(1);
239 EXPECT_CALL(*external_view_embedder, PrepareFlutterView(
240 /*frame_size=*/DlISize(),
241 /*device_pixel_ratio=*/2.0))
242 .Times(1);
243 EXPECT_CALL(*external_view_embedder,
244 SubmitFlutterView(/*flutter_view_id=*/kImplicitViewId, _, _, _))
245 .Times(1);
246 EXPECT_CALL(
247 *external_view_embedder,
248 EndFrame(/*should_resubmit_frame=*/false,
249 /*raster_thread_merger=*/fml::RefPtr<fml::RasterThreadMerger>(
250 nullptr)))
251 .Times(1);
252
253 rasterizer->Setup(std::move(surface));
255 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
256 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
257 auto layer_tree = std::make_unique<LayerTree>(/*root_layer=*/nullptr,
258 /*frame_size=*/DlISize());
259 auto layer_tree_item = std::make_unique<FrameItem>(
260 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
261 kDevicePixelRatio),
263 PipelineProduceResult result =
264 pipeline->Produce().Complete(std::move(layer_tree_item));
265 EXPECT_TRUE(result.success);
266 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
267 rasterizer->Draw(pipeline);
268 latch.Signal();
269 });
270 latch.Wait();
271}
272
274 RasterizerTest,
275 drawWithExternalViewEmbedderAndThreadMergerNotMergedExternalViewEmbedderSubmitFrameNotCalled) {
276 std::string test_name =
277 ::testing::UnitTest::GetInstance()->current_test_info()->name();
278 ThreadHost thread_host("io.flutter.test." + test_name + ".",
282 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
283 thread_host.raster_thread->GetTaskRunner(),
284 thread_host.ui_thread->GetTaskRunner(),
285 thread_host.io_thread->GetTaskRunner());
286 NiceMock<MockDelegate> delegate;
287 Settings settings;
288 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
289 EXPECT_CALL(delegate, GetTaskRunners())
290 .WillRepeatedly(ReturnRef(task_runners));
291 EXPECT_CALL(delegate, OnFrameRasterized(_));
292 auto rasterizer = std::make_unique<Rasterizer>(delegate);
293 auto surface = std::make_unique<NiceMock<MockSurface>>();
294 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
295 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
296 rasterizer->SetExternalViewEmbedder(external_view_embedder);
297 EXPECT_CALL(*external_view_embedder, SupportsDynamicThreadMerging)
298 .WillRepeatedly(Return(true));
299 SurfaceFrame::FramebufferInfo framebuffer_info;
300 framebuffer_info.supports_readback = true;
301 auto surface_frame = std::make_unique<SurfaceFrame>(
302 /*surface=*/
303 nullptr, framebuffer_info,
304 /*encode_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
305 /*submit_callback=*/[](const SurfaceFrame&) { return true; },
306 /*frame_size=*/DlISize(800, 600));
307 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true));
308 EXPECT_CALL(*surface, AcquireFrame(DlISize()))
309 .WillOnce(Return(ByMove(std::move(surface_frame))));
310 EXPECT_CALL(*surface, MakeRenderContextCurrent())
311 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
312
313 EXPECT_CALL(*external_view_embedder, BeginFrame(/*context=*/nullptr,
314 /*raster_thread_merger=*/_))
315 .Times(1);
316 EXPECT_CALL(*external_view_embedder, PrepareFlutterView(
317 /*frame_size=*/DlISize(),
318 /*device_pixel_ratio=*/2.0))
319 .Times(1);
320 EXPECT_CALL(*external_view_embedder,
321 SubmitFlutterView(/*flutter_view_id=*/kImplicitViewId, _, _, _))
322 .Times(0);
323 EXPECT_CALL(*external_view_embedder, EndFrame(/*should_resubmit_frame=*/false,
324 /*raster_thread_merger=*/_))
325 .Times(1);
326
327 rasterizer->Setup(std::move(surface));
329 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
330 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
331 auto layer_tree = std::make_unique<LayerTree>(
332 /*root_layer=*/nullptr, /*frame_size=*/DlISize());
333 auto layer_tree_item = std::make_unique<FrameItem>(
334 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
335 kDevicePixelRatio),
337 PipelineProduceResult result =
338 pipeline->Produce().Complete(std::move(layer_tree_item));
339 EXPECT_TRUE(result.success);
340 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
341 rasterizer->Draw(pipeline);
342 latch.Signal();
343 });
344 latch.Wait();
345}
346
348 RasterizerTest,
349 drawWithExternalViewEmbedderAndThreadsMergedExternalViewEmbedderSubmitFrameCalled) {
350 std::string test_name =
351 ::testing::UnitTest::GetInstance()->current_test_info()->name();
352 ThreadHost thread_host("io.flutter.test." + test_name + ".",
357 TaskRunners task_runners("test",
358 fml::MessageLoop::GetCurrent().GetTaskRunner(),
359 fml::MessageLoop::GetCurrent().GetTaskRunner(),
360 thread_host.ui_thread->GetTaskRunner(),
361 thread_host.io_thread->GetTaskRunner());
362
363 NiceMock<MockDelegate> delegate;
364 Settings settings;
365 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
366 EXPECT_CALL(delegate, GetTaskRunners())
367 .WillRepeatedly(ReturnRef(task_runners));
368 EXPECT_CALL(delegate, OnFrameRasterized(_));
369
370 auto rasterizer = std::make_unique<Rasterizer>(delegate);
371 auto surface = std::make_unique<NiceMock<MockSurface>>();
372
373 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
374 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
375 rasterizer->SetExternalViewEmbedder(external_view_embedder);
376
377 SurfaceFrame::FramebufferInfo framebuffer_info;
378 framebuffer_info.supports_readback = true;
379
380 auto surface_frame = std::make_unique<SurfaceFrame>(
381 /*surface=*/
382 nullptr, framebuffer_info,
383 /*encode_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
384 /*submit_callback=*/[](const SurfaceFrame&) { return true; },
385 /*frame_size=*/DlISize(800, 600));
386 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true));
387 EXPECT_CALL(*surface, AcquireFrame(DlISize()))
388 .WillOnce(Return(ByMove(std::move(surface_frame))));
389 EXPECT_CALL(*surface, MakeRenderContextCurrent())
390 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
391 EXPECT_CALL(*external_view_embedder, SupportsDynamicThreadMerging)
392 .WillRepeatedly(Return(true));
393
394 EXPECT_CALL(*external_view_embedder, BeginFrame(/*context=*/nullptr,
395 /*raster_thread_merger=*/_))
396 .Times(1);
397 EXPECT_CALL(*external_view_embedder, PrepareFlutterView(
398 /*frame_size=*/DlISize(),
399 /*device_pixel_ratio=*/2.0))
400 .Times(1);
401 EXPECT_CALL(*external_view_embedder,
402 SubmitFlutterView(/*flutter_view_id=*/kImplicitViewId, _, _, _))
403 .Times(1);
404 EXPECT_CALL(*external_view_embedder, EndFrame(/*should_resubmit_frame=*/false,
405 /*raster_thread_merger=*/_))
406 .Times(1);
407
408 rasterizer->Setup(std::move(surface));
409
410 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
411 auto layer_tree = std::make_unique<LayerTree>(/*root_layer=*/nullptr,
412 /*frame_size=*/DlISize());
413 auto layer_tree_item = std::make_unique<FrameItem>(
414 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
415 kDevicePixelRatio),
417 PipelineProduceResult result =
418 pipeline->Produce().Complete(std::move(layer_tree_item));
419 EXPECT_TRUE(result.success);
420 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
421 rasterizer->Draw(pipeline);
422}
423
424TEST(RasterizerTest,
425 drawLastLayerTreeWithThreadsMergedExternalViewEmbedderAndEndFrameCalled) {
426 std::string test_name =
427 ::testing::UnitTest::GetInstance()->current_test_info()->name();
428 ThreadHost thread_host("io.flutter.test." + test_name + ".",
433 TaskRunners task_runners("test",
434 fml::MessageLoop::GetCurrent().GetTaskRunner(),
435 fml::MessageLoop::GetCurrent().GetTaskRunner(),
436 thread_host.ui_thread->GetTaskRunner(),
437 thread_host.io_thread->GetTaskRunner());
438
439 NiceMock<MockDelegate> delegate;
440 Settings settings;
441 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
442 EXPECT_CALL(delegate, GetTaskRunners())
443 .WillRepeatedly(ReturnRef(task_runners));
444 EXPECT_CALL(delegate, OnFrameRasterized(_));
445
446 auto rasterizer = std::make_unique<Rasterizer>(delegate);
447 auto surface = std::make_unique<NiceMock<MockSurface>>();
448
449 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
450 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
451 rasterizer->SetExternalViewEmbedder(external_view_embedder);
452
453 SurfaceFrame::FramebufferInfo framebuffer_info;
454 framebuffer_info.supports_readback = true;
455
456 auto surface_frame1 = std::make_unique<SurfaceFrame>(
457 /*surface=*/
458 nullptr, framebuffer_info,
459 /*encode_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
460 /*submit_callback=*/[](const SurfaceFrame&) { return true; },
461 /*frame_size=*/DlISize(800, 600));
462 auto surface_frame2 = std::make_unique<SurfaceFrame>(
463 /*surface=*/
464 nullptr, framebuffer_info,
465 /*encode_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
466 /*submit_callback=*/[](const SurfaceFrame&) { return true; },
467 /*frame_size=*/DlISize(800, 600));
468 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled())
469 .WillRepeatedly(Return(true));
470 // Prepare two frames for Draw() and DrawLastLayerTrees().
471 EXPECT_CALL(*surface, AcquireFrame(DlISize()))
472 .WillOnce(Return(ByMove(std::move(surface_frame1))))
473 .WillOnce(Return(ByMove(std::move(surface_frame2))));
474 EXPECT_CALL(*surface, MakeRenderContextCurrent())
475 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
476 EXPECT_CALL(*external_view_embedder, SupportsDynamicThreadMerging)
477 .WillRepeatedly(Return(true));
478
479 EXPECT_CALL(*external_view_embedder, BeginFrame(/*context=*/nullptr,
480 /*raster_thread_merger=*/_))
481 .Times(2);
482 EXPECT_CALL(*external_view_embedder, PrepareFlutterView(
483 /*frame_size=*/DlISize(),
484 /*device_pixel_ratio=*/2.0))
485 .Times(2);
486 EXPECT_CALL(*external_view_embedder,
487 SubmitFlutterView(/*flutter_view_id=*/kImplicitViewId, _, _, _))
488 .Times(2);
489 EXPECT_CALL(*external_view_embedder, EndFrame(/*should_resubmit_frame=*/false,
490 /*raster_thread_merger=*/_))
491 .Times(2);
492
493 rasterizer->Setup(std::move(surface));
494
495 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
496 auto layer_tree = std::make_unique<LayerTree>(/*root_layer=*/nullptr,
497 /*frame_size=*/DlISize());
498 auto layer_tree_item = std::make_unique<FrameItem>(
499 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
500 kDevicePixelRatio),
502 PipelineProduceResult result =
503 pipeline->Produce().Complete(std::move(layer_tree_item));
504 EXPECT_TRUE(result.success);
505
506 // The Draw() will respectively call BeginFrame(), SubmitFlutterView() and
507 // EndFrame() one time.
508 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
509 rasterizer->Draw(pipeline);
510
511 // The DrawLastLayerTrees() will respectively call BeginFrame(),
512 // SubmitFlutterView() and EndFrame() one more time, totally 2 times.
513 rasterizer->DrawLastLayerTrees(CreateFinishedBuildRecorder());
514}
515
516TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNoSurfaceIsSet) {
517 std::string test_name =
518 ::testing::UnitTest::GetInstance()->current_test_info()->name();
519 ThreadHost thread_host("io.flutter.test." + test_name + ".",
523 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
524 thread_host.raster_thread->GetTaskRunner(),
525 thread_host.ui_thread->GetTaskRunner(),
526 thread_host.io_thread->GetTaskRunner());
527 NiceMock<MockDelegate> delegate;
528 Settings settings;
529 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
530 EXPECT_CALL(delegate, GetTaskRunners())
531 .WillRepeatedly(ReturnRef(task_runners));
532 auto rasterizer = std::make_unique<Rasterizer>(delegate);
533
534 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
535 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
536 rasterizer->SetExternalViewEmbedder(external_view_embedder);
537
538 EXPECT_CALL(
539 *external_view_embedder,
540 EndFrame(/*should_resubmit_frame=*/false,
541 /*raster_thread_merger=*/fml::RefPtr<fml::RasterThreadMerger>(
542 nullptr)))
543 .Times(0);
544
546 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
547 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
548 auto layer_tree = std::make_unique<LayerTree>(
549 /*root_layer=*/nullptr, /*frame_size=*/DlISize());
550 auto layer_tree_item = std::make_unique<FrameItem>(
551 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
552 kDevicePixelRatio),
554 PipelineProduceResult result =
555 pipeline->Produce().Complete(std::move(layer_tree_item));
556 EXPECT_TRUE(result.success);
557 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
558 rasterizer->Draw(pipeline);
559 latch.Signal();
560 });
561 latch.Wait();
562}
563
564TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNotUsedThisFrame) {
565 std::string test_name =
566 ::testing::UnitTest::GetInstance()->current_test_info()->name();
567 ThreadHost thread_host("io.flutter.test." + test_name + ".",
571 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
572 thread_host.raster_thread->GetTaskRunner(),
573 thread_host.ui_thread->GetTaskRunner(),
574 thread_host.io_thread->GetTaskRunner());
575 NiceMock<MockDelegate> delegate;
576 Settings settings;
577 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
578 EXPECT_CALL(delegate, GetTaskRunners())
579 .WillRepeatedly(ReturnRef(task_runners));
580 auto is_gpu_disabled_sync_switch =
581 std::make_shared<const fml::SyncSwitch>(false);
582 ON_CALL(delegate, GetIsGpuDisabledSyncSwitch())
583 .WillByDefault(Return(is_gpu_disabled_sync_switch));
584
585 auto rasterizer = std::make_unique<Rasterizer>(delegate);
586 auto surface = std::make_unique<NiceMock<MockSurface>>();
587 EXPECT_CALL(*surface, MakeRenderContextCurrent())
588 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
589
590 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
591 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
592 rasterizer->SetExternalViewEmbedder(external_view_embedder);
593 rasterizer->Setup(std::move(surface));
594
595 EXPECT_CALL(*external_view_embedder, BeginFrame(/*context=*/nullptr,
596 /*raster_thread_merger=*/_))
597 .Times(0);
598 EXPECT_CALL(*external_view_embedder, PrepareFlutterView(
599 /*frame_size=*/DlISize(),
600 /*device_pixel_ratio=*/2.0))
601 .Times(0);
602 EXPECT_CALL(
603 *external_view_embedder,
604 EndFrame(/*should_resubmit_frame=*/false,
605 /*raster_thread_merger=*/fml::RefPtr<fml::RasterThreadMerger>(
606 nullptr)))
607 .Times(0);
608
610 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
611 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
612 auto layer_tree = std::make_unique<LayerTree>(
613 /*root_layer=*/nullptr, /*frame_size=*/DlISize());
614 auto layer_tree_item = std::make_unique<FrameItem>(
615 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
616 kDevicePixelRatio),
618 PipelineProduceResult result =
619 pipeline->Produce().Complete(std::move(layer_tree_item));
620 EXPECT_TRUE(result.success);
621 // Always discard the layer tree.
622 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(true));
623 DrawStatus status = rasterizer->Draw(pipeline);
624 EXPECT_EQ(status, DrawStatus::kDone);
625 EXPECT_EQ(rasterizer->GetLastDrawStatus(kImplicitViewId),
627 latch.Signal();
628 });
629 latch.Wait();
630}
631
632TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenPipelineIsEmpty) {
633 std::string test_name =
634 ::testing::UnitTest::GetInstance()->current_test_info()->name();
635 ThreadHost thread_host("io.flutter.test." + test_name + ".",
639 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
640 thread_host.raster_thread->GetTaskRunner(),
641 thread_host.ui_thread->GetTaskRunner(),
642 thread_host.io_thread->GetTaskRunner());
643 NiceMock<MockDelegate> delegate;
644 Settings settings;
645 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
646 EXPECT_CALL(delegate, GetTaskRunners())
647 .WillRepeatedly(ReturnRef(task_runners));
648
649 auto rasterizer = std::make_unique<Rasterizer>(delegate);
650 auto surface = std::make_unique<NiceMock<MockSurface>>();
651 EXPECT_CALL(*surface, MakeRenderContextCurrent())
652 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
653
654 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
655 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
656 rasterizer->SetExternalViewEmbedder(external_view_embedder);
657 rasterizer->Setup(std::move(surface));
658
659 EXPECT_CALL(
660 *external_view_embedder,
661 EndFrame(/*should_resubmit_frame=*/false,
662 /*raster_thread_merger=*/fml::RefPtr<fml::RasterThreadMerger>(
663 nullptr)))
664 .Times(0);
665
667 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
668 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
669 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
670 DrawStatus status = rasterizer->Draw(pipeline);
671 EXPECT_EQ(status, DrawStatus::kPipelineEmpty);
672 latch.Signal();
673 });
674 latch.Wait();
675}
676
677TEST(RasterizerTest, drawMultipleViewsWithExternalViewEmbedder) {
678 std::string test_name =
679 ::testing::UnitTest::GetInstance()->current_test_info()->name();
680 ThreadHost thread_host("io.flutter.test." + test_name + ".",
684 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
685 thread_host.raster_thread->GetTaskRunner(),
686 thread_host.ui_thread->GetTaskRunner(),
687 thread_host.io_thread->GetTaskRunner());
688 NiceMock<MockDelegate> delegate;
689 Settings settings;
690 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
691 EXPECT_CALL(delegate, GetTaskRunners())
692 .WillRepeatedly(ReturnRef(task_runners));
693 EXPECT_CALL(delegate, OnFrameRasterized(_));
694 auto rasterizer = std::make_unique<Rasterizer>(delegate);
695 auto surface = std::make_unique<NiceMock<MockSurface>>();
696 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
697 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
698 rasterizer->SetExternalViewEmbedder(external_view_embedder);
699 EXPECT_CALL(*external_view_embedder, SupportsDynamicThreadMerging)
700 .WillRepeatedly(Return(false));
701 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true));
702 EXPECT_CALL(*surface, AcquireFrame(DlISize())).Times(2);
703 ON_CALL(*surface, AcquireFrame).WillByDefault([](const DlISize& size) {
704 SurfaceFrame::FramebufferInfo framebuffer_info;
705 framebuffer_info.supports_readback = true;
706 return std::make_unique<SurfaceFrame>(
707 /*surface=*/
708 nullptr, framebuffer_info,
709 /*encode_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
710 /*submit_callback=*/[](const SurfaceFrame&) { return true; },
711 /*frame_size=*/DlISize(800, 600));
712 });
713 EXPECT_CALL(*surface, MakeRenderContextCurrent())
714 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
715
716 EXPECT_CALL(*external_view_embedder, BeginFrame(/*context=*/nullptr,
717 /*raster_thread_merger=*/_))
718 .Times(1);
719 EXPECT_CALL(*external_view_embedder,
720 PrepareFlutterView(/*frame_size=*/DlISize(),
721 /*device_pixel_ratio=*/1.5))
722 .Times(1);
723 EXPECT_CALL(*external_view_embedder,
724 SubmitFlutterView(/*flutter_view_id=*/0, _, _, _))
725 .Times(1);
726 EXPECT_CALL(*external_view_embedder,
727 PrepareFlutterView(/*frame_size=*/DlISize(),
728 /*device_pixel_ratio=*/2.0))
729 .Times(1);
730 EXPECT_CALL(*external_view_embedder,
731 SubmitFlutterView(/*flutter_view_id=*/1, _, _, _))
732 .Times(1);
733 EXPECT_CALL(*external_view_embedder, EndFrame(/*should_resubmit_frame=*/false,
734 /*raster_thread_merger=*/_))
735 .Times(1);
736
737 rasterizer->Setup(std::move(surface));
739 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
740 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
741 std::vector<std::unique_ptr<LayerTreeTask>> tasks;
742 tasks.push_back(std::make_unique<LayerTreeTask>(
743 0, std::make_unique<LayerTree>(nullptr, DlISize()), 1.5));
744 tasks.push_back(std::make_unique<LayerTreeTask>(
745 1, std::make_unique<LayerTree>(nullptr, DlISize()), 2.0));
746 auto layer_tree_item = std::make_unique<FrameItem>(
747 std::move(tasks), CreateFinishedBuildRecorder());
748 PipelineProduceResult result =
749 pipeline->Produce().Complete(std::move(layer_tree_item));
750 EXPECT_TRUE(result.success);
751 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
752 rasterizer->Draw(pipeline);
753 latch.Signal();
754 });
755 latch.Wait();
756}
757
758TEST(RasterizerTest,
759 drawWithGpuEnabledAndSurfaceAllowsDrawingWhenGpuDisabledDoesAcquireFrame) {
760 std::string test_name =
761 ::testing::UnitTest::GetInstance()->current_test_info()->name();
762 ThreadHost thread_host("io.flutter.test." + test_name + ".",
766 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
767 thread_host.raster_thread->GetTaskRunner(),
768 thread_host.ui_thread->GetTaskRunner(),
769 thread_host.io_thread->GetTaskRunner());
770 NiceMock<MockDelegate> delegate;
771 Settings settings;
772 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
773 EXPECT_CALL(delegate, GetTaskRunners())
774 .WillRepeatedly(ReturnRef(task_runners));
775 EXPECT_CALL(delegate, OnFrameRasterized(_));
776
777 auto rasterizer = std::make_unique<Rasterizer>(delegate);
778 auto surface = std::make_unique<NiceMock<MockSurface>>();
779 auto is_gpu_disabled_sync_switch =
780 std::make_shared<const fml::SyncSwitch>(false);
781
782 SurfaceFrame::FramebufferInfo framebuffer_info;
783 framebuffer_info.supports_readback = true;
784 auto surface_frame = std::make_unique<SurfaceFrame>(
785 /*surface=*/
786 nullptr, /*framebuffer_info=*/framebuffer_info,
787 /*encode_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
788 /*submit_callback=*/[](const SurfaceFrame&) { return true; },
789 /*frame_size=*/DlISize(800, 600));
790 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true));
791 ON_CALL(delegate, GetIsGpuDisabledSyncSwitch())
792 .WillByDefault(Return(is_gpu_disabled_sync_switch));
793 EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch()).Times(0);
794 EXPECT_CALL(*surface, AcquireFrame(DlISize()))
795 .WillOnce(Return(ByMove(std::move(surface_frame))));
796 EXPECT_CALL(*surface, MakeRenderContextCurrent())
797 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
798
799 rasterizer->Setup(std::move(surface));
801 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
802 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
803 auto layer_tree = std::make_unique<LayerTree>(
804 /*root_layer=*/nullptr, /*frame_size=*/DlISize());
805 auto layer_tree_item = std::make_unique<FrameItem>(
806 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
807 kDevicePixelRatio),
809 PipelineProduceResult result =
810 pipeline->Produce().Complete(std::move(layer_tree_item));
811 EXPECT_TRUE(result.success);
812 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
813 rasterizer->Draw(pipeline);
814 latch.Signal();
815 });
816 latch.Wait();
817}
818
820 RasterizerTest,
821 drawWithGpuDisabledAndSurfaceAllowsDrawingWhenGpuDisabledDoesAcquireFrame) {
822 std::string test_name =
823 ::testing::UnitTest::GetInstance()->current_test_info()->name();
824 ThreadHost thread_host("io.flutter.test." + test_name + ".",
828 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
829 thread_host.raster_thread->GetTaskRunner(),
830 thread_host.ui_thread->GetTaskRunner(),
831 thread_host.io_thread->GetTaskRunner());
832 NiceMock<MockDelegate> delegate;
833 Settings settings;
834 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
835 EXPECT_CALL(delegate, GetTaskRunners())
836 .WillRepeatedly(ReturnRef(task_runners));
837 EXPECT_CALL(delegate, OnFrameRasterized(_));
838 auto rasterizer = std::make_unique<Rasterizer>(delegate);
839 auto surface = std::make_unique<NiceMock<MockSurface>>();
840 auto is_gpu_disabled_sync_switch =
841 std::make_shared<const fml::SyncSwitch>(true);
842
843 SurfaceFrame::FramebufferInfo framebuffer_info;
844 framebuffer_info.supports_readback = true;
845
846 auto surface_frame = std::make_unique<SurfaceFrame>(
847 /*surface=*/
848 nullptr, /*framebuffer_info=*/framebuffer_info,
849 /*encode_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
850 /*submit_callback=*/[](const SurfaceFrame&) { return true; },
851 /*frame_size=*/DlISize(800, 600));
852 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true));
853 ON_CALL(delegate, GetIsGpuDisabledSyncSwitch())
854 .WillByDefault(Return(is_gpu_disabled_sync_switch));
855 EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch()).Times(0);
856 EXPECT_CALL(*surface, AcquireFrame(DlISize()))
857 .WillOnce(Return(ByMove(std::move(surface_frame))));
858 EXPECT_CALL(*surface, MakeRenderContextCurrent())
859 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
860
861 rasterizer->Setup(std::move(surface));
863 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
864 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
865 auto layer_tree = std::make_unique<LayerTree>(
866 /*root_layer=*/nullptr, /*frame_size=*/DlISize());
867 auto layer_tree_item = std::make_unique<FrameItem>(
868 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
869 kDevicePixelRatio),
871 PipelineProduceResult result =
872 pipeline->Produce().Complete(std::move(layer_tree_item));
873 EXPECT_TRUE(result.success);
874 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
875 DrawStatus status = rasterizer->Draw(pipeline);
876 EXPECT_EQ(status, DrawStatus::kDone);
877 latch.Signal();
878 });
879 latch.Wait();
880}
881
883 RasterizerTest,
884 drawWithGpuEnabledAndSurfaceDisallowsDrawingWhenGpuDisabledDoesAcquireFrame) {
885 std::string test_name =
886 ::testing::UnitTest::GetInstance()->current_test_info()->name();
887 ThreadHost thread_host("io.flutter.test." + test_name + ".",
891 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
892 thread_host.raster_thread->GetTaskRunner(),
893 thread_host.ui_thread->GetTaskRunner(),
894 thread_host.io_thread->GetTaskRunner());
895 NiceMock<MockDelegate> delegate;
896 Settings settings;
897 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
898 EXPECT_CALL(delegate, GetTaskRunners())
899 .WillRepeatedly(ReturnRef(task_runners));
900 EXPECT_CALL(delegate, OnFrameRasterized(_));
901 auto rasterizer = std::make_unique<Rasterizer>(delegate);
902 auto surface = std::make_unique<NiceMock<MockSurface>>();
903 auto is_gpu_disabled_sync_switch =
904 std::make_shared<const fml::SyncSwitch>(false);
905
906 SurfaceFrame::FramebufferInfo framebuffer_info;
907 framebuffer_info.supports_readback = true;
908
909 auto surface_frame = std::make_unique<SurfaceFrame>(
910 /*surface=*/
911 nullptr, /*framebuffer_info=*/framebuffer_info,
912 /*encode_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
913 /*submit_callback=*/[](const SurfaceFrame&) { return true; },
914 /*frame_size=*/DlISize(800, 600));
915 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(false));
916 EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch())
917 .WillOnce(Return(is_gpu_disabled_sync_switch));
918 EXPECT_CALL(*surface, AcquireFrame(DlISize()))
919 .WillOnce(Return(ByMove(std::move(surface_frame))));
920 EXPECT_CALL(*surface, MakeRenderContextCurrent())
921 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
922
923 rasterizer->Setup(std::move(surface));
925 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
926 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
927 auto layer_tree = std::make_unique<LayerTree>(
928 /*root_layer=*/nullptr, /*frame_size=*/DlISize());
929 auto layer_tree_item = std::make_unique<FrameItem>(
930 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
931 kDevicePixelRatio),
933 PipelineProduceResult result =
934 pipeline->Produce().Complete(std::move(layer_tree_item));
935 EXPECT_TRUE(result.success);
936 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
937 DrawStatus status = rasterizer->Draw(pipeline);
938 EXPECT_EQ(status, DrawStatus::kDone);
939 latch.Signal();
940 });
941 latch.Wait();
942}
943
945 RasterizerTest,
946 drawWithGpuDisabledAndSurfaceDisallowsDrawingWhenGpuDisabledDoesntAcquireFrame) {
947 std::string test_name =
948 ::testing::UnitTest::GetInstance()->current_test_info()->name();
949 ThreadHost thread_host("io.flutter.test." + test_name + ".",
953 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
954 thread_host.raster_thread->GetTaskRunner(),
955 thread_host.ui_thread->GetTaskRunner(),
956 thread_host.io_thread->GetTaskRunner());
957 NiceMock<MockDelegate> delegate;
958 Settings settings;
959 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
960 EXPECT_CALL(delegate, GetTaskRunners())
961 .WillRepeatedly(ReturnRef(task_runners));
962 EXPECT_CALL(delegate, OnFrameRasterized(_)).Times(0);
963 auto rasterizer = std::make_unique<Rasterizer>(delegate);
964 auto surface = std::make_unique<NiceMock<MockSurface>>();
965 auto is_gpu_disabled_sync_switch =
966 std::make_shared<const fml::SyncSwitch>(true);
967
968 SurfaceFrame::FramebufferInfo framebuffer_info;
969 framebuffer_info.supports_readback = true;
970
971 auto surface_frame = std::make_unique<SurfaceFrame>(
972 /*surface=*/
973 nullptr, /*framebuffer_info=*/framebuffer_info,
974 /*encode_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
975 /*submit_callback=*/[](const SurfaceFrame&) { return true; },
976 /*frame_size=*/DlISize(800, 600));
977 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(false));
978 EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch())
979 .WillOnce(Return(is_gpu_disabled_sync_switch));
980 EXPECT_CALL(*surface, AcquireFrame(DlISize())).Times(0);
981 EXPECT_CALL(*surface, MakeRenderContextCurrent())
982 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
983
984 rasterizer->Setup(std::move(surface));
986 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
987 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
988 auto layer_tree = std::make_unique<LayerTree>(
989 /*root_layer=*/nullptr, /*frame_size=*/DlISize());
990 auto layer_tree_item = std::make_unique<FrameItem>(
991 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
992 kDevicePixelRatio),
994 PipelineProduceResult result =
995 pipeline->Produce().Complete(std::move(layer_tree_item));
996 EXPECT_TRUE(result.success);
997 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
998 DrawStatus status = rasterizer->Draw(pipeline);
999 EXPECT_EQ(status, DrawStatus::kGpuUnavailable);
1000 latch.Signal();
1001 });
1002 latch.Wait();
1003}
1004
1006 RasterizerTest,
1007 FrameTimingRecorderShouldStartRecordingRasterTimeBeforeSurfaceAcquireFrame) {
1008 std::string test_name =
1009 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1010 ThreadHost thread_host("io.flutter.test." + test_name + ".",
1014 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
1015 thread_host.raster_thread->GetTaskRunner(),
1016 thread_host.ui_thread->GetTaskRunner(),
1017 thread_host.io_thread->GetTaskRunner());
1018 NiceMock<MockDelegate> delegate;
1019 Settings settings;
1020 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
1021 EXPECT_CALL(delegate, GetTaskRunners())
1022 .WillRepeatedly(ReturnRef(task_runners));
1023 EXPECT_CALL(delegate, OnFrameRasterized(_))
1024 .WillOnce([&](const FrameTiming& frame_timing) {
1026 fml::TimePoint raster_start =
1027 frame_timing.Get(FrameTiming::kRasterStart);
1028 EXPECT_TRUE(now - raster_start < fml::TimeDelta::FromSecondsF(1));
1029 });
1030
1031 auto rasterizer = std::make_unique<Rasterizer>(delegate);
1032 auto surface = std::make_unique<NiceMock<MockSurface>>();
1033 auto is_gpu_disabled_sync_switch =
1034 std::make_shared<const fml::SyncSwitch>(false);
1035 ON_CALL(delegate, GetIsGpuDisabledSyncSwitch())
1036 .WillByDefault(Return(is_gpu_disabled_sync_switch));
1037 ON_CALL(*surface, AcquireFrame(DlISize()))
1038 .WillByDefault(::testing::Invoke([] { return nullptr; }));
1039 EXPECT_CALL(*surface, AcquireFrame(DlISize()));
1040 EXPECT_CALL(*surface, MakeRenderContextCurrent())
1041 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
1042 rasterizer->Setup(std::move(surface));
1044 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1045 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
1046 auto layer_tree = std::make_unique<LayerTree>(
1047 /*root_layer=*/nullptr, /*frame_size=*/DlISize());
1048 auto layer_tree_item = std::make_unique<FrameItem>(
1049 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
1050 kDevicePixelRatio),
1052 PipelineProduceResult result =
1053 pipeline->Produce().Complete(std::move(layer_tree_item));
1054 EXPECT_TRUE(result.success);
1055 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
1056 DrawStatus status = rasterizer->Draw(pipeline);
1057 EXPECT_EQ(status, DrawStatus::kDone);
1058 EXPECT_EQ(rasterizer->GetLastDrawStatus(kImplicitViewId),
1060 latch.Signal();
1061 });
1062 latch.Wait();
1063}
1064
1065TEST(RasterizerTest,
1066 drawLayerTreeWithCorrectFrameTimingWhenPipelineIsMoreAvailable) {
1067 std::string test_name =
1068 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1069 ThreadHost thread_host("io.flutter.test." + test_name + ".",
1073 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
1074 thread_host.raster_thread->GetTaskRunner(),
1075 thread_host.ui_thread->GetTaskRunner(),
1076 thread_host.io_thread->GetTaskRunner());
1077 NiceMock<MockDelegate> delegate;
1078 Settings settings;
1079 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
1080 ON_CALL(delegate, GetTaskRunners()).WillByDefault(ReturnRef(task_runners));
1081
1083 std::unique_ptr<Rasterizer> rasterizer;
1084 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1085 rasterizer = std::make_unique<Rasterizer>(delegate);
1086 latch.Signal();
1087 });
1088 latch.Wait();
1089
1090 auto surface = std::make_unique<NiceMock<MockSurface>>();
1091 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled())
1092 .WillRepeatedly(Return(true));
1093 ON_CALL(*surface, AcquireFrame(DlISize()))
1094 .WillByDefault(::testing::Invoke([] {
1095 SurfaceFrame::FramebufferInfo framebuffer_info;
1096 framebuffer_info.supports_readback = true;
1097 return std::make_unique<SurfaceFrame>(
1098 /*surface=*/
1099 nullptr, framebuffer_info,
1100 /*encode_callback=*/
1101 [](const SurfaceFrame&, DlCanvas*) { return true; },
1102 /*submit_callback=*/[](const SurfaceFrame& frame) { return true; },
1103 /*frame_size=*/DlISize(800, 600));
1104 }));
1105 ON_CALL(*surface, MakeRenderContextCurrent())
1106 .WillByDefault(::testing::Invoke(
1107 [] { return std::make_unique<GLContextDefaultResult>(true); }));
1108
1109 fml::CountDownLatch count_down_latch(2);
1110 auto first_timestamp = fml::TimePoint::Now();
1111 auto second_timestamp = first_timestamp + fml::TimeDelta::FromMilliseconds(8);
1112 std::vector<fml::TimePoint> timestamps = {first_timestamp, second_timestamp};
1113 int frame_rasterized_count = 0;
1114 EXPECT_CALL(delegate, OnFrameRasterized(_))
1115 .Times(2)
1116 .WillRepeatedly([&](const FrameTiming& frame_timing) {
1117 EXPECT_EQ(timestamps[frame_rasterized_count],
1118 frame_timing.Get(FrameTiming::kVsyncStart));
1119 EXPECT_EQ(timestamps[frame_rasterized_count],
1120 frame_timing.Get(FrameTiming::kBuildStart));
1121 EXPECT_EQ(timestamps[frame_rasterized_count],
1122 frame_timing.Get(FrameTiming::kBuildFinish));
1123 frame_rasterized_count++;
1124 count_down_latch.CountDown();
1125 });
1126
1127 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1128 rasterizer->Setup(std::move(surface));
1129 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
1130 for (int i = 0; i < 2; i++) {
1131 auto layer_tree = std::make_unique<LayerTree>(
1132 /*root_layer=*/nullptr, /*frame_size=*/DlISize());
1133 auto layer_tree_item = std::make_unique<FrameItem>(
1134 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
1135 kDevicePixelRatio),
1136 CreateFinishedBuildRecorder(timestamps[i]));
1137 PipelineProduceResult result =
1138 pipeline->Produce().Complete(std::move(layer_tree_item));
1139 EXPECT_TRUE(result.success);
1140 EXPECT_EQ(result.is_first_item, i == 0);
1141 }
1142 // Although we only call 'Rasterizer::Draw' once, it will be called twice
1143 // finally because there are two items in the pipeline.
1144 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
1145 rasterizer->Draw(pipeline);
1146 });
1147 count_down_latch.Wait();
1148 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1149 rasterizer.reset();
1150 latch.Signal();
1151 });
1152 latch.Wait();
1153}
1154
1155TEST(RasterizerTest, TeardownFreesResourceCache) {
1156 std::string test_name =
1157 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1158 ThreadHost thread_host("io.flutter.test." + test_name + ".",
1162 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
1163 thread_host.raster_thread->GetTaskRunner(),
1164 thread_host.ui_thread->GetTaskRunner(),
1165 thread_host.io_thread->GetTaskRunner());
1166
1167 NiceMock<MockDelegate> delegate;
1168 Settings settings;
1169 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
1170 EXPECT_CALL(delegate, GetTaskRunners())
1171 .WillRepeatedly(ReturnRef(task_runners));
1172
1173 auto rasterizer = std::make_unique<Rasterizer>(delegate);
1174 auto surface = std::make_unique<NiceMock<MockSurface>>();
1175 auto context = GrDirectContext::MakeMock(nullptr);
1176 context->setResourceCacheLimit(0);
1177
1178 EXPECT_CALL(*surface, MakeRenderContextCurrent())
1179 .WillRepeatedly([]() -> std::unique_ptr<GLContextResult> {
1180 return std::make_unique<GLContextDefaultResult>(true);
1181 });
1182 EXPECT_CALL(*surface, GetContext()).WillRepeatedly(Return(context.get()));
1183
1184 rasterizer->Setup(std::move(surface));
1185 EXPECT_EQ(context->getResourceCacheLimit(), 0ul);
1186
1187 rasterizer->SetResourceCacheMaxBytes(10000000, false);
1188 EXPECT_EQ(context->getResourceCacheLimit(), 10000000ul);
1189 EXPECT_EQ(context->getResourceCachePurgeableBytes(), 0ul);
1190
1191 int count = 0;
1192 size_t bytes = 0;
1193 context->getResourceCacheUsage(&count, &bytes);
1194 EXPECT_EQ(bytes, 0ul);
1195
1196 auto image_info =
1197 SkImageInfo::MakeN32Premul(500, 500, SkColorSpace::MakeSRGB());
1198 auto sk_surface = SkSurfaces::RenderTarget(context.get(),
1199 skgpu::Budgeted::kYes, image_info);
1200 EXPECT_TRUE(sk_surface);
1201
1202 SkPaint paint;
1203 sk_surface->getCanvas()->drawPaint(paint);
1204 context->flushAndSubmit(GrSyncCpu::kYes);
1205
1206 EXPECT_EQ(context->getResourceCachePurgeableBytes(), 0ul);
1207
1208 sk_surface.reset();
1209
1210 context->getResourceCacheUsage(&count, &bytes);
1211 EXPECT_GT(bytes, 0ul);
1212 EXPECT_GT(context->getResourceCachePurgeableBytes(), 0ul);
1213
1214 rasterizer->Teardown();
1215 EXPECT_EQ(context->getResourceCachePurgeableBytes(), 0ul);
1216}
1217
1218TEST(RasterizerTest, TeardownNoSurface) {
1219 std::string test_name =
1220 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1221 ThreadHost thread_host("io.flutter.test." + test_name + ".",
1225 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
1226 thread_host.raster_thread->GetTaskRunner(),
1227 thread_host.ui_thread->GetTaskRunner(),
1228 thread_host.io_thread->GetTaskRunner());
1229
1230 NiceMock<MockDelegate> delegate;
1231 Settings settings;
1232 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
1233 EXPECT_CALL(delegate, GetTaskRunners())
1234 .WillRepeatedly(ReturnRef(task_runners));
1235
1236 auto rasterizer = std::make_unique<Rasterizer>(delegate);
1237
1238 EXPECT_TRUE(rasterizer);
1239 rasterizer->Teardown();
1240}
1241
1242TEST(RasterizerTest, presentationTimeSetWhenVsyncTargetInFuture) {
1243 GTEST_SKIP() << "eglPresentationTime is disabled due to "
1244 "https://github.com/flutter/flutter/issues/112503";
1245#if false
1246 std::string test_name =
1247 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1248 ThreadHost thread_host("io.flutter.test." + test_name + ".",
1251 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
1252 thread_host.raster_thread->GetTaskRunner(),
1253 thread_host.ui_thread->GetTaskRunner(),
1254 thread_host.io_thread->GetTaskRunner());
1255
1256 NiceMock<MockDelegate> delegate;
1257 Settings settings;
1258 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
1259 ON_CALL(delegate, GetTaskRunners()).WillByDefault(ReturnRef(task_runners));
1260
1262 std::unique_ptr<Rasterizer> rasterizer;
1263 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1264 rasterizer = std::make_unique<Rasterizer>(delegate);
1265 latch.Signal();
1266 });
1267 latch.Wait();
1268
1269 const auto millis_16 = fml::TimeDelta::FromMilliseconds(16);
1270 const auto first_timestamp = fml::TimePoint::Now() + millis_16;
1271 auto second_timestamp = first_timestamp + millis_16;
1272 std::vector<fml::TimePoint> timestamps = {first_timestamp, second_timestamp};
1273
1274 int frames_submitted = 0;
1275 fml::CountDownLatch submit_latch(2);
1276 auto surface = std::make_unique<MockSurface>();
1277 ON_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillByDefault(Return(true));
1278 ON_CALL(*surface, AcquireFrame(DlISize()))
1279 .WillByDefault(::testing::Invoke([&] {
1280 SurfaceFrame::FramebufferInfo framebuffer_info;
1281 framebuffer_info.supports_readback = true;
1282 return std::make_unique<SurfaceFrame>(
1283 /*surface=*/nullptr, framebuffer_info,
1284 /*submit_callback=*/
1285 [&](const SurfaceFrame& frame, DlCanvas*) {
1286 const auto pres_time = *frame.submit_info().presentation_time;
1287 const auto diff = pres_time - first_timestamp;
1288 int num_frames_submitted = frames_submitted++;
1289 EXPECT_EQ(diff.ToMilliseconds(),
1290 num_frames_submitted * millis_16.ToMilliseconds());
1291 submit_latch.CountDown();
1292 return true;
1293 },
1294 /*frame_size=*/DlISize(800, 600));
1295 }));
1296
1297 ON_CALL(*surface, MakeRenderContextCurrent())
1298 .WillByDefault(::testing::Invoke(
1299 [] { return std::make_unique<GLContextDefaultResult>(true); }));
1300
1301 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1302 rasterizer->Setup(std::move(surface));
1303 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
1304 for (int i = 0; i < 2; i++) {
1305 auto layer_tree = std::make_unique<LayerTree>(
1306 /*root_layer=*/nullptr, /*frame_size=*/DlISize());
1307 auto layer_tree_item = std::make_unique<FrameItem>(
1308 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
1309 kDevicePixelRatio),
1310 CreateFinishedBuildRecorder(timestamps[i]));
1311 PipelineProduceResult result =
1312 pipeline->Produce().Complete(std::move(layer_tree_item));
1313 EXPECT_TRUE(result.success);
1314 EXPECT_EQ(result.is_first_item, i == 0);
1315 }
1316 // Although we only call 'Rasterizer::Draw' once, it will be called twice
1317 // finally because there are two items in the pipeline.
1318 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
1319 rasterizer->Draw(pipeline);
1320 });
1321
1322 submit_latch.Wait();
1323 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1324 rasterizer.reset();
1325 latch.Signal();
1326 });
1327 latch.Wait();
1328#endif // false
1329}
1330
1331TEST(RasterizerTest, presentationTimeNotSetWhenVsyncTargetInPast) {
1332 GTEST_SKIP() << "eglPresentationTime is disabled due to "
1333 "https://github.com/flutter/flutter/issues/112503";
1334#if false
1335 std::string test_name =
1336 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1337 ThreadHost thread_host("io.flutter.test." + test_name + ".",
1340 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
1341 thread_host.raster_thread->GetTaskRunner(),
1342 thread_host.ui_thread->GetTaskRunner(),
1343 thread_host.io_thread->GetTaskRunner());
1344
1345 NiceMock<MockDelegate> delegate;
1346 Settings settings;
1347 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
1348 ON_CALL(delegate, GetTaskRunners()).WillByDefault(ReturnRef(task_runners));
1349
1351 std::unique_ptr<Rasterizer> rasterizer;
1352 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1353 rasterizer = std::make_unique<Rasterizer>(delegate);
1354 latch.Signal();
1355 });
1356 latch.Wait();
1357
1358 const auto millis_16 = fml::TimeDelta::FromMilliseconds(16);
1359 const auto first_timestamp = fml::TimePoint::Now() - millis_16;
1360
1361 fml::CountDownLatch submit_latch(1);
1362 auto surface = std::make_unique<MockSurface>();
1363 ON_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillByDefault(Return(true));
1364 ON_CALL(*surface, AcquireFrame(DlISize()))
1365 .WillByDefault(::testing::Invoke([&] {
1366 SurfaceFrame::FramebufferInfo framebuffer_info;
1367 framebuffer_info.supports_readback = true;
1368 return std::make_unique<SurfaceFrame>(
1369 /*surface=*/nullptr, framebuffer_info,
1370 /*submit_callback=*/
1371 [&](const SurfaceFrame& frame, DlCanvas*) {
1372 const std::optional<fml::TimePoint> pres_time =
1373 frame.submit_info().presentation_time;
1374 EXPECT_EQ(pres_time, std::nullopt);
1375 submit_latch.CountDown();
1376 return true;
1377 },
1378 /*frame_size=*/DlISize(800, 600));
1379 }));
1380
1381 ON_CALL(*surface, MakeRenderContextCurrent())
1382 .WillByDefault(::testing::Invoke(
1383 [] { return std::make_unique<GLContextDefaultResult>(true); }));
1384
1385 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1386 rasterizer->Setup(std::move(surface));
1387 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
1388 auto layer_tree = std::make_unique<LayerTree>(
1389 /*root_layer=*/nullptr, /*frame_size=*/DlISize());
1390 auto layer_tree_item = std::make_unique<FrameItem>(
1391 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
1392 kDevicePixelRatio),
1393 CreateFinishedBuildRecorder(first_timestamp));
1394 PipelineProduceResult result =
1395 pipeline->Produce().Complete(std::move(layer_tree_item));
1396 EXPECT_TRUE(result.success);
1397 EXPECT_EQ(result.is_first_item, true);
1398 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
1399 rasterizer->Draw(pipeline);
1400 });
1401
1402 submit_latch.Wait();
1403 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1404 rasterizer.reset();
1405 latch.Signal();
1406 });
1407 latch.Wait();
1408#endif // false
1409}
1410
1411} // namespace flutter
Developer-facing API for rendering anything within the engine.
Definition dl_canvas.h:32
fml::TimePoint Get(Phase phase) const
Definition settings.h:43
const SubmitInfo & submit_info() const
static void EnsureInitializedForCurrentThread()
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
static constexpr TimeDelta FromSecondsF(double seconds)
Definition time_delta.h:53
static constexpr TimeDelta FromMilliseconds(int64_t millis)
Definition time_delta.h:46
static TimePoint Now()
Definition time_point.cc:49
const EmbeddedViewParams * params
VkSurfaceKHR surface
Definition main.cc:65
G_BEGIN_DECLS FlutterViewId view_id
static std::unique_ptr< FrameTimingsRecorder > CreateFinishedBuildRecorder()
TEST(FrameTimingsRecorderTest, RecordVsync)
impeller::Matrix DlMatrix
impeller::ISize32 DlISize
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
constexpr FlutterViewId kImplicitViewId
std::chrono::duration< double, std::milli > Milliseconds
Definition time_delta.h:18
The collection of all the threads used by the engine.
Definition thread_host.h:21
std::unique_ptr< fml::Thread > io_thread
Definition thread_host.h:86
std::unique_ptr< fml::Thread > platform_thread
Definition thread_host.h:83
std::unique_ptr< fml::Thread > raster_thread
Definition thread_host.h:85
std::unique_ptr< fml::Thread > ui_thread
Definition thread_host.h:84
int_closure create