b6e1eb7c890709087676fa280f8e3f9cddbb6cd0
[platform/upstream/libSkiaSharp.git] / tests / ResourceCacheTest.cpp
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 #if SK_SUPPORT_GPU
9
10 #include "GrContext.h"
11 #include "GrContextFactory.h"
12 #include "GrGpu.h"
13 #include "GrGpuResourceCacheAccess.h"
14 #include "GrGpuResourcePriv.h"
15 #include "GrRenderTarget.h"
16 #include "GrRenderTargetPriv.h"
17 #include "GrResourceCache.h"
18 #include "SkCanvas.h"
19 #include "SkGr.h"
20 #include "SkMessageBus.h"
21 #include "SkSurface.h"
22 #include "Test.h"
23
24 static const int gWidth = 640;
25 static const int gHeight = 480;
26
27 ////////////////////////////////////////////////////////////////////////////////
28 static void test_cache(skiatest::Reporter* reporter, GrContext* context, SkCanvas* canvas) {
29     const SkIRect size = SkIRect::MakeWH(gWidth, gHeight);
30
31     SkBitmap src;
32     src.allocN32Pixels(size.width(), size.height());
33     src.eraseColor(SK_ColorBLACK);
34     size_t srcSize = src.getSize();
35
36     size_t initialCacheSize;
37     context->getResourceCacheUsage(NULL, &initialCacheSize);
38
39     int oldMaxNum;
40     size_t oldMaxBytes;
41     context->getResourceCacheLimits(&oldMaxNum, &oldMaxBytes);
42
43     // Set the cache limits so we can fit 10 "src" images and the
44     // max number of textures doesn't matter
45     size_t maxCacheSize = initialCacheSize + 10*srcSize;
46     context->setResourceCacheLimits(1000, maxCacheSize);
47
48     SkBitmap readback;
49     readback.allocN32Pixels(size.width(), size.height());
50
51     for (int i = 0; i < 100; ++i) {
52         canvas->drawBitmap(src, 0, 0);
53         canvas->readPixels(size, &readback);
54
55         // "modify" the src texture
56         src.notifyPixelsChanged();
57
58         size_t curCacheSize;
59         context->getResourceCacheUsage(NULL, &curCacheSize);
60
61         // we should never go over the size limit
62         REPORTER_ASSERT(reporter, curCacheSize <= maxCacheSize);
63     }
64
65     context->setResourceCacheLimits(oldMaxNum, oldMaxBytes);
66 }
67
68 static void test_stencil_buffers(skiatest::Reporter* reporter, GrContext* context) {
69     GrSurfaceDesc smallDesc;
70     smallDesc.fFlags = kRenderTarget_GrSurfaceFlag;
71     smallDesc.fConfig = kSkia8888_GrPixelConfig;
72     smallDesc.fWidth = 4;
73     smallDesc.fHeight = 4;
74     smallDesc.fSampleCnt = 0;
75
76     // Test that two budgeted RTs with the same desc share a stencil buffer.
77     SkAutoTUnref<GrTexture> smallRT0(context->createTexture(smallDesc, true));
78     if (smallRT0 && smallRT0->asRenderTarget()) {
79         smallRT0->asRenderTarget()->renderTargetPriv().attachStencilBuffer();
80     }
81
82     SkAutoTUnref<GrTexture> smallRT1(context->createTexture(smallDesc, true));
83     if (smallRT1 && smallRT1->asRenderTarget()) {
84         smallRT1->asRenderTarget()->renderTargetPriv().attachStencilBuffer();
85     }
86
87     REPORTER_ASSERT(reporter, smallRT0 && smallRT1 &&
88                               smallRT0->asRenderTarget() && smallRT1->asRenderTarget() &&
89                               smallRT0->asRenderTarget()->renderTargetPriv().getStencilBuffer() ==
90                               smallRT1->asRenderTarget()->renderTargetPriv().getStencilBuffer());
91
92     // An unbudgeted RT with the same desc should also share.
93     SkAutoTUnref<GrTexture> smallRT2(context->createTexture(smallDesc, false));
94     if (smallRT2 && smallRT2->asRenderTarget()) {
95         smallRT2->asRenderTarget()->renderTargetPriv().attachStencilBuffer();
96     }
97     REPORTER_ASSERT(reporter, smallRT0 && smallRT2 &&
98                               smallRT0->asRenderTarget() && smallRT2->asRenderTarget() &&
99                               smallRT0->asRenderTarget()->renderTargetPriv().getStencilBuffer() ==
100                               smallRT2->asRenderTarget()->renderTargetPriv().getStencilBuffer());
101
102     // An RT with a much larger size should not share.
103     GrSurfaceDesc bigDesc;
104     bigDesc.fFlags = kRenderTarget_GrSurfaceFlag;
105     bigDesc.fConfig = kSkia8888_GrPixelConfig;
106     bigDesc.fWidth = 400;
107     bigDesc.fHeight = 200;
108     bigDesc.fSampleCnt = 0;
109     SkAutoTUnref<GrTexture> bigRT(context->createTexture(bigDesc, false));
110     if (bigRT && bigRT->asRenderTarget()) {
111         bigRT->asRenderTarget()->renderTargetPriv().attachStencilBuffer();
112     }
113     REPORTER_ASSERT(reporter, smallRT0 && bigRT &&
114                               smallRT0->asRenderTarget() && bigRT->asRenderTarget() &&
115                               smallRT0->asRenderTarget()->renderTargetPriv().getStencilBuffer() !=
116                               bigRT->asRenderTarget()->renderTargetPriv().getStencilBuffer());
117
118     if (context->getMaxSampleCount() >= 4) {
119         // An RT with a different sample count should not share. 
120         GrSurfaceDesc smallMSAADesc = smallDesc;
121         smallMSAADesc.fSampleCnt = 4;
122         SkAutoTUnref<GrTexture> smallMSAART0(context->createTexture(smallMSAADesc, false));
123         if (smallMSAART0 && smallMSAART0->asRenderTarget()) {
124             smallMSAART0->asRenderTarget()->renderTargetPriv().attachStencilBuffer();
125         }
126 #ifdef SK_BUILD_FOR_ANDROID
127         if (!smallMSAART0) {
128             // The nexus player seems to fail to create MSAA textures.
129             return;
130         }
131 #endif
132         REPORTER_ASSERT(reporter,
133                         smallRT0 && smallMSAART0 &&
134                         smallRT0->asRenderTarget() && smallMSAART0->asRenderTarget() &&
135                         smallRT0->asRenderTarget()->renderTargetPriv().getStencilBuffer() !=
136                         smallMSAART0->asRenderTarget()->renderTargetPriv().getStencilBuffer());
137         // A second MSAA RT should share with the first MSAA RT.
138         SkAutoTUnref<GrTexture> smallMSAART1(context->createTexture(smallMSAADesc, false));
139         if (smallMSAART1 && smallMSAART1->asRenderTarget()) {
140             smallMSAART1->asRenderTarget()->renderTargetPriv().attachStencilBuffer();
141         }
142         REPORTER_ASSERT(reporter,
143                         smallMSAART0 && smallMSAART1 &&
144                         smallMSAART0->asRenderTarget() &&
145                         smallMSAART1->asRenderTarget() &&
146                         smallMSAART0->asRenderTarget()->renderTargetPriv().getStencilBuffer() ==
147                         smallMSAART1->asRenderTarget()->renderTargetPriv().getStencilBuffer());
148         // But not one with a larger sample count should not. (Also check that the request for 4
149         // samples didn't get rounded up to >= 8 or else they could share.).
150         if (context->getMaxSampleCount() >= 8 && smallMSAART0 && smallMSAART0->asRenderTarget() &&
151             smallMSAART0->asRenderTarget()->numSamples() < 8) {
152             smallMSAADesc.fSampleCnt = 8;
153             smallMSAART1.reset(context->createTexture(smallMSAADesc, false));
154             SkAutoTUnref<GrTexture> smallMSAART1(context->createTexture(smallMSAADesc, false));
155             if (smallMSAART1 && smallMSAART1->asRenderTarget()) {
156                 smallMSAART1->asRenderTarget()->renderTargetPriv().attachStencilBuffer();
157             }
158             REPORTER_ASSERT(reporter,
159                             smallMSAART0 && smallMSAART1 &&
160                             smallMSAART0->asRenderTarget() &&
161                             smallMSAART1->asRenderTarget() &&
162                             smallMSAART0->asRenderTarget()->renderTargetPriv().getStencilBuffer() !=
163                             smallMSAART1->asRenderTarget()->renderTargetPriv().getStencilBuffer());
164         }
165     }
166 }
167
168 class TestResource : public GrGpuResource {
169     static const size_t kDefaultSize = 100;
170     enum ScratchConstructor { kScratchConstructor };
171 public:
172     SK_DECLARE_INST_COUNT(TestResource);
173     /** Property that distinctly categorizes the resource.
174      * For example, textures have width, height, ... */
175     enum SimulatedProperty { kA_SimulatedProperty, kB_SimulatedProperty };
176
177     TestResource(GrGpu* gpu, size_t size, GrGpuResource::LifeCycle lifeCycle)
178         : INHERITED(gpu, lifeCycle)
179         , fToDelete(NULL)
180         , fSize(size)
181         , fProperty(kA_SimulatedProperty) {
182         ++fNumAlive;
183         this->registerWithCache();
184     }
185
186     TestResource(GrGpu* gpu, GrGpuResource::LifeCycle lifeCycle)
187         : INHERITED(gpu, lifeCycle)
188         , fToDelete(NULL)
189         , fSize(kDefaultSize)
190         , fProperty(kA_SimulatedProperty) {
191         ++fNumAlive;
192         this->registerWithCache();
193     }
194
195     TestResource(GrGpu* gpu)
196         : INHERITED(gpu, kCached_LifeCycle)
197         , fToDelete(NULL)
198         , fSize(kDefaultSize)
199         , fProperty(kA_SimulatedProperty) {
200         ++fNumAlive;
201         this->registerWithCache();
202     }
203
204     static TestResource* CreateScratch(GrGpu* gpu, SimulatedProperty property, bool cached = true) {
205         return SkNEW_ARGS(TestResource, (gpu, property, cached, kScratchConstructor));
206     }
207
208     ~TestResource() {
209         --fNumAlive;
210         SkSafeUnref(fToDelete);
211     }
212
213     void setSize(size_t size) {
214         fSize = size;
215         this->didChangeGpuMemorySize();
216     }
217
218     static int NumAlive() { return fNumAlive; }
219
220     void setUnrefWhenDestroyed(TestResource* resource) {
221         SkRefCnt_SafeAssign(fToDelete, resource);
222     }
223
224     static void ComputeScratchKey(SimulatedProperty property, GrScratchKey* key) {
225         static GrScratchKey::ResourceType t = GrScratchKey::GenerateResourceType();
226         GrScratchKey::Builder builder(key, t, kScratchKeyFieldCnt);
227         for (int i = 0; i < kScratchKeyFieldCnt; ++i) {
228             builder[i] = static_cast<uint32_t>(i + property);
229         }
230     }
231
232     static size_t ExpectedScratchKeySize() {
233         return sizeof(uint32_t) * (kScratchKeyFieldCnt + GrScratchKey::kMetaDataCnt);
234     }
235
236 private:
237     static const int kScratchKeyFieldCnt = 6;
238
239     TestResource(GrGpu* gpu, SimulatedProperty property, bool cached, ScratchConstructor)
240         : INHERITED(gpu, cached ? kCached_LifeCycle : kUncached_LifeCycle)
241         , fToDelete(NULL)
242         , fSize(kDefaultSize)
243         , fProperty(property) {
244         GrScratchKey scratchKey;
245         ComputeScratchKey(fProperty, &scratchKey);
246         this->setScratchKey(scratchKey);
247         ++fNumAlive;
248         this->registerWithCache();
249     }
250
251     size_t onGpuMemorySize() const SK_OVERRIDE { return fSize; }
252
253     TestResource* fToDelete;
254     size_t fSize;
255     static int fNumAlive;
256     SimulatedProperty fProperty;
257     typedef GrGpuResource INHERITED;
258 };
259 int TestResource::fNumAlive = 0;
260
261 class Mock {
262 public:
263     Mock(int maxCnt, size_t maxBytes) {
264         fContext.reset(GrContext::CreateMockContext());
265         SkASSERT(fContext);
266         fContext->setResourceCacheLimits(maxCnt, maxBytes);
267         GrResourceCache* cache = fContext->getResourceCache();
268         cache->purgeAllUnlocked();
269         SkASSERT(0 == cache->getResourceCount() && 0 == cache->getResourceBytes());
270     }
271
272     GrResourceCache* cache() { return fContext->getResourceCache(); }
273
274     GrContext* context() { return fContext; }
275
276 private:
277     SkAutoTUnref<GrContext> fContext;
278 };
279
280 static void test_no_key(skiatest::Reporter* reporter) {
281     Mock mock(10, 30000);
282     GrContext* context = mock.context();
283     GrResourceCache* cache = mock.cache();
284
285     // Create a bunch of resources with no keys
286     TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu()));
287     TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu()));
288     TestResource* c = SkNEW_ARGS(TestResource, (context->getGpu()));
289     TestResource* d = SkNEW_ARGS(TestResource, (context->getGpu()));
290     a->setSize(11);
291     b->setSize(12);
292     c->setSize(13);
293     d->setSize(14);
294
295     REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
296     REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
297     REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() +
298                               d->gpuMemorySize() == cache->getResourceBytes());
299
300     // Should be safe to purge without deleting the resources since we still have refs.
301     cache->purgeAllUnlocked();
302     REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
303
304     // Since the resources have neither unique nor scratch keys, delete immediately upon unref.
305
306     a->unref();
307     REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive());
308     REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
309     REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() + d->gpuMemorySize() ==
310                               cache->getResourceBytes());
311
312     c->unref();
313     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
314     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
315     REPORTER_ASSERT(reporter, b->gpuMemorySize() + d->gpuMemorySize() ==
316                               cache->getResourceBytes());
317
318     d->unref();
319     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
320     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
321     REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes());
322
323     b->unref();
324     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
325     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
326     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
327 }
328
329 // Each integer passed as a template param creates a new domain.
330 template <int> static void make_unique_key(GrUniqueKey* key, int data) {
331     static GrUniqueKey::Domain d = GrUniqueKey::GenerateDomain();
332     GrUniqueKey::Builder builder(key, d, 1);
333     builder[0] = data;
334 }
335
336 static void test_budgeting(skiatest::Reporter* reporter) {
337     Mock mock(10, 300);
338     GrContext* context = mock.context();
339     GrResourceCache* cache = mock.cache();
340
341     GrUniqueKey uniqueKey;
342     make_unique_key<0>(&uniqueKey, 0);
343
344     // Create a scratch, a unique, and a wrapped resource
345     TestResource* scratch =
346             TestResource::CreateScratch(context->getGpu(), TestResource::kB_SimulatedProperty);
347     scratch->setSize(10);
348     TestResource* unique = SkNEW_ARGS(TestResource, (context->getGpu()));
349     unique->setSize(11);
350     unique->resourcePriv().setUniqueKey(uniqueKey);
351     TestResource* wrapped = SkNEW_ARGS(TestResource,
352                                        (context->getGpu(), GrGpuResource::kWrapped_LifeCycle));
353     wrapped->setSize(12);
354     TestResource* unbudgeted = SkNEW_ARGS(TestResource,
355                                           (context->getGpu(), GrGpuResource::kUncached_LifeCycle));
356     unbudgeted->setSize(13);
357
358     // Make sure we can't add a unique key to the wrapped resource
359     GrUniqueKey uniqueKey2;
360     make_unique_key<0>(&uniqueKey2, 1);
361     wrapped->resourcePriv().setUniqueKey(uniqueKey2);
362     REPORTER_ASSERT(reporter, NULL == cache->findAndRefUniqueResource(uniqueKey2));
363
364     // Make sure sizes are as we expect
365     REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
366     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() +
367                               wrapped->gpuMemorySize() + unbudgeted->gpuMemorySize() ==
368                               cache->getResourceBytes());
369     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
370     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() ==
371                               cache->getBudgetedResourceBytes());
372
373     // Our refs mean that the resources are non purgeable.
374     cache->purgeAllUnlocked();
375     REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
376     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() +
377                               wrapped->gpuMemorySize() + unbudgeted->gpuMemorySize() ==
378                               cache->getResourceBytes());
379     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
380     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() ==
381                               cache->getBudgetedResourceBytes());
382
383     // Unreffing the wrapped resource should free it right away.
384     wrapped->unref();
385     REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
386     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() +
387                               unbudgeted->gpuMemorySize() == cache->getResourceBytes());
388
389     // Now try freeing the budgeted resources first
390     wrapped = SkNEW_ARGS(TestResource, (context->getGpu(), GrGpuResource::kWrapped_LifeCycle));
391     scratch->setSize(12);
392     unique->unref();
393     cache->purgeAllUnlocked();
394     REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
395     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + wrapped->gpuMemorySize() +
396                               unbudgeted->gpuMemorySize() == cache->getResourceBytes());
397     REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
398     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() == cache->getBudgetedResourceBytes());
399
400     scratch->unref();
401     cache->purgeAllUnlocked();
402     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
403     REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() + wrapped->gpuMemorySize() ==
404                               cache->getResourceBytes());
405     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
406     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
407
408     wrapped->unref();
409     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
410     REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() == cache->getResourceBytes());
411     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
412     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
413
414     unbudgeted->unref();
415     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
416     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
417     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
418     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
419 }
420
421 static void test_unbudgeted(skiatest::Reporter* reporter) {
422     Mock mock(10, 30000);
423     GrContext* context = mock.context();
424     GrResourceCache* cache = mock.cache();
425
426     GrUniqueKey uniqueKey;
427     make_unique_key<0>(&uniqueKey, 0);
428
429     TestResource* scratch;
430     TestResource* unique;
431     TestResource* wrapped;
432     TestResource* unbudgeted;
433
434     // A large uncached or wrapped resource shouldn't evict anything.
435     scratch = TestResource::CreateScratch(context->getGpu(), TestResource::kB_SimulatedProperty);
436     scratch->setSize(10);
437     scratch->unref();
438     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
439     REPORTER_ASSERT(reporter, 10 == cache->getResourceBytes());
440     REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
441     REPORTER_ASSERT(reporter, 10 == cache->getBudgetedResourceBytes());
442
443     unique = SkNEW_ARGS(TestResource, (context->getGpu()));
444     unique->setSize(11);
445     unique->resourcePriv().setUniqueKey(uniqueKey);
446     unique->unref();
447     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
448     REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes());
449     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
450     REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
451
452     size_t large = 2 * cache->getResourceBytes();
453     unbudgeted = SkNEW_ARGS(TestResource,
454                             (context->getGpu(), large, GrGpuResource::kUncached_LifeCycle));
455     REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
456     REPORTER_ASSERT(reporter, 21 + large == cache->getResourceBytes());
457     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
458     REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
459
460     unbudgeted->unref();
461     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
462     REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes());
463     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
464     REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
465
466     wrapped = SkNEW_ARGS(TestResource,
467                          (context->getGpu(), large, GrGpuResource::kWrapped_LifeCycle));
468     REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
469     REPORTER_ASSERT(reporter, 21 + large == cache->getResourceBytes());
470     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
471     REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
472
473     wrapped->unref();
474     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
475     REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes());
476     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
477     REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
478
479     cache->purgeAllUnlocked();
480     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
481     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
482     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
483     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
484 }
485
486 // This method can't be static because it needs to friended in GrGpuResource::CacheAccess.
487 void test_unbudgeted_to_scratch(skiatest::Reporter* reporter);
488 /*static*/ void test_unbudgeted_to_scratch(skiatest::Reporter* reporter) {
489     Mock mock(10, 300);
490     GrContext* context = mock.context();
491     GrResourceCache* cache = mock.cache();
492
493     TestResource* resource =
494         TestResource::CreateScratch(context->getGpu(), TestResource::kA_SimulatedProperty, false);
495     GrScratchKey key;
496     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &key);
497
498     size_t size = resource->gpuMemorySize();
499     for (int i = 0; i < 2; ++i) {
500         // Since this resource is unbudgeted, it should not be reachable as scratch.
501         REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key);
502         REPORTER_ASSERT(reporter, !resource->cacheAccess().isScratch());
503         REPORTER_ASSERT(reporter, !resource->resourcePriv().isBudgeted());
504         REPORTER_ASSERT(reporter, NULL == cache->findAndRefScratchResource(key));
505         REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
506         REPORTER_ASSERT(reporter, size == cache->getResourceBytes());
507         REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
508         REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
509
510         // Once it is unrefed, it should become available as scratch.
511         resource->unref();
512         REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
513         REPORTER_ASSERT(reporter, size == cache->getResourceBytes());
514         REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
515         REPORTER_ASSERT(reporter, size == cache->getBudgetedResourceBytes());
516         resource = static_cast<TestResource*>(cache->findAndRefScratchResource(key));
517         REPORTER_ASSERT(reporter, resource);
518         REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key);
519         REPORTER_ASSERT(reporter, resource->cacheAccess().isScratch());
520         REPORTER_ASSERT(reporter, resource->resourcePriv().isBudgeted());
521
522         if (0 == i) {
523             // If made unbudgeted, it should return to original state: ref'ed and unbudgeted. Try 
524             // the above tests again.
525             resource->resourcePriv().makeUnbudgeted();
526         } else {
527             // After the second time around, try removing the scratch key
528             resource->resourcePriv().removeScratchKey();
529             REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
530             REPORTER_ASSERT(reporter, size == cache->getResourceBytes());
531             REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
532             REPORTER_ASSERT(reporter, size == cache->getBudgetedResourceBytes());
533             REPORTER_ASSERT(reporter, !resource->resourcePriv().getScratchKey().isValid());
534             REPORTER_ASSERT(reporter, !resource->cacheAccess().isScratch());
535             REPORTER_ASSERT(reporter, resource->resourcePriv().isBudgeted());
536
537             // now when it is unrefed it should die since it has no key.
538             resource->unref();
539             REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
540             REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
541             REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
542             REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
543         }
544     }
545 }
546
547 static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
548     Mock mock(5, 30000);
549     GrContext* context = mock.context();
550     GrResourceCache* cache = mock.cache();
551
552     // Create two resources that have the same scratch key.
553     TestResource* a = TestResource::CreateScratch(context->getGpu(),
554                                                   TestResource::kB_SimulatedProperty);
555     TestResource* b = TestResource::CreateScratch(context->getGpu(),
556                                                   TestResource::kB_SimulatedProperty);
557     a->setSize(11);
558     b->setSize(12);
559     GrScratchKey scratchKey1;
560     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey1);
561     // Check for negative case consistency. (leaks upon test failure.)
562     REPORTER_ASSERT(reporter, NULL == cache->findAndRefScratchResource(scratchKey1));
563
564     GrScratchKey scratchKey;
565     TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey);
566
567     // Scratch resources are registered with GrResourceCache just by existing. There are 2.
568     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
569     SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));)
570     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
571     REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() ==
572                               cache->getResourceBytes());
573
574     // Our refs mean that the resources are non purgeable.
575     cache->purgeAllUnlocked();
576     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
577     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
578
579     // Unref but don't purge
580     a->unref();
581     b->unref();
582     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
583     SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));)
584
585     // Purge again. This time resources should be purgeable.
586     cache->purgeAllUnlocked();
587     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
588     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
589     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
590 }
591
592 static void test_remove_scratch_key(skiatest::Reporter* reporter) {
593     Mock mock(5, 30000);
594     GrContext* context = mock.context();
595     GrResourceCache* cache = mock.cache();
596
597     // Create two resources that have the same scratch key.
598     TestResource* a = TestResource::CreateScratch(context->getGpu(),
599                                                   TestResource::kB_SimulatedProperty);
600     TestResource* b = TestResource::CreateScratch(context->getGpu(),
601                                                   TestResource::kB_SimulatedProperty);
602     a->unref();
603     b->unref();
604
605     GrScratchKey scratchKey;
606     // Ensure that scratch key lookup is correct for negative case.
607     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey);
608     // (following leaks upon test failure).
609     REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey) == NULL);
610
611     // Scratch resources are registered with GrResourceCache just by existing. There are 2.
612     TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey);
613     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
614     SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));)
615     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
616
617     // Find the first resource and remove its scratch key
618     GrGpuResource* find;
619     find = cache->findAndRefScratchResource(scratchKey);
620     find->resourcePriv().removeScratchKey();
621     // It's still alive, but not cached by scratch key anymore
622     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
623     SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->countScratchEntriesForKey(scratchKey));)
624     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
625
626     // The cache should immediately delete it when it's unrefed since it isn't accessible.
627     find->unref();
628     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
629     SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->countScratchEntriesForKey(scratchKey));)
630     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
631
632     // Repeat for the second resource.
633     find = cache->findAndRefScratchResource(scratchKey);
634     find->resourcePriv().removeScratchKey();
635     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
636     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
637     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
638
639     // Should be able to call this multiple times with no problem.
640     find->resourcePriv().removeScratchKey();
641     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
642     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
643     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
644
645     find->unref();
646     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
647     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
648     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
649 }
650
651 static void test_scratch_key_consistency(skiatest::Reporter* reporter) {
652     Mock mock(5, 30000);
653     GrContext* context = mock.context();
654     GrResourceCache* cache = mock.cache();
655
656     // Create two resources that have the same scratch key.
657     TestResource* a = TestResource::CreateScratch(context->getGpu(),
658                                                   TestResource::kB_SimulatedProperty);
659     TestResource* b = TestResource::CreateScratch(context->getGpu(),
660                                                   TestResource::kB_SimulatedProperty);
661     a->unref();
662     b->unref();
663
664     GrScratchKey scratchKey;
665     // Ensure that scratch key comparison and assignment is consistent.
666     GrScratchKey scratchKey1;
667     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey1);
668     GrScratchKey scratchKey2;
669     TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey2);
670     REPORTER_ASSERT(reporter, scratchKey1.size() == TestResource::ExpectedScratchKeySize());
671     REPORTER_ASSERT(reporter, scratchKey1 != scratchKey2);
672     REPORTER_ASSERT(reporter, scratchKey2 != scratchKey1);
673     scratchKey = scratchKey1;
674     REPORTER_ASSERT(reporter, scratchKey.size() == TestResource::ExpectedScratchKeySize());
675     REPORTER_ASSERT(reporter, scratchKey1 == scratchKey);
676     REPORTER_ASSERT(reporter, scratchKey == scratchKey1);
677     REPORTER_ASSERT(reporter, scratchKey2 != scratchKey);
678     REPORTER_ASSERT(reporter, scratchKey != scratchKey2);
679     scratchKey = scratchKey2;
680     REPORTER_ASSERT(reporter, scratchKey.size() == TestResource::ExpectedScratchKeySize());
681     REPORTER_ASSERT(reporter, scratchKey1 != scratchKey);
682     REPORTER_ASSERT(reporter, scratchKey != scratchKey1);
683     REPORTER_ASSERT(reporter, scratchKey2 == scratchKey);
684     REPORTER_ASSERT(reporter, scratchKey == scratchKey2);
685
686     // Ensure that scratch key lookup is correct for negative case.
687     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey);
688     // (following leaks upon test failure).
689     REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey) == NULL);
690
691     // Find the first resource with a scratch key and a copy of a scratch key.
692     TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey);
693     GrGpuResource* find = cache->findAndRefScratchResource(scratchKey);
694     REPORTER_ASSERT(reporter, find != NULL);
695     find->unref();
696
697     scratchKey2 = scratchKey;
698     find = cache->findAndRefScratchResource(scratchKey2);
699     REPORTER_ASSERT(reporter, find != NULL);
700     REPORTER_ASSERT(reporter, find == a || find == b);
701
702     GrGpuResource* find2 = cache->findAndRefScratchResource(scratchKey2);
703     REPORTER_ASSERT(reporter, find2 != NULL);
704     REPORTER_ASSERT(reporter, find2 == a || find2 == b);
705     REPORTER_ASSERT(reporter, find2 != find);
706     find2->unref();
707     find->unref();
708 }
709
710 static void test_duplicate_unique_key(skiatest::Reporter* reporter) {
711     Mock mock(5, 30000);
712     GrContext* context = mock.context();
713     GrResourceCache* cache = mock.cache();
714
715     GrUniqueKey key;
716     make_unique_key<0>(&key, 0);
717     
718     // Create two resources that we will attempt to register with the same unique key.
719     TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu()));
720     a->setSize(11);
721     
722     // Set key on resource a.
723     a->resourcePriv().setUniqueKey(key);
724     REPORTER_ASSERT(reporter, a == cache->findAndRefUniqueResource(key));
725     a->unref();
726
727     // Make sure that redundantly setting a's key works.
728     a->resourcePriv().setUniqueKey(key);
729     REPORTER_ASSERT(reporter, a == cache->findAndRefUniqueResource(key));
730     a->unref();
731     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
732     REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache->getResourceBytes());
733     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
734
735     // Create resource b and set the same key. It should replace a's unique key cache entry.
736     TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu()));
737     b->setSize(12);
738     b->resourcePriv().setUniqueKey(key);
739     REPORTER_ASSERT(reporter, b == cache->findAndRefUniqueResource(key));
740     b->unref();
741
742     // Still have two resources because a is still reffed.
743     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
744     REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() == cache->getResourceBytes());
745     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
746
747     a->unref();
748     // Now a should be gone.
749     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
750     REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes());
751     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
752
753     // Now replace b with c, but make sure c can start with one unique key and change it to b's key.
754     // Also make b be unreffed when replacement occurs.
755     b->unref();
756     TestResource* c = SkNEW_ARGS(TestResource, (context->getGpu()));
757     GrUniqueKey differentKey;
758     make_unique_key<0>(&differentKey, 1);
759     c->setSize(13);
760     c->resourcePriv().setUniqueKey(differentKey);
761     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
762     REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() == cache->getResourceBytes());
763     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
764     // c replaces b and b should be immediately purged.
765     c->resourcePriv().setUniqueKey(key);
766     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
767     REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes());
768     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
769
770     // c shouldn't be purged because it is ref'ed.
771     cache->purgeAllUnlocked();
772     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
773     REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes());
774     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
775
776     // Drop the ref on c, it should be kept alive because it has a unique key.
777     c->unref();
778     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
779     REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes());
780     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
781
782     // Verify that we can find c, then remove its unique key. It should get purged immediately.
783     REPORTER_ASSERT(reporter, c == cache->findAndRefUniqueResource(key));
784     c->resourcePriv().removeUniqueKey();
785     c->unref();
786     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
787     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
788     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
789 }
790
791 static void test_purge_invalidated(skiatest::Reporter* reporter) {
792     Mock mock(5, 30000);
793     GrContext* context = mock.context();
794     GrResourceCache* cache = mock.cache();
795
796     GrUniqueKey key1, key2, key3;
797     make_unique_key<0>(&key1, 1);
798     make_unique_key<0>(&key2, 2);
799     make_unique_key<0>(&key3, 3);
800     
801     // Add three resources to the cache. Only c is usable as scratch.
802     TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu()));
803     TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu()));
804     TestResource* c = TestResource::CreateScratch(context->getGpu(),
805                                                   TestResource::kA_SimulatedProperty);
806     a->resourcePriv().setUniqueKey(key1);
807     b->resourcePriv().setUniqueKey(key2);
808     c->resourcePriv().setUniqueKey(key3);
809     a->unref();
810     // hold b until *after* the message is sent.
811     c->unref();
812
813     REPORTER_ASSERT(reporter, cache->hasUniqueKey(key1));
814     REPORTER_ASSERT(reporter, cache->hasUniqueKey(key2));
815     REPORTER_ASSERT(reporter, cache->hasUniqueKey(key3));
816     REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive());
817
818     typedef GrUniqueKeyInvalidatedMessage Msg;
819     typedef SkMessageBus<GrUniqueKeyInvalidatedMessage> Bus;
820
821     // Invalidate two of the three, they should be purged and no longer accessible via their keys.
822     Bus::Post(Msg(key1));
823     Bus::Post(Msg(key2));
824     cache->purgeAsNeeded();
825     // a should be deleted now, but we still have a ref on b.
826     REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1));
827     REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key2));
828     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
829     REPORTER_ASSERT(reporter, cache->hasUniqueKey(key3));
830
831     // Invalidate the third.
832     Bus::Post(Msg(key3));
833     cache->purgeAsNeeded();
834     // we still have a ref on b, c should be recycled as scratch.
835     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
836     REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key3));
837
838     // make b purgeable. It should be immediately deleted since it has no key.
839     b->unref();
840     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
841
842     // Make sure we actually get to c via it's scratch key, before we say goodbye.
843     GrScratchKey scratchKey;
844     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey);
845     GrGpuResource* scratch = cache->findAndRefScratchResource(scratchKey);
846     REPORTER_ASSERT(reporter, scratch == c);
847     SkSafeUnref(scratch);
848
849     // Get rid of c.
850     cache->purgeAllUnlocked();
851     scratch = cache->findAndRefScratchResource(scratchKey);
852     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
853     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
854     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
855     REPORTER_ASSERT(reporter, !scratch);
856     SkSafeUnref(scratch);
857 }
858
859 static void test_cache_chained_purge(skiatest::Reporter* reporter) {
860     Mock mock(3, 30000);
861     GrContext* context = mock.context();
862     GrResourceCache* cache = mock.cache();
863
864     GrUniqueKey key1, key2;
865     make_unique_key<0>(&key1, 1);
866     make_unique_key<0>(&key2, 2);
867
868
869     TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu()));
870     TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu()));
871     a->resourcePriv().setUniqueKey(key1);
872     b->resourcePriv().setUniqueKey(key2);
873
874     // Make a cycle
875     a->setUnrefWhenDestroyed(b);
876     b->setUnrefWhenDestroyed(a);
877
878     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
879
880     a->unref();
881     b->unref();
882
883     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
884
885     cache->purgeAllUnlocked();
886     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
887
888     // Break the cycle
889     a->setUnrefWhenDestroyed(NULL);
890     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
891
892     cache->purgeAllUnlocked();
893     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
894 }
895
896 static void test_resource_size_changed(skiatest::Reporter* reporter) {
897     GrUniqueKey key1, key2;
898     make_unique_key<0>(&key1, 1);
899     make_unique_key<0>(&key2, 2);
900
901     // Test changing resources sizes (both increase & decrease).
902     {
903         Mock mock(3, 30000);
904         GrContext* context = mock.context();
905         GrResourceCache* cache = mock.cache();
906
907         TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu()));
908         a->resourcePriv().setUniqueKey(key1);
909         a->unref();
910
911         TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu()));
912         b->resourcePriv().setUniqueKey(key2);
913         b->unref();
914
915         REPORTER_ASSERT(reporter, 200 == cache->getResourceBytes());
916         REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
917         {
918             SkAutoTUnref<TestResource> find2(
919                 static_cast<TestResource*>(cache->findAndRefUniqueResource(key2)));
920             find2->setSize(200);
921             SkAutoTUnref<TestResource> find1(
922                 static_cast<TestResource*>(cache->findAndRefUniqueResource(key1)));
923             find1->setSize(50);
924         }
925
926         REPORTER_ASSERT(reporter, 250 == cache->getResourceBytes());
927         REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
928     }
929
930     // Test increasing a resources size beyond the cache budget.
931     {
932         Mock mock(2, 300);
933         GrContext* context = mock.context();
934         GrResourceCache* cache = mock.cache();
935
936         TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu()));
937         a->setSize(100);
938         a->resourcePriv().setUniqueKey(key1);
939         a->unref();
940
941         TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu()));
942         b->setSize(100);
943         b->resourcePriv().setUniqueKey(key2);
944         b->unref();
945
946         REPORTER_ASSERT(reporter, 200 == cache->getResourceBytes());
947         REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
948
949         {
950             SkAutoTUnref<TestResource> find2(static_cast<TestResource*>(
951                 cache->findAndRefUniqueResource(key2)));
952             find2->setSize(201);
953         }
954         REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1));
955
956         REPORTER_ASSERT(reporter, 201 == cache->getResourceBytes());
957         REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
958     }
959 }
960
961 static void test_timestamp_wrap(skiatest::Reporter* reporter) {
962     static const int kCount = 50;
963     static const int kBudgetCnt = kCount / 2;
964     static const int kLockedFreq = 8;
965     static const int kBudgetSize = 0x80000000;
966
967     SkRandom random;
968
969     // Run the test 2*kCount times;
970     for (int i = 0; i < 2 * kCount; ++i ) {
971         Mock mock(kBudgetCnt, kBudgetSize);
972         GrContext* context = mock.context();
973         GrResourceCache* cache = mock.cache();
974
975         // Pick a random number of resources to add before the timestamp will wrap.
976         cache->changeTimestamp(SK_MaxU32 - random.nextULessThan(kCount + 1));
977
978         static const int kNumToPurge = kCount - kBudgetCnt;
979
980         SkTDArray<int> shouldPurgeIdxs;
981         int purgeableCnt = 0;
982         SkTDArray<GrGpuResource*> resourcesToUnref;
983
984         // Add kCount resources, holding onto resources at random so we have a mix of purgeable and
985         // unpurgeable resources.
986         for (int j = 0; j < kCount; ++j) {
987             GrUniqueKey key;
988             make_unique_key<0>(&key, j);
989
990             TestResource* r = SkNEW_ARGS(TestResource, (context->getGpu()));
991             r->resourcePriv().setUniqueKey(key);
992             if (random.nextU() % kLockedFreq) {
993                 // Make this is purgeable.
994                 r->unref();
995                 ++purgeableCnt;
996                 if (purgeableCnt <= kNumToPurge) {
997                     *shouldPurgeIdxs.append() = j;
998                 }
999             } else {
1000                 *resourcesToUnref.append() = r;
1001             }
1002         }
1003
1004         // Verify that the correct resources were purged.
1005         int currShouldPurgeIdx = 0;
1006         for (int j = 0; j < kCount; ++j) {
1007             GrUniqueKey key;
1008             make_unique_key<0>(&key, j);
1009             GrGpuResource* res = cache->findAndRefUniqueResource(key);
1010             if (currShouldPurgeIdx < shouldPurgeIdxs.count() &&
1011                 shouldPurgeIdxs[currShouldPurgeIdx] == j) {
1012                 ++currShouldPurgeIdx;
1013                 REPORTER_ASSERT(reporter, NULL == res);
1014             } else {
1015                 REPORTER_ASSERT(reporter, NULL != res);
1016             }
1017             SkSafeUnref(res);
1018         }
1019
1020         for (int j = 0; j < resourcesToUnref.count(); ++j) {
1021             resourcesToUnref[j]->unref();
1022         }
1023     }
1024 }
1025
1026 static void test_large_resource_count(skiatest::Reporter* reporter) {
1027     // Set the cache size to double the resource count because we're going to create 2x that number
1028     // resources, using two different key domains. Add a little slop to the bytes because we resize
1029     // down to 1 byte after creating the resource.
1030     static const int kResourceCnt = 2000;
1031
1032     Mock mock(2 * kResourceCnt, 2 * kResourceCnt + 1000);
1033     GrContext* context = mock.context();
1034     GrResourceCache* cache = mock.cache();
1035
1036     for (int i = 0; i < kResourceCnt; ++i) {
1037         GrUniqueKey key1, key2;
1038         make_unique_key<1>(&key1, i);
1039         make_unique_key<2>(&key2, i);
1040
1041         TestResource* resource;
1042
1043         resource = SkNEW_ARGS(TestResource, (context->getGpu()));
1044         resource->resourcePriv().setUniqueKey(key1);
1045         resource->setSize(1);
1046         resource->unref();
1047
1048         resource = SkNEW_ARGS(TestResource, (context->getGpu()));
1049         resource->resourcePriv().setUniqueKey(key2);
1050         resource->setSize(1);
1051         resource->unref();
1052     }
1053
1054     REPORTER_ASSERT(reporter, TestResource::NumAlive() == 2 * kResourceCnt);
1055     REPORTER_ASSERT(reporter, cache->getBudgetedResourceBytes() == 2 * kResourceCnt);
1056     REPORTER_ASSERT(reporter, cache->getBudgetedResourceCount() == 2 * kResourceCnt);
1057     REPORTER_ASSERT(reporter, cache->getResourceBytes() == 2 * kResourceCnt);
1058     REPORTER_ASSERT(reporter, cache->getResourceCount() == 2 * kResourceCnt);
1059     for (int i = 0; i < kResourceCnt; ++i) {
1060         GrUniqueKey key1, key2;
1061         make_unique_key<1>(&key1, i);
1062         make_unique_key<2>(&key2, i);
1063
1064         REPORTER_ASSERT(reporter, cache->hasUniqueKey(key1));
1065         REPORTER_ASSERT(reporter, cache->hasUniqueKey(key2));
1066     }
1067
1068     cache->purgeAllUnlocked();
1069     REPORTER_ASSERT(reporter, TestResource::NumAlive() == 0);
1070     REPORTER_ASSERT(reporter, cache->getBudgetedResourceBytes() == 0);
1071     REPORTER_ASSERT(reporter, cache->getBudgetedResourceCount() == 0);
1072     REPORTER_ASSERT(reporter, cache->getResourceBytes() == 0);
1073     REPORTER_ASSERT(reporter, cache->getResourceCount() == 0);
1074
1075     for (int i = 0; i < kResourceCnt; ++i) {
1076         GrUniqueKey key1, key2;
1077         make_unique_key<1>(&key1, i);
1078         make_unique_key<2>(&key2, i);
1079
1080         REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1));
1081         REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key2));
1082     }
1083 }
1084
1085 ////////////////////////////////////////////////////////////////////////////////
1086 DEF_GPUTEST(ResourceCache, reporter, factory) {
1087     for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
1088         GrContextFactory::GLContextType glType = static_cast<GrContextFactory::GLContextType>(type);
1089         if (!GrContextFactory::IsRenderingGLContext(glType)) {
1090             continue;
1091         }
1092         GrContext* context = factory->get(glType);
1093         if (NULL == context) {
1094             continue;
1095         }
1096         GrSurfaceDesc desc;
1097         desc.fConfig = kSkia8888_GrPixelConfig;
1098         desc.fFlags = kRenderTarget_GrSurfaceFlag;
1099         desc.fWidth = gWidth;
1100         desc.fHeight = gHeight;
1101         SkImageInfo info = SkImageInfo::MakeN32Premul(gWidth, gHeight);
1102         SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(context,
1103                                                                    SkSurface::kNo_Budgeted, info));
1104         test_cache(reporter, context, surface->getCanvas());
1105         test_stencil_buffers(reporter, context);
1106     }
1107
1108     // The below tests create their own mock contexts.
1109     test_no_key(reporter);
1110     test_budgeting(reporter);
1111     test_unbudgeted(reporter);
1112     test_unbudgeted_to_scratch(reporter);
1113     test_duplicate_unique_key(reporter);
1114     test_duplicate_scratch_key(reporter);
1115     test_remove_scratch_key(reporter);
1116     test_scratch_key_consistency(reporter);
1117     test_purge_invalidated(reporter);
1118     test_cache_chained_purge(reporter);
1119     test_resource_size_changed(reporter);
1120     test_timestamp_wrap(reporter);
1121     test_large_resource_count(reporter);
1122 }
1123
1124 #endif