[wk2] RemoteLayerBackingStore front buffers should be purgeable when unparented
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 May 2014 06:14:15 +0000 (06:14 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 May 2014 06:14:15 +0000 (06:14 +0000)
https://bugs.webkit.org/show_bug.cgi?id=133020
<rdar://problem/16521736>

Reviewed by Simon Fraser.

* Shared/mac/RemoteLayerBackingStore.mm:
(WebKit::RemoteLayerBackingStore::display):
Let the context know whenever a RemoteLayerBackingStore is displayed, so that
RemoteLayerBackingStoreCollection can (if needed) note that the backing store
is active once again (because we only display parented backing store).

(WebKit::RemoteLayerBackingStore::setBufferVolatility):
Ensure that we never have live contexts attached to any buffers when
marking them volatile, because checking isInUse() with live contexts is futile.

* Shared/mac/RemoteLayerBackingStoreCollection.h:
* Shared/mac/RemoteLayerBackingStoreCollection.mm:
(WebKit::RemoteLayerBackingStoreCollection::RemoteLayerBackingStoreCollection):
(WebKit::RemoteLayerBackingStoreCollection::willFlushLayers):
(WebKit::RemoteLayerBackingStoreCollection::willCommitLayerTree):
(WebKit::RemoteLayerBackingStoreCollection::didFlushLayers):
(WebKit::RemoteLayerBackingStoreCollection::backingStoreWillBeDestroyed):
(WebKit::RemoteLayerBackingStoreCollection::backingStoreWillBeDisplayed):
(WebKit::RemoteLayerBackingStoreCollection::markBackingStoreVolatileImmediately):
(WebKit::RemoteLayerBackingStoreCollection::markBackingStoreVolatile):
(WebKit::RemoteLayerBackingStoreCollection::backingStoreBecameUnreachable):
(WebKit::RemoteLayerBackingStoreCollection::volatilityTimerFired):
(WebKit::RemoteLayerBackingStoreCollection::scheduleVolatilityTimer):
(WebKit::RemoteLayerBackingStoreCollection::purgeabilityTimerFired): Deleted.
(WebKit::RemoteLayerBackingStoreCollection::schedulePurgeabilityTimer): Deleted.
Rename purgeable->volatile for accuracy.
Keep track of two sets of backing store: those which are active/parented, and
those which are not. Backing store is moved to the inactive set after building
the transaction in which its owning layer is unparented.
When backing store is unparented, try to mark it volatile immediately. Also,
mark the backing store property as dirty on the owning layer so that when
said layer is reparented, we encode the backing store in the commit that reparents it,
as the UI process will throw away its reference to the backing store when
the layer is unparented. Mark the front buffers of unparented layers as volatile,
in addition to the others.

* Shared/mac/RemoteLayerTreeTransaction.h:
(WebKit::RemoteLayerTreeTransaction::layerIDsWithNewlyUnreachableBackingStore):
* Shared/mac/RemoteLayerTreeTransaction.mm:
(WebKit::RemoteLayerTreeTransaction::encode):
(WebKit::RemoteLayerTreeTransaction::decode):
(WebKit::RemoteLayerTreeTransaction::setLayerIDsWithNewlyUnreachableBackingStore):
Include the list of layers (by ID) with backing store which just became unreachable in the transaction.

* UIProcess/mac/RemoteLayerTreeHost.mm:
(WebKit::RemoteLayerTreeHost::updateLayerTree):
Clear the contents of layers which now have unreachable backing store.
Otherwise, the UI process would hold a 'use' on the IOSurface, and prevent
the Web process from marking it volatile.

* WebProcess/WebPage/mac/RemoteLayerTreeContext.h:
* WebProcess/WebPage/mac/RemoteLayerTreeContext.mm:
(WebKit::RemoteLayerTreeContext::backingStoreWillBeDisplayed):
* WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.mm:
(WebKit::RemoteLayerTreeDrawingArea::flushLayers):
Give RemoteLayerBackingStoreCollection a shot at the RemoteLayerTreeTransaction,
so that it can fill in layerIDsWithNewlyUnreachableBackingStore.
Also, let it know when the flush begins and ends, so that it can keep track
of which layers were reached in the flush.

* WebCore.exp.in:
* platform/graphics/cg/IOSurfacePool.cpp:
(WebCore::IOSurfacePool::willAddSurface):
* platform/graphics/cocoa/IOSurface.h:
* platform/graphics/cocoa/IOSurface.mm:
(IOSurface::releaseGraphicsContext):
Rename clearGraphicsContext to releaseGraphicsContext for clarity.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@169370 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
Source/WebCore/ChangeLog
Source/WebCore/WebCore.exp.in
Source/WebCore/platform/graphics/cg/IOSurfacePool.cpp
Source/WebCore/platform/graphics/cocoa/IOSurface.h
Source/WebCore/platform/graphics/cocoa/IOSurface.mm
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/mac/RemoteLayerBackingStore.mm
Source/WebKit2/Shared/mac/RemoteLayerBackingStoreCollection.h
Source/WebKit2/Shared/mac/RemoteLayerBackingStoreCollection.mm
Source/WebKit2/Shared/mac/RemoteLayerTreeTransaction.h
Source/WebKit2/Shared/mac/RemoteLayerTreeTransaction.mm
Source/WebKit2/UIProcess/mac/RemoteLayerTreeHost.mm
Source/WebKit2/WebProcess/WebPage/mac/RemoteLayerTreeContext.h
Source/WebKit2/WebProcess/WebPage/mac/RemoteLayerTreeContext.mm
Source/WebKit2/WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.mm

index f575c90..a7ea312 100644 (file)
@@ -1,3 +1,19 @@
+2014-05-26  Tim Horton  <timothy_horton@apple.com>
+
+        [wk2] RemoteLayerBackingStore front buffers should be purgeable when unparented
+        https://bugs.webkit.org/show_bug.cgi?id=133020
+        <rdar://problem/16521736>
+
+        Reviewed by Simon Fraser.
+
+        * WebCore.exp.in:
+        * platform/graphics/cg/IOSurfacePool.cpp:
+        (WebCore::IOSurfacePool::willAddSurface):
+        * platform/graphics/cocoa/IOSurface.h:
+        * platform/graphics/cocoa/IOSurface.mm:
+        (IOSurface::releaseGraphicsContext):
+        Rename clearGraphicsContext to releaseGraphicsContext for clarity.
+
 2014-05-26  Philip Rogers  <pdr@google.com>
 
         Remove special case for transparent SVG root layers
index d78575f..8c4a341 100644 (file)
@@ -3143,9 +3143,9 @@ __ZN7WebCore13IOSurfacePool11setPoolSizeEm
 __ZN7WebCore9IOSurface11createImageEv
 __ZN7WebCore9IOSurface13setIsVolatileEb
 __ZN7WebCore9IOSurface18createFromMachPortEjNS_10ColorSpaceE
-__ZN7WebCore9IOSurface20clearGraphicsContextEv
 __ZN7WebCore9IOSurface21ensureGraphicsContextEv
 __ZN7WebCore9IOSurface21ensurePlatformContextEv
+__ZN7WebCore9IOSurface22releaseGraphicsContextEv
 __ZN7WebCore9IOSurface6createENS_7IntSizeENS_10ColorSpaceE
 __ZNK7WebCore9IOSurface14createMachPortEv
 __ZNK7WebCore9IOSurface7isInUseEv
index 0529d68..0c609a8 100644 (file)
@@ -80,7 +80,7 @@ void IOSurfacePool::willAddSurface(IOSurface* surface, bool inUse)
     CachedSurfaceDetails& details = m_surfaceDetails.add(surface, CachedSurfaceDetails()).iterator->value;
     details.resetLastUseTime();
 
-    surface->clearGraphicsContext();
+    surface->releaseGraphicsContext();
 
     size_t surfaceBytes = surface->totalBytes();
 
index 4c31ca5..540a87d 100644 (file)
@@ -75,7 +75,7 @@ public:
 
     // The graphics context cached on the surface counts as a "user", so to get
     // an accurate result from isInUse(), it needs to be released.
-    void clearGraphicsContext();
+    void releaseGraphicsContext();
 
 private:
     IOSurface(IntSize, ColorSpace);
index 01fe0ec..f6601e3 100644 (file)
@@ -191,7 +191,7 @@ bool IOSurface::isInUse() const
     return IOSurfaceIsInUse(m_surface.get());
 }
 
