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