forked from mirrors/gecko-dev
		
	Backed out changeset 3a9dce735340 (bug 1645528) for causing crashes with nsRefreshDriver CLOSED TREE
This commit is contained in:
		
							parent
							
								
									77dfbe7938
								
							
						
					
					
						commit
						c5213774a6
					
				
					 19 changed files with 305 additions and 294 deletions
				
			
		|  | @ -14,7 +14,6 @@ | |||
| #include <algorithm> | ||||
| #include <utility> | ||||
| 
 | ||||
| #include "BackgroundChild.h" | ||||
| #include "BrowserParent.h" | ||||
| #include "ClientLayerManager.h" | ||||
| #include "ContentChild.h" | ||||
|  | @ -75,7 +74,6 @@ | |||
| #include "mozilla/gfx/Matrix.h" | ||||
| #include "mozilla/gfx/gfxVars.h" | ||||
| #include "mozilla/ipc/BackgroundUtils.h" | ||||
| #include "mozilla/ipc/PBackgroundChild.h" | ||||
| #include "mozilla/ipc/URIUtils.h" | ||||
| #include "mozilla/layers/APZCCallbackHelper.h" | ||||
| #include "mozilla/layers/APZCTreeManagerChild.h" | ||||
|  | @ -144,10 +142,6 @@ | |||
| #  include "mozilla/plugins/PluginWidgetChild.h" | ||||
| #endif | ||||
| 
 | ||||
| #ifdef MOZ_WAYLAND | ||||
| #  include "nsAppRunner.h" | ||||
| #endif | ||||
| 
 | ||||
