Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(284)

Side by Side Diff: media/gpu/avda_codec_allocator_unittest.cc

Issue 2508053002: media: Do a TimedWait() for video surface teardown in AVDA (Closed)
Patch Set: Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/gpu/avda_codec_allocator.h" 5 #include "media/gpu/avda_codec_allocator.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <memory> 9 #include <memory>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/time/tick_clock.h" 13 #include "base/time/tick_clock.h"
14 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h" 15 #include "testing/gtest/include/gtest/gtest.h"
15 16
17 using testing::NiceMock;
18 using testing::_;
19
16 namespace media { 20 namespace media {
17 namespace { 21 namespace {
18 template <typename ReturnType> 22 template <typename ReturnType>
19 void RunAndSignalTask(base::WaitableEvent* event, 23 void RunAndSignalTask(base::WaitableEvent* event,
20 ReturnType* return_value, 24 ReturnType* return_value,
21 const base::Callback<ReturnType(void)>& cb) { 25 const base::Callback<ReturnType(void)>& cb) {
22 *return_value = cb.Run(); 26 *return_value = cb.Run();
23 event->Signal(); 27 event->Signal();
24 } 28 }
25 } 29 }
(...skipping 14 matching lines...) Expand all
40 void Advance(int msec) { 44 void Advance(int msec) {
41 base::AutoLock auto_lock(lock_); 45 base::AutoLock auto_lock(lock_);
42 now_ += base::TimeDelta::FromMilliseconds(msec); 46 now_ += base::TimeDelta::FromMilliseconds(msec);
43 } 47 }
44 48
45 private: 49 private:
46 base::Lock lock_; 50 base::Lock lock_;
47 base::TimeTicks now_; 51 base::TimeTicks now_;
48 }; 52 };
49 53
54 class MockClient : public AVDACodecAllocatorClient {
55 public:
56 MOCK_METHOD1(OnSurfaceAvailable, void(bool success));
57 MOCK_METHOD0(OnSurfaceDestroyed, void());
58
59 // Gmock doesn't let us mock methods taking move-only types.
60 MOCK_METHOD1(OnCodecConfiguredMock, void(VideoCodecBridge* media_codec));
61 void OnCodecConfigured(
62 std::unique_ptr<VideoCodecBridge> media_codec) override {
63 OnCodecConfiguredMock(media_codec.get());
64 }
65 };
66
50 class AVDACodecAllocatorTest : public testing::Test { 67 class AVDACodecAllocatorTest : public testing::Test {
51 public: 68 public:
52 AVDACodecAllocatorTest() : allocator_thread_("AllocatorThread") {} 69 AVDACodecAllocatorTest() : allocator_thread_("AllocatorThread") {}
53 ~AVDACodecAllocatorTest() override {} 70 ~AVDACodecAllocatorTest() override {}
54 71
55 protected: 72 protected:
56 void SetUp() override { 73 void SetUp() override {
57 // Start the main thread for the allocator. This would normally be the GPU 74 // Start the main thread for the allocator. This would normally be the GPU
58 // main thread. 75 // main thread.
59 ASSERT_TRUE(allocator_thread_.Start()); 76 ASSERT_TRUE(allocator_thread_.Start());
60 77
61 // AVDACodecAllocator likes to post tasks to the current thread. 78 // AVDACodecAllocator likes to post tasks to the current thread.
62 79
63 test_information_.reset(new AVDACodecAllocator::TestInformation()); 80 test_information_.reset(new AVDACodecAllocator::TestInformation());
64 test_information_->tick_clock_.reset(new MockTickClock()); 81 test_information_->tick_clock_.reset(new MockTickClock());
65 test_information_->stop_event_.reset(new base::WaitableEvent( 82 test_information_->stop_event_.reset(new base::WaitableEvent(
66 base::WaitableEvent::ResetPolicy::AUTOMATIC, 83 base::WaitableEvent::ResetPolicy::AUTOMATIC,
67 base::WaitableEvent::InitialState::NOT_SIGNALED)); 84 base::WaitableEvent::InitialState::NOT_SIGNALED));
68 85
69 // Allocate the allocator on the appropriate thread. 86 // Allocate the allocator on the appropriate thread.
70 allocator_ = PostAndWait( 87 allocator_ = PostAndWait(
71 FROM_HERE, base::Bind( 88 FROM_HERE, base::Bind(
72 [](AVDACodecAllocator::TestInformation* test_info) { 89 [](AVDACodecAllocator::TestInformation* test_info) {
73 return new AVDACodecAllocator(test_info); 90 return new AVDACodecAllocator(test_info);
74 }, 91 },
75 test_information_.get())); 92 test_information_.get()));
93 allocator2_ = new AVDACodecAllocator(test_information_.get());
76 94
77 // All threads should be stopped 95 // All threads should be stopped
78 ASSERT_FALSE(IsThreadRunning(AVDACodecAllocator::TaskType::AUTO_CODEC)); 96 ASSERT_FALSE(IsThreadRunning(TaskType::AUTO_CODEC));
79 ASSERT_FALSE(IsThreadRunning(AVDACodecAllocator::TaskType::SW_CODEC)); 97 ASSERT_FALSE(IsThreadRunning(TaskType::SW_CODEC));
80 98
81 // Register an AVDA instance to start the allocator's threads. 99 // Register an AVDA instance to start the allocator's threads.
82 ASSERT_TRUE(StartThread(avda1_)); 100 ASSERT_TRUE(StartThread(avda1_));
83 101
84 // Assert that at least the AUTO_CODEC thread is started. The other might 102 // Assert that at least the AUTO_CODEC thread is started. The other might
85 // not be. 103 // not be.
86 ASSERT_TRUE(IsThreadRunning(AVDACodecAllocator::TaskType::AUTO_CODEC)); 104 ASSERT_TRUE(IsThreadRunning(TaskType::AUTO_CODEC));
87 ASSERT_EQ(AVDACodecAllocator::TaskType::AUTO_CODEC, 105 ASSERT_EQ(TaskType::AUTO_CODEC, TaskTypeForAllocation());
88 TaskTypeForAllocation());
89 } 106 }
90 107
91 void TearDown() override { 108 void TearDown() override {
92 // Don't leave any threads hung, or this will hang too. 109 // Don't leave any threads hung, or this will hang too.
93 // It would be nice if we could let a unique ptr handle this, but the 110 // It would be nice if we could let a unique ptr handle this, but the
94 // destructor is private. We also have to destroy it on the right thread. 111 // destructor is private. We also have to destroy it on the right thread.
95 PostAndWait(FROM_HERE, base::Bind( 112 PostAndWait(FROM_HERE, base::Bind(
96 [](AVDACodecAllocator* allocator) { 113 [](AVDACodecAllocator* allocator) {
97 delete allocator; 114 delete allocator;
98 return true; 115 return true;
99 }, 116 },
100 allocator_)); 117 allocator_));
101 118
102 allocator_thread_.Stop(); 119 allocator_thread_.Stop();
120 delete allocator2_;
103 } 121 }
104 122
105 protected: 123 protected:
106 static void WaitUntilRestarted(base::WaitableEvent* about_to_wait_event, 124 static void WaitUntilRestarted(base::WaitableEvent* about_to_wait_event,
107 base::WaitableEvent* wait_event) { 125 base::WaitableEvent* wait_event) {
108 // Notify somebody that we've started. 126 // Notify somebody that we've started.
109 about_to_wait_event->Signal(); 127 about_to_wait_event->Signal();
110 wait_event->Wait(); 128 wait_event->Wait();
111 } 129 }
112 130
113 static void SignalImmediately(base::WaitableEvent* event) { event->Signal(); } 131 static void SignalImmediately(base::WaitableEvent* event) { event->Signal(); }
114 132
115 // Start / stop the threads for |avda| on the right thread. 133 // Start / stop the threads for |avda| on the right thread.
116 bool StartThread(AndroidVideoDecodeAccelerator* avda) { 134 bool StartThread(AVDACodecAllocatorClient* avda) {
117 return PostAndWait(FROM_HERE, base::Bind( 135 return PostAndWait(FROM_HERE, base::Bind(
118 [](AVDACodecAllocator* allocator, 136 [](AVDACodecAllocator* allocator,
119 AndroidVideoDecodeAccelerator* avda) { 137 AVDACodecAllocatorClient* avda) {
120 return allocator->StartThread(avda); 138 return allocator->StartThread(avda);
121 }, 139 },
122 allocator_, avda)); 140 allocator_, avda));
123 } 141 }
124 142
125 void StopThread(AndroidVideoDecodeAccelerator* avda) { 143 void StopThread(AVDACodecAllocatorClient* avda) {
126 // Note that we also wait for the stop event, so that we know that the 144 // Note that we also wait for the stop event, so that we know that the
127 // stop has completed. It's async with respect to the allocator thread. 145 // stop has completed. It's async with respect to the allocator thread.
128 PostAndWait(FROM_HERE, base::Bind( 146 PostAndWait(FROM_HERE, base::Bind(
129 [](AVDACodecAllocator* allocator, 147 [](AVDACodecAllocator* allocator,
130 AndroidVideoDecodeAccelerator* avda) { 148 AVDACodecAllocatorClient* avda) {
131 allocator->StopThread(avda); 149 allocator->StopThread(avda);
132 return true; 150 return true;
133 }, 151 },
134 allocator_, avda)); 152 allocator_, avda));
135 // Note that we don't do this on the allocator thread, since that's the 153 // Note that we don't do this on the allocator thread, since that's the
136 // thread that will signal it. 154 // thread that will signal it.
137 test_information_->stop_event_->Wait(); 155 test_information_->stop_event_->Wait();
138 } 156 }
139 157
140 // Return the running state of |task_type|, doing the necessary thread hops. 158 // Return the running state of |task_type|, doing the necessary thread hops.
141 bool IsThreadRunning(AVDACodecAllocator::TaskType task_type) { 159 bool IsThreadRunning(TaskType task_type) {
142 return PostAndWait( 160 return PostAndWait(
143 FROM_HERE, 161 FROM_HERE,
144 base::Bind( 162 base::Bind(
145 [](AVDACodecAllocator* allocator, 163 [](AVDACodecAllocator* allocator, TaskType task_type) {
146 AVDACodecAllocator::TaskType task_type) {
147 return allocator->GetThreadForTesting(task_type).IsRunning(); 164 return allocator->GetThreadForTesting(task_type).IsRunning();
148 }, 165 },
149 allocator_, task_type)); 166 allocator_, task_type));
150 } 167 }
151 168
152 AVDACodecAllocator::TaskType TaskTypeForAllocation() { 169 TaskType TaskTypeForAllocation() {
153 return PostAndWait(FROM_HERE, 170 return PostAndWait(FROM_HERE,
154 base::Bind(&AVDACodecAllocator::TaskTypeForAllocation, 171 base::Bind(&AVDACodecAllocator::TaskTypeForAllocation,
155 base::Unretained(allocator_))); 172 base::Unretained(allocator_)));
156 } 173 }
157 174
158 scoped_refptr<base::SingleThreadTaskRunner> TaskRunnerFor( 175 scoped_refptr<base::SingleThreadTaskRunner> TaskRunnerFor(
159 AVDACodecAllocator::TaskType task_type) { 176 TaskType task_type) {
160 return PostAndWait(FROM_HERE, 177 return PostAndWait(FROM_HERE,
161 base::Bind(&AVDACodecAllocator::TaskRunnerFor, 178 base::Bind(&AVDACodecAllocator::TaskRunnerFor,
162 base::Unretained(allocator_), task_type)); 179 base::Unretained(allocator_), task_type));
163 } 180 }
164 181
165 // Post |cb| to the allocator thread, and wait for a response. Note that we 182 // Post |cb| to the allocator thread, and wait for a response. Note that we
166 // don't have a specialization for void, and void won't work as written. So, 183 // don't have a specialization for void, and void won't work as written. So,
167 // be sure to return something. 184 // be sure to return something.
168 template <typename ReturnType> 185 template <typename ReturnType>
169 ReturnType PostAndWait(const tracked_objects::Location& from_here, 186 ReturnType PostAndWait(const tracked_objects::Location& from_here,
170 const base::Callback<ReturnType(void)>& cb) { 187 const base::Callback<ReturnType(void)>& cb) {
171 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, 188 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
172 base::WaitableEvent::InitialState::NOT_SIGNALED); 189 base::WaitableEvent::InitialState::NOT_SIGNALED);
173 ReturnType return_value = ReturnType(); 190 ReturnType return_value = ReturnType();
174 allocator_thread_.task_runner()->PostTask( 191 allocator_thread_.task_runner()->PostTask(
175 from_here, 192 from_here,
176 base::Bind(&RunAndSignalTask<ReturnType>, &event, &return_value, cb)); 193 base::Bind(&RunAndSignalTask<ReturnType>, &event, &return_value, cb));
177 event.Wait(); 194 event.Wait();
178 return return_value; 195 return return_value;
179 } 196 }
180 197
181 base::Thread allocator_thread_; 198 base::Thread allocator_thread_;
182 199
183 // Test info that we provide to the codec allocator. 200 // Test info that we provide to the codec allocator.
184 std::unique_ptr<AVDACodecAllocator::TestInformation> test_information_; 201 std::unique_ptr<AVDACodecAllocator::TestInformation> test_information_;
185 202
186 // Allocator that we own. Would be a unique_ptr, but the destructor is 203 // Allocators that we own. The first is intialized to be used on the allocator
187 // private. Plus, we need to destruct it from the right thread. 204 // thread and the second one is initialized on the test thread. Each test
205 // should only be using one of the two. They are not unique_ptrs because the
206 // destructor is private and they need to be destructed on the right thread.
188 AVDACodecAllocator* allocator_ = nullptr; 207 AVDACodecAllocator* allocator_ = nullptr;
208 AVDACodecAllocator* allocator2_ = nullptr;
189 209
190 AndroidVideoDecodeAccelerator* avda1_ = (AndroidVideoDecodeAccelerator*)0x1; 210 NiceMock<MockClient> client1_, client2_, client3_;
191 AndroidVideoDecodeAccelerator* avda2_ = (AndroidVideoDecodeAccelerator*)0x2; 211 NiceMock<MockClient>* avda1_ = &client1_;
212 NiceMock<MockClient>* avda2_ = &client2_;
213 NiceMock<MockClient>* avda3_ = &client3_;
192 }; 214 };
193 215
194 TEST_F(AVDACodecAllocatorTest, TestMultiInstance) { 216 TEST_F(AVDACodecAllocatorTest, TestMultiInstance) {
195 // Add an avda instance. This one must succeed immediately, since the last 217 // Add an avda instance. This one must succeed immediately, since the last
196 // one is still running. 218 // one is still running.
197 ASSERT_TRUE(StartThread(avda2_)); 219 ASSERT_TRUE(StartThread(avda2_));
198 220
199 // Stop the original avda instance. 221 // Stop the original avda instance.
200 StopThread(avda1_); 222 StopThread(avda1_);
201 223
202 // Verify that the AUTO_CODEC thread is still running. 224 // Verify that the AUTO_CODEC thread is still running.
203 ASSERT_TRUE(IsThreadRunning(AVDACodecAllocator::TaskType::AUTO_CODEC)); 225 ASSERT_TRUE(IsThreadRunning(TaskType::AUTO_CODEC));
204 ASSERT_EQ(AVDACodecAllocator::TaskType::AUTO_CODEC, TaskTypeForAllocation()); 226 ASSERT_EQ(TaskType::AUTO_CODEC, TaskTypeForAllocation());
205 227
206 // Remove the second instance and wait for it to stop. Remember that it 228 // Remove the second instance and wait for it to stop. Remember that it
207 // stops after messages have been posted to the thread, so we don't know 229 // stops after messages have been posted to the thread, so we don't know
208 // how long it will take. 230 // how long it will take.
209 StopThread(avda2_); 231 StopThread(avda2_);
210 232
211 // Verify that the threads have stopped. 233 // Verify that the threads have stopped.
212 ASSERT_FALSE(IsThreadRunning(AVDACodecAllocator::TaskType::AUTO_CODEC)); 234 ASSERT_FALSE(IsThreadRunning(TaskType::AUTO_CODEC));
213 ASSERT_FALSE(IsThreadRunning(AVDACodecAllocator::TaskType::SW_CODEC)); 235 ASSERT_FALSE(IsThreadRunning(TaskType::SW_CODEC));
214 } 236 }
215 237
216 TEST_F(AVDACodecAllocatorTest, TestHangThread) { 238 TEST_F(AVDACodecAllocatorTest, TestHangThread) {
217 ASSERT_EQ(AVDACodecAllocator::TaskType::AUTO_CODEC, TaskTypeForAllocation()); 239 ASSERT_EQ(TaskType::AUTO_CODEC, TaskTypeForAllocation());
218 240
219 // Hang the AUTO_CODEC thread. 241 // Hang the AUTO_CODEC thread.
220 base::WaitableEvent about_to_wait_event( 242 base::WaitableEvent about_to_wait_event(
221 base::WaitableEvent::ResetPolicy::MANUAL, 243 base::WaitableEvent::ResetPolicy::MANUAL,
222 base::WaitableEvent::InitialState::NOT_SIGNALED); 244 base::WaitableEvent::InitialState::NOT_SIGNALED);
223 base::WaitableEvent wait_event( 245 base::WaitableEvent wait_event(
224 base::WaitableEvent::ResetPolicy::MANUAL, 246 base::WaitableEvent::ResetPolicy::MANUAL,
225 base::WaitableEvent::InitialState::NOT_SIGNALED); 247 base::WaitableEvent::InitialState::NOT_SIGNALED);
226 TaskRunnerFor(AVDACodecAllocator::TaskType::AUTO_CODEC) 248 TaskRunnerFor(TaskType::AUTO_CODEC)
227 ->PostTask(FROM_HERE, 249 ->PostTask(FROM_HERE,
228 base::Bind(&AVDACodecAllocatorTest::WaitUntilRestarted, 250 base::Bind(&AVDACodecAllocatorTest::WaitUntilRestarted,
229 &about_to_wait_event, &wait_event)); 251 &about_to_wait_event, &wait_event));
230 // Wait until the task starts, so that |allocator_| starts the hang timer. 252 // Wait until the task starts, so that |allocator_| starts the hang timer.
231 about_to_wait_event.Wait(); 253 about_to_wait_event.Wait();
232 254
233 // Verify that we've failed over after a long time has passed. 255 // Verify that we've failed over after a long time has passed.
234 static_cast<MockTickClock*>(test_information_->tick_clock_.get()) 256 static_cast<MockTickClock*>(test_information_->tick_clock_.get())
235 ->Advance(1000); 257 ->Advance(1000);
236 // Note that this should return the SW codec task type even if that thread 258 // Note that this should return the SW codec task type even if that thread
237 // failed to start. TaskRunnerFor() will return the current thread in that 259 // failed to start. TaskRunnerFor() will return the current thread in that
238 // case too. 260 // case too.
239 ASSERT_EQ(AVDACodecAllocator::TaskType::SW_CODEC, TaskTypeForAllocation()); 261 ASSERT_EQ(TaskType::SW_CODEC, TaskTypeForAllocation());
240 262
241 // Un-hang the thread and wait for it to let another task run. This will 263 // Un-hang the thread and wait for it to let another task run. This will
242 // notify |allocator_| that the thread is no longer hung. 264 // notify |allocator_| that the thread is no longer hung.
243 base::WaitableEvent done_waiting_event( 265 base::WaitableEvent done_waiting_event(
244 base::WaitableEvent::ResetPolicy::MANUAL, 266 base::WaitableEvent::ResetPolicy::MANUAL,
245 base::WaitableEvent::InitialState::NOT_SIGNALED); 267 base::WaitableEvent::InitialState::NOT_SIGNALED);
246 TaskRunnerFor(AVDACodecAllocator::TaskType::AUTO_CODEC) 268 TaskRunnerFor(TaskType::AUTO_CODEC)
247 ->PostTask(FROM_HERE, 269 ->PostTask(FROM_HERE,
248 base::Bind(&AVDACodecAllocatorTest::SignalImmediately, 270 base::Bind(&AVDACodecAllocatorTest::SignalImmediately,
249 &done_waiting_event)); 271 &done_waiting_event));
250 wait_event.Signal(); 272 wait_event.Signal();
251 done_waiting_event.Wait(); 273 done_waiting_event.Wait();
252 274
253 // Verify that we've un-failed over. 275 // Verify that we've un-failed over.
254 ASSERT_EQ(AVDACodecAllocator::TaskType::AUTO_CODEC, TaskTypeForAllocation()); 276 ASSERT_EQ(TaskType::AUTO_CODEC, TaskTypeForAllocation());
277 }
278
279 TEST_F(AVDACodecAllocatorTest, AllocatingASurfaceTextureAlwaysSucceeds) {
280 ASSERT_TRUE(
281 allocator2_->AllocateSurface(avda1_, SurfaceManager::kNoSurfaceID));
282 ASSERT_TRUE(
283 allocator2_->AllocateSurface(avda2_, SurfaceManager::kNoSurfaceID));
284 }
285
286 TEST_F(AVDACodecAllocatorTest, AllocatingAnOwnedSurfaceFails) {
287 ASSERT_TRUE(allocator2_->AllocateSurface(avda1_, 1));
288 ASSERT_FALSE(allocator2_->AllocateSurface(avda2_, 1));
289 }
290
291 TEST_F(AVDACodecAllocatorTest, LaterWaitersReplaceEarlierWaiters) {
292 allocator2_->AllocateSurface(avda1_, 1);
293 allocator2_->AllocateSurface(avda2_, 1);
294 EXPECT_CALL(*avda2_, OnSurfaceAvailable(false));
295 allocator2_->AllocateSurface(avda3_, 1);
296 }
297
298 TEST_F(AVDACodecAllocatorTest, WaitersBecomeOwnersWhenSurfacesAreReleased) {
299 allocator2_->AllocateSurface(avda1_, 1);
300 allocator2_->AllocateSurface(avda2_, 1);
301 EXPECT_CALL(*avda2_, OnSurfaceAvailable(true));
302 allocator2_->DeallocateSurface(avda1_, 1);
303 // The surface should still be owned.
304 ASSERT_FALSE(allocator2_->AllocateSurface(avda1_, 1));
305 }
306
307 TEST_F(AVDACodecAllocatorTest, DeallocatingUnownedSurfacesIsSafe) {
308 allocator2_->DeallocateSurface(avda1_, 1);
309 allocator2_->DeallocateSurface(avda1_, SurfaceManager::kNoSurfaceID);
310 }
311
312 TEST_F(AVDACodecAllocatorTest, WaitersAreRemovedIfTheyDeallocate) {
313 allocator2_->AllocateSurface(avda1_, 1);
314 allocator2_->AllocateSurface(avda2_, 1);
315 allocator2_->DeallocateSurface(avda2_, 1);
316 // avda2_ should should not receive a notification.
317 EXPECT_CALL(*avda2_, OnSurfaceAvailable(_)).Times(0);
318 allocator2_->DeallocateSurface(avda1_, 1);
255 } 319 }
256 320
257 } // namespace media 321 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698