Flutter Engine
The Flutter Engine
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
7#include "flutter/shell/common/rasterizer.h"
8
9#include <memory>
10#include <optional>
11
12#include "flutter/flow/frame_timings.h"
13#include "flutter/fml/synchronization/count_down_latch.h"
14#include "flutter/fml/time/time_point.h"
15#include "flutter/shell/common/thread_host.h"
16#include "flutter/testing/testing.h"
17
22
23#include "gmock/gmock.h"
24
25using testing::_;
26using testing::ByMove;
27using testing::NiceMock;
28using testing::Return;
29using testing::ReturnRef;
30
31namespace flutter {
32namespace {
33
34constexpr float kDevicePixelRatio = 2.0f;
35constexpr int64_t kImplicitViewId = 0;
36
37std::vector<std::unique_ptr<LayerTreeTask>> SingleLayerTreeList(
38 int64_t view_id,
39 std::unique_ptr<LayerTree> layer_tree,
40 float pixel_ratio) {
41 std::vector<std::unique_ptr<LayerTreeTask>> tasks;
42 tasks.push_back(std::make_unique<LayerTreeTask>(
43 view_id, std::move(layer_tree), pixel_ratio));
44 return tasks;
45}
46
47class MockDelegate : public Rasterizer::Delegate {
48 public:
49 MOCK_METHOD(void,
50 OnFrameRasterized,
51 (const FrameTiming& frame_timing),
52 (override));
53 MOCK_METHOD(fml::Milliseconds, GetFrameBudget, (), (override));
54 MOCK_METHOD(fml::TimePoint, GetLatestFrameTargetTime, (), (const, override));
55 MOCK_METHOD(const TaskRunners&, GetTaskRunners, (), (const, override));
57 GetParentRasterThreadMerger,
58 (),
59 (const, override));
60 MOCK_METHOD(std::shared_ptr<const fml::SyncSwitch>,
61 GetIsGpuDisabledSyncSwitch,
62 (),
63 (const, override));
64 MOCK_METHOD(const Settings&, GetSettings, (), (const, override));
65 MOCK_METHOD(bool,
66 ShouldDiscardLayerTree,
67 (int64_t, const flutter::LayerTree&),
68 (override));
69};
70
71class MockSurface : public Surface {
72 public:
73 MOCK_METHOD(bool, IsValid, (), (override));
74 MOCK_METHOD(std::unique_ptr<SurfaceFrame>,
75 AcquireFrame,
76 (const SkISize& size),
77 (override));
78 MOCK_METHOD(SkMatrix, GetRootTransformation, (), (const, override));
79 MOCK_METHOD(GrDirectContext*, GetContext, (), (override));
80 MOCK_METHOD(std::unique_ptr<GLContextResult>,
81 MakeRenderContextCurrent,
82 (),
83 (override));
84 MOCK_METHOD(bool, ClearRenderContext, (), (override));
85 MOCK_METHOD(bool, AllowsDrawingWhenGpuDisabled, (), (const, override));
86};
87
88class MockExternalViewEmbedder : public ExternalViewEmbedder {
89 public:
90 MOCK_METHOD(DlCanvas*, GetRootCanvas, (), (override));
91 MOCK_METHOD(void, CancelFrame, (), (override));
92 MOCK_METHOD(
93 void,
94 BeginFrame,
95 (GrDirectContext * context,
96 const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger),
97 (override));
98 MOCK_METHOD(void,
99 PrepareFlutterView,
100 (SkISize frame_size, double device_pixel_ratio),
101 (override));
102 MOCK_METHOD(void,
103 PrerollCompositeEmbeddedView,
104 (int64_t view_id, std::unique_ptr<EmbeddedViewParams> params),
105 (override));
106 MOCK_METHOD(
108 PostPrerollAction,
109 (const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger),
110 (override));
111 MOCK_METHOD(DlCanvas*, CompositeEmbeddedView, (int64_t view_id), (override));
112 MOCK_METHOD(void,
113 SubmitFlutterView,
114 (int64_t flutter_view_id,
115 GrDirectContext* context,
116 const std::shared_ptr<impeller::AiksContext>& aiks_context,
117 std::unique_ptr<SurfaceFrame> frame),
118 (override));
119 MOCK_METHOD(
120 void,
121 EndFrame,
122 (bool should_resubmit_frame,
123 const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger),
124 (override));
125 MOCK_METHOD(bool, SupportsDynamicThreadMerging, (), (override));
126};
127} // namespace
128
129TEST(RasterizerTest, create) {
130 NiceMock<MockDelegate> delegate;
132 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
133 auto rasterizer = std::make_unique<Rasterizer>(delegate);
134 EXPECT_TRUE(rasterizer != nullptr);
135}
136
137static std::unique_ptr<FrameTimingsRecorder> CreateFinishedBuildRecorder(
138 fml::TimePoint timestamp) {
139 std::unique_ptr<FrameTimingsRecorder> recorder =
140 std::make_unique<FrameTimingsRecorder>();
141 recorder->RecordVsync(timestamp, timestamp);
142 recorder->RecordBuildStart(timestamp);
143 recorder->RecordBuildEnd(timestamp);
144 return recorder;
145}
146
147static std::unique_ptr<FrameTimingsRecorder> CreateFinishedBuildRecorder() {
149}
150
151TEST(RasterizerTest, drawEmptyPipeline) {
152 std::string test_name =
153 ::testing::UnitTest::GetInstance()->current_test_info()->name();
154 ThreadHost thread_host("io.flutter.test." + test_name + ".",
155 ThreadHost::Type::kPlatform |
156 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
157 ThreadHost::Type::kUi);
158 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
159 thread_host.raster_thread->GetTaskRunner(),
160 thread_host.ui_thread->GetTaskRunner(),
161 thread_host.io_thread->GetTaskRunner());
162 NiceMock<MockDelegate> delegate;
164 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
165 ON_CALL(delegate, GetTaskRunners()).WillByDefault(ReturnRef(task_runners));
166 auto rasterizer = std::make_unique<Rasterizer>(delegate);
167 auto surface = std::make_unique<NiceMock<MockSurface>>();
168 EXPECT_CALL(*surface, MakeRenderContextCurrent())
169 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
170 rasterizer->Setup(std::move(surface));
172 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
173 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
174 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
175 rasterizer->Draw(pipeline);
176 latch.Signal();
177 });
178 latch.Wait();
179}
180
181TEST(RasterizerTest,
182 drawWithExternalViewEmbedderExternalViewEmbedderSubmitFrameCalled) {
183 std::string test_name =
184 ::testing::UnitTest::GetInstance()->current_test_info()->name();
185 ThreadHost thread_host("io.flutter.test." + test_name + ".",
186 ThreadHost::Type::kPlatform |
187 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
188 ThreadHost::Type::kUi);
189 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
190 thread_host.raster_thread->GetTaskRunner(),
191 thread_host.ui_thread->GetTaskRunner(),
192 thread_host.io_thread->GetTaskRunner());
193 NiceMock<MockDelegate> delegate;
195 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
196 EXPECT_CALL(delegate, GetTaskRunners())
197 .WillRepeatedly(ReturnRef(task_runners));
198 EXPECT_CALL(delegate, OnFrameRasterized(_));
199 auto rasterizer = std::make_unique<Rasterizer>(delegate);
200 auto surface = std::make_unique<NiceMock<MockSurface>>();
201
202 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
203 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
204 rasterizer->SetExternalViewEmbedder(external_view_embedder);
205
206 SurfaceFrame::FramebufferInfo framebuffer_info;
207 framebuffer_info.supports_readback = true;
208
209 auto surface_frame = std::make_unique<SurfaceFrame>(
210 /*surface=*/
211 nullptr, framebuffer_info,
212 /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
213 /*frame_size=*/SkISize::Make(800, 600));
214 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true));
215 EXPECT_CALL(*surface, AcquireFrame(SkISize()))
216 .WillOnce(Return(ByMove(std::move(surface_frame))));
217 EXPECT_CALL(*surface, MakeRenderContextCurrent())
218 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
219
220 EXPECT_CALL(*external_view_embedder,
221 BeginFrame(/*context=*/nullptr,
222 /*raster_thread_merger=*/
224 .Times(1);
225 EXPECT_CALL(*external_view_embedder, PrepareFlutterView(
226 /*frame_size=*/SkISize(),
227 /*device_pixel_ratio=*/2.0))
228 .Times(1);
229 EXPECT_CALL(*external_view_embedder,
230 SubmitFlutterView(/*flutter_view_id=*/kImplicitViewId, _, _, _))
231 .Times(1);
232 EXPECT_CALL(
233 *external_view_embedder,
234 EndFrame(/*should_resubmit_frame=*/false,
235 /*raster_thread_merger=*/fml::RefPtr<fml::RasterThreadMerger>(
236 nullptr)))
237 .Times(1);
238
239 rasterizer->Setup(std::move(surface));
241 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
242 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
243 auto layer_tree = std::make_unique<LayerTree>(/*root_layer=*/nullptr,
244 /*frame_size=*/SkISize());
245 auto layer_tree_item = std::make_unique<FrameItem>(
246 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
247 kDevicePixelRatio),
250 pipeline->Produce().Complete(std::move(layer_tree_item));
251 EXPECT_TRUE(result.success);
252 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
253 rasterizer->Draw(pipeline);
254 latch.Signal();
255 });
256 latch.Wait();
257}
258
260 RasterizerTest,
261 drawWithExternalViewEmbedderAndThreadMergerNotMergedExternalViewEmbedderSubmitFrameNotCalled) {
262 std::string test_name =
263 ::testing::UnitTest::GetInstance()->current_test_info()->name();
264 ThreadHost thread_host("io.flutter.test." + test_name + ".",
265 ThreadHost::Type::kPlatform |
266 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
267 ThreadHost::Type::kUi);
268 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
269 thread_host.raster_thread->GetTaskRunner(),
270 thread_host.ui_thread->GetTaskRunner(),
271 thread_host.io_thread->GetTaskRunner());
272 NiceMock<MockDelegate> delegate;
274 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
275 EXPECT_CALL(delegate, GetTaskRunners())
276 .WillRepeatedly(ReturnRef(task_runners));
277 EXPECT_CALL(delegate, OnFrameRasterized(_));
278 auto rasterizer = std::make_unique<Rasterizer>(delegate);
279 auto surface = std::make_unique<NiceMock<MockSurface>>();
280 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
281 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
282 rasterizer->SetExternalViewEmbedder(external_view_embedder);
283 EXPECT_CALL(*external_view_embedder, SupportsDynamicThreadMerging)
284 .WillRepeatedly(Return(true));
285 SurfaceFrame::FramebufferInfo framebuffer_info;
286 framebuffer_info.supports_readback = true;
287 auto surface_frame = std::make_unique<SurfaceFrame>(
288 /*surface=*/
289 nullptr, framebuffer_info,
290 /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
291 /*frame_size=*/SkISize::Make(800, 600));
292 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true));
293 EXPECT_CALL(*surface, AcquireFrame(SkISize()))
294 .WillOnce(Return(ByMove(std::move(surface_frame))));
295 EXPECT_CALL(*surface, MakeRenderContextCurrent())
296 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
297
298 EXPECT_CALL(*external_view_embedder, BeginFrame(/*context=*/nullptr,
299 /*raster_thread_merger=*/_))
300 .Times(1);
301 EXPECT_CALL(*external_view_embedder, PrepareFlutterView(
302 /*frame_size=*/SkISize(),
303 /*device_pixel_ratio=*/2.0))
304 .Times(1);
305 EXPECT_CALL(*external_view_embedder,
306 SubmitFlutterView(/*flutter_view_id=*/kImplicitViewId, _, _, _))
307 .Times(0);
308 EXPECT_CALL(*external_view_embedder, EndFrame(/*should_resubmit_frame=*/false,
309 /*raster_thread_merger=*/_))
310 .Times(1);
311
312 rasterizer->Setup(std::move(surface));
314 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
315 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
316 auto layer_tree = std::make_unique<LayerTree>(
317 /*root_layer=*/nullptr, /*frame_size=*/SkISize());
318 auto layer_tree_item = std::make_unique<FrameItem>(
319 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
320 kDevicePixelRatio),
323 pipeline->Produce().Complete(std::move(layer_tree_item));
324 EXPECT_TRUE(result.success);
325 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
326 rasterizer->Draw(pipeline);
327 latch.Signal();
328 });
329 latch.Wait();
330}
331
333 RasterizerTest,
334 drawWithExternalViewEmbedderAndThreadsMergedExternalViewEmbedderSubmitFrameCalled) {
335 std::string test_name =
336 ::testing::UnitTest::GetInstance()->current_test_info()->name();
337 ThreadHost thread_host("io.flutter.test." + test_name + ".",
338 ThreadHost::Type::kPlatform |
339 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
340 ThreadHost::Type::kUi);
342 TaskRunners task_runners("test",
343 fml::MessageLoop::GetCurrent().GetTaskRunner(),
344 fml::MessageLoop::GetCurrent().GetTaskRunner(),
345 thread_host.ui_thread->GetTaskRunner(),
346 thread_host.io_thread->GetTaskRunner());
347
348 NiceMock<MockDelegate> delegate;
350 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
351 EXPECT_CALL(delegate, GetTaskRunners())
352 .WillRepeatedly(ReturnRef(task_runners));
353 EXPECT_CALL(delegate, OnFrameRasterized(_));
354
355 auto rasterizer = std::make_unique<Rasterizer>(delegate);
356 auto surface = std::make_unique<NiceMock<MockSurface>>();
357
358 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
359 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
360 rasterizer->SetExternalViewEmbedder(external_view_embedder);
361
362 SurfaceFrame::FramebufferInfo framebuffer_info;
363 framebuffer_info.supports_readback = true;
364
365 auto surface_frame = std::make_unique<SurfaceFrame>(
366 /*surface=*/
367 nullptr, framebuffer_info,
368 /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
369 /*frame_size=*/SkISize::Make(800, 600));
370 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true));
371 EXPECT_CALL(*surface, AcquireFrame(SkISize()))
372 .WillOnce(Return(ByMove(std::move(surface_frame))));
373 EXPECT_CALL(*surface, MakeRenderContextCurrent())
374 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
375 EXPECT_CALL(*external_view_embedder, SupportsDynamicThreadMerging)
376 .WillRepeatedly(Return(true));
377
378 EXPECT_CALL(*external_view_embedder, BeginFrame(/*context=*/nullptr,
379 /*raster_thread_merger=*/_))
380 .Times(1);
381 EXPECT_CALL(*external_view_embedder, PrepareFlutterView(
382 /*frame_size=*/SkISize(),
383 /*device_pixel_ratio=*/2.0))
384 .Times(1);
385 EXPECT_CALL(*external_view_embedder,
386 SubmitFlutterView(/*flutter_view_id=*/kImplicitViewId, _, _, _))
387 .Times(1);
388 EXPECT_CALL(*external_view_embedder, EndFrame(/*should_resubmit_frame=*/false,
389 /*raster_thread_merger=*/_))
390 .Times(1);
391
392 rasterizer->Setup(std::move(surface));
393
394 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
395 auto layer_tree = std::make_unique<LayerTree>(/*root_layer=*/nullptr,
396 /*frame_size=*/SkISize());
397 auto layer_tree_item = std::make_unique<FrameItem>(
398 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
399 kDevicePixelRatio),
402 pipeline->Produce().Complete(std::move(layer_tree_item));
403 EXPECT_TRUE(result.success);
404 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
405 rasterizer->Draw(pipeline);
406}
407
408TEST(RasterizerTest,
409 drawLastLayerTreeWithThreadsMergedExternalViewEmbedderAndEndFrameCalled) {
410 std::string test_name =
411 ::testing::UnitTest::GetInstance()->current_test_info()->name();
412 ThreadHost thread_host("io.flutter.test." + test_name + ".",
413 ThreadHost::Type::kPlatform |
414 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
415 ThreadHost::Type::kUi);
417 TaskRunners task_runners("test",
418 fml::MessageLoop::GetCurrent().GetTaskRunner(),
419 fml::MessageLoop::GetCurrent().GetTaskRunner(),
420 thread_host.ui_thread->GetTaskRunner(),
421 thread_host.io_thread->GetTaskRunner());
422
423 NiceMock<MockDelegate> delegate;
425 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
426 EXPECT_CALL(delegate, GetTaskRunners())
427 .WillRepeatedly(ReturnRef(task_runners));
428 EXPECT_CALL(delegate, OnFrameRasterized(_));
429
430 auto rasterizer = std::make_unique<Rasterizer>(delegate);
431 auto surface = std::make_unique<NiceMock<MockSurface>>();
432
433 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
434 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
435 rasterizer->SetExternalViewEmbedder(external_view_embedder);
436
437 SurfaceFrame::FramebufferInfo framebuffer_info;
438 framebuffer_info.supports_readback = true;
439
440 auto surface_frame1 = std::make_unique<SurfaceFrame>(
441 /*surface=*/
442 nullptr, framebuffer_info,
443 /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
444 /*frame_size=*/SkISize::Make(800, 600));
445 auto surface_frame2 = std::make_unique<SurfaceFrame>(
446 /*surface=*/
447 nullptr, framebuffer_info,
448 /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
449 /*frame_size=*/SkISize::Make(800, 600));
450 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled())
451 .WillRepeatedly(Return(true));
452 // Prepare two frames for Draw() and DrawLastLayerTrees().
453 EXPECT_CALL(*surface, AcquireFrame(SkISize()))
454 .WillOnce(Return(ByMove(std::move(surface_frame1))))
455 .WillOnce(Return(ByMove(std::move(surface_frame2))));
456 EXPECT_CALL(*surface, MakeRenderContextCurrent())
457 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
458 EXPECT_CALL(*external_view_embedder, SupportsDynamicThreadMerging)
459 .WillRepeatedly(Return(true));
460
461 EXPECT_CALL(*external_view_embedder, BeginFrame(/*context=*/nullptr,
462 /*raster_thread_merger=*/_))
463 .Times(2);
464 EXPECT_CALL(*external_view_embedder, PrepareFlutterView(
465 /*frame_size=*/SkISize(),
466 /*device_pixel_ratio=*/2.0))
467 .Times(2);
468 EXPECT_CALL(*external_view_embedder,
469 SubmitFlutterView(/*flutter_view_id=*/kImplicitViewId, _, _, _))
470 .Times(2);
471 EXPECT_CALL(*external_view_embedder, EndFrame(/*should_resubmit_frame=*/false,
472 /*raster_thread_merger=*/_))
473 .Times(2);
474
475 rasterizer->Setup(std::move(surface));
476
477 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
478 auto layer_tree = std::make_unique<LayerTree>(/*root_layer=*/nullptr,
479 /*frame_size=*/SkISize());
480 auto layer_tree_item = std::make_unique<FrameItem>(
481 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
482 kDevicePixelRatio),
485 pipeline->Produce().Complete(std::move(layer_tree_item));
486 EXPECT_TRUE(result.success);
487
488 // The Draw() will respectively call BeginFrame(), SubmitFlutterView() and
489 // EndFrame() one time.
490 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
491 rasterizer->Draw(pipeline);
492
493 // The DrawLastLayerTrees() will respectively call BeginFrame(),
494 // SubmitFlutterView() and EndFrame() one more time, totally 2 times.
495 rasterizer->DrawLastLayerTrees(CreateFinishedBuildRecorder());
496}
497
498TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNoSurfaceIsSet) {
499 std::string test_name =
500 ::testing::UnitTest::GetInstance()->current_test_info()->name();
501 ThreadHost thread_host("io.flutter.test." + test_name + ".",
502 ThreadHost::Type::kPlatform |
503 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
504 ThreadHost::Type::kUi);
505 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
506 thread_host.raster_thread->GetTaskRunner(),
507 thread_host.ui_thread->GetTaskRunner(),
508 thread_host.io_thread->GetTaskRunner());
509 NiceMock<MockDelegate> delegate;
511 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
512 EXPECT_CALL(delegate, GetTaskRunners())
513 .WillRepeatedly(ReturnRef(task_runners));
514 auto rasterizer = std::make_unique<Rasterizer>(delegate);
515
516 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
517 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
518 rasterizer->SetExternalViewEmbedder(external_view_embedder);
519
520 EXPECT_CALL(
521 *external_view_embedder,
522 EndFrame(/*should_resubmit_frame=*/false,
523 /*raster_thread_merger=*/fml::RefPtr<fml::RasterThreadMerger>(
524 nullptr)))
525 .Times(0);
526
528 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
529 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
530 auto layer_tree = std::make_unique<LayerTree>(
531 /*root_layer=*/nullptr, /*frame_size=*/SkISize());
532 auto layer_tree_item = std::make_unique<FrameItem>(
533 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
534 kDevicePixelRatio),
537 pipeline->Produce().Complete(std::move(layer_tree_item));
538 EXPECT_TRUE(result.success);
539 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
540 rasterizer->Draw(pipeline);
541 latch.Signal();
542 });
543 latch.Wait();
544}
545
546TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNotUsedThisFrame) {
547 std::string test_name =
548 ::testing::UnitTest::GetInstance()->current_test_info()->name();
549 ThreadHost thread_host("io.flutter.test." + test_name + ".",
550 ThreadHost::Type::kPlatform |
551 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
552 ThreadHost::Type::kUi);
553 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
554 thread_host.raster_thread->GetTaskRunner(),
555 thread_host.ui_thread->GetTaskRunner(),
556 thread_host.io_thread->GetTaskRunner());
557 NiceMock<MockDelegate> delegate;
559 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
560 EXPECT_CALL(delegate, GetTaskRunners())
561 .WillRepeatedly(ReturnRef(task_runners));
562 auto is_gpu_disabled_sync_switch =
563 std::make_shared<const fml::SyncSwitch>(false);
564 ON_CALL(delegate, GetIsGpuDisabledSyncSwitch())
565 .WillByDefault(Return(is_gpu_disabled_sync_switch));
566
567 auto rasterizer = std::make_unique<Rasterizer>(delegate);
568 auto surface = std::make_unique<NiceMock<MockSurface>>();
569 EXPECT_CALL(*surface, MakeRenderContextCurrent())
570 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
571
572 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
573 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
574 rasterizer->SetExternalViewEmbedder(external_view_embedder);
575 rasterizer->Setup(std::move(surface));
576
577 EXPECT_CALL(*external_view_embedder, BeginFrame(/*context=*/nullptr,
578 /*raster_thread_merger=*/_))
579 .Times(0);
580 EXPECT_CALL(*external_view_embedder, PrepareFlutterView(
581 /*frame_size=*/SkISize(),
582 /*device_pixel_ratio=*/2.0))
583 .Times(0);
584 EXPECT_CALL(
585 *external_view_embedder,
586 EndFrame(/*should_resubmit_frame=*/false,
587 /*raster_thread_merger=*/fml::RefPtr<fml::RasterThreadMerger>(
588 nullptr)))
589 .Times(0);
590
592 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
593 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
594 auto layer_tree = std::make_unique<LayerTree>(
595 /*root_layer=*/nullptr, /*frame_size=*/SkISize());
596 auto layer_tree_item = std::make_unique<FrameItem>(
597 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
598 kDevicePixelRatio),
601 pipeline->Produce().Complete(std::move(layer_tree_item));
602 EXPECT_TRUE(result.success);
603 // Always discard the layer tree.
604 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(true));
605 DrawStatus status = rasterizer->Draw(pipeline);
606 EXPECT_EQ(status, DrawStatus::kDone);
607 EXPECT_EQ(rasterizer->GetLastDrawStatus(kImplicitViewId),
609 latch.Signal();
610 });
611 latch.Wait();
612}
613
614TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenPipelineIsEmpty) {
615 std::string test_name =
616 ::testing::UnitTest::GetInstance()->current_test_info()->name();
617 ThreadHost thread_host("io.flutter.test." + test_name + ".",
618 ThreadHost::Type::kPlatform |
619 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
620 ThreadHost::Type::kUi);
621 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
622 thread_host.raster_thread->GetTaskRunner(),
623 thread_host.ui_thread->GetTaskRunner(),
624 thread_host.io_thread->GetTaskRunner());
625 NiceMock<MockDelegate> delegate;
627 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
628 EXPECT_CALL(delegate, GetTaskRunners())
629 .WillRepeatedly(ReturnRef(task_runners));
630
631 auto rasterizer = std::make_unique<Rasterizer>(delegate);
632 auto surface = std::make_unique<NiceMock<MockSurface>>();
633 EXPECT_CALL(*surface, MakeRenderContextCurrent())
634 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
635
636 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
637 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
638 rasterizer->SetExternalViewEmbedder(external_view_embedder);
639 rasterizer->Setup(std::move(surface));
640
641 EXPECT_CALL(
642 *external_view_embedder,
643 EndFrame(/*should_resubmit_frame=*/false,
644 /*raster_thread_merger=*/fml::RefPtr<fml::RasterThreadMerger>(
645 nullptr)))
646 .Times(0);
647
649 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
650 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
651 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
652 DrawStatus status = rasterizer->Draw(pipeline);
653 EXPECT_EQ(status, DrawStatus::kPipelineEmpty);
654 latch.Signal();
655 });
656 latch.Wait();
657}
658
659TEST(RasterizerTest, drawMultipleViewsWithExternalViewEmbedder) {
660 std::string test_name =
661 ::testing::UnitTest::GetInstance()->current_test_info()->name();
662 ThreadHost thread_host("io.flutter.test." + test_name + ".",
663 ThreadHost::Type::kPlatform |
664 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
665 ThreadHost::Type::kUi);
666 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
667 thread_host.raster_thread->GetTaskRunner(),
668 thread_host.ui_thread->GetTaskRunner(),
669 thread_host.io_thread->GetTaskRunner());
670 NiceMock<MockDelegate> delegate;
672 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
673 EXPECT_CALL(delegate, GetTaskRunners())
674 .WillRepeatedly(ReturnRef(task_runners));
675 EXPECT_CALL(delegate, OnFrameRasterized(_));
676 auto rasterizer = std::make_unique<Rasterizer>(delegate);
677 auto surface = std::make_unique<NiceMock<MockSurface>>();
678 std::shared_ptr<NiceMock<MockExternalViewEmbedder>> external_view_embedder =
679 std::make_shared<NiceMock<MockExternalViewEmbedder>>();
680 rasterizer->SetExternalViewEmbedder(external_view_embedder);
681 EXPECT_CALL(*external_view_embedder, SupportsDynamicThreadMerging)
682 .WillRepeatedly(Return(false));
683 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true));
684 EXPECT_CALL(*surface, AcquireFrame(SkISize())).Times(2);
685 ON_CALL(*surface, AcquireFrame).WillByDefault([](const SkISize& size) {
686 SurfaceFrame::FramebufferInfo framebuffer_info;
687 framebuffer_info.supports_readback = true;
688 return std::make_unique<SurfaceFrame>(
689 /*surface=*/
690 nullptr, framebuffer_info,
691 /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
692 /*frame_size=*/SkISize::Make(800, 600));
693 });
694 EXPECT_CALL(*surface, MakeRenderContextCurrent())
695 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
696
697 EXPECT_CALL(*external_view_embedder, BeginFrame(/*context=*/nullptr,
698 /*raster_thread_merger=*/_))
699 .Times(1);
700 EXPECT_CALL(*external_view_embedder,
701 PrepareFlutterView(/*frame_size=*/SkISize(),
702 /*device_pixel_ratio=*/1.5))
703 .Times(1);
704 EXPECT_CALL(*external_view_embedder,
705 SubmitFlutterView(/*flutter_view_id=*/0, _, _, _))
706 .Times(1);
707 EXPECT_CALL(*external_view_embedder,
708 PrepareFlutterView(/*frame_size=*/SkISize(),
709 /*device_pixel_ratio=*/2.0))
710 .Times(1);
711 EXPECT_CALL(*external_view_embedder,
712 SubmitFlutterView(/*flutter_view_id=*/1, _, _, _))
713 .Times(1);
714 EXPECT_CALL(*external_view_embedder, EndFrame(/*should_resubmit_frame=*/false,
715 /*raster_thread_merger=*/_))
716 .Times(1);
717
718 rasterizer->Setup(std::move(surface));
720 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
721 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
722 std::vector<std::unique_ptr<LayerTreeTask>> tasks;
723 tasks.push_back(std::make_unique<LayerTreeTask>(
724 0, std::make_unique<LayerTree>(nullptr, SkISize()), 1.5));
725 tasks.push_back(std::make_unique<LayerTreeTask>(
726 1, std::make_unique<LayerTree>(nullptr, SkISize()), 2.0));
727 auto layer_tree_item = std::make_unique<FrameItem>(
728 std::move(tasks), CreateFinishedBuildRecorder());
730 pipeline->Produce().Complete(std::move(layer_tree_item));
731 EXPECT_TRUE(result.success);
732 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
733 rasterizer->Draw(pipeline);
734 latch.Signal();
735 });
736 latch.Wait();
737}
738
739TEST(RasterizerTest,
740 drawWithGpuEnabledAndSurfaceAllowsDrawingWhenGpuDisabledDoesAcquireFrame) {
741 std::string test_name =
742 ::testing::UnitTest::GetInstance()->current_test_info()->name();
743 ThreadHost thread_host("io.flutter.test." + test_name + ".",
744 ThreadHost::Type::kPlatform |
745 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
746 ThreadHost::Type::kUi);
747 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
748 thread_host.raster_thread->GetTaskRunner(),
749 thread_host.ui_thread->GetTaskRunner(),
750 thread_host.io_thread->GetTaskRunner());
751 NiceMock<MockDelegate> delegate;
753 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
754 EXPECT_CALL(delegate, GetTaskRunners())
755 .WillRepeatedly(ReturnRef(task_runners));
756 EXPECT_CALL(delegate, OnFrameRasterized(_));
757
758 auto rasterizer = std::make_unique<Rasterizer>(delegate);
759 auto surface = std::make_unique<NiceMock<MockSurface>>();
760 auto is_gpu_disabled_sync_switch =
761 std::make_shared<const fml::SyncSwitch>(false);
762
763 SurfaceFrame::FramebufferInfo framebuffer_info;
764 framebuffer_info.supports_readback = true;
765 auto surface_frame = std::make_unique<SurfaceFrame>(
766 /*surface=*/
767 nullptr, /*framebuffer_info=*/framebuffer_info,
768 /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
769 /*frame_size=*/SkISize::Make(800, 600));
770 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true));
771 ON_CALL(delegate, GetIsGpuDisabledSyncSwitch())
772 .WillByDefault(Return(is_gpu_disabled_sync_switch));
773 EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch()).Times(0);
774 EXPECT_CALL(*surface, AcquireFrame(SkISize()))
775 .WillOnce(Return(ByMove(std::move(surface_frame))));
776 EXPECT_CALL(*surface, MakeRenderContextCurrent())
777 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
778
779 rasterizer->Setup(std::move(surface));
781 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
782 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
783 auto layer_tree = std::make_unique<LayerTree>(
784 /*root_layer=*/nullptr, /*frame_size=*/SkISize());
785 auto layer_tree_item = std::make_unique<FrameItem>(
786 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
787 kDevicePixelRatio),
790 pipeline->Produce().Complete(std::move(layer_tree_item));
791 EXPECT_TRUE(result.success);
792 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
793 rasterizer->Draw(pipeline);
794 latch.Signal();
795 });
796 latch.Wait();
797}
798
800 RasterizerTest,
801 drawWithGpuDisabledAndSurfaceAllowsDrawingWhenGpuDisabledDoesAcquireFrame) {
802 std::string test_name =
803 ::testing::UnitTest::GetInstance()->current_test_info()->name();
804 ThreadHost thread_host("io.flutter.test." + test_name + ".",
805 ThreadHost::Type::kPlatform |
806 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
807 ThreadHost::Type::kUi);
808 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
809 thread_host.raster_thread->GetTaskRunner(),
810 thread_host.ui_thread->GetTaskRunner(),
811 thread_host.io_thread->GetTaskRunner());
812 NiceMock<MockDelegate> delegate;
814 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
815 EXPECT_CALL(delegate, GetTaskRunners())
816 .WillRepeatedly(ReturnRef(task_runners));
817 EXPECT_CALL(delegate, OnFrameRasterized(_));
818 auto rasterizer = std::make_unique<Rasterizer>(delegate);
819 auto surface = std::make_unique<NiceMock<MockSurface>>();
820 auto is_gpu_disabled_sync_switch =
821 std::make_shared<const fml::SyncSwitch>(true);
822
823 SurfaceFrame::FramebufferInfo framebuffer_info;
824 framebuffer_info.supports_readback = true;
825
826 auto surface_frame = std::make_unique<SurfaceFrame>(
827 /*surface=*/
828 nullptr, /*framebuffer_info=*/framebuffer_info,
829 /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
830 /*frame_size=*/SkISize::Make(800, 600));
831 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true));
832 ON_CALL(delegate, GetIsGpuDisabledSyncSwitch())
833 .WillByDefault(Return(is_gpu_disabled_sync_switch));
834 EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch()).Times(0);
835 EXPECT_CALL(*surface, AcquireFrame(SkISize()))
836 .WillOnce(Return(ByMove(std::move(surface_frame))));
837 EXPECT_CALL(*surface, MakeRenderContextCurrent())
838 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
839
840 rasterizer->Setup(std::move(surface));
842 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
843 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
844 auto layer_tree = std::make_unique<LayerTree>(
845 /*root_layer=*/nullptr, /*frame_size=*/SkISize());
846 auto layer_tree_item = std::make_unique<FrameItem>(
847 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
848 kDevicePixelRatio),
851 pipeline->Produce().Complete(std::move(layer_tree_item));
852 EXPECT_TRUE(result.success);
853 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
854 DrawStatus status = rasterizer->Draw(pipeline);
855 EXPECT_EQ(status, DrawStatus::kDone);
856 latch.Signal();
857 });
858 latch.Wait();
859}
860
862 RasterizerTest,
863 drawWithGpuEnabledAndSurfaceDisallowsDrawingWhenGpuDisabledDoesAcquireFrame) {
864 std::string test_name =
865 ::testing::UnitTest::GetInstance()->current_test_info()->name();
866 ThreadHost thread_host("io.flutter.test." + test_name + ".",
867 ThreadHost::Type::kPlatform |
868 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
869 ThreadHost::Type::kUi);
870 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
871 thread_host.raster_thread->GetTaskRunner(),
872 thread_host.ui_thread->GetTaskRunner(),
873 thread_host.io_thread->GetTaskRunner());
874 NiceMock<MockDelegate> delegate;
876 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
877 EXPECT_CALL(delegate, GetTaskRunners())
878 .WillRepeatedly(ReturnRef(task_runners));
879 EXPECT_CALL(delegate, OnFrameRasterized(_));
880 auto rasterizer = std::make_unique<Rasterizer>(delegate);
881 auto surface = std::make_unique<NiceMock<MockSurface>>();
882 auto is_gpu_disabled_sync_switch =
883 std::make_shared<const fml::SyncSwitch>(false);
884
885 SurfaceFrame::FramebufferInfo framebuffer_info;
886 framebuffer_info.supports_readback = true;
887
888 auto surface_frame = std::make_unique<SurfaceFrame>(
889 /*surface=*/
890 nullptr, /*framebuffer_info=*/framebuffer_info,
891 /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
892 /*frame_size=*/SkISize::Make(800, 600));
893 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(false));
894 EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch())
895 .WillOnce(Return(is_gpu_disabled_sync_switch));
896 EXPECT_CALL(*surface, AcquireFrame(SkISize()))
897 .WillOnce(Return(ByMove(std::move(surface_frame))));
898 EXPECT_CALL(*surface, MakeRenderContextCurrent())
899 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
900
901 rasterizer->Setup(std::move(surface));
903 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
904 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
905 auto layer_tree = std::make_unique<LayerTree>(
906 /*root_layer=*/nullptr, /*frame_size=*/SkISize());
907 auto layer_tree_item = std::make_unique<FrameItem>(
908 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
909 kDevicePixelRatio),
912 pipeline->Produce().Complete(std::move(layer_tree_item));
913 EXPECT_TRUE(result.success);
914 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
915 DrawStatus status = rasterizer->Draw(pipeline);
916 EXPECT_EQ(status, DrawStatus::kDone);
917 latch.Signal();
918 });
919 latch.Wait();
920}
921
923 RasterizerTest,
924 drawWithGpuDisabledAndSurfaceDisallowsDrawingWhenGpuDisabledDoesntAcquireFrame) {
925 std::string test_name =
926 ::testing::UnitTest::GetInstance()->current_test_info()->name();
927 ThreadHost thread_host("io.flutter.test." + test_name + ".",
928 ThreadHost::Type::kPlatform |
929 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
930 ThreadHost::Type::kUi);
931 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
932 thread_host.raster_thread->GetTaskRunner(),
933 thread_host.ui_thread->GetTaskRunner(),
934 thread_host.io_thread->GetTaskRunner());
935 NiceMock<MockDelegate> delegate;
937 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
938 EXPECT_CALL(delegate, GetTaskRunners())
939 .WillRepeatedly(ReturnRef(task_runners));
940 EXPECT_CALL(delegate, OnFrameRasterized(_)).Times(0);
941 auto rasterizer = std::make_unique<Rasterizer>(delegate);
942 auto surface = std::make_unique<NiceMock<MockSurface>>();
943 auto is_gpu_disabled_sync_switch =
944 std::make_shared<const fml::SyncSwitch>(true);
945
946 SurfaceFrame::FramebufferInfo framebuffer_info;
947 framebuffer_info.supports_readback = true;
948
949 auto surface_frame = std::make_unique<SurfaceFrame>(
950 /*surface=*/
951 nullptr, /*framebuffer_info=*/framebuffer_info,
952 /*submit_callback=*/[](const SurfaceFrame&, DlCanvas*) { return true; },
953 /*frame_size=*/SkISize::Make(800, 600));
954 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(false));
955 EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch())
956 .WillOnce(Return(is_gpu_disabled_sync_switch));
957 EXPECT_CALL(*surface, AcquireFrame(SkISize())).Times(0);
958 EXPECT_CALL(*surface, MakeRenderContextCurrent())
959 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
960
961 rasterizer->Setup(std::move(surface));
963 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
964 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
965 auto layer_tree = std::make_unique<LayerTree>(
966 /*root_layer=*/nullptr, /*frame_size=*/SkISize());
967 auto layer_tree_item = std::make_unique<FrameItem>(
968 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
969 kDevicePixelRatio),
972 pipeline->Produce().Complete(std::move(layer_tree_item));
973 EXPECT_TRUE(result.success);
974 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
975 DrawStatus status = rasterizer->Draw(pipeline);
976 EXPECT_EQ(status, DrawStatus::kGpuUnavailable);
977 latch.Signal();
978 });
979 latch.Wait();
980}
981
983 RasterizerTest,
984 FrameTimingRecorderShouldStartRecordingRasterTimeBeforeSurfaceAcquireFrame) {
985 std::string test_name =
986 ::testing::UnitTest::GetInstance()->current_test_info()->name();
987 ThreadHost thread_host("io.flutter.test." + test_name + ".",
988 ThreadHost::Type::kPlatform |
989 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
990 ThreadHost::Type::kUi);
991 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
992 thread_host.raster_thread->GetTaskRunner(),
993 thread_host.ui_thread->GetTaskRunner(),
994 thread_host.io_thread->GetTaskRunner());
995 NiceMock<MockDelegate> delegate;
997 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
998 EXPECT_CALL(delegate, GetTaskRunners())
999 .WillRepeatedly(ReturnRef(task_runners));
1000 EXPECT_CALL(delegate, OnFrameRasterized(_))
1001 .WillOnce([&](const FrameTiming& frame_timing) {
1003 fml::TimePoint raster_start =
1004 frame_timing.Get(FrameTiming::kRasterStart);
1005 EXPECT_TRUE(now - raster_start < fml::TimeDelta::FromSecondsF(1));
1006 });
1007
1008 auto rasterizer = std::make_unique<Rasterizer>(delegate);
1009 auto surface = std::make_unique<NiceMock<MockSurface>>();
1010 auto is_gpu_disabled_sync_switch =
1011 std::make_shared<const fml::SyncSwitch>(false);
1012 ON_CALL(delegate, GetIsGpuDisabledSyncSwitch())
1013 .WillByDefault(Return(is_gpu_disabled_sync_switch));
1014 ON_CALL(*surface, AcquireFrame(SkISize()))
1015 .WillByDefault(::testing::Invoke([] { return nullptr; }));
1016 EXPECT_CALL(*surface, AcquireFrame(SkISize()));
1017 EXPECT_CALL(*surface, MakeRenderContextCurrent())
1018 .WillOnce(Return(ByMove(std::make_unique<GLContextDefaultResult>(true))));
1019 rasterizer->Setup(std::move(surface));
1021 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1022 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
1023 auto layer_tree = std::make_unique<LayerTree>(
1024 /*root_layer=*/nullptr, /*frame_size=*/SkISize());
1025 auto layer_tree_item = std::make_unique<FrameItem>(
1026 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
1027 kDevicePixelRatio),
1030 pipeline->Produce().Complete(std::move(layer_tree_item));
1031 EXPECT_TRUE(result.success);
1032 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
1033 DrawStatus status = rasterizer->Draw(pipeline);
1034 EXPECT_EQ(status, DrawStatus::kDone);
1035 EXPECT_EQ(rasterizer->GetLastDrawStatus(kImplicitViewId),
1037 latch.Signal();
1038 });
1039 latch.Wait();
1040}
1041
1042TEST(RasterizerTest,
1043 drawLayerTreeWithCorrectFrameTimingWhenPipelineIsMoreAvailable) {
1044 std::string test_name =
1045 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1046 ThreadHost thread_host("io.flutter.test." + test_name + ".",
1047 ThreadHost::Type::kPlatform |
1048 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
1049 ThreadHost::Type::kUi);
1050 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
1051 thread_host.raster_thread->GetTaskRunner(),
1052 thread_host.ui_thread->GetTaskRunner(),
1053 thread_host.io_thread->GetTaskRunner());
1054 NiceMock<MockDelegate> delegate;
1056 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
1057 ON_CALL(delegate, GetTaskRunners()).WillByDefault(ReturnRef(task_runners));
1058
1060 std::unique_ptr<Rasterizer> rasterizer;
1061 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1062 rasterizer = std::make_unique<Rasterizer>(delegate);
1063 latch.Signal();
1064 });
1065 latch.Wait();
1066
1067 auto surface = std::make_unique<NiceMock<MockSurface>>();
1068 EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled())
1069 .WillRepeatedly(Return(true));
1070 ON_CALL(*surface, AcquireFrame(SkISize()))
1071 .WillByDefault(::testing::Invoke([] {
1072 SurfaceFrame::FramebufferInfo framebuffer_info;
1073 framebuffer_info.supports_readback = true;
1074 return std::make_unique<SurfaceFrame>(
1075 /*surface=*/
1076 nullptr, framebuffer_info,
1077 /*submit_callback=*/
1078 [](const SurfaceFrame& frame, DlCanvas*) { return true; },
1079 /*frame_size=*/SkISize::Make(800, 600));
1080 }));
1081 ON_CALL(*surface, MakeRenderContextCurrent())
1082 .WillByDefault(::testing::Invoke(
1083 [] { return std::make_unique<GLContextDefaultResult>(true); }));
1084
1085 fml::CountDownLatch count_down_latch(2);
1086 auto first_timestamp = fml::TimePoint::Now();
1087 auto second_timestamp = first_timestamp + fml::TimeDelta::FromMilliseconds(8);
1088 std::vector<fml::TimePoint> timestamps = {first_timestamp, second_timestamp};
1089 int frame_rasterized_count = 0;
1090 EXPECT_CALL(delegate, OnFrameRasterized(_))
1091 .Times(2)
1092 .WillRepeatedly([&](const FrameTiming& frame_timing) {
1093 EXPECT_EQ(timestamps[frame_rasterized_count],
1094 frame_timing.Get(FrameTiming::kVsyncStart));
1095 EXPECT_EQ(timestamps[frame_rasterized_count],
1096 frame_timing.Get(FrameTiming::kBuildStart));
1097 EXPECT_EQ(timestamps[frame_rasterized_count],
1098 frame_timing.Get(FrameTiming::kBuildFinish));
1099 frame_rasterized_count++;
1100 count_down_latch.CountDown();
1101 });
1102
1103 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1104 rasterizer->Setup(std::move(surface));
1105 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
1106 for (int i = 0; i < 2; i++) {
1107 auto layer_tree = std::make_unique<LayerTree>(
1108 /*root_layer=*/nullptr, /*frame_size=*/SkISize());
1109 auto layer_tree_item = std::make_unique<FrameItem>(
1110 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
1111 kDevicePixelRatio),
1112 CreateFinishedBuildRecorder(timestamps[i]));
1114 pipeline->Produce().Complete(std::move(layer_tree_item));
1115 EXPECT_TRUE(result.success);
1116 EXPECT_EQ(result.is_first_item, i == 0);
1117 }
1118 // Although we only call 'Rasterizer::Draw' once, it will be called twice
1119 // finally because there are two items in the pipeline.
1120 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
1121 rasterizer->Draw(pipeline);
1122 });
1123 count_down_latch.Wait();
1124 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1125 rasterizer.reset();
1126 latch.Signal();
1127 });
1128 latch.Wait();
1129}
1130
1131TEST(RasterizerTest, TeardownFreesResourceCache) {
1132 std::string test_name =
1133 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1134 ThreadHost thread_host("io.flutter.test." + test_name + ".",
1135 ThreadHost::Type::kPlatform |
1136 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
1137 ThreadHost::Type::kUi);
1138 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
1139 thread_host.raster_thread->GetTaskRunner(),
1140 thread_host.ui_thread->GetTaskRunner(),
1141 thread_host.io_thread->GetTaskRunner());
1142
1143 NiceMock<MockDelegate> delegate;
1145 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
1146 EXPECT_CALL(delegate, GetTaskRunners())
1147 .WillRepeatedly(ReturnRef(task_runners));
1148
1149 auto rasterizer = std::make_unique<Rasterizer>(delegate);
1150 auto surface = std::make_unique<NiceMock<MockSurface>>();
1151 auto context = GrDirectContext::MakeMock(nullptr);
1152 context->setResourceCacheLimit(0);
1153
1154 EXPECT_CALL(*surface, MakeRenderContextCurrent())
1155 .WillRepeatedly([]() -> std::unique_ptr<GLContextResult> {
1156 return std::make_unique<GLContextDefaultResult>(true);
1157 });
1158 EXPECT_CALL(*surface, GetContext()).WillRepeatedly(Return(context.get()));
1159
1160 rasterizer->Setup(std::move(surface));
1161 EXPECT_EQ(context->getResourceCacheLimit(), 0ul);
1162
1163 rasterizer->SetResourceCacheMaxBytes(10000000, false);
1164 EXPECT_EQ(context->getResourceCacheLimit(), 10000000ul);
1165 EXPECT_EQ(context->getResourceCachePurgeableBytes(), 0ul);
1166
1167 int count = 0;
1168 size_t bytes = 0;
1169 context->getResourceCacheUsage(&count, &bytes);
1170 EXPECT_EQ(bytes, 0ul);
1171
1172 auto image_info =
1174 auto sk_surface = SkSurfaces::RenderTarget(context.get(),
1175 skgpu::Budgeted::kYes, image_info);
1176 EXPECT_TRUE(sk_surface);
1177
1178 SkPaint paint;
1179 sk_surface->getCanvas()->drawPaint(paint);
1180 context->flushAndSubmit(GrSyncCpu::kYes);
1181
1182 EXPECT_EQ(context->getResourceCachePurgeableBytes(), 0ul);
1183
1184 sk_surface.reset();
1185
1186 context->getResourceCacheUsage(&count, &bytes);
1187 EXPECT_GT(bytes, 0ul);
1188 EXPECT_GT(context->getResourceCachePurgeableBytes(), 0ul);
1189
1190 rasterizer->Teardown();
1191 EXPECT_EQ(context->getResourceCachePurgeableBytes(), 0ul);
1192}
1193
1194TEST(RasterizerTest, TeardownNoSurface) {
1195 std::string test_name =
1196 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1197 ThreadHost thread_host("io.flutter.test." + test_name + ".",
1198 ThreadHost::Type::kPlatform |
1199 ThreadHost::Type::kRaster | ThreadHost::Type::kIo |
1200 ThreadHost::Type::kUi);
1201 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
1202 thread_host.raster_thread->GetTaskRunner(),
1203 thread_host.ui_thread->GetTaskRunner(),
1204 thread_host.io_thread->GetTaskRunner());
1205
1206 NiceMock<MockDelegate> delegate;
1208 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
1209 EXPECT_CALL(delegate, GetTaskRunners())
1210 .WillRepeatedly(ReturnRef(task_runners));
1211
1212 auto rasterizer = std::make_unique<Rasterizer>(delegate);
1213
1214 EXPECT_TRUE(rasterizer);
1215 rasterizer->Teardown();
1216}
1217
1218TEST(RasterizerTest, presentationTimeSetWhenVsyncTargetInFuture) {
1219 GTEST_SKIP() << "eglPresentationTime is disabled due to "
1220 "https://github.com/flutter/flutter/issues/112503";
1221#if false
1222 std::string test_name =
1223 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1224 ThreadHost thread_host("io.flutter.test." + test_name + ".",
1225 ThreadHost::Type::kPlatform | ThreadHost::Type::kRaster |
1226 ThreadHost::Type::kIo | ThreadHost::Type::kUi);
1227 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
1228 thread_host.raster_thread->GetTaskRunner(),
1229 thread_host.ui_thread->GetTaskRunner(),
1230 thread_host.io_thread->GetTaskRunner());
1231
1232 NiceMock<MockDelegate> delegate;
1234 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
1235 ON_CALL(delegate, GetTaskRunners()).WillByDefault(ReturnRef(task_runners));
1236
1238 std::unique_ptr<Rasterizer> rasterizer;
1239 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1240 rasterizer = std::make_unique<Rasterizer>(delegate);
1241 latch.Signal();
1242 });
1243 latch.Wait();
1244
1245 const auto millis_16 = fml::TimeDelta::FromMilliseconds(16);
1246 const auto first_timestamp = fml::TimePoint::Now() + millis_16;
1247 auto second_timestamp = first_timestamp + millis_16;
1248 std::vector<fml::TimePoint> timestamps = {first_timestamp, second_timestamp};
1249
1250 int frames_submitted = 0;
1251 fml::CountDownLatch submit_latch(2);
1252 auto surface = std::make_unique<MockSurface>();
1253 ON_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillByDefault(Return(true));
1254 ON_CALL(*surface, AcquireFrame(SkISize()))
1255 .WillByDefault(::testing::Invoke([&] {
1256 SurfaceFrame::FramebufferInfo framebuffer_info;
1257 framebuffer_info.supports_readback = true;
1258 return std::make_unique<SurfaceFrame>(
1259 /*surface=*/nullptr, framebuffer_info,
1260 /*submit_callback=*/
1261 [&](const SurfaceFrame& frame, DlCanvas*) {
1262 const auto pres_time = *frame.submit_info().presentation_time;
1263 const auto diff = pres_time - first_timestamp;
1264 int num_frames_submitted = frames_submitted++;
1265 EXPECT_EQ(diff.ToMilliseconds(),
1266 num_frames_submitted * millis_16.ToMilliseconds());
1267 submit_latch.CountDown();
1268 return true;
1269 },
1270 /*frame_size=*/SkISize::Make(800, 600));
1271 }));
1272
1273 ON_CALL(*surface, MakeRenderContextCurrent())
1274 .WillByDefault(::testing::Invoke(
1275 [] { return std::make_unique<GLContextDefaultResult>(true); }));
1276
1277 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1278 rasterizer->Setup(std::move(surface));
1279 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
1280 for (int i = 0; i < 2; i++) {
1281 auto layer_tree = std::make_unique<LayerTree>(
1282 /*root_layer=*/nullptr, /*frame_size=*/SkISize());
1283 auto layer_tree_item = std::make_unique<FrameItem>(
1284 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
1285 kDevicePixelRatio),
1286 CreateFinishedBuildRecorder(timestamps[i]));
1288 pipeline->Produce().Complete(std::move(layer_tree_item));
1289 EXPECT_TRUE(result.success);
1290 EXPECT_EQ(result.is_first_item, i == 0);
1291 }
1292 // Although we only call 'Rasterizer::Draw' once, it will be called twice
1293 // finally because there are two items in the pipeline.
1294 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
1295 rasterizer->Draw(pipeline);
1296 });
1297
1298 submit_latch.Wait();
1299 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1300 rasterizer.reset();
1301 latch.Signal();
1302 });
1303 latch.Wait();
1304#endif // false
1305}
1306
1307TEST(RasterizerTest, presentationTimeNotSetWhenVsyncTargetInPast) {
1308 GTEST_SKIP() << "eglPresentationTime is disabled due to "
1309 "https://github.com/flutter/flutter/issues/112503";
1310#if false
1311 std::string test_name =
1312 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1313 ThreadHost thread_host("io.flutter.test." + test_name + ".",
1314 ThreadHost::Type::kPlatform | ThreadHost::Type::kRaster |
1315 ThreadHost::Type::kIo | ThreadHost::Type::kUi);
1316 TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
1317 thread_host.raster_thread->GetTaskRunner(),
1318 thread_host.ui_thread->GetTaskRunner(),
1319 thread_host.io_thread->GetTaskRunner());
1320
1321 NiceMock<MockDelegate> delegate;
1323 ON_CALL(delegate, GetSettings()).WillByDefault(ReturnRef(settings));
1324 ON_CALL(delegate, GetTaskRunners()).WillByDefault(ReturnRef(task_runners));
1325
1327 std::unique_ptr<Rasterizer> rasterizer;
1328 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1329 rasterizer = std::make_unique<Rasterizer>(delegate);
1330 latch.Signal();
1331 });
1332 latch.Wait();
1333
1334 const auto millis_16 = fml::TimeDelta::FromMilliseconds(16);
1335 const auto first_timestamp = fml::TimePoint::Now() - millis_16;
1336
1337 fml::CountDownLatch submit_latch(1);
1338 auto surface = std::make_unique<MockSurface>();
1339 ON_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillByDefault(Return(true));
1340 ON_CALL(*surface, AcquireFrame(SkISize()))
1341 .WillByDefault(::testing::Invoke([&] {
1342 SurfaceFrame::FramebufferInfo framebuffer_info;
1343 framebuffer_info.supports_readback = true;
1344 return std::make_unique<SurfaceFrame>(
1345 /*surface=*/nullptr, framebuffer_info,
1346 /*submit_callback=*/
1347 [&](const SurfaceFrame& frame, DlCanvas*) {
1348 const std::optional<fml::TimePoint> pres_time =
1349 frame.submit_info().presentation_time;
1350 EXPECT_EQ(pres_time, std::nullopt);
1351 submit_latch.CountDown();
1352 return true;
1353 },
1354 /*frame_size=*/SkISize::Make(800, 600));
1355 }));
1356
1357 ON_CALL(*surface, MakeRenderContextCurrent())
1358 .WillByDefault(::testing::Invoke(
1359 [] { return std::make_unique<GLContextDefaultResult>(true); }));
1360
1361 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1362 rasterizer->Setup(std::move(surface));
1363 auto pipeline = std::make_shared<FramePipeline>(/*depth=*/10);
1364 auto layer_tree = std::make_unique<LayerTree>(
1365 /*root_layer=*/nullptr, /*frame_size=*/SkISize());
1366 auto layer_tree_item = std::make_unique<FrameItem>(
1367 SingleLayerTreeList(kImplicitViewId, std::move(layer_tree),
1368 kDevicePixelRatio),
1369 CreateFinishedBuildRecorder(first_timestamp));
1371 pipeline->Produce().Complete(std::move(layer_tree_item));
1372 EXPECT_TRUE(result.success);
1373 EXPECT_EQ(result.is_first_item, true);
1374 ON_CALL(delegate, ShouldDiscardLayerTree).WillByDefault(Return(false));
1375 rasterizer->Draw(pipeline);
1376 });
1377
1378 submit_latch.Wait();
1379 thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
1380 rasterizer.reset();
1381 latch.Signal();
1382 });
1383 latch.Wait();
1384#endif // false
1385}
1386
1387} // namespace flutter
int count
Definition: FontMgrTest.cpp:50
static sk_sp< GrDirectContext > MakeMock(const GrMockOptions *, const GrContextOptions &)
static sk_sp< SkColorSpace > MakeSRGB()
Developer-facing API for rendering anything within the engine.
Definition: dl_canvas.h:38
fml::TimePoint Get(Phase phase) const
Definition: settings.h:51
static void EnsureInitializedForCurrentThread()
Definition: message_loop.cc:27
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
Definition: message_loop.cc:19
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 Paint & paint
Definition: color_source.cc:38
@ kRaster
Suitable for thread which raster data.
Definition: embedder.h:266
const EmbeddedViewParams * params
VkSurfaceKHR surface
Definition: main.cc:49
double frame
Definition: examples.cpp:31
GAsyncResult * result
SK_API GrDirectContext * GetContext(const SkImage *src)
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
Definition: create.py:1
ObjectPtr Invoke(const Library &lib, const char *name)
static std::unique_ptr< FrameTimingsRecorder > CreateFinishedBuildRecorder(fml::TimePoint timestamp)
TEST(FrameTimingsRecorderTest, RecordVsync)
constexpr FlutterViewId kImplicitViewId
it will be possible to load the file into Perfetto s trace viewer 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
Definition: switches.h:259
std::chrono::duration< double, std::milli > Milliseconds
Definition: time_delta.h:18
flutter::DlCanvas DlCanvas
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
static SkImageInfo MakeN32Premul(int width, int height)
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
#define EXPECT_TRUE(handle)
Definition: unit_test.h:678