Flutter Engine
The Flutter Engine
raster_thread_merger_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/fml/raster_thread_merger.h"
8
9#include <thread>
10
11#include "flutter/fml/memory/ref_ptr.h"
12#include "flutter/fml/message_loop.h"
13#include "flutter/fml/synchronization/count_down_latch.h"
14#include "flutter/fml/synchronization/waitable_event.h"
15#include "flutter/fml/task_runner.h"
16#include "flutter/fml/thread.h"
17#include "gtest/gtest.h"
18
19namespace fml {
20namespace testing {
21
22/// A mock task queue NOT calling MessageLoop->Run() in thread
25
26 /// The waiter for message loop initialized ok
28
29 /// The waiter for thread finished
31
32 /// This field must below latch and term member, because
33 /// cpp standard reference:
34 /// non-static data members are initialized in the order they were declared in
35 /// the class definition
36 std::thread thread;
37
39 : thread([this]() {
42 latch.Signal();
43 term.Wait();
44 }) {
45 latch.Wait();
46 }
47
49 term.Signal();
50 thread.join();
51 }
52
55 }
56};
57
58TEST(RasterThreadMerger, RemainMergedTillLeaseExpires) {
59 TaskQueueWrapper queue1;
60 TaskQueueWrapper queue2;
61 fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
62 fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
63 const auto raster_thread_merger =
64 fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
65 const size_t kNumFramesMerged = 5;
66
67 ASSERT_FALSE(raster_thread_merger->IsMerged());
68
69 raster_thread_merger->MergeWithLease(kNumFramesMerged);
70
71 for (size_t i = 0; i < kNumFramesMerged; i++) {
72 ASSERT_TRUE(raster_thread_merger->IsMerged());
73 raster_thread_merger->DecrementLease();
74 }
75
76 ASSERT_FALSE(raster_thread_merger->IsMerged());
77}
78
79TEST(RasterThreadMerger, IsNotOnRasterizingThread) {
80 fml::MessageLoop* loop1 = nullptr;
82 std::thread thread1([&loop1, &latch1]() {
85 loop1->GetTaskRunner()->PostTask([&]() { latch1.Signal(); });
86 loop1->Run();
87 });
88
89 fml::MessageLoop* loop2 = nullptr;
91 std::thread thread2([&loop2, &latch2]() {
94 loop2->GetTaskRunner()->PostTask([&]() { latch2.Signal(); });
95 loop2->Run();
96 });
97
98 latch1.Wait();
99 latch2.Wait();
100
101 fml::TaskQueueId qid1 = loop1->GetTaskRunner()->GetTaskQueueId();
102 fml::TaskQueueId qid2 = loop2->GetTaskRunner()->GetTaskQueueId();
103 const auto raster_thread_merger =
104 fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
105
106 fml::CountDownLatch pre_merge(2), post_merge(2), post_unmerge(2);
107
108 loop1->GetTaskRunner()->PostTask([&]() {
109 ASSERT_FALSE(raster_thread_merger->IsOnRasterizingThread());
110 ASSERT_TRUE(raster_thread_merger->IsOnPlatformThread());
112 pre_merge.CountDown();
113 });
114
115 loop2->GetTaskRunner()->PostTask([&]() {
116 ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
117 ASSERT_FALSE(raster_thread_merger->IsOnPlatformThread());
119 pre_merge.CountDown();
120 });
121
122 pre_merge.Wait();
123
124 raster_thread_merger->MergeWithLease(1);
125
126 loop1->GetTaskRunner()->PostTask([&]() {
127 ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
128 ASSERT_TRUE(raster_thread_merger->IsOnPlatformThread());
130 post_merge.CountDown();
131 });
132
133 loop2->GetTaskRunner()->PostTask([&]() {
134 // this will be false since this is going to be run
135 // on loop1 really.
136 ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
137 ASSERT_TRUE(raster_thread_merger->IsOnPlatformThread());
139 post_merge.CountDown();
140 });
141
142 post_merge.Wait();
143
144 raster_thread_merger->DecrementLease();
145
146 loop1->GetTaskRunner()->PostTask([&]() {
147 ASSERT_FALSE(raster_thread_merger->IsOnRasterizingThread());
148 ASSERT_TRUE(raster_thread_merger->IsOnPlatformThread());
150 post_unmerge.CountDown();
151 });
152
153 loop2->GetTaskRunner()->PostTask([&]() {
154 ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
155 ASSERT_FALSE(raster_thread_merger->IsOnPlatformThread());
157 post_unmerge.CountDown();
158 });
159
160 post_unmerge.Wait();
161
162 loop1->GetTaskRunner()->PostTask([&]() { loop1->Terminate(); });
163
164 loop2->GetTaskRunner()->PostTask([&]() { loop2->Terminate(); });
165
166 thread1.join();
167 thread2.join();
168}
169
170TEST(RasterThreadMerger, LeaseExtension) {
171 TaskQueueWrapper queue1;
172 TaskQueueWrapper queue2;
173
174 fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
175 fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
176 const auto raster_thread_merger =
177 fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
178 const size_t kNumFramesMerged = 5;
179
180 ASSERT_FALSE(raster_thread_merger->IsMerged());
181
182 raster_thread_merger->MergeWithLease(kNumFramesMerged);
183
184 // let there be one more turn till the leases expire.
185 for (size_t i = 0; i < kNumFramesMerged - 1; i++) {
186 ASSERT_TRUE(raster_thread_merger->IsMerged());
187 raster_thread_merger->DecrementLease();
188 }
189
190 // extend the lease once.
191 raster_thread_merger->ExtendLeaseTo(kNumFramesMerged);
192
193 // we will NOT last for 1 extra turn, we just set it.
194 for (size_t i = 0; i < kNumFramesMerged; i++) {
195 ASSERT_TRUE(raster_thread_merger->IsMerged());
196 raster_thread_merger->DecrementLease();
197 }
198
199 ASSERT_FALSE(raster_thread_merger->IsMerged());
200}
201
202TEST(RasterThreadMerger, WaitUntilMerged) {
203 fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger;
204
205 fml::AutoResetWaitableEvent create_thread_merger_latch;
206 fml::MessageLoop* loop_platform = nullptr;
207 fml::AutoResetWaitableEvent latch_platform;
208 fml::AutoResetWaitableEvent term_platform;
209 fml::AutoResetWaitableEvent latch_merged;
210 std::thread thread_platform([&]() {
212 loop_platform = &fml::MessageLoop::GetCurrent();
213 latch_platform.Signal();
214 create_thread_merger_latch.Wait();
215 raster_thread_merger->WaitUntilMerged();
216 latch_merged.Signal();
217 term_platform.Wait();
218 });
219
220 const size_t kNumFramesMerged = 5;
221 fml::MessageLoop* loop_raster = nullptr;
222 fml::AutoResetWaitableEvent term_raster;
223 std::thread thread_raster([&]() {
225 loop_raster = &fml::MessageLoop::GetCurrent();
226 latch_platform.Wait();
227 fml::TaskQueueId qid_platform =
228 loop_platform->GetTaskRunner()->GetTaskQueueId();
229 fml::TaskQueueId qid_raster =
230 loop_raster->GetTaskRunner()->GetTaskQueueId();
231 raster_thread_merger =
232 fml::MakeRefCounted<fml::RasterThreadMerger>(qid_platform, qid_raster);
233 ASSERT_FALSE(raster_thread_merger->IsMerged());
234 create_thread_merger_latch.Signal();
235 raster_thread_merger->MergeWithLease(kNumFramesMerged);
236 term_raster.Wait();
237 });
238
239 latch_merged.Wait();
240 ASSERT_TRUE(raster_thread_merger->IsMerged());
241
242 for (size_t i = 0; i < kNumFramesMerged; i++) {
243 ASSERT_TRUE(raster_thread_merger->IsMerged());
244 raster_thread_merger->DecrementLease();
245 }
246
247 ASSERT_FALSE(raster_thread_merger->IsMerged());
248
249 term_platform.Signal();
250 term_raster.Signal();
251 thread_platform.join();
252 thread_raster.join();
253}
254
255TEST(RasterThreadMerger, HandleTaskQueuesAreTheSame) {
257 fml::TaskQueueId qid1 = queue.GetTaskQueueId();
258 fml::TaskQueueId qid2 = qid1;
259 const auto raster_thread_merger =
260 fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
261 // Statically merged.
262 ASSERT_TRUE(raster_thread_merger->IsMerged());
263
264 // Test decrement lease and unmerge are both no-ops.
265 // The task queues should be always merged.
266 const size_t kNumFramesMerged = 5;
267 raster_thread_merger->MergeWithLease(kNumFramesMerged);
268
269 for (size_t i = 0; i < kNumFramesMerged; i++) {
270 ASSERT_TRUE(raster_thread_merger->IsMerged());
271 raster_thread_merger->DecrementLease();
272 }
273
274 ASSERT_TRUE(raster_thread_merger->IsMerged());
275
276 // Wait until merged should also return immediately.
277 raster_thread_merger->WaitUntilMerged();
278 ASSERT_TRUE(raster_thread_merger->IsMerged());
279}
280
282 TaskQueueWrapper queue1;
283 TaskQueueWrapper queue2;
284 fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
285 fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
286 const auto raster_thread_merger =
287 fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
288
289 raster_thread_merger->Disable();
290 raster_thread_merger->MergeWithLease(1);
291 ASSERT_FALSE(raster_thread_merger->IsMerged());
292
293 raster_thread_merger->Enable();
294 ASSERT_FALSE(raster_thread_merger->IsMerged());
295
296 raster_thread_merger->MergeWithLease(1);
297 ASSERT_TRUE(raster_thread_merger->IsMerged());
298
299 raster_thread_merger->DecrementLease();
300 ASSERT_FALSE(raster_thread_merger->IsMerged());
301}
302
304 TaskQueueWrapper queue1;
305 TaskQueueWrapper queue2;
306 fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
307 fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
308 const auto raster_thread_merger =
309 fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
310
311 raster_thread_merger->Disable();
312 ASSERT_FALSE(raster_thread_merger->IsMerged());
313
314 raster_thread_merger->MergeWithLease(1);
315 ASSERT_FALSE(raster_thread_merger->IsMerged());
316
317 raster_thread_merger->Enable();
318 raster_thread_merger->MergeWithLease(1);
319 ASSERT_TRUE(raster_thread_merger->IsMerged());
320
321 raster_thread_merger->Disable();
322 raster_thread_merger->UnMergeNowIfLastOne();
323 ASSERT_TRUE(raster_thread_merger->IsMerged());
324
325 {
326 auto decrement_result = raster_thread_merger->DecrementLease();
327 ASSERT_EQ(fml::RasterThreadStatus::kRemainsMerged, decrement_result);
328 }
329
330 ASSERT_TRUE(raster_thread_merger->IsMerged());
331
332 raster_thread_merger->Enable();
333 raster_thread_merger->UnMergeNowIfLastOne();
334 ASSERT_FALSE(raster_thread_merger->IsMerged());
335
336 raster_thread_merger->MergeWithLease(1);
337
338 ASSERT_TRUE(raster_thread_merger->IsMerged());
339
340 {
341 auto decrement_result = raster_thread_merger->DecrementLease();
342 ASSERT_EQ(fml::RasterThreadStatus::kUnmergedNow, decrement_result);
343 }
344
345 ASSERT_FALSE(raster_thread_merger->IsMerged());
346}
347
349 TaskQueueWrapper queue1;
350 TaskQueueWrapper queue2;
351 fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
352 fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
353 const auto raster_thread_merger =
354 fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
355 ASSERT_TRUE(raster_thread_merger->IsEnabled());
356
357 raster_thread_merger->Disable();
358 ASSERT_FALSE(raster_thread_merger->IsEnabled());
359
360 raster_thread_merger->Enable();
361 ASSERT_TRUE(raster_thread_merger->IsEnabled());
362}
363
364TEST(RasterThreadMerger, TwoMergersWithSameThreadPairShareEnabledState) {
365 TaskQueueWrapper queue1;
366 TaskQueueWrapper queue2;
367 fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
368 fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
369 const auto merger1 =
371 const auto merger2 =
373 ASSERT_TRUE(merger1->IsEnabled());
374 ASSERT_TRUE(merger2->IsEnabled());
375
376 merger1->Disable();
377 ASSERT_FALSE(merger1->IsEnabled());
378 ASSERT_FALSE(merger2->IsEnabled());
379
380 merger2->Enable();
381 ASSERT_TRUE(merger1->IsEnabled());
382 ASSERT_TRUE(merger2->IsEnabled());
383}
384
385TEST(RasterThreadMerger, RunExpiredTasksWhileFirstTaskMergesThreads) {
386 fml::MessageLoop* loop_platform = nullptr;
388 std::thread thread_platform([&loop_platform, &latch1]() {
390 loop_platform = &fml::MessageLoop::GetCurrent();
391 loop_platform->GetTaskRunner()->PostTask([&]() { latch1.Signal(); });
392 loop_platform->Run();
393 });
394
395 fml::MessageLoop* loop_raster = nullptr;
397 std::thread thread_raster([&loop_raster, &loop_platform, &latch1, &latch2]() {
398 latch1.Wait();
399
401 loop_raster = &fml::MessageLoop::GetCurrent();
402 fml::TaskQueueId qid_platform =
403 loop_platform->GetTaskRunner()->GetTaskQueueId();
404 fml::TaskQueueId qid_raster =
405 loop_raster->GetTaskRunner()->GetTaskQueueId();
406 fml::CountDownLatch post_merge(2);
407 const auto raster_thread_merger =
408 fml::MakeRefCounted<fml::RasterThreadMerger>(qid_platform, qid_raster);
409 loop_raster->GetTaskRunner()->PostTask([&]() {
410 ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
411 ASSERT_FALSE(raster_thread_merger->IsOnPlatformThread());
412 ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid_raster);
413 raster_thread_merger->MergeWithLease(1);
414 post_merge.CountDown();
415 });
416
417 loop_raster->GetTaskRunner()->PostTask([&]() {
418 ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
419 ASSERT_TRUE(raster_thread_merger->IsOnPlatformThread());
420 ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid_platform);
421 raster_thread_merger->DecrementLease();
422 post_merge.CountDown();
423 });
424
425 loop_raster->RunExpiredTasksNow();
426 post_merge.Wait();
427 latch2.Signal();
428 });
429
430 latch2.Wait();
431 loop_platform->GetTaskRunner()->PostTask(
432 [&]() { loop_platform->Terminate(); });
433
434 thread_platform.join();
435 thread_raster.join();
436}
437
438TEST(RasterThreadMerger, RunExpiredTasksWhileFirstTaskUnMergesThreads) {
439 fml::Thread platform_thread("test_platform_thread");
440
441 fml::AutoResetWaitableEvent raster_latch;
442 std::thread thread_raster([&]() {
445
446 fml::TaskQueueId qid_platform =
447 platform_thread.GetTaskRunner()->GetTaskQueueId();
448 fml::TaskQueueId qid_raster =
449 loop_raster->GetTaskRunner()->GetTaskQueueId();
450
451 fml::AutoResetWaitableEvent merge_latch;
452 const auto raster_thread_merger =
453 fml::MakeRefCounted<fml::RasterThreadMerger>(qid_platform, qid_raster);
454 loop_raster->GetTaskRunner()->PostTask([&]() {
455 raster_thread_merger->MergeWithLease(1);
456 merge_latch.Signal();
457 });
458
459 loop_raster->RunExpiredTasksNow();
460 merge_latch.Wait();
461
462 // threads should be merged at this point.
463 fml::AutoResetWaitableEvent unmerge_latch;
464 loop_raster->GetTaskRunner()->PostTask([&]() {
465 ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
466 ASSERT_TRUE(raster_thread_merger->IsOnPlatformThread());
467 ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid_platform);
468 raster_thread_merger->DecrementLease();
469 unmerge_latch.Signal();
470 });
471
472 fml::AutoResetWaitableEvent post_unmerge_latch;
473 loop_raster->GetTaskRunner()->PostTask([&]() {
474 ASSERT_TRUE(raster_thread_merger->IsOnRasterizingThread());
475 ASSERT_FALSE(raster_thread_merger->IsOnPlatformThread());
476 ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid_raster);
477 post_unmerge_latch.Signal();
478 });
479
480 unmerge_latch.Wait();
481 loop_raster->RunExpiredTasksNow();
482
483 post_unmerge_latch.Wait();
484 raster_latch.Signal();
485 });
486
487 raster_latch.Wait();
488 thread_raster.join();
489}
490
491TEST(RasterThreadMerger, SetMergeUnmergeCallback) {
492 TaskQueueWrapper queue1;
493 TaskQueueWrapper queue2;
494 fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
495 fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
496
497 const auto raster_thread_merger =
498 fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
499
500 int callbacks = 0;
501 raster_thread_merger->SetMergeUnmergeCallback(
502 [&callbacks]() { callbacks++; });
503
504 ASSERT_EQ(0, callbacks);
505
506 raster_thread_merger->MergeWithLease(1);
507 ASSERT_EQ(1, callbacks);
508
509 raster_thread_merger->DecrementLease();
510 ASSERT_EQ(2, callbacks);
511}
512
513TEST(RasterThreadMerger, MultipleMergersCanMergeSameThreadPair) {
514 TaskQueueWrapper queue1;
515 TaskQueueWrapper queue2;
516 fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
517 fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
518 // Two mergers will share one same inner merger
519 const auto raster_thread_merger1 =
521 const auto raster_thread_merger2 =
523 qid1, qid2);
524 const size_t kNumFramesMerged = 5;
525 ASSERT_FALSE(raster_thread_merger1->IsMerged());
526 ASSERT_FALSE(raster_thread_merger2->IsMerged());
527
528 // Merge using the first merger
529 raster_thread_merger1->MergeWithLease(kNumFramesMerged);
530
531 ASSERT_TRUE(raster_thread_merger1->IsMerged());
532 ASSERT_TRUE(raster_thread_merger2->IsMerged());
533
534 // let there be one more turn till the leases expire.
535 for (size_t i = 0; i < kNumFramesMerged - 1; i++) {
536 // Check merge state using the two merger
537 ASSERT_TRUE(raster_thread_merger1->IsMerged());
538 ASSERT_TRUE(raster_thread_merger2->IsMerged());
539 raster_thread_merger1->DecrementLease();
540 }
541
542 ASSERT_TRUE(raster_thread_merger1->IsMerged());
543 ASSERT_TRUE(raster_thread_merger2->IsMerged());
544
545 // extend the lease once with the first merger
546 raster_thread_merger1->ExtendLeaseTo(kNumFramesMerged);
547
548 // we will NOT last for 1 extra turn, we just set it.
549 for (size_t i = 0; i < kNumFramesMerged; i++) {
550 // Check merge state using the two merger
551 ASSERT_TRUE(raster_thread_merger1->IsMerged());
552 ASSERT_TRUE(raster_thread_merger2->IsMerged());
553 raster_thread_merger1->DecrementLease();
554 }
555
556 ASSERT_FALSE(raster_thread_merger1->IsMerged());
557 ASSERT_FALSE(raster_thread_merger2->IsMerged());
558}
559
560TEST(RasterThreadMerger, TheLastCallerOfMultipleMergersCanUnmergeNow) {
561 TaskQueueWrapper queue1;
562 TaskQueueWrapper queue2;
563 fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
564 fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
565 // Two mergers will share one same inner merger
566 const auto raster_thread_merger1 =
568 const auto raster_thread_merger2 =
570 qid1, qid2);
571 const size_t kNumFramesMerged = 5;
572 ASSERT_FALSE(raster_thread_merger1->IsMerged());
573 ASSERT_FALSE(raster_thread_merger2->IsMerged());
574
575 // Merge using the mergers
576 raster_thread_merger1->MergeWithLease(kNumFramesMerged);
577 ASSERT_TRUE(raster_thread_merger1->IsMerged());
578 ASSERT_TRUE(raster_thread_merger2->IsMerged());
579 // Extend the second merger's lease
580 raster_thread_merger2->ExtendLeaseTo(kNumFramesMerged);
581 ASSERT_TRUE(raster_thread_merger1->IsMerged());
582 ASSERT_TRUE(raster_thread_merger2->IsMerged());
583
584 // Two callers state becomes one caller left.
585 raster_thread_merger1->UnMergeNowIfLastOne();
586 // Check if still merged
587 ASSERT_TRUE(raster_thread_merger1->IsMerged());
588 ASSERT_TRUE(raster_thread_merger2->IsMerged());
589
590 // One caller state becomes no callers left.
591 raster_thread_merger2->UnMergeNowIfLastOne();
592 // Check if unmerged
593 ASSERT_FALSE(raster_thread_merger1->IsMerged());
594 ASSERT_FALSE(raster_thread_merger2->IsMerged());
595}
596
597TEST(RasterThreadMerger, TheLastMergedCallerOfMultipleMergersCanUnmergeNow) {
598 TaskQueueWrapper queue1;
599 TaskQueueWrapper queue2;
600 fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
601 fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
602 // Two mergers will share one same inner merger
603 const auto raster_thread_merger1 =
605
606 const size_t kNumFramesMerged = 1;
607 ASSERT_FALSE(raster_thread_merger1->IsMerged());
608
609 // Merge using the mergers
610 raster_thread_merger1->MergeWithLease(kNumFramesMerged);
611 ASSERT_TRUE(raster_thread_merger1->IsMerged());
612
613 for (size_t i = 0; i < kNumFramesMerged; i++) {
614 // Un-merge thread merger 1.
615 raster_thread_merger1->DecrementLease();
616 }
617 ASSERT_FALSE(raster_thread_merger1->IsMerged());
618
619 const auto raster_thread_merger2 =
621 qid1, qid2);
622 ASSERT_FALSE(raster_thread_merger2->IsMerged());
623 raster_thread_merger2->MergeWithLease(kNumFramesMerged);
624 ASSERT_TRUE(raster_thread_merger2->IsMerged());
625
626 // One caller state becomes no callers left.
627 raster_thread_merger2->UnMergeNowIfLastOne();
628 // Check if unmerged
629 ASSERT_FALSE(raster_thread_merger1->IsMerged());
630 ASSERT_FALSE(raster_thread_merger2->IsMerged());
631}
632
633/// This case tests multiple standalone engines using independent merger to
634/// merge two different raster threads into the same platform thread.
636 TwoIndependentMergersCanMergeTwoDifferentThreadsIntoSamePlatformThread) {
637 TaskQueueWrapper queue1;
638 TaskQueueWrapper queue2;
639 TaskQueueWrapper queue3;
640 fml::TaskQueueId qid1 = queue1.GetTaskQueueId();
641 fml::TaskQueueId qid2 = queue2.GetTaskQueueId();
642 fml::TaskQueueId qid3 = queue3.GetTaskQueueId();
643
644 // Two mergers will NOT share same inner merger
645 const auto merger_from_2_to_1 =
647 const auto merger_from_3_to_1 =
649 qid1, qid3);
650 const size_t kNumFramesMerged = 5;
651 ASSERT_FALSE(merger_from_2_to_1->IsMerged());
652 ASSERT_FALSE(merger_from_3_to_1->IsMerged());
653
654 // Merge thread2 into thread1
655 merger_from_2_to_1->MergeWithLease(kNumFramesMerged);
656 // Merge thread3 into thread1
657 merger_from_3_to_1->MergeWithLease(kNumFramesMerged);
658
659 ASSERT_TRUE(merger_from_2_to_1->IsMerged());
660 ASSERT_TRUE(merger_from_3_to_1->IsMerged());
661
662 for (size_t i = 0; i < kNumFramesMerged; i++) {
663 ASSERT_TRUE(merger_from_2_to_1->IsMerged());
664 merger_from_2_to_1->DecrementLease();
665 }
666
667 ASSERT_FALSE(merger_from_2_to_1->IsMerged());
668 ASSERT_TRUE(merger_from_3_to_1->IsMerged());
669
670 for (size_t i = 0; i < kNumFramesMerged; i++) {
671 ASSERT_TRUE(merger_from_3_to_1->IsMerged());
672 merger_from_3_to_1->DecrementLease();
673 }
674
675 ASSERT_FALSE(merger_from_2_to_1->IsMerged());
676 ASSERT_FALSE(merger_from_3_to_1->IsMerged());
677
678 merger_from_2_to_1->MergeWithLease(kNumFramesMerged);
679 ASSERT_TRUE(merger_from_2_to_1->IsMerged());
680 ASSERT_FALSE(merger_from_3_to_1->IsMerged());
681 merger_from_3_to_1->MergeWithLease(kNumFramesMerged);
682 ASSERT_TRUE(merger_from_2_to_1->IsMerged());
683 ASSERT_TRUE(merger_from_3_to_1->IsMerged());
684
685 // Can unmerge independently
686 merger_from_2_to_1->UnMergeNowIfLastOne();
687 ASSERT_FALSE(merger_from_2_to_1->IsMerged());
688 ASSERT_TRUE(merger_from_3_to_1->IsMerged());
689
690 // Can unmerge independently
691 merger_from_3_to_1->UnMergeNowIfLastOne();
692 ASSERT_FALSE(merger_from_2_to_1->IsMerged());
693 ASSERT_FALSE(merger_from_3_to_1->IsMerged());
694}
695
696} // namespace testing
697} // namespace fml
static void loop1(skiatest::Reporter *reporter, const char *filename)
static void loop2(skiatest::Reporter *reporter, const char *filename)
static void EnsureInitializedForCurrentThread()
Definition: message_loop.cc:27
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
Definition: message_loop.cc:56
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
Definition: message_loop.cc:19
static TaskQueueId GetCurrentTaskQueueId()
Definition: message_loop.cc:76
void RunExpiredTasksNow()
Definition: message_loop.cc:72
static fml::RefPtr< fml::RasterThreadMerger > CreateOrShareThreadMerger(const fml::RefPtr< fml::RasterThreadMerger > &parent_merger, TaskQueueId platform_id, TaskQueueId raster_id)
void MergeWithLease(size_t lease_term)
RasterThreadStatus DecrementLease()
virtual void PostTask(const fml::closure &task) override
Definition: task_runner.cc:24
virtual TaskQueueId GetTaskQueueId()
Definition: task_runner.cc:38
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
Definition: thread.cc:164
VkQueue queue
Definition: main.cc:55
TEST(BacktraceTest, CanGatherBacktrace)
Definition: ascii_trie.cc:9
A mock task queue NOT calling MessageLoop->Run() in thread.
fml::AutoResetWaitableEvent term
The waiter for thread finished.
fml::AutoResetWaitableEvent latch
The waiter for message loop initialized ok.