|
1 |
|
2 /* |
|
3 * Copyright 2011 Google Inc. |
|
4 * |
|
5 * Use of this source code is governed by a BSD-style license that can be |
|
6 * found in the LICENSE file. |
|
7 */ |
|
8 #include "SkImageRefPool.h" |
|
9 #include "SkImageRef.h" |
|
10 #include "SkThread.h" |
|
11 |
|
12 SkImageRefPool::SkImageRefPool() { |
|
13 fRAMBudget = 0; // means no explicit limit |
|
14 fRAMUsed = 0; |
|
15 fCount = 0; |
|
16 fHead = fTail = NULL; |
|
17 } |
|
18 |
|
19 SkImageRefPool::~SkImageRefPool() { |
|
20 // SkASSERT(NULL == fHead); |
|
21 } |
|
22 |
|
23 void SkImageRefPool::setRAMBudget(size_t size) { |
|
24 if (fRAMBudget != size) { |
|
25 fRAMBudget = size; |
|
26 this->purgeIfNeeded(); |
|
27 } |
|
28 } |
|
29 |
|
30 void SkImageRefPool::justAddedPixels(SkImageRef* ref) { |
|
31 #ifdef DUMP_IMAGEREF_LIFECYCLE |
|
32 SkDebugf("=== ImagePool: add pixels %s [%d %d %d] bytes=%d heap=%d\n", |
|
33 ref->getURI(), |
|
34 ref->fBitmap.width(), ref->fBitmap.height(), |
|
35 ref->fBitmap.bytesPerPixel(), |
|
36 ref->fBitmap.getSize(), (int)fRAMUsed); |
|
37 #endif |
|
38 fRAMUsed += ref->ramUsed(); |
|
39 this->purgeIfNeeded(); |
|
40 } |
|
41 |
|
42 void SkImageRefPool::canLosePixels(SkImageRef* ref) { |
|
43 // the refs near fHead have recently been released (used) |
|
44 // if we purge, we purge from the tail |
|
45 this->detach(ref); |
|
46 this->addToHead(ref); |
|
47 this->purgeIfNeeded(); |
|
48 } |
|
49 |
|
50 void SkImageRefPool::purgeIfNeeded() { |
|
51 // do nothing if we have a zero-budget (i.e. unlimited) |
|
52 if (fRAMBudget != 0) { |
|
53 this->setRAMUsed(fRAMBudget); |
|
54 } |
|
55 } |
|
56 |
|
57 void SkImageRefPool::setRAMUsed(size_t limit) { |
|
58 SkImageRef* ref = fTail; |
|
59 |
|
60 while (NULL != ref && fRAMUsed > limit) { |
|
61 // only purge it if its pixels are unlocked |
|
62 if (!ref->isLocked() && ref->fBitmap.getPixels()) { |
|
63 size_t size = ref->ramUsed(); |
|
64 SkASSERT(size <= fRAMUsed); |
|
65 fRAMUsed -= size; |
|
66 |
|
67 #ifdef DUMP_IMAGEREF_LIFECYCLE |
|
68 SkDebugf("=== ImagePool: purge %s [%d %d %d] bytes=%d heap=%d\n", |
|
69 ref->getURI(), |
|
70 ref->fBitmap.width(), ref->fBitmap.height(), |
|
71 ref->fBitmap.bytesPerPixel(), |
|
72 (int)size, (int)fRAMUsed); |
|
73 #endif |
|
74 |
|
75 // remember the bitmap config (don't call reset), |
|
76 // just clear the pixel memory |
|
77 ref->fBitmap.setPixels(NULL); |
|
78 SkASSERT(NULL == ref->fBitmap.getPixels()); |
|
79 } |
|
80 ref = ref->fPrev; |
|
81 } |
|
82 } |
|
83 |
|
84 /////////////////////////////////////////////////////////////////////////////// |
|
85 |
|
86 void SkImageRefPool::addToHead(SkImageRef* ref) { |
|
87 ref->fNext = fHead; |
|
88 ref->fPrev = NULL; |
|
89 |
|
90 if (fHead) { |
|
91 SkASSERT(NULL == fHead->fPrev); |
|
92 fHead->fPrev = ref; |
|
93 } |
|
94 fHead = ref; |
|
95 |
|
96 if (NULL == fTail) { |
|
97 fTail = ref; |
|
98 } |
|
99 fCount += 1; |
|
100 SkASSERT(computeCount() == fCount); |
|
101 |
|
102 fRAMUsed += ref->ramUsed(); |
|
103 } |
|
104 |
|
105 void SkImageRefPool::addToTail(SkImageRef* ref) { |
|
106 ref->fNext = NULL; |
|
107 ref->fPrev = fTail; |
|
108 |
|
109 if (fTail) { |
|
110 SkASSERT(NULL == fTail->fNext); |
|
111 fTail->fNext = ref; |
|
112 } |
|
113 fTail = ref; |
|
114 |
|
115 if (NULL == fHead) { |
|
116 fHead = ref; |
|
117 } |
|
118 fCount += 1; |
|
119 SkASSERT(computeCount() == fCount); |
|
120 |
|
121 fRAMUsed += ref->ramUsed(); |
|
122 } |
|
123 |
|
124 void SkImageRefPool::detach(SkImageRef* ref) { |
|
125 SkASSERT(fCount > 0); |
|
126 |
|
127 if (fHead == ref) { |
|
128 fHead = ref->fNext; |
|
129 } |
|
130 if (fTail == ref) { |
|
131 fTail = ref->fPrev; |
|
132 } |
|
133 if (ref->fPrev) { |
|
134 ref->fPrev->fNext = ref->fNext; |
|
135 } |
|
136 if (ref->fNext) { |
|
137 ref->fNext->fPrev = ref->fPrev; |
|
138 } |
|
139 |
|
140 ref->fNext = ref->fPrev = NULL; |
|
141 |
|
142 fCount -= 1; |
|
143 SkASSERT(computeCount() == fCount); |
|
144 |
|
145 SkASSERT(fRAMUsed >= ref->ramUsed()); |
|
146 fRAMUsed -= ref->ramUsed(); |
|
147 } |
|
148 |
|
149 int SkImageRefPool::computeCount() const { |
|
150 SkImageRef* ref = fHead; |
|
151 int count = 0; |
|
152 |
|
153 while (ref != NULL) { |
|
154 count += 1; |
|
155 ref = ref->fNext; |
|
156 } |
|
157 |
|
158 #ifdef SK_DEBUG |
|
159 ref = fTail; |
|
160 int count2 = 0; |
|
161 |
|
162 while (ref != NULL) { |
|
163 count2 += 1; |
|
164 ref = ref->fPrev; |
|
165 } |
|
166 SkASSERT(count2 == count); |
|
167 #endif |
|
168 |
|
169 return count; |
|
170 } |
|
171 |
|
172 /////////////////////////////////////////////////////////////////////////////// |
|
173 |
|
174 #include "SkStream.h" |
|
175 |
|
176 void SkImageRefPool::dump() const { |
|
177 #if defined(SK_DEBUG) || defined(DUMP_IMAGEREF_LIFECYCLE) |
|
178 SkDebugf("ImagePool dump: bugdet: %d used: %d count: %d\n", |
|
179 (int)fRAMBudget, (int)fRAMUsed, fCount); |
|
180 |
|
181 SkImageRef* ref = fHead; |
|
182 |
|
183 while (ref != NULL) { |
|
184 SkDebugf(" [%3d %3d %d] ram=%d data=%d locked=%d %s\n", ref->fBitmap.width(), |
|
185 ref->fBitmap.height(), ref->fBitmap.config(), |
|
186 ref->ramUsed(), (int)ref->fStream->getLength(), |
|
187 ref->isLocked(), ref->getURI()); |
|
188 |
|
189 ref = ref->fNext; |
|
190 } |
|
191 #endif |
|
192 } |