blob: fe9b0f812d0994e4f8a57636cdc72887776a51e1 [file] [log] [blame]
Robert Phillips26f3aeb2020-09-16 10:57:32 -04001/*
2 * Copyright 2020 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#include "include/core/SkCanvas.h"
9#include "include/core/SkDeferredDisplayListRecorder.h"
10#include "include/core/SkSurfaceCharacterization.h"
11#include "src/gpu/GrContextPriv.h"
12#include "src/gpu/GrProxyProvider.h"
13#include "src/gpu/GrRecordingContextPriv.h"
14#include "src/gpu/GrRenderTargetContext.h"
Robert Phillips3380be92020-09-25 12:47:10 -040015#include "src/gpu/GrStyle.h"
Robert Phillips26f3aeb2020-09-16 10:57:32 -040016#include "src/gpu/GrThreadSafeUniquelyKeyedProxyViewCache.h"
17#include "tests/Test.h"
18#include "tests/TestUtils.h"
19
Robert Phillipsc2fe1642020-09-22 17:34:51 -040020#include <thread>
21
Robert Phillips26f3aeb2020-09-16 10:57:32 -040022static constexpr int kImageWH = 32;
23static constexpr auto kImageOrigin = kBottomLeft_GrSurfaceOrigin;
24
25static SkImageInfo default_ii(int wh) {
26 return SkImageInfo::Make(wh, wh, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
27}
28
Robert Phillips3380be92020-09-25 12:47:10 -040029static std::unique_ptr<GrRenderTargetContext> new_RTC(GrRecordingContext* rContext, int wh) {
30 return GrRenderTargetContext::Make(rContext,
31 GrColorType::kRGBA_8888,
32 nullptr,
33 SkBackingFit::kExact,
34 {wh, wh},
35 1,
36 GrMipMapped::kNo,
37 GrProtected::kNo,
38 kImageOrigin,
39 SkBudgeted::kYes);
40}
41
Robert Phillips26f3aeb2020-09-16 10:57:32 -040042static void create_key(GrUniqueKey* key, int wh) {
43 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
44 GrUniqueKey::Builder builder(key, kDomain, 1);
45 builder[0] = wh;
46 builder.finish();
47};
48
Robert Phillips3380be92020-09-25 12:47:10 -040049static SkBitmap create_bitmap(int wh) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -040050 SkBitmap bitmap;
51
52 bitmap.allocPixels(default_ii(wh));
53
54 SkCanvas tmp(bitmap);
55 tmp.clear(SK_ColorWHITE);
56
57 SkPaint blue;
58 blue.setColor(SK_ColorBLUE);
Robert Phillips3380be92020-09-25 12:47:10 -040059 blue.setAntiAlias(false);
Robert Phillips26f3aeb2020-09-16 10:57:32 -040060
Robert Phillips3380be92020-09-25 12:47:10 -040061 tmp.drawRect({10, 10, wh-10.0f, wh-10.0f}, blue);
Robert Phillips26f3aeb2020-09-16 10:57:32 -040062
Robert Phillipsdefd2232020-09-25 15:25:46 -040063 bitmap.setImmutable();
Robert Phillips26f3aeb2020-09-16 10:57:32 -040064 return bitmap;
65}
66
67class TestHelper {
68public:
69 struct Stats {
70 int fCacheHits = 0;
71 int fCacheMisses = 0;
72
73 int fNumSWCreations = 0;
Robert Phillips3380be92020-09-25 12:47:10 -040074 int fNumLazyCreations = 0;
Robert Phillips26f3aeb2020-09-16 10:57:32 -040075 int fNumHWCreations = 0;
76 };
77
78 TestHelper(GrDirectContext* dContext) : fDContext(dContext) {
79
80 fDst = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, default_ii(kImageWH));
81 SkAssertResult(fDst);
82
83 SkSurfaceCharacterization characterization;
84 SkAssertResult(fDst->characterize(&characterization));
85
86 fRecorder1 = std::make_unique<SkDeferredDisplayListRecorder>(characterization);
Robert Phillipsdefd2232020-09-25 15:25:46 -040087 this->ddlCanvas1()->clear(SkColors::kGreen);
Robert Phillips26f3aeb2020-09-16 10:57:32 -040088
89 fRecorder2 = std::make_unique<SkDeferredDisplayListRecorder>(characterization);
Robert Phillipsdefd2232020-09-25 15:25:46 -040090 this->ddlCanvas2()->clear(SkColors::kRed);
Robert Phillips26f3aeb2020-09-16 10:57:32 -040091 }
92
93 ~TestHelper() {
Robert Phillips187b04b2020-09-22 12:18:16 -040094 fDContext->flush();
95 fDContext->submit(true);
Robert Phillips26f3aeb2020-09-16 10:57:32 -040096 }
97
98 Stats* stats() { return &fStats; }
99
Robert Phillips752f7e12020-09-18 12:28:59 -0400100 int numCacheEntries() const { return this->threadSafeViewCache()->numEntries(); }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400101
102 GrDirectContext* dContext() { return fDContext; }
103
104 SkCanvas* liveCanvas() { return fDst ? fDst->getCanvas() : nullptr; }
105 SkCanvas* ddlCanvas1() { return fRecorder1 ? fRecorder1->getCanvas() : nullptr; }
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400106 sk_sp<SkDeferredDisplayList> snap1() {
107 if (fRecorder1) {
108 sk_sp<SkDeferredDisplayList> tmp = fRecorder1->detach();
109 fRecorder1 = nullptr;
110 return tmp;
111 }
112
113 return nullptr;
114 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400115 SkCanvas* ddlCanvas2() { return fRecorder2 ? fRecorder2->getCanvas() : nullptr; }
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400116 sk_sp<SkDeferredDisplayList> snap2() {
117 if (fRecorder2) {
118 sk_sp<SkDeferredDisplayList> tmp = fRecorder2->detach();
119 fRecorder2 = nullptr;
120 return tmp;
121 }
122
123 return nullptr;
124 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400125
126 GrThreadSafeUniquelyKeyedProxyViewCache* threadSafeViewCache() {
Robert Phillips752f7e12020-09-18 12:28:59 -0400127 return fDContext->priv().threadSafeViewCache();
128 }
129
130 const GrThreadSafeUniquelyKeyedProxyViewCache* threadSafeViewCache() const {
131 return fDContext->priv().threadSafeViewCache();
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400132 }
133
134 // Add a draw on 'canvas' that will introduce a ref on the 'wh' view
135 void accessCachedView(SkCanvas* canvas,
136 int wh,
Robert Phillips3380be92020-09-25 12:47:10 -0400137 bool failLookup = false,
138 bool failFillingIn = false) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400139 GrRecordingContext* rContext = canvas->recordingContext();
140
141 auto view = AccessCachedView(rContext, this->threadSafeViewCache(),
Robert Phillips3380be92020-09-25 12:47:10 -0400142 wh, failLookup, failFillingIn, &fStats);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400143 SkASSERT(view);
144
145 auto rtc = canvas->internal_private_accessTopLayerRenderTargetContext();
146
147 rtc->drawTexture(nullptr,
148 view,
149 kPremul_SkAlphaType,
150 GrSamplerState::Filter::kNearest,
151 GrSamplerState::MipmapMode::kNone,
152 SkBlendMode::kSrcOver,
Robert Phillipsdefd2232020-09-25 15:25:46 -0400153 {1.0f, 1.0f, 1.0f, 1.0f},
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400154 SkRect::MakeWH(wh, wh),
155 SkRect::MakeWH(wh, wh),
156 GrAA::kNo,
157 GrQuadAAFlags::kNone,
158 SkCanvas::kFast_SrcRectConstraint,
159 SkMatrix::I(),
160 nullptr);
161 }
162
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400163 // Besides checking that the number of refs and cache hits and misses are as expected, this
164 // method also validates that the unique key doesn't appear in any of the other caches.
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400165 bool checkView(SkCanvas* canvas, int wh, int hits, int misses, int numRefs) {
166 if (fStats.fCacheHits != hits || fStats.fCacheMisses != misses) {
Robert Phillips187b04b2020-09-22 12:18:16 -0400167 SkDebugf("Hits E: %d A: %d --- Misses E: %d A: %d\n",
168 hits, fStats.fCacheHits, misses, fStats.fCacheMisses);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400169 return false;
170 }
171
172 GrUniqueKey key;
173 create_key(&key, wh);
174
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400175 auto threadSafeViewCache = this->threadSafeViewCache();
176
177 GrSurfaceProxyView view = threadSafeViewCache->find(key);
Robert Phillips187b04b2020-09-22 12:18:16 -0400178 if (!view.proxy()) {
179 return false;
180 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400181
182 if (!view.proxy()->refCntGreaterThan(numRefs+1) || // +1 for 'view's ref
183 view.proxy()->refCntGreaterThan(numRefs+2)) {
184 return false;
185 }
186
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400187 if (canvas) {
188 GrRecordingContext* rContext = canvas->recordingContext();
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400189 GrProxyProvider* recordingProxyProvider = rContext->priv().proxyProvider();
190 sk_sp<GrTextureProxy> result = recordingProxyProvider->findProxyByUniqueKey(key);
191 if (result) {
192 // views in this cache should never appear in the recorder's cache
193 return false;
194 }
195 }
196
197 {
198 GrProxyProvider* directProxyProvider = fDContext->priv().proxyProvider();
199 sk_sp<GrTextureProxy> result = directProxyProvider->findProxyByUniqueKey(key);
200 if (result) {
201 // views in this cache should never appear in the main proxy cache
202 return false;
203 }
204 }
205
206 {
207 auto resourceProvider = fDContext->priv().resourceProvider();
208 sk_sp<GrSurface> surf = resourceProvider->findByUniqueKey<GrSurface>(key);
209 if (surf) {
210 // the textures backing the views in this cache should never be discoverable in the
211 // resource cache
212 return false;
213 }
214 }
215
216 return true;
217 }
218
Robert Phillipsdefd2232020-09-25 15:25:46 -0400219 bool checkImage(skiatest::Reporter* reporter, sk_sp<SkSurface> s) {
220 SkBitmap actual;
221
222 actual.allocPixels(default_ii(kImageWH));
223
224 if (!s->readPixels(actual, 0, 0)) {
225 return false;
226 }
227
228 SkBitmap expected = create_bitmap(kImageWH);
229
230 const float tols[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
231
232 auto error = std::function<ComparePixmapsErrorReporter>(
233 [reporter](int x, int y, const float diffs[4]) {
234 SkASSERT(x >= 0 && y >= 0);
235 ERRORF(reporter, "mismatch at %d, %d (%f, %f, %f %f)",
236 x, y, diffs[0], diffs[1], diffs[2], diffs[3]);
237 });
238
239 return ComparePixels(expected.pixmap(), actual.pixmap(), tols, error);
240 }
241
242 bool checkImage(skiatest::Reporter* reporter) {
243 return this->checkImage(reporter, fDst);
244 }
245
246 bool checkImage(skiatest::Reporter* reporter, sk_sp<SkDeferredDisplayList> ddl) {
247 sk_sp<SkSurface> tmp = SkSurface::MakeRenderTarget(fDContext,
248 SkBudgeted::kNo,
249 default_ii(kImageWH));
250 if (!tmp) {
251 return false;
252 }
253
254 if (!tmp->draw(std::move(ddl))) {
255 return false;
256 }
257
258 return this->checkImage(reporter, std::move(tmp));
259 }
260
Robert Phillips187b04b2020-09-22 12:18:16 -0400261 size_t gpuSize(int wh) const {
262 GrBackendFormat format = fDContext->defaultBackendFormat(kRGBA_8888_SkColorType,
263 GrRenderable::kNo);
264
265 return GrSurface::ComputeSize(*fDContext->priv().caps(), format,
266 {wh, wh}, 1, GrMipMapped::kNo, false);
267 }
268
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400269private:
Robert Phillips3380be92020-09-25 12:47:10 -0400270 // In the gpu-creation case, we need to pre-emptively place a lazy proxy in the shared
271 // cache. This object allows that lazy proxy to be instantiated with some rendering result
272 // generated after the fact.
273 class Trampoline : public SkRefCnt {
274 public:
275 sk_sp<GrTextureProxy> fProxy;
276 };
277
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400278 static GrSurfaceProxyView AccessCachedView(GrRecordingContext*,
279 GrThreadSafeUniquelyKeyedProxyViewCache*,
Robert Phillips187b04b2020-09-22 12:18:16 -0400280 int wh,
Robert Phillips3380be92020-09-25 12:47:10 -0400281 bool failLookup, bool failFillingIn,
282 Stats*);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400283 static GrSurfaceProxyView CreateViewOnCpu(GrRecordingContext*, int wh, Stats*);
Robert Phillips3380be92020-09-25 12:47:10 -0400284 static std::tuple<GrSurfaceProxyView, sk_sp<Trampoline>> CreateLazyView(GrDirectContext*,
285 int wh, Stats*);
286 static bool FillInViewOnGpu(GrDirectContext*, int wh, Stats*,
287 const GrSurfaceProxyView& lazyView,
288 sk_sp<Trampoline>);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400289
290 Stats fStats;
291 GrDirectContext* fDContext = nullptr;
292
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400293 sk_sp<SkSurface> fDst;
294 std::unique_ptr<SkDeferredDisplayListRecorder> fRecorder1;
295 std::unique_ptr<SkDeferredDisplayListRecorder> fRecorder2;
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400296};
297
298GrSurfaceProxyView TestHelper::CreateViewOnCpu(GrRecordingContext* rContext,
299 int wh,
300 Stats* stats) {
301 GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
302
Robert Phillips3380be92020-09-25 12:47:10 -0400303 sk_sp<GrTextureProxy> proxy = proxyProvider->createProxyFromBitmap(create_bitmap(wh),
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400304 GrMipmapped::kNo,
305 SkBackingFit::kExact,
306 SkBudgeted::kYes);
307 if (!proxy) {
308 return {};
309 }
310
311 GrSwizzle swizzle = rContext->priv().caps()->getReadSwizzle(proxy->backendFormat(),
312 GrColorType::kRGBA_8888);
313 ++stats->fNumSWCreations;
314 return {std::move(proxy), kImageOrigin, swizzle};
315}
316
Robert Phillips3380be92020-09-25 12:47:10 -0400317std::tuple<GrSurfaceProxyView, sk_sp<TestHelper::Trampoline>> TestHelper::CreateLazyView(
318 GrDirectContext* dContext, int wh, Stats* stats) {
319
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400320 GrProxyProvider* proxyProvider = dContext->priv().proxyProvider();
321
Robert Phillips3380be92020-09-25 12:47:10 -0400322 sk_sp<Trampoline> trampoline(new Trampoline);
Robert Phillips187b04b2020-09-22 12:18:16 -0400323
Robert Phillips3380be92020-09-25 12:47:10 -0400324 GrProxyProvider::TextureInfo texInfo { GrMipMapped::kNo, GrTextureType::k2D };
325
326 GrBackendFormat format = dContext->defaultBackendFormat(kRGBA_8888_SkColorType,
327 GrRenderable::kYes);
328 sk_sp<GrRenderTargetProxy> proxy = proxyProvider->createLazyRenderTargetProxy(
329 [trampoline] (GrResourceProvider* resourceProvider, const GrSurfaceProxy::LazySurfaceDesc&)
330 -> GrSurfaceProxy::LazyCallbackResult {
331 if (!resourceProvider || !trampoline->fProxy || !trampoline->fProxy->isInstantiated()) {
332 return GrSurfaceProxy::LazyCallbackResult(nullptr, true);
333
334 }
335
336 SkASSERT(!trampoline->fProxy->peekTexture()->getUniqueKey().isValid());
337 return GrSurfaceProxy::LazyCallbackResult(sk_ref_sp(trampoline->fProxy->peekTexture()));
338 },
339 format,
340 {wh, wh},
341 /* renderTargetSampleCnt */ 1,
342 GrInternalSurfaceFlags::kNone,
343 &texInfo,
344 GrMipmapStatus::kNotAllocated,
345 SkBackingFit::kExact,
346 SkBudgeted::kYes,
347 GrProtected::kNo,
348 /* wrapsVkSecondaryCB */ false,
349 GrSurfaceProxy::UseAllocator::kYes);
350
351 GrSwizzle swizzle = dContext->priv().caps()->getReadSwizzle(format, GrColorType::kRGBA_8888);
352
353 ++stats->fNumLazyCreations;
354 return {{std::move(proxy), kImageOrigin, swizzle}, std::move(trampoline)};
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400355}
356
Robert Phillips3380be92020-09-25 12:47:10 -0400357bool TestHelper::FillInViewOnGpu(GrDirectContext* dContext, int wh, Stats* stats,
358 const GrSurfaceProxyView& lazyView,
359 sk_sp<Trampoline> trampoline) {
360
361 std::unique_ptr<GrRenderTargetContext> rtc = new_RTC(dContext, wh);
362
363 GrPaint paint;
364 paint.setColor4f({0.0f, 0.0f, 1.0f, 1.0f});
365
366 rtc->clear({1.0f, 1.0f, 1.0f, 1.0f});
367 rtc->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(),
368 { 10, 10, wh-10.0f, wh-10.0f }, &GrStyle::SimpleFill());
369
370 ++stats->fNumHWCreations;
371 auto view = rtc->readSurfaceView();
372
373 SkASSERT(view.swizzle() == lazyView.swizzle());
374 SkASSERT(view.origin() == lazyView.origin());
375 trampoline->fProxy = view.asTextureProxyRef();
376
377 return true;
378}
379
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400380GrSurfaceProxyView TestHelper::AccessCachedView(
381 GrRecordingContext* rContext,
382 GrThreadSafeUniquelyKeyedProxyViewCache* threadSafeViewCache,
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400383 int wh,
Robert Phillips3380be92020-09-25 12:47:10 -0400384 bool failLookup, bool failFillingIn,
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400385 Stats* stats) {
386 GrUniqueKey key;
387 create_key(&key, wh);
388
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400389 if (GrDirectContext* dContext = rContext->asDirectContext()) {
Robert Phillips3380be92020-09-25 12:47:10 -0400390 // The gpu thread gets priority over the recording threads. If the gpu thread is first,
391 // it crams a lazy proxy into the cache and then fills it in later.
392 auto [lazyView, trampoline] = CreateLazyView(dContext, wh, stats);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400393
Robert Phillips3380be92020-09-25 12:47:10 -0400394 GrSurfaceProxyView view = threadSafeViewCache->findOrAdd(key, lazyView);
395 if (view != lazyView) {
396 ++stats->fCacheHits;
397 return view;
398 }
399
400 ++stats->fCacheMisses;
401
402 if (failFillingIn) {
403 // Simulate something going horribly wrong at flush-time so no GrTexture is
404 // available to fulfill the lazy proxy.
405 return view;
406 }
407
408 if (!FillInViewOnGpu(dContext, wh, stats, lazyView, std::move(trampoline))) {
409 // In this case something has gone disastrously wrong so set up to drop the draw
410 // that needed this resource and reduce future pollution of the cache.
411 threadSafeViewCache->remove(key);
412 return {};
413 }
414
415 return view;
416 } else {
417 GrSurfaceProxyView view;
418
419 // We can "fail the lookup" to simulate a threaded race condition
Robert Phillipsaac57282020-09-30 10:23:38 -0400420 if (view = threadSafeViewCache->find(key); !failLookup && view) {
Robert Phillips3380be92020-09-25 12:47:10 -0400421 ++stats->fCacheHits;
422 return view;
423 }
424
425 ++stats->fCacheMisses;
426
427 view = CreateViewOnCpu(rContext, wh, stats);
428 SkASSERT(view);
429
430 return threadSafeViewCache->add(key, view);
431 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400432}
433
434// Case 1: ensure two DDL recorders share the view
435DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeViewCache1, reporter, ctxInfo) {
436 TestHelper helper(ctxInfo.directContext());
437
438 helper.accessCachedView(helper.ddlCanvas1(), kImageWH);
Robert Phillips187b04b2020-09-22 12:18:16 -0400439 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas1(), kImageWH,
440 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400441
442 helper.accessCachedView(helper.ddlCanvas2(), kImageWH);
Robert Phillips187b04b2020-09-22 12:18:16 -0400443 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas2(), kImageWH,
444 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400445
446 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400447 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 0);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400448 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
449 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 1);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400450
451 helper.checkImage(reporter, helper.snap1());
452 helper.checkImage(reporter, helper.snap2());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400453}
454
455// Case 2: ensure that, if the direct context version wins, it is reused by the DDL recorders
456DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeViewCache2, reporter, ctxInfo) {
457 TestHelper helper(ctxInfo.directContext());
458
459 helper.accessCachedView(helper.liveCanvas(), kImageWH);
Robert Phillips187b04b2020-09-22 12:18:16 -0400460 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), kImageWH,
461 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400462
463 helper.accessCachedView(helper.ddlCanvas1(), kImageWH);
Robert Phillips187b04b2020-09-22 12:18:16 -0400464 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas1(), kImageWH,
465 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400466
467 helper.accessCachedView(helper.ddlCanvas2(), kImageWH);
Robert Phillips187b04b2020-09-22 12:18:16 -0400468 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas2(), kImageWH,
469 /*hits*/ 2, /*misses*/ 1, /*refs*/ 3));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400470
471 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400472 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400473 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
474 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400475
476 helper.checkImage(reporter);
477 helper.checkImage(reporter, helper.snap1());
478 helper.checkImage(reporter, helper.snap2());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400479}
480
481// Case 3: ensure that, if the cpu-version wins, it is reused by the direct context
482DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeViewCache3, reporter, ctxInfo) {
483 TestHelper helper(ctxInfo.directContext());
484
485 helper.accessCachedView(helper.ddlCanvas1(), kImageWH);
Robert Phillips187b04b2020-09-22 12:18:16 -0400486 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas1(), kImageWH,
487 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400488
489 helper.accessCachedView(helper.liveCanvas(), kImageWH);
Robert Phillips187b04b2020-09-22 12:18:16 -0400490 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), kImageWH,
491 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400492
493 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400494 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400495 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
496 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 1);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400497
498 helper.checkImage(reporter);
499 helper.checkImage(reporter, helper.snap1());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400500}
501
502// Case 4: ensure that, if two DDL recorders get in a race, they still end up sharing a single view
503DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeViewCache4, reporter, ctxInfo) {
504 TestHelper helper(ctxInfo.directContext());
505
506 helper.accessCachedView(helper.ddlCanvas1(), kImageWH);
Robert Phillips187b04b2020-09-22 12:18:16 -0400507 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas1(), kImageWH,
508 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400509
510 static const bool kFailLookup = true;
511 helper.accessCachedView(helper.ddlCanvas2(), kImageWH, kFailLookup);
Robert Phillips187b04b2020-09-22 12:18:16 -0400512 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas2(), kImageWH,
513 /*hits*/ 0, /*misses*/ 2, /*refs*/ 2));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400514
515 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400516 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 0);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400517 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
518 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 2);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400519
520 helper.checkImage(reporter, helper.snap1());
521 helper.checkImage(reporter, helper.snap2());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400522}
Robert Phillips752f7e12020-09-18 12:28:59 -0400523
Robert Phillips3380be92020-09-25 12:47:10 -0400524// Case 4.5: check that, if a live rendering and a DDL recording get into a race, the live
525// rendering takes precedence.
526DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeViewCache4_5, reporter, ctxInfo) {
527 TestHelper helper(ctxInfo.directContext());
528
529 helper.accessCachedView(helper.liveCanvas(), kImageWH);
530 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), kImageWH,
531 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1));
532
533 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
534 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
535 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
536 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
537
538 static const bool kFailLookup = true;
539 helper.accessCachedView(helper.ddlCanvas1(), kImageWH, kFailLookup);
540 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas1(), kImageWH,
541 /*hits*/ 0, /*misses*/ 2, /*refs*/ 2));
542
543 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
544 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
545 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
546 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 1);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400547
548 helper.checkImage(reporter);
549 helper.checkImage(reporter, helper.snap1());
Robert Phillips3380be92020-09-25 12:47:10 -0400550}
551
552// Case 4.75: check that, if a live rendering fails to generate the content needed to instantiate
553// its lazy proxy, life goes on
554DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeViewCache4_75, reporter, ctxInfo) {
555 auto dContext = ctxInfo.directContext();
556
557 TestHelper helper(dContext);
558
559 static const bool kFailFillingIn = true;
560 helper.accessCachedView(helper.liveCanvas(), kImageWH, false, kFailFillingIn);
561 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), kImageWH,
562 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1));
563
564 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
565 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
566 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
567 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
568
569 dContext->flush();
570 dContext->submit(true);
571
572 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), kImageWH,
573 /*hits*/ 0, /*misses*/ 1, /*refs*/ 0));
574
575 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
576 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
577 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
578 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
579}
580
Robert Phillips752f7e12020-09-18 12:28:59 -0400581// Case 5: ensure that expanding the map works
582DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeViewCache5, reporter, ctxInfo) {
583 TestHelper helper(ctxInfo.directContext());
584
585 auto threadSafeViewCache = helper.threadSafeViewCache();
586
587 int size = 16;
588 helper.accessCachedView(helper.ddlCanvas1(), size);
589
Robert Phillipsc61c8952020-09-22 14:24:43 -0400590 size_t initialSize = threadSafeViewCache->approxBytesUsedForHash();
Robert Phillips752f7e12020-09-18 12:28:59 -0400591
Robert Phillipsc61c8952020-09-22 14:24:43 -0400592 while (initialSize == threadSafeViewCache->approxBytesUsedForHash()) {
Robert Phillips752f7e12020-09-18 12:28:59 -0400593 size *= 2;
594 helper.accessCachedView(helper.ddlCanvas1(), size);
595 }
596}
597
Robert Phillipsdefd2232020-09-25 15:25:46 -0400598// Case 6: Check on dropping refs. In particular, that the cache has its own ref to keep
599// the backing resource alive and locked.
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400600DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeViewCache6, reporter, ctxInfo) {
601 TestHelper helper(ctxInfo.directContext());
602
603 helper.accessCachedView(helper.ddlCanvas1(), kImageWH);
604 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips187b04b2020-09-22 12:18:16 -0400605 REPORTER_ASSERT(reporter, helper.checkView(nullptr, kImageWH,
606 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400607
608 helper.accessCachedView(helper.ddlCanvas2(), kImageWH);
609 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
Robert Phillips187b04b2020-09-22 12:18:16 -0400610 REPORTER_ASSERT(reporter, helper.checkView(nullptr, kImageWH,
611 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400612
613 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
614
615 ddl1 = nullptr;
Robert Phillips187b04b2020-09-22 12:18:16 -0400616 REPORTER_ASSERT(reporter, helper.checkView(nullptr, kImageWH,
617 /*hits*/ 1, /*misses*/ 1, /*refs*/ 1));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400618
619 ddl2 = nullptr;
Robert Phillips187b04b2020-09-22 12:18:16 -0400620 REPORTER_ASSERT(reporter, helper.checkView(nullptr, kImageWH,
621 /*hits*/ 1, /*misses*/ 1, /*refs*/ 0));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400622
623 // The cache still has its ref
624 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
625
Robert Phillips187b04b2020-09-22 12:18:16 -0400626 REPORTER_ASSERT(reporter, helper.checkView(nullptr, kImageWH,
627 /*hits*/ 1, /*misses*/ 1, /*refs*/ 0));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400628}
Robert Phillips45593682020-09-18 16:16:33 -0400629
Robert Phillipsdefd2232020-09-25 15:25:46 -0400630// Case 7: Check that invoking dropAllRefs and dropUniqueRefs directly works as expected; i.e.,
631// dropAllRefs removes everything while dropUniqueRefs is more measured.
Robert Phillips45593682020-09-18 16:16:33 -0400632DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeViewCache7, reporter, ctxInfo) {
633 TestHelper helper(ctxInfo.directContext());
634
635 helper.accessCachedView(helper.ddlCanvas1(), kImageWH);
636 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips187b04b2020-09-22 12:18:16 -0400637 REPORTER_ASSERT(reporter, helper.checkView(nullptr, kImageWH,
638 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1));
Robert Phillips45593682020-09-18 16:16:33 -0400639
640 helper.accessCachedView(helper.ddlCanvas2(), 2*kImageWH);
641 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
Robert Phillips187b04b2020-09-22 12:18:16 -0400642 REPORTER_ASSERT(reporter, helper.checkView(nullptr, 2*kImageWH,
643 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1));
Robert Phillips45593682020-09-18 16:16:33 -0400644
645 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
646
Robert Phillips331699c2020-09-22 15:20:01 -0400647 helper.threadSafeViewCache()->dropUniqueRefs(nullptr);
Robert Phillips45593682020-09-18 16:16:33 -0400648 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
649
650 ddl1 = nullptr;
651
Robert Phillips331699c2020-09-22 15:20:01 -0400652 helper.threadSafeViewCache()->dropUniqueRefs(nullptr);
Robert Phillips45593682020-09-18 16:16:33 -0400653 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips187b04b2020-09-22 12:18:16 -0400654 REPORTER_ASSERT(reporter, helper.checkView(nullptr, 2*kImageWH,
655 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1));
Robert Phillips45593682020-09-18 16:16:33 -0400656
657 helper.threadSafeViewCache()->dropAllRefs();
658 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
659
660 ddl2 = nullptr;
661}
Robert Phillips187b04b2020-09-22 12:18:16 -0400662
663// Case 8: This checks that GrContext::abandonContext works as expected wrt the thread
664// safe cache. This simulates the case where we have one DDL that has finished
665// recording but one still recording when the abandonContext fires.
666DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeViewCache8, reporter, ctxInfo) {
667 TestHelper helper(ctxInfo.directContext());
668
669 helper.accessCachedView(helper.liveCanvas(), kImageWH);
670 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), kImageWH,
671 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1));
672
673 helper.accessCachedView(helper.ddlCanvas1(), kImageWH);
674 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
675 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas1(), kImageWH,
676 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2));
677
678 helper.accessCachedView(helper.ddlCanvas2(), kImageWH);
679 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas2(), kImageWH,
680 /*hits*/ 2, /*misses*/ 1, /*refs*/ 3));
681
682 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400683 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips187b04b2020-09-22 12:18:16 -0400684 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
685 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
686
687 ctxInfo.directContext()->abandonContext(); // This should exercise dropAllRefs
688
689 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
690
691 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
692
693 ddl1 = nullptr;
694 ddl2 = nullptr;
695}
696
697// Case 9: This checks that GrContext::releaseResourcesAndAbandonContext works as expected wrt
698// the thread safe cache. This simulates the case where we have one DDL that has finished
699// recording but one still recording when the releaseResourcesAndAbandonContext fires.
700DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeViewCache9, reporter, ctxInfo) {
701 TestHelper helper(ctxInfo.directContext());
702
703 helper.accessCachedView(helper.liveCanvas(), kImageWH);
704 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), kImageWH,
705 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1));
706
707 helper.accessCachedView(helper.ddlCanvas1(), kImageWH);
708 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
709 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas1(), kImageWH,
710 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2));
711
712 helper.accessCachedView(helper.ddlCanvas2(), kImageWH);
713 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas2(), kImageWH,
714 /*hits*/ 2, /*misses*/ 1, /*refs*/ 3));
715
716 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400717 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips187b04b2020-09-22 12:18:16 -0400718 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
719 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
720
721 ctxInfo.directContext()->releaseResourcesAndAbandonContext(); // This should hit dropAllRefs
722
723 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
724
725 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
726
727 ddl1 = nullptr;
728 ddl2 = nullptr;
729}
730
731// Case 10: This checks that the GrContext::purgeUnlockedResources(size_t) variant works as
732// expected wrt the thread safe cache. It, in particular, tests out the MRU behavior
733// of the shared cache.
734DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeViewCache10, reporter, ctxInfo) {
735 auto dContext = ctxInfo.directContext();
736
737 if (GrBackendApi::kOpenGL != dContext->backend()) {
738 // The lower-level backends have too much going on for the following simple purging
739 // test to work
740 return;
741 }
742
743 TestHelper helper(dContext);
744
745 helper.accessCachedView(helper.liveCanvas(), kImageWH);
746 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), kImageWH,
747 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1));
748
749 helper.accessCachedView(helper.ddlCanvas1(), kImageWH);
750 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
751 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas1(), kImageWH,
752 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2));
753
754 helper.accessCachedView(helper.liveCanvas(), 2*kImageWH);
755 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), 2*kImageWH,
756 /*hits*/ 1, /*misses*/ 2, /*refs*/ 1));
757
758 helper.accessCachedView(helper.ddlCanvas2(), 2*kImageWH);
759 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
760 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas2(), 2*kImageWH,
761 /*hits*/ 2, /*misses*/ 2, /*refs*/ 2));
762
763 dContext->flush();
764 dContext->submit(true);
765
766 // This should clear out everything but the textures locked in the thread-safe cache
767 dContext->purgeUnlockedResources(false);
768
769 ddl1 = nullptr;
770 ddl2 = nullptr;
771
772 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
773 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), kImageWH,
774 /*hits*/ 2, /*misses*/ 2, /*refs*/ 0));
775 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), 2*kImageWH,
776 /*hits*/ 2, /*misses*/ 2, /*refs*/ 0));
777
778 // Regardless of which image is MRU, this should force the other out
779 size_t desiredBytes = helper.gpuSize(2*kImageWH) + helper.gpuSize(kImageWH)/2;
780
781 auto cache = dContext->priv().getResourceCache();
782 size_t currentBytes = cache->getResourceBytes();
783
784 SkASSERT(currentBytes >= desiredBytes);
785 size_t amountToPurge = currentBytes - desiredBytes;
786
787 // The 2*kImageWH texture should be MRU.
788 dContext->purgeUnlockedResources(amountToPurge, true);
789
790 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
791
792 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), 2*kImageWH,
793 /*hits*/ 2, /*misses*/ 2, /*refs*/ 0));
794}
Robert Phillips331699c2020-09-22 15:20:01 -0400795
796// Case 11: This checks that scratch-only variant of GrContext::purgeUnlockedResources works as
Robert Phillipsdefd2232020-09-25 15:25:46 -0400797// expected wrt the thread safe cache. In particular, that when 'scratchResourcesOnly'
798// is true, the call has no effect on the cache.
Robert Phillips331699c2020-09-22 15:20:01 -0400799DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeViewCache11, reporter, ctxInfo) {
800 auto dContext = ctxInfo.directContext();
801
802 TestHelper helper(dContext);
803
804 helper.accessCachedView(helper.liveCanvas(), kImageWH);
805 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), kImageWH,
806 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1));
807
808 helper.accessCachedView(helper.liveCanvas(), 2*kImageWH);
809 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), 2*kImageWH,
810 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1));
811
812 dContext->flush();
813 dContext->submit(true);
814
815 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
816 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), kImageWH,
817 /*hits*/ 0, /*misses*/ 2, /*refs*/ 0));
818 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), 2*kImageWH,
819 /*hits*/ 0, /*misses*/ 2, /*refs*/ 0));
820
821 // This shouldn't remove anything from the cache
822 dContext->purgeUnlockedResources(/* scratchResourcesOnly */ true);
823
824 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
825
826 dContext->purgeUnlockedResources(/* scratchResourcesOnly */ false);
827
828 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
829}
830
Robert Phillipsdefd2232020-09-25 15:25:46 -0400831// Case 12: Test out purges caused by resetting the cache budget to 0. Note that, due to
832// the how the cache operates (i.e., not directly driven by ref/unrefs) there
833// needs to be an explicit kick to purge the cache.
Robert Phillips331699c2020-09-22 15:20:01 -0400834DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeViewCache12, reporter, ctxInfo) {
835 auto dContext = ctxInfo.directContext();
836
837 TestHelper helper(dContext);
838
839 helper.accessCachedView(helper.liveCanvas(), kImageWH);
840 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), kImageWH,
841 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1));
842 helper.accessCachedView(helper.ddlCanvas1(), kImageWH);
843 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
844 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas1(), kImageWH,
845 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2));
846
847 helper.accessCachedView(helper.liveCanvas(), 2*kImageWH);
848 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), 2*kImageWH,
849 /*hits*/ 1, /*misses*/ 2, /*refs*/ 1));
850
851 dContext->flush();
852 dContext->submit(true);
853
854 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
855 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), kImageWH,
856 /*hits*/ 1, /*misses*/ 2, /*refs*/ 1));
857 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), 2*kImageWH,
858 /*hits*/ 1, /*misses*/ 2, /*refs*/ 0));
859
860 dContext->setResourceCacheLimit(0);
861
862 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
863
864 ddl1 = nullptr;
865
Robert Phillipsdefd2232020-09-25 15:25:46 -0400866 // Explicitly kick off the purge - it won't happen automatically on unref
Robert Phillips331699c2020-09-22 15:20:01 -0400867 dContext->performDeferredCleanup(std::chrono::milliseconds(0));
868
869 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
870}
Robert Phillipsc2fe1642020-09-22 17:34:51 -0400871
872// Case 13: Test out the 'msNotUsed' parameter to GrContext::performDeferredCleanup.
873DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeViewCache13, reporter, ctxInfo) {
874 auto dContext = ctxInfo.directContext();
875
876 TestHelper helper(dContext);
877
878 helper.accessCachedView(helper.ddlCanvas1(), kImageWH);
879
880 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas1(), kImageWH,
881 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1));
882 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
883
884 std::this_thread::sleep_for(std::chrono::milliseconds(5));
885 auto firstTime = GrStdSteadyClock::now();
886 std::this_thread::sleep_for(std::chrono::milliseconds(5));
887
888 helper.accessCachedView(helper.ddlCanvas2(), 2*kImageWH);
889 REPORTER_ASSERT(reporter, helper.checkView(helper.ddlCanvas2(), 2*kImageWH,
890 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1));
891 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
892
893 ddl1 = nullptr;
894 ddl2 = nullptr;
895
896 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
897
898 auto secondTime = GrStdSteadyClock::now();
899
900 auto msecs = std::chrono::duration_cast<std::chrono::milliseconds>(secondTime - firstTime);
901 dContext->performDeferredCleanup(msecs);
902
903 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
904 REPORTER_ASSERT(reporter, helper.checkView(helper.liveCanvas(), 2*kImageWH,
905 /*hits*/ 0, /*misses*/ 2, /*refs*/ 0));
906}