diff options
Diffstat (limited to 'gfx/tests/gtest/TestVsync.cpp')
-rw-r--r-- | gfx/tests/gtest/TestVsync.cpp | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/gfx/tests/gtest/TestVsync.cpp b/gfx/tests/gtest/TestVsync.cpp new file mode 100644 index 0000000000..ed77c59b08 --- /dev/null +++ b/gfx/tests/gtest/TestVsync.cpp @@ -0,0 +1,203 @@ +/* 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 "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(const VsyncEvent& aVsync) override { + MonitorAutoLock lock(mVsyncMonitor); + mDidGetVsyncNotification = true; + mVsyncMonitor.Notify(); + return true; + } + + void WaitForVsyncNotification() { + MOZ_ASSERT(NS_IsMainThread()); + if (DidGetVsyncNotification()) { + return; + } + + { // scope lock + MonitorAutoLock lock(mVsyncMonitor); + lock.Wait(TimeDuration::FromMilliseconds(kVsyncTimeoutMS)); + } + } + + 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(); + 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; + + globalDisplay.DisableVsync(); + ASSERT_FALSE(globalDisplay.IsVsyncEnabled()); +} + +// 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; + + globalDisplay.DisableVsync(); + ASSERT_FALSE(globalDisplay.IsVsyncEnabled()); +} + +// 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; + + globalDisplay.DisableVsync(); + ASSERT_FALSE(globalDisplay.IsVsyncEnabled()); +} + +// 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); + + globalDisplay.DisableVsync(); + ASSERT_FALSE(globalDisplay.IsVsyncEnabled()); +} |