TestVsync.cpp (5136B)
1 /* vim:set ts=2 sw=2 sts=2 et: */ 2 /* Any copyright is dedicated to the Public Domain. 3 * http://creativecommons.org/publicdomain/zero/1.0/ 4 */ 5 6 #include "gmock/gmock.h" 7 #include "gtest/gtest.h" 8 #include "gfxPlatform.h" 9 10 #include "MainThreadUtils.h" 11 #include "nsIThread.h" 12 #include "mozilla/RefPtr.h" 13 #include "SoftwareVsyncSource.h" 14 #include "VsyncSource.h" 15 #include "mozilla/gtest/MozAssertions.h" 16 #include "mozilla/Monitor.h" 17 #include "mozilla/TimeStamp.h" 18 #include "mozilla/VsyncDispatcher.h" 19 20 using namespace mozilla; 21 using namespace mozilla::gfx; 22 using namespace mozilla::layers; 23 using ::testing::_; 24 25 // Timeout for vsync events to occur in milliseconds 26 // Windows 8.1 has intermittents at 50 ms. Raise limit to 5 vsync intervals. 27 const int kVsyncTimeoutMS = 80; 28 29 class TestVsyncObserver : public VsyncObserver { 30 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestVsyncObserver, override) 31 32 public: 33 TestVsyncObserver() 34 : mDidGetVsyncNotification(false), mVsyncMonitor("VsyncMonitor") {} 35 36 virtual void NotifyVsync(const VsyncEvent& aVsync) override { 37 MonitorAutoLock lock(mVsyncMonitor); 38 mDidGetVsyncNotification = true; 39 mVsyncMonitor.Notify(); 40 } 41 42 void WaitForVsyncNotification() { 43 MOZ_ASSERT(NS_IsMainThread()); 44 if (DidGetVsyncNotification()) { 45 return; 46 } 47 48 { // scope lock 49 MonitorAutoLock lock(mVsyncMonitor); 50 lock.Wait(TimeDuration::FromMilliseconds(kVsyncTimeoutMS)); 51 } 52 } 53 54 bool DidGetVsyncNotification() { 55 MonitorAutoLock lock(mVsyncMonitor); 56 return mDidGetVsyncNotification; 57 } 58 59 void ResetVsyncNotification() { 60 MonitorAutoLock lock(mVsyncMonitor); 61 mDidGetVsyncNotification = false; 62 } 63 64 private: 65 ~TestVsyncObserver() = default; 66 67 bool mDidGetVsyncNotification; 68 69 private: 70 Monitor mVsyncMonitor MOZ_UNANNOTATED; 71 }; 72 73 class VsyncTester : public ::testing::Test { 74 protected: 75 explicit VsyncTester() { 76 gfxPlatform::GetPlatform(); 77 mVsyncDispatcher = gfxPlatform::GetPlatform()->GetGlobalVsyncDispatcher(); 78 mVsyncSource = mVsyncDispatcher->GetCurrentVsyncSource(); 79 MOZ_RELEASE_ASSERT(mVsyncSource, "GFX: Vsync source not found."); 80 } 81 82 virtual ~VsyncTester() { mVsyncSource = nullptr; } 83 84 RefPtr<VsyncDispatcher> mVsyncDispatcher; 85 RefPtr<VsyncSource> mVsyncSource; 86 }; 87 88 static void FlushMainThreadLoop() { 89 // Some tasks are pushed onto the main thread when adding vsync observers 90 // This function will ensure all tasks are executed on the main thread 91 // before returning. 92 nsCOMPtr<nsIThread> mainThread; 93 nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread)); 94 ASSERT_NS_SUCCEEDED(rv); 95 96 rv = NS_OK; 97 bool processed = true; 98 while (processed && NS_SUCCEEDED(rv)) { 99 rv = mainThread->ProcessNextEvent(false, &processed); 100 } 101 } 102 103 // Tests that we can enable/disable vsync notifications 104 TEST_F(VsyncTester, EnableVsync) { 105 mVsyncSource->DisableVsync(); 106 ASSERT_FALSE(mVsyncSource->IsVsyncEnabled()); 107 108 mVsyncSource->EnableVsync(); 109 ASSERT_TRUE(mVsyncSource->IsVsyncEnabled()); 110 111 mVsyncSource->DisableVsync(); 112 ASSERT_FALSE(mVsyncSource->IsVsyncEnabled()); 113 } 114 115 // Test that if we have vsync enabled, the source should get vsync 116 // notifications 117 TEST_F(VsyncTester, CompositorGetVsyncNotifications) { 118 mVsyncSource->DisableVsync(); 119 ASSERT_FALSE(mVsyncSource->IsVsyncEnabled()); 120 121 RefPtr<CompositorVsyncDispatcher> vsyncDispatcher = 122 new CompositorVsyncDispatcher(mVsyncDispatcher); 123 RefPtr<TestVsyncObserver> testVsyncObserver = new TestVsyncObserver(); 124 125 vsyncDispatcher->SetCompositorVsyncObserver(testVsyncObserver); 126 FlushMainThreadLoop(); 127 ASSERT_TRUE(mVsyncSource->IsVsyncEnabled()); 128 129 testVsyncObserver->WaitForVsyncNotification(); 130 ASSERT_TRUE(testVsyncObserver->DidGetVsyncNotification()); 131 132 vsyncDispatcher->SetCompositorVsyncObserver(nullptr); 133 FlushMainThreadLoop(); 134 135 vsyncDispatcher = nullptr; 136 testVsyncObserver = nullptr; 137 ASSERT_FALSE(mVsyncSource->IsVsyncEnabled()); 138 } 139 140 // Test that child refresh vsync observers get vsync notifications 141 TEST_F(VsyncTester, ChildRefreshDriverGetVsyncNotifications) { 142 mVsyncSource->DisableVsync(); 143 ASSERT_FALSE(mVsyncSource->IsVsyncEnabled()); 144 145 ASSERT_TRUE(mVsyncDispatcher != nullptr); 146 147 RefPtr<TestVsyncObserver> testVsyncObserver = new TestVsyncObserver(); 148 mVsyncDispatcher->AddVsyncObserver(testVsyncObserver); 149 ASSERT_TRUE(mVsyncSource->IsVsyncEnabled()); 150 151 testVsyncObserver->WaitForVsyncNotification(); 152 ASSERT_TRUE(testVsyncObserver->DidGetVsyncNotification()); 153 154 mVsyncDispatcher->RemoveVsyncObserver(testVsyncObserver); 155 testVsyncObserver->ResetVsyncNotification(); 156 testVsyncObserver->WaitForVsyncNotification(); 157 ASSERT_FALSE(testVsyncObserver->DidGetVsyncNotification()); 158 159 testVsyncObserver = nullptr; 160 161 mVsyncSource->DisableVsync(); 162 ASSERT_FALSE(mVsyncSource->IsVsyncEnabled()); 163 } 164 165 // Test that we can read the vsync rate 166 TEST_F(VsyncTester, VsyncSourceHasVsyncRate) { 167 TimeDuration vsyncRate = mVsyncSource->GetVsyncRate(); 168 ASSERT_NE(vsyncRate, TimeDuration::Forever()); 169 ASSERT_GT(vsyncRate.ToMilliseconds(), 0); 170 171 mVsyncSource->DisableVsync(); 172 ASSERT_FALSE(mVsyncSource->IsVsyncEnabled()); 173 }