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