OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2013 Google Inc. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license that can be | |
5 * found in the LICENSE file. | |
6 */ | |
7 | |
8 #include "SkThread.h" | |
9 #include "SkPurgeableImageCache.h" | |
10 #include "SkPurgeableMemoryBlock.h" | |
11 | |
12 #ifdef SK_DEBUG | |
13 #include "SkTSearch.h" | |
14 #endif | |
15 | |
16 SK_DECLARE_STATIC_MUTEX(gPurgeableImageMutex); | |
17 | |
18 SkImageCache* SkPurgeableImageCache::Create() { | |
19 if (!SkPurgeableMemoryBlock::IsSupported()) { | |
20 return NULL; | |
21 } | |
22 SkAutoMutexAcquire ac(&gPurgeableImageMutex); | |
23 static SkPurgeableImageCache gCache; | |
24 gCache.ref(); | |
25 return &gCache; | |
26 } | |
27 | |
28 SkPurgeableImageCache::SkPurgeableImageCache() {} | |
29 | |
30 #ifdef SK_DEBUG | |
31 SkPurgeableImageCache::~SkPurgeableImageCache() { | |
32 SkASSERT(fRecs.count() == 0); | |
33 } | |
34 #endif | |
35 | |
36 | |
37 void* SkPurgeableImageCache::allocAndPinCache(size_t bytes, intptr_t* ID) { | |
38 SkAutoMutexAcquire ac(&gPurgeableImageMutex); | |
39 | |
40 SkPurgeableMemoryBlock* block = SkPurgeableMemoryBlock::Create(bytes); | |
41 if (NULL == block) { | |
42 return NULL; | |
43 } | |
44 | |
45 SkPurgeableMemoryBlock::PinResult pinResult; | |
46 void* data = block->pin(&pinResult); | |
47 if (NULL == data) { | |
48 SkDELETE(block); | |
49 return NULL; | |
50 } | |
51 | |
52 SkASSERT(ID != NULL); | |
53 *ID = reinterpret_cast<intptr_t>(block); | |
54 #ifdef SK_DEBUG | |
55 // Insert into the array of all recs: | |
56 int index = this->findRec(*ID); | |
57 SkASSERT(index < 0); | |
58 fRecs.insert(~index, 1, ID); | |
59 #endif | |
60 return data; | |
61 } | |
62 | |
63 void* SkPurgeableImageCache::pinCache(intptr_t ID, SkImageCache::DataStatus* sta
tus) { | |
64 SkASSERT(ID != SkImageCache::UNINITIALIZED_ID); | |
65 SkAutoMutexAcquire ac(&gPurgeableImageMutex); | |
66 | |
67 SkASSERT(this->findRec(ID) >= 0); | |
68 SkPurgeableMemoryBlock* block = reinterpret_cast<SkPurgeableMemoryBlock*>(ID
); | |
69 SkPurgeableMemoryBlock::PinResult pinResult; | |
70 void* data = block->pin(&pinResult); | |
71 if (NULL == data) { | |
72 this->removeRec(ID); | |
73 return NULL; | |
74 } | |
75 | |
76 switch (pinResult) { | |
77 case SkPurgeableMemoryBlock::kRetained_PinResult: | |
78 *status = SkImageCache::kRetained_DataStatus; | |
79 break; | |
80 | |
81 case SkPurgeableMemoryBlock::kUninitialized_PinResult: | |
82 *status = SkImageCache::kUninitialized_DataStatus; | |
83 break; | |
84 | |
85 default: | |
86 // Invalid value. Treat as a failure to pin. | |
87 SkASSERT(false); | |
88 this->removeRec(ID); | |
89 return NULL; | |
90 } | |
91 | |
92 return data; | |
93 } | |
94 | |
95 void SkPurgeableImageCache::releaseCache(intptr_t ID) { | |
96 SkASSERT(ID != SkImageCache::UNINITIALIZED_ID); | |
97 SkAutoMutexAcquire ac(&gPurgeableImageMutex); | |
98 | |
99 SkASSERT(this->findRec(ID) >= 0); | |
100 SkPurgeableMemoryBlock* block = reinterpret_cast<SkPurgeableMemoryBlock*>(ID
); | |
101 block->unpin(); | |
102 } | |
103 | |
104 void SkPurgeableImageCache::throwAwayCache(intptr_t ID) { | |
105 SkASSERT(ID != SkImageCache::UNINITIALIZED_ID); | |
106 SkAutoMutexAcquire ac(&gPurgeableImageMutex); | |
107 | |
108 this->removeRec(ID); | |
109 } | |
110 | |
111 #ifdef SK_DEBUG | |
112 SkImageCache::MemoryStatus SkPurgeableImageCache::getMemoryStatus(intptr_t ID) c
onst { | |
113 SkAutoMutexAcquire ac(&gPurgeableImageMutex); | |
114 if (SkImageCache::UNINITIALIZED_ID == ID || this->findRec(ID) < 0) { | |
115 return SkImageCache::kFreed_MemoryStatus; | |
116 } | |
117 | |
118 SkPurgeableMemoryBlock* block = reinterpret_cast<SkPurgeableMemoryBlock*>(ID
); | |
119 if (block->isPinned()) { | |
120 return SkImageCache::kPinned_MemoryStatus; | |
121 } | |
122 return SkImageCache::kUnpinned_MemoryStatus; | |
123 } | |
124 | |
125 void SkPurgeableImageCache::purgeAllUnpinnedCaches() { | |
126 SkAutoMutexAcquire ac(&gPurgeableImageMutex); | |
127 if (SkPurgeableMemoryBlock::PlatformSupportsPurgingAllUnpinnedBlocks()) { | |
128 SkPurgeableMemoryBlock::PurgeAllUnpinnedBlocks(); | |
129 } else { | |
130 // Go through the blocks, and purge them individually. | |
131 // Rather than deleting the blocks, which would interfere with further c
alls, purge them | |
132 // and keep them around. | |
133 for (int i = 0; i < fRecs.count(); i++) { | |
134 SkPurgeableMemoryBlock* block = reinterpret_cast<SkPurgeableMemoryBl
ock*>(fRecs[i]); | |
135 if (!block->isPinned()) { | |
136 if (!block->purge()) { | |
137 // FIXME: This should be more meaningful (which one, etc...) | |
138 SkDebugf("Failed to purge\n"); | |
139 } | |
140 } | |
141 } | |
142 } | |
143 } | |
144 | |
145 int SkPurgeableImageCache::findRec(intptr_t rec) const { | |
146 return SkTSearch(fRecs.begin(), fRecs.count(), rec, sizeof(intptr_t)); | |
147 } | |
148 #endif | |
149 | |
150 void SkPurgeableImageCache::removeRec(intptr_t ID) { | |
151 #ifdef SK_DEBUG | |
152 int index = this->findRec(ID); | |
153 SkASSERT(index >= 0); | |
154 fRecs.remove(index); | |
155 #endif | |
156 SkPurgeableMemoryBlock* block = reinterpret_cast<SkPurgeableMemoryBlock*>(ID
); | |
157 SkASSERT(!block->isPinned()); | |
158 SkDELETE(block); | |
159 } | |
OLD | NEW |