summaryrefslogtreecommitdiffstats
path: root/gfx/tests/gtest/TestVsync.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/tests/gtest/TestVsync.cpp')
-rw-r--r--gfx/tests/gtest/TestVsync.cpp205
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);
+}