1 /* 2 * Copyright (C) 2014 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#import "config.h" 27#import "RemoteLayerBackingStoreCollection.h" 28 29#import "PlatformCALayerRemote.h" 30#import "RemoteLayerBackingStore.h" 31#import "RemoteLayerTreeContext.h" 32 33const std::chrono::seconds volatileBackingStoreAgeThreshold = 1_s; 34const std::chrono::milliseconds volatileSecondaryBackingStoreAgeThreshold = 200_ms; 35const std::chrono::milliseconds volatilityTimerInterval = 200_ms; 36 37namespace WebKit { 38 39RemoteLayerBackingStoreCollection::RemoteLayerBackingStoreCollection() 40 : m_volatilityTimer(this, &RemoteLayerBackingStoreCollection::volatilityTimerFired) 41 , m_inLayerFlush(false) 42{ 43} 44 45void RemoteLayerBackingStoreCollection::willFlushLayers() 46{ 47 m_inLayerFlush = true; 48 m_reachableBackingStoreInLatestFlush.clear(); 49} 50 51void RemoteLayerBackingStoreCollection::willCommitLayerTree(RemoteLayerTreeTransaction& transaction) 52{ 53 ASSERT(m_inLayerFlush); 54 Vector<WebCore::GraphicsLayer::PlatformLayerID> newlyUnreachableLayerIDs; 55 for (auto& backingStore : m_liveBackingStore) { 56 if (!m_reachableBackingStoreInLatestFlush.contains(backingStore)) 57 newlyUnreachableLayerIDs.append(backingStore->layer()->layerID()); 58 } 59 60 transaction.setLayerIDsWithNewlyUnreachableBackingStore(newlyUnreachableLayerIDs); 61} 62 63void RemoteLayerBackingStoreCollection::didFlushLayers() 64{ 65 m_inLayerFlush = false; 66 67 Vector<RemoteLayerBackingStore*> newlyUnreachableBackingStore; 68 for (auto& backingStore : m_liveBackingStore) { 69 if (!m_reachableBackingStoreInLatestFlush.contains(backingStore)) 70 newlyUnreachableBackingStore.append(backingStore); 71 } 72 73 for (auto& backingStore : newlyUnreachableBackingStore) 74 backingStoreBecameUnreachable(*backingStore); 75 76 if (!newlyUnreachableBackingStore.isEmpty()) 77 scheduleVolatilityTimer(); 78} 79 80void RemoteLayerBackingStoreCollection::backingStoreWasCreated(RemoteLayerBackingStore& backingStore) 81{ 82 m_liveBackingStore.add(&backingStore); 83} 84 85void RemoteLayerBackingStoreCollection::backingStoreWillBeDestroyed(RemoteLayerBackingStore& backingStore) 86{ 87 m_liveBackingStore.remove(&backingStore); 88 m_unparentedBackingStore.remove(&backingStore); 89} 90 91void RemoteLayerBackingStoreCollection::backingStoreWillBeDisplayed(RemoteLayerBackingStore& backingStore) 92{ 93 ASSERT(m_inLayerFlush); 94 m_reachableBackingStoreInLatestFlush.add(&backingStore); 95 96 auto backingStoreIter = m_unparentedBackingStore.find(&backingStore); 97 if (backingStoreIter == m_unparentedBackingStore.end()) 98 return; 99 m_liveBackingStore.add(&backingStore); 100 m_unparentedBackingStore.remove(backingStoreIter); 101} 102 103bool RemoteLayerBackingStoreCollection::markBackingStoreVolatileImmediately(RemoteLayerBackingStore& backingStore, VolatilityMarkingFlags volatilityMarkingFlags) 104{ 105 ASSERT(!m_inLayerFlush); 106 bool successfullyMadeBackingStoreVolatile = true; 107 108 if (!backingStore.setBufferVolatility(RemoteLayerBackingStore::BufferType::SecondaryBack, true)) 109 successfullyMadeBackingStoreVolatile = false; 110 111 if (!backingStore.setBufferVolatility(RemoteLayerBackingStore::BufferType::Back, true)) 112 successfullyMadeBackingStoreVolatile = false; 113 114 if (!m_reachableBackingStoreInLatestFlush.contains(&backingStore) || (volatilityMarkingFlags & MarkBuffersIgnoringReachability)) { 115 if (!backingStore.setBufferVolatility(RemoteLayerBackingStore::BufferType::Front, true)) 116 successfullyMadeBackingStoreVolatile = false; 117 } 118 119 return successfullyMadeBackingStoreVolatile; 120} 121 122bool RemoteLayerBackingStoreCollection::markBackingStoreVolatile(RemoteLayerBackingStore& backingStore, std::chrono::steady_clock::time_point now) 123{ 124 if (now - backingStore.lastDisplayTime() < volatileBackingStoreAgeThreshold) { 125 if (now - backingStore.lastDisplayTime() >= volatileSecondaryBackingStoreAgeThreshold) 126 backingStore.setBufferVolatility(RemoteLayerBackingStore::BufferType::SecondaryBack, true); 127 128 return false; 129 } 130 131 return markBackingStoreVolatileImmediately(backingStore); 132} 133 134void RemoteLayerBackingStoreCollection::backingStoreBecameUnreachable(RemoteLayerBackingStore& backingStore) 135{ 136 ASSERT(backingStore.layer()); 137 138 auto backingStoreIter = m_liveBackingStore.find(&backingStore); 139 if (backingStoreIter == m_liveBackingStore.end()) 140 return; 141 m_unparentedBackingStore.add(&backingStore); 142 m_liveBackingStore.remove(backingStoreIter); 143 144 // If a layer with backing store is removed from the tree, mark it as having changed backing store, so that 145 // on the commit which returns it to the tree, we serialize the backing store (despite possibly not painting). 146 backingStore.layer()->properties().notePropertiesChanged(RemoteLayerTreeTransaction::BackingStoreChanged); 147 148 // This will not succeed in marking all buffers as volatile, because the commit unparenting the layer hasn't 149 // made it to the UI process yet. The volatility timer will finish marking the remaining buffers later. 150 markBackingStoreVolatileImmediately(backingStore); 151} 152 153bool RemoteLayerBackingStoreCollection::markAllBackingStoreVolatileImmediatelyIfPossible() 154{ 155 bool successfullyMadeBackingStoreVolatile = true; 156 157 for (const auto& backingStore : m_liveBackingStore) 158 successfullyMadeBackingStoreVolatile &= markBackingStoreVolatileImmediately(*backingStore, MarkBuffersIgnoringReachability); 159 160 for (const auto& backingStore : m_unparentedBackingStore) 161 successfullyMadeBackingStoreVolatile &= markBackingStoreVolatileImmediately(*backingStore, MarkBuffersIgnoringReachability); 162 163 return successfullyMadeBackingStoreVolatile; 164} 165 166void RemoteLayerBackingStoreCollection::volatilityTimerFired(WebCore::Timer<RemoteLayerBackingStoreCollection>&) 167{ 168 bool successfullyMadeBackingStoreVolatile = true; 169 170 auto now = std::chrono::steady_clock::now(); 171 for (const auto& backingStore : m_liveBackingStore) 172 successfullyMadeBackingStoreVolatile &= markBackingStoreVolatile(*backingStore, now); 173 174 for (const auto& backingStore : m_unparentedBackingStore) 175 successfullyMadeBackingStoreVolatile &= markBackingStoreVolatileImmediately(*backingStore); 176 177 if (successfullyMadeBackingStoreVolatile) 178 m_volatilityTimer.stop(); 179} 180 181void RemoteLayerBackingStoreCollection::scheduleVolatilityTimer() 182{ 183 if (m_volatilityTimer.isActive()) 184 return; 185 186 m_volatilityTimer.startRepeating(volatilityTimerInterval); 187} 188 189} // namespace WebKit 190