| #ifdef NS_PRINTING | ||||
| #  include "nsIPrintSession.h" | ||||
| #  include "nsIPrintSettings.h" | ||||
|  | @ -320,7 +314,6 @@ BrowserChild::BrowserChild(ContentChild* aManager, const TabId& aTabId, | |||
|       mDidFakeShow(false), | ||||
|       mTriedBrowserInit(false), | ||||
|       mOrientation(hal::eScreenOrientation_PortraitPrimary), | ||||
|       mVsyncChild(nullptr), | ||||
|       mIgnoreKeyPressEvent(false), | ||||
|       mHasValidInnerSize(false), | ||||
|       mDestroyed(false), | ||||
|  | @ -557,8 +550,6 @@ nsresult BrowserChild::Init(mozIDOMWindowProxy* aParent, | |||
|   NS_ENSURE_SUCCESS(rv, rv); | ||||
| #endif | ||||
| 
 | ||||
|   InitVsyncChild(); | ||||
| 
 | ||||
|   // We've all set up, make sure our visibility state is consistent. This is
 | ||||
|   // important for OOP iframes, which start off as hidden.
 | ||||
|   UpdateVisibility(); | ||||
|  | @ -566,20 +557,6 @@ nsresult BrowserChild::Init(mozIDOMWindowProxy* aParent, | |||
|   return NS_OK; | ||||
| } | ||||
| 
 | ||||
| void BrowserChild::InitVsyncChild() { | ||||
| #if defined(MOZ_WAYLAND) | ||||
|   if (!IsWaylandDisabled()) { | ||||
|     PVsyncChild* actor = SendPVsyncConstructor(); | ||||
|     mVsyncChild = static_cast<VsyncChild*>(actor); | ||||
|   } else | ||||
| #endif | ||||
|   { | ||||
|     PBackgroundChild* actorChild = | ||||
|         BackgroundChild::GetOrCreateForCurrentThread(); | ||||
|     mVsyncChild = static_cast<VsyncChild*>(actorChild->SendPVsyncConstructor()); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void BrowserChild::NotifyTabContextUpdated() { | ||||
|   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); | ||||
|   MOZ_ASSERT(docShell); | ||||
|  | @ -2166,23 +2143,6 @@ bool BrowserChild::DeallocPFilePickerChild(PFilePickerChild* actor) { | |||
|   return true; | ||||
| } | ||||
| 
 | ||||
| PVsyncChild* BrowserChild::AllocPVsyncChild() { | ||||
|   RefPtr<dom::VsyncChild> actor = new VsyncChild(); | ||||
|   // There still has one ref-count after return, and it will be released in
 | ||||
|   // DeallocPVsyncChild().
 | ||||
|   return actor.forget().take(); | ||||
| } | ||||
| 
 | ||||
| bool BrowserChild::DeallocPVsyncChild(PVsyncChild* aActor) { | ||||
|   MOZ_ASSERT(aActor); | ||||
| 
 | ||||
|   // This actor already has one ref-count. Please check AllocPVsyncChild().
 | ||||
|   RefPtr<VsyncChild> actor = dont_AddRef(static_cast<VsyncChild*>(aActor)); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| RefPtr<VsyncChild> BrowserChild::GetVsyncChild() { return mVsyncChild; } | ||||
| 
 | ||||
| mozilla::ipc::IPCResult BrowserChild::RecvActivateFrameEvent( | ||||
|     const nsString& aType, const bool& capture) { | ||||
|   nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation()); | ||||
|  |  | |||
|  | @ -29,7 +29,6 @@ | |||
| #include "mozilla/dom/CoalescedMouseData.h" | ||||
| #include "mozilla/dom/CoalescedWheelData.h" | ||||
| #include "mozilla/dom/MessageManagerCallback.h" | ||||
| #include "mozilla/dom/VsyncChild.h" | ||||
| #include "mozilla/DOMEventTargetHelper.h" | ||||
| #include "mozilla/EventDispatcher.h" | ||||
| #include "mozilla/EventForwards.h" | ||||
|  | @ -437,12 +436,6 @@ class BrowserChild final : public nsMessageManagerScriptExecutor, | |||
|   PFilePickerChild* AllocPFilePickerChild(const nsString& aTitle, | ||||
|                                           const int16_t& aMode); | ||||
| 
 | ||||
|   virtual PVsyncChild* AllocPVsyncChild(); | ||||
| 
 | ||||
|   virtual bool DeallocPVsyncChild(PVsyncChild* aActor); | ||||
| 
 | ||||
|   RefPtr<VsyncChild> GetVsyncChild(); | ||||
| 
 | ||||
|   bool DeallocPFilePickerChild(PFilePickerChild* aActor); | ||||
| 
 | ||||
|   nsIWebNavigation* WebNavigation() const { return mWebNav; } | ||||
|  | @ -754,8 +747,6 @@ class BrowserChild final : public nsMessageManagerScriptExecutor, | |||
|       const mozilla::layers::CompositorOptions& aCompositorOptions); | ||||
|   void InitAPZState(); | ||||
| 
 | ||||
|   void InitVsyncChild(); | ||||
| 
 | ||||
|   void DestroyWindow(); | ||||
| 
 | ||||
|   void ApplyParentShowInfo(const ParentShowInfo&); | ||||
|  | @ -823,8 +814,6 @@ class BrowserChild final : public nsMessageManagerScriptExecutor, | |||
|   bool mTriedBrowserInit; | ||||
|   hal::ScreenOrientation mOrientation; | ||||
| 
 | ||||
|   RefPtr<VsyncChild> mVsyncChild; | ||||
| 
 | ||||
|   bool mIgnoreKeyPressEvent; | ||||
|   RefPtr<APZEventState> mAPZEventState; | ||||
|   SetAllowedTouchBehaviorCallback mSetAllowedTouchBehaviorCallback; | ||||
|  |  | |||
|  | @ -129,7 +129,6 @@ | |||
| #include "mozilla/dom/CrashReport.h" | ||||
| #include "nsISecureBrowserUI.h" | ||||
| #include "nsIXULRuntime.h" | ||||
| #include "VsyncSource.h" | ||||
| 
 | ||||
| #ifdef XP_WIN | ||||
| #  include "mozilla/plugins/PluginWidgetParent.h" | ||||
|  | @ -225,7 +224,6 @@ BrowserParent::BrowserParent(ContentParent* aManager, const TabId& aTabId, | |||
|       mCustomCursorHotspotX(0), | ||||
|       mCustomCursorHotspotY(0), | ||||
|       mVerifyDropLinks{}, | ||||
|       mVsyncParent(nullptr), | ||||
|       mDocShellIsActive(false), | ||||
|       mMarkedDestroying(false), | ||||
|       mIsDestroyed(false), | ||||
|  | @ -565,8 +563,6 @@ void BrowserParent::SetOwnerElement(Element* aElement) { | |||
|     mBrowsingContext->SetEmbedderElement(mFrameElement); | ||||
|   } | ||||
| 
 | ||||
|   UpdateVsyncParentVsyncSource(); | ||||
| 
 | ||||
|   VisitChildren([aElement](BrowserBridgeParent* aBrowser) { | ||||
|     if (auto* browserParent = aBrowser->GetBrowserParent()) { | ||||
|       browserParent->SetOwnerElement(aElement); | ||||
|  | @ -1350,28 +1346,6 @@ IPCResult BrowserParent::RecvNewWindowGlobal( | |||
|   return IPC_OK(); | ||||
| } | ||||
| 
 | ||||
| PVsyncParent* BrowserParent::AllocPVsyncParent() { | ||||
|   MOZ_ASSERT(!mVsyncParent); | ||||
|   mVsyncParent = new VsyncParent(); | ||||
|   UpdateVsyncParentVsyncSource(); | ||||
|   return mVsyncParent.get(); | ||||
| } | ||||
| 
 | ||||
| bool BrowserParent::DeallocPVsyncParent(PVsyncParent* aActor) { | ||||
|   mVsyncParent = nullptr; | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| void BrowserParent::UpdateVsyncParentVsyncSource() { | ||||
|   if (!mVsyncParent) { | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   if (nsCOMPtr<nsIWidget> widget = GetWidget()) { | ||||
|     mVsyncParent->UpdateVsyncSource(widget->GetVsyncSource()); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void BrowserParent::SendMouseEvent(const nsAString& aType, float aX, float aY, | ||||
|                                    int32_t aButton, int32_t aClickCount, | ||||
|                                    int32_t aModifiers) { | ||||
|  |  | |||
|  | @ -18,7 +18,6 @@ | |||
| #include "mozilla/dom/BrowserBridgeParent.h" | ||||
| #include "mozilla/dom/PBrowserParent.h" | ||||
| #include "mozilla/dom/TabContext.h" | ||||
| #include "mozilla/dom/VsyncParent.h" | ||||
| #include "mozilla/dom/ipc/IdType.h" | ||||
| #include "mozilla/layout/RemoteLayerTreeOwner.h" | ||||
| #include "nsCOMPtr.h" | ||||
|  | @ -461,10 +460,6 @@ class BrowserParent final : public PBrowserParent, | |||
| 
 | ||||
|   bool DeallocPColorPickerParent(PColorPickerParent* aColorPicker); | ||||
| 
 | ||||
|   PVsyncParent* AllocPVsyncParent(); | ||||
| 
 | ||||
|   bool DeallocPVsyncParent(PVsyncParent* aActor); | ||||
| 
 | ||||
| #ifdef ACCESSIBILITY | ||||
|   PDocAccessibleParent* AllocPDocAccessibleParent(PDocAccessibleParent*, | ||||
|                                                   const uint64_t&, | ||||
|  | @ -877,8 +872,6 @@ class BrowserParent final : public PBrowserParent, | |||
|   void SendRealTouchMoveEvent(WidgetTouchEvent& aEvent, APZData& aAPZData, | ||||
|                               uint32_t aConsecutiveTouchMoveCount); | ||||
| 
 | ||||
|   void UpdateVsyncParentVsyncSource(); | ||||
| 
 | ||||
|  public: | ||||
|   // Unsets sTopLevelWebFocus regardless of its current value.
 | ||||
|   static void UnsetTopLevelWebFocusAll(); | ||||
|  | @ -964,8 +957,6 @@ class BrowserParent final : public PBrowserParent, | |||
| 
 | ||||
|   nsTArray<nsString> mVerifyDropLinks; | ||||
| 
 | ||||
|   RefPtr<VsyncParent> mVsyncParent; | ||||
| 
 | ||||
| #ifdef DEBUG | ||||
|   int32_t mActiveSupressDisplayportCount = 0; | ||||
| #endif | ||||
|  |  | |||
|  | @ -20,7 +20,6 @@ include protocol PRemoteLazyInputStream; | |||
| include protocol PPaymentRequest; | ||||
| include protocol PWindowGlobal; | ||||
| include protocol PBrowserBridge; | ||||
| include protocol PVsync; | ||||
| 
 | ||||
| include DOMTypes; | ||||
| include NeckoChannelParams; | ||||
|  | @ -191,7 +190,6 @@ nested(upto inside_cpow) sync refcounted protocol PBrowser | |||
|     manages PPaymentRequest; | ||||
|     manages PWindowGlobal; | ||||
|     manages PBrowserBridge; | ||||
|     manages PVsync; | ||||
| 
 | ||||
| both: | ||||
|     async AsyncMessage(nsString aMessage, ClonedMessageData aData); | ||||
|  | @ -219,11 +217,6 @@ parent: | |||
| 
 | ||||
|     async PPaymentRequest(); | ||||
| 
 | ||||
|     /** | ||||
|      * Create a new Vsync connection for our associated root widget | ||||
|      */ | ||||
|     async PVsync(); | ||||
| 
 | ||||
|     /** | ||||
|      * Sends an NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW to be adopted by the | ||||
|      * widget's shareable window on the chrome side. Only used on Windows. | ||||
|  |  | |||
|  | @ -71,8 +71,6 @@ EXPORTS.mozilla.dom += [ | |||
|     "URLClassifierChild.h", | ||||
|     "URLClassifierParent.h", | ||||
|     "UserActivationIPCUtils.h", | ||||
|     "VsyncChild.h", | ||||
|     "VsyncParent.h", | ||||
|     "WindowGlobalActor.h", | ||||
|     "WindowGlobalChild.h", | ||||
|     "WindowGlobalParent.h", | ||||
|  | @ -132,8 +130,6 @@ UNIFIED_SOURCES += [ | |||
| SOURCES += [ | ||||
|     "ContentChild.cpp", | ||||
|     "ProcessHangMonitor.cpp", | ||||
|     "VsyncChild.cpp", | ||||
|     "VsyncParent.cpp", | ||||
| ] | ||||
| 
 | ||||
| PREPROCESSED_IPDL_SOURCES += [ | ||||
|  | @ -159,7 +155,6 @@ IPDL_SOURCES += [ | |||
|     "PURLClassifier.ipdl", | ||||
|     "PURLClassifierInfo.ipdlh", | ||||
|     "PURLClassifierLocal.ipdl", | ||||
|     "PVsync.ipdl", | ||||
|     "PWindowGlobal.ipdl", | ||||
|     "ServiceWorkerConfiguration.ipdlh", | ||||
|     "WindowGlobalTypes.ipdlh", | ||||
|  |  | |||
|  | @ -46,11 +46,11 @@ | |||
| #include "mozilla/dom/ServiceWorkerContainerChild.h" | ||||
| #include "mozilla/dom/ServiceWorkerManagerChild.h" | ||||
| #include "mozilla/dom/BrowserChild.h" | ||||
| #include "mozilla/dom/VsyncChild.h" | ||||
| #include "mozilla/ipc/IPCStreamAlloc.h" | ||||
| #include "mozilla/ipc/PBackgroundTestChild.h" | ||||
| #include "mozilla/ipc/PChildToParentStreamChild.h" | ||||
| #include "mozilla/ipc/PParentToChildStreamChild.h" | ||||
| #include "mozilla/layout/VsyncChild.h" | ||||
| #include "mozilla/net/HttpBackgroundChannelChild.h" | ||||
| #include "mozilla/net/PUDPSocketChild.h" | ||||
| #include "mozilla/dom/network/UDPSocketChild.h" | ||||
|  | @ -408,8 +408,8 @@ bool BackgroundChildImpl::DeallocPFileDescriptorSetChild( | |||
|   return true; | ||||
| } | ||||
| 
 | ||||
| dom::PVsyncChild* BackgroundChildImpl::AllocPVsyncChild() { | ||||
|   RefPtr<dom::VsyncChild> actor = new dom::VsyncChild(); | ||||
| BackgroundChildImpl::PVsyncChild* BackgroundChildImpl::AllocPVsyncChild() { | ||||
|   RefPtr<mozilla::layout::VsyncChild> actor = new mozilla::layout::VsyncChild(); | ||||
|   // There still has one ref-count after return, and it will be released in
 | ||||
|   // DeallocPVsyncChild().
 | ||||
|   return actor.forget().take(); | ||||
|  | @ -419,8 +419,8 @@ bool BackgroundChildImpl::DeallocPVsyncChild(PVsyncChild* aActor) { | |||
|   MOZ_ASSERT(aActor); | ||||
| 
 | ||||
|   // This actor already has one ref-count. Please check AllocPVsyncChild().
 | ||||
|   RefPtr<dom::VsyncChild> actor = | ||||
|       dont_AddRef(static_cast<dom::VsyncChild*>(aActor)); | ||||
|   RefPtr<mozilla::layout::VsyncChild> actor = | ||||
|       dont_AddRef(static_cast<mozilla::layout::VsyncChild*>(aActor)); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
|  | @ -619,7 +619,7 @@ bool BackgroundChildImpl::DeallocPClientManagerChild( | |||
| 
 | ||||
| #ifdef EARLY_BETA_OR_EARLIER | ||||
| void BackgroundChildImpl::OnChannelReceivedMessage(const Message& aMsg) { | ||||
|   if (aMsg.type() == dom::PVsync::MessageType::Msg_Notify__ID) { | ||||
|   if (aMsg.type() == layout::PVsync::MessageType::Msg_Notify__ID) { | ||||
|     // Not really necessary to look at the message payload, it will be
 | ||||
|     // <0.5ms away from TimeStamp::Now()
 | ||||
|     SchedulerGroup::MarkVsyncReceived(); | ||||
|  |  | |||
|  | @ -55,7 +55,6 @@ | |||
| #include "mozilla/dom/network/UDPSocketParent.h" | ||||
| #include "mozilla/dom/quota/ActorsParent.h" | ||||
| #include "mozilla/dom/simpledb/ActorsParent.h" | ||||
| #include "mozilla/dom/VsyncParent.h" | ||||
| #include "mozilla/ipc/BackgroundParent.h" | ||||
| #include "mozilla/ipc/BackgroundUtils.h" | ||||
| #include "mozilla/ipc/Endpoint.h" | ||||
|  | @ -65,6 +64,7 @@ | |||
| #include "mozilla/ipc/PBackgroundTestParent.h" | ||||
| #include "mozilla/ipc/PChildToParentStreamParent.h" | ||||
| #include "mozilla/ipc/PParentToChildStreamParent.h" | ||||
| #include "mozilla/layout/VsyncParent.h" | ||||
| #include "mozilla/media/MediaParent.h" | ||||
| #include "mozilla/net/BackgroundDataBridgeParent.h" | ||||
| #include "mozilla/net/HttpBackgroundChannelParent.h" | ||||
|  | @ -717,8 +717,8 @@ BackgroundParentImpl::PVsyncParent* BackgroundParentImpl::AllocPVsyncParent() { | |||
|   AssertIsInMainOrSocketProcess(); | ||||
|   AssertIsOnBackgroundThread(); | ||||
| 
 | ||||
|   RefPtr<mozilla::dom::VsyncParent> actor = new mozilla::dom::VsyncParent(); | ||||
|   actor->UpdateVsyncSource(nullptr); | ||||
|   RefPtr<mozilla::layout::VsyncParent> actor = | ||||
|       mozilla::layout::VsyncParent::Create(); | ||||
|   // There still has one ref-count after return, and it will be released in
 | ||||
|   // DeallocPVsyncParent().
 | ||||
|   return actor.forget().take(); | ||||
|  | @ -730,8 +730,8 @@ bool BackgroundParentImpl::DeallocPVsyncParent(PVsyncParent* aActor) { | |||
|   MOZ_ASSERT(aActor); | ||||
| 
 | ||||
|   // This actor already has one ref-count. Please check AllocPVsyncParent().
 | ||||
|   RefPtr<mozilla::dom::VsyncParent> actor = | ||||
|       dont_AddRef(static_cast<mozilla::dom::VsyncParent*>(aActor)); | ||||
|   RefPtr<mozilla::layout::VsyncParent> actor = | ||||
|       dont_AddRef(static_cast<mozilla::layout::VsyncParent*>(aActor)); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,6 +12,11 @@ | |||
| #include "mozilla/ipc/PBackgroundParent.h" | ||||
| 
 | ||||
| namespace mozilla { | ||||
| 
 | ||||
| namespace layout { | ||||
| class VsyncParent; | ||||
| }  // namespace layout
 | ||||
| 
 | ||||
| namespace ipc { | ||||
| 
 | ||||
| // Instances of this class should never be created directly. This class is meant
 | ||||
|  |  | |||
|  | @ -692,6 +692,9 @@ nsresult nsPresContext::Init(nsDeviceContext* aDeviceContext) { | |||
| 
 | ||||
|     if (!mRefreshDriver) { | ||||
|       mRefreshDriver = new nsRefreshDriver(this); | ||||
|       if (XRE_IsContentProcess()) { | ||||
|         mRefreshDriver->InitializeTimer(); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -59,12 +59,10 @@ | |||
| #include "nsViewManager.h" | ||||
| #include "GeckoProfiler.h" | ||||
| #include "nsNPAPIPluginInstance.h" | ||||
| #include "mozilla/dom/BrowserChild.h" | ||||
| #include "mozilla/dom/CallbackDebuggerNotification.h" | ||||
| #include "mozilla/dom/Event.h" | ||||
| #include "mozilla/dom/Performance.h" | ||||
| #include "mozilla/dom/Selection.h" | ||||
| #include "mozilla/dom/VsyncChild.h" | ||||
| #include "mozilla/dom/WindowBinding.h" | ||||
| #include "mozilla/RestyleManager.h" | ||||
| #include "Layers.h" | ||||
|  | @ -77,6 +75,7 @@ | |||
| 
 | ||||
| #include "BackgroundChild.h" | ||||
| #include "mozilla/ipc/PBackgroundChild.h" | ||||
| #include "mozilla/layout/VsyncChild.h" | ||||
| #include "VsyncSource.h" | ||||
| #include "mozilla/VsyncDispatcher.h" | ||||
| #include "mozilla/Unused.h" | ||||
|  | @ -247,6 +246,26 @@ class RefreshDriverTimer { | |||
| 
 | ||||
|   TimeStamp MostRecentRefresh() const { return mLastFireTime; } | ||||
| 
 | ||||
|   void SwapRefreshDrivers(RefreshDriverTimer* aNewTimer) { | ||||
|     MOZ_ASSERT(NS_IsMainThread()); | ||||
| 
 | ||||
|     for (nsRefreshDriver* driver : mContentRefreshDrivers) { | ||||
|       aNewTimer->AddRefreshDriver(driver); | ||||
|       driver->mActiveTimer = aNewTimer; | ||||
|     } | ||||
|     mContentRefreshDrivers.Clear(); | ||||
| 
 | ||||
|     for (nsRefreshDriver* driver : mRootRefreshDrivers) { | ||||
|       aNewTimer->AddRefreshDriver(driver); | ||||
|       driver->mActiveTimer = aNewTimer; | ||||
|     } | ||||
|     mRootRefreshDrivers.Clear(); | ||||
| 
 | ||||
|     aNewTimer->mLastFireTime = mLastFireTime; | ||||
| 
 | ||||
|     StopTimer(); | ||||
|   } | ||||
| 
 | ||||
|   virtual TimeDuration GetTimerRate() = 0; | ||||
| 
 | ||||
|   TimeStamp GetIdleDeadlineHint(TimeStamp aDefault) { | ||||
|  | @ -427,45 +446,56 @@ class SimpleTimerBasedRefreshDriverTimer : public RefreshDriverTimer { | |||
|  */ | ||||
| class VsyncRefreshDriverTimer : public RefreshDriverTimer { | ||||
|  public: | ||||
|   VsyncRefreshDriverTimer() | ||||
|       : mVsyncChild(nullptr), mVsyncRate(TimeDuration::Forever()) { | ||||
|   VsyncRefreshDriverTimer() : mVsyncChild(nullptr) { | ||||
|     MOZ_ASSERT(XRE_IsParentProcess()); | ||||
|     MOZ_ASSERT(NS_IsMainThread()); | ||||
|     mVsyncSource = gfxPlatform::GetPlatform()->GetHardwareVsync(); | ||||
|     mVsyncObserver = new RefreshDriverVsyncObserver(this); | ||||
|     RefPtr<mozilla::gfx::VsyncSource> vsyncSource = | ||||
|         gfxPlatform::GetPlatform()->GetHardwareVsync(); | ||||
|     MOZ_ALWAYS_TRUE(mVsyncDispatcher = | ||||
|                         mVsyncSource->GetRefreshTimerVsyncDispatcher()); | ||||
|                         vsyncSource->GetRefreshTimerVsyncDispatcher()); | ||||
|     mVsyncDispatcher->AddChildRefreshTimer(mVsyncObserver); | ||||
|     mVsyncRate = vsyncSource->GetGlobalDisplay().GetVsyncRate(); | ||||
|   } | ||||
| 
 | ||||
|   explicit VsyncRefreshDriverTimer(VsyncChild* aVsyncChild) | ||||
|       : mVsyncChild(aVsyncChild) { | ||||
|     MOZ_ASSERT(!XRE_IsParentProcess()); | ||||
|     MOZ_ASSERT(NS_IsMainThread()); | ||||
|     MOZ_ASSERT(mVsyncChild); | ||||
|     mVsyncObserver = new RefreshDriverVsyncObserver(this); | ||||
|     mVsyncChild->SetVsyncObserver(mVsyncObserver); | ||||
|     mVsyncRate = mVsyncChild->GetVsyncRate(); | ||||
|   } | ||||
| 
 | ||||
|   // Constructor for when we have a local vsync source. As it is local, we do
 | ||||
|   // not have to worry about it being re-inited by gfxPlatform on frame rate
 | ||||
|   // change on the global source.
 | ||||
|   explicit VsyncRefreshDriverTimer(const RefPtr<gfx::VsyncSource>& aVsyncSource) | ||||
|       : mVsyncSource(aVsyncSource), | ||||
|         mVsyncChild(nullptr), | ||||
|         mVsyncRate(TimeDuration::Forever()) { | ||||
|       : mVsyncChild(nullptr) { | ||||
|     MOZ_ASSERT(XRE_IsParentProcess()); | ||||
|     MOZ_ASSERT(NS_IsMainThread()); | ||||
|     mVsyncSource = aVsyncSource; | ||||
|     mVsyncObserver = new RefreshDriverVsyncObserver(this); | ||||
|     MOZ_ALWAYS_TRUE(mVsyncDispatcher = | ||||
|                         aVsyncSource->GetRefreshTimerVsyncDispatcher()); | ||||
|   } | ||||
| 
 | ||||
|   explicit VsyncRefreshDriverTimer(const RefPtr<VsyncChild>& aVsyncChild) | ||||
|       : mVsyncSource(nullptr), | ||||
|         mVsyncDispatcher(nullptr), | ||||
|         mVsyncChild(aVsyncChild), | ||||
|         mVsyncRate(TimeDuration::Forever()) { | ||||
|     MOZ_ASSERT(XRE_IsContentProcess()); | ||||
|     MOZ_ASSERT(NS_IsMainThread()); | ||||
|     mVsyncObserver = new RefreshDriverVsyncObserver(this); | ||||
|     mVsyncDispatcher->AddChildRefreshTimer(mVsyncObserver); | ||||
|     mVsyncRate = aVsyncSource->GetGlobalDisplay().GetVsyncRate(); | ||||
|   } | ||||
| 
 | ||||
|   TimeDuration GetTimerRate() override { | ||||
|     if (mVsyncSource) { | ||||
|       mVsyncRate = mVsyncSource->GetGlobalDisplay().GetVsyncRate(); | ||||
|     } else if (mVsyncChild) { | ||||
|       mVsyncRate = mVsyncChild->GetVsyncRate(); | ||||
|     if (mVsyncRate != TimeDuration::Forever()) { | ||||
|       return mVsyncRate; | ||||
|     } | ||||
| 
 | ||||
|     if (mVsyncChild) { | ||||
|       // VsyncChild::VsyncRate() is a simple getter for the cached
 | ||||
|       // hardware vsync rate. We depend on that
 | ||||
|       // VsyncChild::GetVsyncRate() being called in the constructor
 | ||||
|       // will result in a response with the actual vsync rate sooner
 | ||||
|       // or later. Until that happens VsyncChild::VsyncRate() returns
 | ||||
|       // TimeDuration::Forever() and we have to guess below.
 | ||||
|       mVsyncRate = mVsyncChild->VsyncRate(); | ||||
|     } | ||||
| 
 | ||||
|     // If hardware queries fail / are unsupported, we have to just guess.
 | ||||
|  | @ -742,11 +772,16 @@ class VsyncRefreshDriverTimer : public RefreshDriverTimer { | |||
|   };  // RefreshDriverVsyncObserver
 | ||||
| 
 | ||||
|   ~VsyncRefreshDriverTimer() override { | ||||
|     if (mVsyncDispatcher) { | ||||
|     if (XRE_IsParentProcess()) { | ||||
|       mVsyncDispatcher->RemoveChildRefreshTimer(mVsyncObserver); | ||||
|       mVsyncDispatcher = nullptr; | ||||
|     } else if (mVsyncChild) { | ||||
|       mVsyncChild->RemoveChildRefreshTimer(mVsyncObserver); | ||||
|     } else { | ||||
|       // Since the PVsyncChild actors live through the life of the process, just
 | ||||
|       // send the unobserveVsync message to disable vsync event. We don't need
 | ||||
|       // to handle the cleanup stuff of this actor. PVsyncChild::ActorDestroy()
 | ||||
|       // will be called and clean up this actor.
 | ||||
|       Unused << mVsyncChild->SendUnobserve(); | ||||
|       mVsyncChild->SetVsyncObserver(nullptr); | ||||
|       mVsyncChild = nullptr; | ||||
|     } | ||||
| 
 | ||||
|  | @ -762,10 +797,10 @@ class VsyncRefreshDriverTimer : public RefreshDriverTimer { | |||
| 
 | ||||
|     mLastFireTime = TimeStamp::Now(); | ||||
| 
 | ||||
|     if (mVsyncDispatcher) { | ||||
|     if (XRE_IsParentProcess()) { | ||||
|       mVsyncDispatcher->AddChildRefreshTimer(mVsyncObserver); | ||||
|     } else if (mVsyncChild) { | ||||
|       mVsyncChild->AddChildRefreshTimer(mVsyncObserver); | ||||
|     } else { | ||||
|       Unused << mVsyncChild->SendObserve(); | ||||
|       mVsyncObserver->OnTimerStart(); | ||||
|     } | ||||
| 
 | ||||
|  | @ -776,10 +811,10 @@ class VsyncRefreshDriverTimer : public RefreshDriverTimer { | |||
|     // Protect updates to `sActiveVsyncTimers`.
 | ||||
|     MOZ_ASSERT(NS_IsMainThread()); | ||||
| 
 | ||||
|     if (mVsyncDispatcher) { | ||||
|     if (XRE_IsParentProcess()) { | ||||
|       mVsyncDispatcher->RemoveChildRefreshTimer(mVsyncObserver); | ||||
|     } else if (mVsyncChild) { | ||||
|       mVsyncChild->RemoveChildRefreshTimer(mVsyncObserver); | ||||
|     } else { | ||||
|       Unused << mVsyncChild->SendUnobserve(); | ||||
|     } | ||||
| 
 | ||||
|     MOZ_ASSERT(sActiveVsyncTimers > 0); | ||||
|  | @ -971,12 +1006,34 @@ class InactiveRefreshDriverTimer final | |||
| 
 | ||||
| }  // namespace mozilla
 | ||||
| 
 | ||||
| static nsTArray<RefreshDriverTimer*>* sRegularRateTimers; | ||||
| static StaticRefPtr<RefreshDriverTimer> sRegularRateTimer; | ||||
| static StaticRefPtr<InactiveRefreshDriverTimer> sThrottledRateTimer; | ||||
| 
 | ||||
| static void CreateContentVsyncRefreshTimer(void*) { | ||||
|   MOZ_ASSERT(NS_IsMainThread()); | ||||
|   MOZ_ASSERT(!XRE_IsParentProcess()); | ||||
| 
 | ||||
|   // Create the PVsync actor child for vsync-base refresh timer.
 | ||||
|   // PBackgroundChild is created synchronously. We will still use software
 | ||||
|   // timer before PVsync ready, and change to use hw timer when the connection
 | ||||
|   // is done. Please check nsRefreshDriver::PVsyncActorCreated().
 | ||||
| 
 | ||||
|   PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread(); | ||||
|   if (NS_WARN_IF(!actorChild)) { | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   layout::PVsyncChild* actor = actorChild->SendPVsyncConstructor(); | ||||
|   if (NS_WARN_IF(!actor)) { | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   layout::VsyncChild* child = static_cast<layout::VsyncChild*>(actor); | ||||
|   nsRefreshDriver::PVsyncActorCreated(child); | ||||
| } | ||||
| 
 | ||||
| void nsRefreshDriver::CreateVsyncRefreshTimer() { | ||||
|   MOZ_ASSERT(NS_IsMainThread()); | ||||
|   MOZ_ASSERT(!mOwnTimer); | ||||
| 
 | ||||
|   PodArrayZero(sJankLevels); | ||||
| 
 | ||||
|  | @ -985,25 +1042,32 @@ void nsRefreshDriver::CreateVsyncRefreshTimer() { | |||
|   } | ||||
| 
 | ||||
|   // If available, we fetch the widget-specific vsync source.
 | ||||
|   //
 | ||||
|   // NOTE(heycam): If we are initializing an nsRefreshDriver under
 | ||||
|   // nsPresContext::Init, then this GetRootWidget() call will fail, as the
 | ||||
|   // pres context does not yet have a pres shell. For now, null check the
 | ||||
|   // pres shell to avoid a console warning.
 | ||||
|   nsPresContext* pc = GetPresContext(); | ||||
|   nsIWidget* widget = pc->GetPresShell() ? pc->GetRootWidget() : nullptr; | ||||
|   if (widget) { | ||||
|     if (RefPtr<gfx::VsyncSource> localVsyncSource = widget->GetVsyncSource()) { | ||||
|     RefPtr<gfx::VsyncSource> localVsyncSource = widget->GetVsyncSource(); | ||||
|     if (localVsyncSource) { | ||||
|       mOwnTimer = new VsyncRefreshDriverTimer(localVsyncSource); | ||||
|     } else if (BrowserChild* browserChild = widget->GetOwningBrowserChild()) { | ||||
|       if (RefPtr<VsyncChild> localVsyncSource = browserChild->GetVsyncChild()) { | ||||
|         mOwnTimer = new VsyncRefreshDriverTimer(localVsyncSource); | ||||
|       } | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if (!mOwnTimer) { | ||||
|     mOwnTimer = new StartupRefreshDriverTimer(GetRegularTimerInterval()); | ||||
|   if (XRE_IsParentProcess()) { | ||||
|     // Make sure all vsync systems are ready.
 | ||||
|     gfxPlatform::GetPlatform(); | ||||
|     // In parent process, we don't need to use ipc. We can create the
 | ||||
|     // VsyncRefreshDriverTimer directly.
 | ||||
|     sRegularRateTimer = new VsyncRefreshDriverTimer(); | ||||
|     return; | ||||
|   } | ||||
|   if (!sRegularRateTimers) { | ||||
|     sRegularRateTimers = new nsTArray<RefreshDriverTimer*>(); | ||||
|   } | ||||
|   sRegularRateTimers->AppendElement(mOwnTimer.get()); | ||||
| 
 | ||||
|   // If this process is not created by NUWA, just create the vsync timer here.
 | ||||
|   CreateContentVsyncRefreshTimer(nullptr); | ||||
| } | ||||
| 
 | ||||
| static uint32_t GetFirstFrameDelay(imgIRequest* req) { | ||||
|  | @ -1021,10 +1085,8 @@ static uint32_t GetFirstFrameDelay(imgIRequest* req) { | |||
| 
 | ||||
| /* static */ | ||||
| void nsRefreshDriver::Shutdown() { | ||||
|   MOZ_ASSERT(NS_IsMainThread()); | ||||
|   // clean up our timers
 | ||||
|   delete sRegularRateTimers; | ||||
|   sRegularRateTimers = nullptr; | ||||
|   sRegularRateTimer = nullptr; | ||||
|   sThrottledRateTimer = nullptr; | ||||
| } | ||||
| 
 | ||||
|  | @ -1080,10 +1142,26 @@ RefreshDriverTimer* nsRefreshDriver::ChooseTimer() { | |||
|     return sThrottledRateTimer; | ||||
|   } | ||||
| 
 | ||||
|   if (!mOwnTimer) { | ||||
|   if (!sRegularRateTimer && !mOwnTimer) { | ||||
|     double rate = GetRegularTimerInterval(); | ||||
| 
 | ||||
|     // Try to use vsync-base refresh timer first for sRegularRateTimer.
 | ||||
|     CreateVsyncRefreshTimer(); | ||||
| 
 | ||||
|     if (mOwnTimer) { | ||||
|       return mOwnTimer.get(); | ||||
|     } | ||||
| 
 | ||||
|     if (!sRegularRateTimer) { | ||||
|       sRegularRateTimer = new StartupRefreshDriverTimer(rate); | ||||
|     } | ||||
|   } | ||||
|   return mOwnTimer.get(); | ||||
| 
 | ||||
|   if (mOwnTimer) { | ||||
|     return mOwnTimer.get(); | ||||
|   } | ||||
| 
 | ||||
|   return sRegularRateTimer; | ||||
| } | ||||
| 
 | ||||
| nsRefreshDriver::nsRefreshDriver(nsPresContext* aPresContext) | ||||
|  | @ -1135,9 +1213,6 @@ nsRefreshDriver::~nsRefreshDriver() { | |||
|     mRootRefresh->RemoveRefreshObserver(this, FlushType::Style); | ||||
|     mRootRefresh = nullptr; | ||||
|   } | ||||
|   if (mOwnTimer && sRegularRateTimers) { | ||||
|     sRegularRateTimers->RemoveElement(mOwnTimer.get()); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // Method for testing.  See nsIDOMWindowUtils.advanceTimeAndRefresh
 | ||||
|  | @ -2600,6 +2675,21 @@ void nsRefreshDriver::SetThrottled(bool aThrottled) { | |||
| 
 | ||||
| nsPresContext* nsRefreshDriver::GetPresContext() const { return mPresContext; } | ||||
| 
 | ||||
| /*static*/ | ||||
| void nsRefreshDriver::PVsyncActorCreated(VsyncChild* aVsyncChild) { | ||||
|   MOZ_ASSERT(NS_IsMainThread()); | ||||
|   MOZ_ASSERT(!XRE_IsParentProcess()); | ||||
|   RefPtr<RefreshDriverTimer> vsyncRefreshDriverTimer = | ||||
|       new VsyncRefreshDriverTimer(aVsyncChild); | ||||
| 
 | ||||
|   // If we are using software timer, swap current timer to
 | ||||
|   // VsyncRefreshDriverTimer.
 | ||||
|   if (sRegularRateTimer) { | ||||
|     sRegularRateTimer->SwapRefreshDrivers(vsyncRefreshDriverTimer); | ||||
|   } | ||||
|   sRegularRateTimer = std::move(vsyncRefreshDriverTimer); | ||||
| } | ||||
| 
 | ||||
| void nsRefreshDriver::DoRefresh() { | ||||
|   // Don't do a refresh unless we're in a state where we should be refreshing.
 | ||||
|   if (!IsFrozen() && mPresContext && mActiveTimer) { | ||||
|  | @ -2676,34 +2766,27 @@ TimeStamp nsRefreshDriver::GetIdleDeadlineHint(TimeStamp aDefault) { | |||
|   MOZ_ASSERT(NS_IsMainThread()); | ||||
|   MOZ_ASSERT(!aDefault.IsNull()); | ||||
| 
 | ||||
|   if (!sRegularRateTimers || sRegularRateTimers->IsEmpty()) { | ||||
|   if (!sRegularRateTimer) { | ||||
|     return aDefault; | ||||
|   } | ||||
| 
 | ||||
|   // For computing idleness of refresh drivers we only care about
 | ||||
|   // sRegularRateTimers, since we consider refresh drivers attached to
 | ||||
|   // sRegularRateTimer, since we consider refresh drivers attached to
 | ||||
|   // sThrottledRateTimer to be inactive. This implies that tasks
 | ||||
|   // resulting from a tick on the sRegularRateTimer counts as being
 | ||||
|   // busy but tasks resulting from a tick on sThrottledRateTimer
 | ||||
|   // counts as being idle.
 | ||||
|   return sRegularRateTimers->ElementAt(0)->GetIdleDeadlineHint(aDefault); | ||||
|   return sRegularRateTimer->GetIdleDeadlineHint(aDefault); | ||||
| } | ||||
| 
 | ||||
| /* static */ | ||||
| Maybe<TimeStamp> nsRefreshDriver::GetNextTickHint() { | ||||
|   MOZ_ASSERT(NS_IsMainThread()); | ||||
| 
 | ||||
|   if (!sRegularRateTimers) { | ||||
|   if (!sRegularRateTimer) { | ||||
|     return Nothing(); | ||||
|   } | ||||
| 
 | ||||
|   for (RefreshDriverTimer* timer : *sRegularRateTimers) { | ||||
|     Maybe<TimeStamp> tickHint = timer->GetNextTickHint(); | ||||
|     if (tickHint.isSome()) { | ||||
|       return tickHint; | ||||
|     } | ||||
|   } | ||||
|   return Nothing(); | ||||
|   return sRegularRateTimer->GetNextTickHint(); | ||||
| } | ||||
| 
 | ||||
| void nsRefreshDriver::Disconnect() { | ||||
|  |  | |||
|  | @ -43,6 +43,10 @@ class PresShell; | |||
| class RefreshDriverTimer; | ||||
| class Runnable; | ||||
| 
 | ||||
| namespace layout { | ||||
| class VsyncChild; | ||||
| }  // namespace layout
 | ||||
| 
 | ||||
| }  // namespace mozilla
 | ||||
| 
 | ||||
| class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator, | ||||
|  | @ -294,6 +298,14 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator, | |||
|    */ | ||||
|   nsPresContext* GetPresContext() const; | ||||
| 
 | ||||
|   /**
 | ||||
|    * PBackgroundChild actor is created asynchronously in content process. | ||||
|    * We can't create vsync-based timers during PBackground startup. This | ||||
|    * function will be called when PBackgroundChild actor is created. Then we can | ||||
|    * do the pending vsync-based timer creation. | ||||
|    */ | ||||
|   static void PVsyncActorCreated(mozilla::layout::VsyncChild* aVsyncChild); | ||||
| 
 | ||||
|   void CreateVsyncRefreshTimer(); | ||||
| 
 | ||||
| #ifdef DEBUG | ||||
|  |  | |||
|  | @ -23,6 +23,9 @@ class AnimationEventDispatcher; | |||
| class PendingFullscreenEvent; | ||||
| class PresShell; | ||||
| class RefreshDriverTimer; | ||||
| namespace layout { | ||||
| class VsyncChild; | ||||
| } | ||||
| }  // namespace mozilla
 | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -4,23 +4,22 @@ | |||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||
| 
 | ||||
| include protocol PBackground; | ||||
| include protocol PBrowser; | ||||
| include "mozilla/layers/LayersMessageUtils.h"; | ||||
| 
 | ||||
| using class mozilla::TimeStamp from "mozilla/TimeStamp.h"; | ||||
| using mozilla::VsyncEvent from "mozilla/VsyncDispatcher.h"; | ||||
| 
 | ||||
| namespace mozilla { | ||||
| namespace dom { | ||||
| namespace layout { | ||||
| 
 | ||||
| /* | ||||
|  * The PVsync is a sub-protocol in PBackground or PBrowser and it is used to | ||||
|  * notify the vsync event from chrome to content process. It also provides the | ||||
|  * The PVsync is a sub-protocol in PBackground and it is used to notify | ||||
|  * the vsync event from chrome to content process. It also provides the | ||||
|  * interfaces for content to observe/unobserve vsync event notifications. | ||||
|  */ | ||||
| async protocol PVsync | ||||
| { | ||||
|   manager PBackground or PBrowser; | ||||
|   manager PBackground; | ||||
| 
 | ||||
| child: | ||||
|   // Send vsync event from chrome to content process. | ||||
|  | @ -36,9 +35,10 @@ parent: | |||
|   async RequestVsyncRate(); | ||||
| 
 | ||||
|   // This message is never sent. Each PVsync actor will stay alive as long as | ||||
|   // its PBackground or PBrowser manager. | ||||
|   // its PBackground manager. | ||||
|   async __delete__(); | ||||
| }; | ||||
| 
 | ||||
| } // namespace dom | ||||
| } // namespace layout | ||||
| } // namespace mozilla | ||||
| 
 | ||||
|  | @ -10,18 +10,17 @@ | |||
| #include "mozilla/VsyncDispatcher.h" | ||||
| #include "nsThreadUtils.h" | ||||
| 
 | ||||
| namespace mozilla::dom { | ||||
| namespace mozilla::layout { | ||||
| 
 | ||||
| VsyncChild::VsyncChild() | ||||
|     : mIsShutdown(false), | ||||
|       mVsyncRate(TimeDuration::Forever()), | ||||
|       lastVsyncRateTime(TimeStamp()) { | ||||
|     : mObservingVsync(false), | ||||
|       mIsShutdown(false), | ||||
|       mVsyncRate(TimeDuration::Forever()) { | ||||
|   MOZ_ASSERT(NS_IsMainThread()); | ||||
| } | ||||
| 
 | ||||
| VsyncChild::~VsyncChild() { MOZ_ASSERT(NS_IsMainThread()); } | ||||
| 
 | ||||
| /* do not delete yet so the file history is preserved
 | ||||
| bool VsyncChild::SendObserve() { | ||||
|   MOZ_ASSERT(NS_IsMainThread()); | ||||
|   if (!mObservingVsync && !mIsShutdown) { | ||||
|  | @ -39,42 +38,12 @@ bool VsyncChild::SendUnobserve() { | |||
|   } | ||||
|   return true; | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| void VsyncChild::AddChildRefreshTimer(VsyncObserver* aVsyncObserver) { | ||||
|   MOZ_ASSERT(NS_IsMainThread()); | ||||
|   MOZ_ASSERT(!mObservers.Contains(aVsyncObserver)); | ||||
| 
 | ||||
|   if (mIsShutdown) { | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   if (mObservers.IsEmpty()) { | ||||
|     Unused << PVsyncChild::SendObserve(); | ||||
|   } | ||||
|   mObservers.AppendElement(std::move(aVsyncObserver)); | ||||
| } | ||||
| 
 | ||||
| void VsyncChild::RemoveChildRefreshTimer(VsyncObserver* aVsyncObserver) { | ||||
|   MOZ_ASSERT(NS_IsMainThread()); | ||||
|   if (mIsShutdown) { | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   if (mObservers.RemoveElement(aVsyncObserver) && mObservers.IsEmpty()) { | ||||
|     Unused << PVsyncChild::SendUnobserve(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void VsyncChild::ActorDestroy(ActorDestroyReason aActorDestroyReason) { | ||||
|   MOZ_ASSERT(NS_IsMainThread()); | ||||
|   MOZ_ASSERT(!mIsShutdown); | ||||
|   mIsShutdown = true; | ||||
| 
 | ||||
|   if (!mObservers.IsEmpty()) { | ||||
|     Unused << PVsyncChild::SendUnobserve(); | ||||
|   } | ||||
|   mObservers.Clear(); | ||||
|   mObserver = nullptr; | ||||
| } | ||||
| 
 | ||||
| mozilla::ipc::IPCResult VsyncChild::RecvNotify(const VsyncEvent& aVsync) { | ||||
|  | @ -82,26 +51,30 @@ mozilla::ipc::IPCResult VsyncChild::RecvNotify(const VsyncEvent& aVsync) { | |||
|   MOZ_ASSERT(!mIsShutdown); | ||||
| 
 | ||||
|   SchedulerGroup::MarkVsyncRan(); | ||||
| 
 | ||||
|   for (VsyncObserver* observer : mObservers.ForwardRange()) { | ||||
|     observer->NotifyVsync(aVsync); | ||||
|   if (mObservingVsync && mObserver) { | ||||
|     mObserver->NotifyVsync(aVsync); | ||||
|   } | ||||
|   return IPC_OK(); | ||||
| } | ||||
| 
 | ||||
| void VsyncChild::SetVsyncObserver(VsyncObserver* aVsyncObserver) { | ||||
|   MOZ_ASSERT(NS_IsMainThread()); | ||||
|   mObserver = aVsyncObserver; | ||||
| } | ||||
| 
 | ||||
| TimeDuration VsyncChild::GetVsyncRate() { | ||||
|   // Throttle vsync rate requests to avoid unnecessary IPC
 | ||||
|   if (lastVsyncRateTime.IsNull() || | ||||
|       (TimeStamp::Now() - lastVsyncRateTime).ToMilliseconds() > 250) { | ||||
|   if (mVsyncRate == TimeDuration::Forever()) { | ||||
|     PVsyncChild::SendRequestVsyncRate(); | ||||
|     lastVsyncRateTime = TimeStamp::Now(); | ||||
|   } | ||||
| 
 | ||||
|   return mVsyncRate; | ||||
| } | ||||
| 
 | ||||
| TimeDuration VsyncChild::VsyncRate() { return mVsyncRate; } | ||||
| 
 | ||||
| mozilla::ipc::IPCResult VsyncChild::RecvVsyncRate(const float& aVsyncRate) { | ||||
|   mVsyncRate = TimeDuration::FromMilliseconds(aVsyncRate); | ||||
|   return IPC_OK(); | ||||
| } | ||||
| 
 | ||||
| }  // namespace mozilla::dom
 | ||||
| }  // namespace mozilla::layout
 | ||||
|  | @ -4,19 +4,22 @@ | |||
|  * 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/. */
 | ||||
| 
 | ||||
| #ifndef mozilla_dom_ipc_VsyncChild_h | ||||
| #define mozilla_dom_ipc_VsyncChild_h | ||||
| #ifndef mozilla_layout_ipc_VsyncChild_h | ||||
| #define mozilla_layout_ipc_VsyncChild_h | ||||
| 
 | ||||
| #include "mozilla/dom/PVsyncChild.h" | ||||
| #include "mozilla/RefPtr.h" | ||||
| #include "mozilla/layout/PVsyncChild.h" | ||||
| #include "nsISupportsImpl.h" | ||||
| #include "nsTObserverArray.h" | ||||
| #include "mozilla/RefPtr.h" | ||||
| 
 | ||||
| namespace mozilla { | ||||
| 
 | ||||
| class VsyncObserver; | ||||
| 
 | ||||
| namespace dom { | ||||
| namespace ipc { | ||||
| class BackgroundChildImpl; | ||||
| }  // namespace ipc
 | ||||
| 
 | ||||
| namespace layout { | ||||
| 
 | ||||
| // The PVsyncChild actor receives a vsync event from the main process and
 | ||||
| // delivers it to the child process. Currently this is restricted to the main
 | ||||
|  | @ -25,30 +28,44 @@ namespace dom { | |||
| class VsyncChild final : public PVsyncChild { | ||||
|   NS_INLINE_DECL_REFCOUNTING(VsyncChild) | ||||
| 
 | ||||
|   friend class mozilla::ipc::BackgroundChildImpl; | ||||
|   friend class PVsyncChild; | ||||
| 
 | ||||
|  public: | ||||
|   VsyncChild(); | ||||
| 
 | ||||
|   void AddChildRefreshTimer(VsyncObserver* aVsyncObserver); | ||||
|   void RemoveChildRefreshTimer(VsyncObserver* aVsyncObserver); | ||||
|   // Hide the SendObserve/SendUnobserve in PVsyncChild. We add an flag
 | ||||
|   // mObservingVsync to handle the race problem of unobserving vsync event.
 | ||||
|   bool SendObserve(); | ||||
|   bool SendUnobserve(); | ||||
| 
 | ||||
|   // Bind a VsyncObserver into VsyncChild after ipc channel connected.
 | ||||
|   void SetVsyncObserver(VsyncObserver* aVsyncObserver); | ||||
|   // GetVsyncRate is a getter for mVsyncRate which sends a requests to
 | ||||
|   // VsyncParent to retreive the hardware vsync rate if mVsyncRate
 | ||||
|   // hasn't already been set.
 | ||||
|   TimeDuration GetVsyncRate(); | ||||
|   // VsyncRate is a getter for mVsyncRate which always returns
 | ||||
|   // mVsyncRate directly, potentially returning
 | ||||
|   // TimeDuration::Forever() if mVsyncRate hasn't been set by calling
 | ||||
|   // GetVsyncRate.
 | ||||
|   TimeDuration VsyncRate(); | ||||
| 
 | ||||
|  private: | ||||
|   VsyncChild(); | ||||
|   virtual ~VsyncChild(); | ||||
| 
 | ||||
|   mozilla::ipc::IPCResult RecvNotify(const VsyncEvent& aVsync); | ||||
|   mozilla::ipc::IPCResult RecvVsyncRate(const float& aVsyncRate); | ||||
|   virtual void ActorDestroy(ActorDestroyReason aActorDestroyReason) override; | ||||
| 
 | ||||
|   bool mObservingVsync; | ||||
|   bool mIsShutdown; | ||||
| 
 | ||||
|   // The content side vsync observer.
 | ||||
|   RefPtr<VsyncObserver> mObserver; | ||||
|   TimeDuration mVsyncRate; | ||||
|   TimeStamp lastVsyncRateTime; | ||||
|   nsTObserverArray<VsyncObserver*> mObservers; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace dom
 | ||||
| }  // namespace layout
 | ||||
| }  // namespace mozilla
 | ||||
| 
 | ||||
| #endif  // mozilla_dom_ipc_VsyncChild_h
 | ||||
| #endif  // mozilla_layout_ipc_VsyncChild_h
 | ||||
|  | @ -10,49 +10,51 @@ | |||
| #include "BackgroundParentImpl.h" | ||||
| #include "gfxPlatform.h" | ||||
| #include "mozilla/Unused.h" | ||||
| #include "nsIThread.h" | ||||
| #include "nsThreadUtils.h" | ||||
| #include "VsyncSource.h" | ||||
| 
 | ||||
| namespace mozilla::dom { | ||||
| namespace mozilla { | ||||
| 
 | ||||
| using namespace ipc; | ||||
| 
 | ||||
| namespace layout { | ||||
| 
 | ||||
| /*static*/ | ||||
| already_AddRefed<VsyncParent> VsyncParent::Create() { | ||||
|   AssertIsOnBackgroundThread(); | ||||
|   RefPtr<gfx::VsyncSource> vsyncSource = | ||||
|       gfxPlatform::GetPlatform()->GetHardwareVsync(); | ||||
|   RefPtr<VsyncParent> vsyncParent = new VsyncParent(); | ||||
|   vsyncParent->mVsyncDispatcher = vsyncSource->GetRefreshTimerVsyncDispatcher(); | ||||
|   return vsyncParent.forget(); | ||||
| } | ||||
| 
 | ||||
| VsyncParent::VsyncParent() | ||||
|     : mObservingVsync(false), | ||||
|       mDestroyed(false), | ||||
|       mInitialThread(NS_GetCurrentThread()) {} | ||||
|       mBackgroundThread(NS_GetCurrentThread()) { | ||||
|   MOZ_ASSERT(mBackgroundThread); | ||||
|   AssertIsOnBackgroundThread(); | ||||
| } | ||||
| 
 | ||||
| void VsyncParent::UpdateVsyncSource( | ||||
|     const RefPtr<gfx::VsyncSource>& aVsyncSource) { | ||||
|   mVsyncSource = aVsyncSource; | ||||
|   if (!mVsyncSource) { | ||||
|     mVsyncSource = gfxPlatform::GetPlatform()->GetHardwareVsync(); | ||||
|   } | ||||
| 
 | ||||
|   if (mObservingVsync) { | ||||
|     mVsyncDispatcher->RemoveChildRefreshTimer(this); | ||||
|   } | ||||
|   mVsyncDispatcher = mVsyncSource->GetRefreshTimerVsyncDispatcher(); | ||||
|   if (mObservingVsync) { | ||||
|     mVsyncDispatcher->AddChildRefreshTimer(this); | ||||
|   } | ||||
| VsyncParent::~VsyncParent() { | ||||
|   // Since we use NS_INLINE_DECL_THREADSAFE_REFCOUNTING, we can't make sure
 | ||||
|   // VsyncParent is always released on the background thread.
 | ||||
| } | ||||
| 
 | ||||
| bool VsyncParent::NotifyVsync(const VsyncEvent& aVsync) { | ||||
|   if (IsOnInitialThread()) { | ||||
|     DispatchVsyncEvent(aVsync); | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   // Called on hardware vsync thread. We should post to current ipc thread.
 | ||||
|   MOZ_ASSERT(!IsOnBackgroundThread()); | ||||
|   nsCOMPtr<nsIRunnable> vsyncEvent = NewRunnableMethod<VsyncEvent>( | ||||
|       "dom::VsyncParent::DispatchVsyncEvent", this, | ||||
|       "layout::VsyncParent::DispatchVsyncEvent", this, | ||||
|       &VsyncParent::DispatchVsyncEvent, aVsync); | ||||
|   MOZ_ALWAYS_SUCCEEDS(mInitialThread->Dispatch(vsyncEvent, NS_DISPATCH_NORMAL)); | ||||
|   MOZ_ALWAYS_SUCCEEDS( | ||||
|       mBackgroundThread->Dispatch(vsyncEvent, NS_DISPATCH_NORMAL)); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| void VsyncParent::DispatchVsyncEvent(const VsyncEvent& aVsync) { | ||||
|   AssertIsOnInitialThread(); | ||||
|   AssertIsOnBackgroundThread(); | ||||
| 
 | ||||
|   // If we call NotifyVsync() when we handle ActorDestroy() message, we might
 | ||||
|   // still call DispatchVsyncEvent().
 | ||||
|  | @ -65,14 +67,17 @@ void VsyncParent::DispatchVsyncEvent(const VsyncEvent& aVsync) { | |||
| } | ||||
| 
 | ||||
| mozilla::ipc::IPCResult VsyncParent::RecvRequestVsyncRate() { | ||||
|   AssertIsOnInitialThread(); | ||||
|   TimeDuration vsyncRate = mVsyncSource->GetGlobalDisplay().GetVsyncRate(); | ||||
|   AssertIsOnBackgroundThread(); | ||||
|   TimeDuration vsyncRate = gfxPlatform::GetPlatform() | ||||
|                                ->GetHardwareVsync() | ||||
|                                ->GetGlobalDisplay() | ||||
|                                .GetVsyncRate(); | ||||
|   Unused << SendVsyncRate(vsyncRate.ToMilliseconds()); | ||||
|   return IPC_OK(); | ||||
| } | ||||
| 
 | ||||
| mozilla::ipc::IPCResult VsyncParent::RecvObserve() { | ||||
|   AssertIsOnInitialThread(); | ||||
|   AssertIsOnBackgroundThread(); | ||||
|   if (!mObservingVsync) { | ||||
|     mVsyncDispatcher->AddChildRefreshTimer(this); | ||||
|     mObservingVsync = true; | ||||
|  | @ -82,7 +87,7 @@ mozilla::ipc::IPCResult VsyncParent::RecvObserve() { | |||
| } | ||||
| 
 | ||||
| mozilla::ipc::IPCResult VsyncParent::RecvUnobserve() { | ||||
|   AssertIsOnInitialThread(); | ||||
|   AssertIsOnBackgroundThread(); | ||||
|   if (mObservingVsync) { | ||||
|     mVsyncDispatcher->RemoveChildRefreshTimer(this); | ||||
|     mObservingVsync = false; | ||||
|  | @ -91,9 +96,9 @@ mozilla::ipc::IPCResult VsyncParent::RecvUnobserve() { | |||
|   return IPC_FAIL_NO_REASON(this); | ||||
| } | ||||
| 
 | ||||
| void VsyncParent::ActorDestroy(ActorDestroyReason aActorDestroyReason) { | ||||
| void VsyncParent::ActorDestroy(ActorDestroyReason aReason) { | ||||
|   MOZ_ASSERT(!mDestroyed); | ||||
|   AssertIsOnInitialThread(); | ||||
|   AssertIsOnBackgroundThread(); | ||||
|   if (mObservingVsync) { | ||||
|     mVsyncDispatcher->RemoveChildRefreshTimer(this); | ||||
|   } | ||||
|  | @ -101,10 +106,5 @@ void VsyncParent::ActorDestroy(ActorDestroyReason aActorDestroyReason) { | |||
|   mDestroyed = true; | ||||
| } | ||||
| 
 | ||||
| bool VsyncParent::IsOnInitialThread() { | ||||
|   return NS_GetCurrentThread() == mInitialThread; | ||||
| } | ||||
| 
 | ||||
| void VsyncParent::AssertIsOnInitialThread() { MOZ_ASSERT(IsOnInitialThread()); } | ||||
| 
 | ||||
| }  // namespace mozilla::dom
 | ||||
| }  // namespace layout
 | ||||
| }  // namespace mozilla
 | ||||
|  | @ -4,31 +4,36 @@ | |||
|  * 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/. */
 | ||||
| 
 | ||||
| #ifndef mozilla_dom_ipc_VsyncParent_h | ||||
| #define mozilla_dom_ipc_VsyncParent_h | ||||
| #ifndef mozilla_layout_ipc_VsyncParent_h | ||||
| #define mozilla_layout_ipc_VsyncParent_h | ||||
| 
 | ||||
| #include "mozilla/dom/PVsyncParent.h" | ||||
| #include "mozilla/layout/PVsyncParent.h" | ||||
| #include "mozilla/VsyncDispatcher.h" | ||||
| #include "nsCOMPtr.h" | ||||
| #include "mozilla/RefPtr.h" | ||||
| #include "VsyncSource.h" | ||||
| 
 | ||||
| class nsIThread; | ||||
| 
 | ||||
| namespace mozilla::dom { | ||||
| namespace mozilla { | ||||
| 
 | ||||
| namespace ipc { | ||||
| class BackgroundParentImpl; | ||||
| }  // namespace ipc
 | ||||
| 
 | ||||
| namespace layout { | ||||
| 
 | ||||
| // Use PBackground thread in the main process to send vsync notifications to
 | ||||
| // content process. This actor will be released when its parent protocol calls
 | ||||
| // DeallocPVsyncParent().
 | ||||
| class VsyncParent final : public PVsyncParent, public VsyncObserver { | ||||
|   friend class mozilla::ipc::BackgroundParentImpl; | ||||
|   friend class PVsyncParent; | ||||
| 
 | ||||
|  public: | ||||
|   VsyncParent(); | ||||
|   void UpdateVsyncSource(const RefPtr<gfx::VsyncSource>& aVsyncSource); | ||||
| 
 | ||||
|  private: | ||||
|   virtual ~VsyncParent() = default; | ||||
|   static already_AddRefed<VsyncParent> Create(); | ||||
| 
 | ||||
|   VsyncParent(); | ||||
|   virtual ~VsyncParent(); | ||||
| 
 | ||||
|   virtual bool NotifyVsync(const VsyncEvent& aVsync) override; | ||||
|   mozilla::ipc::IPCResult RecvRequestVsyncRate(); | ||||
|  | @ -39,16 +44,13 @@ class VsyncParent final : public PVsyncParent, public VsyncObserver { | |||
| 
 | ||||
|   void DispatchVsyncEvent(const VsyncEvent& aVsync); | ||||
| 
 | ||||
|   bool IsOnInitialThread(); | ||||
|   void AssertIsOnInitialThread(); | ||||
| 
 | ||||
|   bool mObservingVsync; | ||||
|   bool mDestroyed; | ||||
|   nsCOMPtr<nsIThread> mInitialThread; | ||||
|   RefPtr<gfx::VsyncSource> mVsyncSource; | ||||
|   nsCOMPtr<nsIThread> mBackgroundThread; | ||||
|   RefPtr<RefreshTimerVsyncDispatcher> mVsyncDispatcher; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace mozilla::dom
 | ||||
| }  // namespace layout
 | ||||
| }  // namespace mozilla
 | ||||
| 
 | ||||
| #endif  // mozilla_dom_ipc_VsyncParent_h
 | ||||
| #endif  // mozilla_layout_ipc_VsyncParent_h
 | ||||
|  | @ -9,12 +9,23 @@ with Files("**"): | |||
| 
 | ||||
| EXPORTS.mozilla.layout += [ | ||||
|     "RemoteLayerTreeOwner.h", | ||||
|     "VsyncChild.h", | ||||
|     "VsyncParent.h", | ||||
| ] | ||||
| 
 | ||||
| UNIFIED_SOURCES += [ | ||||
|     "RemoteLayerTreeOwner.cpp", | ||||
| ] | ||||
| 
 | ||||
| SOURCES += [ | ||||
|     "VsyncChild.cpp", | ||||
|     "VsyncParent.cpp", | ||||
| ] | ||||
| 
 | ||||
| IPDL_SOURCES = [ | ||||
|     "PVsync.ipdl", | ||||
| ] | ||||
| 
 | ||||
| include("/ipc/chromium/chromium-config.mozbuild") | ||||
| 
 | ||||
| FINAL_LIBRARY = "xul" | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Noemi Erli
						Noemi Erli