Bug 1592150 - Move a step in the NativeLayerCA swap chain from mSurfaces to a new field called mFrontSurface. r=jrmuizel
authorMarkus Stange <mstange@themasta.com>
Tue, 19 Nov 2019 03:10:58 +0000
changeset 502526 292ede718577ae84b3856c72dae29989803e764b
parent 502525 f5173fdbd7c6bb50a84256690d6c0d03d9da9426
child 502527 ffcddfbaf321cb2f7ca87fe3ab68a1347b4328aa
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1592150
milestone72.0a1
Bug 1592150 - Move a step in the NativeLayerCA swap chain from mSurfaces to a new field called mFrontSurface. r=jrmuizel This gives us easy access to a surface that has valid content. In the next patch, we will use this surface to copy valid content from. Differential Revision: https://phabricator.services.mozilla.com/D51759
gfx/layers/NativeLayerCA.h
gfx/layers/NativeLayerCA.mm
--- a/gfx/layers/NativeLayerCA.h
+++ b/gfx/layers/NativeLayerCA.h
@@ -143,32 +143,35 @@ class NativeLayerCA : public NativeLayer
       const MutexAutoLock&);
 
   // Controls access to all fields of this class.
   Mutex mMutex;
 
   // Each IOSurface is initially created inside NextSurface.
   // The surface stays alive until the recycling mechanism in NextSurface
   // determines it is no longer needed (because the swap chain has grown too
-  // long) or until the layer is destroyed. During the surface's lifetime, it
-  // will continuously move through the fields mInProgressSurface,
-  // mReadySurface, and back to front through the mSurfaces queue:
+  // long) or until the layer is destroyed.
+  // During the surface's lifetime, it will continuously move through the fields
+  // mInProgressSurface, mReadySurface, mFrontSurface, and back to front through
+  // the mSurfaces queue:
   //
   //  mSurfaces.front()
   //  ------[NextSurface()]-----> mInProgressSurface
   //  --[NotifySurfaceReady()]--> mReadySurface
+  //  ----[ApplyChanges()]------> mFrontSurface
   //  ----[ApplyChanges()]------> mSurfaces.back()  --> .... -->
   //  mSurfaces.front()
   //
   // We mark an IOSurface as "in use" as long as it is either in
-  // mInProgressSurface or in mReadySurface. When it is in the mSurfaces queue,
-  // it is not marked as "in use" by us - but it can be "in use" by the window
-  // server. Consequently, IOSurfaceIsInUse on a surface from mSurfaces reflects
-  // whether the window server is still reading from the surface, and we can use
-  // this indicator to decide when to recycle the surface.
+  // mInProgressSurface or in mReadySurface. When it is in mFrontSurface or in
+  // the mSurfaces queue, it is not marked as "in use" by us - but it can be "in
+  // use" by the window server. Consequently, IOSurfaceIsInUse on a surface from
+  // mSurfaces reflects whether the window server is still reading from the
+  // surface, and we can use this indicator to decide when to recycle the
+  // surface.
   //
   // Users of NativeLayerCA normally proceed in this order:
   //  1. Begin a frame by calling NextSurface to get the surface.
   //  2. Draw to the surface.
   //  3. Mark the surface as done by calling NotifySurfaceReady.
   //  4. Trigger a CoreAnimation transaction, and call ApplyChanges within the
   //  transaction.
   //
@@ -198,19 +201,24 @@ class NativeLayerCA : public NativeLayer
   Maybe<SurfaceWithInvalidRegion> mInProgressSurface;
 
   // The surface that the most recent call to NotifySurfaceReady was for.
   // Will only be Some() between calls to NotifySurfaceReady and the next call
   // to ApplyChanges.
   // Both mInProgressSurface and mReadySurface can be Some() at the same time.
   Maybe<SurfaceWithInvalidRegion> mReadySurface;
 
-  // The queue of surfaces which make up our "swap chain".
+  // The surface that the most recent call to ApplyChanges set on the CALayer.
+  // Will be Some() after the first sequence of NextSurface, NotifySurfaceReady,
+  // ApplyChanges calls, for the rest of the layer's life time.
+  Maybe<SurfaceWithInvalidRegion> mFrontSurface;
+
+  // The queue of surfaces which make up the rest of our "swap chain".
   // mSurfaces.front() is the next surface we'll attempt to use.
-  // mSurfaces.back() is the one we submitted most recently.
+  // mSurfaces.back() is the one that was used most recently.
   std::deque<SurfaceWithInvalidRegion> mSurfaces;
 
   // Non-null between calls to NextSurfaceAsDrawTarget and NotifySurfaceReady.
   RefPtr<MacIOSurface> mInProgressLockedIOSurface;
 
   RefPtr<gl::GLContextCGL> mGLContext;
 
   std::unordered_map<CFTypeRefPtr<IOSurfaceRef>, UniquePtr<gl::MozFramebuffer>>
--- a/gfx/layers/NativeLayerCA.mm
+++ b/gfx/layers/NativeLayerCA.mm
@@ -234,16 +234,19 @@ void NativeLayerCA::InvalidateRegionThro
                                                         const IntRegion& aRegion) {
   IntRegion r = aRegion;
   if (mInProgressSurface) {
     mInProgressSurface->mInvalidRegion.OrWith(r);
   }
   if (mReadySurface) {
     mReadySurface->mInvalidRegion.OrWith(r);
   }
+  if (mFrontSurface) {
+    mFrontSurface->mInvalidRegion.OrWith(r);
+  }
   for (auto& surf : mSurfaces) {
     surf.mInvalidRegion.OrWith(r);
   }
 }
 
 CFTypeRefPtr<IOSurfaceRef> NativeLayerCA::NextSurface(const MutexAutoLock& aLock) {
   if (mSize.IsEmpty()) {
     NSLog(@"NextSurface returning nullptr because of invalid mSize (%d, %d).", mSize.width,
@@ -460,29 +463,35 @@ void NativeLayerCA::ApplyChanges() {
   mMutatedPosition = false;
   mMutatedBackingScale = false;
   mMutatedSurfaceIsFlipped = false;
   mMutatedClipRect = false;
 
   if (mReadySurface) {
     mContentCALayer.contents = (id)mReadySurface->mSurface.get();
     IOSurfaceDecrementUseCount(mReadySurface->mSurface.get());
-    mSurfaces.push_back(*mReadySurface);
+
+    if (mFrontSurface) {
+      mSurfaces.push_back(*mFrontSurface);
+      mFrontSurface = Nothing();
+    }
+
+    mFrontSurface = Some(*mReadySurface);
     mReadySurface = Nothing();
   }
 }
 
 // Called when mMutex is already being held by the current thread.
 std::vector<NativeLayerCA::SurfaceWithInvalidRegion> NativeLayerCA::RemoveExcessUnusedSurfaces(
     const MutexAutoLock&) {
   std::vector<SurfaceWithInvalidRegion> usedSurfaces;
   std::vector<SurfaceWithInvalidRegion> unusedSurfaces;
 
-  // Separate mSurfaces into used and unused surfaces, leaving 2 surfaces behind.
-  while (mSurfaces.size() > 2) {
+  // Separate mSurfaces into used and unused surfaces, leaving 1 surface behind.
+  while (mSurfaces.size() > 1) {
     auto surf = std::move(mSurfaces.front());
     mSurfaces.pop_front();
     if (IOSurfaceIsInUse(surf.mSurface.get())) {
       usedSurfaces.push_back(std::move(surf));
     } else {
       unusedSurfaces.push_back(std::move(surf));
     }
   }