Don't reset devices for each tab when the compositor resets. (bug 1316788, r=rhunt)
authorDavid Anderson <danderson@mozilla.com>
Mon, 14 Nov 2016 11:47:01 -0800
changeset 322509 b4ab43a2c1ec4cc95ac7b017b62b0420d7db10b1
parent 322508 4da186740a81e2c4bb7821a957226ffeac631d58
child 322510 878e54671aea2d422d124ba76da873936089fe92
push id21
push usermaklebus@msu.edu
push dateThu, 01 Dec 2016 06:22:08 +0000
reviewersrhunt
bugs1316788
milestone52.0a1
Don't reset devices for each tab when the compositor resets. (bug 1316788, r=rhunt)
dom/ipc/TabChild.cpp
gfx/ipc/CompositorSession.h
gfx/ipc/GPUProcessManager.cpp
gfx/ipc/GPUProcessManager.h
gfx/ipc/InProcessCompositorSession.cpp
gfx/ipc/InProcessCompositorSession.h
gfx/ipc/RemoteCompositorSession.cpp
gfx/ipc/RemoteCompositorSession.h
gfx/layers/ipc/CompositorBridgeChild.cpp
gfx/layers/ipc/CompositorBridgeChild.h
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/CompositorBridgeParent.h
gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
gfx/layers/ipc/PCompositorBridge.ipdl
widget/nsBaseWidget.cpp
widget/nsBaseWidget.h
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
widget/windows/nsWindowGfx.cpp
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2998,18 +2998,16 @@ TabChild::ReinitRendering()
 
   nsCOMPtr<nsIDocument> doc(GetDocument());
   doc->NotifyLayerManagerRecreated();
 }
 
 void
 TabChild::CompositorUpdated(const TextureFactoryIdentifier& aNewIdentifier)
 {
-  gfxPlatform::GetPlatform()->CompositorUpdated();
-
   RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
   ClientLayerManager* clm = lm->AsClientLayerManager();
   MOZ_ASSERT(clm);
 
   mTextureFactoryIdentifier = aNewIdentifier;
   clm->UpdateTextureFactoryIdentifier(aNewIdentifier);
   FrameLayerBuilder::InvalidateAllLayers(clm);
 }
--- a/gfx/ipc/CompositorSession.h
+++ b/gfx/ipc/CompositorSession.h
@@ -40,16 +40,17 @@ protected:
   typedef gfx::GPUProcessHost GPUProcessHost;
   typedef widget::CompositorWidget CompositorWidget;
   typedef widget::CompositorWidgetDelegate CompositorWidgetDelegate;
 
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorSession)
 
   virtual bool Reset(const nsTArray<LayersBackend>& aBackendHints,
+                     uint64_t aSeqNo,
                      TextureFactoryIdentifier* aOutIdentifier) = 0;
 
   virtual void Shutdown() = 0;
 
   // This returns a CompositorBridgeParent if the compositor resides in the same process.
   virtual CompositorBridgeParent* GetInProcessBridge() const = 0;
 
   // Set the GeckoContentController for the root of the layer tree.
--- a/gfx/ipc/GPUProcessManager.cpp
+++ b/gfx/ipc/GPUProcessManager.cpp
@@ -55,16 +55,17 @@ void
 GPUProcessManager::Shutdown()
 {
   sSingleton = nullptr;
 }
 
 GPUProcessManager::GPUProcessManager()
  : mTaskFactory(this),
    mNextLayerTreeId(0),
