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