• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <atomic>
8 #include <thread>
9 
10 #include "flutter/fml/gpu_thread_merger.h"
11 #include "flutter/fml/message_loop.h"
12 #include "flutter/fml/synchronization/count_down_latch.h"
13 #include "flutter/fml/synchronization/waitable_event.h"
14 #include "flutter/fml/task_runner.h"
15 #include "gtest/gtest.h"
16 
TEST(GpuThreadMerger,RemainMergedTillLeaseExpires)17 TEST(GpuThreadMerger, RemainMergedTillLeaseExpires) {
18   fml::MessageLoop* loop1 = nullptr;
19   fml::AutoResetWaitableEvent latch1;
20   fml::AutoResetWaitableEvent term1;
21   std::thread thread1([&loop1, &latch1, &term1]() {
22     fml::MessageLoop::EnsureInitializedForCurrentThread();
23     loop1 = &fml::MessageLoop::GetCurrent();
24     latch1.Signal();
25     term1.Wait();
26   });
27 
28   fml::MessageLoop* loop2 = nullptr;
29   fml::AutoResetWaitableEvent latch2;
30   fml::AutoResetWaitableEvent term2;
31   std::thread thread2([&loop2, &latch2, &term2]() {
32     fml::MessageLoop::EnsureInitializedForCurrentThread();
33     loop2 = &fml::MessageLoop::GetCurrent();
34     latch2.Signal();
35     term2.Wait();
36   });
37 
38   latch1.Wait();
39   latch2.Wait();
40 
41   fml::TaskQueueId qid1 = loop1->GetTaskRunner()->GetTaskQueueId();
42   fml::TaskQueueId qid2 = loop2->GetTaskRunner()->GetTaskQueueId();
43   const auto gpu_thread_merger_ =
44       fml::MakeRefCounted<fml::GpuThreadMerger>(qid1, qid2);
45   const int kNumFramesMerged = 5;
46 
47   ASSERT_FALSE(gpu_thread_merger_->IsMerged());
48 
49   gpu_thread_merger_->MergeWithLease(kNumFramesMerged);
50 
51   for (int i = 0; i < kNumFramesMerged; i++) {
52     ASSERT_TRUE(gpu_thread_merger_->IsMerged());
53     gpu_thread_merger_->DecrementLease();
54   }
55 
56   ASSERT_FALSE(gpu_thread_merger_->IsMerged());
57 
58   term1.Signal();
59   term2.Signal();
60   thread1.join();
61   thread2.join();
62 }
63 
TEST(GpuThreadMerger,IsNotOnRasterizingThread)64 TEST(GpuThreadMerger, IsNotOnRasterizingThread) {
65   fml::MessageLoop* loop1 = nullptr;
66   fml::AutoResetWaitableEvent latch1;
67   std::thread thread1([&loop1, &latch1]() {
68     fml::MessageLoop::EnsureInitializedForCurrentThread();
69     loop1 = &fml::MessageLoop::GetCurrent();
70     loop1->GetTaskRunner()->PostTask([&]() { latch1.Signal(); });
71     loop1->Run();
72   });
73 
74   fml::MessageLoop* loop2 = nullptr;
75   fml::AutoResetWaitableEvent latch2;
76   std::thread thread2([&loop2, &latch2]() {
77     fml::MessageLoop::EnsureInitializedForCurrentThread();
78     loop2 = &fml::MessageLoop::GetCurrent();
79     loop2->GetTaskRunner()->PostTask([&]() { latch2.Signal(); });
80     loop2->Run();
81   });
82 
83   latch1.Wait();
84   latch2.Wait();
85 
86   fml::TaskQueueId qid1 = loop1->GetTaskRunner()->GetTaskQueueId();
87   fml::TaskQueueId qid2 = loop2->GetTaskRunner()->GetTaskQueueId();
88   const auto gpu_thread_merger_ =
89       fml::MakeRefCounted<fml::GpuThreadMerger>(qid1, qid2);
90 
91   fml::CountDownLatch pre_merge(2), post_merge(2), post_unmerge(2);
92 
93   loop1->GetTaskRunner()->PostTask([&]() {
94     ASSERT_FALSE(gpu_thread_merger_->IsOnRasterizingThread());
95     ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid1);
96     pre_merge.CountDown();
97   });
98 
99   loop2->GetTaskRunner()->PostTask([&]() {
100     ASSERT_TRUE(gpu_thread_merger_->IsOnRasterizingThread());
101     ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid2);
102     pre_merge.CountDown();
103   });
104 
105   pre_merge.Wait();
106 
107   gpu_thread_merger_->MergeWithLease(1);
108 
109   loop1->GetTaskRunner()->PostTask([&]() {
110     ASSERT_TRUE(gpu_thread_merger_->IsOnRasterizingThread());
111     ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid1);
112     post_merge.CountDown();
113   });
114 
115   loop2->GetTaskRunner()->PostTask([&]() {
116     // this will be false since this is going to be run
117     // on loop1 really.
118     ASSERT_TRUE(gpu_thread_merger_->IsOnRasterizingThread());
119     ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid1);
120     post_merge.CountDown();
121   });
122 
123   post_merge.Wait();
124 
125   gpu_thread_merger_->DecrementLease();
126 
127   loop1->GetTaskRunner()->PostTask([&]() {
128     ASSERT_FALSE(gpu_thread_merger_->IsOnRasterizingThread());
129     ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid1);
130     post_unmerge.CountDown();
131   });
132 
133   loop2->GetTaskRunner()->PostTask([&]() {
134     ASSERT_TRUE(gpu_thread_merger_->IsOnRasterizingThread());
135     ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid2);
136     post_unmerge.CountDown();
137   });
138 
139   post_unmerge.Wait();
140 
141   loop1->GetTaskRunner()->PostTask([&]() { loop1->Terminate(); });
142 
143   loop2->GetTaskRunner()->PostTask([&]() { loop2->Terminate(); });
144 
145   thread1.join();
146   thread2.join();
147 }
148 
TEST(GpuThreadMerger,LeaseExtension)149 TEST(GpuThreadMerger, LeaseExtension) {
150   fml::MessageLoop* loop1 = nullptr;
151   fml::AutoResetWaitableEvent latch1;
152   fml::AutoResetWaitableEvent term1;
153   std::thread thread1([&loop1, &latch1, &term1]() {
154     fml::MessageLoop::EnsureInitializedForCurrentThread();
155     loop1 = &fml::MessageLoop::GetCurrent();
156     latch1.Signal();
157     term1.Wait();
158   });
159 
160   fml::MessageLoop* loop2 = nullptr;
161   fml::AutoResetWaitableEvent latch2;
162   fml::AutoResetWaitableEvent term2;
163   std::thread thread2([&loop2, &latch2, &term2]() {
164     fml::MessageLoop::EnsureInitializedForCurrentThread();
165     loop2 = &fml::MessageLoop::GetCurrent();
166     latch2.Signal();
167     term2.Wait();
168   });
169 
170   latch1.Wait();
171   latch2.Wait();
172 
173   fml::TaskQueueId qid1 = loop1->GetTaskRunner()->GetTaskQueueId();
174   fml::TaskQueueId qid2 = loop2->GetTaskRunner()->GetTaskQueueId();
175   const auto gpu_thread_merger_ =
176       fml::MakeRefCounted<fml::GpuThreadMerger>(qid1, qid2);
177   const int kNumFramesMerged = 5;
178 
179   ASSERT_FALSE(gpu_thread_merger_->IsMerged());
180 
181   gpu_thread_merger_->MergeWithLease(kNumFramesMerged);
182 
183   // let there be one more turn till the leases expire.
184   for (int i = 0; i < kNumFramesMerged - 1; i++) {
185     ASSERT_TRUE(gpu_thread_merger_->IsMerged());
186     gpu_thread_merger_->DecrementLease();
187   }
188 
189   // extend the lease once.
190   gpu_thread_merger_->ExtendLeaseTo(kNumFramesMerged);
191 
192   // we will NOT last for 1 extra turn, we just set it.
193   for (int i = 0; i < kNumFramesMerged; i++) {
194     ASSERT_TRUE(gpu_thread_merger_->IsMerged());
195     gpu_thread_merger_->DecrementLease();
196   }
197 
198   ASSERT_FALSE(gpu_thread_merger_->IsMerged());
199 
200   term1.Signal();
201   term2.Signal();
202   thread1.join();
203   thread2.join();
204 }
205