+   mNextResetSequenceNo(0),
    mNumProcessAttempts(0),
    mDeviceResetCount(0),
    mProcess(nullptr),
    mGPUChild(nullptr)
 {
   MOZ_COUNT_CTOR(GPUProcessManager);
 
   mObserver = new Observer(this);
@@ -301,20 +302,22 @@ GPUProcessManager::OnProcessDeviceReset(
 
   if (ShouldLimitDeviceResets(mDeviceResetCount, delta)) {
     DestroyProcess();
     DisableGPUProcess("GPU processed experienced too many device resets");
 
     HandleProcessLost();
     return;
   }
+  
+  uint64_t seqNo = GetNextDeviceResetSequenceNumber();
 
   // We're good, do a reset like normal
   for (auto& session : mRemoteSessions) {
-    session->NotifyDeviceReset();
+    session->NotifyDeviceReset(seqNo);
   }
 }
 
 void
 GPUProcessManager::OnProcessUnexpectedShutdown(GPUProcessHost* aHost)
 {
   MOZ_ASSERT(mProcess && mProcess == aHost);
 
--- a/gfx/ipc/GPUProcessManager.h
+++ b/gfx/ipc/GPUProcessManager.h
@@ -143,16 +143,24 @@ public:
     return mGPUChild;
   }
 
   // Returns whether or not a GPU process was ever launched.
   bool AttemptedGPUProcess() const {
     return mNumProcessAttempts > 0;
   }
 
+  // Returns the next compositor reset sequence number, a monotonic counter
+  // for when the compositing device resets. Since content processes are
+  // notified of resets through each individual tab, this allows content to
+  // only re-acquire devices once for each reset.
+  uint64_t GetNextDeviceResetSequenceNumber() {
+    return ++mNextResetSequenceNo;
+  }
+
 private:
   // Called from our xpcom-shutdown observer.
   void OnXPCOMShutdown();
 
   bool CreateContentCompositorBridge(base::ProcessId aOtherProcess,
                                      ipc::Endpoint<PCompositorBridgeChild>* aOutEndpoint);
   bool CreateContentImageBridge(base::ProcessId aOtherProcess,
                                 ipc::Endpoint<PImageBridgeChild>* aOutEndpoint);
@@ -208,16 +216,17 @@ private:
   };
   friend class Observer;
 
 private:
   RefPtr<Observer> mObserver;
   ipc::TaskFactory<GPUProcessManager> mTaskFactory;
   RefPtr<VsyncIOThreadHolder> mVsyncIOThread;
   uint64_t mNextLayerTreeId;
+  uint64_t mNextResetSequenceNo;
   uint32_t mNumProcessAttempts;
 
   nsTArray<RefPtr<RemoteCompositorSession>> mRemoteSessions;
   nsTArray<GPUProcessListener*> mListeners;
 
   uint32_t mDeviceResetCount;
   TimeStamp mDeviceResetLastTime;
 
--- a/gfx/ipc/InProcessCompositorSession.cpp
+++ b/gfx/ipc/InProcessCompositorSession.cpp
@@ -56,19 +56,21 @@ InProcessCompositorSession::SetContentCo
 
 RefPtr<IAPZCTreeManager>
 InProcessCompositorSession::GetAPZCTreeManager() const
 {
   return mCompositorBridgeParent->GetAPZCTreeManager(mRootLayerTreeId);
 }
 
 bool
-InProcessCompositorSession::Reset(const nsTArray<LayersBackend>& aBackendHints, TextureFactoryIdentifier* aOutIdentifier)
+InProcessCompositorSession::Reset(const nsTArray<LayersBackend>& aBackendHints,
+                                  uint64_t aSeqNo,
+                                  TextureFactoryIdentifier* aOutIdentifier)
 {
-  return mCompositorBridgeParent->ResetCompositor(aBackendHints, aOutIdentifier);
+  return mCompositorBridgeParent->ResetCompositor(aBackendHints, aSeqNo, aOutIdentifier);
 }
 
 void
 InProcessCompositorSession::Shutdown()
 {
   // Destroy will synchronously wait for the parent to acknowledge shutdown,
   // at which point CBP will defer a Release on the compositor thread. We
   // can safely release our reference now, and let the destructor run on either
--- a/gfx/ipc/InProcessCompositorSession.h
+++ b/gfx/ipc/InProcessCompositorSession.h
@@ -25,17 +25,19 @@ public:
     CSSToLayoutDeviceScale aScale,
     bool aUseAPZ,
     bool aUseExternalSurfaceSize,
     const gfx::IntSize& aSurfaceSize);
 
   CompositorBridgeParent* GetInProcessBridge() const override;
   void SetContentController(GeckoContentController* aController) override;
   RefPtr<IAPZCTreeManager> GetAPZCTreeManager() const override;
