summaryrefslogtreecommitdiffstats
path: root/gfx/thebes/VsyncSource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/thebes/VsyncSource.cpp')
-rw-r--r--gfx/thebes/VsyncSource.cpp153
1 files changed, 153 insertions, 0 deletions
diff --git a/gfx/thebes/VsyncSource.cpp b/gfx/thebes/VsyncSource.cpp
new file mode 100644
index 000000000..cb69db560
--- /dev/null
+++ b/gfx/thebes/VsyncSource.cpp
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "VsyncSource.h"
+#include "nsThreadUtils.h"
+#include "nsXULAppAPI.h"
+#include "mozilla/VsyncDispatcher.h"
+#include "MainThreadUtils.h"
+
+namespace mozilla {
+namespace gfx {
+
+void
+VsyncSource::AddCompositorVsyncDispatcher(CompositorVsyncDispatcher* aCompositorVsyncDispatcher)
+{
+ MOZ_ASSERT(XRE_IsParentProcess());
+ MOZ_ASSERT(NS_IsMainThread());
+ // Just use the global display until we have enough information to get the
+ // corresponding display for compositor.
+ GetGlobalDisplay().AddCompositorVsyncDispatcher(aCompositorVsyncDispatcher);
+}
+
+void
+VsyncSource::RemoveCompositorVsyncDispatcher(CompositorVsyncDispatcher* aCompositorVsyncDispatcher)
+{
+ MOZ_ASSERT(XRE_IsParentProcess());
+ MOZ_ASSERT(NS_IsMainThread());
+ // See also AddCompositorVsyncDispatcher().
+ GetGlobalDisplay().RemoveCompositorVsyncDispatcher(aCompositorVsyncDispatcher);
+}
+
+RefPtr<RefreshTimerVsyncDispatcher>
+VsyncSource::GetRefreshTimerVsyncDispatcher()
+{
+ MOZ_ASSERT(XRE_IsParentProcess());
+ // See also AddCompositorVsyncDispatcher().
+ return GetGlobalDisplay().GetRefreshTimerVsyncDispatcher();
+}
+
+VsyncSource::Display::Display()
+ : mDispatcherLock("display dispatcher lock")
+ , mRefreshTimerNeedsVsync(false)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ mRefreshTimerVsyncDispatcher = new RefreshTimerVsyncDispatcher();
+}
+
+VsyncSource::Display::~Display()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MutexAutoLock lock(mDispatcherLock);
+ mRefreshTimerVsyncDispatcher = nullptr;
+ mCompositorVsyncDispatchers.Clear();
+}
+
+void
+VsyncSource::Display::NotifyVsync(TimeStamp aVsyncTimestamp)
+{
+ // Called on the vsync thread
+ MutexAutoLock lock(mDispatcherLock);
+
+ for (size_t i = 0; i < mCompositorVsyncDispatchers.Length(); i++) {
+ mCompositorVsyncDispatchers[i]->NotifyVsync(aVsyncTimestamp);
+ }
+
+ mRefreshTimerVsyncDispatcher->NotifyVsync(aVsyncTimestamp);
+}
+
+TimeDuration
+VsyncSource::Display::GetVsyncRate()
+{
+ // If hardware queries fail / are unsupported, we have to just guess.
+ return TimeDuration::FromMilliseconds(1000.0 / 60.0);
+}
+
+void
+VsyncSource::Display::AddCompositorVsyncDispatcher(CompositorVsyncDispatcher* aCompositorVsyncDispatcher)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(aCompositorVsyncDispatcher);
+ { // scope lock
+ MutexAutoLock lock(mDispatcherLock);
+ if (!mCompositorVsyncDispatchers.Contains(aCompositorVsyncDispatcher)) {
+ mCompositorVsyncDispatchers.AppendElement(aCompositorVsyncDispatcher);
+ }
+ }
+ UpdateVsyncStatus();
+}
+
+void
+VsyncSource::Display::RemoveCompositorVsyncDispatcher(CompositorVsyncDispatcher* aCompositorVsyncDispatcher)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(aCompositorVsyncDispatcher);
+ { // Scope lock
+ MutexAutoLock lock(mDispatcherLock);
+ if (mCompositorVsyncDispatchers.Contains(aCompositorVsyncDispatcher)) {
+ mCompositorVsyncDispatchers.RemoveElement(aCompositorVsyncDispatcher);
+ }
+ }
+ UpdateVsyncStatus();
+}
+
+void
+VsyncSource::Display::NotifyRefreshTimerVsyncStatus(bool aEnable)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ mRefreshTimerNeedsVsync = aEnable;
+ UpdateVsyncStatus();
+}
+
+void
+VsyncSource::Display::UpdateVsyncStatus()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ // WARNING: This function SHOULD NOT BE CALLED WHILE HOLDING LOCKS
+ // NotifyVsync grabs a lock to dispatch vsync events
+ // When disabling vsync, we wait for the underlying thread to stop on some platforms
+ // We can deadlock if we wait for the underlying vsync thread to stop
+ // while the vsync thread is in NotifyVsync.
+ bool enableVsync = false;
+ { // scope lock
+ MutexAutoLock lock(mDispatcherLock);
+ enableVsync = !mCompositorVsyncDispatchers.IsEmpty() || mRefreshTimerNeedsVsync;
+ }
+
+ if (enableVsync) {
+ EnableVsync();
+ } else {
+ DisableVsync();
+ }
+
+ if (IsVsyncEnabled() != enableVsync) {
+ NS_WARNING("Vsync status did not change.");
+ }
+}
+
+RefPtr<RefreshTimerVsyncDispatcher>
+VsyncSource::Display::GetRefreshTimerVsyncDispatcher()
+{
+ return mRefreshTimerVsyncDispatcher;
+}
+
+void
+VsyncSource::Shutdown()
+{
+ GetGlobalDisplay().Shutdown();
+}
+
+} //namespace gfx
+} //namespace mozilla