diff options
Diffstat (limited to 'gfx/tests/gtest/TestVsync.cpp')
-rw-r--r-- | gfx/tests/gtest/TestVsync.cpp | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/gfx/tests/gtest/TestVsync.cpp b/gfx/tests/gtest/TestVsync.cpp new file mode 100644 index 000000000..c9cd97ae7 --- /dev/null +++ b/gfx/tests/gtest/TestVsync.cpp @@ -0,0 +1,205 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "gfxPlatform.h" +#include "gfxPrefs.h" +#include "MainThreadUtils.h" +#include "nsIThread.h" +#include "mozilla/RefPtr.h" +#include "SoftwareVsyncSource.h" +#include "VsyncSource.h" +#include "mozilla/Monitor.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/VsyncDispatcher.h" + +using namespace mozilla; +using namespace mozilla::gfx; +using namespace mozilla::layers; +using ::testing::_; + +// Timeout for vsync events to occur in milliseconds +// Windows 8.1 has intermittents at 50 ms. Raise limit to 5 vsync intervals. +const int kVsyncTimeoutMS = 80; + +class TestVsyncObserver : public VsyncObserver { +public: + TestVsyncObserver() + : mDidGetVsyncNotification(false) + , mVsyncMonitor("VsyncMonitor") + { + } + + virtual bool NotifyVsync(TimeStamp aVsyncTimeStamp) override { + MonitorAutoLock lock(mVsyncMonitor); + mDidGetVsyncNotification = true; + mVsyncMonitor.Notify(); + return true; + } + + void WaitForVsyncNotification() + { + MOZ_ASSERT(NS_IsMainThread()); + if (DidGetVsyncNotification()) { + return; + } + + { // scope lock + MonitorAutoLock lock(mVsyncMonitor); + PRIntervalTime timeout = PR_MillisecondsToInterval(kVsyncTimeoutMS); + lock.Wait(timeout); + } + } + + bool DidGetVsyncNotification() + { + MonitorAutoLock lock(mVsyncMonitor); + return mDidGetVsyncNotification; + } + + void ResetVsyncNotification() + { + MonitorAutoLock lock(mVsyncMonitor); + mDidGetVsyncNotification = false; + } + +private: + bool mDidGetVsyncNotification; + +private: + Monitor mVsyncMonitor; +}; + +class VsyncTester : public ::testing::Test { +protected: + explicit VsyncTester() + { + gfxPlatform::GetPlatform(); + gfxPrefs::GetSingleton(); + mVsyncSource = gfxPlatform::GetPlatform()->GetHardwareVsync(); + MOZ_RELEASE_ASSERT(mVsyncSource, "GFX: Vsync source not found."); + } + + virtual ~VsyncTester() + { + mVsyncSource = nullptr; + } + + RefPtr<VsyncSource> mVsyncSource; +}; + +static void +FlushMainThreadLoop() +{ + // Some tasks are pushed onto the main thread when adding vsync observers + // This function will ensure all tasks are executed on the main thread + // before returning. + nsCOMPtr<nsIThread> mainThread; + nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread)); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + + rv = NS_OK; + bool processed = true; + while (processed && NS_SUCCEEDED(rv)) { + rv = mainThread->ProcessNextEvent(false, &processed); + } +} + +// Tests that we can enable/disable vsync notifications +TEST_F(VsyncTester, EnableVsync) +{ + VsyncSource::Display& globalDisplay = mVsyncSource->GetGlobalDisplay(); + globalDisplay.DisableVsync(); + ASSERT_FALSE(globalDisplay.IsVsyncEnabled()); + + globalDisplay.EnableVsync(); + ASSERT_TRUE(globalDisplay.IsVsyncEnabled()); + + globalDisplay.DisableVsync(); + ASSERT_FALSE(globalDisplay.IsVsyncEnabled()); +} + +// Test that if we have vsync enabled, the display should get vsync notifications +TEST_F(VsyncTester, CompositorGetVsyncNotifications) +{ + VsyncSource::Display& globalDisplay = mVsyncSource->GetGlobalDisplay(); + globalDisplay.DisableVsync(); + ASSERT_FALSE(globalDisplay.IsVsyncEnabled()); + + RefPtr<CompositorVsyncDispatcher> vsyncDispatcher = new CompositorVsyncDispatcher(); + RefPtr<TestVsyncObserver> testVsyncObserver = new TestVsyncObserver(); + + vsyncDispatcher->SetCompositorVsyncObserver(testVsyncObserver); + FlushMainThreadLoop(); + ASSERT_TRUE(globalDisplay.IsVsyncEnabled()); + + testVsyncObserver->WaitForVsyncNotification(); + ASSERT_TRUE(testVsyncObserver->DidGetVsyncNotification()); + + vsyncDispatcher = nullptr; + testVsyncObserver = nullptr; +} + +// Test that if we have vsync enabled, the parent refresh driver should get notifications +TEST_F(VsyncTester, ParentRefreshDriverGetVsyncNotifications) +{ + VsyncSource::Display& globalDisplay = mVsyncSource->GetGlobalDisplay(); + globalDisplay.DisableVsync(); + ASSERT_FALSE(globalDisplay.IsVsyncEnabled()); + + RefPtr<RefreshTimerVsyncDispatcher> vsyncDispatcher = globalDisplay.GetRefreshTimerVsyncDispatcher(); + ASSERT_TRUE(vsyncDispatcher != nullptr); + + RefPtr<TestVsyncObserver> testVsyncObserver = new TestVsyncObserver(); + vsyncDispatcher->SetParentRefreshTimer(testVsyncObserver); + ASSERT_TRUE(globalDisplay.IsVsyncEnabled()); + + testVsyncObserver->WaitForVsyncNotification(); + ASSERT_TRUE(testVsyncObserver->DidGetVsyncNotification()); + vsyncDispatcher->SetParentRefreshTimer(nullptr); + + testVsyncObserver->ResetVsyncNotification(); + testVsyncObserver->WaitForVsyncNotification(); + ASSERT_FALSE(testVsyncObserver->DidGetVsyncNotification()); + + vsyncDispatcher = nullptr; + testVsyncObserver = nullptr; +} + +// Test that child refresh vsync observers get vsync notifications +TEST_F(VsyncTester, ChildRefreshDriverGetVsyncNotifications) +{ + VsyncSource::Display& globalDisplay = mVsyncSource->GetGlobalDisplay(); + globalDisplay.DisableVsync(); + ASSERT_FALSE(globalDisplay.IsVsyncEnabled()); + + RefPtr<RefreshTimerVsyncDispatcher> vsyncDispatcher = globalDisplay.GetRefreshTimerVsyncDispatcher(); + ASSERT_TRUE(vsyncDispatcher != nullptr); + + RefPtr<TestVsyncObserver> testVsyncObserver = new TestVsyncObserver(); + vsyncDispatcher->AddChildRefreshTimer(testVsyncObserver); + ASSERT_TRUE(globalDisplay.IsVsyncEnabled()); + + testVsyncObserver->WaitForVsyncNotification(); + ASSERT_TRUE(testVsyncObserver->DidGetVsyncNotification()); + + vsyncDispatcher->RemoveChildRefreshTimer(testVsyncObserver); + testVsyncObserver->ResetVsyncNotification(); + testVsyncObserver->WaitForVsyncNotification(); + ASSERT_FALSE(testVsyncObserver->DidGetVsyncNotification()); + + vsyncDispatcher = nullptr; + testVsyncObserver = nullptr; +} + +// Test that we can read the vsync rate +TEST_F(VsyncTester, VsyncSourceHasVsyncRate) +{ + VsyncSource::Display& globalDisplay = mVsyncSource->GetGlobalDisplay(); + TimeDuration vsyncRate = globalDisplay.GetVsyncRate(); + ASSERT_NE(vsyncRate, TimeDuration::Forever()); + ASSERT_GT(vsyncRate.ToMilliseconds(), 0); +} |