-  bool Reset(const nsTArray<LayersBackend>& aBackendHints, TextureFactoryIdentifier* aOutIdentifier) override;
+  bool Reset(const nsTArray<LayersBackend>& aBackendHints,
+             uint64_t aSeqNo,
+             TextureFactoryIdentifier* aOutIdentifier) override;
   void Shutdown() override;
 
 private:
   InProcessCompositorSession(widget::CompositorWidget* aWidget,
                              CompositorBridgeChild* aChild,
                              CompositorBridgeParent* aParent);
 
 private:
--- a/gfx/ipc/RemoteCompositorSession.cpp
+++ b/gfx/ipc/RemoteCompositorSession.cpp
@@ -34,20 +34,20 @@ RemoteCompositorSession::RemoteComposito
 
 RemoteCompositorSession::~RemoteCompositorSession()
 {
   // This should have been shutdown first.
   MOZ_ASSERT(!mCompositorBridgeChild);
 }
 
 void
-RemoteCompositorSession::NotifyDeviceReset()
+RemoteCompositorSession::NotifyDeviceReset(uint64_t aSeqNo)
 {
   MOZ_ASSERT(mWidget);
-  mWidget->OnRenderingDeviceReset();
+  mWidget->OnRenderingDeviceReset(aSeqNo);
 }
 
 void
 RemoteCompositorSession::NotifySessionLost()
 {
   // Re-entrancy should be impossible: when we are being notified of a lost
   // session, we have by definition not shut down yet. We will shutdown, but
   // then will be removed from the notification list.
@@ -82,20 +82,22 @@ RemoteCompositorSession::GetWidget()
 
 RefPtr<IAPZCTreeManager>
 RemoteCompositorSession::GetAPZCTreeManager() const
 {
   return mAPZ;
 }
 
 bool
-RemoteCompositorSession::Reset(const nsTArray<LayersBackend>& aBackendHints, TextureFactoryIdentifier* aOutIdentifier)
+RemoteCompositorSession::Reset(const nsTArray<LayersBackend>& aBackendHints,
+                               uint64_t aSeqNo,
+                               TextureFactoryIdentifier* aOutIdentifier)
 {
   bool didReset;
-  Unused << mCompositorBridgeChild->SendReset(aBackendHints, &didReset, aOutIdentifier);
+  Unused << mCompositorBridgeChild->SendReset(aBackendHints, aSeqNo, &didReset, aOutIdentifier);
   return didReset;
 }
 
 void
 RemoteCompositorSession::Shutdown()
 {
   mContentController = nullptr;
   if (mAPZ) {
--- a/gfx/ipc/RemoteCompositorSession.h
+++ b/gfx/ipc/RemoteCompositorSession.h
@@ -23,20 +23,22 @@ public:
                           const uint64_t& aRootLayerTreeId);
   ~RemoteCompositorSession() override;
 
   CompositorBridgeParent* GetInProcessBridge() const override;
   void SetContentController(GeckoContentController* aController) override;
   GeckoContentController* GetContentController();
   nsIWidget* GetWidget();
   RefPtr<IAPZCTreeManager> GetAPZCTreeManager() const override;
-  bool Reset(const nsTArray<LayersBackend>& aBackendHints, TextureFactoryIdentifier* aOutIdentifier) override;
+  bool Reset(const nsTArray<LayersBackend>& aBackendHints,
+             uint64_t aSeqNo,
+             TextureFactoryIdentifier* aOutIdentifier) override;
   void Shutdown() override;
 
-  void NotifyDeviceReset();
+  void NotifyDeviceReset(uint64_t aSeqNo);
   void NotifySessionLost();
 
 private:
   nsBaseWidget* mWidget;
   RefPtr<APZCTreeManagerChild> mAPZ;
   RefPtr<GeckoContentController> mContentController;
 };
 
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -333,22 +333,31 @@ CompositorBridgeChild::RecvInvalidateLay
       child->InvalidateLayers();
     }
   }
   return true;
 }
 
 bool
 CompositorBridgeChild::RecvCompositorUpdated(const uint64_t& aLayersId,
-                                             const TextureFactoryIdentifier& aNewIdentifier)
+                                             const TextureFactoryIdentifier& aNewIdentifier,
+                                             const uint64_t& aSeqNo)
 {
   if (mLayerManager) {
     // This case is handled directly by nsBaseWidget.
     MOZ_ASSERT(aLayersId == 0);
   } else if (aLayersId != 0) {
+    // Update gfxPlatform if this is the first time we're seeing this compositor
+    // update (we will get an update for each connected tab).
+    static uint64_t sLastSeqNo = 0;
+    if (sLastSeqNo != aSeqNo) {
+      gfxPlatform::GetPlatform()->CompositorUpdated();
+      sLastSeqNo = aSeqNo;
+    }
+
     if (dom::TabChild* child = dom::TabChild::GetFrom(aLayersId)) {
       child->CompositorUpdated(aNewIdentifier);
     }
     if (!mCanSend) {
       return true;
     }
     SendAcknowledgeCompositorUpdate(aLayersId);
   }
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -98,17 +98,18 @@ public:
                    const TimeStamp& aCompositeStart,
                    const TimeStamp& aCompositeEnd) override;
 
   virtual bool
   RecvInvalidateLayers(const uint64_t& aLayersId) override;
 
   virtual bool
   RecvCompositorUpdated(const uint64_t& aLayersId,
-                        const TextureFactoryIdentifier& aNewIdentifier) override;
+                        const TextureFactoryIdentifier& aNewIdentifier,
+                        const uint64_t& aSeqNo) override;
 
   virtual bool
   RecvOverfill(const uint32_t &aOverfill) override;
 
   virtual bool
   RecvUpdatePluginConfigurations(const LayoutDeviceIntPoint& aContentOffset,
                                  const LayoutDeviceIntRegion& aVisibleRegion,
                                  nsTArray<PluginWindowData>&& aPlugins) override;
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -679,20 +679,23 @@ CompositorBridgeParent::Initialize()
   }
 
   LayerScope::SetPixelScale(mScale.scale);
 
   mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
 }
 
 bool
