1 /*
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 */
7 
8 #if SK_SUPPORT_GPU
9 
10 #include "GrContext.h"
11 #include "GrContextFactory.h"
12 #include "GrLayerCache.h"
13 #include "SkPictureRecorder.h"
14 #include "Test.h"
15 
16 class TestingAccess {
17 public:
NumLayers(GrLayerCache * cache)18     static unsigned NumLayers(GrLayerCache* cache) {
19         return cache->numLayers();
20     }
Purge(GrLayerCache * cache,uint32_t pictureID)21     static void Purge(GrLayerCache* cache, uint32_t pictureID) {
22         cache->purge(pictureID);
23     }
Uses(GrCachedLayer * layer)24     static int Uses(GrCachedLayer* layer) {
25         return layer->uses();
26     }
Find(GrLayerCache * cache,uint32_t pictureID,const SkMatrix & initialMat,const unsigned * key,int keySize)27     static GrCachedLayer* Find(GrLayerCache* cache, uint32_t pictureID,
28                                const SkMatrix& initialMat,
29                                const unsigned* key, int keySize) {
30         return cache->findLayer(pictureID, initialMat, key, keySize);
31     }
32 };
33 
34 // Add several layers to the cache
create_layers(skiatest::Reporter * reporter,GrLayerCache * cache,const SkPicture & picture,unsigned numToAdd,unsigned idOffset)35 static void create_layers(skiatest::Reporter* reporter,
36                           GrLayerCache* cache,
37                           const SkPicture& picture,
38                           unsigned numToAdd,
39                           unsigned idOffset) {
40 
41     for (unsigned i = 0; i < numToAdd; ++i) {
42         unsigned indices[1] = { idOffset+i+1 };
43         GrCachedLayer* layer = cache->findLayerOrCreate(picture.uniqueID(),
44                                                         idOffset+i+1, idOffset+i+2,
45                                                         SkIRect::MakeEmpty(),
46                                                         SkIRect::MakeEmpty(),
47                                                         SkMatrix::I(),
48                                                         indices, 1,
49                                                         NULL);
50         REPORTER_ASSERT(reporter, layer);
51         GrCachedLayer* temp = TestingAccess::Find(cache, picture.uniqueID(), SkMatrix::I(),
52                                                   indices, 1);
53         REPORTER_ASSERT(reporter, temp == layer);
54 
55         REPORTER_ASSERT(reporter, TestingAccess::NumLayers(cache) == idOffset + i + 1);
56 
57         REPORTER_ASSERT(reporter, picture.uniqueID() == layer->pictureID());
58         REPORTER_ASSERT(reporter, layer->start() == idOffset + i + 1);
59         REPORTER_ASSERT(reporter, layer->stop() == idOffset + i + 2);
60         REPORTER_ASSERT(reporter, NULL == layer->texture());
61         REPORTER_ASSERT(reporter, NULL == layer->paint());
62         REPORTER_ASSERT(reporter, !layer->isAtlased());
63     }
64 }
65 
lock_layer(skiatest::Reporter * reporter,GrLayerCache * cache,GrCachedLayer * layer)66 static void lock_layer(skiatest::Reporter* reporter,
67                        GrLayerCache* cache,
68                        GrCachedLayer* layer) {
69     // Make the layer 512x512 (so it can be atlased)
70     GrSurfaceDesc desc;
71     desc.fWidth = 512;
72     desc.fHeight = 512;
73     desc.fConfig = kSkia8888_GrPixelConfig;
74 
75     bool needsRerendering;
76     bool inAtlas = cache->tryToAtlas(layer, desc, &needsRerendering);
77     if (!inAtlas) {
78         cache->lock(layer, desc, &needsRerendering);
79     }
80     REPORTER_ASSERT(reporter, needsRerendering);
81 
82     cache->lock(layer, desc, &needsRerendering);
83     REPORTER_ASSERT(reporter, !needsRerendering);
84 
85     REPORTER_ASSERT(reporter, layer->texture());
86     REPORTER_ASSERT(reporter, layer->locked());
87 
88     cache->addUse(layer);
89 
90     REPORTER_ASSERT(reporter, 1 == TestingAccess::Uses(layer));
91 }
92 
93 // This test case exercises the public API of the GrLayerCache class.
94 // In particular it checks its interaction with the resource cache (w.r.t.
95 // locking & unlocking textures).
96 // TODO: need to add checks on VRAM usage!
DEF_GPUTEST(GpuLayerCache,reporter,factory)97 DEF_GPUTEST(GpuLayerCache, reporter, factory) {
98     static const unsigned kInitialNumLayers = 5;
99 
100     for (int i= 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
101         GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
102 
103         if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
104             continue;
105         }
106 
107         GrContext* context = factory->get(glCtxType);
108 
109         if (NULL == context) {
110             continue;
111         }
112 
113         SkPictureRecorder recorder;
114         recorder.beginRecording(1, 1);
115         SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
116 
117         GrLayerCache cache(context);
118 
119         create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
120 
121         for (unsigned i = 0; i < kInitialNumLayers; ++i) {
122             unsigned indices[1] = { i + 1 };
123             GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
124                                                        indices, 1);
125             REPORTER_ASSERT(reporter, layer);
126 
127             lock_layer(reporter, &cache, layer);
128 
129             // The first 4 layers should be in the atlas (and thus have non-empty
130             // rects)
131             if (i < 4) {
132                 REPORTER_ASSERT(reporter, layer->isAtlased());
133             } else {
134                 // The 5th layer couldn't fit in the atlas
135                 REPORTER_ASSERT(reporter, !layer->isAtlased());
136             }
137         }
138 
139         // Unlock the textures
140         for (unsigned i = 0; i < kInitialNumLayers; ++i) {
141             unsigned indices[1] = { i+1 };
142 
143             GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
144                                                        indices, 1);
145             REPORTER_ASSERT(reporter, layer);
146             cache.removeUse(layer);
147         }
148 
149         for (unsigned i = 0; i < kInitialNumLayers; ++i) {
150             unsigned indices[1] = { i+1 };
151 
152             GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
153                                                        indices, 1);
154             REPORTER_ASSERT(reporter, layer);
155 
156             // All the layers should be unlocked
157             REPORTER_ASSERT(reporter, !layer->locked());
158 
159             // When hoisted layers aren't cached they are aggressively removed
160             // from the atlas
161 #if GR_CACHE_HOISTED_LAYERS
162             // The first 4 layers should still be in the atlas.
163             if (i < 4) {
164                 REPORTER_ASSERT(reporter, layer->texture());
165                 REPORTER_ASSERT(reporter, layer->isAtlased());
166             } else {
167 #endif
168                 // The final layer should not be atlased.
169                 REPORTER_ASSERT(reporter, NULL == layer->texture());
170                 REPORTER_ASSERT(reporter, !layer->isAtlased());
171 #if GR_CACHE_HOISTED_LAYERS
172             }
173 #endif
174         }
175 
176         {
177             unsigned indices[1] = { kInitialNumLayers+1 };
178 
179             // Add an additional layer. Since all the layers are unlocked this
180             // will force out the first atlased layer
181             create_layers(reporter, &cache, *picture, 1, kInitialNumLayers);
182             GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
183                                                        indices, 1);
184             REPORTER_ASSERT(reporter, layer);
185 
186             lock_layer(reporter, &cache, layer);
187             cache.removeUse(layer);
188         }
189 
190         for (unsigned i = 0; i < kInitialNumLayers+1; ++i) {
191             unsigned indices[1] = { i+1 };
192 
193             GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
194                                                        indices, 1);
195 #if GR_CACHE_HOISTED_LAYERS
196             // 3 old layers plus the new one should be in the atlas.
197             if (1 == i || 2 == i || 3 == i || 5 == i) {
198                 REPORTER_ASSERT(reporter, layer);
199                 REPORTER_ASSERT(reporter, !layer->locked());
200                 REPORTER_ASSERT(reporter, layer->texture());
201                 REPORTER_ASSERT(reporter, layer->isAtlased());
202             } else if (4 == i) {
203 #endif
204                 // The one that was never atlased should still be around
205                 REPORTER_ASSERT(reporter, layer);
206 
207                 REPORTER_ASSERT(reporter, NULL == layer->texture());
208                 REPORTER_ASSERT(reporter, !layer->isAtlased());
209 #if GR_CACHE_HOISTED_LAYERS
210             } else {
211                 // The one bumped out of the atlas (i.e., 0) should be gone
212                 REPORTER_ASSERT(reporter, NULL == layer);
213             }
214 #endif
215         }
216 
217         //--------------------------------------------------------------------
218         // Free them all SkGpuDevice-style. This will not free up the
219         // atlas' texture but will eliminate all the layers.
220         TestingAccess::Purge(&cache, picture->uniqueID());
221 
222         REPORTER_ASSERT(reporter, TestingAccess::NumLayers(&cache) == 0);
223         // TODO: add VRAM/resource cache check here
224 
225         //--------------------------------------------------------------------
226         // Test out the GrContext-style purge. This should remove all the layers
227         // and the atlas.
228         // Re-create the layers
229         create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
230 
231         // Free them again GrContext-style. This should free up everything.
232         cache.freeAll();
233 
234         REPORTER_ASSERT(reporter, TestingAccess::NumLayers(&cache) == 0);
235         // TODO: add VRAM/resource cache check here
236 
237         //--------------------------------------------------------------------
238         // Test out the MessageBus-style purge. This will not free the atlas
239         // but should eliminate the free-floating layers.
240         create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
241 
242         picture.reset(NULL);
243         cache.processDeletedPictures();
244 
245         REPORTER_ASSERT(reporter, TestingAccess::NumLayers(&cache) == 0);
246         // TODO: add VRAM/resource cache check here
247     }
248 }
249 
250 #endif
251