blob: bb12d667eeeb8a5d203e4effec551dce600af5fb [file] [log] [blame]
halcanary805ef152014-07-17 06:58:01 -07001/*
2 * Copyright 2014 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 */
reed30ad5302014-09-16 10:39:55 -07007
halcanary805ef152014-07-17 06:58:01 -07008#include "Test.h"
reed04617132014-08-21 09:46:49 -07009#include "SkBitmapCache.h"
reed30ad5302014-09-16 10:39:55 -070010#include "SkCanvas.h"
danakj790ffe32014-09-11 10:49:52 -070011#include "SkDiscardableMemoryPool.h"
reed30ad5302014-09-16 10:39:55 -070012#include "SkGraphics.h"
13#include "SkResourceCache.h"
reed3054be12014-12-10 07:24:28 -080014#include "SkSurface.h"
halcanary805ef152014-07-17 06:58:01 -070015
16static const int kCanvasSize = 1;
17static const int kBitmapSize = 16;
18static const int kScale = 8;
19
halcanary1d1795b2014-07-18 09:18:40 -070020static bool is_in_scaled_image_cache(const SkBitmap& orig,
21 SkScalar xScale,
22 SkScalar yScale) {
23 SkBitmap scaled;
humperd73c1692014-08-28 14:27:42 -070024 float roundedImageWidth = SkScalarRoundToScalar(orig.width() * xScale);
yunchao.he90acb8e2015-01-23 17:06:20 -080025 float roundedImageHeight = SkScalarRoundToScalar(orig.height() * yScale);
humperd73c1692014-08-28 14:27:42 -070026 return SkBitmapCache::Find(orig, roundedImageWidth, roundedImageHeight, &scaled);
halcanary1d1795b2014-07-18 09:18:40 -070027}
28
yunchao.he90acb8e2015-01-23 17:06:20 -080029// Draw a scaled bitmap, then return true if it has been cached.
30static bool test_scaled_image_cache_usage() {
reed3054be12014-12-10 07:24:28 -080031 SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(kCanvasSize, kCanvasSize));
32 SkCanvas* canvas = surface->getCanvas();
halcanary805ef152014-07-17 06:58:01 -070033 SkBitmap bitmap;
reed84825042014-09-02 12:50:45 -070034 bitmap.allocN32Pixels(kBitmapSize, kBitmapSize);
halcanary0db38cc2014-07-17 10:17:28 -070035 bitmap.eraseColor(0xFFFFFFFF);
yunchao.he90acb8e2015-01-23 17:06:20 -080036 SkScalar xScale = SkIntToScalar(kScale);
37 SkScalar yScale = xScale / 2;
38 SkScalar xScaledSize = SkIntToScalar(kBitmapSize) * xScale;
39 SkScalar yScaledSize = SkIntToScalar(kBitmapSize) * yScale;
40 canvas->clipRect(SkRect::MakeLTRB(0, 0, xScaledSize, yScaledSize));
halcanary805ef152014-07-17 06:58:01 -070041 SkPaint paint;
reed93a12152015-03-16 10:08:34 -070042 paint.setFilterQuality(kHigh_SkFilterQuality);
halcanary1d1795b2014-07-18 09:18:40 -070043
halcanary805ef152014-07-17 06:58:01 -070044 canvas->drawBitmapRect(bitmap,
yunchao.he90acb8e2015-01-23 17:06:20 -080045 SkRect::MakeLTRB(0, 0, xScaledSize, yScaledSize),
halcanary805ef152014-07-17 06:58:01 -070046 &paint);
halcanary1d1795b2014-07-18 09:18:40 -070047
yunchao.he90acb8e2015-01-23 17:06:20 -080048 return is_in_scaled_image_cache(bitmap, xScale, yScale);
halcanary805ef152014-07-17 06:58:01 -070049}
50
51// http://crbug.com/389439
reed011f39a2014-08-28 13:35:23 -070052DEF_TEST(ResourceCache_SingleAllocationByteLimit, reporter) {
53 size_t originalByteLimit = SkGraphics::GetResourceCacheTotalByteLimit();
halcanary805ef152014-07-17 06:58:01 -070054 size_t originalAllocationLimit =
reed011f39a2014-08-28 13:35:23 -070055 SkGraphics::GetResourceCacheSingleAllocationByteLimit();
halcanary805ef152014-07-17 06:58:01 -070056
57 size_t size = kBitmapSize * kScale * kBitmapSize * kScale
58 * SkColorTypeBytesPerPixel(kN32_SkColorType);
59
reed011f39a2014-08-28 13:35:23 -070060 SkGraphics::SetResourceCacheTotalByteLimit(0); // clear cache
61 SkGraphics::SetResourceCacheTotalByteLimit(2 * size);
62 SkGraphics::SetResourceCacheSingleAllocationByteLimit(0); // No limit
halcanary805ef152014-07-17 06:58:01 -070063
yunchao.he90acb8e2015-01-23 17:06:20 -080064 REPORTER_ASSERT(reporter, test_scaled_image_cache_usage());
halcanary805ef152014-07-17 06:58:01 -070065
reed011f39a2014-08-28 13:35:23 -070066 SkGraphics::SetResourceCacheTotalByteLimit(0); // clear cache
67 SkGraphics::SetResourceCacheTotalByteLimit(2 * size);
68 SkGraphics::SetResourceCacheSingleAllocationByteLimit(size * 2); // big enough
halcanary805ef152014-07-17 06:58:01 -070069
yunchao.he90acb8e2015-01-23 17:06:20 -080070 REPORTER_ASSERT(reporter, test_scaled_image_cache_usage());
halcanary805ef152014-07-17 06:58:01 -070071
reed011f39a2014-08-28 13:35:23 -070072 SkGraphics::SetResourceCacheTotalByteLimit(0); // clear cache
73 SkGraphics::SetResourceCacheTotalByteLimit(2 * size);
74 SkGraphics::SetResourceCacheSingleAllocationByteLimit(size / 2); // too small
halcanary805ef152014-07-17 06:58:01 -070075
yunchao.he90acb8e2015-01-23 17:06:20 -080076 REPORTER_ASSERT(reporter, !test_scaled_image_cache_usage());
halcanary805ef152014-07-17 06:58:01 -070077
reed011f39a2014-08-28 13:35:23 -070078 SkGraphics::SetResourceCacheSingleAllocationByteLimit(originalAllocationLimit);
79 SkGraphics::SetResourceCacheTotalByteLimit(originalByteLimit);
halcanary805ef152014-07-17 06:58:01 -070080}
piotaixr42b0dfe2014-09-03 11:33:13 -070081
reed30ad5302014-09-16 10:39:55 -070082////////////////////////////////////////////////////////////////////////////////////////
mtklein26abcf12014-09-04 10:50:53 -070083
reed30ad5302014-09-16 10:39:55 -070084static void make_bitmap(SkBitmap* bitmap, const SkImageInfo& info, SkBitmap::Allocator* allocator) {
bsalomon49f085d2014-09-05 13:34:00 -070085 if (allocator) {
reed30ad5302014-09-16 10:39:55 -070086 bitmap->setInfo(info);
87 allocator->allocPixelRef(bitmap, 0);
piotaixr42b0dfe2014-09-03 11:33:13 -070088 } else {
reed30ad5302014-09-16 10:39:55 -070089 bitmap->allocPixels(info);
piotaixr42b0dfe2014-09-03 11:33:13 -070090 }
piotaixr42b0dfe2014-09-03 11:33:13 -070091}
92
93// http://skbug.com/2894
94DEF_TEST(BitmapCache_add_rect, reporter) {
reed30ad5302014-09-16 10:39:55 -070095 SkResourceCache::DiscardableFactory factory = SkResourceCache::GetDiscardableFactory();
96 SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator();
97
98 SkAutoTDelete<SkResourceCache> cache;
99 if (factory) {
100 cache.reset(SkNEW_ARGS(SkResourceCache, (factory)));
101 } else {
102 const size_t byteLimit = 100 * 1024;
103 cache.reset(SkNEW_ARGS(SkResourceCache, (byteLimit)));
104 }
105 SkBitmap cachedBitmap;
106 make_bitmap(&cachedBitmap, SkImageInfo::MakeN32Premul(5, 5), allocator);
piotaixr42b0dfe2014-09-03 11:33:13 -0700107 cachedBitmap.setImmutable();
108
reed30ad5302014-09-16 10:39:55 -0700109 SkBitmap bm;
110 SkIRect rect = SkIRect::MakeWH(5, 5);
reed83787d02015-02-25 07:17:11 -0800111 uint32_t cachedID = cachedBitmap.getGenerationID();
112 SkPixelRef* cachedPR = cachedBitmap.pixelRef();
reed30ad5302014-09-16 10:39:55 -0700113
piotaixr42b0dfe2014-09-03 11:33:13 -0700114 // Wrong subset size
reed83787d02015-02-25 07:17:11 -0800115 REPORTER_ASSERT(reporter, !SkBitmapCache::Add(cachedPR, SkIRect::MakeWH(4, 6), cachedBitmap, cache));
116 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedID, rect, &bm, cache));
piotaixr42b0dfe2014-09-03 11:33:13 -0700117 // Wrong offset value
reed83787d02015-02-25 07:17:11 -0800118 REPORTER_ASSERT(reporter, !SkBitmapCache::Add(cachedPR, SkIRect::MakeXYWH(-1, 0, 5, 5), cachedBitmap, cache));
119 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedID, rect, &bm, cache));
piotaixr42b0dfe2014-09-03 11:33:13 -0700120
121 // Should not be in the cache
reed83787d02015-02-25 07:17:11 -0800122 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedID, rect, &bm, cache));
piotaixr42b0dfe2014-09-03 11:33:13 -0700123
reed83787d02015-02-25 07:17:11 -0800124 REPORTER_ASSERT(reporter, SkBitmapCache::Add(cachedPR, rect, cachedBitmap, cache));
piotaixr42b0dfe2014-09-03 11:33:13 -0700125 // Should be in the cache, we just added it
reed83787d02015-02-25 07:17:11 -0800126 REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedID, rect, &bm, cache));
piotaixr42b0dfe2014-09-03 11:33:13 -0700127}
danakj790ffe32014-09-11 10:49:52 -0700128
reed9d93c2e2014-10-08 05:17:12 -0700129#include "SkMipMap.h"
130
131enum LockedState {
132 kNotLocked,
133 kLocked,
134};
135
136enum CachedState {
137 kNotInCache,
138 kInCache,
139};
140
141static void check_data(skiatest::Reporter* reporter, const SkCachedData* data,
142 int refcnt, CachedState cacheState, LockedState lockedState) {
143 REPORTER_ASSERT(reporter, data->testing_only_getRefCnt() == refcnt);
144 REPORTER_ASSERT(reporter, data->testing_only_isInCache() == (kInCache == cacheState));
145 bool isLocked = (data->data() != NULL);
146 REPORTER_ASSERT(reporter, isLocked == (lockedState == kLocked));
147}
148
149static void test_mipmapcache(skiatest::Reporter* reporter, SkResourceCache* cache) {
150 cache->purgeAll();
151
152 SkBitmap src;
153 src.allocN32Pixels(5, 5);
154 src.setImmutable();
155
156 const SkMipMap* mipmap = SkMipMapCache::FindAndRef(src, cache);
157 REPORTER_ASSERT(reporter, NULL == mipmap);
158
159 mipmap = SkMipMapCache::AddAndRef(src, cache);
160 REPORTER_ASSERT(reporter, mipmap);
reed7eeba252015-02-24 13:54:23 -0800161
162 {
163 const SkMipMap* mm = SkMipMapCache::FindAndRef(src, cache);
164 REPORTER_ASSERT(reporter, mm);
165 REPORTER_ASSERT(reporter, mm == mipmap);
166 mm->unref();
167 }
168
reed9d93c2e2014-10-08 05:17:12 -0700169 check_data(reporter, mipmap, 2, kInCache, kLocked);
170
171 mipmap->unref();
172 // tricky, since technically after this I'm no longer an owner, but since the cache is
173 // local, I know it won't get purged behind my back
174 check_data(reporter, mipmap, 1, kInCache, kNotLocked);
175
176 // find us again
177 mipmap = SkMipMapCache::FindAndRef(src, cache);
178 check_data(reporter, mipmap, 2, kInCache, kLocked);
179
180 cache->purgeAll();
181 check_data(reporter, mipmap, 1, kNotInCache, kLocked);
182
183 mipmap->unref();
184}
185
reed7eeba252015-02-24 13:54:23 -0800186static void test_mipmap_notify(skiatest::Reporter* reporter, SkResourceCache* cache) {
187 const int N = 3;
188 SkBitmap src[N];
189 for (int i = 0; i < N; ++i) {
190 src[i].allocN32Pixels(5, 5);
191 src[i].setImmutable();
192 SkMipMapCache::AddAndRef(src[i], cache)->unref();
193 }
194
195 for (int i = 0; i < N; ++i) {
196 const SkMipMap* mipmap = SkMipMapCache::FindAndRef(src[i], cache);
197 if (cache) {
198 // if cache is null, we're working on the global cache, and other threads might purge
199 // it, making this check fragile.
200 REPORTER_ASSERT(reporter, mipmap);
201 }
202 SkSafeUnref(mipmap);
203
204 src[i].reset(); // delete the underlying pixelref, which *should* remove us from the cache
205
206 mipmap = SkMipMapCache::FindAndRef(src[i], cache);
207 REPORTER_ASSERT(reporter, !mipmap);
208 }
209}
210
211static void test_bitmap_notify(skiatest::Reporter* reporter, SkResourceCache* cache) {
212 const SkIRect subset = SkIRect::MakeWH(5, 5);
213 const int N = 3;
214 SkBitmap src[N], dst[N];
215 for (int i = 0; i < N; ++i) {
216 src[i].allocN32Pixels(5, 5);
217 src[i].setImmutable();
218 dst[i].allocN32Pixels(5, 5);
219 dst[i].setImmutable();
reed83787d02015-02-25 07:17:11 -0800220 SkBitmapCache::Add(src[i].pixelRef(), subset, dst[i], cache);
reed7eeba252015-02-24 13:54:23 -0800221 }
222
223 for (int i = 0; i < N; ++i) {
224 const uint32_t genID = src[i].getGenerationID();
225 SkBitmap result;
226 bool found = SkBitmapCache::Find(genID, subset, &result, cache);
227 if (cache) {
228 // if cache is null, we're working on the global cache, and other threads might purge
229 // it, making this check fragile.
230 REPORTER_ASSERT(reporter, found);
231 }
232
233 src[i].reset(); // delete the underlying pixelref, which *should* remove us from the cache
234
235 found = SkBitmapCache::Find(genID, subset, &result, cache);
236 REPORTER_ASSERT(reporter, !found);
237 }
238}
239
danakj790ffe32014-09-11 10:49:52 -0700240DEF_TEST(BitmapCache_discarded_bitmap, reporter) {
reed30ad5302014-09-16 10:39:55 -0700241 SkResourceCache::DiscardableFactory factory = SkResourceCache::GetDiscardableFactory();
242 SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator();
243
244 SkAutoTDelete<SkResourceCache> cache;
245 if (factory) {
246 cache.reset(SkNEW_ARGS(SkResourceCache, (factory)));
247 } else {
248 const size_t byteLimit = 100 * 1024;
249 cache.reset(SkNEW_ARGS(SkResourceCache, (byteLimit)));
250 }
251 SkBitmap cachedBitmap;
252 make_bitmap(&cachedBitmap, SkImageInfo::MakeN32Premul(5, 5), allocator);
danakj790ffe32014-09-11 10:49:52 -0700253 cachedBitmap.setImmutable();
254 cachedBitmap.unlockPixels();
255
reed30ad5302014-09-16 10:39:55 -0700256 SkBitmap bm;
257 SkIRect rect = SkIRect::MakeWH(5, 5);
258
danakj790ffe32014-09-11 10:49:52 -0700259 // Add a bitmap to the cache.
reed83787d02015-02-25 07:17:11 -0800260 REPORTER_ASSERT(reporter, SkBitmapCache::Add(cachedBitmap.pixelRef(), rect, cachedBitmap, cache));
reed30ad5302014-09-16 10:39:55 -0700261 REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
danakj790ffe32014-09-11 10:49:52 -0700262
263 // Finding more than once works fine.
reed30ad5302014-09-16 10:39:55 -0700264 REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
danakj790ffe32014-09-11 10:49:52 -0700265 bm.unlockPixels();
266
267 // Drop the pixels in the bitmap.
reed30ad5302014-09-16 10:39:55 -0700268 if (factory) {
269 REPORTER_ASSERT(reporter, SkGetGlobalDiscardableMemoryPool()->getRAMUsed() > 0);
270 SkGetGlobalDiscardableMemoryPool()->dumpPool();
271 REPORTER_ASSERT(reporter, SkGetGlobalDiscardableMemoryPool()->getRAMUsed() == 0);
danakj790ffe32014-09-11 10:49:52 -0700272
reed30ad5302014-09-16 10:39:55 -0700273 // The bitmap is not in the cache since it has been dropped.
274 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
275 }
danakj790ffe32014-09-11 10:49:52 -0700276
reed30ad5302014-09-16 10:39:55 -0700277 make_bitmap(&cachedBitmap, SkImageInfo::MakeN32Premul(5, 5), allocator);
danakj790ffe32014-09-11 10:49:52 -0700278 cachedBitmap.setImmutable();
279 cachedBitmap.unlockPixels();
280
281 // We can add the bitmap back to the cache and find it again.
reed83787d02015-02-25 07:17:11 -0800282 REPORTER_ASSERT(reporter, SkBitmapCache::Add(cachedBitmap.pixelRef(), rect, cachedBitmap, cache));
reed30ad5302014-09-16 10:39:55 -0700283 REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
reed9d93c2e2014-10-08 05:17:12 -0700284
285 test_mipmapcache(reporter, cache);
reed7eeba252015-02-24 13:54:23 -0800286 test_bitmap_notify(reporter, cache);
287 test_mipmap_notify(reporter, cache);
danakj790ffe32014-09-11 10:49:52 -0700288}