-CompositorBridgeParent::RecvReset(nsTArray<LayersBackend>&& aBackendHints, bool* aResult, TextureFactoryIdentifier* aOutIdentifier)
+CompositorBridgeParent::RecvReset(nsTArray<LayersBackend>&& aBackendHints,
+                                  const uint64_t& aSeqNo,
+                                  bool* aResult,
+                                  TextureFactoryIdentifier* aOutIdentifier)
 {
   Maybe<TextureFactoryIdentifier> newIdentifier;
-  ResetCompositorTask(aBackendHints, &newIdentifier);
+  ResetCompositorTask(aBackendHints, aSeqNo, &newIdentifier);
   
   if (newIdentifier) {
     *aResult = true;
     *aOutIdentifier = newIdentifier.value();
   } else {
     *aResult = false;
   }
 
@@ -2049,44 +2052,48 @@ CompositorBridgeParent::InvalidateRemote
       CrossProcessCompositorBridgeParent* cpcp = lts->mCrossProcessParent;
       Unused << cpcp->SendInvalidateLayers(aLayersId);
     }
   });
 }
 
 bool
 CompositorBridgeParent::ResetCompositor(const nsTArray<LayersBackend>& aBackendHints,
+                                        uint64_t aSeqNo,
                                         TextureFactoryIdentifier* aOutIdentifier)
 {
   Maybe<TextureFactoryIdentifier> newIdentifier;
   {
     MonitorAutoLock lock(mResetCompositorMonitor);
 
     CompositorLoop()->PostTask(NewRunnableMethod
                                <StoreCopyPassByConstLRef<nsTArray<LayersBackend>>,
-                                Maybe<TextureFactoryIdentifier>*>(this,
-                                                                  &CompositorBridgeParent::ResetCompositorTask,
-                                                                  aBackendHints,
-                                                                  &newIdentifier));
+                               uint64_t,
+                               Maybe<TextureFactoryIdentifier>*>(this,
+                                                                 &CompositorBridgeParent::ResetCompositorTask,
+                                                                 aBackendHints,
+                                                                 aSeqNo,
+                                                                 &newIdentifier));
 
     mResetCompositorMonitor.Wait();
   }
 
   if (!newIdentifier) {
     return false;
   }
 
   *aOutIdentifier = newIdentifier.value();
   return true;
 }
 
 // Invoked on the compositor thread. The main thread is waiting on the given
 // monitor.
 void
 CompositorBridgeParent::ResetCompositorTask(const nsTArray<LayersBackend>& aBackendHints,
+                                            uint64_t aSeqNo,
                                             Maybe<TextureFactoryIdentifier>* aOutNewIdentifier)
 {
   // Perform the reset inside a lock, so the main thread can wake up as soon as
   // possible. We notify child processes (if necessary) outside the lock.
   Maybe<TextureFactoryIdentifier> newIdentifier;
   {
     MonitorAutoLock lock(mResetCompositorMonitor);
 
@@ -2103,17 +2110,17 @@ CompositorBridgeParent::ResetCompositorT
   if (!newIdentifier) {
     // No compositor change; nothing to do.
     return;
   }
 
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   ForEachIndirectLayerTree([&] (LayerTreeState* lts, uint64_t layersId) -> void {
     if (CrossProcessCompositorBridgeParent* cpcp = lts->mCrossProcessParent) {
-      Unused << cpcp->SendCompositorUpdated(layersId, newIdentifier.value());
+      Unused << cpcp->SendCompositorUpdated(layersId, newIdentifier.value(), aSeqNo);
 
       if (LayerTransactionParent* ltp = lts->mLayerTree) {
         ltp->AddPendingCompositorUpdate();
       }
       lts->mPendingCompositorUpdates++;
     }
   });
 }
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -257,17 +257,20 @@ public:
                        bool aUseAPZ);
 
   // Must only be called by GPUParent. After invoking this, the IPC channel
   // is active and RecvWillStop/ActorDestroy must be called to free the
   // compositor.
   bool Bind(Endpoint<PCompositorBridgeParent>&& aEndpoint);
 
   virtual bool RecvInitialize(const uint64_t& aRootLayerTreeId) override;
