blob: 2249eba904c7dda92955bd1509a80afd53c2450f [file] [log] [blame]
robertphillips952841b2014-06-30 08:26:50 -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*/
7
8#if SK_SUPPORT_GPU
9
10#include "GrContext.h"
robertphillips952841b2014-06-30 08:26:50 -070011#include "GrLayerCache.h"
robertphillips60029a52015-11-09 13:51:06 -080012#include "GrResourceCache.h"
Robert Phillipscfaeec42014-07-13 12:00:50 -040013#include "SkPictureRecorder.h"
robertphillips952841b2014-06-30 08:26:50 -070014#include "Test.h"
15
robertphillipsd771f6b2014-07-22 10:18:06 -070016class TestingAccess {
robertphillips952841b2014-06-30 08:26:50 -070017public:
robertphillips60029a52015-11-09 13:51:06 -080018 static int NumPlots() {
19 return GrLayerCache::kNumPlotsX * GrLayerCache::kNumPlotsY;
20 }
21 static SkISize PlotSize() {
22 return SkISize::Make(GrLayerCache::kAtlasTextureWidth / GrLayerCache::kNumPlotsX,
23 GrLayerCache::kAtlasTextureHeight / GrLayerCache::kNumPlotsY);
24 }
25
26 static GrTexture* GetBackingTexture(GrLayerCache* cache) {
27 return cache->fAtlas->getTextureOrNull();
28 }
29
mtkleinc6ad06a2015-08-19 09:51:00 -070030 static int NumLayers(GrLayerCache* cache) {
robertphillips952841b2014-06-30 08:26:50 -070031 return cache->numLayers();
32 }
robertphillipsd771f6b2014-07-22 10:18:06 -070033 static void Purge(GrLayerCache* cache, uint32_t pictureID) {
34 cache->purge(pictureID);
35 }
robertphillips7bb9ed72014-10-10 11:38:29 -070036 static int Uses(GrCachedLayer* layer) {
37 return layer->uses();
38 }
robertphillips01d6e5f2014-12-01 09:09:27 -080039 static GrCachedLayer* Find(GrLayerCache* cache, uint32_t pictureID,
mtkleinc6ad06a2015-08-19 09:51:00 -070040 const SkMatrix& initialMat,
41 const int* key, int keySize) {
robertphillips01d6e5f2014-12-01 09:09:27 -080042 return cache->findLayer(pictureID, initialMat, key, keySize);
43 }
robertphillips952841b2014-06-30 08:26:50 -070044};
45
46// Add several layers to the cache
47static void create_layers(skiatest::Reporter* reporter,
48 GrLayerCache* cache,
robertphillips320c9232014-07-29 06:07:19 -070049 const SkPicture& picture,
mtkleinc6ad06a2015-08-19 09:51:00 -070050 int numToAdd,
51 int idOffset) {
robertphillips952841b2014-06-30 08:26:50 -070052
mtkleinc6ad06a2015-08-19 09:51:00 -070053 for (int i = 0; i < numToAdd; ++i) {
robertphillips60029a52015-11-09 13:51:06 -080054 int key[1] = { idOffset+i+1 };
mtkleinc6ad06a2015-08-19 09:51:00 -070055 GrCachedLayer* layer = cache->findLayerOrCreate(picture.uniqueID(),
56 idOffset+i+1, idOffset+i+2,
robertphillips3aac6e02014-10-20 08:52:40 -070057 SkIRect::MakeEmpty(),
robertphillips478dd722014-12-16 08:25:55 -080058 SkIRect::MakeEmpty(),
robertphillips4aa6dfc2014-09-17 07:50:47 -070059 SkMatrix::I(),
robertphillips60029a52015-11-09 13:51:06 -080060 key, 1,
halcanary96fcdcc2015-08-27 07:41:13 -070061 nullptr);
bsalomon49f085d2014-09-05 13:34:00 -070062 REPORTER_ASSERT(reporter, layer);
mtkleinc6ad06a2015-08-19 09:51:00 -070063 GrCachedLayer* temp = TestingAccess::Find(cache, picture.uniqueID(), SkMatrix::I(),
robertphillips60029a52015-11-09 13:51:06 -080064 key, 1);
robertphillips320c9232014-07-29 06:07:19 -070065 REPORTER_ASSERT(reporter, temp == layer);
robertphillips952841b2014-06-30 08:26:50 -070066
robertphillips320c9232014-07-29 06:07:19 -070067 REPORTER_ASSERT(reporter, TestingAccess::NumLayers(cache) == idOffset + i + 1);
robertphillips952841b2014-06-30 08:26:50 -070068
robertphillips320c9232014-07-29 06:07:19 -070069 REPORTER_ASSERT(reporter, picture.uniqueID() == layer->pictureID());
robertphillips0c423322014-07-31 11:02:38 -070070 REPORTER_ASSERT(reporter, layer->start() == idOffset + i + 1);
71 REPORTER_ASSERT(reporter, layer->stop() == idOffset + i + 2);
halcanary96fcdcc2015-08-27 07:41:13 -070072 REPORTER_ASSERT(reporter, nullptr == layer->texture());
73 REPORTER_ASSERT(reporter, nullptr == layer->paint());
robertphillips320c9232014-07-29 06:07:19 -070074 REPORTER_ASSERT(reporter, !layer->isAtlased());
robertphillips952841b2014-06-30 08:26:50 -070075 }
robertphillips952841b2014-06-30 08:26:50 -070076}
77
robertphillips320c9232014-07-29 06:07:19 -070078static void lock_layer(skiatest::Reporter* reporter,
79 GrLayerCache* cache,
80 GrCachedLayer* layer) {
robertphillips60029a52015-11-09 13:51:06 -080081 // Make each layer big enough to consume one whole plot in the atlas
bsalomonf2703d82014-10-28 14:33:06 -070082 GrSurfaceDesc desc;
robertphillips60029a52015-11-09 13:51:06 -080083 desc.fFlags = kRenderTarget_GrSurfaceFlag;
84 desc.fWidth = TestingAccess::PlotSize().fWidth;
85 desc.fHeight = TestingAccess::PlotSize().fHeight;
robertphillips320c9232014-07-29 06:07:19 -070086 desc.fConfig = kSkia8888_GrPixelConfig;
87
robertphillipsfd61ed02014-10-28 07:21:44 -070088 bool needsRerendering;
89 bool inAtlas = cache->tryToAtlas(layer, desc, &needsRerendering);
90 if (!inAtlas) {
91 cache->lock(layer, desc, &needsRerendering);
92 }
robertphillips6f294af2014-08-18 08:50:03 -070093 REPORTER_ASSERT(reporter, needsRerendering);
robertphillips320c9232014-07-29 06:07:19 -070094
robertphillipsfd61ed02014-10-28 07:21:44 -070095 cache->lock(layer, desc, &needsRerendering);
robertphillips6f294af2014-08-18 08:50:03 -070096 REPORTER_ASSERT(reporter, !needsRerendering);
robertphillips320c9232014-07-29 06:07:19 -070097
bsalomon49f085d2014-09-05 13:34:00 -070098 REPORTER_ASSERT(reporter, layer->texture());
robertphillips320c9232014-07-29 06:07:19 -070099 REPORTER_ASSERT(reporter, layer->locked());
robertphillips7bb9ed72014-10-10 11:38:29 -0700100
101 cache->addUse(layer);
102
103 REPORTER_ASSERT(reporter, 1 == TestingAccess::Uses(layer));
robertphillips320c9232014-07-29 06:07:19 -0700104}
105
robertphillips952841b2014-06-30 08:26:50 -0700106// This test case exercises the public API of the GrLayerCache class.
107// In particular it checks its interaction with the resource cache (w.r.t.
108// locking & unlocking textures).
109// TODO: need to add checks on VRAM usage!
bsalomonf2f1c172016-04-05 12:59:06 -0700110DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GpuLayerCache, reporter, ctxInfo) {
robertphillips60029a52015-11-09 13:51:06 -0800111 // Add one more layer than can fit in the atlas
112 static const int kInitialNumLayers = TestingAccess::NumPlots() + 1;
robertphillips320c9232014-07-29 06:07:19 -0700113
robertphillips60029a52015-11-09 13:51:06 -0800114#if GR_CACHE_STATS
115 GrResourceCache::Stats stats;
116#endif
117
reedca2622b2016-03-18 07:25:55 -0700118 sk_sp<SkPicture> picture;
robertphillips952841b2014-06-30 08:26:50 -0700119
kkinnunen15302832015-12-01 04:35:26 -0800120 {
121 SkPictureRecorder recorder;
122 SkCanvas* c = recorder.beginRecording(1, 1);
123 // Draw something, anything, to prevent an empty-picture optimization,
124 // which is a singleton and never purged.
125 c->drawRect(SkRect::MakeWH(1,1), SkPaint());
reedca2622b2016-03-18 07:25:55 -0700126 picture = recorder.finishRecordingAsPicture();
kkinnunen15302832015-12-01 04:35:26 -0800127 }
robertphillips952841b2014-06-30 08:26:50 -0700128
bsalomonf2f1c172016-04-05 12:59:06 -0700129 GrResourceCache* resourceCache = ctxInfo.fGrContext->getResourceCache();
robertphillips952841b2014-06-30 08:26:50 -0700130
bsalomonf2f1c172016-04-05 12:59:06 -0700131 GrLayerCache cache(ctxInfo.fGrContext);
robertphillips952841b2014-06-30 08:26:50 -0700132
kkinnunen15302832015-12-01 04:35:26 -0800133 create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
robertphillips60029a52015-11-09 13:51:06 -0800134
kkinnunen15302832015-12-01 04:35:26 -0800135 for (int i = 0; i < kInitialNumLayers; ++i) {
136 int key[1] = { i + 1 };
137 GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
138 key, 1);
139 REPORTER_ASSERT(reporter, layer);
robertphillips60029a52015-11-09 13:51:06 -0800140
kkinnunen15302832015-12-01 04:35:26 -0800141 lock_layer(reporter, &cache, layer);
bsalomone904c092014-07-17 10:50:59 -0700142
robertphillips60029a52015-11-09 13:51:06 -0800143#if GR_CACHE_STATS
144 resourceCache->getStats(&stats);
robertphillips60029a52015-11-09 13:51:06 -0800145#endif
146
kkinnunen15302832015-12-01 04:35:26 -0800147 // The first 4 layers should be in the atlas (and thus have non-empty rects)
148 if (i < TestingAccess::NumPlots()) {
149 REPORTER_ASSERT(reporter, layer->isAtlased());
150#if GR_CACHE_STATS
151 REPORTER_ASSERT(reporter, 1 == stats.fTotal);
152#endif
153 } else {
154 // The 5th layer couldn't fit in the atlas
155 REPORTER_ASSERT(reporter, !layer->isAtlased());
156#if GR_CACHE_STATS
157 REPORTER_ASSERT(reporter, 2 == stats.fTotal);
158#endif
159 }
160 }
robertphillips01d6e5f2014-12-01 09:09:27 -0800161
kkinnunen15302832015-12-01 04:35:26 -0800162 // Unlock the textures
163 for (int i = 0; i < kInitialNumLayers; ++i) {
164 int key[1] = { i+1 };
bsalomone904c092014-07-17 10:50:59 -0700165
kkinnunen15302832015-12-01 04:35:26 -0800166 GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
167 key, 1);
168 REPORTER_ASSERT(reporter, layer);
169 cache.removeUse(layer);
170 }
robertphillips7bb9ed72014-10-10 11:38:29 -0700171
kkinnunen15302832015-12-01 04:35:26 -0800172#if GR_CACHE_STATS
173 resourceCache->getStats(&stats);
174 REPORTER_ASSERT(reporter, 2 == stats.fTotal);
175 // The floating layer is purgeable the cache is not
176 REPORTER_ASSERT(reporter, 1 == stats.fNumPurgeable);
177 REPORTER_ASSERT(reporter, 1 == stats.fNumNonPurgeable);
178#endif
179
180 for (int i = 0; i < kInitialNumLayers; ++i) {
181 int key[1] = { i+1 };
182
183 GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
184 key, 1);
185 REPORTER_ASSERT(reporter, layer);
186
187 // All the layers should be unlocked
188 REPORTER_ASSERT(reporter, !layer->locked());
189
190 // When hoisted layers aren't cached they are aggressively removed
191 // from the atlas
robertphillips4ab5a902014-10-29 13:56:02 -0700192#if GR_CACHE_HOISTED_LAYERS
kkinnunen15302832015-12-01 04:35:26 -0800193 // The first 4 layers should still be in the atlas.
194 if (i < 4) {
195 REPORTER_ASSERT(reporter, layer->texture());
196 REPORTER_ASSERT(reporter, layer->isAtlased());
197 } else {
robertphillips4ab5a902014-10-29 13:56:02 -0700198#endif
kkinnunen15302832015-12-01 04:35:26 -0800199 // The final layer should not be atlased.
200 REPORTER_ASSERT(reporter, nullptr == layer->texture());
201 REPORTER_ASSERT(reporter, !layer->isAtlased());
robertphillips4ab5a902014-10-29 13:56:02 -0700202#if GR_CACHE_HOISTED_LAYERS
bsalomone904c092014-07-17 10:50:59 -0700203 }
robertphillips60029a52015-11-09 13:51:06 -0800204#endif
robertphillips952841b2014-06-30 08:26:50 -0700205 }
kkinnunen15302832015-12-01 04:35:26 -0800206
207 // Let go of the backing texture
208 cache.end();
209 REPORTER_ASSERT(reporter, nullptr == TestingAccess::GetBackingTexture(&cache));
210
211#if GR_CACHE_STATS
212 resourceCache->getStats(&stats);
213 REPORTER_ASSERT(reporter, 2 == stats.fTotal);
214 // Now both the floater and the atlas are purgeable
215 REPORTER_ASSERT(reporter, 2 == stats.fNumPurgeable);
216#endif
217
218 // re-attach to the backing texture
219 cache.begin();
220 REPORTER_ASSERT(reporter, TestingAccess::GetBackingTexture(&cache));
221
222#if GR_CACHE_STATS
223 resourceCache->getStats(&stats);
224 REPORTER_ASSERT(reporter, 2 == stats.fTotal);
225 // The atlas is restored to being non-purgeable
226 REPORTER_ASSERT(reporter, 1 == stats.fNumPurgeable);
227 REPORTER_ASSERT(reporter, 1 == stats.fNumNonPurgeable);
228#endif
229
230 {
231 int key[1] = { kInitialNumLayers+1 };
232
233 // Add an additional layer. Since all the layers are unlocked this
234 // will force out the first atlased layer
235 create_layers(reporter, &cache, *picture, 1, kInitialNumLayers);
236 GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
237 key, 1);
238 REPORTER_ASSERT(reporter, layer);
239
240 lock_layer(reporter, &cache, layer);
241 cache.removeUse(layer);
242 }
243
244 for (int i = 0; i < kInitialNumLayers+1; ++i) {
245 int key[1] = { i+1 };
246
247 GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
248 key, 1);
249#if GR_CACHE_HOISTED_LAYERS
250 // 3 old layers plus the new one should be in the atlas.
251 if (1 == i || 2 == i || 3 == i || 5 == i) {
252 REPORTER_ASSERT(reporter, layer);
253 REPORTER_ASSERT(reporter, !layer->locked());
254 REPORTER_ASSERT(reporter, layer->texture());
255 REPORTER_ASSERT(reporter, layer->isAtlased());
256 } else if (4 == i) {
257#endif
258 // The one that was never atlased should still be around
259 REPORTER_ASSERT(reporter, layer);
260
261 REPORTER_ASSERT(reporter, nullptr == layer->texture());
262 REPORTER_ASSERT(reporter, !layer->isAtlased());
263#if GR_CACHE_HOISTED_LAYERS
264 } else {
265 // The one bumped out of the atlas (i.e., 0) should be gone
266 REPORTER_ASSERT(reporter, nullptr == layer);
267 }
268#endif
269 }
270
271 //--------------------------------------------------------------------
272 // Free them all SkGpuDevice-style. This will not free up the
273 // atlas' texture but will eliminate all the layers.
274 TestingAccess::Purge(&cache, picture->uniqueID());
275
276 REPORTER_ASSERT(reporter, TestingAccess::NumLayers(&cache) == 0);
277
278#if GR_CACHE_STATS
279 resourceCache->getStats(&stats);
280 REPORTER_ASSERT(reporter, 2 == stats.fTotal);
281 // Atlas isn't purgeable
282 REPORTER_ASSERT(reporter, 1 == stats.fNumPurgeable);
283 REPORTER_ASSERT(reporter, 1 == stats.fNumNonPurgeable);
284#endif
285
286 //--------------------------------------------------------------------
287 // Test out the GrContext-style purge. This should remove all the layers
288 // and the atlas.
289 // Re-create the layers
290 create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
291
292 // Free them again GrContext-style. This should free up everything.
293 cache.freeAll();
294
295 REPORTER_ASSERT(reporter, TestingAccess::NumLayers(&cache) == 0);
296
297 REPORTER_ASSERT(reporter, nullptr == TestingAccess::GetBackingTexture(&cache));
298
299#if GR_CACHE_STATS
300 resourceCache->getStats(&stats);
301 REPORTER_ASSERT(reporter, 2 == stats.fTotal);
302 REPORTER_ASSERT(reporter, 2 == stats.fNumPurgeable);
303#endif
304
305 // Purge the resource cache ...
306 resourceCache->purgeAllUnlocked();
307
308#if GR_CACHE_STATS
309 resourceCache->getStats(&stats);
310 REPORTER_ASSERT(reporter, 0 == stats.fTotal);
311#endif
312
313 // and try to re-attach to the backing texture. This should fail
314 cache.begin();
315 REPORTER_ASSERT(reporter, nullptr == TestingAccess::GetBackingTexture(&cache));
316
317 //--------------------------------------------------------------------
318 // Test out the MessageBus-style purge. This will not free the atlas
319 // but should eliminate the free-floating layers.
320 create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
321
322 // Allocate/use the layers
323 for (int i = 0; i < kInitialNumLayers; ++i) {
324 int key[1] = { i + 1 };
325 GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
326 key, 1);
327 REPORTER_ASSERT(reporter, layer);
328
329 lock_layer(reporter, &cache, layer);
330 }
331
332#if GR_CACHE_STATS
333 resourceCache->getStats(&stats);
334 REPORTER_ASSERT(reporter, 2 == stats.fTotal);
335 REPORTER_ASSERT(reporter, 2 == stats.fNumNonPurgeable);
336#endif
337
338 // Unlock the textures
339 for (int i = 0; i < kInitialNumLayers; ++i) {
340 int key[1] = { i+1 };
341
342 GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
343 key, 1);
344 REPORTER_ASSERT(reporter, layer);
345 cache.removeUse(layer);
346 }
347
348 picture.reset(nullptr);
349 cache.processDeletedPictures();
350
351 REPORTER_ASSERT(reporter, TestingAccess::NumLayers(&cache) == 0);
352
353#if GR_CACHE_STATS
354 resourceCache->getStats(&stats);
355 REPORTER_ASSERT(reporter, 2 == stats.fTotal);
356 REPORTER_ASSERT(reporter, 1 == stats.fNumPurgeable);
357 REPORTER_ASSERT(reporter, 1 == stats.fNumNonPurgeable);
358#endif
359
360 cache.end();
361
362#if GR_CACHE_STATS
363 resourceCache->getStats(&stats);
364 REPORTER_ASSERT(reporter, 2 == stats.fTotal);
365 REPORTER_ASSERT(reporter, 2 == stats.fNumPurgeable);
366#endif
robertphillips952841b2014-06-30 08:26:50 -0700367}
368
369#endif