| OLD | NEW | 
|    1 // Copyright 2016 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/test/simple_test_tick_clock.h" | 
|   13 #include "base/time/tick_clock.h" |   14 #include "base/time/tick_clock.h" | 
|   14 #include "testing/gmock/include/gmock/gmock.h" |   15 #include "testing/gmock/include/gmock/gmock.h" | 
|   15 #include "testing/gtest/include/gtest/gtest.h" |   16 #include "testing/gtest/include/gtest/gtest.h" | 
|   16  |   17  | 
|   17 using testing::Invoke; |   18 using testing::Invoke; | 
|   18 using testing::NiceMock; |   19 using testing::NiceMock; | 
|   19 using testing::_; |   20 using testing::_; | 
|   20  |   21  | 
|   21 namespace media { |   22 namespace media { | 
|   22 namespace { |   23 namespace { | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
|   34   if (about_to_wait_event) |   35   if (about_to_wait_event) | 
|   35     about_to_wait_event->Signal(); |   36     about_to_wait_event->Signal(); | 
|   36   wait_event->Wait(); |   37   wait_event->Wait(); | 
|   37 } |   38 } | 
|   38  |   39  | 
|   39 void SignalImmediately(base::WaitableEvent* event) { |   40 void SignalImmediately(base::WaitableEvent* event) { | 
|   40   event->Signal(); |   41   event->Signal(); | 
|   41 } |   42 } | 
|   42 } |   43 } | 
|   43  |   44  | 
|   44 class MockTickClock : public base::TickClock { |  | 
|   45  public: |  | 
|   46   MockTickClock() { |  | 
|   47     // Don't start with the null time. |  | 
|   48     Advance(1000); |  | 
|   49   } |  | 
|   50   ~MockTickClock() override{}; |  | 
|   51   base::TimeTicks NowTicks() override { |  | 
|   52     base::AutoLock auto_lock(lock_); |  | 
|   53     return now_; |  | 
|   54   } |  | 
|   55  |  | 
|   56   // Handy utility. |  | 
|   57   void Advance(int msec) { |  | 
|   58     base::AutoLock auto_lock(lock_); |  | 
|   59     now_ += base::TimeDelta::FromMilliseconds(msec); |  | 
|   60   } |  | 
|   61  |  | 
|   62  private: |  | 
|   63   base::Lock lock_; |  | 
|   64   base::TimeTicks now_; |  | 
|   65 }; |  | 
|   66  |  | 
|   67 class MockClient : public AVDACodecAllocatorClient { |   45 class MockClient : public AVDACodecAllocatorClient { | 
|   68  public: |   46  public: | 
|   69   MOCK_METHOD1(OnSurfaceAvailable, void(bool success)); |   47   MOCK_METHOD1(OnSurfaceAvailable, void(bool success)); | 
|   70   MOCK_METHOD0(OnSurfaceDestroyed, void()); |   48   MOCK_METHOD0(OnSurfaceDestroyed, void()); | 
|   71  |   49  | 
|   72   // Gmock doesn't let us mock methods taking move-only types. |   50   // Gmock doesn't let us mock methods taking move-only types. | 
|   73   MOCK_METHOD1(OnCodecConfiguredMock, void(VideoCodecBridge* media_codec)); |   51   MOCK_METHOD1(OnCodecConfiguredMock, void(VideoCodecBridge* media_codec)); | 
|   74   void OnCodecConfigured( |   52   void OnCodecConfigured( | 
|   75       std::unique_ptr<VideoCodecBridge> media_codec) override { |   53       std::unique_ptr<VideoCodecBridge> media_codec) override { | 
|   76     OnCodecConfiguredMock(media_codec.get()); |   54     OnCodecConfiguredMock(media_codec.get()); | 
|   77   } |   55   } | 
|   78 }; |   56 }; | 
|   79  |   57  | 
|   80 class AVDACodecAllocatorTest : public testing::Test { |   58 class AVDACodecAllocatorTest : public testing::Test { | 
|   81  public: |   59  public: | 
|   82   AVDACodecAllocatorTest() : allocator_thread_("AllocatorThread") {} |   60   AVDACodecAllocatorTest() | 
 |   61       : allocator_thread_("AllocatorThread"), | 
 |   62         stop_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC, | 
 |   63                     base::WaitableEvent::InitialState::NOT_SIGNALED) { | 
 |   64     // Don't start the clock at null. | 
 |   65     tick_clock_.Advance(base::TimeDelta::FromSeconds(1)); | 
 |   66   } | 
 |   67  | 
|   83   ~AVDACodecAllocatorTest() override {} |   68   ~AVDACodecAllocatorTest() override {} | 
|   84  |   69  | 
|   85  protected: |   70  protected: | 
|   86   void SetUp() override { |   71   void SetUp() override { | 
|   87     // Start the main thread for the allocator.  This would normally be the GPU |   72     // Start the main thread for the allocator.  This would normally be the GPU | 
|   88     // main thread. |   73     // main thread. | 
|   89     ASSERT_TRUE(allocator_thread_.Start()); |   74     ASSERT_TRUE(allocator_thread_.Start()); | 
|   90  |   75  | 
|   91     // AVDACodecAllocator likes to post tasks to the current thread. |   76     // Create the first allocator on the allocator thread. | 
|   92  |  | 
|   93     test_information_.reset(new AVDACodecAllocator::TestInformation()); |  | 
|   94     test_information_->tick_clock_.reset(new MockTickClock()); |  | 
|   95     test_information_->stop_event_.reset(new base::WaitableEvent( |  | 
|   96         base::WaitableEvent::ResetPolicy::AUTOMATIC, |  | 
|   97         base::WaitableEvent::InitialState::NOT_SIGNALED)); |  | 
|   98  |  | 
|   99     // Allocate the allocator on the appropriate thread. |  | 
|  100     allocator_ = PostAndWait( |   77     allocator_ = PostAndWait( | 
|  101         FROM_HERE, base::Bind( |   78         FROM_HERE, base::Bind( | 
|  102                        [](AVDACodecAllocator::TestInformation* test_info) { |   79                        [](base::TickClock* clock, base::WaitableEvent* event) { | 
|  103                          return new AVDACodecAllocator(test_info); |   80                          return new AVDACodecAllocator(clock, event); | 
|  104                        }, |   81                        }, | 
|  105                        test_information_.get())); |   82                        &tick_clock_, &stop_event_)); | 
|  106     allocator2_ = new AVDACodecAllocator(test_information_.get()); |   83     allocator2_ = new AVDACodecAllocator(); | 
|  107  |  | 
|  108     // All threads should be stopped |  | 
|  109     ASSERT_FALSE(IsThreadRunning(TaskType::AUTO_CODEC)); |  | 
|  110     ASSERT_FALSE(IsThreadRunning(TaskType::SW_CODEC)); |  | 
|  111  |  | 
|  112     // Register an AVDA instance to start the allocator's threads. |  | 
|  113     ASSERT_TRUE(StartThread(avda1_)); |  | 
|  114  |  | 
|  115     // Assert that at least the AUTO_CODEC thread is started.  The other might |  | 
|  116     // not be. |  | 
|  117     ASSERT_TRUE(IsThreadRunning(TaskType::AUTO_CODEC)); |  | 
|  118     ASSERT_EQ(TaskType::AUTO_CODEC, TaskTypeForAllocation()); |  | 
|  119   } |   84   } | 
|  120  |   85  | 
|  121   void TearDown() override { |   86   void TearDown() override { | 
|  122     // Don't leave any threads hung, or this will hang too. |   87     // Don't leave any threads hung, or this will hang too. | 
|  123     // It would be nice if we could let a unique ptr handle this, but the |   88     // It would be nice if we could let a unique ptr handle this, but the | 
|  124     // destructor is private.  We also have to destroy it on the right thread. |   89     // destructor is private.  We also have to destroy it on the right thread. | 
|  125     PostAndWait(FROM_HERE, base::Bind( |   90     PostAndWait(FROM_HERE, base::Bind( | 
|  126                                [](AVDACodecAllocator* allocator) { |   91                                [](AVDACodecAllocator* allocator) { | 
|  127                                  delete allocator; |   92                                  delete allocator; | 
|  128                                  return true; |   93                                  return true; | 
| (...skipping 21 matching lines...) Expand all  Loading... | 
|  150     // stop has completed.  It's async with respect to the allocator thread. |  115     // stop has completed.  It's async with respect to the allocator thread. | 
|  151     PostAndWait(FROM_HERE, base::Bind( |  116     PostAndWait(FROM_HERE, base::Bind( | 
|  152                                [](AVDACodecAllocator* allocator, |  117                                [](AVDACodecAllocator* allocator, | 
|  153                                   AVDACodecAllocatorClient* avda) { |  118                                   AVDACodecAllocatorClient* avda) { | 
|  154                                  allocator->StopThread(avda); |  119                                  allocator->StopThread(avda); | 
|  155                                  return true; |  120                                  return true; | 
|  156                                }, |  121                                }, | 
|  157                                allocator_, avda)); |  122                                allocator_, avda)); | 
|  158     // Note that we don't do this on the allocator thread, since that's the |  123     // Note that we don't do this on the allocator thread, since that's the | 
|  159     // thread that will signal it. |  124     // thread that will signal it. | 
|  160     test_information_->stop_event_->Wait(); |  125     stop_event_.Wait(); | 
|  161   } |  126   } | 
|  162  |  127  | 
|  163   // Return the running state of |task_type|, doing the necessary thread hops. |  128   // Return the running state of |task_type|, doing the necessary thread hops. | 
|  164   bool IsThreadRunning(TaskType task_type) { |  129   bool IsThreadRunning(TaskType task_type) { | 
|  165     return PostAndWait( |  130     return PostAndWait( | 
|  166         FROM_HERE, |  131         FROM_HERE, | 
|  167         base::Bind( |  132         base::Bind( | 
|  168             [](AVDACodecAllocator* allocator, TaskType task_type) { |  133             [](AVDACodecAllocator* allocator, TaskType task_type) { | 
|  169               return allocator->GetThreadForTesting(task_type).IsRunning(); |  134               return allocator->GetThreadForTesting(task_type).IsRunning(); | 
|  170             }, |  135             }, | 
| (...skipping 24 matching lines...) Expand all  Loading... | 
|  195     ReturnType return_value = ReturnType(); |  160     ReturnType return_value = ReturnType(); | 
|  196     allocator_thread_.task_runner()->PostTask( |  161     allocator_thread_.task_runner()->PostTask( | 
|  197         from_here, |  162         from_here, | 
|  198         base::Bind(&RunAndSignalTask<ReturnType>, &event, &return_value, cb)); |  163         base::Bind(&RunAndSignalTask<ReturnType>, &event, &return_value, cb)); | 
|  199     event.Wait(); |  164     event.Wait(); | 
|  200     return return_value; |  165     return return_value; | 
|  201   } |  166   } | 
|  202  |  167  | 
|  203   base::Thread allocator_thread_; |  168   base::Thread allocator_thread_; | 
|  204  |  169  | 
|  205   // Test info that we provide to the codec allocator. |  170   // The test params for |allocator_|. | 
|  206   std::unique_ptr<AVDACodecAllocator::TestInformation> test_information_; |  171   base::SimpleTestTickClock tick_clock_; | 
 |  172   base::WaitableEvent stop_event_; | 
|  207  |  173  | 
|  208   // Allocators that we own. The first is intialized to be used on the allocator |  174   // Allocators that we own. The first is intialized to be used on the allocator | 
|  209   // thread and the second one is initialized on the test thread. Each test |  175   // thread and the second one is initialized on the test thread. Each test | 
|  210   // should only be using one of the two. They are not unique_ptrs because the |  176   // should only be using one of the two. They are not unique_ptrs because the | 
|  211   // destructor is private and they need to be destructed on the right thread. |  177   // destructor is private and they need to be destructed on the right thread. | 
|  212   AVDACodecAllocator* allocator_ = nullptr; |  178   AVDACodecAllocator* allocator_ = nullptr; | 
|  213   AVDACodecAllocator* allocator2_ = nullptr; |  179   AVDACodecAllocator* allocator2_ = nullptr; | 
|  214  |  180  | 
|  215   NiceMock<MockClient> client1_, client2_, client3_; |  181   NiceMock<MockClient> client1_, client2_, client3_; | 
|  216   NiceMock<MockClient>* avda1_ = &client1_; |  182   NiceMock<MockClient>* avda1_ = &client1_; | 
|  217   NiceMock<MockClient>* avda2_ = &client2_; |  183   NiceMock<MockClient>* avda2_ = &client2_; | 
|  218   NiceMock<MockClient>* avda3_ = &client3_; |  184   NiceMock<MockClient>* avda3_ = &client3_; | 
|  219 }; |  185 }; | 
|  220  |  186  | 
|  221 TEST_F(AVDACodecAllocatorTest, TestMultiInstance) { |  187 TEST_F(AVDACodecAllocatorTest, ThreadsStartWhenClientsStart) { | 
|  222   // Add an avda instance.  This one must succeed immediately, since the last |  | 
|  223   // one is still running. |  | 
|  224   ASSERT_TRUE(StartThread(avda2_)); |  | 
|  225  |  | 
|  226   // Stop the original avda instance. |  | 
|  227   StopThread(avda1_); |  | 
|  228  |  | 
|  229   // Verify that the AUTO_CODEC thread is still running. |  | 
|  230   ASSERT_TRUE(IsThreadRunning(TaskType::AUTO_CODEC)); |  | 
|  231   ASSERT_EQ(TaskType::AUTO_CODEC, TaskTypeForAllocation()); |  | 
|  232  |  | 
|  233   // Remove the second instance and wait for it to stop.  Remember that it |  | 
|  234   // stops after messages have been posted to the thread, so we don't know |  | 
|  235   // how long it will take. |  | 
|  236   StopThread(avda2_); |  | 
|  237  |  | 
|  238   // Verify that the threads have stopped. |  | 
|  239   ASSERT_FALSE(IsThreadRunning(TaskType::AUTO_CODEC)); |  188   ASSERT_FALSE(IsThreadRunning(TaskType::AUTO_CODEC)); | 
|  240   ASSERT_FALSE(IsThreadRunning(TaskType::SW_CODEC)); |  189   ASSERT_FALSE(IsThreadRunning(TaskType::SW_CODEC)); | 
 |  190   ASSERT_TRUE(StartThread(avda1_)); | 
 |  191   // Assert that the AUTO_CODEC thread is started. The other might not be. | 
 |  192   ASSERT_TRUE(IsThreadRunning(TaskType::AUTO_CODEC)); | 
 |  193 } | 
 |  194  | 
 |  195 TEST_F(AVDACodecAllocatorTest, ThreadsStopAfterAllClientsStop) { | 
 |  196   StartThread(avda1_); | 
 |  197   StartThread(avda2_); | 
 |  198   StopThread(avda1_); | 
 |  199   ASSERT_TRUE(IsThreadRunning(TaskType::AUTO_CODEC)); | 
 |  200   StopThread(avda2_); | 
 |  201   ASSERT_FALSE(IsThreadRunning(TaskType::AUTO_CODEC)); | 
 |  202   // Note the SW_CODEC thread might still be running. | 
|  241 } |  203 } | 
|  242  |  204  | 
|  243 TEST_F(AVDACodecAllocatorTest, TestHangThread) { |  205 TEST_F(AVDACodecAllocatorTest, TestHangThread) { | 
 |  206   StartThread(avda1_); | 
|  244   ASSERT_EQ(TaskType::AUTO_CODEC, TaskTypeForAllocation()); |  207   ASSERT_EQ(TaskType::AUTO_CODEC, TaskTypeForAllocation()); | 
|  245  |  208  | 
|  246   // Hang the AUTO_CODEC thread. |  209   // Hang the AUTO_CODEC thread. | 
|  247   base::WaitableEvent about_to_wait_event( |  210   base::WaitableEvent about_to_wait_event( | 
|  248       base::WaitableEvent::ResetPolicy::MANUAL, |  211       base::WaitableEvent::ResetPolicy::MANUAL, | 
|  249       base::WaitableEvent::InitialState::NOT_SIGNALED); |  212       base::WaitableEvent::InitialState::NOT_SIGNALED); | 
|  250   base::WaitableEvent wait_event( |  213   base::WaitableEvent wait_event( | 
|  251       base::WaitableEvent::ResetPolicy::MANUAL, |  214       base::WaitableEvent::ResetPolicy::MANUAL, | 
|  252       base::WaitableEvent::InitialState::NOT_SIGNALED); |  215       base::WaitableEvent::InitialState::NOT_SIGNALED); | 
|  253   TaskRunnerFor(TaskType::AUTO_CODEC) |  216   TaskRunnerFor(TaskType::AUTO_CODEC) | 
|  254       ->PostTask(FROM_HERE, base::Bind(&WaitUntilRestarted, |  217       ->PostTask(FROM_HERE, base::Bind(&WaitUntilRestarted, | 
|  255                                        &about_to_wait_event, &wait_event)); |  218                                        &about_to_wait_event, &wait_event)); | 
|  256   // Wait until the task starts, so that |allocator_| starts the hang timer. |  219   // Wait until the task starts, so that |allocator_| starts the hang timer. | 
|  257   about_to_wait_event.Wait(); |  220   about_to_wait_event.Wait(); | 
|  258  |  221  | 
|  259   // Verify that we've failed over after a long time has passed. |  222   // Verify that we've failed over after a long time has passed. | 
|  260   static_cast<MockTickClock*>(test_information_->tick_clock_.get()) |  223   tick_clock_.Advance(base::TimeDelta::FromSeconds(1)); | 
|  261       ->Advance(1000); |  | 
|  262   // Note that this should return the SW codec task type even if that thread |  224   // Note that this should return the SW codec task type even if that thread | 
|  263   // failed to start.  TaskRunnerFor() will return the current thread in that |  225   // failed to start.  TaskRunnerFor() will return the current thread in that | 
|  264   // case too. |  226   // case too. | 
|  265   ASSERT_EQ(TaskType::SW_CODEC, TaskTypeForAllocation()); |  227   ASSERT_EQ(TaskType::SW_CODEC, TaskTypeForAllocation()); | 
|  266  |  228  | 
|  267   // Un-hang the thread and wait for it to let another task run.  This will |  229   // Un-hang the thread and wait for it to let another task run.  This will | 
|  268   // notify |allocator_| that the thread is no longer hung. |  230   // notify |allocator_| that the thread is no longer hung. | 
|  269   base::WaitableEvent done_waiting_event( |  231   base::WaitableEvent done_waiting_event( | 
|  270       base::WaitableEvent::ResetPolicy::MANUAL, |  232       base::WaitableEvent::ResetPolicy::MANUAL, | 
|  271       base::WaitableEvent::InitialState::NOT_SIGNALED); |  233       base::WaitableEvent::InitialState::NOT_SIGNALED); | 
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  340  |  302  | 
|  341 TEST_F(AVDACodecAllocatorTest, DeallocatingIsSafeDuringSurfaceDestroyed) { |  303 TEST_F(AVDACodecAllocatorTest, DeallocatingIsSafeDuringSurfaceDestroyed) { | 
|  342   allocator2_->AllocateSurface(avda1_, 1); |  304   allocator2_->AllocateSurface(avda1_, 1); | 
|  343   EXPECT_CALL(*avda1_, OnSurfaceDestroyed()).WillOnce(Invoke([=]() { |  305   EXPECT_CALL(*avda1_, OnSurfaceDestroyed()).WillOnce(Invoke([=]() { | 
|  344     allocator2_->DeallocateSurface(avda1_, 1); |  306     allocator2_->DeallocateSurface(avda1_, 1); | 
|  345   })); |  307   })); | 
|  346   allocator2_->OnSurfaceDestroyed(1); |  308   allocator2_->OnSurfaceDestroyed(1); | 
|  347 } |  309 } | 
|  348  |  310  | 
|  349 }  // namespace media |  311 }  // namespace media | 
| OLD | NEW |