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