/* * Copyright (C) 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #import "config.h" #import "RemoteLayerBackingStoreCollection.h" #import "PlatformCALayerRemote.h" #import "RemoteLayerBackingStore.h" #import "RemoteLayerTreeContext.h" const Seconds volatileBackingStoreAgeThreshold = 1_s; const Seconds volatileSecondaryBackingStoreAgeThreshold = 200_ms; const Seconds volatilityTimerInterval = 200_ms; namespace WebKit { RemoteLayerBackingStoreCollection::RemoteLayerBackingStoreCollection() : m_volatilityTimer(*this, &RemoteLayerBackingStoreCollection::volatilityTimerFired) { } void RemoteLayerBackingStoreCollection::willFlushLayers() { m_inLayerFlush = true; m_reachableBackingStoreInLatestFlush.clear(); } void RemoteLayerBackingStoreCollection::willCommitLayerTree(RemoteLayerTreeTransaction& transaction) { ASSERT(m_inLayerFlush); Vector 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 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); } void RemoteLayerBackingStoreCollection::backingStoreWillBeDestroyed(RemoteLayerBackingStore& backingStore) { m_liveBackingStore.remove(&backingStore); m_unparentedBackingStore.remove(&backingStore); } bool RemoteLayerBackingStoreCollection::backingStoreWillBeDisplayed(RemoteLayerBackingStore& backingStore) { ASSERT(m_inLayerFlush); m_reachableBackingStoreInLatestFlush.add(&backingStore); auto backingStoreIter = m_unparentedBackingStore.find(&backingStore); if (backingStoreIter == m_unparentedBackingStore.end()) return false; m_liveBackingStore.add(&backingStore); m_unparentedBackingStore.remove(backingStoreIter); return true; } bool RemoteLayerBackingStoreCollection::markBackingStoreVolatileImmediately(RemoteLayerBackingStore& backingStore, VolatilityMarkingFlags volatilityMarkingFlags) { 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) || (volatilityMarkingFlags & MarkBuffersIgnoringReachability)) { if (!backingStore.setBufferVolatility(RemoteLayerBackingStore::BufferType::Front, true)) successfullyMadeBackingStoreVolatile = false; } return successfullyMadeBackingStoreVolatile; } bool RemoteLayerBackingStoreCollection::markBackingStoreVolatile(RemoteLayerBackingStore& backingStore, MonotonicTime now) { if (now - backingStore.lastDisplayTime() < volatileBackingStoreAgeThreshold) { if (now - backingStore.lastDisplayTime() >= volatileSecondaryBackingStoreAgeThreshold) backingStore.setBufferVolatility(RemoteLayerBackingStore::BufferType::SecondaryBack, true); 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); // 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); } bool RemoteLayerBackingStoreCollection::markAllBackingStoreVolatileImmediatelyIfPossible() { bool successfullyMadeBackingStoreVolatile = true; for (const auto& backingStore : m_liveBackingStore) successfullyMadeBackingStoreVolatile &= markBackingStoreVolatileImmediately(*backingStore, MarkBuffersIgnoringReachability); for (const auto& backingStore : m_unparentedBackingStore) successfullyMadeBackingStoreVolatile &= markBackingStoreVolatileImmediately(*backingStore, MarkBuffersIgnoringReachability); return successfullyMadeBackingStoreVolatile; } void RemoteLayerBackingStoreCollection::volatilityTimerFired() { bool successfullyMadeBackingStoreVolatile = true; auto now = MonotonicTime::now(); for (const auto& backingStore : m_liveBackingStore) successfullyMadeBackingStoreVolatile &= markBackingStoreVolatile(*backingStore, now); for (const auto& backingStore : m_unparentedBackingStore) successfullyMadeBackingStoreVolatile &= markBackingStoreVolatileImmediately(*backingStore); if (successfullyMadeBackingStoreVolatile) m_volatilityTimer.stop(); } void RemoteLayerBackingStoreCollection::scheduleVolatilityTimer() { if (m_volatilityTimer.isActive()) return; m_volatilityTimer.startRepeating(volatilityTimerInterval); } } // namespace WebKit