summaryrefslogtreecommitdiffstats
path: root/widget/android/AndroidVsync.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--widget/android/AndroidVsync.cpp140
1 files changed, 140 insertions, 0 deletions
diff --git a/widget/android/AndroidVsync.cpp b/widget/android/AndroidVsync.cpp
new file mode 100644
index 0000000000..a25644ce80
--- /dev/null
+++ b/widget/android/AndroidVsync.cpp
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "AndroidVsync.h"
+
+#include "nsTArray.h"
+
+/**
+ * Implementation for the AndroidVsync class.
+ */
+
+namespace mozilla {
+namespace widget {
+
+StaticDataMutex<ThreadSafeWeakPtr<AndroidVsync>> AndroidVsync::sInstance(
+ "AndroidVsync::sInstance");
+
+/* static */ RefPtr<AndroidVsync> AndroidVsync::GetInstance() {
+ auto weakInstance = sInstance.Lock();
+ RefPtr<AndroidVsync> instance(*weakInstance);
+ if (!instance) {
+ instance = new AndroidVsync();
+ *weakInstance = instance;
+ }
+ return instance;
+}
+
+/**
+ * Owned by the Java AndroidVsync instance.
+ */
+class AndroidVsyncSupport final
+ : public java::AndroidVsync::Natives<AndroidVsyncSupport> {
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AndroidVsyncSupport)
+
+ using Base = java::AndroidVsync::Natives<AndroidVsyncSupport>;
+ using Base::AttachNative;
+ using Base::DisposeNative;
+
+ explicit AndroidVsyncSupport(AndroidVsync* aAndroidVsync)
+ : mAndroidVsync(std::move(aAndroidVsync),
+ "AndroidVsyncSupport::mAndroidVsync") {}
+
+ // Called by Java
+ void NotifyVsync(const java::AndroidVsync::LocalRef& aInstance,
+ int64_t aFrameTimeNanos) {
+ auto androidVsync = mAndroidVsync.Lock();
+ if (*androidVsync) {
+ (*androidVsync)->NotifyVsync(aFrameTimeNanos);
+ }
+ }
+
+ // Called by the AndroidVsync destructor
+ void Unlink() {
+ auto androidVsync = mAndroidVsync.Lock();
+ *androidVsync = nullptr;
+ }
+
+ protected:
+ ~AndroidVsyncSupport() = default;
+
+ DataMutex<AndroidVsync*> mAndroidVsync;
+};
+
+AndroidVsync::AndroidVsync() : mImpl("AndroidVsync.mImpl") {
+ AndroidVsyncSupport::Init();
+
+ auto impl = mImpl.Lock();
+ impl->mSupport = new AndroidVsyncSupport(this);
+ impl->mSupportJava = java::AndroidVsync::New();
+ AndroidVsyncSupport::AttachNative(impl->mSupportJava, impl->mSupport);
+ float fps = impl->mSupportJava->GetRefreshRate();
+ impl->mVsyncDuration = TimeDuration::FromMilliseconds(1000.0 / fps);
+}
+
+AndroidVsync::~AndroidVsync() {
+ auto impl = mImpl.Lock();
+ impl->mInputObservers.Clear();
+ impl->mRenderObservers.Clear();
+ impl->UpdateObservingVsync();
+ impl->mSupport->Unlink();
+}
+
+TimeDuration AndroidVsync::GetVsyncRate() {
+ auto impl = mImpl.Lock();
+ return impl->mVsyncDuration;
+}
+
+void AndroidVsync::RegisterObserver(Observer* aObserver, ObserverType aType) {
+ auto impl = mImpl.Lock();
+ if (aType == AndroidVsync::INPUT) {
+ impl->mInputObservers.AppendElement(aObserver);
+ } else {
+ impl->mRenderObservers.AppendElement(aObserver);
+ }
+ impl->UpdateObservingVsync();
+}
+
+void AndroidVsync::UnregisterObserver(Observer* aObserver, ObserverType aType) {
+ auto impl = mImpl.Lock();
+ if (aType == AndroidVsync::INPUT) {
+ impl->mInputObservers.RemoveElement(aObserver);
+ } else {
+ impl->mRenderObservers.RemoveElement(aObserver);
+ }
+ impl->UpdateObservingVsync();
+}
+
+void AndroidVsync::Impl::UpdateObservingVsync() {
+ bool shouldObserve =
+ !mInputObservers.IsEmpty() || !mRenderObservers.IsEmpty();
+ if (shouldObserve != mObservingVsync) {
+ mObservingVsync = mSupportJava->ObserveVsync(shouldObserve);
+ }
+}
+
+// Always called on the Java UI thread.
+void AndroidVsync::NotifyVsync(int64_t aFrameTimeNanos) {
+ // Convert aFrameTimeNanos to a TimeStamp. The value converts trivially to
+ // the internal ticks representation of TimeStamp_posix; both use the
+ // monotonic clock and are in nanoseconds.
+ TimeStamp timeStamp = TimeStamp::FromSystemTime(aFrameTimeNanos);
+
+ // Do not keep the lock held while calling OnVsync.
+ nsTArray<Observer*> observers;
+ {
+ auto impl = mImpl.Lock();
+ observers.AppendElements(impl->mInputObservers);
+ observers.AppendElements(impl->mRenderObservers);
+ }
+ for (Observer* observer : observers) {
+ observer->OnVsync(timeStamp);
+ }
+}
+
+} // namespace widget
+} // namespace mozilla