forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			150 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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 "AndroidBridge.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);
 | |
| }
 | |
| 
 | |
| AndroidVsync::~AndroidVsync() {
 | |
|   auto impl = mImpl.Lock();
 | |
|   impl->mInputObservers.Clear();
 | |
|   impl->mRenderObservers.Clear();
 | |
|   impl->UpdateObservingVsync();
 | |
|   impl->mSupport->Unlink();
 | |
| }
 | |
| 
 | |
| 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) {
 | |
|   MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
 | |
| 
 | |
|   // 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);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void AndroidVsync::OnMaybeUpdateRefreshRate() {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   auto impl = mImpl.Lock();
 | |
| 
 | |
|   nsTArray<Observer*> observers;
 | |
|   observers.AppendElements(impl->mRenderObservers);
 | |
| 
 | |
|   for (Observer* observer : observers) {
 | |
|     observer->OnMaybeUpdateRefreshRate();
 | |
|   }
 | |
| }
 | |
| 
 | |
| }  // namespace widget
 | |
| }  // namespace mozilla
 | 
