[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 f575c90c14005695a4b86f286d79753f6c6c3ee7..a7ea312ad6374b1962b8efdb3cb467d34e982456 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 d78575fac70e8ff7e854693f62cbf3df65f8eea4..8c4a341dba89b4b2e74b3a688cb069670f90e0d4 100644 (file)
@@ -3143,9 +3143,9 @@ __ZN7WebCore13IOSurfacePool11setPoolSizeEm
 __ZN7WebCore9IOSurface11createImageEv
 __ZN7WebCore9IOSurface13setIsVolatileEb
 __ZN7WebCore9IOSurface18createFromMachPortEjNS_10ColorSpaceE
-__ZN7WebCore9IOSurface20clearGraphicsContextEv
 __ZN7WebCore9IOSurface21ensureGraphicsContextEv
 __ZN7WebCore9IOSurface21ensurePlatformContextEv
+__ZN7WebCore9IOSurface22releaseGraphicsContextEv
 __ZN7WebCore9IOSurface6createENS_7IntSizeENS_10ColorSpaceE
 __ZNK7WebCore9IOSurface14createMachPortEv
 __ZNK7WebCore9IOSurface7isInUseEv
index 0529d68d869ac717d984971faf5af1a9ab0c5628..0c609a81baddcb70e9a83bbde3562b6c10e1514c 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 4c31ca55e4e93675e65e8ce001fb15d4ea454727..540a87d5e494f346c6c8b9ada4b2ab3099b1cb5a 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 01fe0ec6faaa23fde198a84c389407bccb09ec7b..f6601e3c647a9fc59f2af06850cdab0007417741 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 4fffb241259af9b5223c19f7517df8bb72c4fb90..d4b9765f1456662bd681db65858e309a9b89990a 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 6c0ea498f2532a7feb4458d07e22c4782c3da76c..eb74ab7e51ef3d3c42e324d77303a25890e328e0 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 3b8ee771f7136574fb5817089075732a588f4606..81d2b107f15dc0db97e613f77ffe00f3a72531d8 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 14fa992f5fe57bdd67dad8af0c8c34924c85ac0b..d1d9583212c4bb1de64cc6b9ad174b2eff2c6d84 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 2df5581f20062ca8e7f8899df82332d1c1358ceb..908dcdc3f75c3274dca3dc21753e9e5a28b5774e 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 1b87ae4a63b50d340a354ee8c1ed1045719c81fb..685371d3eae290ddf16b545b1f83c10531ae7f41 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 8239a5515fb7132aecc15b09b92887c3d5c8f1db..066f5d7a011bc834d183e21d384f3d2186b9d18c 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 4dd528425df4559321ebedd8b05b38a16dd9d66c..ea9f404fdf93457d617d35ab7bae1a9426dbead2 100644 (file)
@@ -50,6 +50,7 @@ public:
 
     void backingStoreWasCreated(RemoteLayerBackingStore*);
     void backingStoreWillBeDestroyed(RemoteLayerBackingStore*);
+    void backingStoreWillBeDisplayed(RemoteLayerBackingStore*);
 
     LayerHostingMode layerHostingMode() const { return m_webPage->layerHostingMode(); }
 
index 4cb10a9e9cf7f3a7d62520b2fc231cb257ac1ac3..cf29eb90c33660597f22e9eeec54fccea6249c8f 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 6c0169921fb70124687325491014c4e366d46a55..f5df88e650410cd830516dd172afdfde849a4ea8 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;