-void IOSurface::clearGraphicsContext()
+void IOSurface::releaseGraphicsContext()
 {
     m_graphicsContext = nullptr;
     m_cgContext = nullptr;
index 4fffb24..d4b9765 100644 (file)
@@ -1,3 +1,71 @@
+2014-05-26  Tim Horton  <timothy_horton@apple.com>
+
+        [wk2] RemoteLayerBackingStore front buffers should be purgeable when unparented
+        https://bugs.webkit.org/show_bug.cgi?id=133020
+        <rdar://problem/16521736>
+
+        Reviewed by Simon Fraser.
+
+        * Shared/mac/RemoteLayerBackingStore.mm:
+        (WebKit::RemoteLayerBackingStore::display):
+        Let the context know whenever a RemoteLayerBackingStore is displayed, so that
+        RemoteLayerBackingStoreCollection can (if needed) note that the backing store
+        is active once again (because we only display parented backing store).
+
+        (WebKit::RemoteLayerBackingStore::setBufferVolatility):
+        Ensure that we never have live contexts attached to any buffers when
+        marking them volatile, because checking isInUse() with live contexts is futile.
+
+        * Shared/mac/RemoteLayerBackingStoreCollection.h:
+        * Shared/mac/RemoteLayerBackingStoreCollection.mm:
+        (WebKit::RemoteLayerBackingStoreCollection::RemoteLayerBackingStoreCollection):
+        (WebKit::RemoteLayerBackingStoreCollection::willFlushLayers):
+        (WebKit::RemoteLayerBackingStoreCollection::willCommitLayerTree):
+        (WebKit::RemoteLayerBackingStoreCollection::didFlushLayers):
+        (WebKit::RemoteLayerBackingStoreCollection::backingStoreWillBeDestroyed):
+        (WebKit::RemoteLayerBackingStoreCollection::backingStoreWillBeDisplayed):
+        (WebKit::RemoteLayerBackingStoreCollection::markBackingStoreVolatileImmediately):
+        (WebKit::RemoteLayerBackingStoreCollection::markBackingStoreVolatile):
+        (WebKit::RemoteLayerBackingStoreCollection::backingStoreBecameUnreachable):
+        (WebKit::RemoteLayerBackingStoreCollection::volatilityTimerFired):
+        (WebKit::RemoteLayerBackingStoreCollection::scheduleVolatilityTimer):
+        (WebKit::RemoteLayerBackingStoreCollection::purgeabilityTimerFired): Deleted.
+        (WebKit::RemoteLayerBackingStoreCollection::schedulePurgeabilityTimer): Deleted.
+        Rename purgeable->volatile for accuracy.
+        Keep track of two sets of backing store: those which are active/parented, and
+        those which are not. Backing store is moved to the inactive set after building
+        the transaction in which its owning layer is unparented.
+        When backing store is unparented, try to mark it volatile immediately. Also,
+        mark the backing store property as dirty on the owning layer so that when
+        said layer is reparented, we encode the backing store in the commit that reparents it,
+        as the UI process will throw away its reference to the backing store when
+        the layer is unparented. Mark the front buffers of unparented layers as volatile,
+        in addition to the others.
+
+        * Shared/mac/RemoteLayerTreeTransaction.h:
+        (WebKit::RemoteLayerTreeTransaction::layerIDsWithNewlyUnreachableBackingStore):
+        * Shared/mac/RemoteLayerTreeTransaction.mm:
+        (WebKit::RemoteLayerTreeTransaction::encode):
+        (WebKit::RemoteLayerTreeTransaction::decode):
+        (WebKit::RemoteLayerTreeTransaction::setLayerIDsWithNewlyUnreachableBackingStore):
+        Include the list of layers (by ID) with backing store which just became unreachable in the transaction.
+
+        * UIProcess/mac/RemoteLayerTreeHost.mm:
+        (WebKit::RemoteLayerTreeHost::updateLayerTree):
+        Clear the contents of layers which now have unreachable backing store.
+        Otherwise, the UI process would hold a 'use' on the IOSurface, and prevent
+        the Web process from marking it volatile.
+
+        * WebProcess/WebPage/mac/RemoteLayerTreeContext.h:
+        * WebProcess/WebPage/mac/RemoteLayerTreeContext.mm:
+        (WebKit::RemoteLayerTreeContext::backingStoreWillBeDisplayed):
+        * WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.mm:
+        (WebKit::RemoteLayerTreeDrawingArea::flushLayers):
+        Give RemoteLayerBackingStoreCollection a shot at the RemoteLayerTreeTransaction,
+        so that it can fill in layerIDsWithNewlyUnreachableBackingStore.
+        Also, let it know when the flush begins and ends, so that it can keep track
+        of which layers were reached in the flush.
+
 2014-05-26  Shivakumar JM  <shiva.jm@samsung.com>
 
         [EFL][WK2] Fix EWK2BackForwardListTest test fails.
index 6c0ea49..eb74ab7 100644 (file)
@@ -201,6 +201,9 @@ bool RemoteLayerBackingStore::display()
 
     m_lastDisplayTime = std::chrono::steady_clock::now();
 
+    if (m_context)
+        m_context->backingStoreWillBeDisplayed(this);
+
     // Make the previous front buffer non-volatile early, so that we can dirty the whole layer if it comes back empty.
     setBufferVolatility(BufferType::Front, false);
 
@@ -236,7 +239,7 @@ bool RemoteLayerBackingStore::display()
         context.translate(0, -expandedScaledSize.height());
         drawInContext(context, backImage.get());
 
-        m_frontBuffer.surface->clearGraphicsContext();
+        m_frontBuffer.surface->releaseGraphicsContext();
 
         return true;
     }
