blob: b8bbfd2f6eb20992512e7eea4df27b838dd950cb [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkImageRefPool.h"
9#include "SkImageRef.h"
10#include "SkThread.h"
11
12SkImageRefPool::SkImageRefPool() {
13 fRAMBudget = 0; // means no explicit limit
14 fRAMUsed = 0;
15 fCount = 0;
16 fHead = fTail = NULL;
17}
18
19SkImageRefPool::~SkImageRefPool() {
20 // SkASSERT(NULL == fHead);
21}
22
23void SkImageRefPool::setRAMBudget(size_t size) {
24 if (fRAMBudget != size) {
25 fRAMBudget = size;
26 this->purgeIfNeeded();
27 }
28}
29
30void 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
42void 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
50void 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
57void SkImageRefPool::setRAMUsed(size_t limit) {
58 SkImageRef* ref = fTail;
rmistry@google.comd6176b02012-08-23 18:14:13 +000059
reed@android.com8a1c16f2008-12-17 15:59:43 +000060 while (NULL != ref && fRAMUsed > limit) {
61 // only purge it if its pixels are unlocked
reed@google.comff0da4f2012-05-17 13:14:52 +000062 if (!ref->isLocked() && ref->fBitmap.getPixels()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000063 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
rmistry@google.comd6176b02012-08-23 18:14:13 +000074
reed@android.com8a1c16f2008-12-17 15:59:43 +000075 // 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
86void SkImageRefPool::addToHead(SkImageRef* ref) {
87 ref->fNext = fHead;
88 ref->fPrev = NULL;
rmistry@google.comd6176b02012-08-23 18:14:13 +000089
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 if (fHead) {
91 SkASSERT(NULL == fHead->fPrev);
92 fHead->fPrev = ref;
93 }
94 fHead = ref;
rmistry@google.comd6176b02012-08-23 18:14:13 +000095
reed@android.com8a1c16f2008-12-17 15:59:43 +000096 if (NULL == fTail) {
97 fTail = ref;
98 }
99 fCount += 1;
100 SkASSERT(computeCount() == fCount);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000101
reed@android.com8a1c16f2008-12-17 15:59:43 +0000102 fRAMUsed += ref->ramUsed();
103}
104
105void SkImageRefPool::addToTail(SkImageRef* ref) {
106 ref->fNext = NULL;
107 ref->fPrev = fTail;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000108
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109 if (fTail) {
110 SkASSERT(NULL == fTail->fNext);
111 fTail->fNext = ref;
112 }
113 fTail = ref;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000114
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115 if (NULL == fHead) {
116 fHead = ref;
117 }
118 fCount += 1;
119 SkASSERT(computeCount() == fCount);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000120
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121 fRAMUsed += ref->ramUsed();
122}
123
124void SkImageRefPool::detach(SkImageRef* ref) {
125 SkASSERT(fCount > 0);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000126
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127 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 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000139
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140 ref->fNext = ref->fPrev = NULL;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000141
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142 fCount -= 1;
143 SkASSERT(computeCount() == fCount);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000144
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145 SkASSERT(fRAMUsed >= ref->ramUsed());
146 fRAMUsed -= ref->ramUsed();
147}
148
149int SkImageRefPool::computeCount() const {
150 SkImageRef* ref = fHead;
151 int count = 0;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000152
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 while (ref != NULL) {
154 count += 1;
155 ref = ref->fNext;
156 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000157
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158#ifdef SK_DEBUG
159 ref = fTail;
160 int count2 = 0;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000161
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162 while (ref != NULL) {
163 count2 += 1;
164 ref = ref->fPrev;
165 }
166 SkASSERT(count2 == count);
167#endif
rmistry@google.comd6176b02012-08-23 18:14:13 +0000168
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 return count;
170}
171
172///////////////////////////////////////////////////////////////////////////////
173
174#include "SkStream.h"
175
176void 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);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000180
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181 SkImageRef* ref = fHead;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000182
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183 while (ref != NULL) {
reed@google.comff0da4f2012-05-17 13:14:52 +0000184 SkDebugf(" [%3d %3d %d] ram=%d data=%d locked=%d %s\n", ref->fBitmap.width(),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185 ref->fBitmap.height(), ref->fBitmap.config(),
186 ref->ramUsed(), (int)ref->fStream->getLength(),
reed@google.comff0da4f2012-05-17 13:14:52 +0000187 ref->isLocked(), ref->getURI());
rmistry@google.comd6176b02012-08-23 18:14:13 +0000188
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 ref = ref->fNext;
190 }
191#endif
192}
193