diff options
Diffstat (limited to 'widget/android/AndroidVsync.cpp')
-rw-r--r-- | widget/android/AndroidVsync.cpp | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/widget/android/AndroidVsync.cpp b/widget/android/AndroidVsync.cpp new file mode 100644 index 0000000000..b168154810 --- /dev/null +++ b/widget/android/AndroidVsync.cpp @@ -0,0 +1,142 @@ +/* -*- 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 "mozilla/java/GeckoAppShellWrappers.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 = java::GeckoAppShell::GetScreenRefreshRate(); + 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); + } + aObserver->Dispose(); + 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 |