[WTF] Move currentCPUTime and sleep(Seconds) to CPUTime.h and Seconds.h respectively
[WebKit-https.git] / Source / WebCore / platform / graphics / ca / LayerPool.cpp
1 /*
2  * Copyright (C) 2012, 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 #include "config.h"
27 #include "LayerPool.h"
28
29 #include "Logging.h"
30 #include <wtf/NeverDestroyed.h>
31
32 namespace WebCore {
33
34 static const Seconds capacityDecayTime { 5_s };
35
36 LayerPool::LayerPool()
37     : m_totalBytes(0)
38     , m_maxBytesForPool(48 * 1024 * 1024)
39     , m_pruneTimer(*this, &LayerPool::pruneTimerFired)
40 {
41     allLayerPools().add(this);
42 }
43
44 LayerPool::~LayerPool()
45 {
46     allLayerPools().remove(this);
47 }
48
49 HashSet<LayerPool*>& LayerPool::allLayerPools()
50 {
51     static NeverDestroyed<HashSet<LayerPool*>> allLayerPools;
52     return allLayerPools.get();
53 }
54
55 unsigned LayerPool::backingStoreBytesForSize(const IntSize& size)
56 {
57     return (size.area() * 4).unsafeGet();
58 }
59
60 LayerPool::LayerList& LayerPool::listOfLayersWithSize(const IntSize& size, AccessType accessType)
61 {
62     HashMap<IntSize, LayerList>::iterator it = m_reuseLists.find(size);
63     if (it == m_reuseLists.end()) {
64         it = m_reuseLists.add(size, LayerList()).iterator;
65         m_sizesInPruneOrder.append(size);
66     } else if (accessType == MarkAsUsed) {
67         m_sizesInPruneOrder.remove(m_sizesInPruneOrder.reverseFind(size));
68         m_sizesInPruneOrder.append(size);
69     }
70     return it->value;
71 }
72
73 void LayerPool::addLayer(const RefPtr<PlatformCALayer>& layer)
74 {
75     IntSize layerSize(expandedIntSize(layer->bounds().size()));
76     if (!canReuseLayerWithSize(layerSize))
77         return;
78
79     listOfLayersWithSize(layerSize).prepend(layer);
80     m_totalBytes += backingStoreBytesForSize(layerSize);
81     
82     m_lastAddTime = MonotonicTime::now();
83     schedulePrune();
84 }
85
86 RefPtr<PlatformCALayer> LayerPool::takeLayerWithSize(const IntSize& size)
87 {
88     if (!canReuseLayerWithSize(size))
89         return nullptr;
90     LayerList& reuseList = listOfLayersWithSize(size, MarkAsUsed);
91     if (reuseList.isEmpty())
92         return nullptr;
93     m_totalBytes -= backingStoreBytesForSize(size);
94     return reuseList.takeFirst();
95 }
96     
97 unsigned LayerPool::decayedCapacity() const
98 {
99     // Decay to one quarter over capacityDecayTime
100     Seconds timeSinceLastAdd = MonotonicTime::now() - m_lastAddTime;
101     if (timeSinceLastAdd > capacityDecayTime)
102         return m_maxBytesForPool / 4;
103     float decayProgess = float(timeSinceLastAdd / capacityDecayTime);
104     return m_maxBytesForPool / 4 + m_maxBytesForPool * 3 / 4 * (1 - decayProgess);
105 }
106
107 void LayerPool::schedulePrune()
108 {
109     if (m_pruneTimer.isActive())
110         return;
111     m_pruneTimer.startOneShot(1_s);
112 }
113
114 void LayerPool::pruneTimerFired()
115 {
116     unsigned shrinkTo = decayedCapacity();
117     while (m_totalBytes > shrinkTo) {
118         ASSERT(!m_sizesInPruneOrder.isEmpty());
119         IntSize sizeToDrop = m_sizesInPruneOrder.first();
120         LayerList& oldestReuseList = m_reuseLists.find(sizeToDrop)->value;
121         if (oldestReuseList.isEmpty()) {
122             m_reuseLists.remove(sizeToDrop);
123             m_sizesInPruneOrder.remove(0);
124             continue;
125         }
126
127         m_totalBytes -= backingStoreBytesForSize(sizeToDrop);
128         // The last element in the list is the oldest, hence most likely not to
129         // still have a backing store.
130         oldestReuseList.remove(--oldestReuseList.end());
131     }
132     if (MonotonicTime::now() - m_lastAddTime <= capacityDecayTime)
133         schedulePrune();
134 }
135
136 void LayerPool::drain()
137 {
138     m_reuseLists.clear();
139     m_sizesInPruneOrder.clear();
140     m_totalBytes = 0;
141 }
142
143 }