@@ -382,6 +385,8 @@ bool RemoteLayerBackingStore::setBufferVolatility(BufferType type, bool isVolati
     switch(type) {
     case BufferType::Front:
         if (m_frontBuffer.surface && m_frontBuffer.isVolatile != isVolatile) {
+            if (isVolatile)
+                m_frontBuffer.surface->releaseGraphicsContext();
             if (!isVolatile || !m_frontBuffer.surface->isInUse()) {
                 IOSurface::SurfaceState previousState = m_frontBuffer.surface->setIsVolatile(isVolatile);
                 m_frontBuffer.isVolatile = isVolatile;
@@ -395,6 +400,8 @@ bool RemoteLayerBackingStore::setBufferVolatility(BufferType type, bool isVolati
         break;
     case BufferType::Back:
         if (m_backBuffer.surface && m_backBuffer.isVolatile != isVolatile) {
+            if (isVolatile)
+                m_backBuffer.surface->releaseGraphicsContext();
             if (!isVolatile || !m_backBuffer.surface->isInUse()) {
                 m_backBuffer.surface->setIsVolatile(isVolatile);
                 m_backBuffer.isVolatile = isVolatile;
@@ -404,6 +411,8 @@ bool RemoteLayerBackingStore::setBufferVolatility(BufferType type, bool isVolati
         break;
     case BufferType::SecondaryBack:
         if (m_secondaryBackBuffer.surface && m_secondaryBackBuffer.isVolatile != isVolatile) {
+            if (isVolatile)
+                m_secondaryBackBuffer.surface->releaseGraphicsContext();
             if (!isVolatile || !m_secondaryBackBuffer.surface->isInUse()) {
                 m_secondaryBackBuffer.surface->setIsVolatile(isVolatile);
                 m_secondaryBackBuffer.isVolatile = isVolatile;
index 3b8ee77..81d2b10 100644 (file)
@@ -34,6 +34,7 @@ namespace WebKit {
 
 class RemoteLayerBackingStore;
 class RemoteLayerTreeContext;
+class RemoteLayerTreeTransaction;
 
 class RemoteLayerBackingStoreCollection {
     WTF_MAKE_NONCOPYABLE(RemoteLayerBackingStoreCollection);
@@ -45,17 +46,29 @@ public:
     void backingStoreWasCreated(RemoteLayerBackingStore*);
     void backingStoreWillBeDestroyed(RemoteLayerBackingStore*);
 
-    void purgeabilityTimerFired(WebCore::Timer<RemoteLayerBackingStoreCollection>&);
+    void backingStoreWillBeDisplayed(RemoteLayerBackingStore*);
+    void backingStoreBecameUnreachable(RemoteLayerBackingStore*);
 
-    void schedulePurgeabilityTimer();
+    void willFlushLayers();
+    void willCommitLayerTree(RemoteLayerTreeTransaction&);
+    void didFlushLayers();
+
+    void volatilityTimerFired(WebCore::Timer<RemoteLayerBackingStoreCollection>&);
+
+    void scheduleVolatilityTimer();
 
 private:
-    HashSet<RemoteLayerBackingStore*> m_liveBackingStore;
+    bool markBackingStoreVolatileImmediately(RemoteLayerBackingStore&);
+    bool markBackingStoreVolatile(RemoteLayerBackingStore&, std::chrono::steady_clock::time_point now);
 
-    void markInactiveBackingStorePurgeable();
+    HashSet<RemoteLayerBackingStore*> m_liveBackingStore;
+    HashSet<RemoteLayerBackingStore*> m_unparentedBackingStore;
+    HashSet<RemoteLayerBackingStore*> m_reachableBackingStoreInLatestFlush;
 
     RemoteLayerTreeContext* m_context;
-    WebCore::Timer<RemoteLayerBackingStoreCollection> m_purgeabilityTimer;
+    WebCore::Timer<RemoteLayerBackingStoreCollection> m_volatilityTimer;
+
+    bool m_inLayerFlush;
 };
 
 } // namespace WebKit
index 14fa992..d1d9583 100644 (file)
 #import "RemoteLayerBackingStore.h"
 #import "RemoteLayerTreeContext.h"
 
-const std::chrono::seconds purgeableBackingStoreAgeThreshold = 1_s;
-const std::chrono::milliseconds purgeableSecondaryBackingStoreAgeThreshold = 200_ms;
-const std::chrono::milliseconds purgeabilityTimerInterval = 200_ms;
+const std::chrono::seconds volatileBackingStoreAgeThreshold = 1_s;
+const std::chrono::milliseconds volatileSecondaryBackingStoreAgeThreshold = 200_ms;
+const std::chrono::milliseconds volatilityTimerInterval = 200_ms;
 
 namespace WebKit {
 
 RemoteLayerBackingStoreCollection::RemoteLayerBackingStoreCollection(RemoteLayerTreeContext* context)
     : m_context(context)
-    , m_purgeabilityTimer(this, &RemoteLayerBackingStoreCollection::purgeabilityTimerFired)
+    , m_volatilityTimer(this, &RemoteLayerBackingStoreCollection::volatilityTimerFired)
+    , m_inLayerFlush(false)
 {
 }
 
+void RemoteLayerBackingStoreCollection::willFlushLayers()
+{
+    m_inLayerFlush = true;
+    m_reachableBackingStoreInLatestFlush.clear();
+}
+
+void RemoteLayerBackingStoreCollection::willCommitLayerTree(RemoteLayerTreeTransaction& transaction)
+{
+    ASSERT(m_inLayerFlush);
+    Vector<WebCore::GraphicsLayer::PlatformLayerID> newlyUnreachableLayerIDs;
+    for (auto& backingStore : m_liveBackingStore) {
+        if (!m_reachableBackingStoreInLatestFlush.contains(backingStore))
+            newlyUnreachableLayerIDs.append(backingStore->layer()->layerID());
+    }
+
+    transaction.setLayerIDsWithNewlyUnreachableBackingStore(newlyUnreachableLayerIDs);
+}
+
+void RemoteLayerBackingStoreCollection::didFlushLayers()
+{
+    m_inLayerFlush = false;
+
+    Vector<RemoteLayerBackingStore*> newlyUnreachableBackingStore;
+    for (auto& backingStore : m_liveBackingStore) {
+        if (!m_reachableBackingStoreInLatestFlush.contains(backingStore))
+            newlyUnreachableBackingStore.append(backingStore);
+    }
+
+    for (auto& backingStore : newlyUnreachableBackingStore)
+        backingStoreBecameUnreachable(backingStore);
+
+    if (!newlyUnreachableBackingStore.isEmpty())
+        scheduleVolatilityTimer();
+}
+
 void RemoteLayerBackingStoreCollection::backingStoreWasCreated(RemoteLayerBackingStore* backingStore)
 {
     m_liveBackingStore.add(backingStore);
@@ -50,41 +86,92 @@ void RemoteLayerBackingStoreCollection::backingStoreWasCreated(RemoteLayerBackin
 void RemoteLayerBackingStoreCollection::backingStoreWillBeDestroyed(RemoteLayerBackingStore* backingStore)
 {
     m_liveBackingStore.remove(backingStore);
+    m_unparentedBackingStore.remove(backingStore);
 }
 
-void RemoteLayerBackingStoreCollection::purgeabilityTimerFired(WebCore::Timer<RemoteLayerBackingStoreCollection>&)
+void RemoteLayerBackingStoreCollection::backingStoreWillBeDisplayed(RemoteLayerBackingStore* backingStore)
 {
-    auto now = std::chrono::steady_clock::now();
-    bool hadRecentlyPaintedBackingStore = false;
-    bool successfullyMadeBackingStorePurgeable = true;
+    ASSERT(m_inLayerFlush);
+    m_reachableBackingStoreInLatestFlush.add(backingStore);
+
+    auto backingStoreIter = m_unparentedBackingStore.find(backingStore);
+    if (backingStoreIter == m_unparentedBackingStore.end())
+        return;
+    m_liveBackingStore.add(backingStore);
+    m_unparentedBackingStore.remove(backingStoreIter);
+}
 
-    for (const auto& backingStore : m_liveBackingStore) {
-        if (now - backingStore->lastDisplayTime() < purgeableBackingStoreAgeThreshold) {
-            hadRecentlyPaintedBackingStore = true;
+bool RemoteLayerBackingStoreCollection::markBackingStoreVolatileImmediately(RemoteLayerBackingStore& backingStore)
+{
+    ASSERT(!m_inLayerFlush);
+    bool successfullyMadeBackingStoreVolatile = true;
+
+    if (!backingStore.setBufferVolatility(RemoteLayerBackingStore::BufferType::SecondaryBack, true))
+        successfullyMadeBackingStoreVolatile = false;
+
+    if (!backingStore.setBufferVolatility(RemoteLayerBackingStore::BufferType::Back, true))
+        successfullyMadeBackingStoreVolatile = false;
+
+    if (!m_reachableBackingStoreInLatestFlush.contains(&backingStore)) {
+        if (!backingStore.setBufferVolatility(RemoteLayerBackingStore::BufferType::Front, true))
+            successfullyMadeBackingStoreVolatile = false;
+    }
 
-            if (now - backingStore->lastDisplayTime() >= purgeableSecondaryBackingStoreAgeThreshold)
-                backingStore->setBufferVolatility(RemoteLayerBackingStore::BufferType::SecondaryBack, true);
+    return successfullyMadeBackingStoreVolatile;
+}
 
-            continue;
-        }
+bool RemoteLayerBackingStoreCollection::markBackingStoreVolatile(RemoteLayerBackingStore& backingStore, std::chrono::steady_clock::time_point now)
+{
+    if (now - backingStore.lastDisplayTime() < volatileBackingStoreAgeThreshold) {
+        if (now - backingStore.lastDisplayTime() >= volatileSecondaryBackingStoreAgeThreshold)
+            backingStore.setBufferVolatility(RemoteLayerBackingStore::BufferType::SecondaryBack, true);
 
-        // FIXME: If the layer is unparented, we should make all buffers volatile.
-        if (!backingStore->setBufferVolatility(RemoteLayerBackingStore::BufferType::SecondaryBack, true))
-            successfullyMadeBackingStorePurgeable = false;
-        if (!backingStore->setBufferVolatility(RemoteLayerBackingStore::BufferType::Back, true))
-            successfullyMadeBackingStorePurgeable = false;
+        return false;
     }
+    
+    return markBackingStoreVolatileImmediately(backingStore);
+}
+
+void RemoteLayerBackingStoreCollection::backingStoreBecameUnreachable(RemoteLayerBackingStore* backingStore)
+{
+    ASSERT(backingStore->layer());
+
+    auto backingStoreIter = m_liveBackingStore.find(backingStore);
+    if (backingStoreIter == m_liveBackingStore.end())
+        return;
+    m_unparentedBackingStore.add(backingStore);
+    m_liveBackingStore.remove(backingStoreIter);
+
+    // If a layer with backing store is removed from the tree, mark it as having changed backing store, so that
+    // on the commit which returns it to the tree, we serialize the backing store (despite possibly not painting).
+    backingStore->layer()->properties().notePropertiesChanged(RemoteLayerTreeTransaction::BackingStoreChanged);
+
+    // This will not succeed in marking all buffers as volatile, because the commit unparenting the layer hasn't
+    // made it to the UI process yet. The volatility timer will finish marking the remaining buffers later.
+    markBackingStoreVolatileImmediately(*backingStore);
+}
+
+void RemoteLayerBackingStoreCollection::volatilityTimerFired(WebCore::Timer<RemoteLayerBackingStoreCollection>&)
+{
+    bool successfullyMadeBackingStoreVolatile = true;
+
+    auto now = std::chrono::steady_clock::now();
+    for (const auto& backingStore : m_liveBackingStore)
+        successfullyMadeBackingStoreVolatile &= markBackingStoreVolatile(*backingStore, now);
+
+    for (const auto& backingStore : m_unparentedBackingStore)
+        successfullyMadeBackingStoreVolatile &= markBackingStoreVolatileImmediately(*backingStore);
 
-    if (!hadRecentlyPaintedBackingStore && successfullyMadeBackingStorePurgeable)
-        m_purgeabilityTimer.stop();
+    if (successfullyMadeBackingStoreVolatile)
+        m_volatilityTimer.stop();
 }
 
-void RemoteLayerBackingStoreCollection::schedulePurgeabilityTimer()
+void RemoteLayerBackingStoreCollection::scheduleVolatilityTimer()
 {
-    if (m_purgeabilityTimer.isActive())
+    if (m_volatilityTimer.isActive())
         return;
 
-    m_purgeabilityTimer.startRepeating(purgeabilityTimerInterval);
+    m_volatilityTimer.startRepeating(volatilityTimerInterval);
 }
 
 } // namespace WebKit
index 2df5581..908dcdc 100644 (file)
@@ -163,6 +163,7 @@ public:
     void layerPropertiesChanged(PlatformCALayerRemote*, LayerProperties&);
     void setCreatedLayers(Vector<LayerCreationProperties>);
     void setDestroyedLayerIDs(Vector<WebCore::GraphicsLayer::PlatformLayerID>);
+    void setLayerIDsWithNewlyUnreachableBackingStore(Vector<WebCore::GraphicsLayer::PlatformLayerID>);
 
 #if !defined(NDEBUG) || !LOG_DISABLED
     WTF::CString description() const;
@@ -173,6 +174,7 @@ public:
 
     Vector<LayerCreationProperties> createdLayers() const { return m_createdLayers; }
     Vector<WebCore::GraphicsLayer::PlatformLayerID> destroyedLayers() const { return m_destroyedLayerIDs; }
+    Vector<WebCore::GraphicsLayer::PlatformLayerID> layerIDsWithNewlyUnreachableBackingStore() const { return m_layerIDsWithNewlyUnreachableBackingStore; }
 
     Vector<RefPtr<PlatformCALayerRemote>>& changedLayers() { return m_changedLayers; }
 
@@ -214,6 +216,7 @@ private:
     Vector<LayerCreationProperties> m_createdLayers;
     Vector<WebCore::GraphicsLayer::PlatformLayerID> m_destroyedLayerIDs;
     Vector<WebCore::GraphicsLayer::PlatformLayerID> m_videoLayerIDsPendingFullscreen;
+    Vector<WebCore::GraphicsLayer::PlatformLayerID> m_layerIDsWithNewlyUnreachableBackingStore;
 
     WebCore::IntSize m_contentsSize;
     WebCore::Color m_pageExtendedBackgroundColor;
index 1b87ae4..685371d 100644 (file)
@@ -452,6 +452,7 @@ void RemoteLayerTreeTransaction::encode(IPC::ArgumentEncoder& encoder) const
     
     encoder << m_destroyedLayerIDs;
     encoder << m_videoLayerIDsPendingFullscreen;
+    encoder << m_layerIDsWithNewlyUnreachableBackingStore;
 
     encoder << m_contentsSize;
     encoder << m_pageExtendedBackgroundColor;
@@ -503,6 +504,14 @@ bool RemoteLayerTreeTransaction::decode(IPC::ArgumentDecoder& decoder, RemoteLay
     if (!decoder.decode(result.m_videoLayerIDsPendingFullscreen))
         return false;
 
+    if (!decoder.decode(result.m_layerIDsWithNewlyUnreachableBackingStore))
+        return false;
+
+    for (auto& layerID : result.m_layerIDsWithNewlyUnreachableBackingStore) {
+        if (!layerID)
+            return false;
+    }
+
     if (!decoder.decode(result.m_contentsSize))
         return false;
     
@@ -555,6 +564,11 @@ void RemoteLayerTreeTransaction::setDestroyedLayerIDs(Vector<GraphicsLayer::Plat
     m_destroyedLayerIDs = std::move(destroyedLayerIDs);
 }
 
+void RemoteLayerTreeTransaction::setLayerIDsWithNewlyUnreachableBackingStore(Vector<GraphicsLayer::PlatformLayerID> layerIDsWithNewlyUnreachableBackingStore)
+{
+    m_layerIDsWithNewlyUnreachableBackingStore = std::move(layerIDsWithNewlyUnreachableBackingStore);
+}
+
 #if !defined(NDEBUG) || !LOG_DISABLED
 
 class RemoteLayerTreeTextStream : public TextStream
index 8239a55..066f5d7 100644 (file)
@@ -96,6 +96,11 @@ bool RemoteLayerTreeHost::updateLayerTree(const RemoteLayerTreeTransaction& tran
     for (auto& destroyedLayer : transaction.destroyedLayers())
         layerWillBeRemoved(destroyedLayer);
 
+    // Drop the contents of any layers which were unparented; the Web process will re-send
+    // the backing store in the commit that reparents them.
+    for (auto& newlyUnreachableLayerID : transaction.layerIDsWithNewlyUnreachableBackingStore())
+        asLayer(getLayer(newlyUnreachableLayerID)).contents = nullptr;
+
     return rootLayerChanged;
 }
 
index 4dd5284..ea9f404 100644 (file)
@@ -50,6 +50,7 @@ public:
 
     void backingStoreWasCreated(RemoteLayerBackingStore*);
     void backingStoreWillBeDestroyed(RemoteLayerBackingStore*);
+    void backingStoreWillBeDisplayed(RemoteLayerBackingStore*);
 
     LayerHostingMode layerHostingMode() const { return m_webPage->layerHostingMode(); }
 
index 4cb10a9..cf29eb9 100644 (file)
@@ -86,6 +86,11 @@ void RemoteLayerTreeContext::backingStoreWillBeDestroyed(RemoteLayerBackingStore
     m_backingStoreCollection.backingStoreWillBeDestroyed(backingStore);
 }
 
+void RemoteLayerTreeContext::backingStoreWillBeDisplayed(RemoteLayerBackingStore* backingStore)
+{
+    m_backingStoreCollection.backingStoreWillBeDisplayed(backingStore);
+}
+
 std::unique_ptr<GraphicsLayer> RemoteLayerTreeContext::createGraphicsLayer(GraphicsLayerClient& client)
 {
     return std::make_unique<GraphicsLayerCARemote>(client, this);
index 6c01699..f5df88e 100644 (file)
@@ -257,6 +257,9 @@ void RemoteLayerTreeDrawingArea::flushLayers()
 
     RELEASE_ASSERT(!m_pendingBackingStoreFlusher || m_pendingBackingStoreFlusher->hasFlushed());
 
+    RemoteLayerBackingStoreCollection& backingStoreCollection = m_remoteLayerTreeContext->backingStoreCollection();
+    backingStoreCollection.willFlushLayers();
+
     m_webPage->layoutIfNeeded();
 
     FloatRect visibleRect(FloatPoint(), m_viewSize);
@@ -265,9 +268,10 @@ void RemoteLayerTreeDrawingArea::flushLayers()
     m_webPage->corePage()->mainFrame().view()->flushCompositingStateIncludingSubframes();
     m_rootLayer->flushCompositingStateForThisLayerOnly();
 
-    // FIXME: minize these transactions if nothing changed.
+    // FIXME: Minimize these transactions if nothing changed.
     RemoteLayerTreeTransaction layerTransaction;
     m_remoteLayerTreeContext->buildTransaction(layerTransaction, *toGraphicsLayerCARemote(m_rootLayer.get())->platformCALayer());
+    backingStoreCollection.willCommitLayerTree(layerTransaction);
     m_webPage->willCommitLayerTree(layerTransaction);
 
     RemoteScrollingCoordinatorTransaction scrollingTransaction;
@@ -282,6 +286,7 @@ void RemoteLayerTreeDrawingArea::flushLayers()
     auto commitEncoder = std::make_unique<IPC::MessageEncoder>(Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree::receiverName(), Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree::name(), m_webPage->pageID());
     commitEncoder->encode(message.arguments());
 
+    // FIXME: Move all backing store flushing management to RemoteLayerBackingStoreCollection.
     bool hadAnyChangedBackingStore = false;
     Vector<RetainPtr<CGContextRef>> contextsToFlush;
     for (auto& layer : layerTransaction.changedLayers()) {
@@ -296,8 +301,10 @@ void RemoteLayerTreeDrawingArea::flushLayers()
         layer->didCommit();
     }
 
+    backingStoreCollection.didFlushLayers();
+
     if (hadAnyChangedBackingStore)
-        m_remoteLayerTreeContext->backingStoreCollection().schedulePurgeabilityTimer();
+        backingStoreCollection.scheduleVolatilityTimer();
 
     RefPtr<BackingStoreFlusher> backingStoreFlusher = BackingStoreFlusher::create(WebProcess::shared().parentProcessConnection(), std::move(commitEncoder), std::move(contextsToFlush));
     m_pendingBackingStoreFlusher = backingStoreFlusher;