-  virtual bool RecvReset(nsTArray<LayersBackend>&& aBackendHints, bool* aResult, TextureFactoryIdentifier* aOutIdentifier) override;
+  virtual bool RecvReset(nsTArray<LayersBackend>&& aBackendHints,
+                         const uint64_t& aSeqNo,
+                         bool* aResult,
+                         TextureFactoryIdentifier* aOutIdentifier) override;
   virtual bool RecvGetFrameUniformity(FrameUniformityData* aOutData) override;
   virtual bool RecvRequestOverfill() override;
   virtual bool RecvWillClose() override;
   virtual bool RecvPause() override;
   virtual bool RecvResume() override;
   virtual bool RecvNotifyChildCreated(const uint64_t& child) override;
   virtual bool RecvNotifyChildRecreated(const uint64_t& child) override;
   virtual bool RecvAdoptChild(const uint64_t& child) override;
@@ -344,16 +347,17 @@ public:
    *
    * Note that this posts a task directly, rather than using synchronous
    * IPDL, and waits on a monitor notification from the compositor thread.
    * We do this as a best-effort attempt to jump any IPDL messages that
    * have not yet been posted (and are sitting around in the IO pipe), to
    * minimize the amount of time the main thread is blocked.
    */
   bool ResetCompositor(const nsTArray<LayersBackend>& aBackendHints,
+                       uint64_t aSeqNo,
                        TextureFactoryIdentifier* aOutIdentifier);
 
   /**
    * This forces the is-first-paint flag to true. This is intended to
    * be called by the widget code when it loses its viewport information
    * (or for whatever reason wants to refresh the viewport information).
    * The information refresh happens because the compositor will call
    * SetFirstPaintViewport on the next frame of composition.
@@ -579,16 +583,17 @@ protected:
   void ForceComposition();
   void CancelCurrentCompositeTask();
   void Invalidate();
   bool IsPendingComposite();
   void FinishPendingComposite();
 
   RefPtr<Compositor> NewCompositor(const nsTArray<LayersBackend>& aBackendHints);
   void ResetCompositorTask(const nsTArray<LayersBackend>& aBackendHints,
+                           uint64_t aSeqNo,
                            Maybe<TextureFactoryIdentifier>* aOutNewIdentifier);
   Maybe<TextureFactoryIdentifier> ResetCompositorImpl(const nsTArray<LayersBackend>& aBackendHints);
 
   /**
    * Add a compositor to the global compositor map.
    */
   static void AddCompositor(CompositorBridgeParent* compositor, uint64_t* id);
   /**
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
@@ -37,17 +37,21 @@ public:
     }
     mSelfRef = this;
   }
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   // FIXME/bug 774388: work out what shutdown protocol we need.
   virtual bool RecvInitialize(const uint64_t& aRootLayerTreeId) override { return false; }
-  virtual bool RecvReset(nsTArray<LayersBackend>&& aBackendHints, bool* aResult, TextureFactoryIdentifier* aOutIdentifier) override { return false; }
+  virtual bool RecvReset(nsTArray<LayersBackend>&& aBackendHints,
+                         const uint64_t& aSeqNo,
+                         bool* aResult,
+                         TextureFactoryIdentifier* aOutIdentifier) override
+  { return false; }
   virtual bool RecvRequestOverfill() override { return true; }
   virtual bool RecvWillClose() override { return true; }
   virtual bool RecvPause() override { return true; }
   virtual bool RecvResume() override { return true; }
   virtual bool RecvNotifyChildCreated(const uint64_t& child) override;
   virtual bool RecvNotifyChildRecreated(const uint64_t& child) override { return false; }
   virtual bool RecvAdoptChild(const uint64_t& child) override { return false; }
   virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
--- a/gfx/layers/ipc/PCompositorBridge.ipdl
+++ b/gfx/layers/ipc/PCompositorBridge.ipdl
@@ -57,18 +57,22 @@ sync protocol PCompositorBridge
 child:
   // The child should invalidate retained layers. This is used for local
   // compositor device resets, such as in CompositorD3D9, and ensures that
   // TextureSources are recreated.
   async InvalidateLayers(uint64_t layersId);
 
   // The compositor type or device has changed, and a new texture factory
   // identifier is available. Layers must be invalidated and the new identifier
-  // must be propagated.
-  async CompositorUpdated(uint64_t layersId, TextureFactoryIdentifier newIdentifier);
+  // must be propagated. The sequence number is a generation count for the
+  // compositor.
+  async CompositorUpdated(
+    uint64_t layersId,
+    TextureFactoryIdentifier newIdentifier,
+    uint64_t seqNo);
 
   // The compositor completed a layers transaction. id is the layers id
   // of the child layer tree that was composited (or 0 when notifying
   // the root layer tree).
   // transactionId is the id of the transaction before this composite, or 0
   // if there was no transaction since the last composite.
   async DidComposite(uint64_t id, uint64_t transactionId,
                      TimeStamp compositeStart, TimeStamp compositeEnd);
@@ -118,17 +122,18 @@ child:
   async ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive);
 
 parent:
   // Must be called before Initialize().
   async PCompositorWidget(CompositorWidgetInitData aInitData);
 
   // When out-of-process, this must be called to finish initialization.
   sync Initialize(uint64_t rootLayerTreeId);
-  sync Reset(LayersBackend[] aBackendHints) returns (bool aResult, TextureFactoryIdentifier aOutIdentifier);
+  sync Reset(LayersBackend[] aBackendHints, uint64_t aSeqNo)
+    returns (bool aResult, TextureFactoryIdentifier aOutIdentifier);
 
   // Returns whether this Compositor has APZ enabled or not.
   sync AsyncPanZoomEnabled(uint64_t layersId) returns (bool aHasAPZ);
 
   // Must be called after Initialize(), and only succeeds if AsyncPanZoomEnabled() is true.
   async PAPZ(uint64_t layersId);
   async PAPZCTreeManager(uint64_t layersId);
 
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -308,17 +308,17 @@ void nsBaseWidget::DestroyLayerManager()
   if (mLayerManager) {
     mLayerManager->Destroy();
     mLayerManager = nullptr;
   }
   DestroyCompositor();
 }
 
 void
-nsBaseWidget::OnRenderingDeviceReset()
+nsBaseWidget::OnRenderingDeviceReset(uint64_t aSeqNo)
 {
   if (!mLayerManager || !mCompositorSession) {
     return;
   }
 
   nsTArray<LayersBackend> backendHints;
   gfxPlatform::GetPlatform()->GetCompositorBackends(ComputeShouldAccelerate(), backendHints);
 
@@ -332,17 +332,17 @@ nsBaseWidget::OnRenderingDeviceReset()
   if (!ComputeShouldAccelerate() &&
       clm->GetTextureFactoryIdentifier().mParentBackend != LayersBackend::LAYERS_BASIC)
   {
     return;
   }
 
   // Recreate the compositor.
   TextureFactoryIdentifier identifier;
-  if (!mCompositorSession->Reset(backendHints, &identifier)) {
+  if (!mCompositorSession->Reset(backendHints, aSeqNo, &identifier)) {
     // No action was taken, so we don't have to do anything.
     return;
   }
 
   // Invalidate all layers.
   FrameLayerBuilder::InvalidateAllLayers(mLayerManager);
 
   // Update the texture factory identifier.
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -569,17 +569,17 @@ protected:
   virtual void WindowUsesOMTC() {}
   virtual void RegisterTouchWindow() {}
 
   nsIDocument* GetDocument() const;
 
   void EnsureTextEventDispatcher();
 
   // Notify the compositor that a device reset has occurred.
-  void OnRenderingDeviceReset();
+  void OnRenderingDeviceReset(uint64_t aSeqNo);
 
   bool UseAPZ();
 
   /**
    * For widgets that support synthesizing native touch events, this function
    * can be used to manage the current state of synthetic pointers. Each widget
    * must maintain its own MultiTouchInput instance and pass it in as the state,
    * along with the desired parameters for the changes. This function returns
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -1155,38 +1155,40 @@ nsWindow::GetParentWindowBase(bool aIncl
   return static_cast<nsWindowBase*>(widget);
 }
  
 BOOL CALLBACK
 nsWindow::EnumAllChildWindProc(HWND aWnd, LPARAM aParam)
 {
   nsWindow *wnd = WinUtils::GetNSWindowPtr(aWnd);
   if (wnd) {
-    ((nsWindow::WindowEnumCallback*)aParam)(wnd);
+    reinterpret_cast<nsTArray<nsWindow*>*>(aParam)->AppendElement(wnd);
   }
   return TRUE;
 }
 
 BOOL CALLBACK
 nsWindow::EnumAllThreadWindowProc(HWND aWnd, LPARAM aParam)
 {
   nsWindow *wnd = WinUtils::GetNSWindowPtr(aWnd);
   if (wnd) {
-    ((nsWindow::WindowEnumCallback*)aParam)(wnd);
+    reinterpret_cast<nsTArray<nsWindow*>*>(aParam)->AppendElement(wnd);
   }
   EnumChildWindows(aWnd, EnumAllChildWindProc, aParam);
   return TRUE;
 }
 
-void
-nsWindow::EnumAllWindows(WindowEnumCallback aCallback)
-{
+/* static*/ nsTArray<nsWindow*>
+nsWindow::EnumAllWindows()
+{
+  nsTArray<nsWindow*> windows;
   EnumThreadWindows(GetCurrentThreadId(),
                     EnumAllThreadWindowProc,
-                    (LPARAM)aCallback);
+                    reinterpret_cast<LPARAM>(&windows));
+  return windows;
 }
 
 static already_AddRefed<SourceSurface>
 CreateSourceSurfaceForGfxSurface(gfxASurface* aSurface)
 {
   MOZ_ASSERT(aSurface);
   return Factory::CreateSourceSurfaceForCairoSurface(
            aSurface->CairoSurface(), aSurface->GetSize(),
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -249,18 +249,17 @@ public:
   /**
    * Window utilities
    */
   nsWindow*               GetTopLevelWindow(bool aStopOnDialogOrPopup);
   WNDPROC                 GetPrevWindowProc() { return mPrevWndProc; }
   WindowHook&             GetWindowHook() { return mWindowHook; }
   nsWindow*               GetParentWindow(bool aIncludeOwner);
   // Get an array of all nsWindow*s on the main thread.
-  typedef void            (WindowEnumCallback)(nsWindow*);
-  static void             EnumAllWindows(WindowEnumCallback aCallback);
+  static nsTArray<nsWindow*> EnumAllWindows();
 
   /**
    * Misc.
    */
   virtual bool            AutoErase(HDC dc);
   bool WidgetTypeSupportsAcceleration() override;
 
   void                    ForcePresent();
--- a/widget/windows/nsWindowGfx.cpp
+++ b/widget/windows/nsWindowGfx.cpp
@@ -38,16 +38,17 @@ using mozilla::plugins::PluginInstancePa
 #include "gfxContext.h"
 #include "prmem.h"
 #include "WinUtils.h"
 #include "nsIWidgetListener.h"
 #include "mozilla/Unused.h"
 #include "nsDebug.h"
 #include "nsIXULRuntime.h"
 
+#include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "ClientLayerManager.h"
 
 #include "nsUXThemeData.h"
 #include "nsUXThemeConstants.h"
 
 using namespace mozilla;
@@ -167,26 +168,27 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t
   // windows event spin loop. If we don't trap for this, we'll try to paint,
   // but view manager will refuse to paint the surface, resulting is black
   // flashes on the plugin rendering surface.
   if (mozilla::ipc::MessageChannel::IsSpinLoopActive() && mPainting)
     return false;
 
   DeviceResetReason resetReason = DeviceResetReason::OK;
   if (gfxWindowsPlatform::GetPlatform()->DidRenderingDeviceReset(&resetReason)) {
-
     gfxCriticalNote << "(nsWindow) Detected device reset: " << (int)resetReason;
 
     gfxWindowsPlatform::GetPlatform()->UpdateRenderMode();
-    EnumAllWindows([] (nsWindow* aWindow) -> void {
-      aWindow->OnRenderingDeviceReset();
-    });
+
+    uint64_t resetSeqNo = GPUProcessManager::Get()->GetNextDeviceResetSequenceNumber();
+    nsTArray<nsWindow*> windows = EnumAllWindows();
+    for (nsWindow* window : windows) {
+      window->OnRenderingDeviceReset(resetSeqNo);
+    }
 
     gfxCriticalNote << "(nsWindow) Finished device reset.";
-
     return false;
   }
 
   // After we CallUpdateWindow to the child, occasionally a WM_PAINT message
   // is posted to the parent event loop with an empty update rect. Do a
   // dummy paint so that Windows stops dispatching WM_PAINT in an inifinite
   // loop. See bug 543788.
   if (IsPlugin()) {